Salome HOME
4664252bc48c38ca47cd0e43067696e00e31a739
[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_sdprod(self,sd):
272       """
273          Supprime le concept produit sd s'il est produit par l'etape
274       """
275       if sd is not self.sd:return
276       if self.sd != None :
277          self.init_modif()
278          self.parent.del_sdprod(sd)
279          self.sd=None
280          self.fin_modif()
281          self.parent.delete_concept(sd)
282
283    def supprime_sdprods(self):
284       """ 
285             Fonction:
286             Lors d'une destruction d'etape, detruit tous les concepts produits
287             Un opérateur n a qu un concept produit 
288             Une procedure n'en a aucun
289             Une macro en a en général plus d'un
290       """
291       #print "supprime_sdprods",self
292       if self.reuse is self.sd :return
293       # l'étape n'est pas réentrante
294       # le concept retourné par l'étape est à supprimer car il était 
295       # créé par l'étape
296       if self.sd != None :
297          self.parent.del_sdprod(self.sd)
298          self.parent.delete_concept(self.sd)
299
300    def close(self):
301       return
302
303    def delete_concept(self,sd):
304       """ 
305           Inputs :
306              - sd=concept detruit
307           Fonction :
308           Mettre a jour les mots cles de l etape et eventuellement 
309           le concept produit si reuse
310           suite à la disparition du concept sd
311           Seuls les mots cles simples MCSIMP font un traitement autre 
312           que de transmettre aux fils
313       """
314       if self.reuse and self.reuse == sd:
315         self.sd=self.reuse=None
316         self.init_modif()
317       for child in self.mc_liste :
318         child.delete_concept(sd)
319
320    def replace_concept(self,old_sd,sd):
321       """
322           Inputs :
323              - old_sd=concept remplace
324              - sd = nouveau concept 
325           Fonction :
326           Mettre a jour les mots cles de l etape et eventuellement
327           le concept produit si reuse
328           suite au remplacement  du concept old_sd
329       """
330       if self.reuse and self.reuse == old_sd:
331         self.sd=self.reuse=sd
332         self.init_modif()
333       for child in self.mc_liste :
334         child.replace_concept(old_sd,sd)
335
336    def reset_context(self):
337       pass
338
339    def get_noms_sd_oper_reentrant(self):
340       """ 
341           Retourne la liste des noms de concepts utilisés à l'intérieur de la commande
342           qui sont du type que peut retourner cette commande 
343       """
344       liste_sd = self.get_sd_utilisees()
345       l_noms = []
346       if type(self.definition.sd_prod) == types.FunctionType:
347         d=self.cree_dict_valeurs(self.mc_liste)
348         try:
349           classe_sd_prod = apply(self.definition.sd_prod,(),d)
350         except:
351           return []
352       else:
353         classe_sd_prod = self.definition.sd_prod
354       for sd in liste_sd :
355         if sd.__class__ is classe_sd_prod : l_noms.append(sd.nom)
356       l_noms.sort()
357       return l_noms
358
359    def get_genealogie(self):
360       """ 
361           Retourne la liste des noms des ascendants de l'objet self
362           en s'arretant à la première ETAPE rencontrée
363       """
364       return [self.nom]
365
366    def verif_existence_sd(self):
367      """
368         Vérifie que les structures de données utilisées dans self existent bien dans le contexte
369         avant étape, sinon enlève la référence à ces concepts
370      """
371      #print "verif_existence_sd",self.sd
372      for motcle in self.mc_liste :
373          motcle.verif_existence_sd()
374      
375 #ATTENTION SURCHARGE: a garder en synchro ou a reintegrer dans le Noyau
376    def Build_sd(self,nom):
377       """
378            Methode de Noyau surchargee pour poursuivre malgre tout
379            si une erreur se produit pendant la creation du concept produit
380       """
381       try:
382          sd=Noyau.N_ETAPE.ETAPE.Build_sd(self,nom)
383       except AsException,e:
384          # Une erreur s'est produite lors de la construction du concept
385          # Comme on est dans EFICAS, on essaie de poursuivre quand meme
386          # Si on poursuit, on a le choix entre deux possibilités :
387          # 1. on annule la sd associée à self
388          # 2. on la conserve mais il faut la retourner
389          # En plus il faut rendre coherents sdnom et sd.nom
390          self.sd=None
391          self.sdnom=None
392          self.state="unchanged"
393          self.valid=0
394
395       return self.sd
396
397 #ATTENTION SURCHARGE: cette methode doit etre gardée en synchronisation avec Noyau
398    def make_register(self):
399       """
400          Initialise les attributs jdc, id, niveau et réalise les
401          enregistrements nécessaires
402          Pour EFICAS, on tient compte des niveaux
403          Surcharge la methode make_register du package Noyau
404       """
405       if self.parent :
406          self.jdc = self.parent.get_jdc_root()
407          self.id=   self.parent.register(self)
408          self.UserError=self.jdc.UserError
409          if self.definition.niveau :
410             # La définition est dans un niveau. En plus on
411             # l'enregistre dans le niveau
412             self.nom_niveau_definition = self.definition.niveau.nom
413             self.niveau = self.parent.dict_niveaux[self.nom_niveau_definition]
414             self.niveau.register(self)
415          else:
416             # La définition est au niveau global
417             self.nom_niveau_definition = 'JDC'
418             self.niveau=self.parent
419       else:
420          self.jdc = self.parent =None
421          self.id=None
422          self.niveau=None
423          self.UserError="UserError"
424