multisplit
[iramuteq] / iramuteq.py
1 # -*- coding: utf-8 -*-
2 #Author: Pierre Ratinaud
3 #Copyright (c) 2008-2020 Pierre Ratinaud
4 #modification pour python 3 : Laurent Mérat, 6x7 - mai 2020
5 #License: GNU/GPL
6
7 #------------------------------------
8 # import des modules python
9 #------------------------------------
10 import sys
11 import locale
12 import tempfile
13 import codecs
14 import os
15 from random import randint
16 from configparser import ConfigParser, RawConfigParser
17 import webbrowser
18 import logging
19
20 from optparse import OptionParser
21 parser = OptionParser()
22 parser.add_option("-f", "--file", dest="filename",
23                   help="open FILE", metavar="FILE", default=False)
24 (options, args) = parser.parse_args()
25
26 #------------------------------------
27 # import des modules wx
28 #------------------------------------
29 import wx
30 import wx.adv
31 import wx.lib.agw.aui as aui
32 import wx.html
33 import wx.grid
34 import wx.lib.agw.hyperlink as hl
35
36 #------------------------------------
37 # import des fichiers du projet
38 #------------------------------------
39 from analyse_merge import AnalyseMerge
40 from checkinstall import CreateIraDirectory, CheckRPath, FindRPAthWin32, FindRPathNix, CheckRPackages, IsNew, UpgradeConf, CopyConf, RLibsAreInstalled
41 from checkversion import NewVersion
42 from chemins import RscriptsPath, ConstructConfigPath, ConstructDicoPath, ConstructGlobalPath, PathOut
43 from corpus import Builder, SubBuilder, MergeClusters
44 from dialog import PrefDialog
45 from functions import BugReport, PlaySound, History, progressbar
46 from guifunct import *
47 from openanalyse import OpenAnalyse
48 from parse_dmi import ImportDMI
49 from parse_factiva_xml import ImportFactiva
50 from tabafcm import DoAFCM
51 from tabchdalc import AnalyseQuest
52 from tabchddist import ChdCluster
53 from tabchi2 import ChiSquare
54 from tabchi2mcnemar import McNemar
55 from tabfrequence import Frequences, FreqMultiple
56 from tableau import Tableau
57 from tabrsimple import InputText
58 from tabsimi import DoSimi
59 from tabcatego import Categorisation
60 from tabsplitvar import SplitMatrixFromVar
61 from tabverges import Prototypical
62 from textaslexico import Lexico
63 from textlabbe import DistLabbe
64 from textreinert import Reinert
65 from textsimi import SimiTxt, SimiFromCluster
66 from textstat import Stat
67 from textwordcloud import WordCloud, ClusterCloud
68 from tools import Extract
69 from tree import LeftTree
70
71 import langue
72 langue.run()
73
74
75 #------------------------------------
76 # les ID uniques pour tous les éléments qui vont en avoir besoin
77 #------------------------------------
78 ID_OpenData = wx.Window.NewControlId()
79 ID_Import = wx.Window.NewControlId()
80 ID_OpenText = wx.Window.NewControlId()
81 ID_OnOpenAnalyse = wx.Window.NewControlId()
82 ID_Freq = wx.Window.NewControlId()
83 ID_Chi2 = wx.Window.NewControlId()
84 ID_Chi2mc = wx.Window.NewControlId()
85 ID_Student = wx.Window.NewControlId()
86 ID_CHDSIM = wx.Window.NewControlId()
87 ID_CHDReinert = wx.Window.NewControlId()
88 ID_TEXTAFCM = wx.Window.NewControlId()
89 ID_TEXTSTAT = wx.Window.NewControlId()
90 ID_ASLEX = wx.Window.NewControlId()
91 ID_TEXTREINERT = wx.Window.NewControlId()
92 ID_TEXTPAM = wx.Window.NewControlId()
93 ID_CHECKCORPUS = wx.Window.NewControlId()
94 ID_Tabcontent = wx.Window.NewControlId()
95 ID_AFCM = wx.Window.NewControlId()
96 ID_SIMI = wx.Window.NewControlId()
97 ID_CATE = wx.Window.NewControlId()
98 ID_CloseTab = wx.Window.NewControlId()
99 ID_SaveTab = wx.Window.NewControlId()
100 ID_CreateText = wx.Window.NewControlId()
101 ID_ACCEUIL = wx.Window.NewControlId()
102 ID_RESULT = wx.Window.NewControlId()
103 ID_HTMLcontent = wx.Window.NewControlId()
104 ID_SimiTxt = wx.Window.NewControlId()
105 ID_proto = wx.Window.NewControlId()
106 ID_ImportTXM = wx.Window.NewControlId()
107 ID_FreqMulti = wx.Window.NewControlId()
108 ID_Splitfromvar = wx.Window.NewControlId()
109 ID_Subtxtfrommeta = wx.Window.NewControlId()
110 ID_Subtxtfromthem = wx.Window.NewControlId()
111 ID_WC = wx.Window.NewControlId()
112 ID_ImportEuro = wx.Window.NewControlId()
113 ID_Fact_xml = wx.Window.NewControlId()
114 ID_Fact_mail = wx.Window.NewControlId()
115 ID_Fact_copy = wx.Window.NewControlId()
116 ID_exportmeta = wx.Window.NewControlId()
117 ID_importdmi = wx.Window.NewControlId()
118 ID_merge = wx.Window.NewControlId()
119 ID_merge_clusters = wx.Window.NewControlId()
120 ID_labbe = wx.Window.NewControlId()
121
122 #------------------------------------
123 # elements de configuration
124 #------------------------------------
125
126 #encodage
127 # if sys.platform == 'darwin' :
128 #    sys.setdefaultencoding('UTF-8')
129 #    wx.SetDefaultPyEncoding('UTF-8')
130 # else :
131 #    sys.setdefaultencoding(locale.getpreferredencoding())
132
133 #chemin de l'application
134 AppliPath = os.path.abspath(os.path.dirname(os.path.realpath(sys.argv[0])))
135
136 #chemin des images
137 ImagePath = os.path.join(AppliPath, 'images')
138
139 #configuration generale
140 DictConfigPath = ConstructGlobalPath(AppliPath)
141 ConfigGlob = ConfigParser()
142 ConfigGlob.read(DictConfigPath['global'])
143 DefaultConf = ConfigParser()
144 DefaultConf.read(DictConfigPath['preferences'])
145
146 #repertoire de l'utilisateur
147 user_home = os.getenv('HOME')
148 if user_home is None :
149     user_home = os.path.expanduser('~')
150
151 UserConfigPath = os.path.abspath(os.path.join(user_home, '.iramuteq-%s' % ConfigGlob.get('DEFAULT', 'version_nb')))
152 ConfigPath = ConstructConfigPath(UserConfigPath)
153
154 #Si pas de fichiers de config utilisateur, on cree le repertoire
155 CreateIraDirectory(UserConfigPath, AppliPath)
156
157 #fichiers log pour windows (py2exe)
158 log = logging.getLogger('iramuteq')
159 fh = logging.FileHandler(os.path.join(UserConfigPath,'stdout.log'))
160 formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
161 fh.setFormatter(formatter)
162 log.addHandler(fh)
163 if sys.platform != 'win32' and sys.platform != 'darwin':
164     ch = logging.StreamHandler()
165     ch.setFormatter(formatter)
166     log.addHandler(ch)
167 log.setLevel(logging.INFO)
168
169
170 class writer(object):
171
172     def write(self, data):
173         if data.strip() != '' :
174             log.info('ERROR : %s' % data)
175
176
177 class printer(object) :
178
179     def write(self, data) :
180         if data.strip() != '' :
181             log.info('Print : %s' % data)
182
183     # pour eviter des lignes de log d'erreur
184     def flush(self):
185         pass
186
187 #sys.stderr = writer()
188 #sys.stdout = printer()
189
190 images_analyses = {
191         'textroot' : 'textroot.png',
192         'alceste' : 'reinert.png',
193         'reinert' : 'reinert.png',
194         'corpus' : 'textcorpus.png',
195         'wordcloud' :'wordcloud.png',
196         'stat' :'stats.png',
197         'simitxt' : 'simitxt.png',
198         'clustersimitxt' :'clustersimitxt.png',
199         'clustercloud' : 'clustercloud.png',
200         'spec' : 'spec.png',
201         'matroot' : 'matroot.png',
202         'matrix' : 'matrix.png',
203         'freq' : 'frequences.png',
204         'freqmulti' : 'frequences.png',
205         'chi2' : 'chi2.png',
206         'chi2mcnemar' : 'chi2.png',
207         'reinertmatrix' : 'reinertmatrix.png',
208         'simimatrix' : 'simimatrix.png',
209         'simiclustermatrix' : 'simimatrix.png',
210         'proto' : 'proto.png',
211         'TXM' : 'TXM.png',
212         'europress' : 'europress.png',
213         'factiva_xml' : 'factiva_xml.png',
214         'factiva_copy' : 'factiva_copy.png',
215         'factiva_mail': 'factiva_mail.png',
216         'iramuteq' : 'iraicone.png',
217         'subcorpusmeta' : 'subcorpusmeta.png',
218         'subcorpusthema' : 'subcorpusthema.png',
219         'preferences' : 'preferences.png',
220         'exportmetatable' : 'exportmetatable.png',
221         'importdmi' : 'twitter.png',
222         'labbe' : 'spec.png',
223         'categorisation' : 'spec.png',
224          }
225
226
227 #------------------------------------
228 # l'ensemble du contexte de Iramuteq : menu, fenetre, etc.
229 #------------------------------------
230 class IraFrame(wx.Frame):
231
232     def __init__(self, parent,
233                  id= -1, title="",
234                  pos=wx.DefaultPosition,
235                  size=wx.DefaultSize,
236                  style=wx.DEFAULT_FRAME_STYLE |
237                        wx.SUNKEN_BORDER |
238                        wx.CLIP_CHILDREN):
239         log.info('Starting Iramuteq... ' )
240         log.info('version : %s' % ConfigGlob.get('DEFAULT', 'version'))
241         print(size)
242         wx.Frame.__init__(self, parent, id, title, pos, size, style)
243         #Font
244         self.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
245         # configuration
246         self.AppliPath = AppliPath
247         self.images_path = os.path.join(AppliPath,'images')
248         self.UserConfigPath = UserConfigPath
249         #self.RscriptsPath = ConstructRscriptsPath(AppliPath)
250         self.RscriptsPath = PathOut(dirout=os.path.join(AppliPath, 'Rscripts'))
251         self.RscriptsPath.basefiles(RscriptsPath)
252         #self.DictPath = ConstructDicoPath(AppliPath)
253         self.DictPath = ConstructDicoPath(UserConfigPath)
254         self.ConfigGlob = ConfigGlob
255         self.ConfigPath = ConstructConfigPath(self.UserConfigPath)
256         self.pref = RawConfigParser()
257         # workaround for import problem
258         self.SimiFromCluster = SimiFromCluster
259         # tell FrameManager to manage this frame
260         self._mgr = aui.AuiManager()
261         self._mgr.SetManagedWindow(self)
262         self.x = 0
263         #--------------------------------------------------------------------------------
264         # creation menu
265         #--------------------------------------------------------------------------------
266         self.images_analyses = images_analyses
267         for img in images_analyses :
268             self.images_analyses[img] = wx.Image(os.path.join(self.images_path, self.images_analyses[img]),
269                 wx.BITMAP_TYPE_PNG).Scale(16,16).ConvertToBitmap()
270         self.mb = wx.MenuBar()
271
272         # menu 'Fichier' de la barre de menu (en haut de l'écran)
273         file_menu = wx.Menu()
274         item = wx.MenuItem(file_menu, ID_OpenData, _("Open a matrix"), _("Open a matrix"))
275         #item.SetBitmap(wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN))
276         item.SetBitmap(self.images_analyses['matroot'])
277         file_menu.Append(item)
278         item = wx.MenuItem(file_menu, ID_OpenText, _("Open a text corpus"), _("Open a text corpus"))
279         item.SetBitmap(self.images_analyses['textroot'])
280         file_menu.Append(item)
281         item = wx.MenuItem(file_menu, ID_OnOpenAnalyse, _("Open an analysis"), _("Open an analysis"))
282         item.SetBitmap(self.images_analyses['iramuteq'])
283         file_menu.Append(item)
284         item = wx.MenuItem(file_menu, ID_ImportTXM, _("Import from TXM"), _("Import from TXM"))
285         item.SetBitmap(self.images_analyses['TXM'])
286         file_menu.Append(item)
287         item = wx.MenuItem(file_menu, ID_ImportEuro, _("Import from Europress"), _("Import from Europress"))
288         item.SetBitmap(self.images_analyses['europress'])
289         file_menu.Append(item)
290         item = wx.MenuItem(file_menu, ID_importdmi, _("Import from DMI-TCAT (exp.)"), _("Import from DMI-TCAT (exp.)"))
291         item.SetBitmap(self.images_analyses['importdmi'])
292         file_menu.Append(item)
293         item = wx.MenuItem(file_menu, ID_merge, _('Merge graphs'), _('Merge graphs'))
294         file_menu.Append(item)
295         item = wx.MenuItem(file_menu, ID_merge_clusters, _('Corpus from merge clusters'), _('Corpus from merge clusters'))
296         file_menu.Append(item)
297
298         # menu Factiva
299         menuFactiva = wx.Menu()
300         fact_from_xml = wx.MenuItem(menuFactiva, ID_Fact_xml, _("from xml"))
301         fact_from_xml.SetBitmap(self.images_analyses['factiva_xml'])
302         fact_from_mail = wx.MenuItem(menuFactiva, ID_Fact_mail, _("from mail"))
303         fact_from_mail.SetBitmap(self.images_analyses['factiva_mail'])
304         fact_from_txt = wx.MenuItem(menuFactiva, ID_Fact_copy, _("from copy/paste"))
305         fact_from_txt.SetBitmap(self.images_analyses['factiva_copy'])
306         menuFactiva.Append(fact_from_xml)
307         menuFactiva.Append(fact_from_mail)
308         menuFactiva.Append(fact_from_txt)
309         file_menu.Append(-1, _("Import from factiva"), menuFactiva)
310
311         menuTools = wx.Menu()
312         splitvar = wx.MenuItem(menuTools, wx.ID_ANY, _("Split from variable"))
313         extractmod = wx.MenuItem(menuTools, wx.ID_ANY, _("Extract mods"))
314         extractthem = wx.MenuItem(menuTools, wx.ID_ANY, _("Extract thematics"))
315         menuTools.Append(splitvar)
316         menuTools.Append(extractmod)
317         menuTools.Append(extractthem)
318         self.ID_splitvar = splitvar.GetId()
319         self.ID_extractmod = extractmod.GetId()
320         self.ID_extractthem = extractthem.GetId()
321         file_menu.Append(-1, _("Tools"), menuTools)
322
323         # ???
324         #item = wx.MenuItem(file_menu, ID_SaveTab, _(u"Save tab as..."), _(u"Save tab as..."))
325         #item.SetBitmap(wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS))
326         #file_menu.AppendItem(item)
327
328         file_menu.Append(wx.ID_EXIT, _("Exit"))
329         # sous macOS cet élément est apparemment déplacé automatiquement vers le menu 'pomme' ???
330
331         # menu 'Edition' de la barre de menu (en haut de l'écran)
332         # sous macOS, il est déplacé dans le menu 'App'
333         # alors que le menu édition (copier/coller etc. reste vide)
334         edit_menu = wx.Menu()
335         pref = wx.MenuItem(edit_menu, wx.ID_PREFERENCES, _('Preferences'))
336         pref.SetBitmap(self.images_analyses['preferences'])
337         edit_menu.Append(pref)
338
339         # menu 'Vue' de la barre de menu (en haut de l'écran)
340         view_menu = wx.Menu()
341         home = wx.MenuItem(view_menu, ID_ACCEUIL, _("Home page"))
342         home.SetBitmap(wx.ArtProvider.GetBitmap(wx.ART_GO_HOME, size = (16,16)))
343         view_menu.Append(home)
344         results = wx.MenuItem(view_menu, ID_RESULT, _('Show results'))
345         results.SetBitmap(wx.ArtProvider.GetBitmap(wx.ART_LIST_VIEW, size = (16,16)))
346         view_menu.Append(results)
347
348         # menu 'Analyses de matrice' de la barre de menu (en haut de l'écran)
349         matrix_menu = wx.Menu()
350         matanalyses = [[ID_Freq, _("Frequencies"), 'freq'],
351                        [ID_FreqMulti, _("Multiple  Frequencies"), 'freqmulti'],
352                        [ID_Chi2, _("Chi2"), 'chi2'],
353                        [ID_Chi2mc, _("Chi2 McNemar"), 'chi2mcnemar'],
354                        {'name' : _("Clustering"),
355                         'content' : [[ID_CHDReinert, _("Reinert's Method"), 'reinertmatrix']]
356                        },
357                        [ID_SIMI, _("Similarities Analysis"), 'simimatrix'],
358                        [ID_proto, _("Prototypical Analysis"), 'proto'],
359                        [ID_Splitfromvar, _("Split from variable"), 'subcorpusmeta'],
360                        [ID_CATE, _("ElCaTeGoRiZatoR"), 'categorisation'],
361                       ]
362         for analyse in matanalyses :
363             if not isinstance(analyse, dict) :
364                 item = wx.MenuItem(matrix_menu, analyse[0], analyse[1])
365                 item.SetBitmap(self.images_analyses.get(analyse[2], wx.Bitmap(16,16)))
366                 matrix_menu.Append(item)
367             else :
368                 nmenu = wx.Menu()
369                 for subana in analyse['content'] :
370                     item = wx.MenuItem(nmenu, subana[0], subana[1])
371                     item.SetBitmap(self.images_analyses.get(subana[2], wx.Bitmap(16,16)))
372                     nmenu.Append(item)
373                 matrix_menu.Append(-1, analyse['name'], nmenu)
374         self.matrix_menu = matrix_menu
375
376         # menu 'Analyse de texte' de la barre de menu (en haut de l'écran)
377         text_menu = wx.Menu()
378         analyses_text = [[ID_TEXTSTAT, _("Statistics"), 'stat'],
379                          [ID_ASLEX, _("Specificities and CA"), 'spec'],
380                          [ID_labbe, _("Labbe Distance"),'labbe'],
381                          {'name' : _("Clustering"),
382                           'content' : [[ID_TEXTREINERT, _("Reinert's Method"), 'alceste']]
383                          },
384                          [ID_SimiTxt, _("Similarities Analysis"), 'simitxt'],
385                          [ID_WC, _("WordCloud"), 'wordcloud'],
386                          {'name' : _("Sub corpus"),
387                           'content' : [[ID_Subtxtfrommeta, _('Sub corpus from metadata'), 'subcorpusmeta'],
388                                        [ID_Subtxtfromthem, _('Sub corpus from thematic'), 'subcorpusthema']]
389                          },
390                          [ID_exportmeta, _("Export metadata table"), 'exportmetatable'],
391                         ]
392         for analyse in analyses_text :
393             if not isinstance(analyse, dict) :
394                 item = wx.MenuItem(text_menu, analyse[0], analyse[1])
395                 item.SetBitmap(self.images_analyses.get(analyse[2], wx.Bitmap(16,16)))
396                 text_menu.Append(item)
397             else :
398                 nmenu = wx.Menu()
399                 for subana in analyse['content'] :
400                     item = wx.MenuItem(nmenu, subana[0], subana[1])
401                     item.SetBitmap(self.images_analyses.get(subana[2], wx.Bitmap(16,16)))
402                     nmenu.Append(item)
403                 text_menu.Append(-1, analyse['name'], nmenu)
404         self.text_menu = text_menu
405
406         # menu 'Aide' et 'A propos' de la barre de menu (en haut de l'écran)
407         # mais le "à propos est déplacé par macOS sous le menu "Pomme"
408         # et il n'a pas d'action apparemment
409         help_menu = wx.Menu()
410         about = wx.MenuItem(help_menu, wx.ID_ABOUT, _("About..."))
411         about.SetBitmap(wx.ArtProvider.GetBitmap(wx.ART_INFORMATION, size = (16,16)))
412         help_menu.Append(about)
413         help = wx.MenuItem(help_menu, wx.ID_HELP, _("Online help..."))
414         help.SetBitmap(wx.ArtProvider.GetBitmap(wx.ART_HELP, size = (16,16)))
415         help_menu.Append(help)
416
417         # après avoir construit chaque menu, on les ajoute à barre de menu (en haut de l'écran)
418         self.mb.Append(file_menu, _("File"))
419         self.mb.Append(edit_menu, _("Edition"))
420         self.mb.Append(view_menu, _("View"))
421         self.mb.Append(matrix_menu, _("Matrix analysis"))
422         self.mb.Append(text_menu, _("Text analysis"))
423         self.mb.Append(help_menu, _("Help"))
424         self.SetMenuBar(self.mb)
425
426         #--------------------------------------------------------------------
427         # barre de statut : sur macOS, c'est la barre en bas de la fenêtre Iramuteq
428         #--------------------------------------------------------------------
429         self.statusbar = self.CreateStatusBar(2, wx.STB_SIZEGRIP)
430         self.statusbar.SetStatusWidths([-2, -3])
431         self.statusbar.SetStatusText(_("Ready"), 0)
432         self.statusbar.SetStatusText(_("Welcome"), 1)
433         # min size for the frame itself isn't completely done.
434         # see the end up FrameManager::Update() for the test
435         # code. For now, just hard code a frame minimum size
436         self.SetMinSize(wx.Size(800, 600))
437
438         #--------------------------------------------------------------------
439         # barre d'outils : le menu de petits icones en haut de la fenetre
440         # il y en a 4 : tb1, tb_text, tb_mat, tb_help
441         #--------------------------------------------------------------------
442         # tb1
443         tb1 = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.TB_FLAT | wx.TB_NODIVIDER)
444         tb1.SetToolBitmapSize(wx.Size(16, 16))
445         tb1.AddTool(ID_OpenData, "OpenData", self.images_analyses['matroot'], shortHelp=_("Open a matrix"))
446         tb1.AddSeparator()
447         tb1.AddTool(ID_OpenText, "OpenText", self.images_analyses['textroot'], shortHelp=_("Open a text corpus"))
448         tb1.AddSeparator()
449         tb1.AddTool(ID_OnOpenAnalyse, "OpenAnalyse", self.images_analyses['iramuteq'], shortHelp= _("Open an analysis"))
450         tb1.AddSeparator()
451         tb1.AddTool(ID_ImportTXM, "ImportTXM", self.images_analyses['TXM'], shortHelp= _("Import from TXM"))
452         tb1.AddSeparator()
453         tb1.AddTool(ID_ImportEuro, "ImportEuro", self.images_analyses['europress'], shortHelp= _("Import from Europress"))
454         tb1.AddSeparator()
455         tb1.AddTool(ID_importdmi, "ImportDMI", self.images_analyses['importdmi'], shortHelp= _("Import from DMI-TCAT (exp.)"))
456         tb1.AddSeparator()
457         tb1.AddTool(ID_Fact_xml, "ImportFactxml", self.images_analyses['factiva_xml'], shortHelp= _("Factiva from xml"))
458         tb1.AddTool(ID_Fact_mail, "ImportFactmail", self.images_analyses['factiva_mail'], shortHelp= _("Factiva from mail"))
459         tb1.AddTool(ID_Fact_copy, "ImportFactcopy", self.images_analyses['factiva_copy'], shortHelp= _("Factiva from copy/paste"))
460         tb1.AddSeparator()
461         tb1.AddTool(wx.ID_PREFERENCES, "Preferences", self.images_analyses['preferences'], shortHelp= _("Preferences"))
462         tb1.AddSeparator()
463         tb1.AddTool(ID_ACCEUIL, "Home", wx.ArtProvider.GetBitmap(wx.ART_GO_HOME, size = (16,16)), shortHelp= _("Home page"))
464         tb1.AddTool(ID_RESULT, "Results", wx.ArtProvider.GetBitmap(wx.ART_LIST_VIEW, size = (16,16)), shortHelp= _('Show results'))
465         tb1.Realize()
466         # tb_text
467         tb_text = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.TB_FLAT | wx.TB_NODIVIDER)
468         for analyse in analyses_text :
469             if not isinstance(analyse, dict) :
470                 tb_text.AddTool(analyse[0], analyse[1], self.images_analyses.get(analyse[2], wx.Bitmap(16,16)), shortHelp = analyse[1])
471             else :
472                 for subana in analyse['content'] :
473                     tb_text.AddTool(subana[0], subana[1], self.images_analyses.get(subana[2], wx.Bitmap(16,16)), shortHelp = subana[1])
474         tb_text.Realize()
475         # tb_mat
476         tb_mat = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.TB_FLAT | wx.TB_NODIVIDER)
477         for analyse in matanalyses :
478             if not isinstance(analyse, dict) :
479                 tb_mat.AddTool(analyse[0], analyse[1], self.images_analyses.get(analyse[2], wx.Bitmap(16,16)), shortHelp = analyse[1])
480             else :
481                 for subana in analyse['content'] :
482                     tb_mat.AddTool(subana[0], subana[1], self.images_analyses.get(subana[2], wx.Bitmap(16,16)), shortHelp = subana[1])
483         tb_mat.Realize()
484         #tb_help
485         tb_help = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.TB_FLAT | wx.TB_NODIVIDER)
486         tb_help.AddTool(wx.ID_ABOUT, "About", wx.ArtProvider.GetBitmap(wx.ART_INFORMATION, size=(16,16)), shortHelp=_("About..."))
487         tb_help.AddTool(wx.ID_HELP, "Help", wx.ArtProvider.GetBitmap(wx.ART_HELP, size=(16,16)), shortHelp=_("Online help..."))
488         tb_help.Realize()
489
490         # ???
491         self.text_ctrl_txt = wx.TextCtrl(self, -1, "", wx.Point(0, 0), wx.Size(200, 200), wx.NO_BORDER | wx.TE_MULTILINE | wx.TE_RICH2 | wx.TE_READONLY)
492         self._mgr.AddPane(self.text_ctrl_txt, aui.AuiPaneInfo().Name("Text").CenterPane())
493         self._mgr.AddPane(IntroPanel(self), aui.AuiPaneInfo().Name("Intro_Text").CenterPane())
494
495         #------------------------------------------------------------------------------------------------
496         # fichier d'historique de Iramuteq
497         #------------------------------------------------------------------------------------------------
498         if not os.path.exists(os.path.join(UserConfigPath, 'history.db')) :
499             with open(os.path.join(UserConfigPath, 'history.db'), 'w') as f :
500                 f.write('{}')
501         self.history = History(os.path.join(UserConfigPath, 'history.db'))
502         # l'extension ".db" est ajoutée automatiquement par le module
503
504         #------------------------------------------------------------------------------------------------
505         # colonne gauche de la fenetre de Iramuteq, classe "Lefttree"
506         #------------------------------------------------------------------------------------------------
507         #self.history.dostat()
508         self.tree = LeftTree(self)
509         self._mgr.AddPane(self.tree,
510             aui.AuiPaneInfo().
511             Name("lefttree").
512             Caption(_("Historic")).
513             Left().
514             MinSize(wx.Size(300,400)).
515             Layer(1).
516             Position(1).
517             CloseButton(False).
518             MaximizeButton(True).
519             MinimizeButton(True))
520
521         self.nb = aui.AuiNotebook(self,
522             -1,
523             wx.DefaultPosition,
524             wx.DefaultSize,
525             aui.AUI_NB_DEFAULT_STYLE)
526             # | aui.AUI_NB_TAB_EXTERNAL_MOVE | aui.AUI_NB_TAB_MOVE | aui.AUI_NB_TAB_FLOAT | wx.NO_BORDER)
527         notebook_flags = aui.AUI_NB_DEFAULT_STYLE
528         # | aui.AUI_NB_TAB_EXTERNAL_MOVE | aui.AUI_NB_TAB_MOVE | aui.AUI_NB_TAB_FLOAT| wx.NO_BORDER
529         self.nb.SetAGWWindowStyleFlag(notebook_flags)
530         self.nb.SetArtProvider(aui.ChromeTabArt())
531         #self.nb.SetArtProvider(aui.VC8TabArt())
532         #self.nb.parent = self
533         #self._notebook_style = aui.AUI_NB_DEFAULT_STYLE | aui.AUI_NB_TAB_EXTERNAL_MOVE | wx.NO_BORDER
534
535         #------------------------------------------------------------------------------------------------
536         # colonne droite de la fenetre de Iramuteq "Tab_content"
537         #------------------------------------------------------------------------------------------------
538         self._mgr.AddPane(self.nb,
539             aui.AuiPaneInfo().
540             Name("Tab_content").
541             CenterPane())
542         #self._mgr.AddPane(self.Sheet, wx.aui.AuiPaneInfo().Name("Data").CenterPane())
543         #self._mgr.AddPane(self.Sheet, aui.AuiPaneInfo().Name("Data").CenterPane())
544         self.nb.Bind(aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnCloseTab)
545         self.nb.Bind(aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
546
547         #------------------------------------------------------------------------------------------------
548         # ajout des toolbars à la fenetre de Iramuteq
549         # Iramuteq n'utilise pas directement les 'toolbar' au sens de wx.python
550         # mais en fait des ToolbarPane ???
551         #------------------------------------------------------------------------------------------------
552         self._mgr.AddPane(tb1, aui.AuiPaneInfo().
553             Name("tb1").
554             Caption("Fichiers").
555             ToolbarPane().
556             Top().
557             LeftDockable(True).
558             RightDockable(False))
559         self._mgr.AddPane(tb_text, aui.AuiPaneInfo().
560             Name("tb_text").
561             Caption("analyse_text").
562             ToolbarPane().
563             Top().
564             LeftDockable(True).
565             RightDockable(False))
566         self._mgr.AddPane(tb_mat, aui.AuiPaneInfo().
567             Name("tb_mat").
568             Caption("analyse_matrix").
569             ToolbarPane().
570             Top().
571             LeftDockable(True).
572             RightDockable(False))
573         self._mgr.AddPane(tb_help, aui.AuiPaneInfo().
574             Name("tb_help").
575             Caption("help").
576             ToolbarPane().
577             Top().
578             LeftDockable(True).
579             RightDockable(False))
580 # ces deux toolbars sont cachées car elles dépendent du contexte des éléments sélectionnés dans lefttree
581         self._mgr.GetPane('tb_text').Hide()
582         self._mgr.GetPane('tb_mat').Hide()
583
584         self.ShowAPane("Intro_Text")
585         self._mgr.GetPane("lefttree").Show()
586         self._mgr.GetPane("classif_tb").Hide() # utilisé nulle part ailleurs que sur cette ligne ???
587         # "commit" all changes made to FrameManager
588         #self._mgr.Update()
589
590         # Attache les événements aux éléments d'interface
591         self.Bind(wx.EVT_MENU, self.OnAcceuil, id=ID_ACCEUIL)
592         self.Bind(wx.EVT_MENU, self.ShowTab, id=ID_RESULT)
593         self.Bind(wx.EVT_MENU, self.OnOpenData, id=ID_OpenData)
594         self.Bind(wx.EVT_MENU, self.OnOpenText, id=ID_OpenText)
595         self.Bind(wx.EVT_MENU, self.OnOpenAnalyse, id=ID_OnOpenAnalyse)
596         self.Bind(wx.EVT_MENU, self.import_factiva_xml, fact_from_xml)
597         self.Bind(wx.EVT_MENU, self.import_factiva_mail, fact_from_mail)
598         self.Bind(wx.EVT_MENU, self.import_factiva_txt, fact_from_txt)
599         self.Bind(wx.EVT_MENU, self.ExtractTools, splitvar)
600         self.Bind(wx.EVT_MENU, self.ExtractTools, extractmod)
601         self.Bind(wx.EVT_MENU, self.ExtractTools, extractthem)
602         self.Bind(wx.EVT_MENU, self.OnFreq, id=ID_Freq)
603         self.Bind(wx.EVT_MENU, self.OnFreqMulti, id=ID_FreqMulti)
604         self.Bind(wx.EVT_MENU, self.OnChi2, id=ID_Chi2)
605         self.Bind(wx.EVT_MENU, self.OnChi2McNemar, id=ID_Chi2mc)
606         self.Bind(wx.EVT_MENU, self.OnStudent, id=ID_Student)
607         self.Bind(wx.EVT_MENU, self.OnCHDSIM, id=ID_CHDSIM)
608         self.Bind(wx.EVT_MENU, self.OnCHDReinert, id=ID_CHDReinert)
609         self.Bind(wx.EVT_MENU, self.OnAFCM, id=ID_AFCM)
610         self.Bind(wx.EVT_MENU, self.OnProto, id=ID_proto)
611         self.Bind(wx.EVT_MENU, self.OnSplitVar, id = ID_Splitfromvar)
612         self.Bind(wx.EVT_MENU, self.OnCategorisation, id = ID_CATE)
613         #self.Bind(wx.EVT_MENU, self.OnRCode, id=ID_RCODE) #???
614         #self.Bind(wx.EVT_MENU, self.OnSplitVar, id=ID_SPLITVAR) #???
615         #self.Bind(wx.EVT_MENU, self.OnCheckcorpus, id = ID_CHECKCORPUS) #???
616         self.Bind(wx.EVT_MENU, self.OnTextStat, id=ID_TEXTSTAT)
617         self.Bind(wx.EVT_MENU, self.OnTextSpec, id=ID_ASLEX)
618         self.Bind(wx.EVT_MENU, self.OnTextLabbe, id=ID_labbe)
619         self.Bind(wx.EVT_MENU, self.OnTextAfcm, id=ID_TEXTAFCM)
620         self.Bind(wx.EVT_MENU, self.OnTextReinert, id=ID_TEXTREINERT)
621         self.Bind(wx.EVT_MENU, self.OnPamSimple, id=ID_TEXTPAM)
622         self.Bind(wx.EVT_MENU, self.OnSimiTxt, id=ID_SimiTxt)
623         self.Bind(wx.EVT_MENU, self.OnWordCloud, id=ID_WC)
624         self.Bind(wx.EVT_MENU, self.OnSubText, id = ID_Subtxtfrommeta)
625         self.Bind(wx.EVT_MENU, self.OnSubText, id = ID_Subtxtfromthem)
626         self.Bind(wx.EVT_MENU, self.OnSimiTab, id=ID_SIMI)
627         self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT)
628         #self.Bind(wx.EVT_MENU, self.OnSaveTabAs, id=ID_SaveTab) #???
629         self.Bind(wx.EVT_MENU, self.OnAbout, id=wx.ID_ABOUT)
630         self.Bind(wx.EVT_MENU, self.OnHelp, id=wx.ID_HELP)
631         self.Bind(wx.EVT_MENU, self.OnPref, id=wx.ID_PREFERENCES)
632         self.Bind(wx.EVT_MENU, self.OnImportTXM, id=ID_ImportTXM)
633         self.Bind(wx.EVT_MENU, self.OnImportEuropress, id=ID_ImportEuro)
634         self.Bind(wx.EVT_MENU, self.OnImportDMI, id=ID_importdmi)
635         self.Bind(wx.EVT_MENU, self.OnExportMeta, id=ID_exportmeta)
636         self.Bind(wx.EVT_MENU, self.OnMergeGraph, id = ID_merge)
637         self.Bind(wx.EVT_MENU, self.OnMergeClusters, id = ID_merge_clusters)
638         self.Bind(wx.EVT_CLOSE, self.OnClose)
639
640         flags = self._mgr.GetAGWFlags()
641         #flags &= ~wx.aui.AUI_MGR_TRANSPARENT_HINT
642         #flags &= ~wx.aui.AUI_MGR_VENETIAN_BLINDS_HINT
643         #flags &= ~wx.aui.AUI_MGR_RECTANGLE_HINT
644         flags &= ~(aui.AUI_MGR_RECTANGLE_HINT | aui.AUI_MGR_ALLOW_FLOATING)
645         self._mgr.SetAGWFlags(self._mgr.GetAGWFlags() ^ (aui.AUI_MGR_RECTANGLE_HINT | aui.AUI_MGR_ALLOW_FLOATING))
646         self._mgr.GetArtProvider().SetMetric(aui.AUI_DOCKART_GRADIENT_TYPE, aui.AUI_GRADIENT_HORIZONTAL)
647         self.GetDockArt().SetColor(aui.AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR, "#00FFF9")
648         #self.DoUpdate()
649         self._icon = wx.Icon(os.path.join(ImagePath, "iraicone.ico"), wx.BITMAP_TYPE_ICO)
650         self.SetIcon(self._icon)
651
652         self.ctrl = ""
653         self.input_path = [False]
654         self.TEMPDIR = tempfile.mkdtemp('iramuteq')
655         self.FileTabList = []
656         self.listbar=[]
657         self.DictTab = {}
658         self.FreqNum = 0
659         self.colsep = ''
660         self.txtsep = ''
661         self.g_header = False
662         self.g_id = False
663         self.table = ''
664         self.fileforR = ''
665         self.filename = ''
666         self.nastrings = ''
667         self.encode = ''
668         self.SysEncoding = sys.getdefaultencoding()
669         self.syscoding = sys.getdefaultencoding()
670         if self.SysEncoding == 'mac-roman' : self.SysEncoding = 'MacRoman'
671         self.type = ''
672         #------------------------------------------------------------------------------------------------
673         # P3
674         # 'view', 'matrix' et 'text' sont des valeurs attendues par la fonction ShowMenu
675         #self.ShowMenu('view', True)
676         #self.ShowMenu('matrix', False)
677         #self.ShowMenu('text', False)
678         # je commente ces trois lignes car je ne comprends pas
679         # mais je les garde pour le moment, au cas où il y a un mécanisme que je n'ai pas encore compris
680         #------------------------------------------------------------------------------------------------
681         self._mgr.Update()
682         self.DataPop = False
683         self.DataTxt = False
684         self.Text = ''
685         self.lexique = None
686         self.corpus = None
687
688     def finish_init(self) :
689         try :
690             self.pref.read(self.ConfigPath['preferences'])
691             if IsNew(self) :
692                 UpgradeConf(self)
693                 self.pref.read(self.ConfigPath['preferences'])
694                 New = True
695             else :
696                 CopyConf(self)
697                 New = False
698         except :
699             UpgradeConf(self)
700             self.pref.read(self.ConfigPath['preferences'])
701             New = True
702         self.sound = self.pref.getboolean('iramuteq', 'sound')
703         self.check_update = self.pref.getboolean('iramuteq', 'checkupdate')
704         self.version = ConfigGlob.get('DEFAULT', 'version')
705         # configuration des chemins de R
706         self.PathPath = ConfigParser()
707         self.PathPath.read(ConfigPath['path'])
708         BestRPath = False
709         if not CheckRPath(self.PathPath) :
710             if sys.platform == 'win32':
711                 if os.path.exists(self.AppliPath + '\\R\\R\\x64\\R.exe') :
712                     BestRPath = self.AppliPath + '\\R\\R\\bin\\x64\\R.exe'
713                 elif os.path.exists(self.AppliPath + '\\R\\R\\i386\\R.exe') :
714                     BestRPath = self.AppliPath + '\\R\\R\\bin\\i386\\R.exe'
715                 else :
716                     BestRPath = FindRPAthWin32()
717             elif os.path.exists(self.AppliPath + '/R/R') :
718                 BestRPath = self.AppliPath + '/R/R'
719             else:
720                 BestRPath = FindRPathNix()
721             if BestRPath:
722                 self.PathPath.set('PATHS', 'rpath', BestRPath)
723                 with open(ConfigPath['path'], 'w') as f :
724                     self.PathPath.write(f)
725         else:
726             BestRPath = True
727         if BestRPath :
728             self.RPath = self.PathPath.get('PATHS', 'rpath')
729             if New :
730                 CheckRPackages(self)
731             if not RLibsAreInstalled(self) :
732                 CheckRPackages(self)
733         else :
734             msg = '\n'.join([_("Can't find R executable"), _("If R is not installed, get it from http://www.r-project.org."),
735                              _("If R is installed, report its path in Preferences."),
736                              _("IRaMuTeQ does not work without R.")])
737             dlg = wx.MessageDialog(self, msg, _("Problem"), wx.OK | wx.ICON_WARNING)
738             dlg.CenterOnParent()
739             if dlg.ShowModal() in [wx.ID_NO, wx.ID_CANCEL]:
740                 pass
741             dlg.Destroy()
742
743     def OnVerif(self, evt) :
744         pack = CheckRPackages(self)
745         if pack :
746             dlg = wx.MessageDialog(self, _("Installation OK"), _("Installation"), wx.OK | wx.ICON_INFORMATION | wx.STAY_ON_TOP)
747             dlg.CenterOnParent()
748             if dlg.ShowModal() in [wx.ID_NO, wx.ID_CANCEL]:
749                 evt.Veto()
750
751     # appelé par des fonctions de ce fichier et tree.py : OnSelChanged
752     # vu comme elle est écrite, impossible de gérer
753     # l'affichage/masquage des toolbars en fonction du contexte
754     def ShowMenu(self, menu, Show=True):
755         if menu == 'text' :
756             menu_pos = 4
757             if Show :
758                 if self._mgr.GetPane('tb_text').IsShown()  :
759                     return
760                 self._mgr.GetPane('tb_text').Show()
761                 self._mgr.GetPane('tb_mat').Hide()
762                 self.mb.EnableTop(menu_pos, Show)
763                 self.mb.EnableTop(3, False)
764             else :
765                 self._mgr.GetPane('tb_text').Hide()
766         elif menu == 'matrix' :
767             menu_pos = 3
768             if Show :
769                 if self._mgr.GetPane('tb_mat').IsShown():
770                     return
771                 self._mgr.GetPane('tb_mat').Show()
772                 self._mgr.GetPane('tb_text').Hide()
773                 self.mb.EnableTop(menu_pos, Show)
774                 self.mb.EnableTop(4, False)
775             else :
776                 self._mgr.GetPane('tb_mat').Hide()
777         elif menu == 'view' :
778             menu_pos = 2
779         else :
780             menu_pos = None
781         if not menu_pos is None :
782             #self.mb.EnableTop(menu_pos, Show)
783             self.mb.Refresh()
784         self._mgr.Update()
785         self.Refresh()
786
787     #--------------------------------------------------------------------
788     # fin de __init__ du wx.Frame
789     #--------------------------------------------------------------------
790
791     # evenement attaché au bouton de fermeture des fenetres ou onglets ?
792     def OnClose(self, event):
793         print('onclose Iramuteq')
794         with open(self.ConfigPath['path'], 'w') as f :
795             self.PathPath.write(f)
796         self._mgr.UnInit()
797         del self._mgr
798         self.Destroy()
799
800     # evenement attaché au menu 'ouvrir matrice'
801     def OnOpenData(self, event):
802         print('on open data')
803         inputname, self.input_path = OnOpen(self, "Data")
804         if inputname:
805             # filename = self.input_path[0]
806             self.tableau = Tableau(self,os.path.abspath(self.input_path[0]))
807             val = get_table_param(self, self.input_path[0])
808             if val == wx.ID_OK :
809                 busy = wx.BusyInfo(_("Please wait..."), self)
810                 wx.SafeYield()
811                 try :
812                     self.tableau.make_content()
813                     OpenAnalyse(self, self.tableau.parametres)
814                     self.tree.OnItemAppend(self.tableau.parametres)
815                     del busy
816                 except :
817                     del busy
818                     BugReport(self)
819                 # self.tableau.show_tab()
820
821     # evenement attaché au menu 'ouvrir analyse'
822     def OnOpenAnalyse(self, event):
823         print('on open analyse')
824         self.AnalysePath = OnOpen(self, "Analyse")
825         if self.AnalysePath :
826             OpenAnalyse(self, self.AnalysePath[1][0], True)
827             self.ShowMenu('view')
828
829     # evenement attaché au menu 'ouvrir un texte/corpus'
830     def OnOpenText(self, event):
831         print('on open text')
832         inputname, self.input_path = OnOpen(self, "Texte")
833         self.filename = self.input_path[0]
834         if inputname:
835             self.OpenText()
836
837     # evenement attaché au menu 'ouvrir analyse'
838     def OnSubText(self, evt, corpus = None, parametres = None):
839         print('on sub text')
840         if corpus is None :
841             corpus = self.tree.getcorpus()
842         if evt.GetId() == ID_Subtxtfrommeta :
843             parametres = {'frommeta' : True}
844         elif evt.GetId() == ID_Subtxtfromthem :
845             parametres = {'fromtheme' : True}
846         builder = SubBuilder(self, corpus, parametres)
847         if builder.res == wx.ID_OK :
848             busy = wx.BusyInfo(_("Please wait..."), self)
849             wx.SafeYield()
850             corpus = builder.doanalyse()
851             self.history.add(corpus.parametres)
852             OpenAnalyse(self, corpus.parametres)
853             self.tree.OnItemAppend(corpus.parametres)
854             del busy
855
856     # action d'ouverture d'un texte
857     def OpenText(self):
858         print('open text')
859         builder =  Builder(self, 5)
860         if builder.res == wx.ID_OK :
861             try :
862                 corpus = builder.doanalyse()
863                 self.history.add(corpus.parametres)
864                 self.tree.OnItemAppend(corpus.parametres)
865                 OpenAnalyse(self, corpus.parametres)
866             except :
867                 builder.dlg.Destroy()
868                 BugReport(self)
869             else :
870                 count = 1
871                 keepGoing = builder.dlg.Update(count, "Lecture du fichier")
872                 self.ShowMenu('view')
873                 self.ShowMenu('text')
874                 self.ShowMenu('matrix', False)
875                 self.type = "Texte"
876                 self.DataTxt = False
877                 self.Text = ''
878                 count += 1
879                 keepGoing = builder.dlg.Update(count, "Chargement du dictionnaire")
880                 builder.dlg.Destroy()
881
882     # evenement attaché au menu 'quitter'
883     def OnExit(self, event):
884         self.Close()
885
886     # evenement attaché au menu 'à propos'
887     def OnAbout(self, event):
888         print('on about')
889         info = wx.adv.AboutDialogInfo()
890         info.Name = ConfigGlob.get('DEFAULT', 'name')
891         info.Version = ConfigGlob.get('DEFAULT', 'version')
892         info.Copyright = ConfigGlob.get('DEFAULT', 'copyright')
893         info.Translators = ConfigGlob.get('DEFAULT', 'translators').split(';')
894         info.Description = """
895 Interface de R pour les Analyses Multidimensionnelles
896 de Textes et de Questionnaires
897
898 Un logiciel libre
899 construit avec des logiciels libres.
900
901 Laboratoire LERASS
902
903 REPERE
904 """
905         info.WebSite = ("http://www.iramuteq.org", "Site web IRaMuTeQ")
906         dev = ConfigGlob.get('DEFAULT', 'dev').split(';')
907         info.Developers = dev
908         info.License = """Iramuteq est un logiciel libre ; vous pouvez le diffuser et/ou le modifier
909 suivant les termes de la Licence Publique Générale GNU telle que publiée 
910 par la Free Software Foundation ; soit la version 2 de cette licence, 
911 soit (à votre convenance) une version ultérieure.
912
913 Iramuteq est diffusé dans l'espoir qu'il sera utile, 
914 mais SANS AUCUNE GARANTIE ; sans même une garantie implicite 
915 de COMMERCIALISATION ou d'ADÉQUATION À UN USAGE PARTICULIER. 
916 Voyez la Licence Publique Générale GNU pour plus de détails.
917
918 Vous devriez avoir reçu une copie de la Licence Publique Générale GNU
919 avec Iramuteq ; sinon, veuillez écrire à la Free Software Foundation,
920 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, États-Unis."""
921         wx.adv.AboutBox(info)
922
923     # appelé seulement pour l'initialisation de la fenetre principale de Iramuteq
924     def GetDockArt(self):
925         return self._mgr.GetArtProvider()
926
927     # appelé seulement pour l'initialisation de la fenetre principale de Iramuteq
928     def DoUpdate(self):
929         self._mgr.Update()
930
931     # action ou évènement ?
932     def OnPageChanged(self, event) :
933         new = event.GetSelection()
934         nobject = event.GetEventObject()
935         parent = nobject.GetParent()
936         if isinstance(parent, IraFrame) :
937             npage = self.nb.GetPage(new)
938             if 'parametres' in dir(npage) :
939                 self.tree.GiveFocus(uuid=npage.parametres['uuid'])
940
941     # action ou évènement ?
942     def OnCloseTab(self, evt):
943         #log.info('Closing tab %s' % str(evt.GetEventObject()))
944         ctrl = evt.GetEventObject()
945         if isinstance(ctrl.GetParent(), aui.AuiNotebook) or isinstance(ctrl.GetParent(), wx.Panel):
946             notebook = True
947         else :
948             notebook = False
949         page = self.nb.GetPage(self.nb.GetSelection())
950         if 'parametres' in dir(page) and isinstance(ctrl.GetParent(), IraFrame) :
951             self.history.rmtab(page.parametres)
952             self.tree.CloseItem(uuid = page.parametres['uuid'])
953         TabTitle = self.nb.GetPageText(self.nb.GetSelection())
954         if self.nb.GetPageCount() == 1 and not notebook :
955             self.LastTabClose()
956
957     # action ou évènement ?
958     def LastTabClose(self) :
959         if self.nb.GetPageCount() == 1 :
960             if self.DataTxt :
961                 self.ShowAPane("Text")
962             elif self.DataPop :
963                 self.ShowAPane("Data")
964             else :
965                 self.ShowAPane("Intro_Text")
966
967     # action ou évènement ?
968     def GetStartPosition(self):
969         self.x = self.x + 20
970         x = self.x
971         pt = self.ClientToScreen(wx.Point(0, 0))
972         return wx.Point(pt.x + x, pt.y + x)
973
974     # action ou évènement ?
975     def ShowAPane(self, panel):
976         print('ShowAPane')
977         for pane in self._mgr.GetAllPanes() :
978             if not pane.IsToolbar() and pane.name != 'lefttree':
979                 pane.Hide()
980         self._mgr.GetPane(panel).Show()
981         self._mgr.Update()
982         wx.CallAfter(self.nb.SendSizeEvent)
983         self.Refresh()
984
985     # action ou évènement ?
986     def OnAcceuil(self, event):
987         self.ShowAPane("Intro_Text")
988         event.Skip()
989
990     # action ou évènement ?
991     def CreateHTMLCtrl(self):
992         ctrl = wx.html.HtmlWindow(self, -1, wx.DefaultPosition, wx.Size(400, 300))
993         if "gtk2" in wx.PlatformInfo:
994             ctrl.SetStandardFonts()
995         ctrl.SetPage("text")
996         return ctrl
997
998     # action ou évènement ?
999     def ShowTab(self, evt):
1000         self.ShowAPane("Tab_content")
1001
1002     ################################################################
1003     #debut des analyses
1004     ################################################################
1005     def analyse_matrix(self, analyse, analyse_type = '', matrix = None, parametres = None, dlgnb = 1):
1006         if matrix is None :
1007             matrix = self.tree.getmatrix()
1008         if parametres is not None :
1009             parametres['type'] = analyse_type
1010         else :
1011             parametres = {'type' : analyse_type}
1012         try :
1013             #print 'plus de bug@@@@@@@@@@@@@@@@@@@@@@'
1014             analyse(self, matrix, parametres = parametres, dlg = dlgnb)
1015         except:
1016             BugReport(self)
1017
1018     def OnFreq(self, event, matrix = None):
1019         self.analyse_matrix(Frequences, analyse_type = 'freq', matrix = matrix, dlgnb = 3)
1020
1021     def OnFreqMulti(self, event, matrix = None):
1022         self.analyse_matrix(FreqMultiple, analyse_type = 'freqmulti', matrix = matrix, dlgnb = 3)
1023
1024     def OnChi2(self, event, matrix = None):
1025         self.analyse_matrix(ChiSquare, matrix = matrix, analyse_type = 'chi2', dlgnb = 3)
1026
1027     def OnChi2McNemar(self, event, matrix = None):
1028         self.analyse_matrix(McNemar, matrix = matrix, analyse_type = 'chi2mcnemar', dlgnb = 3)
1029
1030     def OnSimiTab(self, event, matrix = None):
1031         self.analyse_matrix(DoSimi, matrix = matrix, analyse_type = 'simimatrix', dlgnb = 5)
1032
1033     def OnCategorisation(self, event, matrix = None) :
1034         self.analyse_matrix(Categorisation, matrix = matrix, analyse_type = 'categorisation', dlgnb = 1)
1035
1036
1037     def OnCHDReinert(self, event, matrix = None):
1038         #if matrix is None :
1039         #    matrix = self.tree.getmatrix()
1040         #AnalyseQuest(self, matrix, parametres = {'type' : 'reinertmatrix'}, dlg = 3)
1041         self.analyse_matrix(AnalyseQuest, matrix = matrix, analyse_type = 'reinertmatrix', dlgnb = 5)
1042
1043     def OnStudent(self, event):
1044         try:
1045             MakeStudent(self)
1046         except:
1047             BugReport(self)
1048
1049     def OnRCode(self, event):
1050         try:
1051             InputText(self)
1052         except:
1053             BugReport(self)
1054
1055     def OnCHDSIM(self, event):
1056         try:
1057             chdsim = ChdCluster(self)
1058             if chdsim.val == wx.ID_OK:
1059                 PlaySound(self)
1060         except:
1061             BugReport(self)
1062
1063 #     def OnCHDReinert(self, event):
1064 #         try:
1065 #          #   print('PLUS DE BUG SUR ALCESTE QUESTIONNAIRE')
1066 #             self.quest = AnalyseQuest(self)
1067 #             if self.quest.val == wx.ID_OK:
1068 #                 PlaySound(self)
1069 #         except:
1070 #             BugReport(self)
1071
1072     def OnMergeGraph(self, evt):
1073         #FIXME
1074         AnalyseMerge(self, {'type': 'merge', 'fileout' : '/tmp/test.txt'}, dlg = 5)
1075
1076     def OnMergeClusters(self, evt) :
1077         print('on merge clusters')
1078         builder = MergeClusters(self, {})
1079         if builder.res == wx.ID_OK :
1080             busy = wx.BusyInfo(_("Please wait..."), self)
1081             wx.SafeYield()
1082             corpus = builder.doanalyse()
1083             self.history.add(corpus.parametres)
1084             OpenAnalyse(self, corpus.parametres)
1085             self.tree.OnItemAppend(corpus.parametres)
1086             del busy
1087
1088     def OnProto(self, evt, matrix = None) :
1089         self.analyse_matrix(Prototypical, matrix = matrix, analyse_type = 'proto', dlgnb = 3) 
1090         #Prototypical(self, {'type' : 'proto'})
1091
1092     def OnSplitVar(self, evt, matrix = None):
1093         if matrix is None :
1094             matrix = self.tree.getmatrix()
1095         self.analyse_matrix(SplitMatrixFromVar, matrix = matrix, analyse_type = 'splitvar', parametres = {'pathout': matrix.pathout.dirout}, dlgnb = 3)
1096         #matrix = self.tree.getmatrix()
1097
1098     def OnSimiTxt(self, evt, corpus = None) :
1099         try :
1100             #self.Text = SimiTxt(self)
1101             if corpus is None :
1102                 corpus = self.tree.getcorpus()
1103             self.Text = SimiTxt(self, corpus, parametres = {'type': 'simitxt'}, dlg = 3)
1104             if self.Text.val == wx.ID_OK :
1105                 PlaySound(self)
1106         except :
1107             BugReport(self)
1108
1109     def OnWordCloud(self, evt, corpus = None) :
1110         try :
1111             if corpus is None :
1112                 corpus = self.tree.getcorpus()
1113             self.Text = WordCloud(self, corpus, parametres = {'type' : 'wordcloud'}, dlg = 3)
1114             if self.Text.val == wx.ID_OK :
1115                 PlaySound(self)
1116         except :
1117             BugReport(self)
1118
1119     def OnClusterCloud(self, corpus, parametres = None) :
1120         self.Text = ClusterCloud(self, corpus, parametres = parametres, dlg = 3)
1121
1122     def OnAFCM(self, event):
1123         try:
1124             DoAFCM(self)
1125         except:
1126             BugReport(self)
1127
1128     def OnTextStat(self, event, corpus = None):
1129         try:
1130             if corpus is None :
1131                 corpus = self.tree.getcorpus()
1132             self.Text = Stat(self, corpus, parametres = {'type': 'stat'}, dlg = 7)
1133             if self.Text.val == wx.ID_OK :
1134                 PlaySound(self)
1135         except:
1136             BugReport(self)
1137
1138     def OnTextSpec(self, event, corpus = None):
1139         try:
1140             #self.Text = AsLexico(self)
1141             if corpus is None :
1142                 corpus = self.tree.getcorpus()
1143             self.Text = Lexico(self, corpus, parametres = {'type' : 'spec'}, dlg = 3)
1144             if self.Text.val == wx.ID_OK :
1145                 PlaySound(self)
1146         except:
1147             BugReport(self)
1148
1149     def OnTextLabbe(self, event, corpus = None):
1150         try:
1151             if corpus is None :
1152                 corpus = self.tree.getcorpus()
1153             self.Text = DistLabbe(self, corpus, parametres = {'type' : 'labbe'}, dlg = 3)
1154             if self.Text.val == wx.ID_OK :
1155                 PlaySound(self)
1156         except:
1157             BugReport(self)
1158
1159     def OnTextAfcm(self, event):
1160         try:
1161             AfcUci(self)
1162             PlaySound(self)
1163         except:
1164             BugReport(self)
1165
1166     def import_factiva_xml(self,event):
1167         try :
1168             ImportFactiva(self, 'xml')
1169         except :
1170             BugReport(self)
1171
1172     def import_factiva_mail(self, evt) :
1173         try :
1174             ImportFactiva(self, 'mail')
1175         except :
1176             BugReport(self)
1177
1178     def import_factiva_txt(self, evt) :
1179         try :
1180             ImportFactiva(self, 'txt')
1181         except :
1182             BugReport(self)
1183
1184     def OnImportTXM(self, evt) :
1185         try :
1186             ImportFactiva(self, 'txm')
1187         except :
1188             BugReport(self)
1189
1190     def OnImportEuropress(self, evt) :
1191         try :
1192             ImportFactiva(self, 'euro')
1193         except :
1194             BugReport(self)
1195
1196     def OnImportDMI(self, evt):
1197         ImportDMI(self, {})
1198
1199     def OnExportMeta(self, evt, corpus = None):
1200         if corpus is None :
1201             corpus = self.tree.getcorpus()
1202         try :
1203             ExportMetaTable(self, corpus)
1204         except :
1205             BugReport(self)
1206
1207     def ExtractTools(self, evt) :
1208         ID = evt.GetId()
1209         if ID == self.ID_splitvar :
1210             Extract(self, 'splitvar')
1211         elif ID == self.ID_extractmod :
1212             Extract(self, 'mods')
1213         elif ID == self.ID_extractthem :
1214             Extract(self, 'them')
1215
1216     def OnTextReinert(self, event, corpus = None):
1217         try:
1218             #RunAnalyse(self, corpus, Alceste, OptAlceste)
1219             if corpus is None :
1220                 corpus = self.tree.getcorpus()
1221             self.Text = Reinert(self, corpus, parametres = {'type': 'alceste'}, dlg = 6)
1222             if self.Text.val == wx.ID_OK:
1223                 PlaySound(self)
1224         except:
1225             BugReport(self)
1226
1227     def OnPamSimple(self, event, corpus = None):
1228         try:
1229             if corpus is None :
1230                 corpus = self.tree.getcorpus()
1231             self.Text = AnalysePam(self, corpus, parametres = {'type' : 'pamtxt'}, dlg = 6)
1232             if self.Text.val == wx.ID_OK:
1233                 PlaySound(self)
1234         except:
1235             BugReport(self)
1236
1237     def SimiCluster(self, parametres = {}, fromprof = False, tableau = None) :
1238         self.analyse_matrix(DoSimi, parametres = parametres, analyse_type = 'simiclustermatrix', matrix = tableau, dlgnb = 5)
1239
1240 #    def OnSimi(self,evt):
1241 #        try :
1242 #            self.res = DoSimi(self, param = None)
1243             #self.res = Verges(self)
1244 #            if self.res.val == wx.ID_OK :
1245 #                PlaySound(self)
1246 #        except :
1247 #            BugReport(self)
1248
1249     def OnHelp(self, event):
1250         webbrowser.open('http://www.iramuteq.org/documentation')
1251
1252     def OnPref(self, event):
1253         dlg = PrefDialog(self)
1254         dlg.CenterOnParent()
1255         self.val = dlg.ShowModal()
1256         dlg.Destroy()
1257
1258     def Upgrade(self) :
1259         if self.check_update:
1260             NewVersion(self)
1261         else:
1262             print('pas de verif')
1263         #IsNew(self)
1264         #CheckRPackages(self)
1265
1266     def OnOpenFromCmdl(self):
1267         truepath = True
1268         if options.filename :
1269             if os.path.exists(options.filename):
1270                 self.filename = os.path.abspath(options.filename)
1271             else:
1272                 truepath = False
1273         elif args :
1274             if os.path.exists(os.path.realpath(args[0])):
1275                 self.filename = os.path.abspath(os.path.realpath(args[0]))
1276             else:
1277                 truepath = False
1278         else:
1279             return
1280         if truepath :
1281             if os.path.splitext(self.filename)[1] in ['.csv', '.xls', '.ods']:
1282                 self.tableau = Tableau(self, self.filename)
1283                 val = get_table_param(self, self.filename)
1284                 if val == wx.ID_OK :
1285                     self.tableau.make_content()
1286                     OpenAnalyse(self, self.tableau.parametres)
1287                     self.tree.OnItemAppend(self.tableau.parametres)
1288                 #get_table_param(self, self.filename)
1289                 #self.tableau.make_content()
1290                 #self.tableau.show_tab()
1291                 #open_data(self, self.filename)
1292             elif os.path.splitext(self.filename)[1] == '.txt':
1293                 self.OpenText()
1294             elif os.path.splitext(self.filename)[1] == '.ira' :
1295                 #self.corpus = Corpus(self)
1296                 #self.Text = OpenAnalyse(self, self.filename)
1297                 OpenAnalyse(self, self.filename)
1298         if not truepath:
1299             print('This file does not exist')
1300
1301
1302 #--------------------------------------------------------------------
1303 # contenu de l'ecran d'accueil
1304 # appelé seulement dans l'initialisation de IraFrame
1305 #--------------------------------------------------------------------
1306 class IntroPanel(wx.Panel):
1307     def __init__(self, parent):
1308         wx.Panel.__init__(self, parent)
1309         #col = randint(0, 255)
1310         #col1 = randint(0,255)
1311         #col2 = randint(0,255)
1312         #col = 57
1313         col = 161
1314         col1 = 198
1315         col2 = 224
1316         bckgrdcolor = wx.Colour(col, col1, col2)
1317         self.SetBackgroundColour(bckgrdcolor)
1318         txtcolour = wx.Colour(250, 250, 250)
1319         linkcolor = wx.Colour(255, 0, 0)
1320         sizer1 = wx.BoxSizer(wx.VERTICAL)
1321         sizer2 = wx.BoxSizer(wx.VERTICAL)
1322         sizer4 = wx.BoxSizer(wx.HORIZONTAL)
1323         grid_sizer_1 = wx.FlexGridSizer(1, 4, 0, 0)
1324         grid_sizer_3 = wx.FlexGridSizer(1, 4, 0, 0)
1325         grid_sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
1326         iralink = hl.HyperLinkCtrl(self,
1327             wx.ID_ANY,
1328             "http://www.iramuteq.org",
1329             URL="http://www.iramuteq.org")
1330         iralink.SetColours(linkcolor, linkcolor, "RED")
1331         iralink.SetBackgroundColour(bckgrdcolor)
1332         iralink.EnableRollover(True)
1333         iralink.SetUnderlines(False, False, True)
1334         iralink.SetBold(True)
1335         iralink.UpdateLink()
1336         PanelPres = wx.Panel(self)
1337         bckgrdcolor = wx.Colour(randint(0, 255), randint(0, 255), randint(0, 255))
1338         PanelPres.SetBackgroundColour(bckgrdcolor)
1339         label_1 = wx.StaticText(self, -1, "IRaMuTeQ", size=(-1, -1))
1340         label_1.SetFont(wx.Font(46,
1341             wx.FONTFAMILY_TELETYPE,
1342             wx.FONTSTYLE_NORMAL,
1343             wx.FONTWEIGHT_BOLD,
1344             0,
1345             "Purisa"))
1346         label_1.SetForegroundColour(wx.RED)
1347         iraicone = wx.Image(os.path.join(ImagePath,'iraicone100x100.png'), wx.BITMAP_TYPE_ANY).ConvertToBitmap()
1348         but_ira = wx.StaticBitmap(self, -1, bitmap = iraicone)
1349         label2 = wx.StaticText(PanelPres, -1 , '\nVersion ' + ConfigGlob.get('DEFAULT', 'version') + '\n')
1350         label2.SetForegroundColour(txtcolour)
1351         label2.SetBackgroundColour(bckgrdcolor)
1352         self.hyper2 = hl.HyperLinkCtrl(PanelPres, wx.ID_ANY, "REPERE", URL="http://repere.no-ip.org/")
1353         self.hyper2.SetColours(linkcolor, linkcolor, "RED")
1354         self.hyper2.SetBackgroundColour(bckgrdcolor)
1355         self.hyper2.EnableRollover(True)
1356         self.hyper2.SetUnderlines(False, False, True)
1357         self.hyper2.SetBold(True)
1358         self.hyper2.UpdateLink()
1359         label_lerass = wx.StaticText(PanelPres, -1, 'Laboratoire ')
1360         label_lerass.SetForegroundColour(txtcolour)
1361         label_lerass.SetBackgroundColour(bckgrdcolor)
1362         self.hyper_lerass = hl.HyperLinkCtrl(PanelPres, -1, 'LERASS', URL="http://www.lerass.com")
1363         self.hyper_lerass.SetColours(linkcolor, linkcolor, "RED")
1364         self.hyper_lerass.SetBackgroundColour(bckgrdcolor)
1365         self.hyper_lerass.EnableRollover(True)
1366         self.hyper_lerass.SetUnderlines(False, False, True)
1367         self.hyper_lerass.SetBold(True)
1368         self.hyper_lerass.UpdateLink()
1369         blank = wx.StaticText(PanelPres, -1, '\n')
1370         blank1 = wx.StaticText(PanelPres, -1, '\n')
1371         labellicence = wx.StaticText(PanelPres, -1, _("License GNU GPL"))
1372         labellicence.SetForegroundColour(txtcolour)
1373         labellicence.SetBackgroundColour(bckgrdcolor)
1374         labelcopy = wx.StaticText(PanelPres, -1, ConfigGlob.get('DEFAULT', 'copyright'))
1375         labelcopy.SetForegroundColour(txtcolour)
1376         labelcopy.SetBackgroundColour(bckgrdcolor)
1377         python_img = wx.Image(os.path.join(ImagePath,'python-logo.jpg'), wx.BITMAP_TYPE_ANY).ConvertToBitmap()
1378         r_img = wx.Image(os.path.join(ImagePath,'Rlogo.jpg'), wx.BITMAP_TYPE_ANY).ConvertToBitmap()
1379         lexique_img = wx.Image(os.path.join(ImagePath,'LexTexte4.jpg'), wx.BITMAP_TYPE_ANY).ConvertToBitmap()
1380         but_python = wx.BitmapButton(self, -1, python_img)
1381         but_lexique = wx.BitmapButton(self, -1, lexique_img)
1382         but_r = wx.BitmapButton(self, -1, r_img)
1383         self.Bind(wx.EVT_BUTTON, self.OnPython, but_python)
1384         self.Bind(wx.EVT_BUTTON, self.OnLexique, but_lexique)
1385         self.Bind(wx.EVT_BUTTON, self.OnR, but_r)
1386         grid_sizer_1.Add(self.hyper2, 0, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, 0)
1387         grid_sizer_3.Add(label_lerass, 0, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, 0)
1388         grid_sizer_3.Add(self.hyper_lerass, 0, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, 0)
1389         sizer4.Add(label_1, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 5)
1390         sizer2.Add(label2, 0, wx.ALIGN_CENTER, 5)
1391         sizer2.Add(wx.StaticText(PanelPres, -1, ''), 0, wx.ALIGN_CENTER, 5)
1392         sizer2.Add(wx.StaticText(PanelPres, -1, ''), 0, wx.ALIGN_CENTER, 5)
1393         sizer2.Add(grid_sizer_3, 0, wx.ALIGN_CENTER, 5)
1394         sizer2.Add(wx.StaticText(PanelPres, -1, ' '), 0, wx.ALIGN_CENTER, 5)
1395         sizer2.Add(grid_sizer_1, 0, wx.ALIGN_CENTER, 5)
1396         sizer2.Add(labellicence, 0, wx.ALIGN_CENTER, 5)
1397         sizer2.Add(labelcopy, 0, wx.ALIGN_CENTER, 5)
1398         sizer1.Add(sizer4, 2, wx.ALIGN_CENTER_HORIZONTAL, 0)
1399         sizer1.Add(but_ira, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 5)
1400         sizer1.Add(iralink, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_TOP, 5)
1401         sizer2.Add(wx.StaticText(PanelPres, -1, ''), 0, wx.ALIGN_CENTER, 10)
1402         PanelPres.SetSizer(sizer2)
1403         grid_sizer_2.Add(but_python, 1, wx.ALIGN_BOTTOM)
1404         grid_sizer_2.Add(but_lexique, 1, wx.ALIGN_BOTTOM)
1405         grid_sizer_2.Add(but_r, 1,  wx.ALIGN_BOTTOM)
1406         sizer1.Add(PanelPres, 0, wx.EXPAND |wx.ALL, 10)
1407         sizer1.Add(grid_sizer_2, 2, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 1)
1408         self.SetSizer(sizer1)
1409         sizer1.Fit(self)
1410
1411     def OnPython(self,evt):
1412         webbrowser.open('http://www.python.org')
1413
1414     def OnLexique(self,evt):
1415         webbrowser.open('http://www.lexique.org')
1416
1417     def OnR(self,evt):
1418         webbrowser.open('http://www.r-project.org')
1419
1420
1421 #--------------------------------------------------------------------
1422 # ecran d'accueil
1423 # appelé seulement par MyApp
1424 #--------------------------------------------------------------------
1425 class MySplashScreen(wx.adv.SplashScreen):
1426
1427     def __init__(self):
1428         bmp = wx.Image(os.path.join(ImagePath, 'splash.png')).ConvertToBitmap()
1429         wx.adv.SplashScreen.__init__(self, bmp,
1430             wx.adv.SPLASH_CENTRE_ON_SCREEN |
1431             wx.adv.SPLASH_TIMEOUT,
1432             1000,
1433             None,
1434             -1)
1435         self.Bind(wx.EVT_CLOSE, self.OnClose)
1436         self.fc = wx.CallLater(1, self.ShowMain)
1437
1438     def OnClose(self, evt):
1439         evt.Skip()
1440         self.Hide()
1441         if self.fc.IsRunning():
1442             self.fc.Stop()
1443             self.ShowMain()
1444
1445     def ShowMain(self):
1446         displaySize = wx.DisplaySize()
1447         w = displaySize[0]/1.2
1448         h = displaySize[1]/1.2
1449         frame = IraFrame(None, -1, "IRaMuTeQ " + ConfigGlob.get('DEFAULT', 'version'), size=(int(w), int(h)))
1450         frame.Show()
1451         frame.finish_init()
1452         frame.Upgrade()
1453         frame.OnOpenFromCmdl()
1454         #if self.fc.IsRunning():
1455         #    self.Raise()
1456         #wx.CallAfter(frame.ShowTip)
1457
1458
1459 class MyApp(wx.App):
1460
1461     def OnInit(self):
1462         """
1463         Create and show the splash screen.  It will then create and show
1464         the main frame when it is time to do so.
1465         """
1466         wx.SystemOptions.SetOption("mac.window-plain-transition", 1)
1467         self.SetAppName("Iramuteq")
1468         splash = MySplashScreen()
1469         splash.Show()
1470         return True
1471
1472 def main():
1473     app = MyApp(False)
1474     app.MainLoop()
1475
1476 if __name__ == '__main__':
1477     __name__ = 'Main'
1478     main()