]> SALOME platform Git repositories - tools/eficas.git/commitdiff
Salome HOME
CCAR: Modified Files:
authoreficas <>
Wed, 6 Nov 2002 17:46:09 +0000 (17:46 +0000)
committereficas <>
Wed, 6 Nov 2002 17:46:09 +0000 (17:46 +0000)
CCAR:  I_ETAPE.py I_FORM_ETAPE.py I_JDC.py I_MACRO_ETAPE.py
CCAR:  I_MCCOMPO.py I_MCLIST.py I_MCSIMP.py I_PROC_ETAPE.py
CCAR: ----------------------------------------------------------------------
CCAR : developpement pour traiter correctement l'insertion
et la destruction des macros avec etapes et concepts inclus.
Ces INCLUDEs sont evalués dans un JDC auxiliaire avant
d'etre insérées définitivement dans la macro apres verification.

Ihm/I_ETAPE.py
Ihm/I_FORM_ETAPE.py
Ihm/I_JDC.py
Ihm/I_MACRO_ETAPE.py
Ihm/I_MCCOMPO.py
Ihm/I_MCLIST.py
Ihm/I_MCSIMP.py
Ihm/I_PROC_ETAPE.py

index 865f23787f588046360cba94273bfcea0ef4f255..5ccb189e1ae94296e2966777f6947f7b925c927f 100644 (file)
@@ -20,6 +20,7 @@
 """
 """
 # Modules Python
+import sys
 import string,types
 from copy import copy
 
@@ -40,10 +41,11 @@ class ETAPE(I_MCCOMPO.MCCOMPO):
 
    def get_sdname(self):
       if CONTEXT.debug : print "SDNAME ",self.reuse,self.sd,self.sd.get_name()
+      sdname=''
       if self.reuse != None:
         sdname= self.reuse.get_name()
       else:
-        sdname=self.sd.get_name()
+        if self.sd:sdname=self.sd.get_name()
       if string.find(sdname,'sansnom') != -1 or string.find(sdname,'SD_') != -1:
         # dans le cas où la SD est 'sansnom' ou 'SD_' on retourne la chaîne vide
         return ''
@@ -59,7 +61,6 @@ class ETAPE(I_MCCOMPO.MCCOMPO):
       """
          Met l'état de l'étape à : modifié
          Propage la modification au parent
-         Si la fonction op_init existe, l'active
       """
       # Une action
       # doit etre realisée apres init_modif et la validite reevaluée
@@ -76,11 +77,10 @@ class ETAPE(I_MCCOMPO.MCCOMPO):
           ex : INCLUDE et POURSUITE
       """
       if self.isvalid() :
-         if type(self.definition.op_init) == types.FunctionType :
-            # XXX Normalement en mode editeur g_context ne peut pas etre utilisé
-            apply(self.definition.op_init,(self,self.parent.g_context))   
-      self.state = 'modified'
-    
+         d=self.parent.get_contexte_apres(self)
+      if self.parent:
+        self.parent.fin_modif()
+
    def nomme_sd(self,nom) :
       """
           Cette méthode a pour fonction de donner un nom (nom) au concept 
@@ -190,9 +190,9 @@ class ETAPE(I_MCCOMPO.MCCOMPO):
           Il faut ajouter la sd si elle existe au contexte global du JDC
           et à la liste des sd
       """
+      if self.actif:return
       self.actif = 1
       if not self.sd : return
-      # XXX Pourquoi faut-il faire ce qui suit ??? par defaut les etapes sont actives
       try:
         self.jdc.append_sdprod(self.sd)
       except:
@@ -209,6 +209,31 @@ class ETAPE(I_MCCOMPO.MCCOMPO):
       self.jdc.del_sdprod(self.sd)
       self.jdc.delete_concept_after_etape(self,self.sd)
 
+   def control_sdprods(self,d):
+      """
+          Cette methode doit updater le contexte fournit par
+          l'appelant en argument (d) en fonction de sa definition
+          tout en verifiant que ses concepts produits ne sont pas 
+          deja definis dans le contexte
+      """
+      if type(self.definition.op_init) == types.FunctionType:
+        apply(self.definition.op_init,(self,d))
+      if self.sd:
+        if d.has_key(self.sd.nom):
+           # Le concept est deja defini
+           if self.reuse and self.reuse is d[self.sd.nom]:
+              # Le concept est reutilise : situation normale
+              pass
+           else:
+              # Redefinition du concept, on l'annule
+              #XXX on pourrait simplement annuler son nom pour conserver les objets
+              # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
+              self.sd=self.reuse=self.sdnom=None
+              self.init_modif()
+        else:
+           # Le concept n'est pas defini, on peut updater d
+           d[self.sd.nom]=self.sd
+
    def supprime_sdprods(self):
       """ 
           Fonction:
