Salome HOME
CCAR: introduction de methodes complementaires pour les validateurs
[tools/eficas.git] / Editeur / composimp.py
index d7ec659b34d9dabd7c1fc975b464499dd2c7f7d4..6fb84f369832fe5d978231df85ac48fbb3a0eb6c 100644 (file)
@@ -1,17 +1,32 @@
-#@ MODIF composimp Editeur  DATE 05/09/2001   AUTEUR DURAND C.DURAND 
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
-# COPYRIGHT (C) 1991 - 2001  EDF R&D                  WWW.CODE-ASTER.ORG
-#              SEE THE FILE "LICENSE.TERMS" FOR INFORMATION ON USAGE AND
-#              REDISTRIBUTION OF THIS FILE.
+# COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
+# THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
+# IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
+# THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
+# (AT YOUR OPTION) ANY LATER VERSION.
+#
+# THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
+# WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
+# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
+# GENERAL PUBLIC LICENSE FOR MORE DETAILS.
+#
+# YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
+# ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
+#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
+#
+#
 # ======================================================================
+# Modules Python
 import string,types,os
 from Tkinter import *
 import Pmw
 from tkFileDialog import *
 from tkMessageBox import showinfo
 from copy import copy,deepcopy
+import traceback
 
+# Modules Eficas
 import Objecttreeitem
 import prefs
 import panels
@@ -45,20 +60,27 @@ class newSIMPPanel(panels.OngletPanel):
       nb.setnaturalsize()
       
 # ----------------------------------------------------------------------------------------
-#   Méthodes utlisées pour l'affectation de la valeur donnée par l'utilisateur
+#   Méthodes utilisées pour l'affectation de la valeur donnée par l'utilisateur
 #    au mot-clé courant
 # ----------------------------------------------------------------------------------------
 
   def record_valeur(self,name=None,mess='Valeur du mot-clé enregistrée'):
       """
-      Enregistre  val comme valeur de self.node.item.object SANS faire de test de validité
+          Enregistre  val comme valeur de self.node.item.object SANS 
+          faire de test de validité
       """
       if self.parent.modified == 'n' : self.parent.init_modif()
       if name != None:
           valeur =name
       else :
+          #XXX Pourquoi proceder ainsi ? Il n'est pas possible de mettre
+          # None comme valeur du mot cle. 
+          # Probablement que ce debranchement permet de mettre record_valeur
+          # en call back, il faut donc aller chercher la valeur dans l'entry
           valeur= self.entry.get()
           self.entry.delete(0,END)
+          #XXX Pour permettre la mise a None du mot cle, on remet None si valeur == ''
+          if valeur == '':valeur=None
       self.node.item.set_valeur(valeur,evaluation='non')
       self.parent.appli.affiche_infos(mess)
       if self.node.item.get_position()=='global':
@@ -67,11 +89,12 @@ class newSIMPPanel(panels.OngletPanel):
           self.node.racine.verif_all()
       else :
           self.node.parent.verif()
+      self.node.update()
       if self.node.item.isvalid():
           self.node.parent.select()
-      self.node.update()
+
 # ----------------------------------------------------------------------------------------
-#   Méthodes utlisées pour la manipulation des items dans les listes de choix
+#   Méthodes utilisées pour la manipulation des items dans les listes de choix
 # ----------------------------------------------------------------------------------------
   def selectValeur(self,name):
       self.selected_valeur = name
@@ -104,7 +127,7 @@ class newSIMPPanel(panels.OngletPanel):
           return
       liste_valeurs.append(self.selected_choix)
       liste_choix = self.Liste_choix.get_liste()
-      liste_choix.remove(self.selected_choix)
+      #  liste_choix.remove(self.selected_choix)
       self.Liste_valeurs.put_liste(liste_valeurs)
       self.Liste_choix.put_liste(liste_choix)
       self.selected_choix = None
@@ -115,6 +138,12 @@ class newSIMPPanel(panels.OngletPanel):
   def deselectChoix(self,name):
       self.selectChoix = None
       
+  def raisecmd(self,page):
+      try:
+         self.entry.focus()
+      except:
+         pass
+
 class SHELLPanel(newSIMPPanel):
   """
   Classe Panel utilisé pour les mots-clés simples qui attendent un shell pour valeur
@@ -181,7 +210,18 @@ class PLUSIEURS_Panel(newSIMPPanel):
       Méthode qui récupère la liste des valeurs donnée par l'utilisateur
       et l'affecte au mot-clé courant.
       """
