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