]> SALOME platform Git repositories - tools/eficas.git/blob - InterfaceTK/widgets.py
Salome HOME
CCAR: merge de la version 1.14 dans la branche principale
[tools/eficas.git] / InterfaceTK / widgets.py
1 # -*- coding: utf-8 -*-
2 #            CONFIGURATION MANAGEMENT OF EDF VERSION
3 # ======================================================================
4 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
5 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
6 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
7 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
8 # (AT YOUR OPTION) ANY LATER VERSION.
9 #
10 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
11 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
12 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
13 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
14 #
15 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
16 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
17 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
18 #
19 #
20 # ======================================================================
21 # ----------------------------------------------------------
22 #   Cette classe sert à définir les widgets utilisés par
23 #          EFICAS
24 # ----------------------------------------------------------
25
26 import Tkinter
27 from Tkinter import *
28 import Pmw
29 import os,sys,re,string
30 import types,fnmatch
31 import traceback
32 from tkFileDialog import *
33 from tkMessageBox import showinfo,askyesno,showerror,askretrycancel
34
35 import fontes
36 import prefs
37 from Editeur.utils import save_in_file
38 from centerwindow import centerwindow
39
40 from Noyau.N_utils import repr_float
41 from Accas import AsException
42
43 # Surcharge de la fonction askyesno qui retourne un resultat errone en Python 2.3 avec Tk 8.4
44 # et Tkinter.wantobject==1
45 import tkMessageBox
46 def askyesno(title=None, message=None, **options):
47     "Ask a question; return true if the answer is yes"
48     s = tkMessageBox._show(title, message, tkMessageBox.QUESTION, tkMessageBox.YESNO, **options)
49     if s == tkMessageBox.YES:return 1
50     if s == tkMessageBox.NO:return 0
51     if s:return 1
52     return 0
53
54     
55 class Fenetre :
56     """ Cette classe permet de créer une fenêtre Toplevel dans laquelle
57         on peut afficher un texte et qui permet de le sauver"""
58     def __init__(self,appli,titre="",texte="",wrap=WORD,width=100,height=30):
59         self.appli=appli
60         if self.appli.test==1 : return
61         self.fenetre = Toplevel()
62         self.fenetre.withdraw()
63         #self.fenetre.configure(width = 800,height=500)
64         self.fenetre.protocol("WM_DELETE_WINDOW", self.quit)
65         self.fenetre.title("Visualisation du "+titre)
66         self.texte = string.replace(texte,'\r\n','\n')
67         self.titre = titre
68         fonte=fontes.standardcourier10
69         # définition des frames
70         self.frame_texte = Frame(self.fenetre)
71         self.frame_boutons = Frame(self.fenetre)
72         #self.frame_texte.place(relx=0,rely=0,relwidth=1,relheight=0.9)
73         #self.frame_boutons.place(relheight=0.1,relx=0,rely=0.9,relwidth=1.)
74         # définition de la zone texte et du scrollbar
75         self.zone_texte = Text(self.frame_texte,font=fonte,wrap=wrap,
76                                height=height,width=width)
77         self.zone_texte.bind("<Key-Prior>", self.page_up)
78         self.zone_texte.bind("<Key-Next>", self.page_down)
79         self.zone_texte.bind("<Key-Up>", self.unit_up)
80         self.zone_texte.bind("<Key-Down>", self.unit_down)
81         self.scroll_v = Scrollbar (self.frame_texte,command = self.zone_texte.yview)
82         #self.scroll_h = Scrollbar (self.frame_texte,command = self.zone_texte.xview)
83         self.scroll_v.pack(side='right',fill ='y')
84         #self.scroll_h.pack(side='bottom',fill ='x')
85         self.zone_texte.pack(side='top',fill='both',expand=1,padx=5,pady=10)
86         self.zone_texte.configure(yscrollcommand=self.scroll_v.set)
87         # définition des boutons
88         self.but_quit = Button(self.frame_boutons,text = "Fermer",command=self.quit,
89                                 default='active')
90         self.but_save = Button(self.frame_boutons,text = "Sauver",command = self.save)
91         #self.but_quit.place(relx=0.4,rely=0.5,anchor='center')
92         #self.but_save.place(relx=0.6,rely=0.5,anchor='center')
93         self.but_quit.pack(side='left',padx=25, pady=5)
94         self.but_save.pack(side='right',padx=25, pady=5)
95         self.frame_texte.pack(side='top',fill='both',expand=1)
96         self.frame_boutons.pack(side='bottom')
97         self.zone_texte.focus_set()
98         self.fenetre.bind('<Return>',self.quit) #dismiss window
99
100         # affichage du texte
101         self.affiche_texte(self.texte)
102         self.zone_texte.config(state=DISABLED)
103         centerwindow(self.fenetre)
104         self.fenetre.deiconify()
105
106     def page_up(self,event):
107         event.widget.yview_scroll(-1, "page")
108         return "break" #Pour eviter la propagation de l'evenement a la fenetre principale
109     def page_down(self,event):
110         event.widget.yview_scroll(1, "page")
111         return "break" #Pour eviter la propagation de l'evenement a la fenetre principale
112     def unit_up(self,event):
113         event.widget.yview_scroll(-1, "unit")
114         return "break" #Pour eviter la propagation de l'evenement a la fenetre principale
115     def unit_down(self,event):
116         event.widget.yview_scroll(1, "unit")
117         return "break" #Pour eviter la propagation de l'evenement a la fenetre principale
118
119     def wait(self):
120         self.fenetre.grab_set()
121         self.zone_texte.focus_set()
122         self.fenetre.wait_window(self.fenetre)
123
124     def quit(self,event=None):
125         self.fenetre.destroy()
126         return "break" #Pour eviter la propagation de l'evenement a la fenetre principale
127
128     def efface_scroll(self):
129         """ Efface le scroll lorsqu'il n'est pas nécessaire : ne marche pas"""
130         self.scroll_v.pack_forget()
131         #self.scroll_h.pack_forget()
132
133     def affiche_texte(self,texte):
134         """ Affiche le texte dans la fenêtre """
135         if texte != "" :
136             self.zone_texte.insert(END,texte)
137             try:
138                 self.fenetre.update_idletasks()
139                 x0,y0,x1,y1 = self.zone_texte.bbox(END)
140                 if (y1-y0) < 300 : self.efface_scroll()
141             except:
142                 pass
143
144     def save(self):
145         """ Permet de sauvegarder le texte dans un fichier dont on a demandé le nom
146         à l'utilisateur """
147         file = asksaveasfilename(parent=self.fenetre,defaultextension = '.comm',
148                                #initialdir = self.appli.CONFIGURATION.rep_user,
149                                initialdir = self.appli.CONFIGURATION.initialdir,
150                                title="Sauvegarde du "+self.titre)
151         if file :
152             if not save_in_file(file,self.texte,None) :
153                 showerror("Sauvegarde impossible",
154                        "Impossible de sauvegarder le texte dans le fichier spécifié\n"+
155                           "Vérifiez les droits d'écriture",parent=self.fenetre)
156             else:
157                 showinfo("Sauvegarde effectuée","Sauvegarde effectuée dans le fichier %s" %file,parent=self.fenetre)
158
159     def destroy(self):
160         try :
161            self.fenetre.destroy()
162         except :
163            pass
164
165 class FenetreSurLigneWarning(Fenetre):
166
167     def affiche_texte(self,texte):
168         """ Affiche le texte dans la fenêtre """
169         ligne=0
170         if texte != "" :
171            texte_cr=texte.splitlines()
172            for l in texte_cr:
173                 ligne=ligne+1
174                 l=l+"\n"
175                 self.zone_texte.insert(END,l)
176                 if (l.find("WARNING") > -1) or (l.find("ERROR") > -1) : 
177                    self.zone_texte.tag_add( "Rouge", str(ligne)+".0", "end-1c" )
178                    self.zone_texte.tag_config("Rouge", foreground='red')
179            try:
180                 self.fenetre.update_idletasks()
181                 x0,y0,x1,y1 = self.zone_texte.bbox(END)
182                 if (y1-y0) < 300 : self.efface_scroll()
183            except:
184                 pass
185
186 class FenetreYesNo(Fenetre):
187     def __init__(self,appli,titre="",texte="",yes="Yes",no="No"):
188         self.appli=appli
189         self.fenetre = Toplevel()
190         self.fenetre.configure(width = 800,height=500)
191         self.fenetre.protocol("WM_DELETE_WINDOW", self.quit)
192         self.fenetre.title(titre)
193         self.texte = string.replace(texte,'\r\n','\n')
194         self.titre = titre
195         fonte=fontes.standardcourier10
196         # définition des frames
197         self.frame_texte = Frame(self.fenetre)
198         self.frame_boutons = Frame(self.fenetre)
199         self.frame_boutons.place(relx=0,rely=0,    relwidth=1.,relheight=0.1)
200         self.frame_texte.place(  relx=0,rely=0.1,  relwidth=1, relheight=0.9)
201         # définition de la zone texte et du scrollbar
202         self.zone_texte = Text(self.frame_texte,font=fonte)
203         self.zone_texte.bind("<Key-Prior>", self.page_up)
204         self.zone_texte.bind("<Key-Next>", self.page_down)
205         self.zone_texte.bind("<Key-Up>", self.unit_up)
206         self.zone_texte.bind("<Key-Down>", self.unit_down)
207         self.scroll_v = Scrollbar (self.frame_texte,command = self.zone_texte.yview)
208         #self.scroll_h = Scrollbar (self.frame_texte,command = self.zone_texte.xview)
209         self.scroll_v.pack(side='right',fill ='y')
210         #self.scroll_h.pack(side='bottom',fill ='x')
211         self.zone_texte.pack(side='top',fill='both',expand=1,padx=5,pady=10)
212         self.zone_texte.configure(yscrollcommand=self.scroll_v.set)
213         # définition des boutons
214         self.but_yes = Button(self.frame_boutons,text = yes,command=self.yes)
215         self.but_no = Button(self.frame_boutons,text = no,command = self.no)
216         self.but_yes.place(relx=0.4,rely=0.5,anchor='center')
217         self.but_no.place(relx=0.6,rely=0.5,anchor='center')
218         # affichage du texte
219         self.affiche_texte(self.texte)
220         centerwindow(self.fenetre)
221
222     def yes(self):
223         self.result=1
224         self.quit()
225
226     def no(self):
227         self.result=0
228         self.quit()
229
230 class FenetreDeSelection(Fenetre):
231     """ Classe dérivée de Fenêtre permettant la récupération d'une zone de texte sélectionnée.
232         Cette classe est utilisée pour affecter une liste de valeurs à un mot-clé.
233     """
234     def __init__(self,panel,item,appli,titre="",texte="",cardinal=1):
235         Fenetre.__init__(self,appli,titre=titre,texte=texte)
236         self.frame_boutons.place_forget()
237         self.frame_texte.place_forget()
238         self.frame_texte.place(relx=0,rely=0,relwidth=1,relheight=0.8)
239         self.frame_boutons.place(relheight=0.2,relx=0,rely=0.8,relwidth=1.)
240
241         self.cardinal=cardinal
242         self.fenetre.configure(width = 320,height=400)
243         centerwindow(self.fenetre)
244         self.panel = panel
245         self.item = item
246         self.fenetre.title(titre)
247         self.but_save.configure(text="Ajouter",command=self.traite_selection)
248         # séparateur par défaut
249         self.separateur = ';'
250         # création de la zone de saisie du séparateur
251         l_separateurs_autorises = self.get_separateurs_autorises()
252         self.choix_sep = Pmw.ComboBox(self.frame_boutons,
253                                       label_text = "Séparateur :",
254                                       labelpos = 'w',
255                                       listheight = 100,
256                                       selectioncommand = self.choose_separateur,
257                                       scrolledlist_items = l_separateurs_autorises)
258         self.choix_sep.component('entry').configure(width=6)
259         self.choix_sep.place(relx=0.01,rely=0.5,anchor='w')
260         self.choix_sep.selectitem(self.separateur)
261         # Replacement
262         self.but_quit.place_forget()
263         self.but_save.place_forget()
264         self.but_all  = Button(self.frame_boutons,text = "Tout Sélectionner", command=self.tout)
265         self.but_save.place(relx=0.6,rely=0.6,anchor='center')
266         self.but_quit.place(relx=0.8,rely=0.6,anchor='center')
267         self.but_all.place(relx=0.7,rely=0.2,anchor='center')
268         self.choose_separateur('espace')
269      
270
271     def get_separateurs_autorises(self):
272         """
273         Retourne la liste des séparateurs autorisés
274         """
275         return ['espace',';',',']
276
277     def choose_separateur(self,nom_sep):
278         """
279         Affecte à self.separateur le caractère séparateur correspondant à nom_sep
280         """
281         if nom_sep == 'espace' :
282             self.separateur = ' '
283         else:
284             self.separateur = nom_sep
285         
286     def tout(self):
287         liste=[]
288         texte=self.texte.splitlines()
289         for l in texte :
290             for mot in string.split(l,self.separateur):
291                if mot != '' and mot != ' ' and mot != self.separateur :
292                   liste.append(mot)
293         self.traite_selection(liste)
294
295     def traite_selection(self,liste=None):
296         """ Cette méthode effectue tous les traitements nécessaires pour vérifier
297             et affecter la liste de valeurs à l'objet réprésenté par self.item
298         """
299         # Récupère la liste des chaines de caractères de la zone sélectionnée
300         message=""
301         if liste == None:
302            message,liste = self.recupere_liste()
303         if self.test_probleme(message,"Sélectionnez des données") == 0:
304             return
305         # Vérifie que le nombre de données est dans les limites attendues
306         message = self.verif_liste(liste)
307         if self.test_probleme(message,"Vérifiez le nombre de données") == 0:
308             return
309         # Crée une liste de valeurs du type attendu
310         message,liste_valeurs = self.creation_liste_valeurs(liste)
311         if self.test_probleme(message,"Vérifiez le type des données") == 0:
312             return
313         # Vérifie que chaque valeur est dans le domaine exigé
314         message = self.verif_valeurs(liste_valeurs)
315         if self.test_probleme(message,"Vérifiez le domaine des valeurs") == 0:
316             return
317         # Ajoute les valeurs dans la liste de valeurs du mot-clé
318         if self.cardinal != 1 :
319            nb=self.cardinal
320            l_valeurs=[]
321            # a ameliorer
322            if (len(liste_valeurs)%nb != 0):
323                 message="La cardinalité n'est pas correcte"
324                 self.test_probleme(message,"On attend des tuples")
325                 return
326            for i in range(len(liste_valeurs)/nb) :
327                if (nb==2):
328                    t=(liste_valeurs[i*nb], liste_valeurs[i*nb+1])
329                elif (nb ==3):
330                    t=(liste_valeurs[i*nb], liste_valeurs[i*nb+1], liste_valeurs[i*nb+2])
331                else :
332                   print "probleme : prevenir la maintenance Eficas"
333                   return
334                l_valeurs.append(t)
335            liste_valeurs=l_valeurs
336         self.ajouter_valeurs(liste_valeurs)
337         self.appli.affiche_infos("Liste de valeurs acceptée")
338
339     def test_probleme(self, message, message_eficas):
340         """ Cette méthode affiche un message d'erreur si message != ''
341             et retourne 0, sinon retourne 1 sans rien afficher.
342         """
343         if message != "":
344             showinfo("Problème",message,parent=self.fenetre)
345             self.fenetre.tkraise()
346             self.appli.affiche_infos(message_eficas)
347             return 0
348         else:
349             return 1
350
351     def recupere_liste(self):
352         """ Cette méthode récupère le texte de la zone sélectionnée, construit et
353             retourne une liste avec les chaines qui se trouvent entre les séparateurs.
354             S'il n'y a pas de données selectionnées, elle retourne un message d'erreur
355             et une liste vide.
356         """
357         message = ""
358         try:
359             selection=self.fenetre.selection_get()
360         except:
361             message = "Pas de donnée sélectionnée"
362             return message,None
363         # les retours chariots doivent être interprétés comme des séparateurs
364         selection = string.replace(selection,'\n',self.separateur)
365         # on splitte la sélection suivant le caractère séparateur
366         liste_chaines = string.split(selection,self.separateur)
367         l_chaines = []
368         for chaine in liste_chaines:
369             chaine = string.strip(chaine)
370             if chaine != '' : l_chaines.append(chaine)
371         return message,l_chaines
372
373     def verif_liste(self, liste):
374         """ Cette méthode effectue des tests sur le nombre d'éléments de la liste
375             et retourne 1 si la liste est correcte, sinon 0 et le message d'erreur
376             correspondant.
377         """
378         message = ""
379         # nombre d'éléments sélectionnés
380         nombre_elements = len(liste)
381         # nombre d'éléments déja dans la liste du panel
382         nombre_in_liste = len(self.panel.Liste_valeurs.get_liste())
383         multiplicite = self.item.GetMultiplicite()
384         if (nombre_elements % multiplicite) != 0:
385             message = "Vous devez sélectionner "+str(multiplicite)+" * n données"
386             return message
387         nombre_valeurs = nombre_elements / multiplicite
388         cardinalite = self.item.GetMinMax()
389         if nombre_valeurs < cardinalite[0]:
390             message = "Vous devez sélectionner au moins "+str(cardinalite[0])+" valeurs"
391             return message
392         if cardinalite[1] != "**" and nombre_valeurs > (long(cardinalite[1])-nombre_in_liste):
393             message = "La liste ne peut avoir plus de "+str(cardinalite[1])+" valeurs"
394             return message
395
396         return message
397
398     def creation_liste_valeurs(self, liste):
399         """ Cette méthode crée et retourne une liste de valeurs du type attendu
400             par le mot-clé. La liste de valeurs est créée à partir de la liste
401             de chaines de caractères transmise.
402         """
403         type_attendu = self.item.GetType()[0]
404         if type_attendu == 'R':
405             return self.convertir(liste, f_conversion= float)
406         elif type_attendu == 'I':
407             return self.convertir(liste, f_conversion= int)
408         elif type_attendu == 'TXM':
409             return self.convertir(liste)
410         else:
411             message = "Seuls les entiers, les réels et les chaines de caractères sont convertis"
412             return message,None
413
414     def convertir(self, liste, f_conversion=None):
415         """ Cette méthode essaie de convertir les éléments de la liste avec la
416             fonction f_conversion si elle existe, et retourne la liste des
417             éléments dans le type voulu en cas de succès, sinon retourne None.
418         """
419         liste_valeurs = []
420         message = ""
421         for chaine in liste:
422             if f_conversion:
423                 try:
424                     liste_valeurs.append(f_conversion(chaine))
425                 except:
426                     message = "Impossible de convertir "+chaine+" dans le type attendu"
427                     return message,None
428             else:
429                 liste_valeurs.append(chaine)
430         return message,liste_valeurs
431
432     def verif_valeurs(self, liste_valeurs):
433         """ Cette méthode teste la validité de tous les éléments de la liste,
434             retourne un message vide s'ils sont valides
435             ou un message non vide au premier élément non valide rencontré
436         """
437         message = ""
438         for valeur in liste_valeurs:
439             test,message = self.item.object.verif_type(valeur)
440             if test == 0: return message
441         return message
442
443     def ajouter_valeurs(self, liste_valeurs):
444         """ Cette méthode ajoute les nouvelles valeurs à la liste existante."""
445         liste = self.panel.Liste_valeurs.get_liste()
446         liste.extend(liste_valeurs)
447         self.panel.Liste_valeurs.put_liste(liste)
448
449 class FenetreDeParametre(Fenetre) :
450     def __init__(self,parent,item,appli,texte):
451         self.parent=parent
452         self.appli=appli
453         self.fenetre = Toplevel()
454         self.fenetre.configure(width = 250,height=100)
455         self.fenetre.protocol("WM_DELETE_WINDOW", self.quit)
456         self.fenetre.title("Parametres")
457         self.titre = "Parametres"
458         self.texte = string.replace(texte,'\r\n','\n')
459         fonte=fontes.standardcourier10
460
461         # définition des frames
462         self.frame_texte = Frame(self.fenetre)
463         self.frame_texte.place(relx=0,rely=0,relwidth=1,relheight=0.7)
464         # définition de la zone texte et du scrollbar
465         self.zone_texte = Text(self.frame_texte,font=fonte)
466         self.zone_texte.bind("<Key-Prior>", self.page_up)
467         self.zone_texte.bind("<Key-Next>", self.page_down)
468         self.zone_texte.bind("<Key-Up>", self.unit_up)
469         self.zone_texte.bind("<Key-Down>", self.unit_down)
470         self.scroll_v = Scrollbar (self.frame_texte,command = self.zone_texte.yview)
471         self.scroll_v.pack(side='right',fill ='y')
472         self.zone_texte.pack(side='top',fill='both',expand=1,padx=5,pady=10)
473         self.zone_texte.configure(yscrollcommand=self.scroll_v.set)
474         # affichage du texte
475         self.affiche_texte(self.texte)
476         self.zone_texte.config(state="disabled")
477
478         # définition des boutons
479         self.frame_boutons = Frame(self.fenetre)
480         self.frame_boutons.place(relheight=0.3,relx=0,rely=0.65,relwidth=1.)
481         self.label1 = Label(self.frame_boutons,text="surligner la")
482         self.label2 = Label(self.frame_boutons,text="ligne entière")
483         self.label1.place(relx=0.1,rely=0)
484         self.label2.place(relx=0.1,rely=0.5)
485         self.but_quit = Button(self.frame_boutons,text = "Fermer",command=self.quit)
486         self.but_save = Button(self.frame_boutons,text = "Choisir",command = self.Choisir)
487         self.but_save.place(relx=0.6,rely=0,relheight=1)
488         self.but_quit.place(relx=0.8,rely=0,relheight=1)
489
490
491     def Choisir(self):
492         try:
493             selection=self.zone_texte.selection_get()
494         except:
495             showerror("Pas de donnée sélectionnée",
496                        "Selectionner un parametre")
497         l_param = ""
498         for param in selection.splitlines():
499             nomparam=param[0:param.find("=")-1]
500             if nomparam != '' : 
501                 l_param=l_param+nomparam+','
502         self.parent.entry.delete(0,Tkinter.END)
503         self.parent.entry.insert(0,l_param[0:-1])
504         self.parent.valid_valeur()
505         self.quit()
506
507 class Formulaire:
508     """
509     Cette classe permet de créer une boîte Dialog dans laquelle
510     on affiche un formulaire à remplir par l'utilisateur
511     """
512     def __init__(self,fen_pere,obj_pere=None,titre="",texte="",items=(),mode='query',commande=None):
513         self.resultat=0
514         if items in ((),[]) : return
515         self.items = items
516         self.titre = titre
517         self.texte = texte
518         self.fen_pere = fen_pere
519         self.obj_pere = obj_pere
520         self.mode= mode
521         self.command = commande
522         self.display()
523
524     def display(self):
525         self.init_validateurs()
526         self.init_fenetre()
527         self.init_texte()
528         self.init_items_formulaire()
529         self.fenetre.activate(geometry='centerscreenalways')
530
531     def init_validateurs(self):
532         """
533         Crée le dictionnaire des validateurs des objets reconnus par le formulaire
534         """
535         self.d_validateurs = {}
536         self.d_validateurs['rep']  = self.repvalidator
537         self.d_validateurs['file'] = self.filevalidator
538         self.d_validateurs['cata']= self.catavalidator
539         self.d_validateurs['mot']= self.motvalidator
540         self.d_validateurs['mot2']= self.mot2validator
541         self.d_validateurs['mot3']= self.mot3validator
542         self.d_validateurs['mot4']= self.mot4validator
543         
544     def init_fenetre(self):
545         """
546         Crée la fenêtre Dialog
547         """
548         if self.mode == 'query':
549             buttons=('Valider','Annuler')
550             defaultbutton = 'Valider'
551         elif self.mode == 'display':
552             if self.command :
553                 buttons=(self.command[0],'OK')
554                 defaultbutton = 'OK'
555             else:
556                 buttons=('OK')
557                 defaultbutton = 'OK'
558         self.fenetre = Pmw.Dialog(self.fen_pere,
559                                   buttons=buttons,
560                                   defaultbutton = defaultbutton,
561                                   title = self.titre,
562                                   command = self.execute)
563         self.fenetre.withdraw()
564         
565     def init_texte(self):
566         """
567         Crée le label qui affiche le texte à l'intérieur du panneau
568         """
569         fonte=fontes.standard
570         fr_texte = Frame(self.fenetre.interior(),height=60)
571         fr_texte.pack(side='top',fill='x',expand=1)
572         Label(fr_texte,text = self.texte, font=fonte).place(relx=0.5,rely=0.5,anchor='center')
573
574     def init_items_formulaire(self):
575         """
576         Crée et affiche les items dans la boîte de dialogue
577         """
578         self.radiobut = 0
579         self.widgets = []
580         self.item_widgets = {}
581         length_maxi = 0
582         for item in self.items:
583             if len(item[0])>length_maxi : length_maxi = len(item[0])
584         window = self.fenetre.interior()
585         for item in self.items :
586             if len(item) == 4 :
587                label,nature,nom_var,defaut = item
588                chaine="Yes" 
589                chaine2="No"
590             else :
591                label,nature,nom_var,defaut,chaine,chaine2 = item
592           
593             # création de la frame
594             fr_item = Frame(window,height=40,width=700)
595             fr_item.pack(side='top',fill='x',expand=1)
596             # création du label
597             Label(fr_item,text = label).place(relx=0.05,rely=0.4)
598             if nature in ('rep','file','cata','mot','mot2','mot3','mot4'):
599                 # création de l'entry
600                 e_item = Entry(fr_item) 
601                 e_item.place(relx=0.5,rely=0.4,relwidth=0.45)
602                 self.widgets.append(e_item)
603                 self.item_widgets[item] = e_item
604                 if defaut : e_item.insert(0,str(defaut))
605             elif nature == 'YesNo':
606                 # création de la StringVar
607                 var = StringVar()
608                 setattr(self,'item_'+nom_var,var)
609                 var.set(defaut)
610                 # création du radiobouton
611                 rb1 = Radiobutton(fr_item,text=chaine,variable=var,value='OUI')
612                 rb2 = Radiobutton(fr_item,text=chaine2,variable=var,value='NON')
613                 rb1.place(relx=0.65,rely=0.5,anchor='center')
614                 rb2.place(relx=0.80,rely=0.5,anchor='center')
615                 self.widgets.append((rb1,rb2))
616                 self.item_widgets[item] = var
617         # détermination de la méthode à appliquer sur les boutons
618         if self.mode == 'query':
619             function = self.active
620         elif self.mode == 'display':
621             function = self.inactive
622         else:
623             return
624         # on applique la méthode sur les boutons (activation ou désactivation)  
625         for widget in self.widgets :
626             if type(widget) == types.TupleType:
627                 for widg in widget :
628                     apply(function,(widg,),{})
629             else:
630                 apply(function,(widget,),{})
631
632     def active(self,widget):
633         """
634         Active le widget passé en argument
635         """
636         widget.configure(state='normal',bg='white')
637
638     def inactive(self,widget):
639         """
640         Inactive le widget passé en argument
641         """
642         if not isinstance(widget,Radiobutton) :
643             widget.configure(state='disabled',bg='gray95')
644         else :
645             widget.configure(state='disabled')
646
647 # --------------------------------------------------------------------------------
648 #       Validateurs des noms de répertoire, de fichiers et de catalogues
649 # -------------------------------------------------------------------------------
650
651     def motvalidator(self,text):
652         text2="("+text+")"
653         return self.motlongueurvalidator(text2,1) 
654
655     def mot2validator(self,text):
656         return self.motlongueurvalidator(text,2) 
657
658     def mot3validator(self,text):
659         return self.motlongueurvalidator(text,3) 
660
661     def mot4validator(self,text):
662         return self.motlongueurvalidator(text,4) 
663
664     def motlongueurvalidator(self,text,longueur):
665         try :
666           if ((text[0] != "(") or (text[-1] != ")")) : return 0
667           if len(text.split(",")) != longueur : return 0
668           return 1
669         except :
670           return 0
671
672     def repvalidator(self,text):
673         """
674         Teste si text peut faire référence à un répertoire ou non
675         Retourne 1 si valide, 0 sinon
676         """
677         return os.path.isdir(text),'Répertoire introuvable : %s' %text
678
679     def filevalidator(self,text):
680         """
681         Teste si text peut faire référence à un fichier ou non
682         Retourne 1 si valide, 0 sinon
683         """
684         return os.path.isfile(text),'Fichier introuvable : %s' %text
685
686     def catavalidator(self,text):
687         """
688         Teste si  text est un chemin d'accès valide à un catalogue
689         Retourne 1 si valide, 0 sinon
690         """
691         return os.path.isfile(text),"Catalogue introuvable : %s" %text
692
693 # --------------------------------------------------------------------------------
694 #       Méthodes callbacks des boutons et de fin
695 # --------------------------------------------------------------------------------
696         
697     def execute(self,txt):
698         """
699         Cette commande est activée à chaque clic sur un bouton.
700         Redirige l'action sur la bonne méthode en fonction du bouton activé
701         """
702         if txt == 'Valider':
703             self.fini()
704         elif txt in ('OK','Annuler'):
705             self.quit()
706         elif txt == 'Modifier':
707             self.resultat = apply(self.command[1],(),{})
708             self.fenetre.destroy()
709         else :
710             print "Nom de bouton inconnu"
711             self.quit()
712
713     def fini(self):
714         """
715         Commande qui termine le panneau et sauvegarde les nouvelles options
716         dans l'objet resultat (dictionnaire)
717         """
718         dico={}
719         for item,widget in self.item_widgets.items():
720             nom_var = item[2]
721             type_var = item[1]
722             valeur = widget.get()
723             if self.d_validateurs.has_key(type_var):
724                 test = self.d_validateurs[type_var](valeur)
725                 if not test :
726                     # une entrée n'est pas valide --> on la met en surbrillance et on quitte la méthode
727                     # sans tuer la fenêtre bien sûr
728                     widget.selection_range(0,END)
729                     return
730             dico[nom_var] = valeur
731         self.fenetre.destroy()    
732         self.resultat=dico
733         
734     def quit(self):
735         self.fenetre.destroy()
736         self.resultat=None
737         
738 class ListeChoix :
739     """ Cette classe est utilisée pour afficher une liste de choix passée en paramètre
740         en passant les commandes à lancer suivant différents bindings """
741     def __init__(self,parent,page,liste,liste_commandes=[],liste_marques =[],active ='oui',filtre='non',titre='',
742                  optionReturn=None, fonte_titre=fontes.standard_gras_souligne):
743         self.parent = parent
744         self.page = page
745         self.liste = liste
746         self.dico_labels={}
747         self.dico_mots={}
748         self.nBlabel = 0
749         self.dico_place={}
750         self.dico_mots={}
751         self.selection = None
752         self.liste_commandes = liste_commandes
753         self.liste_marques = liste_marques
754         self.arg_selected=''
755         self.active = active
756         self.titre = titre
757         self.filtre = filtre
758         self.optionReturn = optionReturn
759         self.fonte_titre=fonte_titre
760         self.init()
761
762     def init(self):        
763         self.make_label_titre()
764         self.make_entry_filtre()
765         self.make_text_box()
766         try:
767             self.entry.component('entry').focus()
768         except:
769             pass
770
771     def make_label_titre(self):
772         """ Crée le label correspondant au titre """
773         if self.titre == '' : return
774         self.label = Label(self.page,
775                            text = self.titre,
776                            font = self.fonte_titre)
777         self.label.pack(side='top',pady=2)
778         
779     def make_entry_filtre(self):
780         """ Crée l'entry permettant à l'utilisateur d'entrer un filtre de sélection dans la liste """
781         if self.filtre != 'oui' : return
782         self.entry = Pmw.EntryField(self.page,labelpos='w',
783                                     label_text="Filtre :",
784                                     command=self.entry_changed)
785         self.entry.pack(side='top',pady=2)
786         
787     def make_text_box(self):
788         """ Crée la fenêtre texte dans laquelle sera affichée la liste """
789         self.MCbox = Text (self.page,relief='sunken',bg='gray95',bd=2)
790         self.MCscroll = Scrollbar (self.page,command = self.MCbox.yview)
791         self.MCscroll.pack(side='right',fill ='y',pady=2)
792         self.MCbox.pack(fill='y',expand=1,padx=2,pady=2)
793         self.MCbox.configure(yscrollcommand=self.MCscroll.set)
794
795
796     def affiche_liste(self):
797         """ Affiche la liste dans la fenêtre"""
798         liste_labels=[]
799         self.MCbox.config(state=NORMAL)
800         self.MCbox.delete(1.0,END)
801         self.nBlabel = 0
802         self.dico_place={}
803         for objet in self.liste :
804           if type(objet) == types.InstanceType:
805               try:
806                   mot = objet.nom
807               except:
808                   mot = str(objet)
809           elif type(objet) in (types.StringType,types.IntType):
810               mot = objet
811           elif type(objet) == types.FloatType :
812               mot = self.parent.get_valeur_texte(objet)
813               if mot == "" :
814                  mot = str(objet)
815           elif type(objet) == types.TupleType :
816               mot="("
817               premier=1
818               for val in objet:
819                  if (not premier):
820                    mot=mot+"," 
821                  else:
822                    premier=0
823                  valtexte = self.parent.get_valeur_texte(val)
824                  if valtexte != "" :
825                     mot=mot+valtexte
826                  else:
827                     mot=mot+str(val)
828               mot=mot+")"
829           elif string.find(str(type(objet)),".SD.") :
830               mot=objet.nom
831           else :
832               mot=`objet`
833           label = Label(self.MCbox,
834                         text = mot,
835                         fg = 'black',bg = 'gray95',justify = 'left')
836           self.dico_labels[mot]=label
837           self.dico_place[mot]=self.nBlabel
838           self.dico_mots[label]=mot
839           self.nBlabel=self.nBlabel+1
840           liste_labels.append(label)
841           self.MCbox.window_create(END,
842                                    window=label,
843                                    stretch = 1)
844           self.MCbox.insert(END,'\n')
845           if self.optionReturn != None :
846               label.bind("<Return>",lambda e,s=self,c=self.liste_commandes[2][1],x=objet,l=label : s.chooseitemsurligne(x,l,c))
847               label.bind("<KP_Enter>",lambda e,s=self,c=self.liste_commandes[2][1],x=objet,l=label : s.chooseitemsurligne(x,l,c))
848           label.bind("<Key-Right>",lambda e,s=self,x=objet,l=label : s.selectNextItem(x,l))
849           label.bind("<Key-Down>",lambda e, s=self,x=objet,l=label : s.selectNextItem(x,l))
850           label.bind("<Key-Left>" ,lambda e,s=self,x=objet,l=label  : s.selectPrevItem(x,l))
851           label.bind("<Key-Up>" ,lambda e,s=self,x=objet,l=label  : s.selectPrevItem(x,l))
852           if self.active == 'oui':
853               label.bind(self.liste_commandes[0][0],lambda e,s=self,c=self.liste_commandes[0][1],x=objet,l=label : s.selectitem(x,l,c))
854               label.bind(self.liste_commandes[1][0],lambda e,s=self,c=self.liste_commandes[1][1],x=objet,l=label : s.deselectitem(l,x,c))
855               label.bind(self.liste_commandes[2][0],lambda e,s=self,c=self.liste_commandes[2][1],x=objet,l=label : s.chooseitem(x,l,c))
856
857         for marque in self.liste_marques:
858            try:
859               self.markitem(liste_labels[marque])
860            except:
861               pass
862
863         self.MCbox.config(state=DISABLED)
864         self.selection = None
865         self.dontselect=0
866         for event,callback in self.liste_commandes:
867             if event == "<Enter>":
868                self.selection=None,None,callback
869                break
870
871     def clear_marque(self):
872         try:
873           self.dico_labels[self.arg_selected].configure(bg='gray95',fg='black')
874           self.arg_selected = ''
875         except :
876           pass
877
878     def surligne(self,marque):
879         try :
880            self.highlightitem(self.dico_labels[marque])
881            self.arg_selected = marque
882         except:
883            pass
884
885     def chooseitemsurligne(self,mot,label,commande):
886         """ Active la méthode de choix passée en argument"""
887         try:
888            mot=self.arg_selected
889            commande(mot)
890         except AsException,e:
891            raison=str(e)
892            showerror(raison.split('\n')[0],raison)
893
894     def chooseitem(self,mot,label,commande):
895         """ Active la méthode de choix passée en argument"""
896         try:
897            commande(mot)
898         except AsException,e:
899            raison=str(e)
900            showerror(raison.split('\n')[0],raison)
901
902     def afficheMot(self,mot):
903         """ Pour contourner le bug sur l index 
904             on commence par la methode dite normale     
905             puis par la methode de contournement     
906             puis rien du tout 
907         """
908         try:
909              labelsuivant=self.dico_labels[mot]
910              index = self.MCbox.index(labelsuivant)
911              self.MCbox.see(index)
912         except :
913              posmot=self.dico_place[mot]
914              totale=self.nBlabel + 0.0
915              self.MCbox.yview_moveto(posmot/totale)
916
917     def selectNextItem(self,mot,label):
918         index=self.liste.index(mot)
919         indexsuivant=index+1
920         if indexsuivant > len(self.liste) -1:
921            indexsuivant=0
922         motsuivant=self.liste[indexsuivant]
923         labelsuivant=self.dico_labels[motsuivant]
924         self.afficheMot(motsuivant)
925         self.selectthis(motsuivant,labelsuivant,self.selection[2],)
926         self.dontselect=1
927            
928     def selectPrevItem(self,mot,label):
929         index=self.liste.index(mot)
930         indexprec=index-1
931         motprec=self.liste[indexprec]
932         labelprec=self.dico_labels[motprec]
933         self.afficheMot(motprec)
934         self.selectthis(motprec,labelprec,self.selection[2],)
935         self.dontselect=1
936         
937     def selectthis(self,mot,label,commande) :
938         self.clear_marque()
939         if self.selection != None :
940             self.deselectitem(self.selection[1],self.selection[0],self.selection[2],)
941         self.highlightitem(label)
942         self.selection = (mot,label,commande)
943         self.arg_selected = mot
944         if commande : commande(mot)
945
946     def selectitem(self,mot,label,commande) :
947         """ Met l'item sélectionné (représenté par son label) en surbrillance
948             et lance la commande associée au double-clic"""
949         if self.dontselect:
950            self.dontselect=0
951            return
952         self.selectthis(mot,label,commande)
953
954     def highlightitem(self,label) :
955         """ Met l'item représenté par son label en surbrillance """
956         label.focus_set()
957         label.configure(bg='#00008b',fg='white')
958         
959     def markitem(self,label):
960         """ Met l'item (représenté par son label) en rouge """
961         label.configure(bg='gray95',fg='red')
962         
963     def deselectitem(self,label,mot='',commande=None) :
964         """ Remet l'item (représenté par son label) en noir"""
965         if label:label.configure(bg='gray95',fg='black')
966         self.arg_selected = ''
967         if commande and mot : commande(mot)
968
969     def cherche_selected_item(self):
970         try :
971            index=self.MCbox.index(self.selection[1])
972            lign,col=map(int,string.split(index,'.'))
973         except :
974            label=self.dico_labels[self.arg_selected]
975            mot=self.dico_mots[label] 
976            lign=self.dico_place[mot]+1
977         return lign
978
979     def remove_selected_item(self):
980         try :
981            index=self.MCbox.index(self.selection[1])
982            lign,col=map(int,string.split(index,'.'))
983         except :
984            label=self.dico_labels[self.arg_selected]
985            mot=self.dico_mots[label] 
986            lign=self.dico_place[mot]+1
987         del self.liste[lign-1]
988         self.affiche_liste()
989
990     def entry_changed(self,event=None):
991         """ Cette méthode est invoquée chaque fois que l'utilisateur modifie le contenu
992         de l'entry et frappe <Return>"""
993         if self.arg_selected != '' : self.deselectitem(self.dico_labels[self.arg_selected])
994         filtre = self.entry.get()+"*"
995         FILTRE = string.upper(filtre)
996         self.dontselect=0
997         for arg in self.liste :
998             if fnmatch.fnmatch(arg,filtre) or fnmatch.fnmatch(arg,FILTRE) :
999                 label=self.dico_labels[arg]
1000                 self.afficheMot(arg)
1001                 self.selectitem(arg,label,self.selection[2])
1002                 break
1003
1004         #try :
1005           #self.dico_labels[self.arg_selected].focus_set()
1006         #except :
1007           #pass
1008
1009
1010     # PN attention à la gestion des paramétres
1011     # cela retourne H = 1 , et ni H, ni 1
1012     #            print repr(val)
1013     #            print val.__class__.__name__
1014     def get_liste(self):
1015         l=[]
1016         for val in self.liste:
1017 #            try:
1018 #                v = eval(val)
1019 #                    l.append(v)
1020 #            except:
1021                 l.append(val)
1022         return l
1023     
1024     def put_liste(self,liste):
1025         self.liste = liste
1026         self.affiche_liste()
1027
1028 class Affichage :
1029   """ Cette classe permet d'afficher au lancement d'EFICAS le message
1030       d'attente et la barre de progression"""
1031   def __init__(self,master,message,barre ='oui'):
1032       from Tools.foztools.foztools import Slider
1033       fonte=fontes.standard12_gras
1034       self.master=master
1035       self.frame = Frame(self.master)
1036       self.frame.pack(expand=1,fill='both')
1037       self.mess = Label(self.frame,text=message,justify='center',
1038                         bd=2,relief='groove',font=fonte)
1039       self.mess.pack(in_ = self.frame,side='top',expand=1,fill='both')
1040       self.progress = Slider(self.frame,value=0,max=100,orientation='horizontal',
1041                              fillColor='#00008b',width=200,height=30,
1042                              background='white',labelColor='red')
1043       if barre == 'oui':
1044           self.progress.frame.pack(in_=self.frame,side='top')
1045       self.master.update()
1046       if barre == 'oui':
1047           self.progress.frame.after(1000,self.update)
1048
1049   def configure(self,**options):
1050       if options.has_key('message'):
1051           self.mess.configure(text=options['message'])
1052       if options.has_key('barre'):
1053           if options['barre'] == 'oui' :
1054               self.progress.frame.pack(in_=self.frame,side='top')
1055           elif options['barre'] == 'non' :
1056               self.progress.frame.pack_forget()
1057       self.master.update_idletasks()
1058       
1059   def quit(self):
1060       self.frame.destroy()
1061       self.master.update()
1062
1063   def update(self,event=None):
1064       """ Permet de faire avancer la barre de progression """
1065       try :
1066           bar=self.progress
1067           bar.value = bar.value+self.increment
1068           bar.update()
1069           self.master.after(100,self.update)
1070       except:
1071           pass
1072
1073   def configure_barre(self,nb):
1074       """ Calcule l'incrément de progression de la barre en fonction
1075           du nombre d'opérations à effectuer afin que le compteur
1076           soit à 100% à la fin des opérations"""
1077       self.increment = 100./nb
1078       self.progress.update()
1079
1080 class Ask_Format_Fichier :
1081     """
1082     Cette classe permet de créer une fenêtre Toplevel dans laquelle
1083     on propose le choix du format de fichier de commandes à ouvrir
1084     """
1085     def __init__(self,appli):
1086         self.fenetre = Toplevel()
1087         self.fenetre.configure(width = 250,height=150)
1088         self.fenetre.protocol("WM_DELETE_WINDOW", self.quit)
1089         self.fenetre.title("Choix du format du fichier de commandes")
1090         # définition des frames
1091         self.frame_texte = Frame(self.fenetre)
1092         self.frame_radioboutons = Frame(self.fenetre)
1093         self.frame_bouton_ok = Frame(self.fenetre)
1094         self.frame_texte.place(relx=0,rely=0,relwidth=1,relheight=0.3)
1095         self.frame_radioboutons.place(relheight=0.5,relx=0,rely=0.3,relwidth=1.)
1096         self.frame_bouton_ok.place(relheight=0.2,relx=0,rely=0.8,relwidth=1.)
1097         # définition de la zone texte et du scrollbar
1098         zone_texte = Label(self.frame_texte,text = "Format du fichier à ouvrir :")
1099         zone_texte.pack(side='top',fill='both',expand=1,padx=5,pady=10)
1100         # définition des radioboutons
1101         Radiobutton(self.frame_radioboutons,text='Format Aster (Code_Aster --> v5)',
1102                     variable=appli.format_fichier,value='Aster').pack(anchor='n')
1103         Radiobutton(self.frame_radioboutons,text='Format Python (Code_Aster v6-->)',
1104                     variable=appli.format_fichier,value='Python').pack(anchor='n')
1105         # création du bouton OK
1106         Button(self.frame_bouton_ok,text='OK',command=self.quit).pack(anchor='n')
1107         # centrage de la fenêtre
1108         centerwindow(self.fenetre)
1109
1110     def quit(self):
1111         self.fenetre.destroy()
1112
1113 class BARRE_K2000(Toplevel):
1114     def __init__(self,master=None,text = ""):
1115         Toplevel.__init__(self,master,relief='groove')
1116         self.master.iconify()
1117         self.geometry("250x100+0+0")
1118         self.protocol("WM_DELETE_WINDOW",self.quit)
1119         # frame principale dans self (= Toplevel)
1120         self.frame = Frame(self)
1121         self.frame.place(relwidth=1,relheight=1)
1122         # frame contenant le texte à afficher 
1123         self.frame_text = Frame(self.frame)
1124         self.frame_text.place(relwidth=1,relheight=0.75,rely=0)
1125         # frame contenant le canvas de la barre
1126         self.frame_canv = Frame(self.frame)
1127         self.frame_canv.place(relwidth=1,relheight=0.25,rely=0.75)
1128         # canvas dans lequel sera affichée la barre K2000
1129         self.canvas = Canvas(self.frame_canv)
1130         self.canvas.place(relx=0.5,rely=0.5,relheight=0.8,relwidth=0.8,anchor='center')
1131         # on affiche le texte et la barre
1132         self.build_text(text)
1133         self.build_batons()
1134         #self.overrideredirect(1)
1135         # on active la barre ...
1136         self.master.after(1000,self.launch)
1137         # on centre la fenêtre
1138         centerwindow(self)
1139         self.focus()
1140
1141     def build_text(self,text):
1142         """
1143         Affichage de text dans frame_text
1144         """
1145         self.texte_var = StringVar()
1146         self.texte_var.set(text)
1147         Label(self.frame_text,textvariable=self.texte_var).place(relx=0.5,rely=0.5,anchor='center')
1148         
1149     def build_batons(self):
1150         """
1151         Construit la suite de bâtons dans le canvas
1152         """
1153         self.l_batons=[]
1154         self.black = -1
1155         self.sens = 'D'
1156         self.quit = 0
1157         for i in range(0,40):
1158             id = self.canvas.create_rectangle(i*5,0,(i+1)*5,20,fill='gray90',outline='')
1159             self.l_batons.append(id)
1160
1161     def launch(self):
1162         """
1163         Active la barre K2000 en affichant les bâtons avec des couleurs en dégradé
1164         """
1165         if self.quit == 1 :
1166             self.destroy()
1167             self.master.deiconify()
1168             return
1169         if self.sens == 'D':
1170             self.black = self.black+1
1171             l_bat = self.l_batons[0:self.black+1]
1172             l_bat.reverse()
1173         elif self.sens == 'G':
1174             self.black = self.black-1
1175             l_bat = self.l_batons[self.black:]
1176         i=0
1177         for bat in l_bat :
1178             num_color = 5+i*10
1179             if num_color < 10 : color = 'black'
1180             elif num_color > 90 : color = 'white'
1181             else: color = 'gray'+`num_color`
1182             self.canvas.itemconfigure(bat,fill=color)
1183             i=i+1
1184         if self.black == len(self.l_batons) :
1185             self.sens = 'G'
1186         if self.black == 0 and self.sens == 'G':self.sens = 'D'
1187         self.after(80,self.launch)
1188
1189     def update_text(self,new_text):
1190         """
1191         Remplace le texte affiché par new_text
1192         """
1193         self.texte_var.set(new_text)
1194         
1195     def quit(self):
1196         self.quit = 1        
1197
1198 class ListeChoixParGroupes(ListeChoix) :
1199     """ 
1200         Cette classe est utilisée pour afficher une liste de commandes classées par
1201         groupes. L'utilisateur peut réaliser des actions de selection
1202         qui déclenchent des actions spécifiées par les bindings contenus dans liste_commandes
1203         Exemple de binding:
1204            liste_commandes = (("<Enter>",self.selectCmd),
1205                               ("<Leave>",self.deselectCmd),
1206                               ("<Double-Button-1>",self.defCmd))
1207         Il s'agit d'une liste de doublets dont le premier element est un evenement et le 
1208         deuxieme un callback a appeler sur l'evenement en question.
1209
1210     """
1211     def __init__(self,parent,page,liste_groupes,dict_groupes,liste_commandes=[],liste_marques =[],
1212                       active ='oui',filtre='non',titre='',optionReturn=None,fonte_titre=fontes.standard_gras_souligne):
1213         self.parent = parent
1214         self.page = page
1215         self.liste_groupes = liste_groupes
1216         self.dict_groupes = dict_groupes
1217         self.dico_labels={}
1218         self.selection = None
1219         self.liste_commandes = liste_commandes
1220         self.liste_marques = liste_marques
1221         self.arg_selected=''
1222         self.active = active
1223         self.titre = titre
1224         self.filtre = filtre
1225         self.optionReturn = optionReturn
1226         self.fonte_titre=fonte_titre
1227         self.init()
1228
1229     def affiche_liste(self):
1230         """ Affiche la liste dans la fenêtre"""
1231         liste_labels=[]
1232         self.dico_mots={}
1233         self.MCbox.config(state=NORMAL)
1234         self.MCbox.delete(1.0,END)
1235         for grp in self.liste_groupes:
1236            # On itère sur les groupes
1237            if grp == "CACHE":continue
1238            liste_commandes=self.dict_groupes[grp]
1239            text="GROUPE<<<<<<<< "+grp+" "
1240            text=text+">"*max(0,30-len(text))
1241            label = Label(self.MCbox,
1242                         text = text,
1243                         fg = 'black',bg = 'gray95',justify = 'left')
1244            # On stocke la relation entre le nom de la commande et le label
1245            self.dico_labels[grp]=label
1246            liste_labels.append(label)
1247            self.MCbox.window_create(END,
1248                                    window=label,
1249                                    stretch = 1)
1250            self.MCbox.insert(END,'\n')
1251            for cmd in liste_commandes:
1252               label = Label(self.MCbox,
1253                         text = cmd,
1254                         fg = 'black',bg = 'gray95',justify = 'left')
1255               # On stocke la relation entre le nom de la commande et le label
1256               self.dico_labels[cmd]=label
1257               self.dico_mots[label]=cmd
1258               self.MCbox.window_create(END,
1259                                    window=label,
1260                                    stretch = 1)
1261               self.MCbox.insert(END,'\n')
1262
1263               def null(*tp,**args): return
1264
1265               if self.active == 'oui':
1266                   # Traitement par defaut des evenements
1267                   label.bind("<Enter>",lambda e,s=self,c=null,x=cmd,l=label: s.selectitem(x,l,c))
1268                   label.bind("<Leave>",lambda e,s=self,c=null,x=cmd,l=label: s.deselectitem(l,x,c))
1269                   label.bind("<Double-Button-1>",lambda e,s=self,c=null,x=cmd,l=label: s.chooseitem(x,l,c))
1270                   label.bind("<Return>",lambda e,s=self,c=null,x=cmd,l=label: s.chooseitem(x,l,c))
1271                   label.bind("<KP_Enter>",lambda e,s=self,c=null,x=cmd,l=label: s.chooseitem(x,l,c))
1272                   label.bind("<Key-Right>",lambda e,s=self,c=null,x=cmd,l=label,gr=grp: s.selectNextItem(x,l,c,gr,x))
1273                   label.bind("<Key-Down>",lambda e,s=self,c=null,x=cmd,l=label,gr=grp: s.selectNextItem(x,l,c,gr,x))
1274                   label.bind("<Key-Left>",lambda e,s=self,c=null,x=cmd,l=label,gr=grp: s.selectPrevItem(x,l,c,gr,x))
1275                   label.bind("<Key-Up>",lambda e,s=self,c=null,x=cmd,l=label,gr=grp: s.selectPrevItem(x,l,c,gr,x))
1276
1277                   # Si des callbacks sont definis on les utilise
1278                   for event,callback in self.liste_commandes:
1279                       if event == "<Enter>":
1280                          label.bind("<Enter>",lambda e,s=self,c=callback,x=cmd,l=label: s.selectitem(x,l,c))
1281                       elif event == "<Leave>":
1282                          label.bind("<Leave>",lambda e,s=self,c=callback,x=cmd,l=label: s.deselectitem(l,x,c))
1283                       elif event == "<Double-Button-1>":
1284                          label.bind("<Double-Button-1>",lambda e,s=self,c=callback,x=cmd,l=label: s.chooseitem(x,l,c))
1285                       elif event == "<Return>":
1286                          label.bind("<Return>",lambda e,s=self,c=callback,x=cmd,l=label: s.chooseitem(x,l,c))
1287                       elif event == "<KP_Enter>":
1288                          label.bind("<KP_Enter>",lambda e,s=self,c=callback,x=cmd,l=label: s.chooseitem(x,l,c))
1289                       elif event == "<Key-Right>":
1290                          label.bind("<Key-Right>",lambda e,s=self,c=callback,x=cmd,l=label,gr=grp:s.selectNextItem(x,l,c,gr,x))
1291                       elif event == "<Key-Down>":
1292                          label.bind("<Key-Down>",lambda e,s=self,c=callback,x=cmd,l=label,gr=grp:s.selectNextItem(x,l,c,gr,x))
1293                       elif event == "<Key-Left>":
1294                          label.bind("<Key-Left>",lambda e,s=self,c=callback,x=cmd,l=label,gr=grp:s.selectPrevItem(x,l,c,gr,x))
1295                       elif event == "<Key-Up>":
1296                          label.bind("<Key-Up>",lambda e,s=self,c=callback,x=cmd,l=label,gr=grp:s.selectPrevItem(x,l,c,gr,x))
1297                       else:
1298                          label.bind(event,lambda e,s=self,c=callback,x=cmd,l=label: c())
1299
1300         for marque in self.liste_marques:
1301            try:
1302               self.markitem(liste_labels[marque])
1303            except:
1304               pass
1305
1306         self.MCbox.config(state=DISABLED)
1307         self.selection = None
1308         self.dontselect=0
1309         for event,callback in self.liste_commandes:
1310             if event == "<Enter>":
1311                self.selection=None,None,callback
1312                break
1313
1314     def selectPrevItem(self,mot,label,callback,group,cmd):
1315         g=self.liste_groupes.index(group)
1316         liste_commandes=self.dict_groupes[group]
1317         c=liste_commandes.index(cmd)
1318         if c > 0:
1319            co=liste_commandes[c-1]
1320         else:
1321            # debut de liste. On passe au groupe precedent
1322            if g > 0:
1323               gr=self.liste_groupes[g-1]
1324               co=self.dict_groupes[gr][-1]
1325            else:
1326               # debut des groupes. On ne fait rien
1327               return
1328         # On a trouve l'item precedent
1329         labelsuivant=self.dico_labels[co]
1330         index = self.MCbox.index(labelsuivant)
1331         self.MCbox.see(index)
1332         self.selectthis(co,labelsuivant,self.selection[2],)
1333         self.dontselect=1
1334
1335     def selectNextItem(self,mot,label,callback,group,cmd):
1336         g=self.liste_groupes.index(group)
1337         liste_commandes=self.dict_groupes[group]
1338         c=liste_commandes.index(cmd)
1339         try:
1340            co=liste_commandes[c+1]
1341         except:
1342            # fin de liste. On passe au groupe suivant
1343            try:
1344               gr=self.liste_groupes[g+1]
1345               co=self.dict_groupes[gr][0]
1346            except:
1347               # fin des groupes. On ne fait rien
1348               return
1349         # On a trouve l'item suivant
1350         labelsuivant=self.dico_labels[co]
1351         index = self.MCbox.index(labelsuivant)
1352         self.MCbox.see(index)
1353         self.selectthis(co,labelsuivant,self.selection[2],)
1354         self.dontselect=1
1355
1356     def entry_changed(self,event=None):
1357         """ 
1358             Cette méthode est invoquée chaque fois que l'utilisateur modifie le contenu
1359             de l'entry et frappe <Return>
1360         """
1361         if self.arg_selected != '' : self.deselectitem(self.dico_labels[self.arg_selected])
1362
1363         filtre = self.entry.get()+"*"
1364         FILTRE = string.upper(filtre)
1365         #
1366         # On cherche d'abord dans les noms de groupe
1367         # puis dans les noms de commande groupe par groupe
1368         #
1369         for grp in self.liste_groupes:
1370             if fnmatch.fnmatch(grp,filtre) or fnmatch.fnmatch(grp,FILTRE) :
1371                 cmd=self.dict_groupes[grp][0]
1372                 label=self.dico_labels[cmd]
1373                 index = self.MCbox.index(label)
1374                 self.MCbox.see(index)
1375                 self.selectitem(cmd,label,self.selection[2])
1376                 # On a trouve un groupe on arrete la recherche
1377                 return
1378
1379         for grp in self.liste_groupes:
1380            for cmd in self.dict_groupes[grp] :
1381               if fnmatch.fnmatch(cmd,filtre) or fnmatch.fnmatch(cmd,FILTRE) :
1382                  label=self.dico_labels[cmd]
1383                  index = self.MCbox.index(label)
1384                  self.MCbox.see(index)
1385                  self.selectitem(cmd,label,self.selection[2])
1386                  # On a trouve une commande  on arrete la recherche
1387                  return
1388