-      l_valeurs = self.Liste_valeurs.get_liste()
+      l1_valeurs = self.Liste_valeurs.get_liste()
+      # PN : remplacement des paramétres par leur nom (cf get_liste)
+      #      
+      l_valeurs=[]
+      for  val in l1_valeurs :
+           if val.__class__.__name__ in ('PARAMETRE','PARAMETRE_EVAL'):
+               v=val.nom
+           else:
+                v=val
+           l_valeurs.append(v)
+    
+      print "l_valeurs = ", l_valeurs
       longueur = len(l_valeurs)
       if longueur < min or longueur > max :
           self.parent.appli.affiche_infos("Valeur refusée : nombre d'éléments incorrect dans la liste")
@@ -193,21 +233,22 @@ class PLUSIEURS_Panel(newSIMPPanel):
       else:
          valeur = None
       self.parent.appli.affiche_infos("Valeur acceptée")
+      print "valeur = " ,valeur
       self.record_valeur(valeur)
       if self.node.item.isvalid():
           self.node.parent.select()
-      # fermeture de la fenêtre de sélection\r
-      if self.ajout_valeurs:\r
-          self.ajout_valeurs.quit()\r
+      # fermeture de la fenêtre de sélection
+      if self.ajout_valeurs:
+          self.ajout_valeurs.quit()
           
   def annule_modifs_valeur(self):
       """
       RAZ de la liste des valeurs (annule toutes les valeurs saisies par l'utilisateur)
       """
       self.node.select()
-      # fermeture de la fenêtre de sélection\r
-      if self.ajout_valeurs:\r
-          self.ajout_valeurs.quit()\r
+      # fermeture de la fenêtre de sélection
+      if self.ajout_valeurs:
+          self.ajout_valeurs.quit()
           
   def traite_reel(self,valeur):
       """
@@ -233,8 +274,8 @@ class PLUSIEURS_Panel(newSIMPPanel):
       """
       Lit ce que l'utilisateur a saisi dans self.entry et cherche à
       l'évaluer :
-      - si la valeur est acceptable, elle est ajoutée dans la liste des valeurs
-      - sinon elle est refusée
+        - si la valeur est acceptable, elle est ajoutée dans la liste des valeurs
+        - sinon elle est refusée
       """
       min,max = self.node.item.GetMinMax()
       if name != None :
@@ -305,10 +346,12 @@ class PLUSIEURS_INTO_Panel(PLUSIEURS_Panel):
       """
       Génère la page de saisie de plusieurs valeurs parmi un ensemble discret
       de possibles
-      """\r
+      """
       self.ajout_valeurs = None
       # On récupère la bulle d'aide du panneau, l'objet, min et max (cardinalité de la liste),
       # la liste des choix et la liste des valeurs
+      aide = self.get_aide()
+      aide = justify_text(texte=aide)
       bulle_aide=self.get_bulle_aide()
       objet_mc = self.node.item.get_definition()
       min,max = self.node.item.GetMinMax()
@@ -324,6 +367,8 @@ class PLUSIEURS_INTO_Panel(PLUSIEURS_Panel):
       self.frame_choix.place(relx=0.6,rely=0.05,relwidth=0.35,relheight=0.7)
       self.frame_boutons = Frame(page)
       self.frame_boutons.place(relx=0.35,rely=0.87,relwidth=0.3,relheight=0.1)
+      self.frame_aide = Frame(page)
+      self.frame_aide.place(relx=0.1,rely=0.75,relwidth=0.9,relheight=0.1)
       liste_commandes_valeurs = (("<Button-1>",self.selectValeur),
                                  ("<Button-3>",self.deselectValeur),
                                  ("<Double-Button-1>",self.sup_valeur))
@@ -357,6 +402,35 @@ class PLUSIEURS_INTO_Panel(PLUSIEURS_Panel):
       for fram in (self.frame_valeurs,self.frame_boutons_fleches,self.frame_choix,self.frame_boutons):
           fram.bind("<Button-3>",lambda e,s=self,a=bulle_aide : s.parent.appli.affiche_aide(e,a))
           fram.bind("<ButtonRelease-3>",self.parent.appli.efface_aide)
