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