Salome HOME
PN vielles macros
[tools/eficas.git] / Ihm / I_JDC.py
index 2c26ab8e653adb28a2595a0b9ac955ee3a1bfeac..f7ef14c0db99c29308f79a065213c027cb959240 100644 (file)
@@ -1,3 +1,23 @@
+# -*- coding: utf-8 -*-
+#            CONFIGURATION MANAGEMENT OF EDF VERSION
+# ======================================================================
+# 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
@@ -6,9 +26,8 @@ import string,linecache
 
 # Modules Eficas
 import I_OBJECT
-from Noyau.N_ASSD import assd
+from Noyau.N_ASSD import ASSD
 from Noyau.N_ETAPE import ETAPE
-from Noyau.N_CO import CO
 from Noyau.N_Exception import AsException
 from Extensions import commentaire,parametre,parametre_eval
 
@@ -21,14 +40,9 @@ class JDC(I_OBJECT.OBJECT):
       self.niveau=self
       self.params=[]
       self.fonctions=[]
-
-   def get_cmd(self,nomcmd):
-      """
-          Retourne l'objet de type COMMANDE de nom nomcmd
-      """
-      for cata in self.cata:
-         if hasattr(cata,nomcmd):
-            return getattr(cata,nomcmd)
+      self._etape_context=None
+      self.recorded_units={}
+      self.old_recorded_units={}
 
    def get_sd_avant_du_bon_type(self,etape,types_permis):
       """
@@ -38,20 +52,32 @@ class JDC(I_OBJECT.OBJECT):
       l=[]
       for k,v in d.items():
         if type(v) != types.InstanceType : continue
-        if assd in types_permis or CO in types_permis :
-          l.append(k)
-          continue
-        for type_ok in types_permis:
-          if type_ok in ('R','I','C','TXM') and v in self.params : l.append(k)
-          elif type_ok == 'R' and v.__class__.__name__ == 'reel' : l.append(k)
-          elif type_ok == 'I' and v.__class__.__name__ == 'entier' : l.append(k)
-          elif type_ok == 'C' and v.__class__.__name__ == 'complexe' : l.append(k)
-          elif type_ok == 'TXM' and v.__class__.__name__ == 'chaine' : l.append(k)
-          elif type(type_ok) != types.ClassType : continue
-          elif v.__class__ == type_ok or issubclass(v.__class__,type_ok): l.append(k)
+        # On considère que seul assd indique un type quelconque pas CO
+        elif self.assd in types_permis :
+           l.append(k)
+        elif self.est_permis(v,types_permis):
+           l.append(k)
       l.sort()
       return l
 
+   def est_permis(self,v,types_permis):
+      for type_ok in types_permis:
+          if type_ok in ('R','I','C','TXM') and v in self.params : 
+             return 1
+          elif type_ok == 'R' and v.__class__.__name__ == 'reel' : 
+             return 1
+          elif type_ok == 'I' and v.__class__.__name__ == 'entier' : 
+             return 1
+          elif type_ok == 'C' and v.__class__.__name__ == 'complexe' : 
+             return 1
+          elif type_ok == 'TXM' and v.__class__.__name__ == 'chaine' : 
+             return 1
+          elif type(type_ok) != types.ClassType : 
+             continue
+          elif v.__class__ == type_ok or issubclass(v.__class__,type_ok):
+             return 1
+      return 0
+
    def addentite(self,name,pos):
       """
           Ajoute une entite :
@@ -83,6 +109,7 @@ class JDC(I_OBJECT.OBJECT):
         if pos == None : pos = 0
         self.etapes.insert(pos,objet)
         self.editmode=0
+        self.reset_context()
         self.active_etapes()
         return objet
       elif name == "PARAMETRE_EVAL":
@@ -93,6 +120,7 @@ class JDC(I_OBJECT.OBJECT):
         if pos == None : pos = 0
         self.etapes.insert(pos,objet)
         self.editmode=0
