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