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