Salome HOME
3b51fbb6444c90bab0d755a51298bb2bbd435e33
[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    def get_noms_sd_oper_reentrant(self):
295       """ 
296           Retourne la liste des noms de concepts utilisés à l'intérieur de la commande
297           qui sont du type que peut retourner cette commande 
298       """
299       liste_sd = self.get_sd_utilisees()
300       l_noms = []
301       if type(self.definition.sd_prod) == types.FunctionType:
302         d=self.cree_dict_valeurs(self.mc_liste)
303         try:
304           classe_sd_prod = apply(self.definition.sd_prod,(),d)
305         except:
306           return []
307       else:
308         classe_sd_prod = self.definition.sd_prod
309       for sd in liste_sd :
310         if sd.__class__ is classe_sd_prod : l_noms.append(sd.nom)
311       l_noms.sort()
312       return l_noms
313
314    def get_genealogie(self):
315       """ 
316           Retourne la liste des noms des ascendants de l'objet self
317           en s'arretant à la première ETAPE rencontrée
318       """
319       return [self.nom]
320
321    def verif_existence_sd(self):
322      """
323         Vérifie que les structures de données utilisées dans self existent bien dans le contexte
324         avant étape, sinon enlève la référence à ces concepts
325      """
326      for motcle in self.mc_liste :
327          motcle.verif_existence_sd()
328      
329 #ATTENTION SURCHARGE: a garder en synchro ou a reintegrer dans le Noyau
330    def Build_sd(self,nom):
331       """
332            Methode de Noyau surchargee pour poursuivre malgre tout
333            si une erreur se produit pendant la creation du concept produit
334       """
335       try:
336          sd=Noyau.N_ETAPE.ETAPE.Build_sd(self,nom)
337          self.state="modified"
338       except AsException,e:
339          # Une erreur s'est produite lors de la construction du concept
340          # Comme on est dans EFICAS, on essaie de poursuivre quand meme
341          # Si on poursuit, on a le choix entre deux possibilités :
342          # 1. on annule la sd associée à self
343          # 2. on la conserve mais il faut la retourner
344          # En plus il faut rendre coherents sdnom et sd.nom
345          self.sd=None
346          self.sdnom=None
347          self.state="unchanged"
348          self.valid=0
349
350       return self.sd
351
352 #ATTENTION SURCHARGE: cette methode doit etre gardée en synchronisation avec Noyau
353    def make_register(self):
354       """
355          Initialise les attributs jdc, id, niveau et réalise les
356          enregistrements nécessaires
357          Pour EFICAS, on tient compte des niveaux
358          Surcharge la methode make_register du package Noyau
359       """
360       if self.parent :
361          self.jdc = self.parent.get_jdc_root()
362          self.id=   self.parent.register(self)
363          if self.definition.niveau :
364             # La définition est dans un niveau. En plus on
365             # l'enregistre dans le niveau
366             self.nom_niveau_definition = self.definition.niveau.nom
367             self.niveau = self.parent.dict_niveaux[self.nom_niveau_definition]
368             self.niveau.register(self)
369          else:
370             # La définition est au niveau global
371             self.nom_niveau_definition = 'JDC'
372             self.niveau=self.parent
373       else:
374          self.jdc = self.parent =None
375          self.id=None
376          self.niveau=None
377