@@ -217,8 +242,6 @@ class ETAPE(I_MCCOMPO.MCCOMPO):
             Une procedure n'en a aucun
             Une macro en a en général plus d'un
       """
-      # XXX pour les macros il faudrait peut etre aussi 
-      #     supprimer les concepts a droite du = ???
       if not self.is_reentrant() :
         # l'étape n'est pas réentrante
         # le concept retourné par l'étape est à supprimer car il était 
@@ -244,6 +267,22 @@ class ETAPE(I_MCCOMPO.MCCOMPO):
       for child in self.mc_liste :
         child.delete_concept(sd)
 
+   def replace_concept(self,old_sd,sd):
+      """
+          Inputs :
+             old_sd=concept remplace
+             sd = nouveau concept 
+          Fonction :
+             Mettre a jour les mots cles de l etape et eventuellement
+             le concept produit si reuse
+             suite au remplacement  du concept old_sd
+      """
+      if self.reuse and self.reuse == old_sd:
+        self.sd=self.reuse=sd
+        self.init_modif()
+      for child in self.mc_liste :
+        child.replace_concept(old_sd,sd)
+
    def make_register(self):
       """
          Initialise les attributs jdc, id, niveau et réalise les
@@ -392,8 +431,10 @@ class ETAPE(I_MCCOMPO.MCCOMPO):
          # En plus il faut rendre coherents sdnom et sd.nom
          self.sd=None
          self.sdnom=None
+         self.state="unchanged"
          self.valid=0
          return self.sd
+
          #raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
          #                     'fichier : ',self.appel[1],e)
       except EOFError:
index 80689be47b094e2a2a9f7cb867c448fded02386b..b76b4b5a39d1b178f5f87a5e32ff29c3c5be3b30 100644 (file)
@@ -262,7 +262,7 @@ class FORM_ETAPE(MACRO_ETAPE):
          Inputs :
            sd=concept detruit
          Fonction :
-           Mettre a jour les mos cles de l etape et eventuellement le concept produit si reuse
+           Mettre a jour les mots cles de l etape et eventuellement le concept produit si reuse
            suite à la disparition du concept sd
            Seuls les mots cles simples MCSIMP font un traitement autre que de transmettre aux fils,
           sauf les objets FORM_ETAPE qui doivent vérifier que le concept détruit n'est pas 
@@ -270,3 +270,14 @@ class FORM_ETAPE(MACRO_ETAPE):
         """
         self.init_modif()
          
+    def replace_concept(self,old_sd,sd):
+        """
+         Inputs :
+           old_sd=concept remplace
+           sd = nouveau concept
+         Fonction :
+           Les objets FORM_ETAPE devraient vérifier que le concept remplacé n'est pas
+           utilisé dans le corps de la fonction
+        """
+        self.init_modif()
+
index 125fb617ae512bee9e742dffefc287744122cf89..3b895351758d0a9014f6971fa23fd955212db033 100644 (file)
@@ -216,6 +216,57 @@ class JDC(I_OBJECT.OBJECT):
       if sd:return sd
       return self.get_sd_apres_etape(nom_sd,etape,avec)
 
+   def get_contexte_avant(self,etape):
+      """
+         Retourne le dictionnaire des concepts connus avant etape
+         On tient compte des commandes qui modifient le contexte
+         comme DETRUIRE ou les macros
+         Si etape == None, on retourne le contexte en fin de JDC
+      """
+      # L'étape courante pour laquelle le contexte a été calculé est
+      # mémorisée dans self.index_etape_courante
+      # XXX on pourrait faire mieux dans le cas PAR_LOT="NON" : en
+      # mémorisant l'étape
+      # courante pendant le processus de construction des étapes.
+      # Si on insère des commandes (par ex, dans EFICAS), il faut préalablement
+      # remettre ce pointeur à 0
+      if etape:
+         index_etape=self.etapes.index(etape)
+      else:
+         index_etape=len(self.etapes)
+      if index_etape >= self.index_etape_courante:
+         # On calcule le contexte en partant du contexte existant
+         d=self.current_context
+         if self.index_etape_courante==0 and self.context_ini:
+            d.update(self.context_ini)
+         liste_etapes=self.etapes[self.index_etape_courante:index_etape]
+      else:
+         d=self.current_context={}
+         if self.context_ini:d.update(self.context_ini)
+         liste_etapes=self.etapes
+
+      for e in liste_etapes:
+         if e is etape:
+            break
+         if e.isactif():
+            e.update_context(d)
+      self.index_etape_courante=index_etape
+      return d
+
+   def get_contexte_apres(self,etape):
+      """
+         Retourne le dictionnaire des concepts connus apres etape
+         On tient compte des commandes qui modifient le contexte
+         comme DETRUIRE ou les macros
+         Si etape == None, on retourne le contexte en fin de JDC
+      """
+      if not etape: return self.get_contexte_avant(etape)
+
+      d=self.get_contexte_avant(etape)
+      if etape.isactif():etape.update_context(d)
+      self.index_etape_courante=self.index_etape_courante+1
+      return d
+
    def active_etapes(self):
       """
           Cette méthode a pour fonction de désactiver les étapes qui doivent
