message
[iramuteq] / functions.py
1 #!/bin/env python
2 # -*- coding: utf-8 -*-
3 #Author: Pierre Ratinaud
4 #Copyright (c) 2008-2012 Pierre Ratinaud
5 #Lisense: GNU/GPL
6
7 import wx
8 import re
9 from ConfigParser import ConfigParser
10 from subprocess import Popen, call, PIPE
11 import thread
12 import os
13 import ast
14 import sys
15 import csv
16 import platform
17 import traceback
18 import codecs
19 import locale
20 import datetime
21 from copy import copy
22 from shutil import copyfile
23 import shelve
24 #from dialog import BugDialog
25 import logging
26
27 log = logging.getLogger('iramuteq')
28
29
30 indices_simi = [u'cooccurrence' ,'pourcentage de cooccurrence',u'Russel',u'Jaccard', 'Kulczynski1', 'Kulczynski2', 'Mountford', 'Fager', 'simple matching', 'Hamman', 'Faith', 'Tanimoto', 'Dice', 'Phi', 'Stiles', 'Michael', 'Mozley', 'Yule', 'Yule2', 'Ochiai', 'Simpson', 'Braun-Blanquet','Chi-squared', 'Phi-squared', 'Tschuprow', 'Cramer', 'Pearson', 'binomial']
31
32
33 class History :
34     def __init__(self, filein, syscoding = 'utf8') :
35         self.filein = filein
36         self.syscoding = syscoding
37         self.corpora = {}
38         self.openedcorpus = {}
39         self.orph = []
40         self.analyses = {}
41         self.history = []
42         self.opened = {}
43         self.read()
44
45     def read(self) :
46         d = shelve.open(self.filein)
47         self.history = d.get('history', [])
48         self.ordercorpus = dict([[corpus['uuid'], i] for i, corpus in enumerate(self.history)])
49         self.corpus = dict([[corpus['uuid'], corpus] for i, corpus in enumerate(self.history)])
50         self.analyses = dict([[analyse['uuid'], analyse] for corpus in self.history for analyse in corpus.get('analyses', [])])
51         #corpusorder = d.get('corpusorder',[])
52         #self.analyseorder = d['analyseorder']
53         #self.order = [uuid for uuid in self.history]
54         #self.order = dict([[i, uuid] for i, uuid in enumerate(self.order)])
55         #self.order = dict([[i, corpus] for i, corpus in enumerate(corpusorder)])
56         #for uuid in self.history :
57         #    if 'corpus_name' in self.history[uuid] :
58         #        self.corpora[uuid] = self.history[uuid]
59         d.close()
60
61 #    def read(self) :
62 #        self.conf = DoConf(self.filein)
63 #        self.order = {}
64 #        self.ordera = {}
65 #        for i, section in enumerate(self.conf.conf.sections()) :
66 #            if self.conf.conf.has_option(section, 'corpus_name') :
67 #                self.corpora[section] = self.conf.getoptions(section)
68 #                self.order[len(self.order)] = section
69 #            else :
70 #                self.analyses[section] = self.conf.getoptions(section)
71 #                self.ordera[len(self.ordera)] = section
72 #        todel = []
73 #        for corpus in self.corpora :
74 #            self.history[corpus] = copy(self.corpora[corpus])
75 #        for analyse in self.analyses :
76 #            if self.analyses[analyse]['corpus'] in self.corpora :
77 #                if 'analyses' in self.history[self.analyses[analyse]['corpus']] :
78 #                    self.history[self.analyses[analyse]['corpus']]['analyses'].append(self.analyses[analyse])
79 #                    todel.append(analyse)
80 #                else :
81 #                    self.history[self.analyses[analyse]['corpus']]['analyses'] = [self.analyses[analyse]]
82 #                    todel.append(analyse)
83 #            else :
84 #                 self.history[analyse] = self.analyses[analyse]
85 #        #for analyse in todel :
86 #        #    del self.analyses[analyse]
87     def write(self) :
88         d = shelve.open(self.filein)
89         d['history'] = self.history
90         #order = [i for i in self.order]
91         #order.sort()
92         #d['corpusorder'] = [self.order[i] for i in order]
93         d.close()
94
95     
96 #    def write(self) :
97 #        sections = self.corpora.keys() + self.analyses.keys()
98 #        parametres = [self.corpora[key] for key in self.corpora.keys()] + [self.analyses[key] for key in self.analyses.keys()]
99 #        self.conf.makeoptions(sections, parametres)
100 #        log.info('write history')
101 #
102     def add(self, analyse) :
103         log.info('add to history %s' % analyse.get('corpus_name', 'pas un corpus'))
104         tosave = {'uuid' : analyse['uuid'], 'ira': analyse['ira'], 'type' : analyse['type']}
105         if analyse.get('corpus', False) :
106             if analyse['uuid'] in self.analyses :
107                 return
108             tosave['corpus'] = analyse['corpus']
109             tosave['name'] = analyse['name']
110             acorpus_uuid =  analyse['corpus']
111             if acorpus_uuid in self.ordercorpus :
112                 if 'analyses' in self.history[self.ordercorpus[acorpus_uuid]] :
113                     self.history[self.ordercorpus[acorpus_uuid]]['analyses'].append(tosave)
114                 else :
115                     self.history[self.ordercorpus[acorpus_uuid]]['analyses'] = [tosave]
116                 #self.analyses[analyse['uuid']] = tosave
117             else :
118                 self.orph.append(tosave)
119                 #self.order[len(self.order)] = analyse['uuid']
120                 #self.analyses[analyse['uuid']] = tosave
121         else :
122             tosave['corpus_name'] = analyse['corpus_name']
123             self.history.append(tosave)
124             #self.order[len(self.order)] = analyse['uuid']
125             #self.corpora[analyse['uuid']] = tosave
126         self.write()
127         self.read()
128
129     def delete(self, analyse, corpus = False) :
130         if corpus :
131             #del self.history[uuid]
132             self.history.pop(self.ordercorpus[analyse['uuid']])
133             #todel = [i for i in self.order if self.order[i] == uuid]
134             #del self.order[todel[0]]
135             #del self.corpora[uuid]
136             #del self.corpora[uuid]
137             #self.conf.conf.remove_section(uuid)
138             #for analyse in self.history[uuid].get('analyses', [False]) :
139             #    if analyse :
140             #        del self.analyses[analyse['uuid']]
141             #        self.conf.conf.remove_section(analyse['uuid'])
142         else :
143             todel = [i for i, ana in enumerate(self.corpus[analyse['corpus']]['analyses']) if ana['uuid'] == analyse['uuid']][0]
144             self.history[self.ordercorpus[analyse['corpus']]]['analyses'].pop(todel)
145             #del self.analyses[uuid]
146             #self.conf.conf.remove_section(uuid)
147         self.write()
148         self.read()
149
150     def addtab(self, analyse) :
151         self.opened[analyse['uuid']] = analyse
152
153     def rmtab(self, analyse) :
154         del self.opened[analyse['uuid']]
155     
156     def __str__(self) :
157         return str(self.history)
158
159 class DoConf :
160     def __init__(self, configfile=None, diff = None, parametres = None) :
161         self.configfile = configfile
162         self.conf = ConfigParser()
163         if configfile is not None :
164             self.conf.readfp(codecs.open(configfile, 'r', 'utf8'))
165         self.parametres = {}
166         if parametres is not None :
167             self.doparametres(parametres)
168
169     def doparametres(self, parametres) :
170         return parametres
171
172     def getsections(self) :
173         return self.conf.sections()
174
175     def getoptions(self, section = None, diff = None):
176         parametres = {}
177         if section is None :
178             section = self.conf.sections()[0]
179         for option in self.conf.options(section) :
180             if self.conf.get(section, option).isdigit() :
181                 parametres[option] = int(self.conf.get(section, option))
182             elif self.conf.get(section, option) == 'False' :
183                 parametres[option] = False
184             elif self.conf.get(section, option) == 'True' :
185                 parametres[option] = True
186             elif self.conf.get(section, option).startswith('(') and self.conf.get(section, option).endswith(')') :
187                 parametres[option] = ast.literal_eval(self.conf.get(section, option))
188             elif self.conf.get(section, option).startswith('[') and self.conf.get(section, option).endswith(']') :
189                 parametres[option] = ast.literal_eval(self.conf.get(section, option))
190             else :
191                 parametres[option] = self.conf.get(section, option)
192         if 'type' not in parametres :
193             parametres['type'] = section
194         return parametres
195             
196     def makeoptions(self, sections, parametres, outfile = None) :
197         txt = ''
198         for i, section in enumerate(sections) :
199             txt += '[%s]\n' % section
200             if not self.conf.has_section(section) :
201                 self.conf.add_section(section)
202             for option in parametres[i] :
203                 if isinstance(parametres[i][option], int) :
204                     self.conf.set(section, option, `parametres[i][option]`)
205                     txt += '%s = %i\n' % (option, parametres[i][option])
206                 elif isinstance(parametres[i][option], basestring) :
207                     self.conf.set(section, option, parametres[i][option].encode('utf8'))
208                     txt += '%s = %s\n' % (option, parametres[i][option])
209                 elif isinstance(parametres[i][option], wx.Colour) :
210                     self.conf.set(section, option, str(parametres[i][option]))
211                     txt += '%s = %s\n' % (option, str(parametres[i][option]))
212                 elif option == 'analyses' :
213                     pass
214                 else :
215                     self.conf.set(section, option, `parametres[i][option]`)
216                     txt += '%s = %s\n' % (option, `parametres[i][option]`)
217         if outfile is None :
218             outfile = self.configfile
219         with codecs.open(outfile, 'w', 'utf8') as f :
220             f.write(txt)
221             #self.conf.write(f)
222
223     def totext(self, parametres) :
224         #txt = ['Corpus']
225         txt = []
226         for val in parametres :
227             if isinstance(parametres[val], int) :
228                 txt.append(' \t\t: '.join([val, `parametres[val]`]))
229             else :
230                 txt.append(' \t\t: '.join([val, parametres[val]]))
231         return '\n'.join(txt)
232
233
234 def write_tab(tab, fileout) :
235         writer = csv.writer(open(fileout, 'wb'), delimiter=';', quoting = csv.QUOTE_NONNUMERIC)
236         writer.writerows(tab)
237
238 class BugDialog(wx.Dialog):
239     def __init__(self, *args, **kwds):
240         # begin wxGlade: MyDialog.__init__
241         kwds["style"] = wx.DEFAULT_DIALOG_STYLE
242         kwds["size"] = wx.Size(500, 200)
243         wx.Dialog.__init__(self, *args, **kwds)
244         self.text_ctrl_1 = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE)
245         self.button_1 = wx.Button(self, wx.ID_OK, "")
246
247         self.__set_properties()
248         self.__do_layout()
249         # end wxGlade
250
251     def __set_properties(self):
252         # begin wxGlade: MyDialog.__set_properties
253         self.SetTitle("Bug")
254         self.SetMinSize(wx.Size(500, 200))
255         self.text_ctrl_1.SetMinSize(wx.Size(500, 200))
256         
257         # end wxGlade
258
259     def __do_layout(self):
260         # begin wxGlade: MyDialog.__do_layout
261         sizer_1 = wx.BoxSizer(wx.VERTICAL)
262         sizer_1.Add(self.text_ctrl_1, 1, wx.EXPAND, 0)
263         sizer_1.Add(self.button_1, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
264         self.SetSizer(sizer_1)
265         sizer_1.Fit(self)
266         self.Layout()
267
268
269 def CreateIraFile(DictPathOut, clusternb, corpname='corpus_name', section = 'analyse'):
270     AnalyseConf = ConfigParser()
271     AnalyseConf.read(DictPathOut['ira'])
272     AnalyseConf.add_section(section)
273     date = datetime.datetime.now().ctime()
274     AnalyseConf.set(section, 'date', str(date))
275     AnalyseConf.set(section, 'clusternb', clusternb)
276     AnalyseConf.set(section, 'corpus_name', corpname)
277
278     fileout = open(DictPathOut['ira'], 'w')
279     AnalyseConf.write(fileout)
280     fileout.close()
281
282 def sortedby(list, direct, *indices):
283
284     """
285         sortedby: sort a list of lists (e.g. a table) by one or more indices
286                   (columns of the table) and return the sorted list
287
288         e.g.
289          for list = [[2,3],[1,2],[3,1]]:
290          sortedby(list,1) will return [[3, 1], [1, 2], [2, 3]],
291          sortedby(list,0) will return [[1, 2], [2, 3], [3, 1]]
292     """
293
294     nlist = map(lambda x, indices=indices: 
295                  map(lambda i, x=x: x[i], indices) + [x],
296                  list)
297     if direct == 1:
298         nlist.sort()
299     elif direct == 2:
300         nlist.sort(reverse=True)
301     return map(lambda l: l[-1], nlist)
302
303 def add_type(line, dictlem):
304     if line[4] in dictlem:
305         line.append(dictlem[line[4]])
306     else :
307         line.append('')
308     return line
309
310 def treat_line_alceste(i, line) :
311     if line[0] == '*' or line[0] == '*****' :
312         return line + ['']
313     if line[5] == 'NA':
314         print 'NA', line[5]
315         pass
316     elif float(line[5].replace(',', '.')) < 0.0001:
317         line[5] = '< 0,0001'
318     elif float(line[5].replace(',', '.')) > 0.05:
319         line[5] = 'NS (%s)' % str(float(line[5].replace(',', '.')))[0:7]
320     else:
321         line[5] = str(float(line[5].replace(',', '.')))[0:7]
322     return [i, int(line[0]), int(line[1]), float(line[2]), float(line[3]), line[6], line[4], line[5]]
323
324 def ReadProfileAsDico(parent, File, Alceste=False, encoding = sys.getdefaultencoding()):
325     #print 'lecture des profils : ReadProfileAsDico'
326     #if Alceste :
327     #    print 'lecture du dictionnaire de type'
328     #    dictlem = {}
329     #    for line in parent.corpus.lem_type_list :
330     #        dictlem[line[0]] = line[1]
331     dictlem = {}
332     print 'lecture des profiles'
333     #encoding = sys.getdefaultencoding()
334     print encoding
335     FileReader = codecs.open(File, 'r', encoding)
336     Filecontent = FileReader.readlines()
337     FileReader.close()
338     DictProfile = {}
339     count = 0
340     rows = [row.replace('\n', '').replace("'", '').replace('\"', '').replace(',', '.').replace('\r','').split(';') for row in Filecontent]
341     rows.pop(0)
342     ClusterNb = rows[0][2]
343     rows.pop(0)
344     clusters = [row[2] for row in rows if row[0] == u'**']
345     valclusters = [row[1:4] for row in rows if row[0] == u'****']
346     lp = [i for i, line in enumerate(rows) if line[0] == u'****']
347     prof = [rows[lp[i] + 1:lp[i+1] - 1] for i in range(0, len(lp)-1)] + [rows[lp[-1] + 1:len(rows)]] 
348     if Alceste :
349         prof = [[add_type(row, dictlem) for row in pr] for pr in prof]
350         prof = [[treat_line_alceste(i,line) for i, line in enumerate(pr)] for pr in prof] 
351     else :
352         prof = [[line + [''] for line in pr] for pr in prof]
353         prof = [[treat_line_alceste(i,line) for i, line in enumerate(pr)] for pr in prof]
354     for i, cluster in enumerate(clusters):
355         DictProfile[cluster] = [valclusters[i]] + prof[i]
356     return DictProfile
357
358 def GetTxtProfile(dictprofile) :
359     proflist = []
360     for classe in range(0, len(dictprofile)) :
361         prof = dictprofile[str(classe + 1)]
362         clinfo = prof[0]
363         proflist.append('\n'.join([' '.join(['classe %i' % (classe + 1), '-', '%s uce sur %s - %s%%' % (clinfo[0], clinfo[1], clinfo[2])]), '\n'.join(['%5s|%5s|%6s|%6s|%8s|%8s|%20s\t%10s' % tuple([str(val) for val in line]) for line in prof if len(line)==8])]))
364     return '\n\n'.join(proflist)
365
366 def formatExceptionInfo(maxTBlevel=5):
367          cla, exc, trbk = sys.exc_info()
368          excName = cla.__name__
369          try:
370              excArgs = exc.args[0]
371          except :
372              excArgs = "<no args>"
373          excTb = traceback.format_tb(trbk, maxTBlevel)
374          return (excName, excArgs, excTb)
375
376
377 #fonction des etudiants de l'iut
378 def decoupercharact(chaine, longueur, longueurOptimale, separateurs = None) :
379     """
380         on part du dernier caractère, et on recule jusqu'au début de la chaîne.
381         Si on trouve un '$', c'est fini.
382         Sinon, on cherche le meilleur candidat. C'est-à-dire le rapport poids/distance le plus important.
383     """
384     separateurs = [[u'.', 60.0], [u'?', 60.0], [u'!', 60.0], [u'£$£', 60], [u':', 50.0], [u';', 40.0], [u',', 10.0], [u' ', 0.1]]
385     trouve = False                 # si on a trouvé un bon séparateur
386     iDecoupe = 0                # indice du caractere ou il faut decouper
387     
388     # on découpe la chaine pour avoir au maximum 240 caractères
389     longueur = min(longueur, len(chaine) - 1)
390     chaineTravail = chaine[:longueur + 1]
391     nbCar = longueur
392     meilleur = ['', 0, 0]        # type, poids et position du meilleur separateur
393     
394     # on vérifie si on ne trouve pas un '$'
395     indice = chaineTravail.find(u'$')
396     if indice > -1:
397         trouve = True
398         iDecoupe = indice
399
400     # si on ne trouve rien, on cherche le meilleur séparateur
401     if not trouve:
402         while nbCar >= 0:
403             caractere = chaineTravail[nbCar]
404             distance = abs(longueurOptimale - nbCar) + 1
405             meilleureDistance = abs(longueurOptimale - meilleur[2]) + 1
406
407             # on vérifie si le caractére courant est une marque de ponctuation
408             for s in separateurs:
409                 if caractere == s[0]:
410                     # si c'est une ponctuation 
411                     
412                     if s[1] / distance > float(meilleur[1]) / meilleureDistance:
413                         # print nbCar, s[0]
414                         meilleur[0] = s[0]
415                         meilleur[1] = s[1]
416                         meilleur[2] = nbCar
417                         trouve = True
418                         iDecoupe = nbCar
419                         
420                     # et on termine la recherche
421                     break
422
423             # on passe au caractère précédant
424             nbCar = nbCar - 1
425     
426     # si on a trouvé
427     if trouve:
428         fin = chaine[iDecoupe + 1:]
429         retour = chaineTravail[:iDecoupe]
430         return len(retour) > 0, retour.split(), fin
431     # si on a rien trouvé
432     return False, chaine.split(), ''
433
434 def BugReport(parent, error = None):
435     for ch in parent.GetChildren():
436         if "<class 'wx._windows.ProgressDialog'>" == str(type(ch)):
437             ch.Destroy()   
438     excName, exc, excTb = formatExceptionInfo()
439     if excName == 'Exception' :
440         txt = 'Message :\n'
441     else :
442         txt = u'            !== BUG ==!       \n'
443         txt += u'*************************************\n'
444         txt += '\n'.join(excTb).replace('    ', ' ')
445         txt += excName + '\n'
446     txt += exc
447
448     dial = BugDialog(parent)
449     #for line in formatExceptionInfo():
450     #    if type(line) == type([]):
451     #        for don in line:
452     #            txt += don.replace('    ', ' ')
453     #    else:
454     #        txt += line + '\n'
455     if 'Rerror' in dir(parent) :
456         txt += parent.Rerror
457         parent.Rerror = ''
458     #if error is not None :
459     #    txt += '\n%s\n' %error
460     print formatExceptionInfo()
461     log.error(txt)
462     dial.text_ctrl_1.write(txt)
463     dial.CenterOnParent()
464     dial.ShowModal()
465     #raise Exception('Bug')
466     
467 def PlaySound(parent):
468     if parent.pref.getboolean('iramuteq', 'sound') :
469         try:
470             if "gtk2" in wx.PlatformInfo:
471                 error = Popen(['aplay','-q',os.path.join(parent.AppliPath,'son_fin.wav')])
472             else :    
473                 sound = wx.Sound(os.path.join(parent.AppliPath, 'son_fin.wav'))
474                 sound.Play(wx.SOUND_SYNC)
475         except :
476             print 'pas de son'
477
478 def ReadDicoAsDico(dicopath):
479     with codecs.open(dicopath, 'r', 'UTF8') as f:
480         content = f.readlines()
481     dico = {}
482     for line in content :
483         if line[0] != u'':
484             line = line.replace(u'\n', '').replace('"', '').split('\t')
485             dico[line[0]] = line[1:]
486     return dico
487
488 def ReadLexique(parent, lang = 'french'):
489     if lang != 'other' :
490         parent.lexique = ReadDicoAsDico(parent.DictPath.get(lang, 'french'))
491     else :
492         parent.lexique = {}
493
494 def ReadList(filein, encoding = sys.getdefaultencoding()):
495     #file = open(filein)
496     file = codecs.open(filein, 'r', encoding)
497     content = file.readlines()
498     file.close()
499     first = content.pop(0)
500     first = first.replace('\n', '').replace('\r','').replace('\"', '').split(';')
501     dict = {}
502     i = 0
503     for line in content:
504         line = line.replace('\n', '').replace('\r','').replace('\"', '').replace(',', '.')
505         line = line.split(';')
506         nline = [line[0]]
507         for val in line[1:]:
508             if val == u'NA' :
509                 don = ''
510             else: 
511                 try:
512                     don = int(val)
513                 except:
514                     don = float('%.5f' % float(val))
515             nline.append(don)
516         dict[i] = nline
517         i += 1
518     return dict, first
519
520 def exec_rcode(rpath, rcode, wait = True, graph = False):
521     print rpath, rcode
522     needX11 = False
523     if sys.platform == 'darwin' :
524         try :
525             macversion = platform.mac_ver()[0].split('.')
526             print macversion
527             if int(macversion[1]) < 5 :
528                 needX11 = True
529             else :
530                 needX11 = False
531         except :
532             needX11 = False
533
534     rpath = rpath.replace('\\','\\\\')
535     if not graph :
536         if wait :
537             if sys.platform == 'win32':
538                 error = call(["%s" % rpath, "--vanilla","--slave","-f", "%s" % rcode])
539             else :
540                 error = call([rpath, '--vanilla','--slave',"-f %s" % rcode])
541             return error
542         else :
543             if sys.platform == 'win32':
544                 pid = Popen(["%s" % rpath, '--vanilla','--slave','-f', "%s" % rcode])
545             else :
546                 pid = Popen([rpath, '--vanilla','--slave',"-f %s" % rcode], stderr = PIPE)
547             return pid
548     else :
549         if wait :
550             if sys.platform == 'win32':
551                 error = call(["%s" % rpath, '--vanilla','--slave','-f', "%s" % rcode])
552             elif sys.platform == 'darwin' and needX11:
553                 os.environ['DISPLAY'] = ':0.0'
554                 error = call([rpath, '--vanilla','--slave',"-f %s" % rcode])
555             else :
556                 error = call([rpath, '--vanilla','--slave',"-f %s" % rcode])
557             return error
558         else :
559             if sys.platform == 'win32':
560                 pid = Popen(["%s" % rpath, '--vanilla','--slave','-f', "%s" % rcode])
561             elif sys.platform == 'darwin' and needX11:
562                 os.environ['DISPLAY'] = ':0.0'
563                 pid = Popen([rpath, '--vanilla','--slave',"-f %s" % rcode], stderr = PIPE)
564             else :
565                 pid = Popen([rpath, '--vanilla','--slave',"-f %s" % rcode], stderr = PIPE)
566             return pid
567
568 def check_Rresult(parent, pid) :
569     if isinstance(pid, Popen) :
570         if pid.returncode != 0 :
571             error = pid.communicate()
572             error = [str(error[0]), error[1]]
573             if error[1] is None :
574                 error[1] = 'None'
575             parent.Rerror = '\n'.join([str(pid.returncode), '\n'.join(error)])
576             try :
577                 raise Exception('\n'.join(u'Erreur R', '\n'.join(error[1:])))
578             except :
579                 BugReport(parent)
580     else :
581         if pid != 0 :
582             try :
583                 raise Exception(u'Erreur R')
584             except :
585                 BugReport(parent)
586
587 def print_liste(filename,liste):
588     with open(filename,'w') as f :
589         for graph in liste :
590             f.write(';'.join(graph)+'\n')
591
592 def read_list_file(filename, encoding = sys.getdefaultencoding()):
593     with codecs.open(filename,'rU', encoding) as f :
594         content=f.readlines()
595         ncontent=[line.replace('\n','').split(';') for line in content if line.strip() != '']
596     return ncontent
597         
598 class MessageImage(wx.Dialog):
599     def __init__(self, parent,title, size):
600         # begin wxGlade: MyFrame.__init__
601        # kwds["style"] = wx.DEFAULT_FRAME_STYLE
602         #wx.Dialog.__init__(self, *args, **kwds)
603         wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = title, pos = wx.DefaultPosition, size = size, style = wx.DEFAULT_DIALOG_STYLE )
604         self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
605         #self.text_ctrl_1 = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE)
606         self.imageFile = False
607         self.imagename = u"chi_classe.png"
608         self.HtmlPage = wx.html.HtmlWindow(self, -1)
609         self.HtmlPage.SetMinSize(size)
610         if "gtk2" in wx.PlatformInfo:
611             self.HtmlPage.SetStandardFonts()
612         self.HtmlPage.SetFonts('Courier', 'Courier')
613         
614         self.button_1 = wx.Button(self, wx.ID_CANCEL)
615         self.button_2 = wx.Button(self, wx.ID_SAVE)
616         self.Bind(wx.EVT_BUTTON, self.OnCloseMe, self.button_1)
617         self.Bind(wx.EVT_BUTTON, self.OnSaveImage, self.button_2)
618         self.do_layout()
619         # end wxGlade
620
621     def do_layout(self):
622         # begin wxGlade: MyFrame.__do_layout
623         self.sizer_1 = wx.BoxSizer(wx.VERTICAL)
624         self.sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
625         self.sizer_1.Add(self.HtmlPage, 0, wx.EXPAND, 0)
626         #self.sizer_2.Add(self.button_1, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ADJUST_MINSIZE, 0)
627         #self.sizer_1.Add(self.sizer_2, 1, wx.EXPAND, 0)
628
629         self.m_sdbSizer1 = wx.StdDialogButtonSizer()
630         self.m_sdbSizer1.AddButton(  self.button_2 )
631         self.m_sdbSizer1.AddButton(  self.button_1 )
632         self.m_sdbSizer1.Realize()
633         self.sizer_1.Add(self.m_sdbSizer1, 0, wx.EXPAND, 5)
634         self.SetSizer(self.sizer_1)
635         self.Layout()
636         self.sizer_1.Fit( self )
637         # end wxGlade
638
639     def addsaveimage(self, imageFile) :
640         self.imageFile = imageFile
641         
642     def OnCloseMe(self, event):
643         self.Destroy()
644
645     def OnSaveImage(self, event) :
646         dlg = wx.FileDialog(
647             self, message="Enregistrer sous...", defaultDir=os.getcwd(),
648             defaultFile= self.imagename, wildcard="png|*.png", style=wx.SAVE | wx.OVERWRITE_PROMPT
649             )
650         dlg.SetFilterIndex(2)
651         dlg.CenterOnParent()
652         if dlg.ShowModal() == wx.ID_OK:
653             path = dlg.GetPath()
654             copyfile(self.imageFile, path)
655             
656
657 def progressbar(self, maxi) :
658     if 'parent' in dir(self) :
659         parent = self.parent
660     else :
661         parent = self
662     return wx.ProgressDialog("Traitements",
663                              "Veuillez patienter...",
664                              maximum=maxi,
665                              parent=parent,
666                              style=wx.PD_APP_MODAL | wx.PD_AUTO_HIDE | wx.PD_ELAPSED_TIME | wx.PD_CAN_ABORT
667                              )
668
669
670 def treat_var_mod(variables) :
671     var_mod = {}
672     for variable in variables :
673         if u'_' in variable :
674             forme = variable.split(u'_')
675             var = forme[0]
676             mod = forme[1]
677             if not var in var_mod :
678                 var_mod[var] = [variable]
679             else :
680                 if not mod in var_mod[var] :
681                     var_mod[var].append(variable)
682     return var_mod