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