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