@@ -245,6 +296,10 @@ class JDC(I_OBJECT.OBJECT):
           un jeu de commandes
       """
       self.init_modif()
+      # On memorise le contexte avant l'etape a supprimer
+      d=self.get_contexte_avant(etape)
+      index_etape=self.etapes.index(etape)
+
       self.etapes.remove(etape)
       if etape.niveau is not self:
         # Dans ce cas l'étape est enregistrée dans un niveau
@@ -253,25 +308,13 @@ class JDC(I_OBJECT.OBJECT):
       etape.supprime_sdprods()
       self.active_etapes()
 
-   def del_sdprod(self,sd):
-      """
-          Supprime la SD sd de la liste des sd et des dictionnaires de contexte
-      """
-      if sd in self.sds : self.sds.remove(sd)
-      if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
-
-   def delete_concept(self,sd):
-      """ 
-          Inputs :
-             sd=concept detruit
-          Fonction :
-             Mettre a jour les etapes du JDC suite à la disparition du 
-             concept sd
-             Seuls les mots cles simples MCSIMP font un traitement autre 
-             que de transmettre aux fils
-      """
-      for etape in self.etapes :
-        etape.delete_concept(sd)
+      # Apres suppression de l'etape il faut controler que les etapes
+      # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape
+      for e in self.etapes[index_etape:]:
+         e.control_sdprods(d)
+      
+      self.reset_context()
+      self.fin_modif()
 
    def analyse(self):
       self.compile()
@@ -368,17 +411,6 @@ class JDC(I_OBJECT.OBJECT):
       if self.appli:
          self.appli.send_message(message)
 
-#XXX ne semble pas servir pour JDC
-#   def reevalue_sd_jdc(self):
-      #""" 
-          #Avec la liste des SD qui ont été supprimées, propage la disparition de ces
-          #SD dans toutes les étapes et descendants
-      #"""
-      #l_sd = self.diff_contextes()
-      #if len(l_sd) == 0 : return
-      #for sd in l_sd:
-        #self.jdc.delete_concept(sd)
-
    def init_modif(self):
       """
       Méthode appelée au moment où une modification va être faite afin de 
@@ -387,6 +419,7 @@ class JDC(I_OBJECT.OBJECT):
       self.state = 'modified'
 
    def fin_modif(self):
+      self.isvalid()
       pass
 
    def get_liste_mc_inconnus(self):
@@ -423,6 +456,7 @@ class JDC(I_OBJECT.OBJECT):
          fproc=open(file,'r')
          text=fproc.read()
          fproc.close()
+      if file == None : return None,None
       text=string.replace(text,'\r\n','\n')
       linecache.cache[file]=0,0,string.split(text,'\n'),file
       return file,text
@@ -435,30 +469,34 @@ class JDC(I_OBJECT.OBJECT):
       """
       return []
 
-   def NommerSdprod(self,sd,sdnom):
+   def NommerSdprod(self,sd,sdnom,restrict='non'):
       """
-          Nomme la SD apres avoir verifie que le nommage est possible : nom
-          non utilise
+          Nomme la SD apres avoir verifie que le nommage est possible : 
+          nom non utilise
           Si le nom est deja utilise, leve une exception
           Met le concept créé dans le concept global g_context
       """
       # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
       # Le dictionnaire g_context ne représente pas le contexte
       # effectif avant une étape.
-      # Il faut utiliser get_contexte_avant avec une indication de l'étape
-      # traitée. Pour le moment, il n'y a pas de moyen de le faire : ajouter 
-      # un attribut dans le JDC ???
+      # Il faut utiliser get_contexte_avant avec indication de l'étape
+      # traitée. 
+      # Cette etape est indiquee par l'attribut _etape_context qui a ete 
+      # positionné préalablement par un appel à set_etape_context
+
       if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
+
       if self._etape_context:
          o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
       else:
-         o=self.g_context.get(sdnom,None)
+         o=self.sds_dict.get(sdnom,None)
+
       if isinstance(o,ASSD):
          raise AsException("Nom de concept deja defini : %s" % sdnom)
 
       # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
       # Ajoute a la creation (appel de reg_sd).
-      self.g_context[sdnom]=sd
+      self.sds_dict[sdnom]=sd
       sd.nom=sdnom
 
    def set_etape_context(self,etape):
@@ -477,6 +515,14 @@ class JDC(I_OBJECT.OBJECT):
       self.current_context={}
       self.index_etape_courante=0
 
