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