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