+   def del_sdprod(self,sd):
+      """
+          Supprime la SD sd de la liste des sd et des dictionnaires de contexte
+      """
+      if sd in self.sds : self.sds.remove(sd)
+      if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
+      if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
+
    def del_param(self,param):
       """
           Supprime le paramètre param de la liste des paramètres
@@ -493,3 +539,101 @@ class JDC(I_OBJECT.OBJECT):
       if fonction in self.fonctions : self.fonctions.remove(fonction)
       if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
 
+   def append_sdprod(self,sd):
+      """
+          Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
+          même nom n'existe pas déjà
+      """
+      if sd == None or sd.nom == None:return
+
+      o=self.sds_dict.get(sd.nom,None)
+      if isinstance(o,ASSD):
+         raise AsException("Nom de concept deja defini : %s" % sd.nom)
+      self.sds_dict[sd.nom]=sd
+      self.g_context[sd.nom] = sd
+      if sd not in self.sds : self.sds.append(sd)
+
+   def append_param(self,param):
+      """
+          Ajoute le paramètre param à la liste des params
+          et au contexte global
+      """
+      # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
+      if param not in self.params : self.params.append(param)
+      self.g_context[param.nom]=param
+
+   def append_fonction(self,fonction):
+      """
+          Ajoute la fonction fonction à la liste des fonctions
+          et au contexte global
+      """
+      # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
+      if fonction not in self.fonctions : self.fonctions.append(fonction)
+      self.g_context[fonction.nom]=fonction
+
+   def delete_concept_after_etape(self,etape,sd):
+      """
+          Met à jour les étapes du JDC qui sont après etape en fonction
+          de la disparition du concept sd
+      """
+      index = self.etapes.index(etape)+1
+      if index == len(self.etapes) : 
+         return # etape est la dernière étape du jdc ...on ne fait rien !
+      for child in self.etapes[index:]:
+        child.delete_concept(sd)
+
+   def delete_concept(self,sd):
+      """
+          Inputs :
+             sd=concept detruit
+          Fonction :
+             Mettre a jour les etapes du JDC suite à la disparition du
+             concept sd
+             Seuls les mots cles simples MCSIMP font un traitement autre
+             que de transmettre aux fils
+      """
+      for etape in self.etapes :
+        etape.delete_concept(sd)
+
+   def replace_concept_after_etape(self,etape,old_sd,sd):
+      """
+          Met à jour les étapes du JDC qui sont après etape en fonction
+          du remplacement du concept sd
+      """
+      index = self.etapes.index(etape)+1
+      if index == len(self.etapes) :
+         return # etape est la dernière étape du jdc ...on ne fait rien !
+      for child in self.etapes[index:]:
+        child.replace_concept(old_sd,sd)
+
+   def dump_state(self):
+      print "dump_state"
+      print "JDC.state: ",self.state
+      for etape in self.etapes :
+         print etape.nom+".state: ",etape.state
+      
+#ATTENTION cette methode surcharge la methode du package Validation : a reintegrer
+   def isvalid(self,cr='non'):
+      """
+        Méthode booléenne qui retourne 0 si le JDC est invalide, 1 sinon
+      """
+      # FR : on prend en compte l'état du JDC ('unchanged','modified','undetermined')
+      # afin d'accélérer le test de validité du JDC
+      if self.state == 'unchanged':
+        return self.valid
+      else:
+        valid = 1
+        texte,test = self.verif_regles()
+        if test == 0:
+          if cr == 'oui': self.cr.fatal(string.strip(texte))
+          valid = 0
+        if valid :
+          for e in self.etapes:
+            if not e.isactif() : continue
+            if not e.isvalid():
+              valid = 0
+              break
+        self.state="unchanged"
+        self.valid = valid
+        return self.valid
+
index 1fd95f5ea63438705876491948d486d10467a186..5c00db692345551efc443def8dd0d5a5ae72711d 100644 (file)
@@ -20,6 +20,7 @@
 """
 """
 # Modules Python
+import sys
 import traceback,types,string
 
 # Modules Eficas
@@ -27,7 +28,7 @@ import I_ETAPE
 from Noyau.N_ASSD import ASSD
 
 # import rajoutés suite à l'ajout de Build_sd --> à résorber
-import Noyau
+import Noyau, Validation.V_MACRO_ETAPE
 from Noyau import N_Exception
 from Noyau.N_Exception import AsException
 # fin import à résorber
@@ -35,8 +36,6 @@ from Noyau.N_Exception import AsException
 class MACRO_ETAPE(I_ETAPE.ETAPE):
 
   def __init__(self):
-      # XXX CCAR : ne suis pas certain que typret doive etre 
-      # initialise à None (a verifier)
       self.typret=None
 
   def get_sdprods(self,nom_sd):
@@ -44,73 +43,90 @@ class MACRO_ETAPE(I_ETAPE.ETAPE):
          Fonction : retourne le concept produit par l etape de nom nom_sd
                     s il existe sinon None
     """
-    if self.sd:
-      if self.sd.nom == nom_sd:
-         return self.sd
+    if self.sd and self.sd.nom == nom_sd :return self.sd
     for co in self.sdprods:
-      if co.nom==nom_sd:return co
+      if co.nom == nom_sd:return co
+    if type(self.definition.op_init) == types.FunctionType:
+      d={}
+      apply(self.definition.op_init,(self,d))
+      return d.get(nom_sd,None)
     return None
 
-  def make_contexte(self,fichier,text):    
-    """
-        Cette méthode sert à créer un contexte en interprétant un texte source
-        Python
-    """
-    # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
-    contexte = self.get_contexte_jdc(fichier,text)
-    if contexte == None :
-      raise Exception("Impossible de relire le fichier")
-    else:
-      self.g_context = contexte
-      if hasattr(self,'contexte_fichier_init'):
-        self.old_contexte_fichier_init = self.contexte_fichier_init
-      self.contexte_fichier_init = contexte
-      # XXX la validité ne doit pas etre forcée à 1. Que faut-il faire exactement ???
-      self.init_modif()
-      #self.valid = 1
-      #self.state = 'unchanged'
-
   def get_contexte_jdc(self,fichier,text):
     """ 
          Interprète text comme un texte de jdc et retourne le 
          contexte final
          cad le dictionnaire des sd disponibles à la dernière étape
          Si text n'est pas un texte de jdc valide, retourne None
+         ou leve une exception
          --> utilisée par ops.POURSUITE et INCLUDE
     """
     try:
