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