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