+      self.frame_aide.update()
+      self.aide = Label(self.frame_aide,
+                        text = aide,
+                        justify='center',
+                        anchor='center',
+                       wraplength=int(self.frame_aide.winfo_width()*0.8))
+      self.aide.place(relx=0.5,rely=0.5,anchor='center',relwidth=1)
+
+  def get_aide(self):
+      """
+      Retourne la phrase d'aide indiquant de quel type de base doivent être les valeurs
+      que saisit l'utilisateur
+      """
+      mc = self.node.item.get_definition()
+      d_aides = { 'TXM' : 'chaînes de caractères',
+                  'R'   : 'réels',
+                  'I'   : 'entiers',
+                  'C'   : 'complexes'}
+      type = mc.type[0]
+      if not d_aides.has_key(type) : 
+        if mc.min == mc.max:
+           return str(mc.min)+" valeur(s) est(sont) attendue(s)"
+         else :
+           return "entrez entre "+str(mc.min)+" et "+str(mc.max)+" valeurs"
+      if mc.min == mc.max:
+          return "Une liste de "+str(mc.min)+" "+d_aides[type]+" est attendue"
+      else :
+          return "Entre "+str(mc.min)+" et "+str(mc.max)+" valeurs de type  "+d_aides[type]+" sont attendues"
+      return "  "
 
   def get_bulle_aide(self):
       """
@@ -424,12 +498,12 @@ class PLUSIEURS_BASE_Panel(PLUSIEURS_Panel):
       # Création de l'entry ou de la liste des SD
       self.label = Label(self.frame_choix,text="Valeur :")
       self.make_entry(frame = self.frame_choix,command = self.add_valeur_sans_into)
-      self.label.place(relx=0.05,rely=0.5)\r
-      # Création d'un bouton "Importer ..." sur le panel.\r
-      bouton_valeurs_fichier = Button(self.frame_choix,\r
-                                      text="Importer ...",\r
-                                      command=self.select_in_file)\r
-      bouton_valeurs_fichier.place(relx=0.28,rely=0.7,relwidth=0.6)\r
+      self.label.place(relx=0.05,rely=0.5)
+      # Création d'un bouton "Importer ..." sur le panel.
+      bouton_valeurs_fichier = Button(self.frame_choix,
+                                      text="Importer ...",
+                                      command=self.select_in_file)
+      bouton_valeurs_fichier.place(relx=0.28,rely=0.7,relwidth=0.6)
       self.ajout_valeurs = None
       # boutons Ajouter et Supprimer
       bouton_add = Button(self.frame_boutons_fleches,
@@ -441,10 +515,12 @@ class PLUSIEURS_BASE_Panel(PLUSIEURS_Panel):
       bouton_add.place(relx=0.3,rely=0.35)
       bouton_sup.place(relx=0.3,rely=0.65)
       # affichage de l'aide
+      self.frame_aide.update()
       self.aide = Label(self.frame_aide,
                         text = aide,
                         justify='center',
-                        anchor='center')
+                        anchor='center',
+                       wraplength=int(self.frame_aide.winfo_width()*0.8))
       self.aide.place(relx=0.5,rely=0.5,anchor='center',relwidth=1)
       self.Liste_valeurs.affiche_liste()
       # boutons Accepter et Annuler
@@ -456,21 +532,24 @@ class PLUSIEURS_BASE_Panel(PLUSIEURS_Panel):
                               command = self.annule_modifs_valeur)
       for but in (bouton_accepter,bouton_annuler):
           but.pack(side='left',padx=5)
-\r
-  def select_in_file(self):\r
-      """ Permet d'ouvrir un fichier choisi par l'utilisateur. """\r
-      nom_fichier = askopenfilename(title="Choix fichier :")\r
-      if nom_fichier == "":\r
-          return\r
-      try:\r
-          f = open(nom_fichier, "rb")\r
-          selection_texte = f.read()\r
-          f.close()\r
-          self.ajout_valeurs = FenetreDeSelection(self, self.node.item,\r
-                                         titre="Sélection de valeurs",\r
-                                         texte=selection_texte)\r
-      except:\r
-          showinfo("Erreur de fichier","impossible d'ouvir le fichier "+nom_fichier)\r
+
+  def select_in_file(self):
+      """ Permet d'ouvrir un fichier choisi par l'utilisateur. """
+      nom_fichier = askopenfilename(title="Choix fichier :")
+      if nom_fichier == "":
+          return
+      try:
+          f = open(nom_fichier, "rb")
+          selection_texte = f.read()
+          f.close()
+          self.ajout_valeurs = FenetreDeSelection(self, 
+                                                 self.node.item,
+                                                 self.parent.appli,
+                                                 titre="Sélection de valeurs",
+                                                 texte=selection_texte)
+      except:
+          traceback.print_exc()
+          showinfo("Erreur de fichier","impossible d'ouvir le fichier "+nom_fichier)
           
   def get_bulle_aide(self):
       """
