]> SALOME platform Git repositories - tools/eficas.git/blob - Editeur/widgets.py
Salome HOME
CCAR: creation V1_13a1 a partir de la branche Liv-V1_12
[tools/eficas.git] / Editeur / 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 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 or isinstance(objet,object):
805              #instance ancienne mode ou nouvelle mode
806               try:
807                   mot = objet.nom
808               except:
809                   mot = str(objet)
810           elif type(objet) in (types.StringType,types.IntType):
811               mot = objet
812           elif type(objet) == types.FloatType :
813               mot = self.parent.get_valeur_texte(objet)
814               if mot == "" :
815                  mot = str(objet)
816           elif type(objet) == types.TupleType :
817               mot="("
818               premier=1
819               for val in objet:
820                  if (not premier):
821                    mot=mot+"," 
822                  else:
823                    premier=0
824                  valtexte = self.parent.get_valeur_texte(val)
825                  if valtexte != "" :
826                     mot=mot+valtexte
827                  else:
828                     mot=mot+str(val)
829               mot=mot+")"
830           else:
831               mot=`objet`
832           label = Label(self.MCbox,
833                         text = mot,
834                         fg = 'black',bg = 'gray95',justify = 'left')
835           self.dico_labels[mot]=label
836           self.dico_place[mot]=self.nBlabel
837           self.dico_mots[label]=mot
838           self.nBlabel=self.nBlabel+1
839           liste_labels.append(label)
840           self.MCbox.window_create(END,
841                                    window=label,
842                                    stretch = 1)
843           self.MCbox.insert(END,'\n')
844           if self.optionReturn != None :
845               label.bind("<Return>",lambda e,s=self,c=self.liste_commandes[2][1],x=objet,l=label : s.chooseitemsurligne(x,l,c))
846               label.bind("<KP_Enter>",lambda e,s=self,c=self.liste_commandes[2][1],x=objet,l=label : s.chooseitemsurligne(x,l,c))
847           label.bind("<Key-Right>",lambda e,s=self,x=objet,l=label : s.selectNextItem(x,l))
848           label.bind("<Key-Down>",lambda e, s=self,x=objet,l=label : s.selectNextItem(x,l))
849           label.bind("<Key-Left>" ,lambda e,s=self,x=objet,l=label  : s.selectPrevItem(x,l))
850           label.bind("<Key-Up>" ,lambda e,s=self,x=objet,l=label  : s.selectPrevItem(x,l))
851           if self.active == 'oui':
852               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))
853               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))
854               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))
855
856         for marque in self.liste_marques:
857            try:
858               self.markitem(liste_labels[marque])
859            except:
860               pass
861
862         self.MCbox.config(state=DISABLED)
863         self.selection = None
864         self.dontselect=0
865         for event,callback in self.liste_commandes:
866             if event == "<Enter>":
867                self.selection=None,None,callback
868                break
869
870     def clear_marque(self):
871         try:
872           self.dico_labels[self.arg_selected].configure(bg='gray95',fg='black')
873           self.arg_selected = ''
874         except :
875           pass
876
877     def surligne(self,marque):
878         try :
879            self.highlightitem(self.dico_labels[marque])
880            self.arg_selected = marque
881         except:
882            pass
883
884     def chooseitemsurligne(self,mot,label,commande):
885         """ Active la méthode de choix passée en argument"""
886         try:
887            mot=self.arg_selected
888            commande(mot)
889         except AsException,e:
890            raison=str(e)
891            showerror(raison.split('\n')[0],raison)
892
893     def chooseitem(self,mot,label,commande):
894         """ Active la méthode de choix passée en argument"""
895         try:
896            commande(mot)
897         except AsException,e:
898            raison=str(e)
899            showerror(raison.split('\n')[0],raison)
900
901     def afficheMot(self,mot):
902         """ Pour contourner le bug sur l index 
903             on commence par la methode dite normale     
904             puis par la methode de contournement     
905             puis rien du tout 
906         """
907         try:
908              labelsuivant=self.dico_labels[mot]
909              index = self.MCbox.index(labelsuivant)
910              self.MCbox.see(index)
911         except :
912              posmot=self.dico_place[mot]
913              totale=self.nBlabel + 0.0
914              self.MCbox.yview_moveto(posmot/totale)
915
916     def selectNextItem(self,mot,label):
917         index=self.liste.index(mot)
918         indexsuivant=index+1
919         if indexsuivant > len(self.liste) -1:
920            indexsuivant=0
921         motsuivant=self.liste[indexsuivant]
922         labelsuivant=self.dico_labels[motsuivant]
923         self.afficheMot(motsuivant)
924         self.selectthis(motsuivant,labelsuivant,self.selection[2],)
925         self.dontselect=1
926            
927     def selectPrevItem(self,mot,label):
928         index=self.liste.index(mot)
929         indexprec=index-1
930         motprec=self.liste[indexprec]
931         labelprec=self.dico_labels[motprec]
932         self.afficheMot(motprec)
933         self.selectthis(motprec,labelprec,self.selection[2],)
934         self.dontselect=1
935         
936     def selectthis(self,mot,label,commande) :
937         self.clear_marque()
938         if self.selection != None :
939             self.deselectitem(self.selection[1],self.selection[0],self.selection[2],)
940         self.highlightitem(label)
941         self.selection = (mot,label,commande)
942         self.arg_selected = mot
943         if commande : commande(mot)
944
945     def selectitem(self,mot,label,commande) :
946         """ Met l'item sélectionné (représenté par son label) en surbrillance
947             et lance la commande associée au double-clic"""
948         if self.dontselect:
949            self.dontselect=0
950            return
951         self.selectthis(mot,label,commande)
952
953     def highlightitem(self,label) :
954         """ Met l'item représenté par son label en surbrillance """
955         label.focus_set()
956         label.configure(bg='#00008b',fg='white')
957         
958     def markitem(self,label):
959         """ Met l'item (représenté par son label) en rouge """
960         label.configure(bg='gray95',fg='red')
961         
962     def deselectitem(self,label,mot='',commande=None) :
963         """ Remet l'item (représenté par son label) en noir"""
964         if label:label.configure(bg='gray95',fg='black')
965         self.arg_selected = ''
966         if commande and mot : commande(mot)
967
968     def cherche_selected_item(self):
969         try :
970            index=self.MCbox.index(self.selection[1])
971            lign,col=map(int,string.split(index,'.'))
972         except :
973            label=self.dico_labels[self.arg_selected]
974            mot=self.dico_mots[label] 
975            lign=self.dico_place[mot]+1
976         return lign
977
978     def remove_selected_item(self):
979         try :
980            index=self.MCbox.index(self.selection[1])
981            lign,col=map(int,string.split(index,'.'))
982         except :
983            label=self.dico_labels[self.arg_selected]
984            mot=self.dico_mots[label] 
985            lign=self.dico_place[mot]+1
986         del self.liste[lign-1]
987         self.affiche_liste()
988
989     def entry_changed(self,event=None):
990         """ Cette méthode est invoquée chaque fois que l'utilisateur modifie le contenu
991         de l'entry et frappe <Return>"""
992         if self.arg_selected != '' : self.deselectitem(self.dico_labels[self.arg_selected])
993         filtre = self.entry.get()+"*"
994         FILTRE = string.upper(filtre)
995         self.dontselect=0
996         for arg in self.liste :
997             if fnmatch.fnmatch(arg,filtre) or fnmatch.fnmatch(arg,FILTRE) :
998                 label=self.dico_labels[arg]
999                 self.afficheMot(arg)
1000                 self.selectitem(arg,label,self.selection[2])
1001                 break
1002
1003         #try :
1004           #self.dico_labels[self.arg_selected].focus_set()
1005         #except :
1006           #pass
1007
1008
1009     # PN attention à la gestion des paramétres
1010     # cela retourne H = 1 , et ni H, ni 1
1011     #            print repr(val)
1012     #            print val.__class__.__name__
1013     def get_liste(self):
1014         l=[]
1015         for val in self.liste:
1016 #            try:
1017 #                v = eval(val)
1018 #                    l.append(v)
1019 #            except:
1020                 l.append(val)
1021         return l
1022     
1023     def put_liste(self,liste):
1024         self.liste = liste
1025         self.affiche_liste()
1026
1027 class Affichage :
1028   """ Cette classe permet d'afficher au lancement d'EFICAS le message
1029       d'attente et la barre de progression"""
1030   def __init__(self,master,message,barre ='oui'):
1031       from Tools.foztools.foztools import Slider
1032       fonte=fontes.standard12_gras
1033       self.master=master
1034       self.frame = Frame(self.master)
1035       self.frame.pack(expand=1,fill='both')
1036       self.mess = Label(self.frame,text=message,justify='center',
1037                         bd=2,relief='groove',font=fonte)
1038       self.mess.pack(in_ = self.frame,side='top',expand=1,fill='both')
1039       self.progress = Slider(self.frame,value=0,max=100,orientation='horizontal',
1040                              fillColor='#00008b',width=200,height=30,
1041                              background='white',labelColor='red')
1042       if barre == 'oui':
1043           self.progress.frame.pack(in_=self.frame,side='top')
1044       self.master.update()
1045       if barre == 'oui':
1046           self.progress.frame.after(1000,self.update)
1047
1048   def configure(self,**options):
1049       if options.has_key('message'):
1050           self.mess.configure(text=options['message'])
1051       if options.has_key('barre'):
1052           if options['barre'] == 'oui' :
1053               self.progress.frame.pack(in_=self.frame,side='top')
1054           elif options['barre'] == 'non' :
1055               self.progress.frame.pack_forget()
1056       self.master.update_idletasks()
1057       
1058   def quit(self):
1059       self.frame.destroy()
1060       self.master.update()
1061
1062   def update(self,event=None):
1063       """ Permet de faire avancer la barre de progression """
1064       try :
1065           bar=self.progress
1066           bar.value = bar.value+self.increment
1067           bar.update()
1068           self.master.after(100,self.update)
1069       except:
1070           pass
1071
1072   def configure_barre(self,nb):
1073       """ Calcule l'incrément de progression de la barre en fonction
1074           du nombre d'opérations à effectuer afin que le compteur
1075           soit à 100% à la fin des opérations"""
1076       self.increment = 100./nb
1077       self.progress.update()
1078
1079 class Ask_Format_Fichier :
1080     """
1081     Cette classe permet de créer une fenêtre Toplevel dans laquelle
1082     on propose le choix du format de fichier de commandes à ouvrir
1083     """
1084     def __init__(self,appli):
1085         self.fenetre = Toplevel()
1086         self.fenetre.configure(width = 250,height=150)
1087         self.fenetre.protocol("WM_DELETE_WINDOW", self.quit)
1088         self.fenetre.title("Choix du format du fichier de commandes")
1089         # définition des frames
1090         self.frame_texte = Frame(self.fenetre)
1091         self.frame_radioboutons = Frame(self.fenetre)
1092         self.frame_bouton_ok = Frame(self.fenetre)
1093         self.frame_texte.place(relx=0,rely=0,relwidth=1,relheight=0.3)
1094         self.frame_radioboutons.place(relheight=0.5,relx=0,rely=0.3,relwidth=1.)
1095         self.frame_bouton_ok.place(relheight=0.2,relx=0,rely=0.8,relwidth=1.)
1096         # définition de la zone texte et du scrollbar
1097         zone_texte = Label(self.frame_texte,text = "Format du fichier à ouvrir :")
1098         zone_texte.pack(side='top',fill='both',expand=1,padx=5,pady=10)
1099         # définition des radioboutons
1100         Radiobutton(self.frame_radioboutons,text='Format Aster (Code_Aster --> v5)',
1101                     variable=appli.format_fichier,value='Aster').pack(anchor='n')
1102         Radiobutton(self.frame_radioboutons,text='Format Python (Code_Aster v6-->)',
1103                     variable=appli.format_fichier,value='Python').pack(anchor='n')
1104         # création du bouton OK
1105         Button(self.frame_bouton_ok,text='OK',command=self.quit).pack(anchor='n')
1106         # centrage de la fenêtre
1107         centerwindow(self.fenetre)
1108
1109     def quit(self):
1110         self.fenetre.destroy()
1111
1112 class BARRE_K2000(Toplevel):
1113     def __init__(self,master=None,text = ""):
1114         Toplevel.__init__(self,master,relief='groove')
1115         self.master.iconify()
1116         self.geometry("250x100+0+0")
1117         self.protocol("WM_DELETE_WINDOW",self.quit)
1118         # frame principale dans self (= Toplevel)
1119         self.frame = Frame(self)
1120         self.frame.place(relwidth=1,relheight=1)
1121         # frame contenant le texte à afficher 
1122         self.frame_text = Frame(self.frame)
1123         self.frame_text.place(relwidth=1,relheight=0.75,rely=0)
1124         # frame contenant le canvas de la barre
1125         self.frame_canv = Frame(self.frame)
1126         self.frame_canv.place(relwidth=1,relheight=0.25,rely=0.75)
1127         # canvas dans lequel sera affichée la barre K2000
1128         self.canvas = Canvas(self.frame_canv)
1129         self.canvas.place(relx=0.5,rely=0.5,relheight=0.8,relwidth=0.8,anchor='center')
1130         # on affiche le texte et la barre
1131         self.build_text(text)
1132         self.build_batons()
1133         #self.overrideredirect(1)
1134         # on active la barre ...
1135         self.master.after(1000,self.launch)
1136         # on centre la fenêtre
1137         centerwindow(self)
1138         self.focus()
1139
1140     def build_text(self,text):
1141         """
1142         Affichage de text dans frame_text
1143         """
1144         self.texte_var = StringVar()
1145         self.texte_var.set(text)
1146         Label(self.frame_text,textvariable=self.texte_var).place(relx=0.5,rely=0.5,anchor='center')
1147         
1148     def build_batons(self):
1149         """
1150         Construit la suite de bâtons dans le canvas
1151         """
1152         self.l_batons=[]
1153         self.black = -1
1154         self.sens = 'D'
1155         self.quit = 0
1156         for i in range(0,40):
1157             id = self.canvas.create_rectangle(i*5,0,(i+1)*5,20,fill='gray90',outline='')
1158             self.l_batons.append(id)
1159
1160     def launch(self):
1161         """
1162         Active la barre K2000 en affichant les bâtons avec des couleurs en dégradé
1163         """
1164         if self.quit == 1 :
1165             self.destroy()
1166             self.master.deiconify()
1167             return
1168         if self.sens == 'D':
1169             self.black = self.black+1
1170             l_bat = self.l_batons[0:self.black+1]
1171             l_bat.reverse()
1172         elif self.sens == 'G':
1173             self.black = self.black-1
1174             l_bat = self.l_batons[self.black:]
1175         i=0
1176         for bat in l_bat :
1177             num_color = 5+i*10
1178             if num_color < 10 : color = 'black'
1179             elif num_color > 90 : color = 'white'
1180             else: color = 'gray'+`num_color`
1181             self.canvas.itemconfigure(bat,fill=color)
1182             i=i+1
1183         if self.black == len(self.l_batons) :
1184             self.sens = 'G'
1185         if self.black == 0 and self.sens == 'G':self.sens = 'D'
1186         self.after(80,self.launch)
1187
1188     def update_text(self,new_text):
1189         """
1190         Remplace le texte affiché par new_text
1191         """
1192         self.texte_var.set(new_text)
1193         
1194     def quit(self):
1195         self.quit = 1        
1196
1197 class ListeChoixParGroupes(ListeChoix) :
1198     """ 
1199         Cette classe est utilisée pour afficher une liste de commandes classées par
1200         groupes. L'utilisateur peut réaliser des actions de selection
1201         qui déclenchent des actions spécifiées par les bindings contenus dans liste_commandes
1202         Exemple de binding:
1203            liste_commandes = (("<Enter>",self.selectCmd),
1204                               ("<Leave>",self.deselectCmd),
1205                               ("<Double-Button-1>",self.defCmd))
1206         Il s'agit d'une liste de doublets dont le premier element est un evenement et le 
1207         deuxieme un callback a appeler sur l'evenement en question.
1208
1209     """
1210     def __init__(self,parent,page,liste_groupes,dict_groupes,liste_commandes=[],liste_marques =[],
1211                       active ='oui',filtre='non',titre='',optionReturn=None,fonte_titre=fontes.standard_gras_souligne):
1212         self.parent = parent
1213         self.page = page
1214         self.liste_groupes = liste_groupes
1215         self.dict_groupes = dict_groupes
1216         self.dico_labels={}
1217         self.selection = None
1218         self.liste_commandes = liste_commandes
1219         self.liste_marques = liste_marques
1220         self.arg_selected=''
1221         self.active = active
1222         self.titre = titre
1223         self.filtre = filtre
1224         self.optionReturn = optionReturn
1225         self.fonte_titre=fonte_titre
1226         self.init()
1227
1228     def affiche_liste(self):
1229         """ Affiche la liste dans la fenêtre"""
1230         liste_labels=[]
1231         self.dico_mots={}
1232         self.MCbox.config(state=NORMAL)
1233         self.MCbox.delete(1.0,END)
1234         for grp in self.liste_groupes:
1235            # On itère sur les groupes
1236            if grp == "CACHE":continue
1237            liste_commandes=self.dict_groupes[grp]
1238            text="GROUPE<<<<<<<< "+grp+" "
1239            text=text+">"*max(0,30-len(text))
1240            label = Label(self.MCbox,
1241                         text = text,
1242                         fg = 'black',bg = 'gray95',justify = 'left')
1243            # On stocke la relation entre le nom de la commande et le label
1244            self.dico_labels[grp]=label
1245            liste_labels.append(label)
1246            self.MCbox.window_create(END,
1247                                    window=label,
1248                                    stretch = 1)
1249            self.MCbox.insert(END,'\n')
1250            for cmd in liste_commandes:
1251               label = Label(self.MCbox,
1252                         text = cmd,
1253                         fg = 'black',bg = 'gray95',justify = 'left')
1254               # On stocke la relation entre le nom de la commande et le label
1255               self.dico_labels[cmd]=label
1256               self.dico_mots[label]=cmd
1257               self.MCbox.window_create(END,
1258                                    window=label,
1259                                    stretch = 1)
1260               self.MCbox.insert(END,'\n')
1261
1262               def null(*tp,**args): return
1263
1264               if self.active == 'oui':
1265                   # Traitement par defaut des evenements
1266                   label.bind("<Enter>",lambda e,s=self,c=null,x=cmd,l=label: s.selectitem(x,l,c))
1267                   label.bind("<Leave>",lambda e,s=self,c=null,x=cmd,l=label: s.deselectitem(l,x,c))
1268                   label.bind("<Double-Button-1>",lambda e,s=self,c=null,x=cmd,l=label: s.chooseitem(x,l,c))
1269                   label.bind("<Return>",lambda e,s=self,c=null,x=cmd,l=label: s.chooseitem(x,l,c))
1270                   label.bind("<KP_Enter>",lambda e,s=self,c=null,x=cmd,l=label: s.chooseitem(x,l,c))
1271                   label.bind("<Key-Right>",lambda e,s=self,c=null,x=cmd,l=label,gr=grp: s.selectNextItem(x,l,c,gr,x))
1272                   label.bind("<Key-Down>",lambda e,s=self,c=null,x=cmd,l=label,gr=grp: s.selectNextItem(x,l,c,gr,x))
1273                   label.bind("<Key-Left>",lambda e,s=self,c=null,x=cmd,l=label,gr=grp: s.selectPrevItem(x,l,c,gr,x))
1274                   label.bind("<Key-Up>",lambda e,s=self,c=null,x=cmd,l=label,gr=grp: s.selectPrevItem(x,l,c,gr,x))
1275
1276                   # Si des callbacks sont definis on les utilise
1277                   for event,callback in self.liste_commandes:
1278                       if event == "<Enter>":
1279                          label.bind("<Enter>",lambda e,s=self,c=callback,x=cmd,l=label: s.selectitem(x,l,c))
1280                       elif event == "<Leave>":
1281                          label.bind("<Leave>",lambda e,s=self,c=callback,x=cmd,l=label: s.deselectitem(l,x,c))
1282                       elif event == "<Double-Button-1>":
1283                          label.bind("<Double-Button-1>",lambda e,s=self,c=callback,x=cmd,l=label: s.chooseitem(x,l,c))
1284                       elif event == "<Return>":
1285                          label.bind("<Return>",lambda e,s=self,c=callback,x=cmd,l=label: s.chooseitem(x,l,c))
1286                       elif event == "<KP_Enter>":
1287                          label.bind("<KP_Enter>",lambda e,s=self,c=callback,x=cmd,l=label: s.chooseitem(x,l,c))
1288                       elif event == "<Key-Right>":
1289                          label.bind("<Key-Right>",lambda e,s=self,c=callback,x=cmd,l=label,gr=grp:s.selectNextItem(x,l,c,gr,x))
1290                       elif event == "<Key-Down>":
1291                          label.bind("<Key-Down>",lambda e,s=self,c=callback,x=cmd,l=label,gr=grp:s.selectNextItem(x,l,c,gr,x))
1292                       elif event == "<Key-Left>":
1293                          label.bind("<Key-Left>",lambda e,s=self,c=callback,x=cmd,l=label,gr=grp:s.selectPrevItem(x,l,c,gr,x))
1294                       elif event == "<Key-Up>":
1295                          label.bind("<Key-Up>",lambda e,s=self,c=callback,x=cmd,l=label,gr=grp:s.selectPrevItem(x,l,c,gr,x))
1296                       else:
1297                          label.bind(event,lambda e,s=self,c=callback,x=cmd,l=label: c())
1298
1299         for marque in self.liste_marques:
1300            try:
1301               self.markitem(liste_labels[marque])
1302            except:
1303               pass
1304
1305         self.MCbox.config(state=DISABLED)
1306         self.selection = None
1307         self.dontselect=0
1308         for event,callback in self.liste_commandes:
1309             if event == "<Enter>":
1310                self.selection=None,None,callback
1311                break
1312
1313     def selectPrevItem(self,mot,label,callback,group,cmd):
1314         g=self.liste_groupes.index(group)
1315         liste_commandes=self.dict_groupes[group]
1316         c=liste_commandes.index(cmd)
1317         if c > 0:
1318            co=liste_commandes[c-1]
1319         else:
1320            # debut de liste. On passe au groupe precedent
1321            if g > 0:
1322               gr=self.liste_groupes[g-1]
1323               co=self.dict_groupes[gr][-1]
1324            else:
1325               # debut des groupes. On ne fait rien
1326               return
1327         # On a trouve l'item precedent
1328         labelsuivant=self.dico_labels[co]
1329         index = self.MCbox.index(labelsuivant)
1330         self.MCbox.see(index)
1331         self.selectthis(co,labelsuivant,self.selection[2],)
1332         self.dontselect=1
1333
1334     def selectNextItem(self,mot,label,callback,group,cmd):
1335         g=self.liste_groupes.index(group)
1336         liste_commandes=self.dict_groupes[group]
1337         c=liste_commandes.index(cmd)
1338         try:
1339            co=liste_commandes[c+1]
1340         except:
1341            # fin de liste. On passe au groupe suivant
1342            try:
1343               gr=self.liste_groupes[g+1]
1344               co=self.dict_groupes[gr][0]
1345            except:
1346               # fin des groupes. On ne fait rien
1347               return
1348         # On a trouve l'item suivant
1349         labelsuivant=self.dico_labels[co]
1350         index = self.MCbox.index(labelsuivant)
1351         self.MCbox.see(index)
1352         self.selectthis(co,labelsuivant,self.selection[2],)
1353         self.dontselect=1
1354
1355     def entry_changed(self,event=None):
1356         """ 
1357             Cette méthode est invoquée chaque fois que l'utilisateur modifie le contenu
1358             de l'entry et frappe <Return>
1359         """
1360         if self.arg_selected != '' : self.deselectitem(self.dico_labels[self.arg_selected])
1361
1362         filtre = self.entry.get()+"*"
1363         FILTRE = string.upper(filtre)
1364         #
1365         # On cherche d'abord dans les noms de groupe
1366         # puis dans les noms de commande groupe par groupe
1367         #
1368         for grp in self.liste_groupes:
1369             if fnmatch.fnmatch(grp,filtre) or fnmatch.fnmatch(grp,FILTRE) :
1370                 cmd=self.dict_groupes[grp][0]
1371                 label=self.dico_labels[cmd]
1372                 index = self.MCbox.index(label)
1373                 self.MCbox.see(index)
1374                 self.selectitem(cmd,label,self.selection[2])
1375                 # On a trouve un groupe on arrete la recherche
1376                 return
1377
1378         for grp in self.liste_groupes:
1379            for cmd in self.dict_groupes[grp] :
1380               if fnmatch.fnmatch(cmd,filtre) or fnmatch.fnmatch(cmd,FILTRE) :
1381                  label=self.dico_labels[cmd]
1382                  index = self.MCbox.index(label)
1383                  self.MCbox.see(index)
1384                  self.selectitem(cmd,label,self.selection[2])
1385                  # On a trouve une commande  on arrete la recherche
1386                  return
1387