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