@@ -700,22 +779,20 @@ class UNIQUE_Panel(newSIMPPanel):
       if not test :
           mess = "impossible d'évaluer : %s " %`valeur`
           self.parent.appli.affiche_infos("Valeur du mot-clé non autorisée :"+mess)
-          return
       elif self.node.item.isvalid() :
           self.parent.appli.affiche_infos('Valeur du mot-clé enregistrée')
+         if self.node.item.get_position()=='global':
+              self.node.etape.verif_all()
+         elif self.node.item.get_position()=='global_jdc':
+              self.node.racine.verif_all()
+         else :
+              self.node.parent.verif()
+         self.node.update()
           self.node.parent.select()
       else :
           cr = self.node.item.get_cr()
           mess = "Valeur du mot-clé non autorisée :"+cr.get_mess_fatal()
           self.record_valeur(anc_val,mess=mess)
-          return
-      if self.node.item.get_position()=='global':
-          self.node.etape.verif_all()
-      elif self.node.item.get_position()=='global_jdc':
-          self.node.racine.verif_all()
-      else :
-          self.node.parent.verif()
-      self.node.update()
 
 class UNIQUE_INTO_Panel(UNIQUE_Panel):
   """
@@ -761,6 +838,37 @@ class UNIQUE_ASSD_Panel(UNIQUE_Panel):
   Classe servant à définir le panneau associé aux objets qui attendent une valeur unique
   d'un type dérivé d'ASSD
   """
+  def valid_valeur_automatique(self):
+      """
+         Réalise la validation d'un concept sans remonter dans le
+         node parent dans le cas ou il n'y a qu'un concept possible (liste de longueur 1)
+         Identique à valid_valeur moins appel de self.node.parent.select()
+         On pourrait supposer que le seul concept présent est valide et donc ne pas
+         réaliser tous les tests de vérification.
+      """
+      if self.parent.modified == 'n' : self.parent.init_modif()
+      valeur = self.get_valeur()
+      self.erase_valeur()
+      anc_val = self.node.item.get_valeur()
+      test = self.node.item.set_valeur(valeur)
+      if not test :
+          mess = "impossible d'évaluer : %s " %`valeur`
+          self.parent.appli.affiche_infos("Valeur du mot-clé non autorisée :"+mess)
+      elif self.node.item.isvalid() :
+          self.parent.appli.affiche_infos('Valeur du mot-clé enregistrée')
+          if self.node.item.get_position()=='global':
+              self.node.etape.verif_all()
+          elif self.node.item.get_position()=='global_jdc':
+              self.node.racine.verif_all()
+          else :
+              self.node.parent.verif()
+          self.node.update()
+          #self.node.parent.select()
+      else :
+          cr = self.node.item.get_cr()
+          mess = "Valeur du mot-clé non autorisée :"+cr.get_mess_fatal()
+          self.record_valeur(anc_val,mess=mess)
+
   def makeValeurPage(self,page):
       """
           Génère la page de saisie de la valeur du mot-clé simple courant qui doit être une 
@@ -775,6 +883,12 @@ class UNIQUE_ASSD_Panel(UNIQUE_Panel):
       # Remplissage du panneau
       self.valeur_choisie = StringVar()
       self.valeur_choisie.set('')
+      min,max =  self.node.item.GetMinMax()
+      if (min == 1 and min == max and len(liste_noms_sd)==1):
+          if self.valeur_choisie.get() != liste_noms_sd[0]:
+            self.valeur_choisie.set(liste_noms_sd[0])
+             self.valid_valeur_automatique()
+        
       self.frame_valeur = Frame(page)
       self.frame_valeur.pack(fill='both',expand=1)
       self.frame_valeur.bind("<Button-3>",lambda e,s=self,a=bulle_aide : s.parent.appli.affiche_aide(e,a))
@@ -878,7 +992,7 @@ class UNIQUE_SDCO_Panel(UNIQUE_ASSD_Panel):
       self.listbox.place(relx=0.5,rely=0.3,relheight=0.4,anchor='center')
       # affichage du bouton 'Nouveau concept'
       self.b_co = Pmw.OptionMenu(self.frame_valeur,labelpos='w',label_text = "Nouveau concept : ",
-                                 items = ('OUI','NON'),menubutton_width=10)
+                                 items = ('NON','OUI'),menubutton_width=10)
       self.b_co.configure(command = lambda e,s=self : s.ask_new_concept())
       self.b_co.place(relx=0.05,rely=0.6,anchor='w')
       self.label_co = Label(self.frame_valeur,text='Nom du nouveau concept :')
@@ -888,9 +1002,12 @@ class UNIQUE_SDCO_Panel(UNIQUE_ASSD_Panel):
       self.l_resu = Label(self.frame_valeur,text='Structure de donnée choisie :')
       self.valeur_choisie = StringVar()
       self.label_valeur = Label(self.frame_valeur,textvariable=self.valeur_choisie)
-      self.aide = Label(self.frame_valeur, text = aide)
+      self.frame_valeur.update()
+      self.aide = Label(self.frame_valeur,
+                        text = aide,
+                       wraplength=int(self.frame_valeur.winfo_width()*0.8),
+                       justify='center')
       self.aide.place(relx=0.5,rely=0.85,anchor='n')
-      self.b_co.invoke('NON')
       # affichage de la valeur courante
       self.display_valeur()
       
@@ -902,13 +1019,66 @@ class UNIQUE_SDCO_Panel(UNIQUE_ASSD_Panel):
       pour valoriser le mot-clé simple courant ou cliquez sur NOUVEAU CONCEPT pour
       entrer le nom d'un concept non encore existant"""
 