-       # on essaie de créer un objet JDC...
+       # on essaie de créer un objet JDC auxiliaire avec un contexte initial
        context_ini = self.parent.get_contexte_avant(self)
 
+       # Indispensable avant de creer un nouveau JDC
        CONTEXT.unset_current_step()
-       j=self.jdc.definition(procedure=text,cata=self.jdc.cata,
-                             nom=fichier,
-                             context_ini = context_ini,
-                             appli=self.jdc.appli)
+       args=self.jdc.args
+       prefix_include=None
+       if hasattr(self,'prefix'):
+          prefix_include=self.prefix
+
+       j=self.JdC_aux( procedure=text,cata=self.jdc.cata,
+                                nom=fichier,
+                                context_ini = context_ini,
+                                appli=self.jdc.appli,
+                                jdc_pere=self.jdc,etape_include=self,
+                                prefix_include=prefix_include,**args)
+
        j.analyse()
-       # XXX en passant par un jdc auxiliaire, on risque de rendre les etapes inactives
-       # on les force dans l'etat actif
-       for etape in j.etapes:
-          etape.active()
     except:
        traceback.print_exc()
+       # On force le contexte (etape courante) à self
+       CONTEXT.unset_current_step()
+       CONTEXT.set_current_step(self)
        return None
-    CONTEXT.set_current_step(self)
+
     if not j.cr.estvide():
-        raise Exception("Impossible de relire le fichier\n"+str(j.cr))
+       # On force le contexte (etape courante) à self
+       CONTEXT.unset_current_step()
+       CONTEXT.set_current_step(self)
+       # Erreurs dans l'INCLUDE. On garde la memoire du fichier mais on n'insere pas les concepts
+       # et les etapes. Ce traitement doit etre fait par l'appelant qui recoit l'exception
+       raise Exception("Impossible de relire le fichier\n"+str(j.cr))
+
+    cr=j.report()
+    if not cr.estvide():
+       # On force le contexte (etape courante) à self
+       CONTEXT.unset_current_step()
+       CONTEXT.set_current_step(self)
+       raise Exception("Le fichier include contient des erreurs\n"+str(j.cr))
+
+    # Cette verification n'est plus necessaire elle est integree dans le JDC_INCLUDE
+    #self.verif_contexte(j_context)
 
-    #XXX la validité d'un source inclus n'est pas identique à celle d'un JDC complet
-    #    impossible de la tester en dehors du JDC d'accueil
-    #cr=j.report()
-    #if not cr.estvide():
-    #    raise Exception("Le fichier contient des erreurs\n"+str(j.cr))
+    # On recupere le contexte apres la derniere etape
     j_context=j.get_contexte_avant(None)
-    # XXX j.g_context doit donner le meme résultat
-    # On retourne le contexte apres la derniere etape
-    # XXX j.supprime() ???
-    self.verif_contexte(j_context)
-    # Le contexte est acceptable. On récupère les étapes internes (pour validation)
+
+    # On remplit le dictionnaire des concepts produits inclus
+    # en retirant les concepts présents dans le  contexte initial
+    self.g_context.clear()
+    for k,v in j_context.items():
+       if not context_ini.has_key(k) or context_ini[k] != v:
+           self.g_context[k]=v
+
+    # On récupère les étapes internes (pour validation)
     self.etapes=j.etapes
+
+    # ainsi que le contexte courant
+    self.current_context=j.current_context
+    self.index_etape_courante=j.index_etape_courante
+
+    # XXX j.supprime() ???
+    # On force le contexte (etape courante) à self
+    CONTEXT.unset_current_step()
+    CONTEXT.set_current_step(self)
+
     return j_context
 
   def verif_contexte(self,context):
@@ -128,27 +144,71 @@ class MACRO_ETAPE(I_ETAPE.ETAPE):
   def reevalue_sd_jdc(self):
      """
          Avec la liste des SD qui ont été supprimées, propage la 
-         disparition de ces SD dans totues les étapes et descendants
+         disparition de ces SD dans toutes les étapes et descendants
      """
-     l_sd = self.diff_contextes()
-     if len(l_sd) == 0 : return
-     for sd in l_sd:
-        self.jdc.delete_concept(sd)
+     l_sd_supp,l_sd_repl = self.diff_contextes()
+     for sd in l_sd_supp:
+        self.parent.delete_concept_after_etape(self,sd)
+     for old_sd,sd in l_sd_repl:
+        self.parent.replace_concept_after_etape(self,old_sd,sd)
 
   def diff_contextes(self):
      """ 
          Réalise la différence entre les 2 contextes 
          old_contexte_fichier_init et contexte_fichier_init
-         cad retourne la liste des sd qui ont disparu 
+         cad retourne la liste des sd qui ont disparu ou ne derivent pas de la meme classe
+         et des sd qui ont ete remplacees
      """
-     if not hasattr(self,'old_contexte_fichier_init'):return []
+     if not hasattr(self,'old_contexte_fichier_init'):return [],[]
      l_sd_suppressed = []
+     l_sd_replaced = []
      for old_key in self.old_contexte_fichier_init.keys():
        if not self.contexte_fichier_init.has_key(old_key):
          if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
            l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
