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