+  def valid_valeur(self):
+      """
+      Teste si la valeur fournie par l'utilisateur est une valeur permise :
+      - si oui, l'enregistre
+      - si non, restaure l'ancienne valeur
+      """
+      if self.parent.modified == 'n' : self.parent.init_modif()
+      valeur = self.get_valeur()
+      self.erase_valeur()
+      anc_val = self.node.item.get_valeur()
+      test_CO=self.node.item.is_CO(anc_val)
+      test = self.node.item.set_valeur(valeur)
+      if not test :
+          mess = "impossible d'évaluer : %s " %`valeur`
+          self.parent.appli.affiche_infos("Valeur du mot-clé non autorisée :"+mess)
+          return
+      elif self.node.item.isvalid() :
+          self.parent.appli.affiche_infos('Valeur du mot-clé enregistrée')
+          if test_CO:
+             # il faut egalement propager la destruction de l'ancien concept
+             self.node.item.delete_valeur_co(valeur=anc_val)
+             # et on force le recalcul des concepts de sortie de l'etape
+             self.node.item.object.etape.get_type_produit(force=1)
+             # et le recalcul du contexte
+             self.node.item.object.etape.parent.reset_context()
+          self.node.parent.select()
+      else :
+          cr = self.node.item.get_cr()
+          mess = "Valeur du mot-clé non autorisée :"+cr.get_mess_fatal()
+          self.record_valeur(anc_val,mess=mess)
+          return
+      if self.node.item.get_position()=='global':
+          self.node.etape.verif_all()
+      elif self.node.item.get_position()=='global_jdc':
+          self.node.racine.verif_all()
+      else :
+          self.node.parent.verif()
+      self.node.update()
+
   def valid_nom_concept_co(self,event=None):
       """
       Lit le nom donné par l'utilisateur au concept de type CO qui doit être
       la valeur du MCS courant et stocke cette valeur
       """
+      if self.parent.modified == 'n' : self.parent.init_modif()
+      anc_val = self.node.item.get_valeur()
       nom_concept = self.entry_co.get()
-      self.node.item.set_valeur_co(nom_concept)
+      test,mess=self.node.item.set_valeur_co(nom_concept)
+      if not test:
+          # On n'a pas pu créer le concept
+          self.parent.appli.affiche_infos(mess)
+          return
+      elif self.node.item.isvalid() :
+          self.parent.appli.affiche_infos('Valeur du mot-clé enregistrée')
+          self.node.parent.select()
+      else :
+          cr = self.node.item.get_cr()
+          mess = "Valeur du mot-clé non autorisée :"+cr.get_mess_fatal()
+          self.record_valeur(anc_val,mess=mess)
+          return
       if self.node.item.get_position()=='global':
           self.node.etape.verif_all()
       elif self.node.item.get_position()=='global_jdc':
@@ -932,24 +1102,56 @@ class UNIQUE_SDCO_Panel(UNIQUE_ASSD_Panel):
           self.label_valeur.place_forget()
           self.entry_co.focus()
       elif new_concept == 'NON':
