Salome HOME
correction pb condition_context avec newJDC
[tools/eficas.git] / Ihm / I_ETAPE.py
1 # -*- coding: utf-8 -*-
2 #            CONFIGURATION MANAGEMENT OF EDF VERSION
3 # ======================================================================
4 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
5 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
6 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
7 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
8 # (AT YOUR OPTION) ANY LATER VERSION.
9 #
10 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
11 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
12 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
13 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
14 #
15 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
16 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
17 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
18 #
19 #
20 # ======================================================================
21 """
22 """
23 # Modules Python
24 import sys,re
25 import string,types
26 from copy import copy
27
28 # Objet re pour controler les identificateurs Python
29 concept_re=re.compile(r'[a-zA-Z_]\w*$')
30
31 # import rajoutés suite à l'ajout de Build_sd --> à résorber
32 import traceback
33 import Noyau
34 from Noyau import N_Exception
35 from Noyau.N_Exception import AsException
36 # fin import à résorber
37
38 # Modules EFICAS
39 import I_MCCOMPO
40
41 class ETAPE(I_MCCOMPO.MCCOMPO):
42
43    def ident(self):
44       return self.nom
45
46    def get_sdname(self):
47       if CONTEXT.debug : print "SDNAME ",self.reuse,self.sd,self.sd.get_name()
48       sdname=''
49       if self.reuse != None:
50         sdname= self.reuse.get_name()
51       else:
52         if self.sd:sdname=self.sd.get_name()
53       if string.find(sdname,'sansnom') != -1 or string.find(sdname,'SD_') != -1:
54         # dans le cas où la SD est 'sansnom' ou 'SD_' on retourne la chaîne vide
55         return ''
56       return sdname
57
58    def is_reentrant(self):
59       """ 
60           Indique si la commande est reentrante
61       """
62       return self.definition.reentrant == 'o' 
63
64    def init_modif(self):
65       """
66          Met l'état de l'étape à : modifié
67          Propage la modification au parent
68       """
69       # init_modif doit etre appelé avant de réaliser une modification
70       # La validité devra etre recalculée apres cette modification
71       # mais dans l'appel à fin_modif pour préserver l'état modified
72       # de tous les objets entre temps
73       print "init_modif",self,self.parent
74       self.state = 'modified'
75       if self.parent:
76         self.parent.init_modif()
77
78    def fin_modif(self):
79       """
80           Méthode appelée une fois qu'une modification a été faite afin de 
81           déclencher d'éventuels traitements post-modification
82           ex : INCLUDE et POURSUITE
83       """
84       print "fin_modif",self,self.parent
85       if self.isvalid() :
86          d=self.parent.get_contexte_apres(self)
87       if self.parent:
88         self.parent.fin_modif()
89
90    def nomme_sd(self,nom) :
91       """
92           Cette méthode a pour fonction de donner un nom (nom) au concept 
93           produit par l'étape (self).
94             - si le concept n'existe pas, on essaye de le créer (à condition que l'étape soit valide ET non réentrante)
95             - si il existe déjà, on le renomme et on répercute les changements dans les autres étapes    
96           Les valeurs de retour sont :
97             - 0 si le nommage n'a pas pu etre mené à son terme,
98             - 1 dans le cas contraire
99       """
100       # Le nom d'un concept doit etre un identificateur Python (toujours vrai ?)
101       if not concept_re.match(nom):
102          return 0,"Un nom de concept doit etre un identificateur Python"
103
104       if len(nom) > 8 and self.jdc.definition.code == 'ASTER':
105         return 0,"Nom de concept trop long (maxi 8 caractères)"
106
107       self.init_modif()
108       #
109       # On verifie d'abord si les mots cles sont valides
110       #
111       if not self.isvalid(sd='non') : return 0,"Nommage du concept refusé : l'opérateur n'est pas valide"
112       #
113       # Cas particulier des opérateurs obligatoirement réentrants
114       #
115       if self.definition.reentrant == 'o':
116         self.sd = self.reuse = self.jdc.get_sd_avant_etape(nom,self)
117         if self.sd != None :
118           self.sdnom=self.sd.nom
119           self.fin_modif()
120           return 1,"Concept existant"
121         else:
122           return 0,"Opérateur réentrant mais concept non existant"
123       #
124       # Cas particulier des opérateurs facultativement réentrants
125       #
126       old_reuse=None
127       if self.definition.reentrant == 'f' :
128         sd = self.jdc.get_sd_avant_etape(nom,self)
129         if sd != None :
130           # FR : il faut tester que la sd trouvée est du bon type !!!!!!!!!!!!!!!!!
131           if isinstance(sd,self.get_type_produit()) :
132              self.sd = self.reuse = sd
133              self.sdnom = sd.nom
134              self.fin_modif()
135              return 1,"Opérateur facultativement réentrant et concept existant trouvé"
136           else:
137              return 0,"Concept déjà existant et de mauvais type"
138         else :
139           # il faut enlever le lien vers une SD existante car si on passe ici
140           # cela signifie que l'opérateur n'est pas utilisé en mode réentrant.
141           # Si on ne fait pas cela, on risque de modifier une SD produite par un autre opérateur
142           if self.reuse :
143              old_reuse=self.reuse
144              self.sd = self.reuse = self.sdnom = None
145       #
146       # On est dans le cas ou l'opérateur n'est pas réentrant ou est facultativement reentrant
147       # mais est utilisé en mode non réentrant
148       #
149       if self.sd == None :
150           if self.parent.get_sd_autour_etape(nom,self):
151             # Un concept de ce nom existe dans le voisinage de l'etape courante
152             # On retablit l'ancien concept reentrant s'il existait
153             if old_reuse:
154                self.sd=self.reuse=old_reuse
155                self.sdnom=old_reuse.nom
156             return 0,"Nommage du concept refuse : un concept de meme nom existe deja"
157           else:
158             # Il n'existe pas de concept de ce nom dans le voisinage de l'etape courante
159             # On peut donc créer le concept retourné.
160             # Il est créé sans nom mais enregistré dans la liste des concepts existants
161             try:
162                self.get_sd_prod()
163                # Il suffit de changer son attribut nom pour le nommer
164                self.sd.nom = nom
165                self.sdnom=nom
166                self.fin_modif()
167                return 1,"Nommage du concept effectué"
168             except:
169                return 0,"Nommage impossible"+str(sys.exc_info()[1])
170       else :
171           old_nom=self.sd.nom
172           if string.find(old_nom,'sansnom') :
173             # Dans le cas où old_nom == sansnom, isvalid retourne 0 alors que ...
174             # par contre si le concept existe et qu'il s'appelle sansnom c'est que l'étape est valide
175             # on peut donc le nommer sans test préalable
176             if self.parent.get_sd_autour_etape(nom,self):
177               return 0,"Nommage du concept refuse : un concept de meme nom existe deja"
178             else:
179               self.sd.nom=nom
180               self.sdnom=nom
181               self.fin_modif()
182               return 1,"Nommage du concept effectué"
183           if self.isvalid() :
184             # Normalement l appel de isvalid a mis a jour le concept produit (son type)
185             # Il suffit de spécifier l attribut nom de sd pour le nommer si le nom n est pas
186             # deja attribué
187             if self.parent.get_sd_autour_etape(nom,self):
188               return 0,"Nommage du concept refuse : un concept de meme nom existe deja"
189             else:
190               self.sd.nom=nom
191               self.sdnom=nom
192               self.fin_modif()
193               return 1,"Nommage du concept effectué"
194           else:
195             # Normalement on ne devrait pas passer ici
196             return 0,'Normalement on ne devrait pas passer ici'
197
198    def get_sdprods(self,nom_sd):
199       """ 
200          Fonction : retourne le concept produit par l etape de nom nom_sd
201          s il existe sinon None
202       """
203       if self.sd:
204         if self.sd.nom == nom_sd:return self.sd
205
206    def active(self):
207       """
208           Rend l'etape courante active.
209           Il faut ajouter la sd si elle existe au contexte global du JDC
210           et à la liste des sd
211       """
212       if self.actif:return
213       self.actif = 1
214       if not self.sd : return
215       try:
216         self.jdc.append_sdprod(self.sd)
217       except:
218         pass
219
220    def inactive(self):
221       """
222           Rend l'etape courante inactive
223           Il faut supprimer la sd du contexte global du JDC
224           et de la liste des sd
225       """
226       self.actif = 0
227       if not self.sd : return
228       self.jdc.del_sdprod(self.sd)
229       self.jdc.delete_concept_after_etape(self,self.sd)
230
231    def control_sdprods(self,d):
232       """
233           Cette methode doit updater le contexte fournit par
234           l'appelant en argument (d) en fonction de sa definition
235           tout en verifiant que ses concepts produits ne sont pas 
236           deja definis dans le contexte
237       """
238       if type(self.definition.op_init) == types.FunctionType:
239         apply(self.definition.op_init,(self,d))
240       if self.sd:
241         if d.has_key(self.sd.nom):
242            # Le concept est deja defini
243            if self.reuse and self.reuse is d[self.sd.nom]:
244               # Le concept est reutilise : situation normale
245               pass
246            else:
247               # Redefinition du concept, on l'annule
248               #XXX on pourrait simplement annuler son nom pour conserver les objets
249               # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
250               self.sd=self.reuse=self.sdnom=None
251               self.init_modif()
252         else:
253            # Le concept n'est pas defini, on peut updater d
254            d[self.sd.nom]=self.sd
255
256    def supprime_sdprods(self):
257       """ 
258             Fonction:
259             Lors d'une destruction d'etape, detruit tous les concepts produits
260             Un opérateur n a qu un concept produit 
261             Une procedure n'en a aucun
262             Une macro en a en général plus d'un
263       """
264       if not self.is_reentrant() :
265         # l'étape n'est pas réentrante
266         # le concept retourné par l'étape est à supprimer car il était 
267         # créé par l'étape
268         if self.sd != None :
269           self.parent.del_sdprod(self.sd)
270           self.parent.delete_concept(self.sd)
271
272    def delete_concept(self,sd):
273       """ 
274           Inputs :
275              - sd=concept detruit
276           Fonction :
277           Mettre a jour les mots cles de l etape et eventuellement 
278           le concept produit si reuse
279           suite à la disparition du concept sd
280           Seuls les mots cles simples MCSIMP font un traitement autre 
281           que de transmettre aux fils
282       """
283       if self.reuse and self.reuse == sd:
284         self.sd=self.reuse=None
285         self.init_modif()
286       for child in self.mc_liste :
287         child.delete_concept(sd)
288
289    def replace_concept(self,old_sd,sd):
290       """
291           Inputs :
292              - old_sd=concept remplace
293              - sd = nouveau concept 
294           Fonction :
295           Mettre a jour les mots cles de l etape et eventuellement
296           le concept produit si reuse
297           suite au remplacement  du concept old_sd
298       """
299       if self.reuse and self.reuse == old_sd:
300         self.sd=self.reuse=sd
301         self.init_modif()
302       for child in self.mc_liste :
303         child.replace_concept(old_sd,sd)
304
305    def get_noms_sd_oper_reentrant(self):
306       """ 
307           Retourne la liste des noms de concepts utilisés à l'intérieur de la commande
308           qui sont du type que peut retourner cette commande 
309       """
310       liste_sd = self.get_sd_utilisees()
311       l_noms = []
312       if type(self.definition.sd_prod) == types.FunctionType:
313         d=self.cree_dict_valeurs(self.mc_liste)
314         try:
315           classe_sd_prod = apply(self.definition.sd_prod,(),d)
316         except:
317           return []
318       else:
319         classe_sd_prod = self.definition.sd_prod
320       for sd in liste_sd :
321         if sd.__class__ is classe_sd_prod : l_noms.append(sd.nom)
322       l_noms.sort()
323       return l_noms
324
325    def get_genealogie(self):
326       """ 
327           Retourne la liste des noms des ascendants de l'objet self
328           en s'arretant à la première ETAPE rencontrée
329       """
330       return [self.nom]
331
332    def verif_existence_sd(self):
333      """
334         Vérifie que les structures de données utilisées dans self existent bien dans le contexte
335         avant étape, sinon enlève la référence à ces concepts
336      """
337      for motcle in self.mc_liste :
338          motcle.verif_existence_sd()
339      
340 #ATTENTION SURCHARGE: a garder en synchro ou a reintegrer dans le Noyau
341    def Build_sd(self,nom):
342       """
343            Methode de Noyau surchargee pour poursuivre malgre tout
344            si une erreur se produit pendant la creation du concept produit
345       """
346       try:
347          sd=Noyau.N_ETAPE.ETAPE.Build_sd(self,nom)
348       except AsException,e:
349          # Une erreur s'est produite lors de la construction du concept
350          # Comme on est dans EFICAS, on essaie de poursuivre quand meme
351          # Si on poursuit, on a le choix entre deux possibilités :
352          # 1. on annule la sd associée à self
353          # 2. on la conserve mais il faut la retourner
354          # En plus il faut rendre coherents sdnom et sd.nom
355          self.sd=None
356          self.sdnom=None
357          self.state="unchanged"
358          self.valid=0
359
360       return self.sd
361
362 #ATTENTION SURCHARGE: cette methode doit etre gardée en synchronisation avec Noyau
363    def make_register(self):
364       """
365          Initialise les attributs jdc, id, niveau et réalise les
366          enregistrements nécessaires
367          Pour EFICAS, on tient compte des niveaux
368          Surcharge la methode make_register du package Noyau
369       """
370       if self.parent :
371          self.jdc = self.parent.get_jdc_root()
372          self.id=   self.parent.register(self)
373          if self.definition.niveau :
374             # La définition est dans un niveau. En plus on
375             # l'enregistre dans le niveau
376             self.nom_niveau_definition = self.definition.niveau.nom
377             self.niveau = self.parent.dict_niveaux[self.nom_niveau_definition]
378             self.niveau.register(self)
379          else:
380             # La définition est au niveau global
381             self.nom_niveau_definition = 'JDC'
382             self.niveau=self.parent
383       else:
384          self.jdc = self.parent =None
385          self.id=None
386          self.niveau=None
387