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