+        self.reset_context()
         self.active_etapes()
         return objet
       elif type(name)==types.InstanceType:
@@ -100,10 +128,8 @@ class JDC(I_OBJECT.OBJECT):
         # existante (par copie donc)
         # on est donc nécessairement en mode editeur ...
         objet = name
-        objet.jdc = objet.parent = self
-        #XXX current_step n'existe plus. A priori le parent devrait etre self
-        # ainsi que le step courant.
-        #objet.parent = self.current_step
+        # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
+        objet.reparent(self)
         self.set_current_step()
         if isinstance(objet,ETAPE):
           if objet.nom_niveau_definition == 'JDC':
@@ -115,8 +141,12 @@ class JDC(I_OBJECT.OBJECT):
             objet.parent.dict_niveaux[objet.nom_niveau_definition].register(objet)
             objet.niveau = objet.parent.dict_niveaux[objet.nom_niveau_definition]
         self.etapes.insert(pos,objet)
+       # il faut vérifier que les concepts utilisés par objet existent bien
+       # à ce niveau d'arborescence
+       objet.verif_existence_sd()
         self.active_etapes()
         self.editmode=0
+        self.reset_context()
         return objet
       else :
         # On veut ajouter une nouvelle commande
@@ -125,13 +155,19 @@ class JDC(I_OBJECT.OBJECT):
           cmd=self.get_cmd(name)
           # L'appel a make_objet n'a pas pour effet d'enregistrer l'étape
           # auprès du step courant car editmode vaut 1
+          # Par contre elle a le bon parent grace a set_current_step
           e=cmd.make_objet()
           if pos == None : pos = 0
           self.etapes.insert(pos,e)
           self.reset_current_step()
           self.editmode=0
+          self.reset_context()
           self.active_etapes()
           return e
+        except AsException,e:
+          self.reset_current_step()
+          self.editmode=0
+          raise AsException("Impossible d ajouter la commande "+name + '\n' +str(e))
         except:
           traceback.print_exc()
           self.reset_current_step()
@@ -151,13 +187,45 @@ class JDC(I_OBJECT.OBJECT):
    def get_sd_avant_etape(self,nom_sd,etape):
       return self.get_contexte_avant(etape).get(nom_sd,None)
 
-   def get_sd_apres_etape(self,nom_sd,etape):
+   def get_sd_apres_etape_avec_detruire(self,nom_sd,sd,etape,avec='non'):
+      """ 
+           Cette méthode retourne la SD sd de nom nom_sd qui est éventuellement
+           définie apres etape en tenant compte des concepts detruits
+           Si avec vaut 'non' exclut etape de la recherche
+      """
+      ietap=self.etapes.index(etape)
+      if avec == 'non':ietap=ietap+1
+      d={nom_sd:sd}
+      for e in self.etapes[ietap:]:
+         if e.isactif():
+            e.update_context(d)
+            autre_sd=d.get(nom_sd,None)
+            if autre_sd is None:
+              # Le concept a ete detruit
+              return None
+            if autre_sd is not sd :
+              # L'etape produit un concept de meme nom
+              if hasattr(e,'reuse') and e.reuse == autre_sd:
+                 # Le concept etant reutilise, on interrompt la recherche. 
+                 # On considere qu'il n'y a pas de nouveau concept defini
+                 # meme si dans les etapes suivantes le concept est detruit
+                 # et un concept de meme nom créé.
+                 return None
+              else:
+                 # Le concept est produit par l'etape
+                 return autre_sd
+      # On n'a rien trouve. Pas de concept de nom nom_sd
+      return None
+
+   def get_sd_apres_etape(self,nom_sd,etape,avec='non'):
       """ 
            Cette méthode retourne la SD de nom nom_sd qui est éventuellement
-            définie apres etape
+           définie apres etape 
+           Si avec vaut 'non' exclut etape de la recherche
       """
       ietap=self.etapes.index(etape)