-     return l_sd_suppressed
+       else:
+         if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
+            # Un concept de meme nom existe
+            old_class=self.old_contexte_fichier_init[old_key].__class__
+            if not isinstance(self.contexte_fichier_init[old_key],old_class):
+               # S'il n'est pas d'une classe derivee, on le supprime
+               l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
+            else:
+               l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
+     return l_sd_suppressed,l_sd_replaced
       
+  def control_sdprods(self,d):
+      """
+          Cette methode doit updater le contexte fournit par
+          l'appelant en argument (d) en fonction de sa definition
+          tout en verifiant que ses concepts produits ne sont pas
+          deja definis dans le contexte
+      """
+      if type(self.definition.op_init) == types.FunctionType:
+        apply(self.definition.op_init,(self,d))
+      if self.sd:
+        if d.has_key(self.sd.nom):
+           # Le concept est deja defini
+           if self.reuse and self.reuse is d[self.sd.nom]:
+              # Le concept est reutilise : situation normale
+              pass
+           else:
+              # Redefinition du concept, on l'annule
+              #XXX on pourrait simplement annuler son nom pour conserver les objets
+              # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
+              self.sd=self.reuse=self.sdnom=None
+              self.init_modif()
+        else:
+           # Le concept n'est pas defini, on peut updater d
+           d[self.sd.nom]=self.sd
+      # On verifie les concepts a droite du signe =
+      for co in self.sdprods:
+        if d.has_key(co.nom) and co is not d[co.nom] :
+           self.delete_concept(co)
+        else:
+           d[co.nom]=co
+       
+
   def supprime_sdprods(self):
       """
           Fonction:
@@ -171,12 +231,12 @@ class MACRO_ETAPE(I_ETAPE.ETAPE):
       # Si la macro a des etapes et des concepts inclus, on les detruit
       for nom_sd,co in self.g_context.items():
          if not isinstance(co,ASSD):continue
-         print "Delete: ",self.nom,co.nom
          self.parent.del_sdprod(co)
          self.parent.delete_concept(co)
       # On met g_context à blanc
       self.g_context={}
          
+#ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
   def Build_sd(self,nom):
      """
         Construit le concept produit de l'opérateur. Deux cas 
@@ -220,8 +280,10 @@ class MACRO_ETAPE(I_ETAPE.ETAPE):
         # 1. on annule la sd associée à self
         # 2. on la conserve mais il faut qu'elle soit correcte et la retourner
         # En plus il faut rendre coherents sdnom et sd.nom
+        # On choisit de retourner None et de mettre l'etape invalide 
         self.sd=None
         self.sdnom=None
+        self.state="unchanged"
         self.valid=0
         return self.sd
         #raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
@@ -234,3 +296,175 @@ class MACRO_ETAPE(I_ETAPE.ETAPE):
         raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
                           'fichier : ',self.appel[1]+'\n',
                            string.join(l))
