]> SALOME platform Git repositories - tools/eficas.git/blob - Ihm/I_MACRO_ETAPE.py
Salome HOME
PN : pour les clefs documentaires
[tools/eficas.git] / Ihm / I_MACRO_ETAPE.py
1 #            CONFIGURATION MANAGEMENT OF EDF VERSION
2 # ======================================================================
3 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
4 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
5 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
6 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
7 # (AT YOUR OPTION) ANY LATER VERSION.
8 #
9 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
10 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
11 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
12 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
13 #
14 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
15 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
16 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
17 #
18 #
19 # ======================================================================
20 """
21 """
22 # Modules Python
23 import sys
24 import traceback,types,string
25
26 # Modules Eficas
27 import I_ETAPE
28 from Noyau.N_ASSD import ASSD
29
30 # import rajoutés suite à l'ajout de Build_sd --> à résorber
31 import Noyau, Validation.V_MACRO_ETAPE
32 from Noyau import N_Exception
33 from Noyau.N_Exception import AsException
34 # fin import à résorber
35
36 class MACRO_ETAPE(I_ETAPE.ETAPE):
37
38   def __init__(self):
39       self.typret=None
40       self.recorded_units={}
41
42   def get_sdprods(self,nom_sd):
43     """ 
44          Fonction : retourne le concept produit par l etape de nom nom_sd
45          s il existe sinon None
46     """
47     if self.sd and self.sd.nom == nom_sd :return self.sd
48     for co in self.sdprods:
49       if co.nom == nom_sd:return co
50     if type(self.definition.op_init) == types.FunctionType:
51       d={}
52       apply(self.definition.op_init,(self,d))
53       return d.get(nom_sd,None)
54     return None
55
56   def get_contexte_jdc(self,fichier,text):
57     """ 
58          Interprète text comme un texte de jdc et retourne le 
59          contexte final
60          cad le dictionnaire des sd disponibles à la dernière étape
61          Si text n'est pas un texte de jdc valide, retourne None
62          ou leve une exception
63          --> utilisée par ops.POURSUITE et INCLUDE
64     """
65     try:
66        # on essaie de créer un objet JDC auxiliaire avec un contexte initial
67        context_ini = self.parent.get_contexte_avant(self)
68
69        # Indispensable avant de creer un nouveau JDC
70        CONTEXT.unset_current_step()
71        args=self.jdc.args
72        prefix_include=None
73        if hasattr(self,'prefix'):
74           prefix_include=self.prefix
75        # ATTENTION : le dictionnaire recorded_units sert à memoriser les unites des 
76        # fichiers inclus. Il est preferable de garder le meme dictionnaire pendant
77        # tout le traitement et de ne pas le reinitialiser brutalement (utiliser clear plutot)
78        # si on ne veut pas perdre la memoire des unites.
79        # En principe si la memorisation est faite au bon moment il n'est pas necessaire
80        # de prendre cette precaution mais ce n'est pas vrai partout.
81        old_recorded_units=self.recorded_units.copy()
82        self.recorded_units.clear()
83
84        j=self.JdC_aux( procedure=text,cata=self.jdc.cata,
85                                 nom=fichier,
86                                 context_ini = context_ini,
87                                 appli=self.jdc.appli,
88                                 jdc_pere=self.jdc,etape_include=self,
89                                 prefix_include=prefix_include,
90                                 recorded_units=self.recorded_units,
91                                 old_recorded_units=old_recorded_units,**args)
92
93        j.analyse()
94        # On récupère les étapes internes (pour validation)
95        self.etapes=j.etapes
96     except:
97        traceback.print_exc()
98        # On force le contexte (etape courante) à self
99        CONTEXT.unset_current_step()
100        CONTEXT.set_current_step(self)
101        return None
102
103     if not j.cr.estvide():
104        # Erreurs dans l'INCLUDE. On garde la memoire du fichier mais on n'insere pas les concepts
105        # On force le contexte (etape courante) à self
106        CONTEXT.unset_current_step()
107        CONTEXT.set_current_step(self)
108        raise Exception("Impossible de relire le fichier\n"+str(j.cr))
109
110     cr=j.report()
111     if not cr.estvide():
112        # On force le contexte (etape courante) à self
113        CONTEXT.unset_current_step()
114        CONTEXT.set_current_step(self)
115        raise Exception("Le fichier include contient des erreurs\n"+str(j.cr))
116
117     # On recupere le contexte apres la derniere etape
118     j_context=j.get_contexte_avant(None)
119
120     # Cette verification n'est plus necessaire elle est integree dans le JDC_INCLUDE
121     self.verif_contexte(j_context)
122
123     # On remplit le dictionnaire des concepts produits inclus
124     # en retirant les concepts présents dans le  contexte initial
125     # On ajoute egalement le concept produit dans le sds_dict du parent
126     # sans verification car on est sur (verification integrée) que le nommage est possible
127     self.g_context.clear()
128     for k,v in j_context.items():
129        if not context_ini.has_key(k) or context_ini[k] != v:
130            self.g_context[k]=v
131            self.parent.sds_dict[k]=v
132
133
134     # On recupere le contexte courant
135     self.current_context=j.current_context
136     self.index_etape_courante=j.index_etape_courante
137
138     # XXX j.supprime() ???
139     # On rétablit le contexte (etape courante) à self
140     CONTEXT.unset_current_step()
141     CONTEXT.set_current_step(self)
142
143     return j_context
144
145   def verif_contexte(self,context):
146      """
147          On verifie que le contexte context peut etre inséré dans le jeu
148          de commandes à la position de self
149      """
150      for nom_sd,sd in context.items():
151         if not isinstance(sd,ASSD):continue
152         #if self.parent.get_sd_apres_etape(nom_sd,etape=self):
153         if self.parent.get_sd_apres_etape_avec_detruire(nom_sd,sd,etape=self):
154            # Il existe un concept produit par une etape apres self => impossible d'inserer
155            # On force le contexte (etape courante) à self
156            CONTEXT.unset_current_step()
157            CONTEXT.set_current_step(self)
158            raise Exception("Impossible d'inclure le fichier. Un concept de nom " + 
159                            "%s existe déjà dans le jeu de commandes." % nom_sd)
160
161   def reevalue_sd_jdc(self):
162      """
163          Avec la liste des SD qui ont été supprimées, propage la 
164          disparition de ces SD dans toutes les étapes et descendants
165      """
166      l_sd_supp,l_sd_repl = self.diff_contextes()
167      for sd in l_sd_supp:
168         self.parent.delete_concept_after_etape(self,sd)
169      for old_sd,sd in l_sd_repl:
170         self.parent.replace_concept_after_etape(self,old_sd,sd)
171
172   def diff_contextes(self):
173      """ 
174          Réalise la différence entre les 2 contextes 
175          old_contexte_fichier_init et contexte_fichier_init
176          cad retourne la liste des sd qui ont disparu ou ne derivent pas de la meme classe
177          et des sd qui ont ete remplacees
178      """
179      if not hasattr(self,'old_contexte_fichier_init'):return [],[]
180      l_sd_suppressed = []
181      l_sd_replaced = []
182      for old_key in self.old_contexte_fichier_init.keys():
183        if not self.contexte_fichier_init.has_key(old_key):
184          if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
185            l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
186        else:
187          if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
188             # Un concept de meme nom existe
189             old_class=self.old_contexte_fichier_init[old_key].__class__
190             if not isinstance(self.contexte_fichier_init[old_key],old_class):
191                # S'il n'est pas d'une classe derivee, on le supprime
192                l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
193             else:
194                l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
195      return l_sd_suppressed,l_sd_replaced
196       
197   def control_sdprods(self,d):
198       """
199           Cette methode doit updater le contexte fournit par
200           l'appelant en argument (d) en fonction de sa definition
201           tout en verifiant que ses concepts produits ne sont pas
202           deja definis dans le contexte
203       """
204       if hasattr(self,"fichier_unite"):
205          self.update_fichier_init(self.fichier_unite)
206          self.init_modif()
207
208       if type(self.definition.op_init) == types.FunctionType:
209         apply(self.definition.op_init,(self,d))
210       if self.sd:
211         if d.has_key(self.sd.nom):
212            # Le concept est deja defini
213            if self.reuse and self.reuse is d[self.sd.nom]:
214               # Le concept est reutilise : situation normale
215               pass
216            else:
217               # Redefinition du concept, on l'annule
218               #XXX on pourrait simplement annuler son nom pour conserver les objets
219               # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
220               self.sd=self.reuse=self.sdnom=None
221               self.init_modif()
222         else:
223            # Le concept n'est pas defini, on peut updater d
224            d[self.sd.nom]=self.sd
225       # On verifie les concepts a droite du signe =
226       for co in self.sdprods:
227         if d.has_key(co.nom) and co is not d[co.nom] :
228            self.delete_concept(co)
229         else:
230            d[co.nom]=co
231        
232
233   def supprime_sdprods(self):
234       """
235           Fonction:
236           Lors d'une destruction d'etape, detruit tous les concepts produits
237           Un opérateur n a qu un concept produit
238           Une procedure n'en a aucun
239           Une macro en a en général plus d'un
240       """
241       if not self.is_reentrant() :
242          # l'étape n'est pas réentrante
243          # le concept retourné par l'étape est à supprimer car il était
244          # créé par l'étape
245          if self.sd != None :
246             self.parent.del_sdprod(self.sd)
247             self.parent.delete_concept(self.sd)
248       # On détruit les concepts à droite du signe =
249       for co in self.sdprods:
250          self.parent.del_sdprod(co)
251          self.parent.delete_concept(co)
252       # Si la macro a des etapes et des concepts inclus, on les detruit
253       for nom_sd,co in self.g_context.items():
254          if not isinstance(co,ASSD):continue
255          self.parent.del_sdprod(co)
256          self.parent.delete_concept(co)
257       # On met g_context à blanc
258       self.g_context={}
259          
260   def make_contexte_include(self,fichier,text):
261     """
262         Cette méthode sert à créer un contexte en interprétant un texte source
263         Python
264     """
265     # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
266     contexte = self.get_contexte_jdc(fichier,text)
267     if contexte == None :
268       raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
269     else:
270       # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
271       # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
272       # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
273       # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
274       # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
275       # g_context est utilisé pour avoir les concepts produits par la macro
276       # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
277       self.contexte_fichier_init = contexte
278
279   def reevalue_fichier_init(self):
280       """Recalcule les concepts produits par le fichier enregistre"""
281       old_context=self.contexte_fichier_init
282       try:
283          self.make_contexte_include(self.fichier_ini ,self.fichier_text)
284       except:
285          l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
286          self.fichier_err = string.join(l)
287          #self.etapes=[]
288          self.g_context={}
289
290          self.old_contexte_fichier_init=old_context
291          self.contexte_fichier_init={}
292          self.reevalue_sd_jdc()
293          return
294
295       # L'evaluation s'est bien passee
296       self.fichier_err = None
297       self.old_contexte_fichier_init=old_context
298       self.reevalue_sd_jdc()
299
300   def update_fichier_init(self,unite):
301       """Reevalue le fichier init sans demander (dans la mesure du possible) a l'utilisateur 
302          les noms des fichiers
303          Ceci suppose que les relations entre unites et noms ont été memorisees préalablement
304       """
305       
306       self.fichier_err=None
307       self.old_contexte_fichier_init=self.contexte_fichier_init
308
309       if unite != self.fichier_unite or not self.parent.recorded_units.has_key(unite):
310          # Changement d'unite ou Nouvelle unite
311          f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
312          units={}
313          if f is not None:
314             self.fichier_ini = f
315             self.fichier_text=text
316          self.recorded_units=units
317          if self.fichier_ini is None and self.jdc.appli:
318             self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
319                      message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
320       else:
321          # Meme unite existante
322          f,text,units=self.parent.recorded_units[unite]
323          self.fichier_ini = f
324          self.fichier_text=text
325          self.recorded_units=units
326
327       if self.fichier_ini is None:
328          # Le fichier n'est pas défini
329          self.fichier_err="Le fichier associé n'est pas défini"
330          self.parent.change_unit(unite,self,self.fichier_unite)
331          self.g_context={}
332          self.contexte_fichier_init={}
333          self.parent.reset_context()
334          self.reevalue_sd_jdc()
335          return
336
337       try:
338         self.make_contexte_include(self.fichier_ini,self.fichier_text)
339         # Les 3 attributs fichier_ini fichier_text recorded_units doivent etre corrects
340         # avant d'appeler change_unit
341         self.parent.change_unit(unite,self,self.fichier_unite)
342       except:
343         # Erreurs lors de l'evaluation de text dans un JDC auxiliaire
344         l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
345         # On conserve la memoire du nouveau fichier
346         # mais on n'utilise pas les concepts crees par ce fichier
347         # on met l'etape en erreur : fichier_err=string.join(l)
348         self.fichier_err=string.join(l)
349         self.parent.change_unit(unite,self,self.fichier_unite)
350         self.g_context={}
351         self.contexte_fichier_init={}
352
353       # Le contexte du parent doit etre reinitialise car les concepts produits ont changé
354       self.parent.reset_context()
355       # Si des concepts ont disparu lors du changement de fichier, on demande leur suppression
356       self.reevalue_sd_jdc()
357
358   def record_unite(self):
359       if self.nom == "POURSUITE":
360          self.parent.record_unit(None,self)
361       else:
362          if hasattr(self,'fichier_unite') : 
363             self.parent.record_unit(self.fichier_unite,self)
364
365   def get_file_memo(self,unite=None,fic_origine=''):
366       """Retourne le nom du fichier et le source correspondant a l'unite unite
367          Initialise en plus recorded_units
368       """
369       units={}
370       if self.parent.old_recorded_units.has_key(unite):
371          f,text,units=self.parent.old_recorded_units[unite]
372          self.recorded_units=units
373          return f,text
374       elif self.jdc :
375          f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
376       else:
377          f,text=None,None
378       self.recorded_units=units
379       if f is None and self.jdc.appli:
380          self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
381                           message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
382       return f,text
383
384 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
385   def get_file(self,unite=None,fic_origine=''):
386       """Retourne le nom du fichier et le source correspondant a l'unite unite
387          Initialise en plus recorded_units
388       """
389       units={}
390       if self.jdc :
391          f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
392       else:
393          f,text=None,None
394       self.recorded_units=units
395       return f,text
396
397 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
398   def make_include(self,unite=None):
399       """
400           Inclut un fichier dont l'unite logique est unite
401           Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
402           Si l'INCLUDE est invalide, la methode doit produire une exception 
403           Sinon on retourne None. Les concepts produits par l'INCLUDE sont
404           pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
405       """
406
407       # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
408       # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
409       del self.unite
410       # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
411       if not unite : return
412
413       if not hasattr(self,'fichier_ini') : 
414          # Si le fichier n'est pas defini on le demande
415          f,text=self.get_file_memo(unite=unite,fic_origine=self.parent.nom)
416          # On memorise le fichier retourne
417          self.fichier_ini  = f
418          self.fichier_text = text
419          self.contexte_fichier_init={}
420          self.fichier_unite=unite
421          self.fichier_err=None
422          import Extensions.jdc_include
423          self.JdC_aux=Extensions.jdc_include.JdC_include
424
425          if f is None:
426              self.fichier_err="Le fichier INCLUDE n est pas defini"
427              self.parent.record_unit(unite,self)
428              raise Exception(self.fichier_err)
429
430          try:
431            self.make_contexte_include(self.fichier_ini ,self.fichier_text)
432            self.parent.record_unit(unite,self)
433          except:
434            l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
435            if self.jdc.appli:
436               self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
437                                             message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
438                                            )
439            self.parent.record_unit(unite,self)
440            self.g_context={}
441            self.fichier_err = string.join(l)
442            self.contexte_fichier_init={}
443            raise
444
445       else:
446          # Si le fichier est deja defini on ne reevalue pas le fichier
447          # et on leve une exception si une erreur a été enregistrée
448          self.update_fichier_init(unite)
449          self.fichier_unite=unite
450          if self.fichier_err is not None: raise Exception(self.fichier_err)
451         
452
453 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
454   def make_contexte(self,fichier,text):
455     """
456         Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
457         en interprétant un texte source Python
458         Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU
459     """
460     # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
461     # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
462     if hasattr(self,'mat'):del self.mat
463     self.fichier_ini =fichier
464     self.fichier_unite =fichier
465     self.fichier_text=text
466     self.fichier_err=None 
467     self.contexte_fichier_init={}
468     # On specifie la classe a utiliser pour le JDC auxiliaire
469     import Extensions.jdc_include
470     self.JdC_aux=Extensions.jdc_include.JdC_include
471     try:
472        self.make_contexte_include(self.fichier_ini ,self.fichier_text)
473        self.parent.record_unit(self.fichier_unite,self)
474     except:
475        l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
476        self.fichier_err = string.join(l)
477        self.parent.record_unit(self.fichier_unite,self)
478        self.g_context={}
479        self.contexte_fichier_init={}
480        raise
481
482 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
483   def update_sdprod(self,cr='non'):
484      # Cette methode peut etre appelee dans EFICAS avec des mots cles de 
485      # la commande modifies. Ceci peut conduire a la construction ou
486      # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
487      # Il faut donc positionner le current_step avant l'appel
488      CONTEXT.unset_current_step()
489      CONTEXT.set_current_step(self)
490      valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
491      CONTEXT.unset_current_step()
492      return valid
493
494 #ATTENTION SURCHARGE: cette methode surcharge celle de Noyau a garder en synchro 
495   def Build_sd(self,nom):
496       """
497            Methode de Noyau surchargee pour poursuivre malgre tout
498            si une erreur se produit pendant la creation du concept produit
499       """
500       try:
501          sd=Noyau.N_MACRO_ETAPE.MACRO_ETAPE.Build_sd(self,nom)
502          self.state="modified"
503       except AsException,e:
504          # Une erreur s'est produite lors de la construction du concept
505          # Comme on est dans EFICAS, on essaie de poursuivre quand meme
506          # Si on poursuit, on a le choix entre deux possibilités :
507          # 1. on annule la sd associée à self
508          # 2. on la conserve mais il faut la retourner
509          # On choisit de l'annuler
510          # En plus il faut rendre coherents sdnom et sd.nom
511          self.sd=None
512          self.sdnom=None
513          self.state="unchanged"
514          self.valid=0
515
516       return self.sd
517
518 #ATTENTION SURCHARGE: cette methode surcharge celle de Noyau a garder en synchro 
519   def make_poursuite(self):
520       """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
521       """
522       if not hasattr(self,'fichier_ini') :
523          # Si le fichier n'est pas defini on le demande
524          f,text=self.get_file_memo(fic_origine=self.parent.nom)
525          # On memorise le fichier retourne
526          self.fichier_ini = f
527          self.fichier_unite = None
528          self.fichier_text = text
529          self.fichier_err=None
530          import Extensions.jdc_include
531          self.JdC_aux=Extensions.jdc_include.JdC_poursuite
532          self.contexte_fichier_init={}
533
534          if f is None:
535              self.fichier_err="Le fichier POURSUITE n'est pas defini"
536              self.parent.record_unit(None,self)
537              raise Exception(self.fichier_err)
538
539          try:
540            self.make_contexte_include(self.fichier_ini,self.fichier_text)
541            self.parent.record_unit(None,self)
542          except:
543            l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
544            if self.jdc.appli:
545               self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
546                                             message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
547                                            )
548            self.parent.record_unit(None,self)
549            self.g_context={}
550            self.fichier_err = string.join(l)
551            self.contexte_fichier_init={}
552            raise
553
554       else:
555          # Si le fichier est deja defini on ne reevalue pas le fichier
556          # et on leve une exception si une erreur a été enregistrée
557          self.update_fichier_init(None)
558          if self.fichier_err is not None: raise Exception(self.fichier_err)
559