-          self.label_co.place_forget()
-          self.entry_co.place_forget()
-          self.l_resu.place(relx=0.05,rely=0.7)
-          self.label_valeur.place(relx=0.45,rely=0.7)
+          # On est passe de OUI à NON, on supprime la valeur
+# PN correction de bug (on passe de non a non et cela supprime la valeur)
+# ajout du if de le ligne suivane
+          if self.node.item.is_CO():
+                self.node.item.delete_valeur_co()
+                self.record_valeur(name=None,mess="Suppression CO enregistrée")
+                self.label_co.place_forget()
+                self.entry_co.place_forget()
+                self.l_resu.place(relx=0.05,rely=0.7)
+                self.label_valeur.place(relx=0.45,rely=0.7)
           
   def display_valeur(self):
       """
       Affiche la valeur de l'objet pointé par self
       """
       valeur = self.node.item.get_valeur()
-      if valeur == None : return # pas de valeur à afficher ...
+      if valeur == None or valeur == '': 
+         self.valeur_choisie.set('')
+         return # pas de valeur à afficher ...
       # il faut configurer le bouton si la valeur est un objet CO
       # sinon afficher le nom du concept dans self.valeur_choisie
-      if valeur.__class__.__name__ != 'CO':
-          self.valeur_choisie.set(valeur.nom)
-      else:
+      if self.node.item.is_CO():
           self.b_co.invoke('OUI')
           self.entry_co.insert(0,valeur.nom)
+      else:
+          self.valeur_choisie.set(valeur.nom)
+
+  def record_valeur(self,name=None,mess='Valeur du mot-clé enregistrée'):
+      """
+      Enregistre  val comme valeur de self.node.item.object SANS faire de test de validité
+      """
+      if self.parent.modified == 'n' : self.parent.init_modif()
+      if name != None:
+          valeur =name
+      else :
+          self.entry_co.delete(0,END)
+          valeur= self.entry_co.get()
+      self.node.item.set_valeur_co(valeur)
+      self.parent.appli.affiche_infos(mess)
+      # On met a jour le display dans le panneau
+      self.display_valeur()
+      if self.node.item.get_position()=='global':
+          self.node.etape.verif_all()
+      elif self.node.item.get_position()=='global_jdc':
+          self.node.racine.verif_all()
+      else :
+          self.node.parent.verif()
+      if self.node.item.isvalid():
+          self.node.parent.select()
+      self.node.update()
 
 
 class UNIQUE_BASE_Panel(UNIQUE_Panel):
@@ -980,7 +1182,11 @@ class UNIQUE_BASE_Panel(UNIQUE_Panel):
       self.entry.bind("<Return>",lambda e,c=self.valid_valeur:c())
       self.entry.focus()
       # aide associée au panneau
-      self.aide = Label(self.frame_valeur, text = aide)
+      self.frame_valeur.update()
+      self.aide = Label(self.frame_valeur, 
+                        text = aide,
+                       wraplength=int(self.frame_valeur.winfo_width()*0.8),
+                       justify='center')
       self.aide.place(relx=0.5,rely=0.7,anchor='n')
       # affichage de la valeur du MCS
       self.display_valeur()
@@ -1012,6 +1218,7 @@ class UNIQUE_BASE_Panel(UNIQUE_Panel):
       if valeur == None : return # pas de valeur à afficher ...
       self.entry.delete(0,END)
       self.entry.insert(0,valeur)
+      self.entry.focus()
       
 class UNIQUE_COMP_Panel(UNIQUE_Panel):
   """
@@ -1047,7 +1254,11 @@ class UNIQUE_COMP_Panel(UNIQUE_Panel):
       self.entry1.place(relx=0.27,rely = 0.5,relwidth=0.35)
       self.entry2.place(relx=0.65,rely = 0.5,relwidth=0.35)
       self.entry1.focus()
-      self.aide = Label(self.frame_valeur, text = aide)
+      self.frame_valeur.update()
+      self.aide = Label(self.frame_valeur,
+                        text = aide,
+                        wraplength=int(self.frame_valeur.winfo_width()*0.8),
+                       justify='center')
       self.aide.place(relx=0.5,rely=0.7,anchor='n')
 
   def get_bulle_aide(self):
@@ -1096,13 +1307,18 @@ class SIMPTreeItem(Objecttreeitem.AtomicObjectTreeItem):
       Cette méthode attribue le panel à l'objet pointé par self en fonction de la
       nature de la valeur demandée pour cet objet
       """