-      for e in self.etapes[ietap+1:]:
+      if avec == 'non':ietap=ietap+1
+      for e in self.etapes[ietap:]:
         sd=e.get_sdprods(nom_sd)
         if sd:
           if hasattr(e,'reuse'):
@@ -165,16 +233,31 @@ class JDC(I_OBJECT.OBJECT):
               return sd
       return None
 
-   def get_sd_autour_etape(self,nom_sd,etape):
+   def get_sd_autour_etape(self,nom_sd,etape,avec='non'):
       """
            Fonction: retourne la SD de nom nom_sd qui est éventuellement
-            définie avant ou apres etape
+           définie avant ou apres etape
            Permet de vérifier si un concept de meme nom existe dans le périmètre 
            d'une étape
+           Si avec vaut 'non' exclut etape de la recherche
       """
       sd=self.get_sd_avant_etape(nom_sd,etape)
       if sd:return sd
-      return self.get_sd_apres_etape(nom_sd,etape)
+      return self.get_sd_apres_etape(nom_sd,etape,avec)
+
+   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):
       """
@@ -203,8 +286,14 @@ class JDC(I_OBJECT.OBJECT):
       """  
           Cette methode a pour fonction de supprimer une étape dans 
           un jeu de commandes
+          Retourne 1 si la suppression a pu être effectuée,
+          Retourne 0 dans le cas contraire
       """
       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
@@ -213,25 +302,14 @@ 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()
+      return 1
 
    def analyse(self):
       self.compile()
@@ -239,34 +317,18 @@ class JDC(I_OBJECT.OBJECT):
       self.exec_compile()
       self.active_etapes()
 
-   def register(self,etape):
-      """ 
-           Cette méthode ajoute  etape dans la liste
-           des etapes self.etapes et retourne l identificateur d'étape
-           fourni par l appel a g_register
-           A quoi sert editmode ?
-           - Si editmode vaut 1, on est en mode edition de JDC. On cherche 
-           à enregistrer une étape que l'on a créée avec eficas (en passant 
-           par addentite) auquel cas on ne veut récupérer que son numéro 
-           d'enregistrement et c'est addentité qui l'enregistre dans 
-           self.etapes à la bonne place...
-           - Si editmode vaut 0, on est en mode relecture d'un fichier de 
-           commandes et on doit enregistrer l'étape à la fin de self.etapes 
-           (dans ce cas l'ordre des étapes est bien l'ordre chronologique 
-           de leur création   )
-      """
-      if not self.editmode:
-         self.etapes.append(etape)
-      else:
-         pass
-      return self.g_register(etape)
-
    def register_parametre(self,param):
       """
           Cette méthode sert à ajouter un paramètre dans la liste des paramètres
       """
       self.params.append(param)
 
+   def register_fonction(self,fonction):
+      """
+          Cette méthode sert à ajouter une fonction dans la liste des fonctions
+      """
+      self.fonctions.append(fonction)
+
    def delete_param(self,param):
       """
           Supprime le paramètre param de la liste des paramètres
@@ -297,6 +359,14 @@ class JDC(I_OBJECT.OBJECT):
         nom = form.nom
         if not nom : continue
         if d.has_key(nom): l_fonctions.append(form.get_formule())
+
+      # on ajoute les concepts produits par DEFI_VALEUR
+      # XXX On pourrait peut etre faire plutot le test sur le type
+      # de concept : entier, reel, complexe, etc.
+      for k,v in d.items():
+         if hasattr(v,'etape') and v.etape.nom in ('DEFI_VALEUR',):
+            l_constantes.append(k)
+
       # on retourne les deux listes
       return l_constantes,l_fonctions
 
@@ -314,17 +384,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 
@@ -333,6 +392,7 @@ class JDC(I_OBJECT.OBJECT):
       self.state = 'modified'
 
    def fin_modif(self):
