Salome HOME
Changement sur le choix des parametres
[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.7,relwidth=1.)
424         self.but_quit = Button(self.frame_boutons,text = "Fermer",command=self.quit)
425         self.but_save = Button(self.frame_boutons,text = "Choisir",command = self.Choisir)
426         self.but_save.place(relx=0.6,rely=0,relheight=1)
427         self.but_quit.place(relx=0.8,rely=0,relheight=1)
428
429
430     def Choisir(self):
431         try:
432             selection=self.zone_texte.selection_get()
433         except:
434             showerror("Pas de donnée sélectionnée",
435                        "Selectionner un parametre")
436         l_param = ""
437         for param in selection.splitlines():
438             nomparam=param[0:param.find("=")-1]
439             if nomparam != '' : 
440                 l_param=l_param+nomparam+','
441         self.parent.entry.delete(0,Tkinter.END)
442         self.parent.entry.insert(0,l_param[0:-1])
443         self.parent.valid_valeur()
444         self.quit()
445
446 class Formulaire:
447     """
448     Cette classe permet de créer une boîte Dialog dans laquelle
449     on affiche un formulaire à remplir par l'utilisateur
450     """
451     def __init__(self,fen_pere,obj_pere=None,titre="",texte="",items=(),mode='query',commande=None):
452         if items in ((),[]) : return
453         self.items = items
454         self.titre = titre
455         self.texte = texte
456         self.fen_pere = fen_pere
457         self.obj_pere = obj_pere
458         self.mode= mode
459         self.command = commande
460         self.display()
461
462     def display(self):
463         self.init_validateurs()
464         self.init_fenetre()
465         self.init_texte()
466         self.init_items_formulaire()
467         self.fenetre.activate(geometry='centerscreenalways')
468
469     def init_validateurs(self):
470         """
471         Crée le dictionnaire des validateurs des objets reconnus par le formulaire
472         """
473         self.d_validateurs = {}
474         self.d_validateurs['rep']  = self.repvalidator
475         self.d_validateurs['file'] = self.filevalidator
476         self.d_validateurs['cata']= self.catavalidator
477         
478     def init_fenetre(self):
479         """
480         Crée la fenêtre Dialog
481         """
482         if self.mode == 'query':
483             buttons=('Valider','Annuler')
484             defaultbutton = 'Valider'
485         elif self.mode == 'display':
486             if self.command :
487                 buttons=(self.command[0],'OK')
488                 defaultbutton = 'OK'
489             else:
490                 buttons=('OK')
491                 defaultbutton = 'OK'
492         self.fenetre = Pmw.Dialog(self.fen_pere,
493                                   buttons=buttons,
494                                   defaultbutton = defaultbutton,
495                                   title = self.titre,
496                                   command = self.execute)
497         self.fenetre.withdraw()
498         
499     def init_texte(self):
500         """
501         Crée le label qui affiche le texte à l'intérieur du panneau
502         """
503         fonte=fontes.standard
504         fr_texte = Frame(self.fenetre.interior(),height=60)
505         fr_texte.pack(side='top',fill='x',expand=1)
506         Label(fr_texte,text = self.texte, font=fonte).place(relx=0.5,rely=0.5,anchor='center')
507
508     def init_items_formulaire(self):
509         """
510         Crée et affiche les items dans la boîte de dialogue
511         """
512         self.radiobut = 0
513         self.widgets = []
514         self.item_widgets = {}
515         length_maxi = 0
516         for item in self.items:
517             if len(item[0])>length_maxi : length_maxi = len(item[0])
518         window = self.fenetre.interior()
519         for item in self.items :
520             label,nature,nom_var,defaut = item
521             # création de la frame
522             fr_item = Frame(window,height=40,width=700)
523             fr_item.pack(side='top',fill='x',expand=1)
524             # création du label
525             Label(fr_item,text = label).place(relx=0.05,rely=0.4)
526             if nature in ('rep','file','cata'):
527                 # création de l'entry
528                 e_item = Entry(fr_item) 
529                 e_item.place(relx=0.5,rely=0.4,relwidth=0.45)
530                 self.widgets.append(e_item)
531                 self.item_widgets[item] = e_item
532                 if defaut : e_item.insert(0,str(defaut))
533             elif nature == 'YesNo':
534                 # création de la StringVar
535                 var = StringVar()
536                 setattr(self,'item_'+nom_var,var)
537                 var.set(defaut)
538                 # création du radiobouton
539                 rb1 = Radiobutton(fr_item,text='OUI',variable=var,value='OUI')
540                 rb2 = Radiobutton(fr_item,text='NON',variable=var,value='NON')
541                 rb1.place(relx=0.65,rely=0.5,anchor='center')
542                 rb2.place(relx=0.80,rely=0.5,anchor='center')
543                 self.widgets.append((rb1,rb2))
544                 self.item_widgets[item] = var
545         # détermination de la méthode à appliquer sur les boutons
546         if self.mode == 'query':
547             function = self.active
548         elif self.mode == 'display':
549             function = self.inactive
550         else:
551             return
552         # on applique la méthode sur les boutons (activation ou désactivation)  
553         for widget in self.widgets :
554             if type(widget) == types.TupleType:
555                 for widg in widget :
556                     apply(function,(widg,),{})
557             else:
558                 apply(function,(widget,),{})
559
560     def active(self,widget):
561         """
562         Active le widget passé en argument
563         """
564         widget.configure(state='normal',bg='white')
565
566     def inactive(self,widget):
567         """
568         Inactive le widget passé en argument
569         """
570         if not isinstance(widget,Radiobutton) :
571             widget.configure(state='disabled',bg='gray95')
572         else :
573             widget.configure(state='disabled')
574
575 # --------------------------------------------------------------------------------
576 #       Validateurs des noms de répertoire, de fichiers et de catalogues
577 # -------------------------------------------------------------------------------
578
579     def repvalidator(self,text):
580         """
581         Teste si text peut faire référence à un répertoire ou non
582         Retourne 1 si valide, 0 sinon
583         """
584         return os.path.isdir(text),'Répertoire introuvable : %s' %text
585
586     def filevalidator(self,text):
587         """
588         Teste si text peut faire référence à un fichier ou non
589         Retourne 1 si valide, 0 sinon
590         """
591         return os.path.isfile(text),'Fichier introuvable : %s' %text
592
593     def catavalidator(self,text):
594         """
595         Teste si  text est un chemin d'accès valide à un catalogue
596         Retourne 1 si valide, 0 sinon
597         """
598         return os.path.isfile(text),"Catalogue introuvable : %s" %text
599
600 # --------------------------------------------------------------------------------
601 #       Méthodes callbacks des boutons et de fin
602 # --------------------------------------------------------------------------------
603         
604     def execute(self,txt):
605         """
606         Cette commande est activée à chaque clic sur un bouton.
607         Redirige l'action sur la bonne méthode en fonction du bouton activé
608         """
609         if txt == 'Valider':
610             self.fini()
611         elif txt in ('OK','Annuler'):
612             self.quit()
613         elif txt == 'Modifier':
614             self.resultat = apply(self.command[1],(),{})
615             self.fenetre.destroy()
616         else :
617             print "Nom de bouton inconnu"
618             self.quit()
619
620     def fini(self):
621         """
622         Commande qui termine le panneau et sauvegarde les nouvelles options
623         dans l'objet resultat (dictionnaire)
624         """
625         dico={}
626         for item,widget in self.item_widgets.items():
627             nom_var = item[2]
628             type_var = item[1]
629             valeur = widget.get()
630             if self.d_validateurs.has_key(type_var):
631                 test = self.d_validateurs[type_var](valeur)
632                 if not test :
633                     # une entrée n'est pas valide --> on la met en surbrillance et on quitte la méthode
634                     # sans tuer la fenêtre bien sûr
635                     widget.selection_range(0,END)
636                     return
637             dico[nom_var] = valeur
638         self.fenetre.destroy()    
639         self.resultat=dico
640         
641     def quit(self):
642         self.fenetre.destroy()
643         self.resultat=None
644         
645 class ListeChoix :
646     """ Cette classe est utilisée pour afficher une liste de choix passée en paramètre
647         en passant les commandes à lancer suivant différents bindings """
648     def __init__(self,parent,page,liste,liste_commandes=[],liste_marques =[],active ='oui',filtre='non',titre=''):
649         self.parent = parent
650         self.page = page
651         self.liste = liste
652         self.dico_labels={}
653         self.selection = None
654         self.liste_commandes = liste_commandes
655         self.liste_marques = liste_marques
656         self.arg_selected=''
657         self.active = active
658         self.titre = titre
659         self.filtre = filtre
660         self.init()
661
662     def init(self):        
663         self.make_label_titre()
664         self.make_entry_filtre()
665         self.make_text_box()
666         try:
667             self.entry.component('entry').focus()
668         except:
669             pass
670
671     def make_label_titre(self):
672         """ Crée le label correspondant au titre """
673         if self.titre == '' : return
674         fonte_titre = fontes.standard_gras_souligne
675         self.label = Label(self.page,
676                            text = self.titre,
677                            font = fonte_titre)
678         self.label.pack(side='top',pady=2)
679         
680     def make_entry_filtre(self):
681         """ Crée l'entry permettant à l'utilisateur d'entrer un filtre de sélection dans la liste """
682         if self.filtre != 'oui' : return
683         self.entry = Pmw.EntryField(self.page,labelpos='w',
684                                     label_text="Filtre :",
685                                     command=self.entry_changed)
686         self.entry.pack(side='top',pady=2)
687         
688     def make_text_box(self):
689         """ Crée la fenêtre texte dans laquelle sera affichée la liste """
690         self.MCbox = Text (self.page,relief='sunken',bg='gray95',bd=2)
691         self.MCscroll = Scrollbar (self.page,command = self.MCbox.yview)
692         self.MCscroll.pack(side='right',fill ='y',pady=2)
693         self.MCbox.pack(fill='y',expand=1,padx=2,pady=2)
694         self.MCbox.configure(yscrollcommand=self.MCscroll.set)
695
696     def affiche_liste(self):
697         """ Affiche la liste dans la fenêtre"""
698         liste_labels=[]
699         self.MCbox.config(state=NORMAL)
700         self.MCbox.delete(1.0,END)
701         for objet in self.liste :
702           if type(objet) == types.InstanceType:
703               try:
704                   mot = objet.nom
705               except:
706                   mot = str(objet)
707           elif type(objet) in (types.StringType,types.IntType):
708               mot = objet
709           elif type(objet) == types.FloatType :
710               #mot = repr_float(objet)
711               mot = str(objet)
712           elif type(objet) == types.TupleType :
713               mot="("
714               premier=1
715               for val in objet:
716                   if (not premier):
717                      mot=mot+"," 
718                   else:
719                      premier=0
720                   mot=mot+str(val)
721               mot=mot+")"
722           else:
723               mot=`objet`
724           label = Label(self.MCbox,
725                         text = mot,
726                         fg = 'black',bg = 'gray95',justify = 'left')
727           self.dico_labels[mot]=label
728           liste_labels.append(label)
729           self.MCbox.window_create(END,
730                                    window=label,
731                                    stretch = 1)
732           self.MCbox.insert(END,'\n')
733           if self.active == 'oui':
734               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))
735               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))
736               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))
737
738         for marque in self.liste_marques:
739            try:
740               self.markitem(liste_labels[marque])
741            except:
742               pass
743
744         self.MCbox.config(state=DISABLED)
745         self.selection = None
746
747     def chooseitem(self,mot,label,commande):
748         """ Active la méthode de choix passée en argument"""
749         try:
750            commande(mot)
751         except AsException,e:
752            raison=str(e)
753            showerror(raison.split('\n')[0],raison)
754         
755     def selectitem(self,mot,label,commande) :
756         """ Met l'item sélectionné (représenté par son label) en surbrillance
757             et lance la commande associée au double-clic"""
758         if self.selection != None :
759             self.deselectitem(self.selection[1],self.selection[0],self.selection[2],)
760         self.highlightitem(label)
761         self.selection = (mot,label,commande)
762         self.arg_selected = mot
763         commande(mot)
764
765     def highlightitem(self,label) :
766         """ Met l'item représenté par son label en surbrillance """
767         label.configure(bg='#00008b',fg='white')
768         
769     def markitem(self,label):
770         """ Met l'item (représenté par son label) en rouge """
771         label.configure(bg='gray95',fg='red')
772         
773     def deselectitem(self,label,mot='',commande=None) :
774         """ Remet l'item (représenté par son label) en noir"""
775         label.configure(bg='gray95',fg='black')
776         self.arg_selected = ''
777         if commande != None : commande(mot)
778
779     def cherche_selected_item(self):
780         index=self.MCbox.index(self.selection[1])
781         lign,col=map(int,string.split(index,'.'))
782         return lign
783
784     def remove_selected_item(self):
785         index=self.MCbox.index(self.selection[1])
786         lign,col=map(int,string.split(index,'.'))
787         del self.liste[lign-1]
788         self.affiche_liste()
789
790     def entry_changed(self,event=None):
791         """ Cette méthode est invoquée chaque fois que l'utilisateur modifie le contenu
792         de l'entry et frappe <Return>"""
793         if self.arg_selected != '' : self.deselectitem(self.dico_labels[self.arg_selected])
794         filtre = self.entry.get()+"*"
795         FILTRE = string.upper(filtre)
796         for arg in self.liste :
797             if fnmatch.fnmatch(arg,filtre) or fnmatch.fnmatch(arg,FILTRE) :
798                 self.highlightitem(self.dico_labels[arg])
799                 index = self.MCbox.index(self.dico_labels[arg])
800                 self.MCbox.see(index)
801                 self.arg_selected = arg
802                 break
803
804     def get_liste_old(self):
805         return self.liste
806
807     # PN attention à la gestion des paramétres
808     # cela retourne H = 1 , et ni H, ni 1
809     #            print repr(val)
810     #            print val.__class__.__name__
811     def get_liste(self):
812         l=[]
813         for val in self.liste:
814 #            try:
815 #                v = eval(val)
816 #               l.append(v)
817 #            except:
818                 l.append(val)
819         return l
820     
821     def put_liste(self,liste):
822         self.liste = liste
823         self.affiche_liste()
824         
825 class Affichage :
826   """ Cette classe permet d'afficher au lancement d'EFICAS le message
827       d'attente et la barre de progression"""
828   def __init__(self,master,message,barre ='oui'):
829       from Tools.foztools.foztools import Slider
830       fonte=fontes.standard12_gras
831       self.master=master
832       self.frame = Frame(self.master)
833       self.frame.pack(expand=1,fill='both')
834       self.mess = Label(self.frame,text=message,justify='center',
835                         bd=2,relief='groove',font=fonte)
836       self.mess.pack(in_ = self.frame,side='top',expand=1,fill='both')
837       self.progress = Slider(self.frame,value=0,max=100,orientation='horizontal',
838                              fillColor='#00008b',width=200,height=30,
839                              background='white',labelColor='red')
840       if barre == 'oui':
841           self.progress.frame.pack(in_=self.frame,side='top')
842       self.master.update()
843       if barre == 'oui':
844           self.progress.frame.after(1000,self.update)
845
846   def configure(self,**options):
847       if options.has_key('message'):
848           self.mess.configure(text=options['message'])
849       if options.has_key('barre'):
850           if options['barre'] == 'oui' :
851               self.progress.frame.pack(in_=self.frame,side='top')
852           elif options['barre'] == 'non' :
853               self.progress.frame.pack_forget()
854       self.master.update_idletasks()
855       
856   def quit(self):
857       self.frame.destroy()
858       self.master.update()
859
860   def update(self,event=None):
861       """ Permet de faire avancer la barre de progression """
862       try :
863           bar=self.progress
864           bar.value = bar.value+self.increment
865           bar.update()
866           self.master.after(100,self.update)
867       except:
868           pass
869
870   def configure_barre(self,nb):
871       """ Calcule l'incrément de progression de la barre en fonction
872           du nombre d'opérations à effectuer afin que le compteur
873           soit à 100% à la fin des opérations"""
874       self.increment = 100./nb
875       self.progress.update()
876
877 class Ask_Format_Fichier :
878     """
879     Cette classe permet de créer une fenêtre Toplevel dans laquelle
880     on propose le choix du format de fichier de commandes à ouvrir
881     """
882     def __init__(self,appli):
883         self.fenetre = Toplevel()
884         self.fenetre.configure(width = 250,height=150)
885         self.fenetre.protocol("WM_DELETE_WINDOW", self.quit)
886         self.fenetre.title("Choix du format du fichier de commandes")
887         # définition des frames
888         self.frame_texte = Frame(self.fenetre)
889         self.frame_radioboutons = Frame(self.fenetre)
890         self.frame_bouton_ok = Frame(self.fenetre)
891         self.frame_texte.place(relx=0,rely=0,relwidth=1,relheight=0.3)
892         self.frame_radioboutons.place(relheight=0.5,relx=0,rely=0.3,relwidth=1.)
893         self.frame_bouton_ok.place(relheight=0.2,relx=0,rely=0.8,relwidth=1.)
894         # définition de la zone texte et du scrollbar
895         zone_texte = Label(self.frame_texte,text = "Format du fichier à ouvrir :")
896         zone_texte.pack(side='top',fill='both',expand=1,padx=5,pady=10)
897         # définition des radioboutons
898         Radiobutton(self.frame_radioboutons,text='Format Aster (Code_Aster --> v5)',
899                     variable=appli.format_fichier,value='Aster').pack(anchor='n')
900         Radiobutton(self.frame_radioboutons,text='Format Python (Code_Aster v6-->)',
901                     variable=appli.format_fichier,value='Python').pack(anchor='n')
902         # création du bouton OK
903         Button(self.frame_bouton_ok,text='OK',command=self.quit).pack(anchor='n')
904         # centrage de la fenêtre
905         centerwindow(self.fenetre)
906
907     def quit(self):
908         self.fenetre.destroy()
909
910 class BARRE_K2000(Toplevel):
911     def __init__(self,master=None,text = ""):
912         Toplevel.__init__(self,master,relief='groove')
913         self.master.iconify()
914         self.geometry("250x100+0+0")
915         self.protocol("WM_DELETE_WINDOW",self.quit)
916         # frame principale dans self (= Toplevel)
917         self.frame = Frame(self)
918         self.frame.place(relwidth=1,relheight=1)
919         # frame contenant le texte à afficher 
920         self.frame_text = Frame(self.frame)
921         self.frame_text.place(relwidth=1,relheight=0.75,rely=0)
922         # frame contenant le canvas de la barre
923         self.frame_canv = Frame(self.frame)
924         self.frame_canv.place(relwidth=1,relheight=0.25,rely=0.75)
925         # canvas dans lequel sera affichée la barre K2000
926         self.canvas = Canvas(self.frame_canv)
927         self.canvas.place(relx=0.5,rely=0.5,relheight=0.8,relwidth=0.8,anchor='center')
928         # on affiche le texte et la barre
929         self.build_text(text)
930         self.build_batons()
931         #self.overrideredirect(1)
932         # on active la barre ...
933         self.master.after(1000,self.launch)
934         # on centre la fenêtre
935         centerwindow(self)
936         self.focus()
937
938     def build_text(self,text):
939         """
940         Affichage de text dans frame_text
941         """
942         self.texte_var = StringVar()
943         self.texte_var.set(text)
944         Label(self.frame_text,textvariable=self.texte_var).place(relx=0.5,rely=0.5,anchor='center')
945         
946     def build_batons(self):
947         """
948         Construit la suite de bâtons dans le canvas
949         """
950         self.l_batons=[]
951         self.black = -1
952         self.sens = 'D'
953         self.quit = 0
954         for i in range(0,40):
955             id = self.canvas.create_rectangle(i*5,0,(i+1)*5,20,fill='gray90',outline='')
956             self.l_batons.append(id)
957
958     def launch(self):
959         """
960         Active la barre K2000 en affichant les bâtons avec des couleurs en dégradé
961         """
962         if self.quit == 1 :
963             self.destroy()
964             self.master.deiconify()
965             return
966         if self.sens == 'D':
967             self.black = self.black+1
968             l_bat = self.l_batons[0:self.black+1]
969             l_bat.reverse()
970         elif self.sens == 'G':
971             self.black = self.black-1
972             l_bat = self.l_batons[self.black:]
973         i=0
974         for bat in l_bat :
975             num_color = 5+i*10
976             if num_color < 10 : color = 'black'
977             elif num_color > 90 : color = 'white'
978             else: color = 'gray'+`num_color`
979             self.canvas.itemconfigure(bat,fill=color)
980             i=i+1
981         if self.black == len(self.l_batons) :
982             self.sens = 'G'
983         if self.black == 0 and self.sens == 'G':self.sens = 'D'
984         self.after(80,self.launch)
985
986     def update_text(self,new_text):
987         """
988         Remplace le texte affiché par new_text
989         """
990         self.texte_var.set(new_text)
991         
992     def quit(self):
993         self.quit = 1        
994
995 class ListeChoixParGroupes(ListeChoix) :
996     """ 
997         Cette classe est utilisée pour afficher une liste de commandes classées par
998         groupes. L'utilisateur peut réaliser des actions de selection
999         qui déclenchent des actions spécifiées par les bindings contenus dans liste_commandes
1000     """
1001     def __init__(self,parent,page,liste_groupes,dict_groupes,liste_commandes=[],liste_marques =[],
1002                       active ='oui',filtre='non',titre=''):
1003         self.parent = parent
1004         self.page = page
1005         self.liste_groupes = liste_groupes
1006         self.dict_groupes = dict_groupes
1007         self.dico_labels={}
1008         self.selection = None
1009         self.liste_commandes = liste_commandes
1010         self.liste_marques = liste_marques
1011         self.arg_selected=''
1012         self.active = active
1013         self.titre = titre
1014         self.filtre = filtre
1015         self.init()
1016
1017     def affiche_liste(self):
1018         """ Affiche la liste dans la fenêtre"""
1019         liste_labels=[]
1020         self.MCbox.config(state=NORMAL)
1021         self.MCbox.delete(1.0,END)
1022         for grp in self.liste_groupes:
1023            # On itère sur les groupes
1024            if grp == "CACHE":continue
1025            liste_commandes=self.dict_groupes[grp]
1026            text="GROUPE<<<<<<<< "+grp+" "
1027            text=text+">"*max(0,30-len(text))
1028            label = Label(self.MCbox,
1029                         text = text,
1030                         fg = 'black',bg = 'gray95',justify = 'left')
1031            # On stocke la relation entre le nom de la commande et le label
1032            self.dico_labels[grp]=label
1033            liste_labels.append(label)
1034            self.MCbox.window_create(END,
1035                                    window=label,
1036                                    stretch = 1)
1037            self.MCbox.insert(END,'\n')
1038            for cmd in liste_commandes:
1039               label = Label(self.MCbox,
1040                         text = cmd,
1041                         fg = 'black',bg = 'gray95',justify = 'left')
1042               # On stocke la relation entre le nom de la commande et le label
1043               self.dico_labels[cmd]=label
1044               self.MCbox.window_create(END,
1045                                    window=label,
1046                                    stretch = 1)
1047               self.MCbox.insert(END,'\n')
1048               if self.active == 'oui':
1049                   label.bind(self.liste_commandes[0][0],
1050                          lambda e,s=self,c=self.liste_commandes[0][1],x=cmd,l=label : s.selectitem(x,l,c))
1051                   label.bind(self.liste_commandes[1][0],
1052                          lambda e,s=self,c=self.liste_commandes[1][1],x=cmd,l=label : s.deselectitem(l,x,c))
1053                   label.bind(self.liste_commandes[2][0],
1054                          lambda e,s=self,c=self.liste_commandes[2][1],x=cmd,l=label : s.chooseitem(x,l,c))
1055
1056         for marque in self.liste_marques:
1057            try:
1058               self.markitem(liste_labels[marque])
1059            except:
1060               pass
1061
1062         self.MCbox.config(state=DISABLED)
1063         self.selection = None
1064
1065     def entry_changed(self,event=None):
1066         """ 
1067             Cette méthode est invoquée chaque fois que l'utilisateur modifie le contenu
1068             de l'entry et frappe <Return>
1069         """
1070         if self.arg_selected != '' : self.deselectitem(self.dico_labels[self.arg_selected])
1071         filtre = self.entry.get()+"*"
1072         FILTRE = string.upper(filtre)
1073         #
1074         # On cherche d'abord dans les noms de groupe
1075         # puis dans les noms de commande groupe par groupe
1076         #
1077         for grp in self.liste_groupes:
1078             if fnmatch.fnmatch(grp,filtre) or fnmatch.fnmatch(grp,FILTRE) :
1079                 index = self.MCbox.index(self.dico_labels[grp])
1080                 self.MCbox.see(index)
1081                 # On ne selectionne pas le groupe
1082                 #self.arg_selected = grp
1083                 # On a trouve un groupe on arrete la recherche
1084                 return
1085
1086         for grp in self.liste_groupes:
1087            for cmd in self.dict_groupes[grp] :
1088               if fnmatch.fnmatch(cmd,filtre) or fnmatch.fnmatch(cmd,FILTRE) :
1089                  self.highlightitem(self.dico_labels[cmd])
1090                  index = self.MCbox.index(self.dico_labels[cmd])
1091                  self.MCbox.see(index)
1092                  self.arg_selected = cmd
1093                  # On a trouve une commande  on arrete la recherche
1094                  return
1095