windows
[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         print("showmenu")
756         if menu == 'text' :
757             menu_pos = 4
758             if Show :
759                 self._mgr.GetPane('tb_text').Show()
760                 self._mgr.GetPane('tb_mat').Hide()
761                 self.mb.EnableTop(menu_pos, Show)
762                 self.mb.EnableTop(3, False)
763             else :
764                 self._mgr.GetPane('tb_text').Hide()
765         elif menu == 'matrix' :
766             menu_pos = 3
767             if Show :
768                 self._mgr.GetPane('tb_mat').Show()
769                 self._mgr.GetPane('tb_text').Hide()
770                 self.mb.EnableTop(menu_pos, Show)
771                 self.mb.EnableTop(4, False)
772             else :
773                 self._mgr.GetPane('tb_mat').Hide()
774         elif menu == 'view' :
775             menu_pos = 2
776         else :
777             menu_pos = None
778         if not menu_pos is None :
779             #self.mb.EnableTop(menu_pos, Show)
780             self.mb.Refresh()
781         self._mgr.Update()
782
783     #--------------------------------------------------------------------
784     # fin de __init__ du wx.Frame
785     #--------------------------------------------------------------------
786
787     # evenement attaché au bouton de fermeture des fenetres ou onglets ?
788     def OnClose(self, event):
789         print('onclose Iramuteq')
790         with open(self.ConfigPath['path'], 'w') as f :
791             self.PathPath.write(f)
792         self._mgr.UnInit()
793         del self._mgr
794         self.Destroy()
795
796     # evenement attaché au menu 'ouvrir matrice'
797     def OnOpenData(self, event):
798         print('on open data')
799         inputname, self.input_path = OnOpen(self, "Data")
800         if inputname:
801             # filename = self.input_path[0]
802             self.tableau = Tableau(self,os.path.abspath(self.input_path[0]))
803             val = get_table_param(self, self.input_path[0])
804             if val == wx.ID_OK :
805                 busy = wx.BusyInfo(_("Please wait..."), self)
806                 wx.SafeYield()
807                 try :
808                     self.tableau.make_content()
809                     OpenAnalyse(self, self.tableau.parametres)
810                     self.tree.OnItemAppend(self.tableau.parametres)
811                     del busy
812                 except :
813                     del busy
814                     BugReport(self)
815                 # self.tableau.show_tab()
816
817     # evenement attaché au menu 'ouvrir analyse'
818     def OnOpenAnalyse(self, event):
819         print('on open analyse')
820         self.AnalysePath = OnOpen(self, "Analyse")
821         if self.AnalysePath :
822             OpenAnalyse(self, self.AnalysePath[1][0], True)
823             self.ShowMenu('view')
824
825     # evenement attaché au menu 'ouvrir un texte/corpus'
826     def OnOpenText(self, event):
827         print('on open text')
828         inputname, self.input_path = OnOpen(self, "Texte")
829         self.filename = self.input_path[0]
830         if inputname:
831             self.OpenText()
832
833     # evenement attaché au menu 'ouvrir analyse'
834     def OnSubText(self, evt, corpus = None, parametres = None):
835         print('on sub text')
836         if corpus is None :
837             corpus = self.tree.getcorpus()
838         if evt.GetId() == ID_Subtxtfrommeta :
839             parametres = {'frommeta' : True}
840         elif evt.GetId() == ID_Subtxtfromthem :
841             parametres = {'fromtheme' : True}
842         builder = SubBuilder(self, corpus, parametres)
843         if builder.res == wx.ID_OK :
844             busy = wx.BusyInfo(_("Please wait..."), self)
845             wx.SafeYield()
846             corpus = builder.doanalyse()
847             self.history.add(corpus.parametres)
848             OpenAnalyse(self, corpus.parametres)
849             self.tree.OnItemAppend(corpus.parametres)
850             del busy
851
852     # action d'ouverture d'un texte
853     def OpenText(self):
854         print('open text')
855         builder =  Builder(self, 5)
856         if builder.res == wx.ID_OK :
857             try :
858                 corpus = builder.doanalyse()
859                 self.history.add(corpus.parametres)
860                 self.tree.OnItemAppend(corpus.parametres)
861                 OpenAnalyse(self, corpus.parametres)
862             except :
863                 builder.dlg.Destroy()
864                 BugReport(self)
865             else :
866                 count = 1
867                 keepGoing = builder.dlg.Update(count, "Lecture du fichier")
868                 self.ShowMenu('view')
869                 self.ShowMenu('text')
870                 self.ShowMenu('matrix', False)
871                 self.type = "Texte"
872                 self.DataTxt = False
873                 self.Text = ''
874                 count += 1
875                 keepGoing = builder.dlg.Update(count, "Chargement du dictionnaire")
876                 builder.dlg.Destroy()
877
878     # evenement attaché au menu 'quitter'
879     def OnExit(self, event):
880         self.Close()
881
882     # evenement attaché au menu 'à propos'
883     def OnAbout(self, event):
884         print('on about')
885         info = wx.adv.AboutDialogInfo()
886         info.Name = ConfigGlob.get('DEFAULT', 'name')
887         info.Version = ConfigGlob.get('DEFAULT', 'version')
888         info.Copyright = ConfigGlob.get('DEFAULT', 'copyright')
889         info.Translators = ConfigGlob.get('DEFAULT', 'translators').split(';')
890         info.Description = """
891 Interface de R pour les Analyses Multidimensionnelles
892 de Textes et de Questionnaires
893
894 Un logiciel libre
895 construit avec des logiciels libres.
896
897 Laboratoire LERASS
898
899 REPERE
900 """
901         info.WebSite = ("http://www.iramuteq.org", "Site web IRaMuTeQ")
902         dev = ConfigGlob.get('DEFAULT', 'dev').split(';')
903         info.Developers = dev
904         info.License = """Iramuteq est un logiciel libre ; vous pouvez le diffuser et/ou le modifier
905 suivant les termes de la Licence Publique Générale GNU telle que publiée 
906 par la Free Software Foundation ; soit la version 2 de cette licence, 
907 soit (à votre convenance) une version ultérieure.
908
909 Iramuteq est diffusé dans l'espoir qu'il sera utile, 
910 mais SANS AUCUNE GARANTIE ; sans même une garantie implicite 
911 de COMMERCIALISATION ou d'ADÉQUATION À UN USAGE PARTICULIER. 
912 Voyez la Licence Publique Générale GNU pour plus de détails.
913
914 Vous devriez avoir reçu une copie de la Licence Publique Générale GNU
915 avec Iramuteq ; sinon, veuillez écrire à la Free Software Foundation,
916 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, États-Unis."""
917         wx.adv.AboutBox(info)
918
919     # appelé seulement pour l'initialisation de la fenetre principale de Iramuteq
920     def GetDockArt(self):
921         return self._mgr.GetArtProvider()
922
923     # appelé seulement pour l'initialisation de la fenetre principale de Iramuteq
924     def DoUpdate(self):
925         self._mgr.Update()
926
927     # action ou évènement ?
928     def OnPageChanged(self, event) :
929         print("OnPageChange")
930         new = event.GetSelection()
931         nobject = event.GetEventObject()
932         parent = nobject.GetParent()
933         if isinstance(parent, IraFrame) :
934             npage = self.nb.GetPage(new)
935             if 'parametres' in dir(npage) :
936                 #self.tree.GiveFocus(uuid=npage.parametres['uuid'])
937                 if npage.parametres.get('matrix', False) :
938                     #self.ShowMenu('text', False)
939                     self.ShowMenu('matrix', True)
940                 elif npage.parametres.get('corpus', False) :
941                     self.ShowMenu('text')
942                     #self.ShowMenu('matrix', False)
943         wx.CallAfter(self.nb.SendSizeEvent)
944         self.Refresh()
945
946     # action ou évènement ?
947     def OnCloseTab(self, evt):
948         #log.info('Closing tab %s' % str(evt.GetEventObject()))
949         ctrl = evt.GetEventObject()
950         if isinstance(ctrl.GetParent(), aui.AuiNotebook) or isinstance(ctrl.GetParent(), wx.Panel):
951             notebook = True
952         else :
953             notebook = False
954         page = self.nb.GetPage(self.nb.GetSelection())
955         if 'parametres' in dir(page) and isinstance(ctrl.GetParent(), IraFrame) :
956             self.history.rmtab(page.parametres)
957             self.tree.CloseItem(uuid = page.parametres['uuid'])
958         TabTitle = self.nb.GetPageText(self.nb.GetSelection())
959         if self.nb.GetPageCount() == 1 and not notebook :
960             self.LastTabClose()
961
962     # action ou évènement ?
963     def LastTabClose(self) :
964         if self.nb.GetPageCount() == 1 :
965             if self.DataTxt :
966                 self.ShowAPane("Text")
967             elif self.DataPop :
968                 self.ShowAPane("Data")
969             else :
970                 self.ShowAPane("Intro_Text")
971
972     # action ou évènement ?
973     def GetStartPosition(self):
974         self.x = self.x + 20
975         x = self.x
976         pt = self.ClientToScreen(wx.Point(0, 0))
977         return wx.Point(pt.x + x, pt.y + x)
978
979     # action ou évènement ?
980     def ShowAPane(self, panel):
981         for pane in self._mgr.GetAllPanes() :
982             if not pane.IsToolbar() and pane.name != 'lefttree':
983                 pane.Hide()
984         self._mgr.GetPane(panel).Show()
985         self._mgr.Update()
986         wx.CallAfter(self.nb.SendSizeEvent)
987         self.Refresh()
988
989     # action ou évènement ?
990     def OnAcceuil(self, event):
991         self.ShowAPane("Intro_Text")
992         event.Skip()
993
994     # action ou évènement ?
995     def CreateHTMLCtrl(self):
996         ctrl = wx.html.HtmlWindow(self, -1, wx.DefaultPosition, wx.Size(400, 300))
997         if "gtk2" in wx.PlatformInfo:
998             ctrl.SetStandardFonts()
999         ctrl.SetPage("text")
1000         return ctrl
1001
1002     # action ou évènement ?
1003     def ShowTab(self, evt):
1004         self.ShowAPane("Tab_content")
1005
1006     ################################################################
1007     #debut des analyses
1008     ################################################################
1009     def analyse_matrix(self, analyse, analyse_type = '', matrix = None, parametres = None, dlgnb = 1):
1010         if matrix is None :
1011             matrix = self.tree.getmatrix()
1012         if parametres is not None :
1013             parametres['type'] = analyse_type
1014         else :
1015             parametres = {'type' : analyse_type}
1016         try :
1017             #print 'plus de bug@@@@@@@@@@@@@@@@@@@@@@'
1018             analyse(self, matrix, parametres = parametres, dlg = dlgnb)
1019         except:
1020             BugReport(self)
1021
1022     def OnFreq(self, event, matrix = None):
1023         self.analyse_matrix(Frequences, analyse_type = 'freq', matrix = matrix, dlgnb = 3)
1024
1025     def OnFreqMulti(self, event, matrix = None):
1026         self.analyse_matrix(FreqMultiple, analyse_type = 'freqmulti', matrix = matrix, dlgnb = 3)
1027
1028     def OnChi2(self, event, matrix = None):
1029         self.analyse_matrix(ChiSquare, matrix = matrix, analyse_type = 'chi2', dlgnb = 3)
1030
1031     def OnChi2McNemar(self, event, matrix = None):
1032         self.analyse_matrix(McNemar, matrix = matrix, analyse_type = 'chi2mcnemar', dlgnb = 3)
1033
1034     def OnSimiTab(self, event, matrix = None):
1035         self.analyse_matrix(DoSimi, matrix = matrix, analyse_type = 'simimatrix', dlgnb = 5)
1036
1037     def OnCategorisation(self, event, matrix = None) :
1038         self.analyse_matrix(Categorisation, matrix = matrix, analyse_type = 'categorisation', dlgnb = 1)
1039
1040
1041     def OnCHDReinert(self, event, matrix = None):
1042         #if matrix is None :
1043         #    matrix = self.tree.getmatrix()
1044         #AnalyseQuest(self, matrix, parametres = {'type' : 'reinertmatrix'}, dlg = 3)
1045         self.analyse_matrix(AnalyseQuest, matrix = matrix, analyse_type = 'reinertmatrix', dlgnb = 5)
1046
1047     def OnStudent(self, event):
1048         try:
1049             MakeStudent(self)
1050         except:
1051             BugReport(self)
1052
1053     def OnRCode(self, event):
1054         try:
1055             InputText(self)
1056         except:
1057             BugReport(self)
1058
1059     def OnCHDSIM(self, event):
1060         try:
1061             chdsim = ChdCluster(self)
1062             if chdsim.val == wx.ID_OK:
1063                 PlaySound(self)
1064         except:
1065             BugReport(self)
1066
1067 #     def OnCHDReinert(self, event):
1068 #         try:
1069 #          #   print('PLUS DE BUG SUR ALCESTE QUESTIONNAIRE')
1070 #             self.quest = AnalyseQuest(self)
1071 #             if self.quest.val == wx.ID_OK:
1072 #                 PlaySound(self)
1073 #         except:
1074 #             BugReport(self)
1075
1076     def OnMergeGraph(self, evt):
1077         #FIXME
1078         AnalyseMerge(self, {'type': 'merge', 'fileout' : '/tmp/test.txt'}, dlg = 5)
1079
1080     def OnMergeClusters(self, evt) :
1081         print('on merge clusters')
1082         builder = MergeClusters(self, {})
1083         if builder.res == wx.ID_OK :
1084             busy = wx.BusyInfo(_("Please wait..."), self)
1085             wx.SafeYield()
1086             corpus = builder.doanalyse()
1087             self.history.add(corpus.parametres)
1088             OpenAnalyse(self, corpus.parametres)
1089             self.tree.OnItemAppend(corpus.parametres)
1090             del busy
1091
1092     def OnProto(self, evt, matrix = None) :
1093         self.analyse_matrix(Prototypical, matrix = matrix, analyse_type = 'proto', dlgnb = 3) 
1094         #Prototypical(self, {'type' : 'proto'})
1095
1096     def OnSplitVar(self, evt, matrix = None):
1097         if matrix is None :
1098             matrix = self.tree.getmatrix()
1099         self.analyse_matrix(SplitMatrixFromVar, matrix = matrix, analyse_type = 'splitvar', parametres = {'pathout': matrix.pathout.dirout}, dlgnb = 3)
1100         #matrix = self.tree.getmatrix()
1101
1102     def OnSimiTxt(self, evt, corpus = None) :
1103         try :
1104             #self.Text = SimiTxt(self)
1105             if corpus is None :
1106                 corpus = self.tree.getcorpus()
1107             self.Text = SimiTxt(self, corpus, parametres = {'type': 'simitxt'}, dlg = 3)
1108             if self.Text.val == wx.ID_OK :
1109                 PlaySound(self)
1110         except :
1111             BugReport(self)
1112
1113     def OnWordCloud(self, evt, corpus = None) :
1114         try :
1115             if corpus is None :
1116                 corpus = self.tree.getcorpus()
1117             self.Text = WordCloud(self, corpus, parametres = {'type' : 'wordcloud'}, dlg = 3)
1118             if self.Text.val == wx.ID_OK :
1119                 PlaySound(self)
1120         except :
1121             BugReport(self)
1122
1123     def OnClusterCloud(self, corpus, parametres = None) :
1124         self.Text = ClusterCloud(self, corpus, parametres = parametres, dlg = 3)
1125
1126     def OnAFCM(self, event):
1127         try:
1128             DoAFCM(self)
1129         except:
1130             BugReport(self)
1131
1132     def OnTextStat(self, event, corpus = None):
1133         try:
1134             if corpus is None :
1135                 corpus = self.tree.getcorpus()
1136             self.Text = Stat(self, corpus, parametres = {'type': 'stat'}, dlg = 7)
1137             if self.Text.val == wx.ID_OK :
1138                 PlaySound(self)
1139         except:
1140             BugReport(self)
1141
1142     def OnTextSpec(self, event, corpus = None):
1143         try:
1144             #self.Text = AsLexico(self)
1145             if corpus is None :
1146                 corpus = self.tree.getcorpus()
1147             self.Text = Lexico(self, corpus, parametres = {'type' : 'spec'}, dlg = 3)
1148             if self.Text.val == wx.ID_OK :
1149                 PlaySound(self)
1150         except:
1151             BugReport(self)
1152
1153     def OnTextLabbe(self, event, corpus = None):
1154         try:
1155             if corpus is None :
1156                 corpus = self.tree.getcorpus()
1157             self.Text = DistLabbe(self, corpus, parametres = {'type' : 'labbe'}, dlg = 3)
1158             if self.Text.val == wx.ID_OK :
1159                 PlaySound(self)
1160         except:
1161             BugReport(self)
1162
1163     def OnTextAfcm(self, event):
1164         try:
1165             AfcUci(self)
1166             PlaySound(self)
1167         except:
1168             BugReport(self)
1169
1170     def import_factiva_xml(self,event):
1171         try :
1172             ImportFactiva(self, 'xml')
1173         except :
1174             BugReport(self)
1175
1176     def import_factiva_mail(self, evt) :
1177         try :
1178             ImportFactiva(self, 'mail')
1179         except :
1180             BugReport(self)
1181
1182     def import_factiva_txt(self, evt) :
1183         try :
1184             ImportFactiva(self, 'txt')
1185         except :
1186             BugReport(self)
1187
1188     def OnImportTXM(self, evt) :
1189         try :
1190             ImportFactiva(self, 'txm')
1191         except :
1192             BugReport(self)
1193
1194     def OnImportEuropress(self, evt) :
1195         try :
1196             ImportFactiva(self, 'euro')
1197         except :
1198             BugReport(self)
1199
1200     def OnImportDMI(self, evt):
1201         ImportDMI(self, {})
1202
1203     def OnExportMeta(self, evt, corpus = None):
1204         if corpus is None :
1205             corpus = self.tree.getcorpus()
1206         try :
1207             ExportMetaTable(self, corpus)
1208         except :
1209             BugReport(self)
1210
1211     def ExtractTools(self, evt) :
1212         ID = evt.GetId()
1213         if ID == self.ID_splitvar :
1214             Extract(self, 'splitvar')
1215         elif ID == self.ID_extractmod :
1216             Extract(self, 'mods')
1217         elif ID == self.ID_extractthem :
1218             Extract(self, 'them')
1219
1220     def OnTextReinert(self, event, corpus = None):
1221         try:
1222             #RunAnalyse(self, corpus, Alceste, OptAlceste)
1223             if corpus is None :
1224                 corpus = self.tree.getcorpus()
1225             self.Text = Reinert(self, corpus, parametres = {'type': 'alceste'}, dlg = 6)
1226             if self.Text.val == wx.ID_OK:
1227                 PlaySound(self)
1228         except:
1229             BugReport(self)
1230
1231     def OnPamSimple(self, event, corpus = None):
1232         try:
1233             if corpus is None :
1234                 corpus = self.tree.getcorpus()
1235             self.Text = AnalysePam(self, corpus, parametres = {'type' : 'pamtxt'}, dlg = 6)
1236             if self.Text.val == wx.ID_OK:
1237                 PlaySound(self)
1238         except:
1239             BugReport(self)
1240
1241     def SimiCluster(self, parametres = {}, fromprof = False, tableau = None) :
1242         self.analyse_matrix(DoSimi, parametres = parametres, analyse_type = 'simiclustermatrix', matrix = tableau, dlgnb = 5)
1243
1244 #    def OnSimi(self,evt):
1245 #        try :
1246 #            self.res = DoSimi(self, param = None)
1247             #self.res = Verges(self)
1248 #            if self.res.val == wx.ID_OK :
1249 #                PlaySound(self)
1250 #        except :
1251 #            BugReport(self)
1252
1253     def OnHelp(self, event):
1254         webbrowser.open('http://www.iramuteq.org/documentation')
1255
1256     def OnPref(self, event):
1257         dlg = PrefDialog(self)
1258         dlg.CenterOnParent()
1259         self.val = dlg.ShowModal()
1260         dlg.Destroy()
1261
1262     def Upgrade(self) :
1263         if self.check_update:
1264             NewVersion(self)
1265         else:
1266             print('pas de verif')
1267         #IsNew(self)
1268         #CheckRPackages(self)
1269
1270     def OnOpenFromCmdl(self):
1271         truepath = True
1272         if options.filename :
1273             if os.path.exists(options.filename):
1274                 self.filename = os.path.abspath(options.filename)
1275             else:
1276                 truepath = False
1277         elif args :
1278             if os.path.exists(os.path.realpath(args[0])):
1279                 self.filename = os.path.abspath(os.path.realpath(args[0]))
1280             else:
1281                 truepath = False
1282         else:
1283             return
1284         if truepath :
1285             if os.path.splitext(self.filename)[1] in ['.csv', '.xls', '.ods']:
1286                 self.tableau = Tableau(self, self.filename)
1287                 val = get_table_param(self, self.filename)
1288                 if val == wx.ID_OK :
1289                     self.tableau.make_content()
1290                     OpenAnalyse(self, self.tableau.parametres)
1291                     self.tree.OnItemAppend(self.tableau.parametres)
1292                 #get_table_param(self, self.filename)
1293                 #self.tableau.make_content()
1294                 #self.tableau.show_tab()
1295                 #open_data(self, self.filename)
1296             elif os.path.splitext(self.filename)[1] == '.txt':
1297                 self.OpenText()
1298             elif os.path.splitext(self.filename)[1] == '.ira' :
1299                 #self.corpus = Corpus(self)
1300                 #self.Text = OpenAnalyse(self, self.filename)
1301                 OpenAnalyse(self, self.filename)
1302         if not truepath:
1303             print('This file does not exist')
1304
1305
1306 #--------------------------------------------------------------------
1307 # contenu de l'ecran d'accueil
1308 # appelé seulement dans l'initialisation de IraFrame
1309 #--------------------------------------------------------------------
1310 class IntroPanel(wx.Panel):
1311     def __init__(self, parent):
1312         wx.Panel.__init__(self, parent)
1313         #col = randint(0, 255)
1314         #col1 = randint(0,255)
1315         #col2 = randint(0,255)
1316         #col = 57
1317         col = 161
1318         col1 = 198
1319         col2 = 224
1320         bckgrdcolor = wx.Colour(col, col1, col2)
1321         self.SetBackgroundColour(bckgrdcolor)
1322         txtcolour = wx.Colour(250, 250, 250)
1323         linkcolor = wx.Colour(255, 0, 0)
1324         sizer1 = wx.BoxSizer(wx.VERTICAL)
1325         sizer2 = wx.BoxSizer(wx.VERTICAL)
1326         sizer4 = wx.BoxSizer(wx.HORIZONTAL)
1327         grid_sizer_1 = wx.FlexGridSizer(1, 4, 0, 0)
1328         grid_sizer_3 = wx.FlexGridSizer(1, 4, 0, 0)
1329         grid_sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
1330         iralink = hl.HyperLinkCtrl(self,
1331             wx.ID_ANY,
1332             "http://www.iramuteq.org",
1333             URL="http://www.iramuteq.org")
1334         iralink.SetColours(linkcolor, linkcolor, "RED")
1335         iralink.SetBackgroundColour(bckgrdcolor)
1336         iralink.EnableRollover(True)
1337         iralink.SetUnderlines(False, False, True)
1338         iralink.SetBold(True)
1339         iralink.UpdateLink()
1340         PanelPres = wx.Panel(self)
1341         bckgrdcolor = wx.Colour(randint(0, 255), randint(0, 255), randint(0, 255))
1342         PanelPres.SetBackgroundColour(bckgrdcolor)
1343         label_1 = wx.StaticText(self, -1, "IRaMuTeQ", size=(-1, -1))
1344         label_1.SetFont(wx.Font(46,
1345             wx.FONTFAMILY_TELETYPE,
1346             wx.FONTSTYLE_NORMAL,
1347             wx.FONTWEIGHT_BOLD,
1348             0,
1349             "Purisa"))
1350         label_1.SetForegroundColour(wx.RED)
1351         iraicone = wx.Image(os.path.join(ImagePath,'iraicone100x100.png'), wx.BITMAP_TYPE_ANY).ConvertToBitmap()
1352         but_ira = wx.StaticBitmap(self, -1, bitmap = iraicone)
1353         label2 = wx.StaticText(PanelPres, -1 , '\nVersion ' + ConfigGlob.get('DEFAULT', 'version') + '\n')
1354         label2.SetForegroundColour(txtcolour)
1355         label2.SetBackgroundColour(bckgrdcolor)
1356         self.hyper2 = hl.HyperLinkCtrl(PanelPres, wx.ID_ANY, "REPERE", URL="http://repere.no-ip.org/")
1357         self.hyper2.SetColours(linkcolor, linkcolor, "RED")
1358         self.hyper2.SetBackgroundColour(bckgrdcolor)
1359         self.hyper2.EnableRollover(True)
1360         self.hyper2.SetUnderlines(False, False, True)
1361         self.hyper2.SetBold(True)
1362         self.hyper2.UpdateLink()
1363         label_lerass = wx.StaticText(PanelPres, -1, 'Laboratoire ')
1364         label_lerass.SetForegroundColour(txtcolour)
1365         label_lerass.SetBackgroundColour(bckgrdcolor)
1366         self.hyper_lerass = hl.HyperLinkCtrl(PanelPres, -1, 'LERASS', URL="http://www.lerass.com")
1367         self.hyper_lerass.SetColours(linkcolor, linkcolor, "RED")
1368         self.hyper_lerass.SetBackgroundColour(bckgrdcolor)
1369         self.hyper_lerass.EnableRollover(True)
1370         self.hyper_lerass.SetUnderlines(False, False, True)
1371         self.hyper_lerass.SetBold(True)
1372         self.hyper_lerass.UpdateLink()
1373         blank = wx.StaticText(PanelPres, -1, '\n')
1374         blank1 = wx.StaticText(PanelPres, -1, '\n')
1375         labellicence = wx.StaticText(PanelPres, -1, _("License GNU GPL"))
1376         labellicence.SetForegroundColour(txtcolour)
1377         labellicence.SetBackgroundColour(bckgrdcolor)
1378         labelcopy = wx.StaticText(PanelPres, -1, ConfigGlob.get('DEFAULT', 'copyright'))
1379         labelcopy.SetForegroundColour(txtcolour)
1380         labelcopy.SetBackgroundColour(bckgrdcolor)
1381         python_img = wx.Image(os.path.join(ImagePath,'python-logo.jpg'), wx.BITMAP_TYPE_ANY).ConvertToBitmap()
1382         r_img = wx.Image(os.path.join(ImagePath,'Rlogo.jpg'), wx.BITMAP_TYPE_ANY).ConvertToBitmap()
1383         lexique_img = wx.Image(os.path.join(ImagePath,'LexTexte4.jpg'), wx.BITMAP_TYPE_ANY).ConvertToBitmap()
1384         but_python = wx.BitmapButton(self, -1, python_img)
1385         but_lexique = wx.BitmapButton(self, -1, lexique_img)
1386         but_r = wx.BitmapButton(self, -1, r_img)
1387         self.Bind(wx.EVT_BUTTON, self.OnPython, but_python)
1388         self.Bind(wx.EVT_BUTTON, self.OnLexique, but_lexique)
1389         self.Bind(wx.EVT_BUTTON, self.OnR, but_r)
1390         grid_sizer_1.Add(self.hyper2, 0, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, 0)
1391         grid_sizer_3.Add(label_lerass, 0, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, 0)
1392         grid_sizer_3.Add(self.hyper_lerass, 0, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL, 0)
1393         sizer4.Add(label_1, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 5)
1394         sizer2.Add(label2, 0, wx.ALIGN_CENTER, 5)
1395         sizer2.Add(wx.StaticText(PanelPres, -1, ''), 0, wx.ALIGN_CENTER, 5)
1396         sizer2.Add(wx.StaticText(PanelPres, -1, ''), 0, wx.ALIGN_CENTER, 5)
1397         sizer2.Add(grid_sizer_3, 0, wx.ALIGN_CENTER, 5)
1398         sizer2.Add(wx.StaticText(PanelPres, -1, ' '), 0, wx.ALIGN_CENTER, 5)
1399         sizer2.Add(grid_sizer_1, 0, wx.ALIGN_CENTER, 5)
1400         sizer2.Add(labellicence, 0, wx.ALIGN_CENTER, 5)
1401         sizer2.Add(labelcopy, 0, wx.ALIGN_CENTER, 5)
1402         sizer1.Add(sizer4, 2, wx.ALIGN_CENTER_HORIZONTAL, 0)
1403         sizer1.Add(but_ira, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 5)
1404         sizer1.Add(iralink, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_TOP, 5)
1405         sizer2.Add(wx.StaticText(PanelPres, -1, ''), 0, wx.ALIGN_CENTER, 10)
1406         PanelPres.SetSizer(sizer2)
1407         grid_sizer_2.Add(but_python, 1, wx.ALIGN_BOTTOM)
1408         grid_sizer_2.Add(but_lexique, 1, wx.ALIGN_BOTTOM)
1409         grid_sizer_2.Add(but_r, 1,  wx.ALIGN_BOTTOM)
1410         sizer1.Add(PanelPres, 0, wx.EXPAND |wx.ALL, 10)
1411         sizer1.Add(grid_sizer_2, 2, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 1)
1412         self.SetSizer(sizer1)
1413         sizer1.Fit(self)
1414
1415     def OnPython(self,evt):
1416         webbrowser.open('http://www.python.org')
1417
1418     def OnLexique(self,evt):
1419         webbrowser.open('http://www.lexique.org')
1420
1421     def OnR(self,evt):
1422         webbrowser.open('http://www.r-project.org')
1423
1424
1425 #--------------------------------------------------------------------
1426 # ecran d'accueil
1427 # appelé seulement par MyApp
1428 #--------------------------------------------------------------------
1429 class MySplashScreen(wx.adv.SplashScreen):
1430
1431     def __init__(self):
1432         bmp = wx.Image(os.path.join(ImagePath, 'splash.png')).ConvertToBitmap()
1433         wx.adv.SplashScreen.__init__(self, bmp,
1434             wx.adv.SPLASH_CENTRE_ON_SCREEN |
1435             wx.adv.SPLASH_TIMEOUT,
1436             1000,
1437             None,
1438             -1)
1439         self.Bind(wx.EVT_CLOSE, self.OnClose)
1440         self.fc = wx.CallLater(1, self.ShowMain)
1441
1442     def OnClose(self, evt):
1443         evt.Skip()
1444         self.Hide()
1445         if self.fc.IsRunning():
1446             self.fc.Stop()
1447             self.ShowMain()
1448
1449     def ShowMain(self):
1450         displaySize = wx.DisplaySize()
1451         w = displaySize[0]/1.2
1452         h = displaySize[1]/1.2
1453         frame = IraFrame(None, -1, "IRaMuTeQ " + ConfigGlob.get('DEFAULT', 'version'), size=(int(w), int(h)))
1454         frame.Show()
1455         frame.finish_init()
1456         frame.Upgrade()
1457         frame.OnOpenFromCmdl()
1458         #if self.fc.IsRunning():
1459         #    self.Raise()
1460         #wx.CallAfter(frame.ShowTip)
1461
1462
1463 class MyApp(wx.App):
1464
1465     def OnInit(self):
1466         """
1467         Create and show the splash screen.  It will then create and show
1468         the main frame when it is time to do so.
1469         """
1470         wx.SystemOptions.SetOption("mac.window-plain-transition", 1)
1471         self.SetAppName("Iramuteq")
1472         splash = MySplashScreen()
1473         splash.Show()
1474         return True
1475
1476 def main():
1477     app = MyApp(False)
1478     app.MainLoop()
1479
1480 if __name__ == '__main__':
1481     __name__ = 'Main'
1482     main()