+      print "affect_panel : ",self.nom,self.is_list(),self.has_into(), self.get_into(None)
       if self.wait_shell():
           # l'objet attend un shell
           self.panel = SHELLPanel
       elif self.wait_into():
           # l'objet prend sa (ses) valeur(s) dans un ensemble discret de valeurs
           min,max = self.GetMinMax()
-          if max != 1 and ((min != 0 and min != max) or (min == 0)):
+          # PN : 
+          # Remplacement du if ??
+          #if max != 1 and ((min != 0 and min != max) or (min == 0)):
+          assert (min <= max)
+          if max > 1 :
              # l'objet attend une liste de valeurs
              self.panel = PLUSIEURS_INTO_Panel
           else:
@@ -1135,7 +1351,6 @@ class SIMPTreeItem(Objecttreeitem.AtomicObjectTreeItem):
                   else:
                       # on attend un entier, un réel ou une string
                       self.panel = UNIQUE_BASE_Panel
-
       
   def SetText(self, text):
     try:
@@ -1158,7 +1373,81 @@ class SIMPTreeItem(Objecttreeitem.AtomicObjectTreeItem):
     Retourne le texte à afficher dans l'arbre représentant la valeur de l'objet
     pointé par self 
     """
-    return self.object.GetText()
+    text= self.object.GetText()
+    return text
+
+  def has_into(self):
+      """
+          Cette méthode indique si le mot cle simple propose un choix (valeur de retour 1)
+          ou s'il n'en propose pas (valeur de retour 0)
+
+          Deux cas principaux peuvent se presenter : avec validateurs ou bien sans.
+          Dans le cas sans validateur, l'information est donnée par l'attribut into
+          de la definition du mot cle.
+          Dans le cas avec validateur, il faut combiner l'information précédente avec
+          celle issue de l'appel de la méthode has_into sur le validateur. On utilisera
+          l'operateur ET pour effectuer cette combinaison (AndVal).
+      """
+      if not self.object.definition.validators:
+           if self.definition.into:
+               return 1
+           else:
+               return 0
+      else:
+           # Dans le cas avec validateurs, pour que le mot cle soit considéré
+           # comme proposant un choix, il faut que into soit présent OU
+           # que la méthode has_into du validateur retourne 1. Dans les autres cas
+           # on retournera 0 (ne propose pas de choix)
+           if self.definition.into:
+                return 1
+           elif self.object.definition.validators.has_into():
+                return 1
+           else:
+                return 0
+
+  def get_into(self,liste_courante=None):
+      """
+          Cette méthode retourne la liste de choix proposée par le mot cle. Si le mot cle ne propose
+          pas de liste de choix, la méthode retourne None.
+          L'argument d'entrée liste_courante, s'il est différent de None, donne la liste des choix déjà
+          effectués par l'utilisateur. Dans ce cas, la méthode get_into doit calculer la liste des choix
+          en en tenant compte.
+          Cette méthode part du principe que la relation entre into du mot clé et les validateurs est
+          une relation de type ET (AndVal).
+      """
+      if not self.object.definition.validators :
+         return self.object.definition.into
+      else:
+         return self.object.definition.validators.get_into(liste_courante,self.definition.into)
+         
+  def is_list(self):
+      """
+          Cette méthode indique si le mot cle simple attend une liste (valeur de retour 1)
+          ou s'il n'en attend pas (valeur de retour 0)
+
+          Deux cas principaux peuvent se presenter : avec validateurs ou bien sans.
+          Dans le cas sans validateur, l'information est donnée par l'attribut max 
+          de la definition du mot cle.
+          Dans le cas avec validateur, il faut combiner l'information précédente avec
+          celle issue de l'appel de la méthode is_list sur le validateur.On utilisera
+          l'operateur ET pour effectuer cette combinaison (AndVal).
+      """
+      if not self.object.definition.validators:
+           if self.definition.max <= 1:
+               return 0
+           else: 
+               return 1
+      else:
+           # Dans le cas avec validateurs, pour que le mot cle soit considéré 
+           # comme acceptant une liste, il faut que max soit supérieur a 1
+           # ET que la méthode is_list du validateur retourne 1. Dans les autres cas
+           # on retournera 0 (n'attend pas de liste)
+           if self.definition.max <= 1:
+                return 0
+           elif not self.object.definition.validators.is_list():
+                return 0
+           else:
+                return 1
 
   def wait_co(self):
       """
