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