+
+  def make_contexte_include(self,fichier,text):
+    """
+        Cette méthode sert à créer un contexte en interprétant un texte source
+        Python
+    """
+    # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
+    contexte = self.get_contexte_jdc(fichier,text)
+    if contexte == None :
+      raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
+    else:
+      # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
+      # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
+      # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
+      # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
+      # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
+      # g_context est utilisé pour avoir les concepts produits par la macro
+      # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
+      self.contexte_fichier_init = contexte
+
+  def reevalue_fichier_init(self):
+      """Recalcule les concepts produits par le fichier enregistre"""
+      old_context=self.contexte_fichier_init
+      try:
+         self.make_contexte_include(self.fichier_ini ,self.fichier_text)
+      except:
+         l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
+         self.fichier_err = string.join(l)
+         self.etapes=[]
+         self.g_context={}
+
+         self.old_contexte_fichier_init=old_context
+         self.contexte_fichier_init={}
+         self.reevalue_sd_jdc()
+         return
+
+      # L'evaluation s'est bien passee
+      self.fichier_err = None
+      self.old_contexte_fichier_init=old_context
+      self.reevalue_sd_jdc()
+
+  def make_poursuite(self):
+      """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
+      """
+      if not hasattr(self,'fichier_ini') :
+         # Si le fichier n'est pas defini on le demande
+         f,text=self.get_file(fic_origine=self.parent.nom)
+         # On memorise le fichier retourne
+         self.fichier_ini = f
+         self.fichier_text = text
+         import Extensions.jdc_include
+         self.JdC_aux=Extensions.jdc_include.JdC_poursuite
+         self.contexte_fichier_init={}
+         if f is None:
+             self.fichier_err="Le fichier POURSUITE n'est pas defini"
+         else:
+             self.fichier_err=None
+
+         if self.fichier_err is not None: raise Exception(self.fichier_err)
+
+         try:
+           self.make_contexte_include(self.fichier_ini,self.fichier_text)
+         except:
+           l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
+           if self.jdc.appli:
+              self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
+                                            message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
+                                           )
+           self.g_context={}
+           self.etapes=[]
+           self.fichier_err = string.join(l)
+           self.contexte_fichier_init={}
+           raise
+
+      else:
+         # Si le fichier est deja defini on ne reevalue pas le fichier
+         # et on leve une exception si une erreur a été enregistrée
+         if self.fichier_err is not None: raise Exception(self.fichier_err)
+
+
+#ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
+  def make_include(self,unite=None):
+      """
+          Inclut un fichier dont l'unite logique est unite
+          Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
+          Si l'INCLUDE est invalide, la methode doit produire une exception 
+          Sinon on retourne None. Les concepts produits par l'INCLUDE sont
+          pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
+      """
+
+      # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
+      # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
+      del self.unite
+      # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
+      if not unite : return
+
+      if not hasattr(self,'fichier_ini') : 
+         # Si le fichier n'est pas defini on le demande
+         f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
+         # On memorise le fichier retourne
+         self.fichier_ini  = f
+         self.fichier_text = text
+         self.contexte_fichier_init={}
+         if f is None:
+             self.fichier_err="Le fichier INCLUDE n est pas defini"
+         else:
+             self.fichier_err=None
+         import Extensions.jdc_include
+         self.JdC_aux=Extensions.jdc_include.JdC_include
+
+         if self.fichier_err is not None: raise Exception(self.fichier_err)
+
+         try:
+           self.make_contexte_include(self.fichier_ini ,self.fichier_text)
+         except:
+           l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
+           if self.jdc.appli:
+              self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
+                                            message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
+                                           )
+           self.g_context={}
+           self.etapes=[]
+           self.fichier_err = string.join(l)
+           self.contexte_fichier_init={}
+           raise
+
+      else:
+         # Si le fichier est deja defini on ne reevalue pas le fichier
+         # et on leve une exception si une erreur a été enregistrée
+         #self.reevalue_fichier_init()
+         if self.fichier_err is not None: raise Exception(self.fichier_err)
+        
+
+#ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
+  def make_contexte(self,fichier,text):
+    """
+        Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
+        en interprétant un texte source Python
+        Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU
+    """
+    # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
+    # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
+    if hasattr(self,'mat'):del self.mat
+    self.fichier_ini =fichier
+    self.fichier_text=text
+    self.fichier_err=None 
+    self.contexte_fichier_init={}
+    # On specifie la classe a utiliser pour le JDC auxiliaire
+    import Extensions.jdc_include
+    self.JdC_aux=Extensions.jdc_include.JdC_include
+    try:
+       self.make_contexte_include(self.fichier_ini ,self.fichier_text)
+    except:
+       l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
+       self.g_context={}
+       self.etapes=[]
+       self.fichier_err = string.join(l)
+       self.contexte_fichier_init={}
+       raise
+
+#ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
+  def update_sdprod(self,cr='non'):
+     # Cette methode peut etre appelee dans EFICAS avec des mots cles de 
+     # la commande modifies. Ceci peut conduire a la construction ou
+     # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
+     # Il faut donc positionner le current_step avant l'appel
+     CONTEXT.unset_current_step()
+     CONTEXT.set_current_step(self)
+     valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
+     CONTEXT.unset_current_step()
+     return valid
+
index d7e828ff7cc44971750f221e745a62b22601fd39..fd773d947cedf5ea6c5209d2018275f43a4feb87 100644 (file)
@@ -309,6 +309,18 @@ class MCCOMPO(I_OBJECT.OBJECT):
     for child in self.mc_liste :
       child.delete_concept(sd)
 
+  def replace_concept(self,old_sd,sd):
+    """
+        Inputs :
+           old_sd=concept remplace
+           sd = nouveau concept
+        Fonction :
+           Mettre a jour les fils de l objet suite au remplacement  du
+           concept old_sd
+    """
+    for child in self.mc_liste :
+      child.replace_concept(old_sd,sd)
+
   def delete_mc_global(self,mc):
     """ 
         Supprime le mot-clé mc de la liste des mots-clés globaux de l'étape 
index b9529e3321600342dbf14841d7838ac75894b889..c201ed25509c6e74a68d4e8b7cd3bf961456a273 100644 (file)
@@ -71,6 +71,18 @@ class MCList:
     for child in self.data :
       child.delete_concept(sd)
 
+  def replace_concept(self,old_sd,sd):
+    """
+        Inputs :
+           old_sd=concept remplacé
+           sd=nouveau concept
+        Fonction :
+           Mettre a jour les fils de l objet suite au remplacement 
+           du concept old_sd
+    """
+    for child in self.data :
+      child.replace_concept(old_sd,sd)
+
   def copy(self):
     """
        Réalise la copie d'une MCList
index ca1bafa3822235bdb54327d4b8200bdbabcc4a1e..cbe8d0c219c214d0195c654620f98d83c26c6762 100644 (file)
@@ -200,6 +200,7 @@ class MCSIMP(I_OBJECT.OBJECT):
         self.val = new_valeur
         self.valeur = valeur
         self.init_modif()
+        self.fin_modif()
         return 1
       else:
         # On n'a pas trouve de concept ni réussi à évaluer la valeur 
@@ -214,27 +215,30 @@ class MCSIMP(I_OBJECT.OBJECT):
           except:
             traceback.print_exc()
             return 0
-          self.val=self.valeur
           self.init_modif()
+          self.val=self.valeur
+          self.fin_modif()
           return 1
         elif type(new_valeur)==types.StringType and self.wait_TXM():
+          self.init_modif()
           self.val = new_valeur
           self.valeur = new_valeur
