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