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