Salome HOME
CCAR: introduction de methodes complementaires pour les validateurs
[tools/eficas.git] / Editeur / composimp.py
1 #            CONFIGURATION MANAGEMENT OF EDF VERSION
2 # ======================================================================
3 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
4 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
5 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
6 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
7 # (AT YOUR OPTION) ANY LATER VERSION.
8 #
9 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
10 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
11 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
12 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
13 #
14 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
15 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
16 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
17 #
18 #
19 # ======================================================================
20 # Modules Python
21 import string,types,os
22 from Tkinter import *
23 import Pmw
24 from tkFileDialog import *
25 from tkMessageBox import showinfo
26 from copy import copy,deepcopy
27 import traceback
28
29 # Modules Eficas
30 import Objecttreeitem
31 import prefs
32 import panels
33 import images
34 from widgets import ListeChoix
35 from widgets import FenetreDeSelection
36
37 from Noyau.N_CR import justify_text
38 from utils import substract_list
39
40
41 class newSIMPPanel(panels.OngletPanel):
42   """
43   Classe virtuelle servant de classe mère à toutes les classes Panel
44   servant à afficher et récupérer la valeur d'un mot-clé simple.
45   Le panel est différent suivant le type de la valeur attendu
46   """
47   def init(self):
48       """
49       Méthode appelée par le constructeur de OngletPanel :
50       construit le notebook à 2 onglets utilisé par tous les panels de
51       tous les mots-clés simples
52       """
53       nb = Pmw.NoteBook(self,raisecommand=self.raisecmd)
54       nb.pack(fill = 'both', expand = 1)
55       self.nb=nb
56       nb.add('Valeur', tab_text='Saisir valeur')
57       #nb.add('Commentaire',tab_text='Insérer commentaire')
58       self.makeValeurPage(nb.page('Valeur'))
59       #self.makeCommentairePage(nb.page("Commentaire"))
60       nb.setnaturalsize()
61       
62 # ----------------------------------------------------------------------------------------
63 #   Méthodes utilisées pour l'affectation de la valeur donnée par l'utilisateur
64 #    au mot-clé courant
65 # ----------------------------------------------------------------------------------------
66
67   def record_valeur(self,name=None,mess='Valeur du mot-clé enregistrée'):
68       """
69           Enregistre  val comme valeur de self.node.item.object SANS 
70           faire de test de validité
71       """
72       if self.parent.modified == 'n' : self.parent.init_modif()
73       if name != None:
74           valeur =name
75       else :
76           #XXX Pourquoi proceder ainsi ? Il n'est pas possible de mettre
77           # None comme valeur du mot cle. 
78           # Probablement que ce debranchement permet de mettre record_valeur
79           # en call back, il faut donc aller chercher la valeur dans l'entry
80           valeur= self.entry.get()
81           self.entry.delete(0,END)
82           #XXX Pour permettre la mise a None du mot cle, on remet None si valeur == ''
83           if valeur == '':valeur=None
84       self.node.item.set_valeur(valeur,evaluation='non')
85       self.parent.appli.affiche_infos(mess)
86       if self.node.item.get_position()=='global':
87           self.node.etape.verif_all()
88       elif self.node.item.get_position()=='global_jdc':
89           self.node.racine.verif_all()
90       else :
91           self.node.parent.verif()
92       self.node.update()
93       if self.node.item.isvalid():
94           self.node.parent.select()
95
96 # ----------------------------------------------------------------------------------------
97 #   Méthodes utilisées pour la manipulation des items dans les listes de choix
98 # ----------------------------------------------------------------------------------------
99   def selectValeur(self,name):
100       self.selected_valeur = name
101
102   def deselectValeur(self,name):
103       self.selectValeur = None
104
105   def sup_valeur(self,name=None):
106       """
107       Supprime la valeur selectionnée de la liste des valeurs et la rajoute
108       à la liste des choix possibles
109       """
110       liste_valeurs = self.Liste_valeurs.get_liste()
111       liste_valeurs.remove(self.selected_valeur)
112       liste_choix = self.node.item.get_definition().into
113       liste_choix = substract_list(liste_choix,liste_valeurs)
114       self.Liste_valeurs.put_liste(liste_valeurs)
115       self.Liste_choix.put_liste(liste_choix)
116       self.selected_valeur = None
117
118   def add_choix(self,name=None):
119       """
120       Ajoute le choix selectionné à la liste des valeurs et le retire
121       de la liste des choix possibles
122       """
123       min,max = self.node.item.GetMinMax()
124       liste_valeurs = self.Liste_valeurs.get_liste()
125       if len(liste_valeurs) >= max :
126           self.parent.appli.affiche_infos("La liste ne peut pas avoir plus de %d éléments" %max)
127           return
128       liste_valeurs.append(self.selected_choix)
129       liste_choix = self.Liste_choix.get_liste()
130       #  liste_choix.remove(self.selected_choix)
131       self.Liste_valeurs.put_liste(liste_valeurs)
132       self.Liste_choix.put_liste(liste_choix)
133       self.selected_choix = None
134
135   def selectChoix(self,name):
136       self.selected_choix = name
137
138   def deselectChoix(self,name):
139       self.selectChoix = None
140       
141   def raisecmd(self,page):
142       try:
143          self.entry.focus()
144       except:
145          pass
146
147 class SHELLPanel(newSIMPPanel):
148   """
149   Classe Panel utilisé pour les mots-clés simples qui attendent un shell pour valeur
150   """
151
152   def makeValeurPage(self,page):
153       """ 
154       Affiche la page concernant l'objet pointé par self qui attend un shell
155       """
156       objet_mc = self.node.item.get_definition()
157       aide = self.gen_aide()
158       aide = justify_text(texte=aide)
159       self.frame = Frame(page)
160       self.frame.place(relx=0,rely=0,relwidth=1,relheight=1)
161       label_aide = Label(self.frame,text = aide)
162       label_aide.place(relx=0.5,rely=0.1,anchor='center')
163       self.text = Text(self.frame,bg='gray95')
164       self.text.place(relx=0.2,rely=0.2,relwidth=0.6,relheight=0.6)
165       but_val = Button(self.frame,text='Valider',command = self.valide_shell)
166       but_ann = Button(self.frame,text='Annuler',command = self.annule_shell)
167       but_val.place(relx=0.35,rely=0.9,anchor='center')
168       but_ann.place(relx=0.65,rely=0.9,anchor='center')
169       self.display_valeur()
170
171   def gen_aide(self):
172       """
173       Retourne une chaîne de caractères d'aide sur la valeur qu'attend l'objet
174       pointé par self
175       """
176       return "Un shell est attendu"
177     
178   def valide_shell(self,event=None):
179       """
180       Récupère la valeur saisie par l'utilisateur dans self.text
181       et la stocke dans l'objet MCSIMP courant
182       """
183       texte = self.text.get(1.0,END)
184       self.record_valeur(texte)
185
186   def annule_shell(self,event=None):
187       """
188       Annule toute saisie dans self.text
189       """
190       self.text.delete(0,END)
191
192   def display_valeur(self,val=None):
193       """
194       Affiche la valeur de l'objet pointé par self
195       """
196       if val != None :
197           valeur = val
198       else:
199           valeur = self.node.item.get_valeur()
200       if valeur == None : return
201       self.text.insert(END,valeur)
202
203 class PLUSIEURS_Panel(newSIMPPanel):
204   """
205   Classe virtuelle servant de classe mère à toutes celles définissant
206   un panneau pour un mot-clé simple qui attend une liste de valeurs
207   """
208   def accepte_modifs_valeur(self,min,max):
209       """
210       Méthode qui récupère la liste des valeurs donnée par l'utilisateur
211       et l'affecte au mot-clé courant.
212       """
213       l1_valeurs = self.Liste_valeurs.get_liste()
214       # PN : remplacement des paramétres par leur nom (cf get_liste)
215       #      
216       l_valeurs=[]
217       for  val in l1_valeurs :
218            if val.__class__.__name__ in ('PARAMETRE','PARAMETRE_EVAL'):
219                 v=val.nom
220            else:
221                 v=val
222            l_valeurs.append(v)
223     
224       print "l_valeurs = ", l_valeurs
225       longueur = len(l_valeurs)
226       if longueur < min or longueur > max :
227           self.parent.appli.affiche_infos("Valeur refusée : nombre d'éléments incorrect dans la liste")
228           return
229       if longueur > 1:
230          valeur = tuple(l_valeurs)
231       elif longueur == 1:
232          valeur = l_valeurs[0]
233       else:
234          valeur = None
235       self.parent.appli.affiche_infos("Valeur acceptée")
236       print "valeur = " ,valeur
237       self.record_valeur(valeur)
238       if self.node.item.isvalid():
239           self.node.parent.select()
240       # fermeture de la fenêtre de sélection
241       if self.ajout_valeurs:
242           self.ajout_valeurs.quit()
243           
244   def annule_modifs_valeur(self):
245       """
246       RAZ de la liste des valeurs (annule toutes les valeurs saisies par l'utilisateur)
247       """
248       self.node.select()
249       # fermeture de la fenêtre de sélection
250       if self.ajout_valeurs:
251           self.ajout_valeurs.quit()
252           
253   def traite_reel(self,valeur):
254       """
255       Cette fonction a pour but de rajouter le '.' en fin de chaîne pour un réel
256       ou de détecter si on fait référence à un concept produit par DEFI_VALEUR
257       ou un EVAL ...
258       """
259       valeur = string.strip(valeur)
260       liste_reels = self.node.item.get_sd_avant_du_bon_type()
261       if valeur in liste_reels:
262           return valeur
263       if len(valeur) >= 3 :
264           if valeur[0:4] == 'EVAL' :
265               # on a trouvé un EVAL --> on retourne directement la valeur
266               return valeur
267       if string.find(valeur,'.') == -1 :
268           # aucun '.' n'a été trouvé dans valeur --> on en rajoute un à la fin
269           return valeur+'.'
270       else:
271           return valeur
272         
273   def add_valeur_sans_into(self,name=None):
274       """
275       Lit ce que l'utilisateur a saisi dans self.entry et cherche à
276       l'évaluer :
277         - si la valeur est acceptable, elle est ajoutée dans la liste des valeurs
278         - sinon elle est refusée
279       """
280       min,max = self.node.item.GetMinMax()
281       if name != None :
282           valeur = name
283       else:
284           valeur = self.get_valeur()
285       if self.node.item.wait_reel():
286           valeur = self.traite_reel(valeur)
287       if self.node.item.wait_geom():
288           val,test1 = valeur,1
289       else:
290           val,test1 = self.node.item.object.eval_valeur(valeur)
291       if test1 :
292           test2 = self.node.item.object.verif_type(val)
293           if test2 :
294               liste_valeurs = self.Liste_valeurs.get_liste()
295               if len(liste_valeurs) >= max :
296                   self.parent.appli.affiche_infos("La liste a déjà atteint le nombre maximum d'éléments, ajout refusé")
297                   self.erase_valeur()
298                   return
299               liste_valeurs.append(val)
300               self.Liste_valeurs.put_liste(liste_valeurs)
301               self.erase_valeur()
302               self.parent.appli.affiche_infos("Nouvelle valeur acceptée")
303           else:
304               self.parent.appli.affiche_infos("Valeur incorrecte : ajout à la liste refusé")
305       else:
306           print "impossible d'évaluer %s" %val
307           self.parent.appli.affiche_infos("Valeur incorrecte : ajout à la liste refusé")
308       #if self.node.item.isvalid():
309       #    self.node.parent.select()
310
311   def sup_valeur_sans_into(self,name=None):
312       """
313       Méthode qui sert à retirer de la liste des valeurs la valeur sélectionnée
314       """
315       liste_valeurs = self.Liste_valeurs.get_liste()
316       try:
317           liste_valeurs.remove(self.selected_valeur)
318       except:
319           # la valeur sélectionnée n'est pas dans la liste
320           return
321       self.Liste_valeurs.put_liste(liste_valeurs)
322       #self.display_valeur('')
323       self.display_valeur(self.selected_valeur)
324       self.selected_valeur = None      
325
326   def display_valeur(self,val=None):
327       """
328       Affiche la valeur passée en argument dans l'entry de saisie.
329       Par défaut affiche la valeur du mot-clé simple
330       """
331       if not val :
332           valeur = self.node.item.getval()
333       else:
334           valeur = val
335       self.entry.delete(0,END)
336       if not valeur : return
337       self.entry.insert(0,str(valeur))
338       
339             
340 class PLUSIEURS_INTO_Panel(PLUSIEURS_Panel):
341   """
342   Classe servant à définir le panneau permettant d'afficher et de saisir une
343   liste de valeurs à choisir parmi une liste discrètes de valeurs possibles
344   """
345   def makeValeurPage(self,page):
346       """
347       Génère la page de saisie de plusieurs valeurs parmi un ensemble discret
348       de possibles
349       """
350       self.ajout_valeurs = None
351       # On récupère la bulle d'aide du panneau, l'objet, min et max (cardinalité de la liste),
352       # la liste des choix et la liste des valeurs
353       aide = self.get_aide()
354       aide = justify_text(texte=aide)
355       bulle_aide=self.get_bulle_aide()
356       objet_mc = self.node.item.get_definition()
357       min,max = self.node.item.GetMinMax()
358       l_choix=list(objet_mc.into)
359       l_choix.sort()
360       l_valeurs = self.node.item.GetListeValeurs()
361       # remplissage du panneau
362       self.frame_valeurs = Frame(page)
363       self.frame_valeurs.place(relx=0.05,rely=0.05,relwidth=0.35,relheight=0.7)
364       self.frame_boutons_fleches = Frame(page)
365       self.frame_boutons_fleches.place(relx=0.4,rely=0.,relwidth=0.2,relheight=0.7)
366       self.frame_choix = Frame(page)
367       self.frame_choix.place(relx=0.6,rely=0.05,relwidth=0.35,relheight=0.7)
368       self.frame_boutons = Frame(page)
369       self.frame_boutons.place(relx=0.35,rely=0.87,relwidth=0.3,relheight=0.1)
370       self.frame_aide = Frame(page)
371       self.frame_aide.place(relx=0.1,rely=0.75,relwidth=0.9,relheight=0.1)
372       liste_commandes_valeurs = (("<Button-1>",self.selectValeur),
373                                  ("<Button-3>",self.deselectValeur),
374                                  ("<Double-Button-1>",self.sup_valeur))
375       liste_commandes_choix = (("<Button-1>",self.selectChoix),
376                                ("<Button-3>",self.deselectChoix),
377                                ("<Double-Button-1>",self.add_choix))
378       self.Liste_valeurs = ListeChoix(self,self.frame_valeurs,l_valeurs,liste_commandes = liste_commandes_valeurs,
379                                       titre="Valeur(s) actuelle(s)")
380       self.Liste_choix = ListeChoix(self,self.frame_choix,l_choix,liste_commandes = liste_commandes_choix,
381                                     titre= "Valeurs possibles")
382       bouton_add = Button(self.frame_boutons_fleches,
383                           #text="<--",
384                           image = images.get_image('arrow_left'),
385                           command = self.add_choix)
386       bouton_sup = Button(self.frame_boutons_fleches,
387                           #text="-->",
388                           image = images.get_image('arrow_right'),
389                           command = self.sup_valeur)
390       bouton_accepter = Button(self.frame_boutons,
391                                text='Valider',
392                                command = lambda s=self,m=min,M=max : s.accepte_modifs_valeur(m,M))
393       bouton_annuler = Button(self.frame_boutons,
394                               text = 'Annuler',
395                               command = self.annule_modifs_valeur)
396       bouton_add.place(relx=0.3,rely=0.35)
397       bouton_sup.place(relx=0.3,rely=0.65)
398       for but in (bouton_accepter,bouton_annuler):
399           but.pack(side='left',padx=5)
400       self.Liste_valeurs.affiche_liste()
401       self.Liste_choix.affiche_liste()
402       for fram in (self.frame_valeurs,self.frame_boutons_fleches,self.frame_choix,self.frame_boutons):
403           fram.bind("<Button-3>",lambda e,s=self,a=bulle_aide : s.parent.appli.affiche_aide(e,a))
404           fram.bind("<ButtonRelease-3>",self.parent.appli.efface_aide)
405       self.frame_aide.update()
406       self.aide = Label(self.frame_aide,
407                         text = aide,
408                         justify='center',
409                         anchor='center',
410                         wraplength=int(self.frame_aide.winfo_width()*0.8))
411       self.aide.place(relx=0.5,rely=0.5,anchor='center',relwidth=1)
412
413   def get_aide(self):
414       """
415       Retourne la phrase d'aide indiquant de quel type de base doivent être les valeurs
416       que saisit l'utilisateur
417       """
418       mc = self.node.item.get_definition()
419       d_aides = { 'TXM' : 'chaînes de caractères',
420                   'R'   : 'réels',
421                   'I'   : 'entiers',
422                   'C'   : 'complexes'}
423       type = mc.type[0]
424       if not d_aides.has_key(type) : 
425          if mc.min == mc.max:
426             return str(mc.min)+" valeur(s) est(sont) attendue(s)"
427          else :
428             return "entrez entre "+str(mc.min)+" et "+str(mc.max)+" valeurs"
429       if mc.min == mc.max:
430           return "Une liste de "+str(mc.min)+" "+d_aides[type]+" est attendue"
431       else :
432           return "Entre "+str(mc.min)+" et "+str(mc.max)+" valeurs de type  "+d_aides[type]+" sont attendues"
433       return "  "
434
435   def get_bulle_aide(self):
436       """
437       Retourne la bulle d'aide du panneau (affichée par clic droit)
438       """
439       return """Un clic sur une valeur des deux listes la sélectionne.
440       - Un clic sur la flèche gauche stocke la valeur possible sélectionnée
441       dans la liste des valeurs que vous voulez affecter au mot-clé simple
442       - Un clic sur la flèche droite déstocke la valeur du mot-clé simple
443       sélectionnée (elle apparaît alors à nouveau comme choix possible
444       dans la liste des choix à droite)
445       - Cliquez sur 'Valider' pour affecter la liste des valeurs sélectionnées
446       au mot-clé simple courant
447       - Cliquez sur 'Annuler' pour restaurer la valeur du mot-clé simple
448       avant toute modification depuis le dernier 'Valider'"""
449
450 class PLUSIEURS_BASE_Panel(PLUSIEURS_Panel):
451   """
452   Classe définissant le panel associé aux mots-clés qui demandent
453   à l'utilisateur de donner une liste de valeurs qui ne sont pas
454   à choisir dans une liste discrètes et qui sont de type de base :
455   entier, réel, string,...
456   """
457   def makeValeurPage(self,page):
458       """
459       Crée la page de saisie d'une liste de valeurs à priori quelconques,
460       cad qui ne sont  pas à choisir dans une liste prédéfinie
461       """
462       # On récupère la bulle d'aide du panneau, l'objet, l'aide,min et max (cardinalité de la liste),
463       # et la liste des valeurs déjà affectées à l'objet courant
464       bulle_aide=self.get_bulle_aide()
465       objet_mc = self.node.item.get_definition()
466       aide = self.get_aide()
467       aide = justify_text(texte=aide)
468       min,max = self.node.item.GetMinMax()
469       l_valeurs = self.node.item.GetListeValeurs()
470       # création des frames globales
471       self.frame1 = Frame(page,relief='groove',bd=2)
472       self.frame2 = Frame(page)
473       self.frame1.place(relx=0.,rely=0.,relwidth=1.,relheight=0.85)
474       self.frame2.place(relx=0.,rely=0.85,relwidth=1,relheight=0.15)
475       self.frame_right = Frame(self.frame1)
476       self.frame_right.place(relx=0.35,rely=0.,relwidth=0.65,relheight=1.)
477       # création des frames internes
478       self.frame_valeurs = Frame(self.frame1)
479       self.frame_valeurs.place(relx=0.02,rely=0.05,relwidth=0.35,relheight=0.95)
480       self.frame_boutons_fleches = Frame(self.frame_right)
481       self.frame_boutons_fleches.place(relx=0.,rely=0.2,relwidth=0.2,relheight=0.5)
482       self.frame_choix = Frame(self.frame_right)
483       self.frame_choix.place(relx=0.2,rely=0.2,relwidth=0.7,relheight=0.5)
484       self.frame_aide = Frame(self.frame_right)
485       self.frame_aide.place(relx=0.1,rely=0.7,relwidth=0.8,relheight=0.3)
486       self.frame_boutons = Frame(self.frame2)
487       self.frame_boutons.place(relx=0.35,rely=0.,relwidth=0.3,relheight=1.)
488       for fram in (self.frame1,self.frame2,self.frame_right,self.frame_valeurs,
489                  self.frame_boutons_fleches,self.frame_choix,self.frame_aide,self.frame_boutons):
490           fram.bind("<Button-3>",lambda e,s=self,a=bulle_aide : s.parent.appli.affiche_aide(e,a))
491           fram.bind("<ButtonRelease-3>",self.parent.appli.efface_aide)
492       # création des objets dans les frames
493       liste_commandes_valeurs = (("<Button-1>",self.selectValeur),
494                                  ("<Button-3>",self.deselectValeur),
495                                  ("<Double-Button-1>",self.sup_valeur_sans_into))
496       self.Liste_valeurs = ListeChoix(self,self.frame_valeurs,l_valeurs,liste_commandes = liste_commandes_valeurs,
497                                       titre="Valeur(s) actuelle(s)")
498       # Création de l'entry ou de la liste des SD
499       self.label = Label(self.frame_choix,text="Valeur :")
500       self.make_entry(frame = self.frame_choix,command = self.add_valeur_sans_into)
501       self.label.place(relx=0.05,rely=0.5)
502       # Création d'un bouton "Importer ..." sur le panel.
503       bouton_valeurs_fichier = Button(self.frame_choix,
504                                       text="Importer ...",
505                                       command=self.select_in_file)
506       bouton_valeurs_fichier.place(relx=0.28,rely=0.7,relwidth=0.6)
507       self.ajout_valeurs = None
508       # boutons Ajouter et Supprimer
509       bouton_add = Button(self.frame_boutons_fleches,
510                           image = images.get_image('arrow_left'),
511                           command = self.add_valeur_sans_into)
512       bouton_sup = Button(self.frame_boutons_fleches,
513                           image = images.get_image('arrow_right'),
514                           command = self.sup_valeur_sans_into)
515       bouton_add.place(relx=0.3,rely=0.35)
516       bouton_sup.place(relx=0.3,rely=0.65)
517       # affichage de l'aide
518       self.frame_aide.update()
519       self.aide = Label(self.frame_aide,
520                         text = aide,
521                         justify='center',
522                         anchor='center',
523                         wraplength=int(self.frame_aide.winfo_width()*0.8))
524       self.aide.place(relx=0.5,rely=0.5,anchor='center',relwidth=1)
525       self.Liste_valeurs.affiche_liste()
526       # boutons Accepter et Annuler
527       bouton_accepter = Button(self.frame_boutons,
528                                text='Valider',
529                                command = lambda s=self,m=min,M=max : s.accepte_modifs_valeur(m,M))
530       bouton_annuler = Button(self.frame_boutons,
531                               text = 'Annuler',
532                               command = self.annule_modifs_valeur)
533       for but in (bouton_accepter,bouton_annuler):
534           but.pack(side='left',padx=5)
535
536   def select_in_file(self):
537       """ Permet d'ouvrir un fichier choisi par l'utilisateur. """
538       nom_fichier = askopenfilename(title="Choix fichier :")
539       if nom_fichier == "":
540           return
541       try:
542           f = open(nom_fichier, "rb")
543           selection_texte = f.read()
544           f.close()
545           self.ajout_valeurs = FenetreDeSelection(self, 
546                                                   self.node.item,
547                                                   self.parent.appli,
548                                                   titre="Sélection de valeurs",
549                                                   texte=selection_texte)
550       except:
551           traceback.print_exc()
552           showinfo("Erreur de fichier","impossible d'ouvir le fichier "+nom_fichier)
553           
554   def get_bulle_aide(self):
555       """
556       Retourne l'aide associée au panneau courant
557       """
558       return """Taper dans la boîte de saisie de droite la valeur que
559       vous voulez affecter au mot-clé simple.
560       - Cliquez sur la flèche gauche ou pressez <Return> pour la faire glisser
561       dans la liste des valeurs que vous voulez affecter au mot-clé simple
562       - Un clic sur une valeur de la liste la sélectionne
563       - Un clic sur la flèche droite ou un double-clic retire la valeur
564       sélectionnée de la liste
565       - Cliquez sur 'Valider' pour que la nouvelle valeur désirée soit affectée
566       au mot-clé simple
567       - Cliquez sur 'Annuler' pour annuler toutes les modifications faites
568       depuis le dernier clic sur 'Valider'"""
569
570   def get_aide(self):
571       """
572       Retourne la phrase d'aide indiquant de quel type de base doivent être les valeurs
573       que saisit l'utilisateur
574       """
575       mc = self.node.item.get_definition()
576       d_aides = { 'TXM' : 'chaînes de caractères',
577                   'R'   : 'réels',
578                   'I'   : 'entiers',
579                   'C'   : 'complexes'}
580       type = mc.type[0]
581       if not d_aides.has_key(type) : return 'Type de base inconnu'
582       if mc.min == mc.max:
583           return "Une liste de "+d_aides[type]+" chaînes de caractères est attendue"
584       else :
585           return "Une liste de "+d_aides[type]+" est attendue (min="+`mc.min`+",max="+`mc.max`+')'
586
587   def make_entry(self,frame,command):
588       """
589       Crée l'entry de saisie de la valeur souhaitée : distingue le
590       cas d'un complexe attendu, d'une autre valeur quelconque
591       """
592       if self.node.item.wait_complex():
593           self.typ_cplx=StringVar()
594           self.typ_cplx.set('RI')
595           rb1 = Radiobutton(frame, text='RI',variable=self.typ_cplx,value='RI')
596           rb2 = Radiobutton(frame, text='MP',variable=self.typ_cplx,value='MP')
597           self.entry1 = Pmw.EntryField(frame,validate='real')
598           self.entry2 = Pmw.EntryField(frame,validate='real')
599           rb1.place(relx=0.05,rely = 0.4)
600           rb2.place(relx=0.05,rely = 0.6)
601           self.entry1.component('entry').bind("<Return>",lambda e,s=self:s.entry2.component('entry').focus)
602           self.entry2.component('entry').bind("<Return>",lambda e,c=command:c())
603           self.entry1.place(relx=0.27,rely = 0.5,relwidth=0.35)
604           self.entry2.place(relx=0.65,rely = 0.5,relwidth=0.35)
605           self.entry1.focus()
606       else:
607           self.entry = Entry(frame,relief='sunken')
608           self.entry.place(relx=0.28,rely=0.5,relwidth=0.6)
609           self.entry.bind("<Return>",lambda e,c=command:c())
610           self.entry.focus()
611
612   def get_valeur(self):
613       """
614       Retourne la valeur saisie par l'utilisateur dans self.entry
615       """
616       return self.entry.get()
617
618   def erase_valeur(self):
619       """
620       Efface la valeur donnée par l'utilisateur dans l'entry
621       """
622       self.entry.delete(0,END)
623         
624 class PLUSIEURS_ASSD_Panel(PLUSIEURS_Panel):
625   """
626   Classe définissant le panel associé aux mots-clés qui demandent
627   à l'utilisateur de donner une liste de valeurs qui ne sont pas
628   à choisir dans une liste discrètes et qui sont de type dérivé d'ASSD
629   """
630   def makeValeurPage(self,page):
631       """
632       Génère la page de saisie de plusieurs noms de SD parmi un ensemble discret
633       de SD possibles, cad d'un type cohérent avec les types attendus par le mot-clé simple
634       """
635       # On récupère la bulle d'aide du panneau, l'objet, l'aide, min et max (cardinalité de la liste),
636       # la liste des valeurs déjà affectées à l'objet courant et la liste des SD du bon type
637       bulle_aide=self.get_bulle_aide()
638       self.ajout_valeurs=None
639       objet_mc = self.node.item.get_definition()
640       aide = self.get_aide()
641       aide = justify_text(texte=aide)
642       min,max = self.node.item.GetMinMax()
643       l_valeurs = self.node.item.GetListeValeurs()
644       l_choix=self.node.item.get_sd_avant_du_bon_type()
645       l_choix.sort()
646       # remplissage du panneau
647       self.frame_valeurs = Frame(page)
648       self.frame_valeurs.place(relx=0.05,rely=0.05,relwidth=0.35,relheight=0.7)
649       self.frame_boutons_fleches = Frame(page)
650       self.frame_boutons_fleches.place(relx=0.4,rely=0.,relwidth=0.2,relheight=0.7)
651       self.frame_choix = Frame(page)
652       self.frame_choix.place(relx=0.6,rely=0.05,relwidth=0.35,relheight=0.7)
653       self.frame_boutons = Frame(page)
654       self.frame_boutons.place(relx=0.35,rely=0.87,relwidth=0.3,relheight=0.1)
655       liste_commandes_valeurs = (("<Button-1>",self.selectValeur),
656                                  ("<Button-3>",self.deselectValeur),
657                                  ("<Double-Button-1>",self.sup_valeur_sans_into))
658       liste_commandes_choix = (("<Button-1>",self.selectChoix),
659                                ("<Button-3>",self.deselectChoix),
660                                ("<Double-Button-1>",self.add_valeur_sans_into))
661       self.Liste_valeurs = ListeChoix(self,self.frame_valeurs,l_valeurs,liste_commandes = liste_commandes_valeurs,
662                                       titre="Valeur(s) actuelle(s)")
663       self.Liste_choix = ListeChoix(self,self.frame_choix,l_choix,liste_commandes = liste_commandes_choix,
664                                     titre= "Valeurs possibles")
665       bouton_add = Button(self.frame_boutons_fleches,
666                           #text="<--",
667                           image = images.get_image('arrow_left'),
668                           command = self.add_valeur_sans_into)
669       bouton_sup = Button(self.frame_boutons_fleches,
670                           #text="-->",
671                           image = images.get_image('arrow_right'),
672                           command = self.sup_valeur_sans_into)
673       bouton_accepter = Button(self.frame_boutons,
674                                text='Valider',
675                                command = lambda s=self,m=min,M=max : s.accepte_modifs_valeur(m,M))
676       bouton_annuler = Button(self.frame_boutons,
677                               text = 'Annuler',
678                               command = self.annule_modifs_valeur)
679       bouton_add.place(relx=0.3,rely=0.35)
680       bouton_sup.place(relx=0.3,rely=0.65)
681       for but in (bouton_accepter,bouton_annuler):
682           but.pack(side='left',padx=5)
683       self.Liste_valeurs.affiche_liste()
684       self.Liste_choix.affiche_liste()
685       for fram in (self.frame_valeurs,self.frame_boutons_fleches,self.frame_choix,self.frame_boutons):
686           fram.bind("<Button-3>",lambda e,s=self,a=bulle_aide : s.parent.appli.affiche_aide(e,a))
687           fram.bind("<ButtonRelease-3>",self.parent.appli.efface_aide)
688
689   def get_bulle_aide(self):
690       """
691       Retourne la bulle d'aide associée au panneau
692       """
693       return """Un clic sur une valeur des deux listes la sélectionne.
694       - Un clic sur la flèche gauche stocke la valeur possible sélectionnée
695       dans la liste des valeurs que vous voulez affecter au mot-clé simple
696       - Un clic sur la flèche droite déstocke la valeur du mot-clé simple
697       sélectionnée (elle apparaît alors à nouveau comme choix possible
698       dans la liste des choix à droite)
699       - Cliquez sur 'Valider' pour affecter la liste des valeurs sélectionnées
700       au mot-clé simple courant
701       - Cliquez sur 'Annuler' pour restaurer la valeur du mot-clé simple
702       avant toute modification depuis le dernier 'Valider'"""
703
704   def get_aide(self):
705       """
706       Retourne la phrase d'aide indiquant de quel type doivent être les
707       valeurs que doit entrer l'utilisateur
708       """
709       mc = self.node.item.get_definition()
710       type = mc.type[0].__name__  
711       if len(mc.type)>1 :
712           for typ in mc.type[1:] :
713               type = type + ' ou '+typ.__name__
714       if mc.min == mc.max:
715         return "Une liste de "+`mc.min`+" objets de type "+type+" est attendue"
716       else :
717         return "Une liste d'objets de type "+type+" est attendue (min="+`mc.min`+",max="+`mc.max`+')'
718     
719   def sup_valeur(self,name=None):
720       """
721       Supprime la valeur selectionnée de la liste des valeurs et la rajoute
722       à la liste des choix possibles
723       """
724       liste_valeurs = self.Liste_valeurs.get_liste()
725       liste_valeurs.remove(self.selected_valeur)
726       liste_choix = self.node.item.get_definition().into
727       liste_choix = substract_list(liste_choix,liste_valeurs)
728       self.Liste_valeurs.put_liste(liste_valeurs)
729       self.Liste_choix.put_liste(liste_choix)
730       self.selected_valeur = None      
731     
732   def erase_valeur(self):
733       pass
734
735   def get_valeur(self):
736       """
737       Retourne la valeur sélectionnée dans la liste des choix
738       """
739       return self.selected_choix
740
741   def display_valeur(self,val=None):
742       """
743          Affiche la valeur passée en argument dans l'entry de saisie.
744          Par défaut affiche la valeur du mot-clé simple
745       """
746       # Il n'y a pas d'entry pour ce type de panneau
747       return
748
749     
750 class UNIQUE_Panel(newSIMPPanel):
751   """
752   Classe virtuelle servant de classe mère à toutes celles définissant un panneau
753   permettant l'affichage et la saisie d'une valeur unique pour le mot-clé simple
754   """
755
756   def erase_valeur(self):
757       """
758       Efface l'entry de saisie
759       """
760       self.entry.delete(0,END)
761
762   def get_valeur(self):
763       """
764       Retourne la valeur donnée par l'utilisateur
765       """
766       return self.entry.get()
767     
768   def valid_valeur(self):
769       """
770       Teste si la valeur fournie par l'utilisateur est une valeur permise :
771       - si oui, l'enregistre
772       - si non, restaure l'ancienne valeur
773       """
774       if self.parent.modified == 'n' : self.parent.init_modif()
775       valeur = self.get_valeur()
776       self.erase_valeur()
777       anc_val = self.node.item.get_valeur()
778       test = self.node.item.set_valeur(valeur)
779       if not test :
780           mess = "impossible d'évaluer : %s " %`valeur`
781           self.parent.appli.affiche_infos("Valeur du mot-clé non autorisée :"+mess)
782       elif self.node.item.isvalid() :
783           self.parent.appli.affiche_infos('Valeur du mot-clé enregistrée')
784           if self.node.item.get_position()=='global':
785               self.node.etape.verif_all()
786           elif self.node.item.get_position()=='global_jdc':
787               self.node.racine.verif_all()
788           else :
789               self.node.parent.verif()
790           self.node.update()
791           self.node.parent.select()
792       else :
793           cr = self.node.item.get_cr()
794           mess = "Valeur du mot-clé non autorisée :"+cr.get_mess_fatal()
795           self.record_valeur(anc_val,mess=mess)
796
797 class UNIQUE_INTO_Panel(UNIQUE_Panel):
798   """
799   Classe définissant le panel associé aux mots-clés qui demandent
800   à l'utilisateur de choisir une seule valeur parmi une liste de valeurs
801   discrètes
802   """
803   def makeValeurPage(self,page):
804       """
805       Génère la page de saisie d'une seule valeur parmi un ensemble
806       discret de possibles
807       """
808       # récupération de la bulle d'aide et de l'objet mc
809       bulle_aide=self.get_bulle_aide()
810       objet_mc = self.node.item.get_definition()
811       # remplissage du panel
812       self.frame_valeur = Frame(page)
813       self.frame_valeur.pack(fill='both',expand=1)
814       self.frame_valeur.bind("<Button-3>",lambda e,s=self,a=bulle_aide : s.parent.appli.affiche_aide(e,a))
815       self.frame_valeur.bind("<ButtonRelease-3>",self.parent.appli.efface_aide)
816       l_choix=list(objet_mc.into)
817       l_choix.sort()
818       self.label = Label(self.frame_valeur,text='Choisir une valeur :')
819       self.label.pack(side='top')
820       self.frame = Frame(page)
821       self.frame.place(relx=0.33,rely=0.2,relwidth=0.33,relheight=0.6)
822       liste_commandes = (("<Button-1>",self.selectChoix),
823                          ("<Button-3>",self.deselectChoix),
824                          ("<Double-Button-1>",self.record_valeur))
825       self.Liste_choix = ListeChoix(self,self.frame,l_choix,liste_commandes = liste_commandes,
826                                     titre="Valeurs possibles")
827       self.Liste_choix.affiche_liste()
828
829   def get_bulle_aide(self):
830       """
831       Retourne la bulle d'aide affectée au panneau courant (affichée par clic droit)
832       """
833       return """Double-cliquez sur la valeur désirée
834       pour valoriser le mot-clé simple courant"""
835
836 class UNIQUE_ASSD_Panel(UNIQUE_Panel):
837   """
838   Classe servant à définir le panneau associé aux objets qui attendent une valeur unique
839   d'un type dérivé d'ASSD
840   """
841   def valid_valeur_automatique(self):
842       """
843          Réalise la validation d'un concept sans remonter dans le
844          node parent dans le cas ou il n'y a qu'un concept possible (liste de longueur 1)
845          Identique à valid_valeur moins appel de self.node.parent.select()
846          On pourrait supposer que le seul concept présent est valide et donc ne pas
847          réaliser tous les tests de vérification.
848       """
849       if self.parent.modified == 'n' : self.parent.init_modif()
850       valeur = self.get_valeur()
851       self.erase_valeur()
852       anc_val = self.node.item.get_valeur()
853       test = self.node.item.set_valeur(valeur)
854       if not test :
855           mess = "impossible d'évaluer : %s " %`valeur`
856           self.parent.appli.affiche_infos("Valeur du mot-clé non autorisée :"+mess)
857       elif self.node.item.isvalid() :
858           self.parent.appli.affiche_infos('Valeur du mot-clé enregistrée')
859           if self.node.item.get_position()=='global':
860               self.node.etape.verif_all()
861           elif self.node.item.get_position()=='global_jdc':
862               self.node.racine.verif_all()
863           else :
864               self.node.parent.verif()
865           self.node.update()
866           #self.node.parent.select()
867       else :
868           cr = self.node.item.get_cr()
869           mess = "Valeur du mot-clé non autorisée :"+cr.get_mess_fatal()
870           self.record_valeur(anc_val,mess=mess)
871
872   def makeValeurPage(self,page):
873       """
874           Génère la page de saisie de la valeur du mot-clé simple courant qui doit être une 
875           SD de type dérivé d'ASSD
876       """
877       # Récupération de l'aide associée au panneau, de l'aide destinée à l'utilisateur,
878       # et de la liste des SD du bon type (constituant la liste des choix)
879       bulle_aide=self.get_bulle_aide()
880       aide=self.get_aide()
881       aide= justify_text(texte=aide)
882       liste_noms_sd = self.node.item.get_sd_avant_du_bon_type()
883       # Remplissage du panneau
884       self.valeur_choisie = StringVar()
885       self.valeur_choisie.set('')
886       min,max =  self.node.item.GetMinMax()
887       if (min == 1 and min == max and len(liste_noms_sd)==1):
888           if self.valeur_choisie.get() != liste_noms_sd[0]:
889              self.valeur_choisie.set(liste_noms_sd[0])
890              self.valid_valeur_automatique()
891          
892       self.frame_valeur = Frame(page)
893       self.frame_valeur.pack(fill='both',expand=1)
894       self.frame_valeur.bind("<Button-3>",lambda e,s=self,a=bulle_aide : s.parent.appli.affiche_aide(e,a))
895       self.frame_valeur.bind("<ButtonRelease-3>",self.parent.appli.efface_aide)
896       self.listbox = Pmw.ScrolledListBox(self.frame_valeur,
897                                          items=liste_noms_sd,
898                                          labelpos='n',
899                                          label_text="Structures de données du type\n requis par l'objet courant :",
900                                          listbox_height = 6,
901                                          selectioncommand=self.select_valeur_from_list,
902                                          dblclickcommand=lambda s=self,c=self.valid_valeur : s.choose_valeur_from_list(c))
903       self.listbox.place(relx=0.5,rely=0.3,relheight=0.4,anchor='center')
904       Label(self.frame_valeur,text='Structure de donnée choisie :').place(relx=0.05,rely=0.6)
905       #self.label_valeur = Label(self.frame_valeur,textvariable=self.valeur_choisie)
906       Label(self.frame_valeur,textvariable=self.valeur_choisie).place(relx=0.5,rely=0.6)
907       # affichage de la valeur courante
908       self.display_valeur()
909
910   def get_bulle_aide(self):
911       """
912       Retourne l'aide associée au panneau
913       """
914       return "Double-cliquez sur la structure de donnée désirée pour valoriser le mot-clé simple courant"
915
916   def get_aide(self):
917       """
918       Retourne la phrase d'aide indiquant de quel type doit être la valeur à donner par l'utilisateur
919       """
920       mc = self.node.item.get_definition()
921       type = mc.type[0].__name__  
922       if len(mc.type)>1 :
923           for typ in mc.type[1:] :
924               type = type + ' ou '+typ.__name__
925       return  "Un objet de type "+type+" est attendu"
926     
927   def select_valeur_from_list(self):
928       """
929       Affecte à valeur choisie la sélection courante dans la liste des choix proposée
930       """
931       if len(self.listbox.get()) == 0 : return
932       choix = self.listbox.getcurselection()[0]
933       self.valeur_choisie.set(choix)
934
935   def choose_valeur_from_list(self,command):
936       """
937       Affecte à valeur choisie la sélection courante dans la liste des choix proposée
938       Exécute command
939       """
940       if len(self.listbox.get()) == 0 : return
941       choix = self.listbox.getcurselection()[0]
942       self.valeur_choisie.set(choix)
943       apply(command,(),{})
944
945   def get_valeur(self):
946       """
947       Retourne la valeur donnée par l'utilisateur au MCS
948       """
949       return self.valeur_choisie.get()
950     
951   def display_valeur(self):
952       """
953       Affiche la valeur de l'objet pointé par self
954       """
955       valeur = self.node.item.get_valeur()
956       if valeur == None : return # pas de valeur à afficher ...
957       self.valeur_choisie.set(valeur.nom)
958
959   def erase_valeur(self):
960       pass
961
962 class UNIQUE_SDCO_Panel(UNIQUE_ASSD_Panel):
963   """
964   Classe servant à définir le panneau correspondant à un mot-clé simple
965   qui attend une valeur unique de type dérivé d'ASSD ou non encore
966   existante (type CO(...) utilisé dans les macros uniquement)
967   """
968   def makeValeurPage(self,page):
969       """
970       Génère la page de saisie de la valeur du mot-clé simple courant qui doit être une SD de type dérivé
971       d'ASSD
972       """
973       # Récupération de l'aide associée au panneau, de l'aide destinée à l'utilisateur,
974       # et de la liste des SD du bon type (constituant la liste des choix)
975       bulle_aide=self.get_bulle_aide()
976       aide=self.get_aide()
977       aide= justify_text(texte=aide)
978       liste_noms_sd = self.node.item.get_sd_avant_du_bon_type()
979       # Remplissage du panneau
980       self.frame_valeur = Frame(page)
981       self.frame_valeur.pack(fill='both',expand=1)
982       self.frame_valeur.bind("<Button-3>",lambda e,s=self,a=bulle_aide : s.parent.appli.affiche_aide(e,a))
983       self.frame_valeur.bind("<ButtonRelease-3>",self.parent.appli.efface_aide)
984       # affichage de la liste des SD existantes et du bon type
985       self.listbox = Pmw.ScrolledListBox(self.frame_valeur,
986                                          items=liste_noms_sd,
987                                          labelpos='n',
988                                          label_text="Structures de données du type\n requis par l'objet courant :",
989                                          listbox_height = 6,
990                                          selectioncommand=self.select_valeur_from_list,
991                                          dblclickcommand=lambda s=self,c=self.valid_valeur : s.choose_valeur_from_list(c))
992       self.listbox.place(relx=0.5,rely=0.3,relheight=0.4,anchor='center')
993       # affichage du bouton 'Nouveau concept'
994       self.b_co = Pmw.OptionMenu(self.frame_valeur,labelpos='w',label_text = "Nouveau concept : ",
995                                  items = ('NON','OUI'),menubutton_width=10)
996       self.b_co.configure(command = lambda e,s=self : s.ask_new_concept())
997       self.b_co.place(relx=0.05,rely=0.6,anchor='w')
998       self.label_co = Label(self.frame_valeur,text='Nom du nouveau concept :')
999       self.entry_co = Entry(self.frame_valeur)
1000       self.entry_co.bind('<Return>',self.valid_nom_concept_co)
1001       # affichage du label de la structure de donnée choisie
1002       self.l_resu = Label(self.frame_valeur,text='Structure de donnée choisie :')
1003       self.valeur_choisie = StringVar()
1004       self.label_valeur = Label(self.frame_valeur,textvariable=self.valeur_choisie)
1005       self.frame_valeur.update()
1006       self.aide = Label(self.frame_valeur,
1007                         text = aide,
1008                         wraplength=int(self.frame_valeur.winfo_width()*0.8),
1009                         justify='center')
1010       self.aide.place(relx=0.5,rely=0.85,anchor='n')
1011       # affichage de la valeur courante
1012       self.display_valeur()
1013       
1014   def get_bulle_aide(self):
1015       """
1016       Retourne la bulle d'aide du panneau
1017       """
1018       return """Double-cliquez sur la structure de donnée désirée
1019       pour valoriser le mot-clé simple courant ou cliquez sur NOUVEAU CONCEPT pour
1020       entrer le nom d'un concept non encore existant"""
1021
1022   def valid_valeur(self):
1023       """
1024       Teste si la valeur fournie par l'utilisateur est une valeur permise :
1025       - si oui, l'enregistre
1026       - si non, restaure l'ancienne valeur
1027       """
1028       if self.parent.modified == 'n' : self.parent.init_modif()
1029       valeur = self.get_valeur()
1030       self.erase_valeur()
1031       anc_val = self.node.item.get_valeur()
1032       test_CO=self.node.item.is_CO(anc_val)
1033       test = self.node.item.set_valeur(valeur)
1034       if not test :
1035           mess = "impossible d'évaluer : %s " %`valeur`
1036           self.parent.appli.affiche_infos("Valeur du mot-clé non autorisée :"+mess)
1037           return
1038       elif self.node.item.isvalid() :
1039           self.parent.appli.affiche_infos('Valeur du mot-clé enregistrée')
1040           if test_CO:
1041              # il faut egalement propager la destruction de l'ancien concept
1042              self.node.item.delete_valeur_co(valeur=anc_val)
1043              # et on force le recalcul des concepts de sortie de l'etape
1044              self.node.item.object.etape.get_type_produit(force=1)
1045              # et le recalcul du contexte
1046              self.node.item.object.etape.parent.reset_context()
1047           self.node.parent.select()
1048       else :
1049           cr = self.node.item.get_cr()
1050           mess = "Valeur du mot-clé non autorisée :"+cr.get_mess_fatal()
1051           self.record_valeur(anc_val,mess=mess)
1052           return
1053       if self.node.item.get_position()=='global':
1054           self.node.etape.verif_all()
1055       elif self.node.item.get_position()=='global_jdc':
1056           self.node.racine.verif_all()
1057       else :
1058           self.node.parent.verif()
1059       self.node.update()
1060
1061   def valid_nom_concept_co(self,event=None):
1062       """
1063       Lit le nom donné par l'utilisateur au concept de type CO qui doit être
1064       la valeur du MCS courant et stocke cette valeur
1065       """
1066       if self.parent.modified == 'n' : self.parent.init_modif()
1067       anc_val = self.node.item.get_valeur()
1068       nom_concept = self.entry_co.get()
1069       test,mess=self.node.item.set_valeur_co(nom_concept)
1070       if not test:
1071           # On n'a pas pu créer le concept
1072           self.parent.appli.affiche_infos(mess)
1073           return
1074       elif self.node.item.isvalid() :
1075           self.parent.appli.affiche_infos('Valeur du mot-clé enregistrée')
1076           self.node.parent.select()
1077       else :
1078           cr = self.node.item.get_cr()
1079           mess = "Valeur du mot-clé non autorisée :"+cr.get_mess_fatal()
1080           self.record_valeur(anc_val,mess=mess)
1081           return
1082       if self.node.item.get_position()=='global':
1083           self.node.etape.verif_all()
1084       elif self.node.item.get_position()=='global_jdc':
1085           self.node.racine.verif_all()
1086       else :
1087           self.node.parent.verif()
1088       if self.node.item.isvalid():
1089           self.node.parent.select()
1090       self.node.update()
1091
1092   def ask_new_concept(self):
1093       """
1094       Crée une entry dans le panneau d'un MCS qui attend un concept OU un CO() afin de
1095       permettre à l'utilisateur de donner le nom du nouveau concept
1096       """
1097       new_concept = self.b_co.getcurselection()
1098       if new_concept == 'OUI':
1099           self.label_co.place(relx=0.05,rely=0.7)
1100           self.entry_co.place(relx=0.45,rely=0.7,relwidth=0.25)
1101           self.l_resu.place_forget()
1102           self.label_valeur.place_forget()
1103           self.entry_co.focus()
1104       elif new_concept == 'NON':
1105           # On est passe de OUI à NON, on supprime la valeur
1106 # PN correction de bug (on passe de non a non et cela supprime la valeur)
1107 # ajout du if de le ligne suivane
1108           if self.node.item.is_CO():
1109                 self.node.item.delete_valeur_co()
1110                 self.record_valeur(name=None,mess="Suppression CO enregistrée")
1111                 self.label_co.place_forget()
1112                 self.entry_co.place_forget()
1113                 self.l_resu.place(relx=0.05,rely=0.7)
1114                 self.label_valeur.place(relx=0.45,rely=0.7)
1115           
1116   def display_valeur(self):
1117       """
1118       Affiche la valeur de l'objet pointé par self
1119       """
1120       valeur = self.node.item.get_valeur()
1121       if valeur == None or valeur == '': 
1122          self.valeur_choisie.set('')
1123          return # pas de valeur à afficher ...
1124       # il faut configurer le bouton si la valeur est un objet CO
1125       # sinon afficher le nom du concept dans self.valeur_choisie
1126       if self.node.item.is_CO():
1127           self.b_co.invoke('OUI')
1128           self.entry_co.insert(0,valeur.nom)
1129       else:
1130           self.valeur_choisie.set(valeur.nom)
1131
1132   def record_valeur(self,name=None,mess='Valeur du mot-clé enregistrée'):
1133       """
1134       Enregistre  val comme valeur de self.node.item.object SANS faire de test de validité
1135       """
1136       if self.parent.modified == 'n' : self.parent.init_modif()
1137       if name != None:
1138           valeur =name
1139       else :
1140           self.entry_co.delete(0,END)
1141           valeur= self.entry_co.get()
1142       self.node.item.set_valeur_co(valeur)
1143       self.parent.appli.affiche_infos(mess)
1144       # On met a jour le display dans le panneau
1145       self.display_valeur()
1146       if self.node.item.get_position()=='global':
1147           self.node.etape.verif_all()
1148       elif self.node.item.get_position()=='global_jdc':
1149           self.node.racine.verif_all()
1150       else :
1151           self.node.parent.verif()
1152       if self.node.item.isvalid():
1153           self.node.parent.select()
1154       self.node.update()
1155
1156
1157 class UNIQUE_BASE_Panel(UNIQUE_Panel):
1158   """
1159   Classe servant à définir le panneau associé aux mots-clés simples qui attendent
1160   une valeur d'un type de base (entier, réel ou string).
1161   """
1162   def makeValeurPage(self,page):
1163       """
1164       Génère la page de saisie de la valeur du mot-clé simple courant qui doit être de type
1165       de base cad entier, réel, string ou complexe
1166       """
1167       # Récupération de l'aide associée au panneau, de l'aide destinée à l'utilisateur,
1168       # et de la liste des SD du bon type (constituant la liste des choix)
1169       bulle_aide=self.get_bulle_aide()
1170       aide=self.get_aide()
1171       aide= justify_text(texte=aide)
1172       liste_noms_sd = self.node.item.get_sd_avant_du_bon_type()
1173       # Remplissage du panneau
1174       self.frame_valeur = Frame(page)
1175       self.frame_valeur.pack(fill='both',expand=1)
1176       self.frame_valeur.bind("<Button-3>",lambda e,s=self,a=bulle_aide : s.parent.appli.affiche_aide(e,a))
1177       self.frame_valeur.bind("<ButtonRelease-3>",self.parent.appli.efface_aide)
1178       self.label = Label(self.frame_valeur,text='Valeur :')
1179       self.label.place(relx=0.1,rely=0.5)
1180       self.entry = Entry(self.frame_valeur,relief='sunken')
1181       self.entry.place(relx=0.28,rely=0.5,relwidth=0.6)
1182       self.entry.bind("<Return>",lambda e,c=self.valid_valeur:c())
1183       self.entry.focus()
1184       # aide associée au panneau
1185       self.frame_valeur.update()
1186       self.aide = Label(self.frame_valeur, 
1187                         text = aide,
1188                         wraplength=int(self.frame_valeur.winfo_width()*0.8),
1189                         justify='center')
1190       self.aide.place(relx=0.5,rely=0.7,anchor='n')
1191       # affichage de la valeur du MCS
1192       self.display_valeur()
1193
1194   def get_aide(self):
1195       """
1196       Retourne la phrase d'aide indiquant de quel type doit être la valeur
1197       du mot-clé simple fournie par l'utilisateur
1198       """
1199       mc = self.node.item.get_definition()
1200       d_aides = { 'TXM' : "Une chaîne de caractères est attendue",
1201                   'R'   : "Un réel est attendu",
1202                   'I'   : "Un entier est attendu"}
1203       type = mc.type[0]
1204       return d_aides.get(type,"Type de base inconnu")
1205
1206   def get_bulle_aide(self):
1207       """
1208       Retourne la bulle d'aide associée au panneau et affichée par clic droit
1209       """
1210       return """Saisissez la valeur que vous voulez affecter au mot-clé simple
1211       dans la zone de saisie et pressez <Return>"""
1212       
1213   def display_valeur(self):
1214       """
1215       Affiche la valeur de l'objet pointé par self
1216       """
1217       valeur = self.node.item.get_valeur()
1218       if valeur == None : return # pas de valeur à afficher ...
1219       self.entry.delete(0,END)
1220       self.entry.insert(0,valeur)
1221       self.entry.focus()
1222       
1223 class UNIQUE_COMP_Panel(UNIQUE_Panel):
1224   """
1225   Classe servant à définir le panneau associé aux mots-clés simples
1226   qui attendent une valeur de type complexe
1227   """
1228   def makeValeurPage(self,page):
1229       """
1230       Génère la page de saisie de la valeur du mot-clé simple courant qui doit être de type
1231       de base cad entier, réel, string ou complexe
1232       """
1233       # Récupération de l'aide associée au panneau et de l'aide destinée à l'utilisateur
1234       bulle_aide=self.get_bulle_aide()
1235       aide=self.get_aide()
1236       aide= justify_text(texte=aide)
1237       # Remplissage du panneau
1238       self.frame_valeur = Frame(page)
1239       self.frame_valeur.pack(fill='both',expand=1)
1240       self.frame_valeur.bind("<Button-3>",lambda e,s=self,a=bulle_aide : s.parent.appli.affiche_aide(e,a))
1241       self.frame_valeur.bind("<ButtonRelease-3>",self.parent.appli.efface_aide)
1242       self.label = Label(self.frame_valeur,text='Valeur :')
1243       self.label.place(relx=0.1,rely=0.5)
1244       self.typ_cplx=StringVar()
1245       self.typ_cplx.set('RI')
1246       rb1 = Radiobutton(self.frame_valeur, text='RI',variable=self.typ_cplx,value='RI')
1247       rb2 = Radiobutton(self.frame_valeur, text='MP',variable=self.typ_cplx,value='MP')
1248       self.entry1 = Pmw.EntryField(self.frame_valeur,validate='real')
1249       self.entry2 = Pmw.EntryField(self.frame_valeur,validate='real')
1250       rb1.place(relx=0.05,rely = 0.4)
1251       rb2.place(relx=0.05,rely = 0.6)
1252       self.entry1.component('entry').bind("<Return>",lambda e,s=self:s.entry2.component('entry').focus())
1253       self.entry2.component('entry').bind("<Return>",lambda e,c=self.valid_valeur:c())
1254       self.entry1.place(relx=0.27,rely = 0.5,relwidth=0.35)
1255       self.entry2.place(relx=0.65,rely = 0.5,relwidth=0.35)
1256       self.entry1.focus()
1257       self.frame_valeur.update()
1258       self.aide = Label(self.frame_valeur,
1259                         text = aide,
1260                         wraplength=int(self.frame_valeur.winfo_width()*0.8),
1261                         justify='center')
1262       self.aide.place(relx=0.5,rely=0.7,anchor='n')
1263
1264   def get_bulle_aide(self):
1265       """
1266       Retourne la bulle d'aide du panneau
1267       """
1268       return """-Choisissez votre format de saisie du complexe :
1269       \t 'RI' = parties réelle et imaginaire
1270       \t 'MP' = module/phase (en degrés)
1271       - Saisissez ensuite dans les deux zones de saisie les deux nombres attendus"""
1272
1273   def get_aide(self):
1274       """
1275       Retourne la phrase d'aide décrivant le type de la valeur que peut prendre
1276       le mot-clé simple courant
1277       """
1278       return 'Un complexe est attendu'
1279
1280   def get_valeur(self):
1281       """
1282       Retourne le complexe saisi par l'utilisateur
1283       """
1284       l=[]
1285       l.append(self.typ_cplx.get())
1286       l.append(string.atof(self.entry1.get()))
1287       l.append(string.atof(self.entry2.get()))
1288       return `tuple(l)`
1289
1290   def erase_valeur(self):
1291       """
1292       Efface les entries de saisie
1293       """
1294       self.typ_cplx = 'RI'
1295       self.entry1.delete(0,END)
1296       self.entry2.delete(0,END)
1297       
1298 class SIMPTreeItem(Objecttreeitem.AtomicObjectTreeItem):
1299   panel = newSIMPPanel
1300
1301   def init(self) :
1302       self.expandable = 0
1303       self.affect_panel()
1304
1305   def affect_panel(self):
1306       """
1307       Cette méthode attribue le panel à l'objet pointé par self en fonction de la
1308       nature de la valeur demandée pour cet objet
1309       """
1310       print "affect_panel : ",self.nom,self.is_list(),self.has_into(), self.get_into(None)
1311       if self.wait_shell():
1312           # l'objet attend un shell
1313           self.panel = SHELLPanel
1314       elif self.wait_into():
1315           # l'objet prend sa (ses) valeur(s) dans un ensemble discret de valeurs
1316           min,max = self.GetMinMax()
1317           # PN : 
1318           # Remplacement du if ??
1319           #if max != 1 and ((min != 0 and min != max) or (min == 0)):
1320           assert (min <= max)
1321           if max > 1 :
1322              # l'objet attend une liste de valeurs
1323              self.panel = PLUSIEURS_INTO_Panel
1324           else:
1325              # l'objet n'attend qu'une seule valeur
1326              self.panel = UNIQUE_INTO_Panel
1327       else:
1328           # l'objet prend une ou des valeurs à priori quelconques
1329           min,max = self.GetMinMax()
1330           if max != 1 :
1331               # on attend une liste de valeurs mais de quel type ?
1332               if self.wait_assd():
1333                   # on attend une liste de SD
1334                   self.panel = PLUSIEURS_ASSD_Panel
1335               else:
1336                   # on attend une liste de valeurs de types debase (entiers, réels,...)
1337                   self.panel = PLUSIEURS_BASE_Panel
1338           else:
1339               # on n'attend qu'une seule valeur mais de quel type ?
1340               if self.wait_co():
1341                   # on attend une SD ou un objet de la classe CO (qui n'existe pas encore)
1342                   self.panel = UNIQUE_SDCO_Panel
1343               elif self.wait_assd():
1344                   # on attend une SD
1345                   self.panel = UNIQUE_ASSD_Panel
1346               else:
1347                   # on attend une valeur d'un type de base (entier,réel,...)
1348                   if self.wait_complex():
1349                       # on attend un complexe
1350                       self.panel = UNIQUE_COMP_Panel
1351                   else:
1352                       # on attend un entier, un réel ou une string
1353                       self.panel = UNIQUE_BASE_Panel
1354       
1355   def SetText(self, text):
1356     try:
1357       value = eval(text)
1358       self.object.setval(value)
1359     except:
1360       pass
1361
1362   def GetIconName(self):
1363     if self.isvalid():
1364       return "ast-green-ball"
1365     elif self.object.isoblig():
1366       return "ast-red-ball"
1367     else:
1368       return "ast-yel-ball"
1369
1370   def GetText(self):
1371     """
1372     Classe SIMPTreeItem
1373     Retourne le texte à afficher dans l'arbre représentant la valeur de l'objet
1374     pointé par self 
1375     """
1376     text= self.object.GetText()
1377     return text
1378
1379   def has_into(self):
1380       """
1381           Cette méthode indique si le mot cle simple propose un choix (valeur de retour 1)
1382           ou s'il n'en propose pas (valeur de retour 0)
1383
1384           Deux cas principaux peuvent se presenter : avec validateurs ou bien sans.
1385           Dans le cas sans validateur, l'information est donnée par l'attribut into
1386           de la definition du mot cle.
1387           Dans le cas avec validateur, il faut combiner l'information précédente avec
1388           celle issue de l'appel de la méthode has_into sur le validateur. On utilisera
1389           l'operateur ET pour effectuer cette combinaison (AndVal).
1390       """
1391       if not self.object.definition.validators:
1392            if self.definition.into:
1393                return 1
1394            else:
1395                return 0
1396       else:
1397            # Dans le cas avec validateurs, pour que le mot cle soit considéré
1398            # comme proposant un choix, il faut que into soit présent OU
1399            # que la méthode has_into du validateur retourne 1. Dans les autres cas
1400            # on retournera 0 (ne propose pas de choix)
1401            if self.definition.into:
1402                 return 1
1403            elif self.object.definition.validators.has_into():
1404                 return 1
1405            else:
1406                 return 0
1407
1408   def get_into(self,liste_courante=None):
1409       """
1410           Cette méthode retourne la liste de choix proposée par le mot cle. Si le mot cle ne propose
1411           pas de liste de choix, la méthode retourne None.
1412           L'argument d'entrée liste_courante, s'il est différent de None, donne la liste des choix déjà
1413           effectués par l'utilisateur. Dans ce cas, la méthode get_into doit calculer la liste des choix
1414           en en tenant compte.
1415           Cette méthode part du principe que la relation entre into du mot clé et les validateurs est
1416           une relation de type ET (AndVal).
1417       """
1418       if not self.object.definition.validators :
1419          return self.object.definition.into
1420       else:
1421          return self.object.definition.validators.get_into(liste_courante,self.definition.into)
1422          
1423   def is_list(self):
1424       """
1425           Cette méthode indique si le mot cle simple attend une liste (valeur de retour 1)
1426           ou s'il n'en attend pas (valeur de retour 0)
1427
1428           Deux cas principaux peuvent se presenter : avec validateurs ou bien sans.
1429           Dans le cas sans validateur, l'information est donnée par l'attribut max 
1430           de la definition du mot cle.
1431           Dans le cas avec validateur, il faut combiner l'information précédente avec
1432           celle issue de l'appel de la méthode is_list sur le validateur.On utilisera
1433           l'operateur ET pour effectuer cette combinaison (AndVal).
1434       """
1435       if not self.object.definition.validators:
1436            if self.definition.max <= 1:
1437                return 0
1438            else: 
1439                return 1
1440       else:
1441            # Dans le cas avec validateurs, pour que le mot cle soit considéré 
1442            # comme acceptant une liste, il faut que max soit supérieur a 1
1443            # ET que la méthode is_list du validateur retourne 1. Dans les autres cas
1444            # on retournera 0 (n'attend pas de liste)
1445            if self.definition.max <= 1:
1446                 return 0
1447            elif not self.object.definition.validators.is_list():
1448                 return 0
1449            else:
1450                 return 1
1451
1452   def wait_co(self):
1453       """
1454       Méthode booléenne qui retourne 1 si l'objet pointé par self
1455       attend un objet de type ASSD qui n'existe pas encore (type CO()),
1456       0 sinon
1457       """
1458       return self.object.wait_co()
1459
1460   def wait_geom(self):
1461       """
1462       Méthode booléenne qui retourne 1 si l'objet pointé par self
1463       attend un objet GEOM, 0 sinon
1464       """
1465       return self.object.wait_geom()
1466     
1467   def wait_complex(self):
1468       """ Méthode booléenne qui retourne 1 si l'objet pointé par self
1469       attend un complexe, 0 sinon """
1470       if 'C' in self.object.definition.type:
1471           return 1
1472       else:
1473           return 0
1474
1475   def wait_reel(self):
1476       """ Méthode booléenne qui retourne 1 si l'objet pointé par self
1477       attend un réel, 0 sinon """
1478       if 'R' in self.object.definition.type:
1479           return 1
1480       else:
1481           return 0
1482         
1483   def wait_shell(self):
1484       """ Méthode booléenne qui retourne 1 si l'objet pointé par self
1485       attend un shell, 0 sinon """
1486       if 'shell' in self.object.definition.type:
1487           return 1
1488       else:
1489           return 0
1490
1491   def wait_into(self):
1492       """ Méthode booléenne qui retourne 1 si l'objet pointé par self
1493       prend ses valeurs dans un ensemble discret (into), 0 sinon """
1494       if self.object.definition.into != None :
1495           return 1
1496       else:
1497           return 0
1498
1499   def wait_assd(self):
1500       """Méthode booléenne qui retourne 1 si l'objet pointé par self
1501       attend un objet de type ASSD ou dérivé, 0 sinon """
1502       return self.object.wait_assd()
1503     
1504   def getval(self):
1505       return self.object.getval()
1506     
1507   def GetMinMax(self):
1508       """ Retourne les valeurs min et max de la définition de object """
1509       return self.object.get_min_max()
1510
1511   def GetMultiplicite(self):
1512       """ A préciser.
1513           Retourne la multiplicité des valeurs affectées à l'objet
1514           représenté par l'item. Pour le moment retourne invariablement 1.
1515       """
1516       return 1
1517
1518   def GetType(self):
1519       """ 
1520           Retourne le type de valeur attendu par l'objet représenté par l'item.
1521       """
1522       return self.object.get_type()
1523
1524   def GetIntervalle(self):
1525       """ 
1526            Retourne le domaine de valeur attendu par l'objet représenté 
1527            par l'item.
1528       """
1529       return self.object.getintervalle()
1530
1531   def IsInIntervalle(self,valeur):
1532       """ 
1533           Retourne 1 si la valeur est dans l'intervalle permis par
1534           l'objet représenté par l'item.
1535       """
1536       return self.object.isinintervalle(valeur)
1537
1538   def set_valeur_co(self,nom_co):
1539       """
1540       Affecte au MCS pointé par self l'objet de type CO et de nom nom_co
1541       """
1542       return self.object.set_valeur_co(nom_co)
1543       
1544   def get_sd_avant_du_bon_type(self):
1545       """
1546       Retourne la liste des noms des SD présentes avant l'étape qui contient
1547       le MCS pointé par self et du type requis par ce MCS
1548       """
1549       return self.object.etape.parent.get_sd_avant_du_bon_type(self.object.etape,
1550                                                                self.object.definition.type)
1551     
1552   def GetListeValeurs(self) :
1553       """ Retourne la liste des valeurs de object """
1554       return self.object.get_liste_valeurs()
1555     
1556   def verif(self):
1557       pass
1558
1559   def isvalid(self):
1560     return self.object.isvalid()
1561
1562   def eval_valeur(self,valeur):
1563       """ Lance l'interprétation de 'valeur' (chaîne de caractères) comme valeur
1564       de l'objet pointé par self :
1565         - retourne l'objet associé si on a pu interpréter (entier, réel, ASSD,...)
1566         - retourne 'valeur' (chaîne de caractères) sinon """
1567       return self.object.eval_valeur(valeur)
1568
1569   def is_CO(self,valeur=None):
1570       """
1571          Indique si valeur est un concept produit de la macro
1572          Cette méthode n'a de sens que pour un MCSIMP d'une MACRO
1573          Si valeur vaut None on teste la valeur du mot cle
1574       """
1575       # Pour savoir si un concept est un nouveau concept de macro
1576       # on regarde s'il est présent dans l'attribut sdprods de l'étape
1577       # ou si son nom de classe est CO.
1578       # Il faut faire les 2 tests car une macro non valide peut etre
1579       # dans un etat pas tres catholique avec des CO pas encore types
1580       # et donc pas dans sdprods (resultat d'une exception dans type_sdprod)
1581       if not valeur:valeur=self.object.valeur
1582       if valeur in self.object.etape.sdprods:return 1
1583       if type(valeur) is not types.ClassType:return 0
1584       if valeur.__class__.__name__ == 'CO':return 1
1585       return 0
1586
1587   def delete_valeur_co(self,valeur=None):
1588       """
1589            Supprime la valeur du mot cle (de type CO)
1590            il faut propager la destruction aux autres etapes
1591       """
1592       if not valeur : valeur=self.object.valeur
1593       # XXX faut il vraiment appeler del_sdprod ???
1594       #self.object.etape.parent.del_sdprod(valeur)
1595       self.object.etape.parent.delete_concept(valeur)
1596
1597 import Accas
1598 treeitem = SIMPTreeItem
1599 objet = Accas.MCSIMP
1600