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