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