Salome HOME
CCAR: diverses corrections lies aux validateurs
[tools/eficas.git] / Editeur / widgets.py
1 #            CONFIGURATION MANAGEMENT OF EDF VERSION
2 # ======================================================================
3 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
4 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
5 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
6 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
7 # (AT YOUR OPTION) ANY LATER VERSION.
8 #
9 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
10 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
11 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
12 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
13 #
14 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
15 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
16 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
17 #
18 #
19 # ======================================================================
20 # ----------------------------------------------------------
21 #   Cette classe sert à définir les widgets utilisés par
22 #          EFICAS
23 # ----------------------------------------------------------
24
25 from Tkinter import *
26 import Pmw
27 import os,sys,re,string
28 import types,fnmatch
29 from tkFileDialog import *
30 from tkMessageBox import showinfo,askyesno,showerror,askretrycancel
31
32 import fontes
33 import prefs
34 from utils import save_in_file
35 from centerwindow import centerwindow
36
37 from Noyau.N_utils import repr_float
38 from Accas import AsException
39     
40 class Fenetre :
41     """ Cette classe permet de créer une fenêtre Toplevel dans laquelle
42         on peut afficher un texte et qui permet de le sauver"""
43     def __init__(self,appli,titre="",texte=""):
44         self.appli=appli
45         self.fenetre = Toplevel()
46         self.fenetre.configure(width = 800,height=500)
47         self.fenetre.protocol("WM_DELETE_WINDOW", self.quit)
48         self.fenetre.title("Visualisation du "+titre)
49         self.texte = string.replace(texte,'\r\n','\n')
50         self.titre = titre
51         fonte=fontes.standardcourier10
52         # définition des frames
53         self.frame_texte = Frame(self.fenetre)
54         self.frame_boutons = Frame(self.fenetre)
55         self.frame_texte.place(relx=0,rely=0,relwidth=1,relheight=0.9)
56         self.frame_boutons.place(relheight=0.1,relx=0,rely=0.9,relwidth=1.)
57         # définition de la zone texte et du scrollbar
58         self.zone_texte = Text(self.frame_texte,font=fonte)
59         self.zone_texte.bind("<Key-Prior>", self.page_up)
60         self.zone_texte.bind("<Key-Next>", self.page_down)
61         self.zone_texte.bind("<Key-Up>", self.unit_up)
62         self.zone_texte.bind("<Key-Down>", self.unit_down)
63         self.scroll_v = Scrollbar (self.frame_texte,command = self.zone_texte.yview)
64         #self.scroll_h = Scrollbar (self.frame_texte,command = self.zone_texte.xview)
65         self.scroll_v.pack(side='right',fill ='y')
66         #self.scroll_h.pack(side='bottom',fill ='x')
67         self.zone_texte.pack(side='top',fill='both',expand=1,padx=5,pady=10)
68         self.zone_texte.configure(yscrollcommand=self.scroll_v.set)
69         # définition des boutons
70         self.but_quit = Button(self.frame_boutons,text = "Fermer",command=self.quit)
71         self.but_save = Button(self.frame_boutons,text = "sauver",command = self.save)
72         self.but_quit.place(relx=0.4,rely=0.5,anchor='center')
73         self.but_save.place(relx=0.6,rely=0.5,anchor='center')
74         # affichage du texte
75         self.affiche_texte(self.texte)
76         centerwindow(self.fenetre)
77
78     def page_up(self,event):
79         event.widget.yview_scroll(-1, "page")
80     def page_down(self,event):
81         event.widget.yview_scroll(1, "page")
82     def unit_up(self,event):
83         event.widget.yview_scroll(-1, "unit")
84     def unit_down(self,event):
85         event.widget.yview_scroll(1, "unit")
86
87     def wait(self):
88         self.fenetre.grab_set()
89         self.zone_texte.focus_set()
90         self.fenetre.wait_window(self.fenetre)
91
92     def quit(self):
93         self.fenetre.destroy()
94
95     def efface_scroll(self):
96         """ Efface le scroll lorsqu'il n'est pas nécessaire : ne marche pas"""
97         self.scroll_v.pack_forget()
98         #self.scroll_h.pack_forget()
99
100     def affiche_texte(self,texte):
101         """ Affiche le texte dans la fenêtre """
102         if texte != "" :
103             self.zone_texte.insert(END,texte)
104             try:
105                 self.fenetre.update_idletasks()
106                 x0,y0,x1,y1 = self.zone_texte.bbox(END)
107                 if (y1-y0) < 300 : self.efface_scroll()
108             except:
109                 pass
110
111     def save(self):
112         """ Permet de sauvegarder le texte dans un fichier dont on a demandé le nom
113         à l'utilisateur """
114         file = asksaveasfilename(defaultextension = '.comm',
115                                #initialdir = self.appli.CONFIGURATION.rep_user,
116                                initialdir = self.appli.CONFIGURATION.initialdir,
117                                title="Sauvegarde du "+self.titre)
118         if file != '':
119             if not save_in_file(file,self.texte) :
120                 showerror("Sauvegarde impossible",
121                        "Impossible de sauvegarder le texte dans le fichier spécifié\n"+
122                           "Vérifiez les droits d'écriture")
123             else:
124                 showinfo("Sauvegarde effectuée","Sauvegarde effectuée dans le fichier %s" %file)
125
126 class FenetreYesNo(Fenetre):
127     def __init__(self,appli,titre="",texte="",yes="Yes",no="No"):
128         self.appli=appli
129         self.fenetre = Toplevel()
130         self.fenetre.configure(width = 800,height=500)
131         self.fenetre.protocol("WM_DELETE_WINDOW", self.quit)
132         self.fenetre.title(titre)
133         self.texte = string.replace(texte,'\r\n','\n')
134         self.titre = titre
135         fonte=fontes.standardcourier10
136         # définition des frames
137         self.frame_texte = Frame(self.fenetre)
138         self.frame_boutons = Frame(self.fenetre)
139         self.frame_boutons.place(relx=0,rely=0,    relwidth=1.,relheight=0.1)
140         self.frame_texte.place(  relx=0,rely=0.1,  relwidth=1, relheight=0.9)
141         # définition de la zone texte et du scrollbar
142         self.zone_texte = Text(self.frame_texte,font=fonte)
143         self.zone_texte.bind("<Key-Prior>", self.page_up)
144         self.zone_texte.bind("<Key-Next>", self.page_down)
145         self.zone_texte.bind("<Key-Up>", self.unit_up)
146         self.zone_texte.bind("<Key-Down>", self.unit_down)
147         self.scroll_v = Scrollbar (self.frame_texte,command = self.zone_texte.yview)
148         #self.scroll_h = Scrollbar (self.frame_texte,command = self.zone_texte.xview)
149         self.scroll_v.pack(side='right',fill ='y')
150         #self.scroll_h.pack(side='bottom',fill ='x')
151         self.zone_texte.pack(side='top',fill='both',expand=1,padx=5,pady=10)
152         self.zone_texte.configure(yscrollcommand=self.scroll_v.set)
153         # définition des boutons
154         self.but_yes = Button(self.frame_boutons,text = yes,command=self.yes)
155         self.but_no = Button(self.frame_boutons,text = no,command = self.no)
156         self.but_yes.place(relx=0.4,rely=0.5,anchor='center')
157         self.but_no.place(relx=0.6,rely=0.5,anchor='center')
158         # affichage du texte
159         self.affiche_texte(self.texte)
160         centerwindow(self.fenetre)
161
162     def yes(self):
163         self.result=1
164         self.quit()
165
166     def no(self):
167         self.result=0
168         self.quit()
169
170 class FenetreDeSelection(Fenetre):
171     """ Classe dérivée de Fenêtre permettant la récupération d'une zone de texte sélectionnée.
172         Cette classe est utilisée pour affecter une liste de valeurs à un mot-clé.
173     """
174     def __init__(self,panel,item,appli,titre="",texte=""):
175         Fenetre.__init__(self,appli,titre=titre,texte=texte)
176         self.fenetre.configure(width = 320,height=400)
177         centerwindow(self.fenetre)
178         self.panel = panel
179         self.item = item
180         self.fenetre.title(titre)
181         self.but_save.configure(text="Ajouter",command=self.traite_selection)
182         # séparateur par défaut
183         self.separateur = ";"
184         # création de la zone de saisie du séparateur
185         l_separateurs_autorises = self.get_separateurs_autorises()
186         self.choix_sep = Pmw.ComboBox(self.frame_boutons,
187                                       label_text = "Séparateur :",
188                                       labelpos = 'w',
189                                       listheight = 100,
190                                       selectioncommand = self.choose_separateur,
191                                       scrolledlist_items = l_separateurs_autorises)
192         self.choix_sep.component('entry').configure(width=6)
193         self.choix_sep.place(relx=0.01,rely=0.5,anchor='w')
194         self.choix_sep.selectitem(self.separateur)
195         # Replacement
196         self.but_quit.place_forget()
197         self.but_save.place_forget()
198         self.but_save.place(relx=0.6,rely=0.5,anchor='center')
199         self.but_quit.place(relx=0.8,rely=0.5,anchor='center')
200
201     def get_separateurs_autorises(self):
202         """
203         Retourne la liste des séparateurs autorisés
204         """
205         return ['espace',';',',']
206
207     def choose_separateur(self,nom_sep):
208         """
209         Affecte à self.separateur le caractère séparateur correspondant à nom_sep
210         """
211         if nom_sep == 'espace' :
212             self.separateur = ' '
213         else:
214             self.separateur = nom_sep
215         
216     def traite_selection(self):
217         """ Cette méthode effectue tous les traitements nécessaires pour vérifier
218             et affecter la liste de valeurs à l'objet réprésenté par self.item
219         """
220         # Récupère la liste des chaines de caractères de la zone sélectionnée
221         message,liste = self.recupere_liste()
222         if self.test_probleme(message,"Sélectionnez des données") == 0:
223             return
224         # Vérifie que le nombre de données est dans les limites attendues
225         message = self.verif_liste(liste)
226         if self.test_probleme(message,"Vérifiez le nombre de données") == 0:
227             return
228         # Crée une liste de valeurs du type attendu
229         message,liste_valeurs = self.creation_liste_valeurs(liste)
230         if self.test_probleme(message,"Vérifiez le type des données") == 0:
231             return
232         # Vérifie que chaque valeur est dans le domaine exigé
233         message = self.verif_valeurs(liste_valeurs)
234         if self.test_probleme(message,"Vérifiez le domaine des valeurs") == 0:
235             return
236         # Ajoute les valeurs dans la liste de valeurs du mot-clé
237         self.ajouter_valeurs(liste_valeurs)
238         self.appli.affiche_infos("Liste de valeurs acceptée")
239
240     def test_probleme(self, message, message_eficas):
241         """ Cette méthode affiche un message d'erreur si message != ''
242             et retourne 0, sinon retourne 1 sans rien afficher.
243         """
244         if message != "":
245             showinfo("Problème",message)
246             self.fenetre.tkraise()
247             self.appli.affiche_infos(message_eficas)
248             return 0
249         else:
250             return 1
251
252     def recupere_liste(self):
253         """ Cette méthode récupère le texte de la zone sélectionnée, construit et
254             retourne une liste avec les chaines qui se trouvent entre les séparateurs.
255             S'il n'y a pas de données selectionnées, elle retourne un message d'erreur
256             et une liste vide.
257         """
258         message = ""
259         try:
260             selection=self.fenetre.selection_get()
261         except:
262             message = "Pas de donnée sélectionnée"
263             return message,None
264         # les retours chariots doivent être interprétés comme des séparateurs
265         selection = string.replace(selection,'\n',self.separateur)
266         # on splitte la sélection suivant le caractère séparateur
267         liste_chaines = string.split(selection,self.separateur)
268         l_chaines = []
269         for chaine in liste_chaines:
270             chaine = string.strip(chaine)
271             if chaine != '' : l_chaines.append(chaine)
272         return message,l_chaines
273
274     def verif_liste(self, liste):
275         """ Cette méthode effectue des tests sur le nombre d'éléments de la liste
276             et retourne 1 si la liste est correcte, sinon 0 et le message d'erreur
277             correspondant.
278         """
279         message = ""
280         # nombre d'éléments sélectionnés
281         nombre_elements = len(liste)
282         # nombre d'éléments déja dans la liste du panel
283         nombre_in_liste = len(self.panel.Liste_valeurs.get_liste())
284         multiplicite = self.item.GetMultiplicite()
285         if (nombre_elements % multiplicite) != 0:
286             message = "Vous devez sélectionner "+str(multiplicite)+" * n données"
287             return message
288         nombre_valeurs = nombre_elements / multiplicite
289         cardinalite = self.item.GetMinMax()
290         if nombre_valeurs < cardinalite[0]:
291             message = "Vous devez sélectionner au moins "+str(cardinalite[0])+" valeurs"
292             return message
293         if cardinalite[1] != "**" and nombre_valeurs > (long(cardinalite[1])-nombre_in_liste):
294             message = "La liste ne peut avoir plus de "+str(cardinalite[1])+" valeurs"
295             return message
296
297         return message
298
299     def creation_liste_valeurs(self, liste):
300         """ Cette méthode crée et retourne une liste de valeurs du type attendu
301             par le mot-clé. La liste de valeurs est créée à partir de la liste
302             de chaines de caractères transmise.
303         """
304         type_attendu = self.item.GetType()[0]
305         if type_attendu == 'R':
306             return self.convertir(liste, f_conversion= float)
307         elif type_attendu == 'I':
308             return self.convertir(liste, f_conversion= int)
309         elif type_attendu == 'TXM':
310             return self.convertir(liste)
311         else:
312             message = "Seuls les entiers, les réels et les chaines de caractères sont convertis"
313             return message,None
314
315     def convertir(self, liste, f_conversion=None):
316         """ Cette méthode essaie de convertir les éléments de la liste avec la
317             fonction f_conversion si elle existe, et retourne la liste des
318             éléments dans le type voulu en cas de succès, sinon retourne None.
319         """
320         liste_valeurs = []
321         message = ""
322         for chaine in liste:
323             if f_conversion:
324                 try:
325                     liste_valeurs.append(f_conversion(chaine))
326                 except:
327                     message = "Impossible de convertir "+chaine+" dans le type attendu"
328                     return message,None
329             else:
330                 liste_valeurs.append(chaine)
331         return message,liste_valeurs
332
333     def verif_valeurs(self, liste_valeurs):
334         """ Cette méthode teste tous les éléments de la liste, et retourne 1 si chaque
335             élément est dans le domaine voulu.
336         """
337         message = ""
338         for valeur in liste_valeurs:
339             test = self.item.IsInIntervalle(valeur)
340             if test == 0:
341                 intervalle = str(self.item.GetIntervalle()[0])+","+str(self.item.GetIntervalle()[1])
342                 message = "La valeur "+str(valeur)+" n'est pas dans l'intervalle ["+intervalle+"]"
343                 return message
344         return message
345
346     def ajouter_valeurs(self, liste_valeurs):
347         """ Cette méthode ajoute les nouvelles valeurs à la liste existante."""
348         liste = self.panel.Liste_valeurs.get_liste()
349         liste.extend(liste_valeurs)
350         self.panel.Liste_valeurs.put_liste(liste)
351
352 class Formulaire:
353     """
354     Cette classe permet de créer une boîte Dialog dans laquelle
355     on affiche un formulaire à remplir par l'utilisateur
356     """
357     def __init__(self,fen_pere,obj_pere=None,titre="",texte="",items=(),mode='query',commande=None):
358         if items in ((),[]) : return
359         self.items = items
360         self.titre = titre
361         self.texte = texte
362         self.fen_pere = fen_pere
363         self.obj_pere = obj_pere
364         self.mode= mode
365         self.command = commande
366         self.display()
367
368     def display(self):
369         self.init_validateurs()
370         self.init_fenetre()
371         self.init_texte()
372         self.init_items_formulaire()
373         self.fenetre.activate(geometry='centerscreenalways')
374
375     def init_validateurs(self):
376         """
377         Crée le dictionnaire des validateurs des objets reconnus par le formulaire
378         """
379         self.d_validateurs = {}
380         self.d_validateurs['rep']  = self.repvalidator
381         self.d_validateurs['file'] = self.filevalidator
382         self.d_validateurs['cata']= self.catavalidator
383         
384     def init_fenetre(self):
385         """
386         Crée la fenêtre Dialog
387         """
388         if self.mode == 'query':
389             buttons=('Valider','Annuler')
390             defaultbutton = 'Valider'
391         elif self.mode == 'display':
392             if self.command :
393                 buttons=(self.command[0],'OK')
394                 defaultbutton = 'OK'
395             else:
396                 buttons=('OK')
397                 defaultbutton = 'OK'
398         self.fenetre = Pmw.Dialog(self.fen_pere,
399                                   buttons=buttons,
400                                   defaultbutton = defaultbutton,
401                                   title = self.titre,
402                                   command = self.execute)
403         self.fenetre.withdraw()
404         
405     def init_texte(self):
406         """
407         Crée le label qui affiche le texte à l'intérieur du panneau
408         """
409         fonte=fontes.standard
410         fr_texte = Frame(self.fenetre.interior(),height=60)
411         fr_texte.pack(side='top',fill='x',expand=1)
412         Label(fr_texte,text = self.texte, font=fonte).place(relx=0.5,rely=0.5,anchor='center')
413
414     def init_items_formulaire(self):
415         """
416         Crée et affiche les items dans la boîte de dialogue
417         """
418         self.radiobut = 0
419         self.widgets = []
420         self.item_widgets = {}
421         length_maxi = 0
422         for item in self.items:
423             if len(item[0])>length_maxi : length_maxi = len(item[0])
424         window = self.fenetre.interior()
425         for item in self.items :
426             label,nature,nom_var,defaut = item
427             # création de la frame
428             fr_item = Frame(window,height=40,width=700)
429             fr_item.pack(side='top',fill='x',expand=1)
430             # création du label
431             Label(fr_item,text = label).place(relx=0.05,rely=0.4)
432             if nature in ('rep','file','cata'):
433                 # création de l'entry
434                 e_item = Entry(fr_item) 
435                 e_item.place(relx=0.5,rely=0.4,relwidth=0.45)
436                 self.widgets.append(e_item)
437                 self.item_widgets[item] = e_item
438                 if defaut : e_item.insert(0,str(defaut))
439             elif nature == 'YesNo':
440                 # création de la StringVar
441                 var = StringVar()
442                 setattr(self,'item_'+nom_var,var)
443                 var.set(defaut)
444                 # création du radiobouton
445                 rb1 = Radiobutton(fr_item,text='OUI',variable=var,value='OUI')
446                 rb2 = Radiobutton(fr_item,text='NON',variable=var,value='NON')
447                 rb1.place(relx=0.65,rely=0.5,anchor='center')
448                 rb2.place(relx=0.80,rely=0.5,anchor='center')
449                 self.widgets.append((rb1,rb2))
450                 self.item_widgets[item] = var
451         # détermination de la méthode à appliquer sur les boutons
452         if self.mode == 'query':
453             function = self.active
454         elif self.mode == 'display':
455             function = self.inactive
456         else:
457             return
458         # on applique la méthode sur les boutons (activation ou désactivation)  
459         for widget in self.widgets :
460             if type(widget) == types.TupleType:
461                 for widg in widget :
462                     apply(function,(widg,),{})
463             else:
464                 apply(function,(widget,),{})
465
466     def active(self,widget):
467         """
468         Active le widget passé en argument
469         """
470         widget.configure(state='normal',bg='white')
471
472     def inactive(self,widget):
473         """
474         Inactive le widget passé en argument
475         """
476         if not isinstance(widget,Radiobutton) :
477             widget.configure(state='disabled',bg='gray95')
478         else :
479             widget.configure(state='disabled')
480
481 # --------------------------------------------------------------------------------
482 #       Validateurs des noms de répertoire, de fichiers et de catalogues
483 # -------------------------------------------------------------------------------
484
485     def repvalidator(self,text):
486         """
487         Teste si text peut faire référence à un répertoire ou non
488         Retourne 1 si valide, 0 sinon
489         """
490         return os.path.isdir(text),'Répertoire introuvable : %s' %text
491
492     def filevalidator(self,text):
493         """
494         Teste si text peut faire référence à un fichier ou non
495         Retourne 1 si valide, 0 sinon
496         """
497         return os.path.isfile(text),'Fichier introuvable : %s' %text
498
499     def catavalidator(self,text):
500         """
501         Teste si  text est un chemin d'accès valide à un catalogue
502         Retourne 1 si valide, 0 sinon
503         """
504         return os.path.isfile(text),"Catalogue introuvable : %s" %text
505
506 # --------------------------------------------------------------------------------
507 #       Méthodes callbacks des boutons et de fin
508 # --------------------------------------------------------------------------------
509         
510     def execute(self,txt):
511         """
512         Cette commande est activée à chaque clic sur un bouton.
513         Redirige l'action sur la bonne méthode en fonction du bouton activé
514         """
515         if txt == 'Valider':
516             self.fini()
517         elif txt in ('OK','Annuler'):
518             self.quit()
519         elif txt == 'Modifier':
520             self.resultat = apply(self.command[1],(),{})
521             self.fenetre.destroy()
522         else :
523             print "Nom de bouton inconnu"
524             self.quit()
525
526     def fini(self):
527         """
528         Commande qui termine le panneau et sauvegarde les nouvelles options
529         dans l'objet resultat (dictionnaire)
530         """
531         dico={}
532         for item,widget in self.item_widgets.items():
533             nom_var = item[2]
534             type_var = item[1]
535             valeur = widget.get()
536             if self.d_validateurs.has_key(type_var):
537                 test = self.d_validateurs[type_var](valeur)
538                 if not test :
539                     # une entrée n'est pas valide --> on la met en surbrillance et on quitte la méthode
540                     # sans tuer la fenêtre bien sûr
541                     widget.selection_range(0,END)
542                     return
543             dico[nom_var] = valeur
544         self.fenetre.destroy()    
545         self.resultat=dico
546         
547     def quit(self):
548         self.fenetre.destroy()
549         self.resultat=None
550         
551 class ListeChoix :
552     """ Cette classe est utilisée pour afficher une liste de choix passée en paramètre
553         en passant les commandes à lancer suivant différents bindings """
554     def __init__(self,parent,page,liste,liste_commandes=[],liste_marques =[],active ='oui',filtre='non',titre=''):
555         self.parent = parent
556         self.page = page
557         self.liste = liste
558         self.dico_labels={}
559         self.selection = None
560         self.liste_commandes = liste_commandes
561         self.liste_marques = liste_marques
562         self.arg_selected=''
563         self.active = active
564         self.titre = titre
565         self.filtre = filtre
566         self.init()
567
568     def init(self):        
569         self.make_label_titre()
570         self.make_entry_filtre()
571         self.make_text_box()
572         try:
573             self.entry.component('entry').focus()
574         except:
575             pass
576
577     def make_label_titre(self):
578         """ Crée le label correspondant au titre """
579         if self.titre == '' : return
580         fonte_titre = fontes.standard_gras_souligne
581         self.label = Label(self.page,
582                            text = self.titre,
583                            font = fonte_titre)
584         self.label.pack(side='top',pady=2)
585         
586     def make_entry_filtre(self):
587         """ Crée l'entry permettant à l'utilisateur d'entrer un filtre de sélection dans la liste """
588         if self.filtre != 'oui' : return
589         self.entry = Pmw.EntryField(self.page,labelpos='w',
590                                     label_text="Filtre :",
591                                     command=self.entry_changed)
592         self.entry.pack(side='top',pady=2)
593         
594     def make_text_box(self):
595         """ Crée la fenêtre texte dans laquelle sera affichée la liste """
596         self.MCbox = Text (self.page,relief='sunken',bg='gray95',bd=2)
597         self.MCscroll = Scrollbar (self.page,command = self.MCbox.yview)
598         self.MCscroll.pack(side='right',fill ='y',pady=2)
599         self.MCbox.pack(fill='y',expand=1,padx=2,pady=2)
600         self.MCbox.configure(yscrollcommand=self.MCscroll.set)
601
602     def affiche_liste(self):
603         """ Affiche la liste dans la fenêtre"""
604         liste_labels=[]
605         self.MCbox.config(state=NORMAL)
606         self.MCbox.delete(1.0,END)
607         for objet in self.liste :
608           if type(objet) == types.InstanceType:
609               try:
610                   mot = objet.nom
611               except:
612                   mot = str(objet)
613           elif type(objet) in (types.StringType,types.IntType):
614               mot = objet
615           elif type(objet) == types.FloatType :
616               #mot = repr_float(objet)
617               mot = str(objet)
618           else:
619               mot=`objet`
620           label = Label(self.MCbox,
621                         text = mot,
622                         fg = 'black',bg = 'gray95',justify = 'left')
623           self.dico_labels[mot]=label
624           liste_labels.append(label)
625           self.MCbox.window_create(END,
626                                    window=label,
627                                    stretch = 1)
628           self.MCbox.insert(END,'\n')
629           if self.active == 'oui':
630               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))
631               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))
632               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))
633
634         for marque in self.liste_marques:
635            try:
636               self.markitem(liste_labels[marque])
637            except:
638               pass
639
640         self.MCbox.config(state=DISABLED)
641         self.selection = None
642
643     def chooseitem(self,mot,label,commande):
644         """ Active la méthode de choix passée en argument"""
645         try:
646            commande(mot)
647         except AsException,e:
648            raison=str(e)
649            showerror(raison.split('\n')[0],raison)
650         
651     def selectitem(self,mot,label,commande) :
652         """ Met l'item sélectionné (représenté par son label) en surbrillance
653             et lance la commande associée au double-clic"""
654         if self.selection != None :
655             self.deselectitem(self.selection[1],self.selection[0],self.selection[2],)
656         self.highlightitem(label)
657         self.selection = (mot,label,commande)
658         self.arg_selected = mot
659         commande(mot)
660
661     def highlightitem(self,label) :
662         """ Met l'item représenté par son label en surbrillance """
663         label.configure(bg='#00008b',fg='white')
664         
665     def markitem(self,label):
666         """ Met l'item (représenté par son label) en rouge """
667         label.configure(bg='gray95',fg='red')
668         
669     def deselectitem(self,label,mot='',commande=None) :
670         """ Remet l'item (représenté par son label) en noir"""
671         label.configure(bg='gray95',fg='black')
672         self.arg_selected = ''
673         if commande != None : commande(mot)
674
675     def entry_changed(self,event=None):
676         """ Cette méthode est invoquée chaque fois que l'utilisateur modifie le contenu
677         de l'entry et frappe <Return>"""
678         if self.arg_selected != '' : self.deselectitem(self.dico_labels[self.arg_selected])
679         filtre = self.entry.get()+"*"
680         FILTRE = string.upper(filtre)
681         for arg in self.liste :
682             if fnmatch.fnmatch(arg,filtre) or fnmatch.fnmatch(arg,FILTRE) :
683                 self.highlightitem(self.dico_labels[arg])
684                 index = self.MCbox.index(self.dico_labels[arg])
685                 self.MCbox.see(index)
686                 self.arg_selected = arg
687                 break
688
689     def get_liste_old(self):
690         return self.liste
691
692     # PN attention à la gestion des paramétres
693     # cela retourne H = 1 , et ni H, ni 1
694     #            print repr(val)
695     #            print val.__class__.__name__
696     def get_liste(self):
697         l=[]
698         for val in self.liste:
699 #            try:
700 #                v = eval(val)
701 #               l.append(v)
702 #            except:
703                 l.append(val)
704         return l
705     
706     def put_liste(self,liste):
707         self.liste = liste
708         self.affiche_liste()
709         
710 class Affichage :
711   """ Cette classe permet d'afficher au lancement d'EFICAS le message
712       d'attente et la barre de progression"""
713   def __init__(self,master,message,barre ='oui'):
714       from Tools.foztools.foztools import Slider
715       fonte=fontes.standard12_gras
716       self.master=master
717       self.frame = Frame(self.master)
718       self.frame.pack(expand=1,fill='both')
719       self.mess = Label(self.frame,text=message,justify='center',
720                         bd=2,relief='groove',font=fonte)
721       self.mess.pack(in_ = self.frame,side='top',expand=1,fill='both')
722       self.progress = Slider(self.frame,value=0,max=100,orientation='horizontal',
723                              fillColor='#00008b',width=200,height=30,
724                              background='white',labelColor='red')
725       if barre == 'oui':
726           self.progress.frame.pack(in_=self.frame,side='top')
727       self.master.update()
728       if barre == 'oui':
729           self.progress.frame.after(1000,self.update)
730
731   def configure(self,**options):
732       if options.has_key('message'):
733           self.mess.configure(text=options['message'])
734       if options.has_key('barre'):
735           if options['barre'] == 'oui' :
736               self.progress.frame.pack(in_=self.frame,side='top')
737           elif options['barre'] == 'non' :
738               self.progress.frame.pack_forget()
739       self.master.update_idletasks()
740       
741   def quit(self):
742       self.frame.destroy()
743       self.master.update()
744
745   def update(self,event=None):
746       """ Permet de faire avancer la barre de progression """
747       try :
748           bar=self.progress
749           bar.value = bar.value+self.increment
750           bar.update()
751           self.master.after(100,self.update)
752       except:
753           pass
754
755   def configure_barre(self,nb):
756       """ Calcule l'incrément de progression de la barre en fonction
757           du nombre d'opérations à effectuer afin que le compteur
758           soit à 100% à la fin des opérations"""
759       self.increment = 100./nb
760       self.progress.update()
761
762 class Ask_Format_Fichier :
763     """
764     Cette classe permet de créer une fenêtre Toplevel dans laquelle
765     on propose le choix du format de fichier de commandes à ouvrir
766     """
767     def __init__(self,appli):
768         self.fenetre = Toplevel()
769         self.fenetre.configure(width = 250,height=150)
770         self.fenetre.protocol("WM_DELETE_WINDOW", self.quit)
771         self.fenetre.title("Choix du format du fichier de commandes")
772         # définition des frames
773         self.frame_texte = Frame(self.fenetre)
774         self.frame_radioboutons = Frame(self.fenetre)
775         self.frame_bouton_ok = Frame(self.fenetre)
776         self.frame_texte.place(relx=0,rely=0,relwidth=1,relheight=0.3)
777         self.frame_radioboutons.place(relheight=0.5,relx=0,rely=0.3,relwidth=1.)
778         self.frame_bouton_ok.place(relheight=0.2,relx=0,rely=0.8,relwidth=1.)
779         # définition de la zone texte et du scrollbar
780         zone_texte = Label(self.frame_texte,text = "Format du fichier à ouvrir :")
781         zone_texte.pack(side='top',fill='both',expand=1,padx=5,pady=10)
782         # définition des radioboutons
783         Radiobutton(self.frame_radioboutons,text='Format Aster (Code_Aster --> v5)',
784                     variable=appli.format_fichier,value='Aster').pack(anchor='n')
785         Radiobutton(self.frame_radioboutons,text='Format Python (Code_Aster v6-->)',
786                     variable=appli.format_fichier,value='Python').pack(anchor='n')
787         # création du bouton OK
788         Button(self.frame_bouton_ok,text='OK',command=self.quit).pack(anchor='n')
789         # centrage de la fenêtre
790         centerwindow(self.fenetre)
791
792     def quit(self):
793         self.fenetre.destroy()
794
795 class BARRE_K2000(Toplevel):
796     def __init__(self,master=None,text = ""):
797         Toplevel.__init__(self,master,relief='groove')
798         self.master.iconify()
799         self.geometry("250x100+0+0")
800         self.protocol("WM_DELETE_WINDOW",self.quit)
801         # frame principale dans self (= Toplevel)
802         self.frame = Frame(self)
803         self.frame.place(relwidth=1,relheight=1)
804         # frame contenant le texte à afficher 
805         self.frame_text = Frame(self.frame)
806         self.frame_text.place(relwidth=1,relheight=0.75,rely=0)
807         # frame contenant le canvas de la barre
808         self.frame_canv = Frame(self.frame)
809         self.frame_canv.place(relwidth=1,relheight=0.25,rely=0.75)
810         # canvas dans lequel sera affichée la barre K2000
811         self.canvas = Canvas(self.frame_canv)
812         self.canvas.place(relx=0.5,rely=0.5,relheight=0.8,relwidth=0.8,anchor='center')
813         # on affiche le texte et la barre
814         self.build_text(text)
815         self.build_batons()
816         #self.overrideredirect(1)
817         # on active la barre ...
818         self.master.after(1000,self.launch)
819         # on centre la fenêtre
820         centerwindow(self)
821         self.focus()
822
823     def build_text(self,text):
824         """
825         Affichage de text dans frame_text
826         """
827         self.texte_var = StringVar()
828         self.texte_var.set(text)
829         Label(self.frame_text,textvariable=self.texte_var).place(relx=0.5,rely=0.5,anchor='center')
830         
831     def build_batons(self):
832         """
833         Construit la suite de bâtons dans le canvas
834         """
835         self.l_batons=[]
836         self.black = -1
837         self.sens = 'D'
838         self.quit = 0
839         for i in range(0,40):
840             id = self.canvas.create_rectangle(i*5,0,(i+1)*5,20,fill='gray90',outline='')
841             self.l_batons.append(id)
842
843     def launch(self):
844         """
845         Active la barre K2000 en affichant les bâtons avec des couleurs en dégradé
846         """
847         if self.quit == 1 :
848             self.destroy()
849             self.master.deiconify()
850             return
851         if self.sens == 'D':
852             self.black = self.black+1
853             l_bat = self.l_batons[0:self.black+1]
854             l_bat.reverse()
855         elif self.sens == 'G':
856             self.black = self.black-1
857             l_bat = self.l_batons[self.black:]
858         i=0
859         for bat in l_bat :
860             num_color = 5+i*10
861             if num_color < 10 : color = 'black'
862             elif num_color > 90 : color = 'white'
863             else: color = 'gray'+`num_color`
864             self.canvas.itemconfigure(bat,fill=color)
865             i=i+1
866         if self.black == len(self.l_batons) :
867             self.sens = 'G'
868         if self.black == 0 and self.sens == 'G':self.sens = 'D'
869         self.after(80,self.launch)
870
871     def update_text(self,new_text):
872         """
873         Remplace le texte affiché par new_text
874         """
875         self.texte_var.set(new_text)
876         
877     def quit(self):
878         self.quit = 1        
879
880 class ListeChoixParGroupes(ListeChoix) :
881     """ 
882         Cette classe est utilisée pour afficher une liste de commandes classées par
883         groupes. L'utilisateur peut réaliser des actions de selection
884         qui déclenchent des actions spécifiées par les bindings contenus dans liste_commandes
885     """
886     def __init__(self,parent,page,liste_groupes,dict_groupes,liste_commandes=[],liste_marques =[],
887                       active ='oui',filtre='non',titre=''):
888         self.parent = parent
889         self.page = page
890         self.liste_groupes = liste_groupes
891         self.dict_groupes = dict_groupes
892         self.dico_labels={}
893         self.selection = None
894         self.liste_commandes = liste_commandes
895         self.liste_marques = liste_marques
896         self.arg_selected=''
897         self.active = active
898         self.titre = titre
899         self.filtre = filtre
900         self.init()
901
902     def affiche_liste(self):
903         """ Affiche la liste dans la fenêtre"""
904         liste_labels=[]
905         self.MCbox.config(state=NORMAL)
906         self.MCbox.delete(1.0,END)
907         for grp in self.liste_groupes:
908            # On itère sur les groupes
909            if grp == "CACHE":continue
910            liste_commandes=self.dict_groupes[grp]
911            text="GROUPE<<<<<<<< "+grp+" "
912            text=text+">"*max(0,30-len(text))
913            label = Label(self.MCbox,
914                         text = text,
915                         fg = 'black',bg = 'gray95',justify = 'left')
916            # On stocke la relation entre le nom de la commande et le label
917            self.dico_labels[grp]=label
918            liste_labels.append(label)
919            self.MCbox.window_create(END,
920                                    window=label,
921                                    stretch = 1)
922            self.MCbox.insert(END,'\n')
923            for cmd in liste_commandes:
924               label = Label(self.MCbox,
925                         text = cmd,
926                         fg = 'black',bg = 'gray95',justify = 'left')
927               # On stocke la relation entre le nom de la commande et le label
928               self.dico_labels[cmd]=label
929               self.MCbox.window_create(END,
930                                    window=label,
931                                    stretch = 1)
932               self.MCbox.insert(END,'\n')
933               if self.active == 'oui':
934                   label.bind(self.liste_commandes[0][0],
935                          lambda e,s=self,c=self.liste_commandes[0][1],x=cmd,l=label : s.selectitem(x,l,c))
936                   label.bind(self.liste_commandes[1][0],
937                          lambda e,s=self,c=self.liste_commandes[1][1],x=cmd,l=label : s.deselectitem(l,x,c))
938                   label.bind(self.liste_commandes[2][0],
939                          lambda e,s=self,c=self.liste_commandes[2][1],x=cmd,l=label : s.chooseitem(x,l,c))
940
941         for marque in self.liste_marques:
942            try:
943               self.markitem(liste_labels[marque])
944            except:
945               pass
946
947         self.MCbox.config(state=DISABLED)
948         self.selection = None
949
950     def entry_changed(self,event=None):
951         """ 
952             Cette méthode est invoquée chaque fois que l'utilisateur modifie le contenu
953             de l'entry et frappe <Return>
954         """
955         if self.arg_selected != '' : self.deselectitem(self.dico_labels[self.arg_selected])
956         filtre = self.entry.get()+"*"
957         FILTRE = string.upper(filtre)
958         #
959         # On cherche d'abord dans les noms de groupe
960         # puis dans les noms de commande groupe par groupe
961         #
962         for grp in self.liste_groupes:
963             if fnmatch.fnmatch(grp,filtre) or fnmatch.fnmatch(grp,FILTRE) :
964                 index = self.MCbox.index(self.dico_labels[grp])
965                 self.MCbox.see(index)
966                 # On ne selectionne pas le groupe
967                 #self.arg_selected = grp
968                 # On a trouve un groupe on arrete la recherche
969                 return
970
971         for grp in self.liste_groupes:
972            for cmd in self.dict_groupes[grp] :
973               if fnmatch.fnmatch(cmd,filtre) or fnmatch.fnmatch(cmd,FILTRE) :
974                  self.highlightitem(self.dico_labels[cmd])
975                  index = self.MCbox.index(self.dico_labels[cmd])
976                  self.MCbox.see(index)
977                  self.arg_selected = cmd
978                  # On a trouve une commande  on arrete la recherche
979                  return
980