Salome HOME
PN pour prise en compte du retour chariot
[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         self.choose_separateur('espace')
229      
230
231     def get_separateurs_autorises(self):
232         """
233         Retourne la liste des séparateurs autorisés
234         """
235         return ['espace',';',',']
236
237     def choose_separateur(self,nom_sep):
238         """
239         Affecte à self.separateur le caractère séparateur correspondant à nom_sep
240         """
241         if nom_sep == 'espace' :
242             self.separateur = ' '
243         else:
244             self.separateur = nom_sep
245         
246     def tout(self):
247         liste=[]
248         texte=self.texte.splitlines()
249         for l in texte :
250             for mot in string.split(l,self.separateur):
251                if mot != '' and mot != ' ' and mot != self.separateur :
252                   liste.append(mot)
253         self.traite_selection(liste)
254
255     def traite_selection(self,liste=None):
256         """ Cette méthode effectue tous les traitements nécessaires pour vérifier
257             et affecter la liste de valeurs à l'objet réprésenté par self.item
258         """
259         # Récupère la liste des chaines de caractères de la zone sélectionnée
260         message=""
261         if liste == None:
262            message,liste = self.recupere_liste()
263         if self.test_probleme(message,"Sélectionnez des données") == 0:
264             return
265         # Vérifie que le nombre de données est dans les limites attendues
266         message = self.verif_liste(liste)
267         if self.test_probleme(message,"Vérifiez le nombre de données") == 0:
268             return
269         # Crée une liste de valeurs du type attendu
270         message,liste_valeurs = self.creation_liste_valeurs(liste)
271         if self.test_probleme(message,"Vérifiez le type des données") == 0:
272             return
273         # Vérifie que chaque valeur est dans le domaine exigé
274         message = self.verif_valeurs(liste_valeurs)
275         if self.test_probleme(message,"Vérifiez le domaine des valeurs") == 0:
276             return
277         # Ajoute les valeurs dans la liste de valeurs du mot-clé
278         if self.cardinal != 1 :
279            nb=self.cardinal
280            l_valeurs=[]
281            # a ameliorer
282            if (len(liste_valeurs)%nb != 0):
283                 message="La cardinalité n'est pas correcte"
284                 self.test_probleme(message,"On attend des tuples")
285                 return
286            for i in range(len(liste_valeurs)/nb) :
287                if (nb==2):
288                    t=(liste_valeurs[i*nb], liste_valeurs[i*nb+1])
289                elif (nb ==3):
290                    t=(liste_valeurs[i*nb], liste_valeurs[i*nb+1], liste_valeurs[i*nb+2])
291                else :
292                   print "probleme : prevenir la maintenance Eficas"
293                   return
294                l_valeurs.append(t)
295            liste_valeurs=l_valeurs
296         self.ajouter_valeurs(liste_valeurs)
297         self.appli.affiche_infos("Liste de valeurs acceptée")
298
299     def test_probleme(self, message, message_eficas):
300         """ Cette méthode affiche un message d'erreur si message != ''
301             et retourne 0, sinon retourne 1 sans rien afficher.
302         """
303         if message != "":
304             showinfo("Problème",message)
305             self.fenetre.tkraise()
306             self.appli.affiche_infos(message_eficas)
307             return 0
308         else:
309             return 1
310
311     def recupere_liste(self):
312         """ Cette méthode récupère le texte de la zone sélectionnée, construit et
313             retourne une liste avec les chaines qui se trouvent entre les séparateurs.
314             S'il n'y a pas de données selectionnées, elle retourne un message d'erreur
315             et une liste vide.
316         """
317         message = ""
318         try:
319             selection=self.fenetre.selection_get()
320         except:
321             message = "Pas de donnée sélectionnée"
322             return message,None
323         # les retours chariots doivent être interprétés comme des séparateurs
324         selection = string.replace(selection,'\n',self.separateur)
325         # on splitte la sélection suivant le caractère séparateur
326         liste_chaines = string.split(selection,self.separateur)
327         l_chaines = []
328         for chaine in liste_chaines:
329             chaine = string.strip(chaine)
330             if chaine != '' : l_chaines.append(chaine)
331         return message,l_chaines
332
333     def verif_liste(self, liste):
334         """ Cette méthode effectue des tests sur le nombre d'éléments de la liste
335             et retourne 1 si la liste est correcte, sinon 0 et le message d'erreur
336             correspondant.
337         """
338         message = ""
339         # nombre d'éléments sélectionnés
340         nombre_elements = len(liste)
341         # nombre d'éléments déja dans la liste du panel
342         nombre_in_liste = len(self.panel.Liste_valeurs.get_liste())
343         multiplicite = self.item.GetMultiplicite()
344         if (nombre_elements % multiplicite) != 0:
345             message = "Vous devez sélectionner "+str(multiplicite)+" * n données"
346             return message
347         nombre_valeurs = nombre_elements / multiplicite
348         cardinalite = self.item.GetMinMax()
349         if nombre_valeurs < cardinalite[0]:
350             message = "Vous devez sélectionner au moins "+str(cardinalite[0])+" valeurs"
351             return message
352         if cardinalite[1] != "**" and nombre_valeurs > (long(cardinalite[1])-nombre_in_liste):
353             message = "La liste ne peut avoir plus de "+str(cardinalite[1])+" valeurs"
354             return message
355
356         return message
357
358     def creation_liste_valeurs(self, liste):
359         """ Cette méthode crée et retourne une liste de valeurs du type attendu
360             par le mot-clé. La liste de valeurs est créée à partir de la liste
361             de chaines de caractères transmise.
362         """
363         type_attendu = self.item.GetType()[0]
364         if type_attendu == 'R':
365             return self.convertir(liste, f_conversion= float)
366         elif type_attendu == 'I':
367             return self.convertir(liste, f_conversion= int)
368         elif type_attendu == 'TXM':
369             return self.convertir(liste)
370         else:
371             message = "Seuls les entiers, les réels et les chaines de caractères sont convertis"
372             return message,None
373
374     def convertir(self, liste, f_conversion=None):
375         """ Cette méthode essaie de convertir les éléments de la liste avec la
376             fonction f_conversion si elle existe, et retourne la liste des
377             éléments dans le type voulu en cas de succès, sinon retourne None.
378         """
379         liste_valeurs = []
380         message = ""
381         for chaine in liste:
382             if f_conversion:
383                 try:
384                     liste_valeurs.append(f_conversion(chaine))
385                 except:
386                     message = "Impossible de convertir "+chaine+" dans le type attendu"
387                     return message,None
388             else:
389                 liste_valeurs.append(chaine)
390         return message,liste_valeurs
391
392     def verif_valeurs(self, liste_valeurs):
393         """ Cette méthode teste tous les éléments de la liste, et retourne 1 si chaque
394             élément est dans le domaine voulu.
395         """
396         message = ""
397         for valeur in liste_valeurs:
398             test = self.item.IsInIntervalle(valeur)
399             if test == 0:
400                 intervalle = str(self.item.GetIntervalle()[0])+","+str(self.item.GetIntervalle()[1])
401                 message = "La valeur "+str(valeur)+" n'est pas dans l'intervalle ["+intervalle+"]"
402                 return message
403         return message
404
405     def ajouter_valeurs(self, liste_valeurs):
406         """ Cette méthode ajoute les nouvelles valeurs à la liste existante."""
407         liste = self.panel.Liste_valeurs.get_liste()
408         liste.extend(liste_valeurs)
409         self.panel.Liste_valeurs.put_liste(liste)
410
411 class FenetreDeParametre(Fenetre) :
412     def __init__(self,parent,item,appli,texte):
413         self.parent=parent
414         self.appli=appli
415         self.fenetre = Toplevel()
416         self.fenetre.configure(width = 250,height=100)
417         self.fenetre.protocol("WM_DELETE_WINDOW", self.quit)
418         self.fenetre.title("Parametres")
419         self.titre = "Parametres"
420         self.texte = string.replace(texte,'\r\n','\n')
421         fonte=fontes.standardcourier10
422
423         # définition des frames
424         self.frame_texte = Frame(self.fenetre)
425         self.frame_texte.place(relx=0,rely=0,relwidth=1,relheight=0.7)
426         # définition de la zone texte et du scrollbar
427         self.zone_texte = Text(self.frame_texte,font=fonte)
428         self.zone_texte.bind("<Key-Prior>", self.page_up)
429         self.zone_texte.bind("<Key-Next>", self.page_down)
430         self.zone_texte.bind("<Key-Up>", self.unit_up)
431         self.zone_texte.bind("<Key-Down>", self.unit_down)
432         self.scroll_v = Scrollbar (self.frame_texte,command = self.zone_texte.yview)
433         self.scroll_v.pack(side='right',fill ='y')
434         self.zone_texte.pack(side='top',fill='both',expand=1,padx=5,pady=10)
435         self.zone_texte.configure(yscrollcommand=self.scroll_v.set)
436         # affichage du texte
437         self.affiche_texte(self.texte)
438         self.zone_texte.config(state="disabled")
439
440         # définition des boutons
441         self.frame_boutons = Frame(self.fenetre)
442         self.frame_boutons.place(relheight=0.3,relx=0,rely=0.65,relwidth=1.)
443         self.label1 = Label(self.frame_boutons,text="surligner la")
444         self.label2 = Label(self.frame_boutons,text="ligne entière")
445         self.label1.place(relx=0.1,rely=0)
446         self.label2.place(relx=0.1,rely=0.5)
447         self.but_quit = Button(self.frame_boutons,text = "Fermer",command=self.quit)
448         self.but_save = Button(self.frame_boutons,text = "Choisir",command = self.Choisir)
449         self.but_save.place(relx=0.6,rely=0,relheight=1)
450         self.but_quit.place(relx=0.8,rely=0,relheight=1)
451
452
453     def Choisir(self):
454         try:
455             selection=self.zone_texte.selection_get()
456         except:
457             showerror("Pas de donnée sélectionnée",
458                        "Selectionner un parametre")
459         l_param = ""
460         for param in selection.splitlines():
461             nomparam=param[0:param.find("=")-1]
462             if nomparam != '' : 
463                 l_param=l_param+nomparam+','
464         self.parent.entry.delete(0,Tkinter.END)
465         self.parent.entry.insert(0,l_param[0:-1])
466         self.parent.valid_valeur()
467         self.quit()
468
469 class Formulaire:
470     """
471     Cette classe permet de créer une boîte Dialog dans laquelle
472     on affiche un formulaire à remplir par l'utilisateur
473     """
474     def __init__(self,fen_pere,obj_pere=None,titre="",texte="",items=(),mode='query',commande=None):
475         if items in ((),[]) : return
476         self.items = items
477         self.titre = titre
478         self.texte = texte
479         self.fen_pere = fen_pere
480         self.obj_pere = obj_pere
481         self.mode= mode
482         self.command = commande
483         self.display()
484
485     def display(self):
486         self.init_validateurs()
487         self.init_fenetre()
488         self.init_texte()
489         self.init_items_formulaire()
490         self.fenetre.activate(geometry='centerscreenalways')
491
492     def init_validateurs(self):
493         """
494         Crée le dictionnaire des validateurs des objets reconnus par le formulaire
495         """
496         self.d_validateurs = {}
497         self.d_validateurs['rep']  = self.repvalidator
498         self.d_validateurs['file'] = self.filevalidator
499         self.d_validateurs['cata']= self.catavalidator
500         
501     def init_fenetre(self):
502         """
503         Crée la fenêtre Dialog
504         """
505         if self.mode == 'query':
506             buttons=('Valider','Annuler')
507             defaultbutton = 'Valider'
508         elif self.mode == 'display':
509             if self.command :
510                 buttons=(self.command[0],'OK')
511                 defaultbutton = 'OK'
512             else:
513                 buttons=('OK')
514                 defaultbutton = 'OK'
515         self.fenetre = Pmw.Dialog(self.fen_pere,
516                                   buttons=buttons,
517                                   defaultbutton = defaultbutton,
518                                   title = self.titre,
519                                   command = self.execute)
520         self.fenetre.withdraw()
521         
522     def init_texte(self):
523         """
524         Crée le label qui affiche le texte à l'intérieur du panneau
525         """
526         fonte=fontes.standard
527         fr_texte = Frame(self.fenetre.interior(),height=60)
528         fr_texte.pack(side='top',fill='x',expand=1)
529         Label(fr_texte,text = self.texte, font=fonte).place(relx=0.5,rely=0.5,anchor='center')
530
531     def init_items_formulaire(self):
532         """
533         Crée et affiche les items dans la boîte de dialogue
534         """
535         self.radiobut = 0
536         self.widgets = []
537         self.item_widgets = {}
538         length_maxi = 0
539         for item in self.items:
540             if len(item[0])>length_maxi : length_maxi = len(item[0])
541         window = self.fenetre.interior()
542         for item in self.items :
543             label,nature,nom_var,defaut = item
544             # création de la frame
545             fr_item = Frame(window,height=40,width=700)
546             fr_item.pack(side='top',fill='x',expand=1)
547             # création du label
548             Label(fr_item,text = label).place(relx=0.05,rely=0.4)
549             if nature in ('rep','file','cata'):
550                 # création de l'entry
551                 e_item = Entry(fr_item) 
552                 e_item.place(relx=0.5,rely=0.4,relwidth=0.45)
553                 self.widgets.append(e_item)
554                 self.item_widgets[item] = e_item
555                 if defaut : e_item.insert(0,str(defaut))
556             elif nature == 'YesNo':
557                 # création de la StringVar
558                 var = StringVar()
559                 setattr(self,'item_'+nom_var,var)
560                 var.set(defaut)
561                 # création du radiobouton
562                 rb1 = Radiobutton(fr_item,text='OUI',variable=var,value='OUI')
563                 rb2 = Radiobutton(fr_item,text='NON',variable=var,value='NON')
564                 rb1.place(relx=0.65,rely=0.5,anchor='center')
565                 rb2.place(relx=0.80,rely=0.5,anchor='center')
566                 self.widgets.append((rb1,rb2))
567                 self.item_widgets[item] = var
568         # détermination de la méthode à appliquer sur les boutons
569         if self.mode == 'query':
570             function = self.active
571         elif self.mode == 'display':
572             function = self.inactive
573         else:
574             return
575         # on applique la méthode sur les boutons (activation ou désactivation)  
576         for widget in self.widgets :
577             if type(widget) == types.TupleType:
578                 for widg in widget :
579                     apply(function,(widg,),{})
580             else:
581                 apply(function,(widget,),{})
582
583     def active(self,widget):
584         """
585         Active le widget passé en argument
586         """
587         widget.configure(state='normal',bg='white')
588
589     def inactive(self,widget):
590         """
591         Inactive le widget passé en argument
592         """
593         if not isinstance(widget,Radiobutton) :
594             widget.configure(state='disabled',bg='gray95')
595         else :
596             widget.configure(state='disabled')
597
598 # --------------------------------------------------------------------------------
599 #       Validateurs des noms de répertoire, de fichiers et de catalogues
600 # -------------------------------------------------------------------------------
601
602     def repvalidator(self,text):
603         """
604         Teste si text peut faire référence à un répertoire ou non
605         Retourne 1 si valide, 0 sinon
606         """
607         return os.path.isdir(text),'Répertoire introuvable : %s' %text
608
609     def filevalidator(self,text):
610         """
611         Teste si text peut faire référence à un fichier ou non
612         Retourne 1 si valide, 0 sinon
613         """
614         return os.path.isfile(text),'Fichier introuvable : %s' %text
615
616     def catavalidator(self,text):
617         """
618         Teste si  text est un chemin d'accès valide à un catalogue
619         Retourne 1 si valide, 0 sinon
620         """
621         return os.path.isfile(text),"Catalogue introuvable : %s" %text
622
623 # --------------------------------------------------------------------------------
624 #       Méthodes callbacks des boutons et de fin
625 # --------------------------------------------------------------------------------
626         
627     def execute(self,txt):
628         """
629         Cette commande est activée à chaque clic sur un bouton.
630         Redirige l'action sur la bonne méthode en fonction du bouton activé
631         """
632         if txt == 'Valider':
633             self.fini()
634         elif txt in ('OK','Annuler'):
635             self.quit()
636         elif txt == 'Modifier':
637             self.resultat = apply(self.command[1],(),{})
638             self.fenetre.destroy()
639         else :
640             print "Nom de bouton inconnu"
641             self.quit()
642
643     def fini(self):
644         """
645         Commande qui termine le panneau et sauvegarde les nouvelles options
646         dans l'objet resultat (dictionnaire)
647         """
648         dico={}
649         for item,widget in self.item_widgets.items():
650             nom_var = item[2]
651             type_var = item[1]
652             valeur = widget.get()
653             if self.d_validateurs.has_key(type_var):
654                 test = self.d_validateurs[type_var](valeur)
655                 if not test :
656                     # une entrée n'est pas valide --> on la met en surbrillance et on quitte la méthode
657                     # sans tuer la fenêtre bien sûr
658                     widget.selection_range(0,END)
659                     return
660             dico[nom_var] = valeur
661         self.fenetre.destroy()    
662         self.resultat=dico
663         
664     def quit(self):
665         self.fenetre.destroy()
666         self.resultat=None
667         
668 class ListeChoix :
669     """ Cette classe est utilisée pour afficher une liste de choix passée en paramètre
670         en passant les commandes à lancer suivant différents bindings """
671     def __init__(self,parent,page,liste,liste_commandes=[],liste_marques =[],active ='oui',filtre='non',titre='',optionReturn=None):
672         self.parent = parent
673         self.page = page
674         self.liste = liste
675         self.dico_labels={}
676         self.selection = None
677         self.liste_commandes = liste_commandes
678         self.liste_marques = liste_marques
679         self.arg_selected=''
680         self.active = active
681         self.titre = titre
682         self.filtre = filtre
683         self.optionReturn = optionReturn
684         self.init()
685
686     def init(self):        
687         self.make_label_titre()
688         self.make_entry_filtre()
689         self.make_text_box()
690         try:
691             self.entry.component('entry').focus()
692         except:
693             pass
694
695     def make_label_titre(self):
696         """ Crée le label correspondant au titre """
697         if self.titre == '' : return
698         fonte_titre = fontes.standard_gras_souligne
699         self.label = Label(self.page,
700                            text = self.titre,
701                            font = fonte_titre)
702         self.label.pack(side='top',pady=2)
703         
704     def make_entry_filtre(self):
705         """ Crée l'entry permettant à l'utilisateur d'entrer un filtre de sélection dans la liste """
706         if self.filtre != 'oui' : return
707         self.entry = Pmw.EntryField(self.page,labelpos='w',
708                                     label_text="Filtre :",
709                                     command=self.entry_changed)
710         self.entry.pack(side='top',pady=2)
711         
712     def make_text_box(self):
713         """ Crée la fenêtre texte dans laquelle sera affichée la liste """
714         self.MCbox = Text (self.page,relief='sunken',bg='gray95',bd=2)
715         self.MCscroll = Scrollbar (self.page,command = self.MCbox.yview)
716         self.MCscroll.pack(side='right',fill ='y',pady=2)
717         self.MCbox.pack(fill='y',expand=1,padx=2,pady=2)
718         self.MCbox.configure(yscrollcommand=self.MCscroll.set)
719
720
721     def affiche_liste(self):
722         """ Affiche la liste dans la fenêtre"""
723         liste_labels=[]
724         self.MCbox.config(state=NORMAL)
725         self.MCbox.delete(1.0,END)
726         for objet in self.liste :
727           if type(objet) == types.InstanceType:
728               try:
729                   mot = objet.nom
730               except:
731                   mot = str(objet)
732           elif type(objet) in (types.StringType,types.IntType):
733               mot = objet
734           elif type(objet) == types.FloatType :
735               #mot = repr_float(objet)
736               mot = str(objet)
737           elif type(objet) == types.TupleType :
738               mot="("
739               premier=1
740               for val in objet:
741                  if (not premier):
742                    mot=mot+"," 
743                  else:
744                    premier=0
745                  mot=mot+str(val)
746               mot=mot+")"
747           else:
748               mot=`objet`
749           label = Label(self.MCbox,
750                         text = mot,
751                         fg = 'black',bg = 'gray95',justify = 'left')
752           self.dico_labels[mot]=label
753           liste_labels.append(label)
754           self.MCbox.window_create(END,
755                                    window=label,
756                                    stretch = 1)
757           self.MCbox.insert(END,'\n')
758           if self.optionReturn != None :
759               label.bind("<Return>",lambda e,s=self,c=self.liste_commandes[2][1],x=objet,l=label : s.chooseitemsurligne(x,l,c))
760           label.bind("<Key-Right>",lambda e,s=self,x=objet,l=label : s.selectNextItem(x,l))
761           if self.active == 'oui':
762               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))
763               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))
764               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))
765
766         for marque in self.liste_marques:
767            try:
768               self.markitem(liste_labels[marque])
769            except:
770               pass
771
772         self.MCbox.config(state=DISABLED)
773         self.selection = None
774
775     def clear_marque(self):
776         try:
777           self.dico_labels[self.arg_selected].configure(bg='gray95',fg='black')
778           self.arg_selected = ''
779         except :
780           pass
781
782     def surligne(self,marque):
783         try :
784            self.highlightitem(self.dico_labels[marque])
785            self.arg_selected = marque
786         except:
787            pass
788
789     def chooseitemsurligne(self,mot,label,commande):
790         """ Active la méthode de choix passée en argument"""
791         try:
792            mot=self.arg_selected
793            commande(mot)
794         except AsException,e:
795            raison=str(e)
796            showerror(raison.split('\n')[0],raison)
797
798     def chooseitem(self,mot,label,commande):
799         """ Active la méthode de choix passée en argument"""
800         try:
801            commande(mot)
802         except AsException,e:
803            raison=str(e)
804            showerror(raison.split('\n')[0],raison)
805         
806     def selectNextItem(self,mot,label):
807         try :
808            index=self.liste.index(mot)
809            indexsuivant=index+1
810            motsuivant=self.liste[indexsuivant]
811            labelsuivant=self.dico_labels[motsuivant]
812            self.clear_marque()
813            if self.selection != None :
814               self.deselectitem(self.selection[1],self.selection[0],self.selection[2],)
815               self.selection = (mot,label,self.selection[2])
816            self.highlightitem(labelsuivant)
817            self.arg_selected=motsuivant
818            labelsuivant.focus_set()
819         # PN il faut faire quelque chose pour être dans la fenetre
820         except:
821            pass
822            
823         
824     def selectitem(self,mot,label,commande) :
825         """ Met l'item sélectionné (représenté par son label) en surbrillance
826             et lance la commande associée au double-clic"""
827         self.clear_marque()
828         if self.selection != None :
829             self.deselectitem(self.selection[1],self.selection[0],self.selection[2],)
830         self.highlightitem(label)
831         self.selection = (mot,label,commande)
832         self.arg_selected = mot
833         commande(mot)
834
835     def highlightitem(self,label) :
836         """ Met l'item représenté par son label en surbrillance """
837         label.configure(bg='#00008b',fg='white')
838         
839     def markitem(self,label):
840         """ Met l'item (représenté par son label) en rouge """
841         label.configure(bg='gray95',fg='red')
842         
843     def deselectitem(self,label,mot='',commande=None) :
844         """ Remet l'item (représenté par son label) en noir"""
845         label.configure(bg='gray95',fg='black')
846         self.arg_selected = ''
847         if commande != None : commande(mot)
848
849     def cherche_selected_item(self):
850         index=self.MCbox.index(self.selection[1])
851         lign,col=map(int,string.split(index,'.'))
852         return lign
853
854     def remove_selected_item(self):
855         index=self.MCbox.index(self.selection[1])
856         lign,col=map(int,string.split(index,'.'))
857         del self.liste[lign-1]
858         self.affiche_liste()
859
860     def entry_changed(self,event=None):
861         """ Cette méthode est invoquée chaque fois que l'utilisateur modifie le contenu
862         de l'entry et frappe <Return>"""
863         if self.arg_selected != '' : self.deselectitem(self.dico_labels[self.arg_selected])
864         filtre = self.entry.get()+"*"
865         FILTRE = string.upper(filtre)
866         for arg in self.liste :
867             if fnmatch.fnmatch(arg,filtre) or fnmatch.fnmatch(arg,FILTRE) :
868                 self.highlightitem(self.dico_labels[arg])
869                 index = self.MCbox.index(self.dico_labels[arg])
870                 self.MCbox.see(index)
871                 self.arg_selected = arg
872                 break
873         try :
874           self.dico_labels[self.arg_selected].focus_set()
875         except :
876           pass
877
878     def get_liste_old(self):
879         return self.liste
880
881     # PN attention à la gestion des paramétres
882     # cela retourne H = 1 , et ni H, ni 1
883     #            print repr(val)
884     #            print val.__class__.__name__
885     def get_liste(self):
886         l=[]
887         for val in self.liste:
888 #            try:
889 #                v = eval(val)
890 #               l.append(v)
891 #            except:
892                 l.append(val)
893         return l
894     
895     def put_liste(self,liste):
896         self.liste = liste
897         self.affiche_liste()
898
899 class Affichage :
900   """ Cette classe permet d'afficher au lancement d'EFICAS le message
901       d'attente et la barre de progression"""
902   def __init__(self,master,message,barre ='oui'):
903       from Tools.foztools.foztools import Slider
904       fonte=fontes.standard12_gras
905       self.master=master
906       self.frame = Frame(self.master)
907       self.frame.pack(expand=1,fill='both')
908       self.mess = Label(self.frame,text=message,justify='center',
909                         bd=2,relief='groove',font=fonte)
910       self.mess.pack(in_ = self.frame,side='top',expand=1,fill='both')
911       self.progress = Slider(self.frame,value=0,max=100,orientation='horizontal',
912                              fillColor='#00008b',width=200,height=30,
913                              background='white',labelColor='red')
914       if barre == 'oui':
915           self.progress.frame.pack(in_=self.frame,side='top')
916       self.master.update()
917       if barre == 'oui':
918           self.progress.frame.after(1000,self.update)
919
920   def configure(self,**options):
921       if options.has_key('message'):
922           self.mess.configure(text=options['message'])
923       if options.has_key('barre'):
924           if options['barre'] == 'oui' :
925               self.progress.frame.pack(in_=self.frame,side='top')
926           elif options['barre'] == 'non' :
927               self.progress.frame.pack_forget()
928       self.master.update_idletasks()
929       
930   def quit(self):
931       self.frame.destroy()
932       self.master.update()
933
934   def update(self,event=None):
935       """ Permet de faire avancer la barre de progression """
936       try :
937           bar=self.progress
938           bar.value = bar.value+self.increment
939           bar.update()
940           self.master.after(100,self.update)
941       except:
942           pass
943
944   def configure_barre(self,nb):
945       """ Calcule l'incrément de progression de la barre en fonction
946           du nombre d'opérations à effectuer afin que le compteur
947           soit à 100% à la fin des opérations"""
948       self.increment = 100./nb
949       self.progress.update()
950
951 class Ask_Format_Fichier :
952     """
953     Cette classe permet de créer une fenêtre Toplevel dans laquelle
954     on propose le choix du format de fichier de commandes à ouvrir
955     """
956     def __init__(self,appli):
957         self.fenetre = Toplevel()
958         self.fenetre.configure(width = 250,height=150)
959         self.fenetre.protocol("WM_DELETE_WINDOW", self.quit)
960         self.fenetre.title("Choix du format du fichier de commandes")
961         # définition des frames
962         self.frame_texte = Frame(self.fenetre)
963         self.frame_radioboutons = Frame(self.fenetre)
964         self.frame_bouton_ok = Frame(self.fenetre)
965         self.frame_texte.place(relx=0,rely=0,relwidth=1,relheight=0.3)
966         self.frame_radioboutons.place(relheight=0.5,relx=0,rely=0.3,relwidth=1.)
967         self.frame_bouton_ok.place(relheight=0.2,relx=0,rely=0.8,relwidth=1.)
968         # définition de la zone texte et du scrollbar
969         zone_texte = Label(self.frame_texte,text = "Format du fichier à ouvrir :")
970         zone_texte.pack(side='top',fill='both',expand=1,padx=5,pady=10)
971         # définition des radioboutons
972         Radiobutton(self.frame_radioboutons,text='Format Aster (Code_Aster --> v5)',
973                     variable=appli.format_fichier,value='Aster').pack(anchor='n')
974         Radiobutton(self.frame_radioboutons,text='Format Python (Code_Aster v6-->)',
975                     variable=appli.format_fichier,value='Python').pack(anchor='n')
976         # création du bouton OK
977         Button(self.frame_bouton_ok,text='OK',command=self.quit).pack(anchor='n')
978         # centrage de la fenêtre
979         centerwindow(self.fenetre)
980
981     def quit(self):
982         self.fenetre.destroy()
983
984 class BARRE_K2000(Toplevel):
985     def __init__(self,master=None,text = ""):
986         Toplevel.__init__(self,master,relief='groove')
987         self.master.iconify()
988         self.geometry("250x100+0+0")
989         self.protocol("WM_DELETE_WINDOW",self.quit)
990         # frame principale dans self (= Toplevel)
991         self.frame = Frame(self)
992         self.frame.place(relwidth=1,relheight=1)
993         # frame contenant le texte à afficher 
994         self.frame_text = Frame(self.frame)
995         self.frame_text.place(relwidth=1,relheight=0.75,rely=0)
996         # frame contenant le canvas de la barre
997         self.frame_canv = Frame(self.frame)
998         self.frame_canv.place(relwidth=1,relheight=0.25,rely=0.75)
999         # canvas dans lequel sera affichée la barre K2000
1000         self.canvas = Canvas(self.frame_canv)
1001         self.canvas.place(relx=0.5,rely=0.5,relheight=0.8,relwidth=0.8,anchor='center')
1002         # on affiche le texte et la barre
1003         self.build_text(text)
1004         self.build_batons()
1005         #self.overrideredirect(1)
1006         # on active la barre ...
1007         self.master.after(1000,self.launch)
1008         # on centre la fenêtre
1009         centerwindow(self)
1010         self.focus()
1011
1012     def build_text(self,text):
1013         """
1014         Affichage de text dans frame_text
1015         """
1016         self.texte_var = StringVar()
1017         self.texte_var.set(text)
1018         Label(self.frame_text,textvariable=self.texte_var).place(relx=0.5,rely=0.5,anchor='center')
1019         
1020     def build_batons(self):
1021         """
1022         Construit la suite de bâtons dans le canvas
1023         """
1024         self.l_batons=[]
1025         self.black = -1
1026         self.sens = 'D'
1027         self.quit = 0
1028         for i in range(0,40):
1029             id = self.canvas.create_rectangle(i*5,0,(i+1)*5,20,fill='gray90',outline='')
1030             self.l_batons.append(id)
1031
1032     def launch(self):
1033         """
1034         Active la barre K2000 en affichant les bâtons avec des couleurs en dégradé
1035         """
1036         if self.quit == 1 :
1037             self.destroy()
1038             self.master.deiconify()
1039             return
1040         if self.sens == 'D':
1041             self.black = self.black+1
1042             l_bat = self.l_batons[0:self.black+1]
1043             l_bat.reverse()
1044         elif self.sens == 'G':
1045             self.black = self.black-1
1046             l_bat = self.l_batons[self.black:]
1047         i=0
1048         for bat in l_bat :
1049             num_color = 5+i*10
1050             if num_color < 10 : color = 'black'
1051             elif num_color > 90 : color = 'white'
1052             else: color = 'gray'+`num_color`
1053             self.canvas.itemconfigure(bat,fill=color)
1054             i=i+1
1055         if self.black == len(self.l_batons) :
1056             self.sens = 'G'
1057         if self.black == 0 and self.sens == 'G':self.sens = 'D'
1058         self.after(80,self.launch)
1059
1060     def update_text(self,new_text):
1061         """
1062         Remplace le texte affiché par new_text
1063         """
1064         self.texte_var.set(new_text)
1065         
1066     def quit(self):
1067         self.quit = 1        
1068
1069 class ListeChoixParGroupes(ListeChoix) :
1070     """ 
1071         Cette classe est utilisée pour afficher une liste de commandes classées par
1072         groupes. L'utilisateur peut réaliser des actions de selection
1073         qui déclenchent des actions spécifiées par les bindings contenus dans liste_commandes
1074     """
1075     def __init__(self,parent,page,liste_groupes,dict_groupes,liste_commandes=[],liste_marques =[],
1076                       active ='oui',filtre='non',titre=''):
1077         self.parent = parent
1078         self.page = page
1079         self.liste_groupes = liste_groupes
1080         self.dict_groupes = dict_groupes
1081         self.dico_labels={}
1082         self.selection = None
1083         self.liste_commandes = liste_commandes
1084         self.liste_marques = liste_marques
1085         self.arg_selected=''
1086         self.active = active
1087         self.titre = titre
1088         self.filtre = filtre
1089         self.init()
1090
1091     def affiche_liste(self):
1092         """ Affiche la liste dans la fenêtre"""
1093         liste_labels=[]
1094         self.MCbox.config(state=NORMAL)
1095         self.MCbox.delete(1.0,END)
1096         for grp in self.liste_groupes:
1097            # On itère sur les groupes
1098            if grp == "CACHE":continue
1099            liste_commandes=self.dict_groupes[grp]
1100            text="GROUPE<<<<<<<< "+grp+" "
1101            text=text+">"*max(0,30-len(text))
1102            label = Label(self.MCbox,
1103                         text = text,
1104                         fg = 'black',bg = 'gray95',justify = 'left')
1105            # On stocke la relation entre le nom de la commande et le label
1106            self.dico_labels[grp]=label
1107            liste_labels.append(label)
1108            self.MCbox.window_create(END,
1109                                    window=label,
1110                                    stretch = 1)
1111            self.MCbox.insert(END,'\n')
1112            for cmd in liste_commandes:
1113               label = Label(self.MCbox,
1114                         text = cmd,
1115                         fg = 'black',bg = 'gray95',justify = 'left')
1116               # On stocke la relation entre le nom de la commande et le label
1117               self.dico_labels[cmd]=label
1118               self.MCbox.window_create(END,
1119                                    window=label,
1120                                    stretch = 1)
1121               self.MCbox.insert(END,'\n')
1122               if self.active == 'oui':
1123                   label.bind(self.liste_commandes[0][0],
1124                          lambda e,s=self,c=self.liste_commandes[0][1],x=cmd,l=label : s.selectitem(x,l,c))
1125                   label.bind(self.liste_commandes[1][0],
1126                          lambda e,s=self,c=self.liste_commandes[1][1],x=cmd,l=label : s.deselectitem(l,x,c))
1127                   label.bind(self.liste_commandes[2][0],
1128                          lambda e,s=self,c=self.liste_commandes[2][1],x=cmd,l=label : s.chooseitem(x,l,c))
1129                   label.bind("<Key-Down>", self.selectNextItem(event))
1130
1131         for marque in self.liste_marques:
1132            try:
1133               self.markitem(liste_labels[marque])
1134            except:
1135               pass
1136
1137         self.MCbox.config(state=DISABLED)
1138         self.selection = None
1139
1140     def entry_changed(self,event=None):
1141         """ 
1142             Cette méthode est invoquée chaque fois que l'utilisateur modifie le contenu
1143             de l'entry et frappe <Return>
1144         """
1145         if self.arg_selected != '' : self.deselectitem(self.dico_labels[self.arg_selected])
1146         filtre = self.entry.get()+"*"
1147         FILTRE = string.upper(filtre)
1148         #
1149         # On cherche d'abord dans les noms de groupe
1150         # puis dans les noms de commande groupe par groupe
1151         #
1152         for grp in self.liste_groupes:
1153             if fnmatch.fnmatch(grp,filtre) or fnmatch.fnmatch(grp,FILTRE) :
1154                 index = self.MCbox.index(self.dico_labels[grp])
1155                 self.MCbox.see(index)
1156                 # On ne selectionne pas le groupe
1157                 #self.arg_selected = grp
1158                 # On a trouve un groupe on arrete la recherche
1159                 return
1160
1161         for grp in self.liste_groupes:
1162            for cmd in self.dict_groupes[grp] :
1163               if fnmatch.fnmatch(cmd,filtre) or fnmatch.fnmatch(cmd,FILTRE) :
1164                  self.highlightitem(self.dico_labels[cmd])
1165                  index = self.MCbox.index(self.dico_labels[cmd])
1166                  self.MCbox.see(index)
1167                  self.arg_selected = cmd
1168                  # On a trouve une commande  on arrete la recherche
1169                  return
1170