@@ -1218,42 +1507,47 @@ class SIMPTreeItem(Objecttreeitem.AtomicObjectTreeItem):
   def GetMinMax(self):
       """ Retourne les valeurs min et max de la définition de object """
       return self.object.get_min_max()
-\r
-  def GetMultiplicite(self):\r
-      """ A préciser.\r
-          Retourne la multiplicité des valeurs affectées à l'objet\r
-          représenté par l'item. Pour le moment retourne invariablement 1.\r
-      """\r
-      return 1\r
-\r
-  def GetType(self):\r
-      """ Retourne le type de valeur attendu par l'objet représenté par l'item.\r
-      """\r
-      return self.object.get_type()\r
-\r
-  def GetIntervalle(self):\r
-      """ Retourne le domaine de valeur attendu par l'objet représenté par l'item.\r
-      """\r
-      return self.object.getintervalle()\r
-\r
-  def IsInIntervalle(self,valeur):\r
-      """ Retourne 1 si la valeur est dans l'intervalle permis par\r
-          l'objet représenté par l'item.\r
-      """\r
-      return self.object.isinintervalle(valeur)\r
+
+  def GetMultiplicite(self):
+      """ A préciser.
+          Retourne la multiplicité des valeurs affectées à l'objet
+          représenté par l'item. Pour le moment retourne invariablement 1.
+      """
+      return 1
+
+  def GetType(self):
+      """ 
+          Retourne le type de valeur attendu par l'objet représenté par l'item.
+      """
+      return self.object.get_type()
+
+  def GetIntervalle(self):
+      """ 
+           Retourne le domaine de valeur attendu par l'objet représenté 
+           par l'item.
+      """
+      return self.object.getintervalle()
+
+  def IsInIntervalle(self,valeur):
+      """ 
+          Retourne 1 si la valeur est dans l'intervalle permis par
+          l'objet représenté par l'item.
+      """
+      return self.object.isinintervalle(valeur)
 
   def set_valeur_co(self,nom_co):
       """
       Affecte au MCS pointé par self l'objet de type CO et de nom nom_co
       """
-      self.object.set_valeur_co(nom_co)
+      return self.object.set_valeur_co(nom_co)
       
   def get_sd_avant_du_bon_type(self):
       """
       Retourne la liste des noms des SD présentes avant l'étape qui contient
       le MCS pointé par self et du type requis par ce MCS
       """
-      return self.object.jdc.get_sd_avant_du_bon_type(self.object.etape,self.object.definition.type)
+      return self.object.etape.parent.get_sd_avant_du_bon_type(self.object.etape,
+                                                               self.object.definition.type)
     
   def GetListeValeurs(self) :
       """ Retourne la liste des valeurs de object """
@@ -1272,6 +1566,34 @@ class SIMPTreeItem(Objecttreeitem.AtomicObjectTreeItem):
         - retourne 'valeur' (chaîne de caractères) sinon """
       return self.object.eval_valeur(valeur)
 
+  def is_CO(self,valeur=None):
+      """
+         Indique si valeur est un concept produit de la macro
+         Cette méthode n'a de sens que pour un MCSIMP d'une MACRO
+         Si valeur vaut None on teste la valeur du mot cle
+      """
+      # Pour savoir si un concept est un nouveau concept de macro
+      # on regarde s'il est présent dans l'attribut sdprods de l'étape
+      # ou si son nom de classe est CO.
+      # Il faut faire les 2 tests car une macro non valide peut etre
+      # dans un etat pas tres catholique avec des CO pas encore types
+      # et donc pas dans sdprods (resultat d'une exception dans type_sdprod)
+      if not valeur:valeur=self.object.valeur
+      if valeur in self.object.etape.sdprods:return 1
+      if type(valeur) is not types.ClassType:return 0
+      if valeur.__class__.__name__ == 'CO':return 1
+      return 0
+
+  def delete_valeur_co(self,valeur=None):
+      """
+           Supprime la valeur du mot cle (de type CO)
+           il faut propager la destruction aux autres etapes
+      """
+      if not valeur : valeur=self.object.valeur
+      # XXX faut il vraiment appeler del_sdprod ???
+      #self.object.etape.parent.del_sdprod(valeur)
+      self.object.etape.parent.delete_concept(valeur)
+
 import Accas
 treeitem = SIMPTreeItem
 objet = Accas.MCSIMP