+      self.isvalid()
       pass
 
    def get_liste_mc_inconnus(self):
@@ -348,28 +408,197 @@ class JDC(I_OBJECT.OBJECT):
               if l : l_mc.extend(l)
      return l_mc    
 
-   def get_file(self,unite=None,fic_origine=''):
+   def get_genealogie(self):
+      """
+          Retourne la liste des noms des ascendants de l'objet self
+          jusqu'à la première ETAPE parent.
+      """
+      return []
+
+   def set_etape_context(self,etape):
+      """
+          Positionne l'etape qui sera utilisee dans NommerSdProd pour
+          decider si le concept passé pourra etre  nommé
+      """
+      self._etape_context=etape
+
+   def reset_context(self):
+      """ 
+          Cette methode reinitialise le contexte glissant pour pouvoir
+          tenir compte des modifications de l'utilisateur : création
+          de commandes, nommage de concepts, etc.
+      """
+      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
+          et du contexte gobal
+      """
+      if param in self.params : self.params.remove(param)
+      if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
+
+   def del_fonction(self,fonction):
+      """
+          Supprime la fonction fonction de la liste des fonctions
+          et du contexte gobal
+      """
+      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(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
+      
+   def change_unit(self,unit,etape,old_unit):
+      if self.recorded_units.has_key(old_unit):del self.recorded_units[old_unit]
+      self.record_unit(unit,etape)
+
+   def record_unit(self,unit,etape):
+      """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
+      if unit is None:
+         # Cas de POURSUITE
+         self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
+      else:
+         self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
+
+#ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
+   def register(self,etape):
+      """
+           Cette méthode ajoute  etape dans la liste
+           des etapes self.etapes et retourne l identificateur d'étape
+           fourni par l appel a g_register
+
+           A quoi sert editmode ?
+              - Si editmode vaut 1, on est en mode edition de JDC. On cherche
+                à enregistrer une étape que l'on a créée avec eficas (en passant
+                par addentite) auquel cas on ne veut récupérer que son numéro
+                d'enregistrement et c'est addentité qui l'enregistre dans
+                self.etapes à la bonne place...
+              - Si editmode vaut 0, on est en mode relecture d'un fichier de
+                commandes et on doit enregistrer l'étape à la fin de self.etapes
+                (dans ce cas l'ordre des étapes est bien l'ordre chronologique
+                de leur création   )
+      """
+      if not self.editmode:
+         self.etapes.append(etape)
+      else:
+         pass
+      return self.g_register(etape)
+
+#ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
+   def NommerSdprod(self,sd,sdnom,restrict='non'):
       """
-          Retourne le nom du fichier correspondant à un numero d'unité
-          logique (entier) ainsi que le source contenu dans le fichier
+          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
       """
-      if self.appli :
-         # Si le JDC est relié à une application maitre, on délègue la recherche
-         file,text = self.appli.get_file(unite,fic_origine)
+      # 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 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:
-         file = None
-         if unite != None:
-            if os.path.exists("fort."+str(unite)):
-               file= "fort."+str(unite)
-         if file == None :
-            raise AsException("Impossible de trouver le fichier correspondant \
-                               a l unite %s" % unite)
-         if not os.path.exists(file):
-            raise AsException("%s n'est pas un fichier existant" % unite)
-         fproc=open(file,'r')
-         text=fproc.read()
-         fproc.close()
-      text=string.replace(text,'\r\n','\n')
-      linecache.cache[file]=0,0,string.split(text,'\n'),file
-      return file,text
+         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.sds_dict[sdnom]=sd
+      sd.nom=sdnom
+
+      # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
+      if restrict == 'non':
+         self.g_context[sdnom]=sd
+
+#ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
+   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)
+
+#ATTENTION SURCHARGE : les methodes ci-dessous surchargent des methodes de Noyau et Validation : a reintegrer