-          self.init_modif()
+          self.fin_modif()
           return 1
         else:
           return 0
     else :
       # on ne fait aucune vérification ...
+      self.init_modif()
       try:
         self.valeur = eval(new_valeur)
         self.val = eval(new_valeur)
-        self.init_modif()
+        self.fin_modif()
         return 1
       except:
         self.valeur = new_valeur
         self.val = new_valeur
-        self.init_modif()
+        self.fin_modif()
         return 1
 
   def eval_valeur(self,new_valeur):
@@ -282,6 +286,32 @@ class MCSIMP(I_OBJECT.OBJECT):
         self.val=None
         self.init_modif()
 
+  def replace_concept(self,old_sd,sd):
+    """
+        Inputs :
+           old_sd=concept remplacé
+           sd=nouveau concept
+        Fonction :
+           Met a jour la valeur du mot cle simple suite au remplacement 
+           du concept old_sd
+    """
+    if type(self.valeur) == types.TupleType :
+      if old_sd in self.valeur:
+        self.valeur=list(self.valeur)
+        i=self.valeur.index(old_sd)
+        self.valeur[i]=sd
+        self.init_modif()
+    elif type(self.valeur) == types.ListType:
+      if old_sd in self.valeur:
+        i=self.valeur.index(old_sd)
+        self.valeur[i]=sd
+        self.init_modif()
+    else:
+      if self.valeur == old_sd:
+        self.valeur=sd
+        self.val=sd
+        self.init_modif()
+
   def copy(self):
     """ Retourne une copie de self """
     objet = self.makeobjet()
@@ -339,9 +369,10 @@ class MCSIMP(I_OBJECT.OBJECT):
          new_objet = CO(nom_co)
          CONTEXT.unset_current_step()
          CONTEXT.set_current_step(cs)
+      self.init_modif()
       self.valeur = new_objet
       self.val = new_objet
-      self.init_modif()
+      self.fin_modif()
       step.reset_context()
       # On force l'enregistrement de new_objet en tant que concept produit 
       # de la macro en appelant get_type_produit avec force=1
@@ -371,13 +402,16 @@ class MCSIMP(I_OBJECT.OBJECT):
         else:
            l.append(sd)
        self.valeur=l
+       # Est ce init_modif ou init_modif_up
+       # Normalement init_modif va avec fin_modif
        self.init_modif()
+       self.fin_modif()
      else:
        if isinstance(self.valeur,ASSD) :
          if self.valeur not in l_sd_avant_etape :
             self.valeur = None
              self.init_modif()
+             self.fin_modif()
  
   def get_min_max(self):
      """
@@ -392,6 +426,48 @@ class MCSIMP(I_OBJECT.OBJECT):
      """
      return self.definition.type
  
+#ATTENTION : toutes les methodes ci apres sont des surcharges du Noyau et de Validation
+# Elles doivent etre reintegrees des que possible
+
+  def isvalid(self,cr='non'):
+      """
+         Cette méthode retourne un indicateur de validité de l'objet
+         de type MCSIMP
+
+         - 0 si l'objet est invalide
+
+         - 1 si l'objet est valide
+
+         Le paramètre cr permet de paramétrer le traitement. 
+         Si cr == 'oui'
+             la méthode construit également un comte-rendu de validation
+             dans self.cr qui doit avoir été créé préalablement.
+      """
+      if self.state == 'unchanged':
+        return self.valid
+      else:
+        valid = 1
+        if hasattr(self,'valid'):
+          old_valid = self.valid
+        else:
+          old_valid = None
+        v=self.valeur
+        #  presence
+        if self.isoblig() and v == None :
+          if cr == 'oui' :
+            self.cr.fatal(string.join(("Mot-clé : ",self.nom," obligatoire non valorisé")))
+          valid = 0
+        # type,into ...
+        valid = self.verif_type(cr=cr)*self.verif_into(cr=cr)*self.verif_card(cr=cr)
+        self.valid = valid
+        self.state = 'unchanged'
+        # Si la validité du mot clé a changé, on le signale à l'objet parent
+        if not old_valid:
+          self.init_modif_up()
+        elif old_valid != self.valid : 
+          self.init_modif_up()
+        return self.valid
+
  
  
  
index 81d6c8107fb6e5076e842992d32db7ffeba6f612..b4ebb72dab5ef4414e0ac712f22fea138bf0b2a3 100644 (file)
@@ -21,7 +21,8 @@ import I_ETAPE
 
 
 # import rajoutés suite à l'ajout de Build_sd --> à résorber
-import traceback,types
+import sys
+import traceback,types,string
 import Noyau
 from Noyau import N_Exception
 from Noyau.N_Exception import AsException
@@ -52,6 +53,18 @@ class PROC_ETAPE(I_ETAPE.ETAPE):
       for child in self.mc_liste :
         child.delete_concept(sd)
 
+   def replace_concept(self,old_sd,sd):
+      """
+          Inputs :
+             old_sd=concept remplacé
+             sd=nouveau concept
+          Fonction :
+             Mettre a jour les mots cles de l etape
+             suite au remplacement du concept old_sd
+      """
+      for child in self.mc_liste :
+        child.replace_concept(old_sd,sd)
+
    def Build_sd(self):
       """
           Cette methode applique la fonction op_init au contexte du parent