Salome HOME
7e58aa0382e47413e2ccb7055ebe1d43bc0f1501
[tools/eficas.git] / Ihm / I_MACRO_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
25 import traceback,types,string
26
27 # Modules Eficas
28 import I_ETAPE
29 import I_ENTITE
30 import I_OBJECT
31 import Noyau
32 from Noyau.N_ASSD import ASSD
33 from Noyau import N__F
34 import convert
35 from Extensions import param2
36
37 # import rajoutés suite à l'ajout de Build_sd --> à résorber
38 import Noyau, Validation.V_MACRO_ETAPE
39 from Noyau import N_Exception
40 from Noyau.N_Exception import AsException
41 import Accas # attention aux imports circulaires
42 # fin import à résorber
43
44 class MACRO_ETAPE(I_ETAPE.ETAPE):
45
46   def __init__(self):
47       self.typret=None
48       #indique si le jeu de commande inclus a pu etre analysé par convert
49       #pour etre editable (0=NON, 1=OUI)
50       self.text_converted=1
51       self.text_error=""
52       self.recorded_units={}
53
54   def get_sdprods(self,nom_sd):
55     """ 
56          Fonction : retourne le concept produit par l etape de nom nom_sd
57          s il existe sinon None
58     """
59     if self.sd and self.sd.nom == nom_sd :return self.sd
60     for co in self.sdprods:
61       if co.nom == nom_sd:return co
62     if type(self.definition.op_init) == types.FunctionType:
63       d={}
64       apply(self.definition.op_init,(self,d))
65       return d.get(nom_sd,None)
66     return None
67
68   def get_contexte_jdc(self,fichier,text):
69     """ 
70          Interprète text comme un texte de jdc et retourne le contexte final.
71
72          Le contexte final est le dictionnaire des sd disponibles à la dernière étape.
73          Si text n'est pas un texte de jdc valide, retourne None
74          ou leve une exception
75          --> utilisée par ops.POURSUITE et INCLUDE
76     """
77     #print "get_contexte_jdc",self,self.nom
78     # On recupere l'etape courante
79     step=CONTEXT.get_current_step()
80     try:
81        # on essaie de créer un objet JDC auxiliaire avec un contexte initial
82        # Attention get_contexte_avant retourne un dictionnaire qui contient
83        # le contexte courant. Ce dictionnaire est reactualise regulierement.
84        # Si on veut garder l'etat du contexte fige, il faut en faire une copie.
85        context_ini = self.parent.get_contexte_avant(self).copy()
86        #print "get_contexte_jdc",context_ini.keys()
87
88        # Indispensable avant de creer un nouveau JDC
89        CONTEXT.unset_current_step()
90        args=self.jdc.args
91        prefix_include=None
92        if hasattr(self,'prefix'):
93           prefix_include=self.prefix
94        # ATTENTION : le dictionnaire recorded_units sert à memoriser les unites des 
95        # fichiers inclus. Il est preferable de garder le meme dictionnaire pendant
96        # tout le traitement et de ne pas le reinitialiser brutalement (utiliser 
97        # clear plutot) si on ne veut pas perdre la memoire des unites.
98        # En principe si la memorisation est faite au bon moment il n'est pas necessaire
99        # de prendre cette precaution mais ce n'est pas vrai partout.
100        old_recorded_units=self.recorded_units.copy()
101
102        # on supprime l'ancien jdc_aux s'il existe
103        if hasattr(self,'jdc_aux') and self.jdc_aux:
104           self.jdc_aux.supprime_aux()
105
106        if fichier is None:fichier="SansNom"
107
108        # Il faut convertir le texte inclus en fonction du format
109        # sauf les INCLUDE_MATERIAU
110        self.text_converted=0
111        self.text_error=""
112        if self.nom != "INCLUDE_MATERIAU":
113           if self.parent.appli.ihm == "QT" :
114               format=self.jdc.appli.format_fichier
115           else :
116               format=self.jdc.appli.format_fichier.get()
117           if convert.plugins.has_key(format):
118               # Le convertisseur existe on l'utilise
119               p=convert.plugins[format]()
120               p.text=text
121               text=p.convert('exec',self.jdc.appli)
122               #Si le fichier ne peut pas etre converti, le cr n'est pas vide
123               #et le texte est retourné tel que
124               if not p.cr.estvide(): 
125                   self.text_converted=0
126                   self.text_error=str(p.cr)
127               else:
128                   self.text_converted=1
129
130        j=self.JdC_aux( procedure=text, nom=fichier,
131                                 appli=self.jdc.appli,
132                                 cata=self.jdc.cata,
133                                 cata_ord_dico=self.jdc.cata_ordonne_dico,
134                                 context_ini = context_ini,
135                                 jdc_pere=self.jdc,etape_include=self,
136                                 prefix_include=prefix_include,
137                                 recorded_units=self.recorded_units,
138                                 old_recorded_units=old_recorded_units,**args)
139
140        j.analyse()
141        # On récupère les étapes internes (pour validation)
142        self.etapes=j.etapes
143        self.jdc_aux=j
144     except:
145        traceback.print_exc()
146        # On retablit l'etape courante step
147        CONTEXT.unset_current_step()
148        CONTEXT.set_current_step(step)
149        return None
150
151     if not j.cr.estvide():
152        # Erreurs dans l'INCLUDE. On garde la memoire du fichier 
153        # mais on n'insere pas les concepts
154        # On retablit l'etape courante step
155        #print j.cr
156        CONTEXT.unset_current_step()
157        CONTEXT.set_current_step(step)
158        raise Exception("Impossible de relire le fichier\n"+str(j.cr))
159
160     if not j.isvalid():
161        # L'INCLUDE n'est pas valide.
162        # on produit un rapport d'erreurs
163        cr=j.report()
164        #print cr
165        # On retablit l'etape courante step
166        CONTEXT.unset_current_step()
167        CONTEXT.set_current_step(step)
168        raise Exception("Le fichier include contient des erreurs\n"+str(cr))
169
170     # Si aucune erreur rencontrée
171     # On recupere le contexte de l'include verifie
172     try:
173        j_context=j.get_verif_contexte()
174        #print j_context.keys()
175        #print j.g_context.keys()
176     except:
177        # On retablit l'etape courante step
178        CONTEXT.unset_current_step()
179        CONTEXT.set_current_step(step)
180        raise
181
182     # Si on est arrivé ici, le texte du fichier inclus (INCLUDE, POURSUITE, ...)
183     # est valide et insérable dans le JDC
184
185     # On remplit le dictionnaire des concepts produits inclus
186     # en retirant les concepts présents dans le  contexte initial
187     # On ajoute egalement le concept produit dans le sds_dict du parent
188     # sans verification car on est sur (verification integrée) que 
189     # le nommage est possible
190     self.g_context.clear()
191     for k,v in j_context.items():
192        if not context_ini.has_key(k) or context_ini[k] != v:
193            self.g_context[k]=v
194            self.parent.sds_dict[k]=v
195
196     #Ce traitement n'est réalisé que dans les cas suivants:
197     #     - si convert n'a pas pu convertir le jeu de commandes
198     #     - et ce n'est pas un INCLUDE_MATERIAU
199     #On collecte les variables Python qui ne sont pas dans le contexte initial
200     #et dans le contexte validé et on en fait un pseudo-parametre (Variable)
201     if self.text_converted == 0 and self.nom != "INCLUDE_MATERIAU":
202         for k,v in j.g_context.items():
203             if k in context_ini:continue
204             if k in j_context:continue
205             if isinstance(v,ASSD):continue
206             if isinstance(v,I_ENTITE.ENTITE):continue
207             if isinstance(v,I_OBJECT.OBJECT):continue
208             if callable(v):continue
209             self.g_context[k]=param2.Variable(k,v)
210
211     # On recupere le contexte courant
212     self.current_context=j.current_context
213     self.index_etape_courante=j.index_etape_courante
214     self.jdc_aux=j
215
216     # On retablit l'etape courante step
217     CONTEXT.unset_current_step()
218     CONTEXT.set_current_step(step)
219
220     return j_context
221
222   def reevalue_sd_jdc(self):
223      """
224          Avec la liste des SD qui ont été supprimées, propage la 
225          disparition de ces SD dans toutes les étapes et descendants
226      """
227      #print "reevalue_sd_jdc"
228      l_sd_supp,l_sd_repl = self.diff_contextes()
229      for sd in l_sd_supp:
230         self.parent.delete_concept_after_etape(self,sd)
231      for old_sd,sd in l_sd_repl:
232         self.parent.replace_concept_after_etape(self,old_sd,sd)
233
234   def diff_contextes(self):
235      """ 
236          Réalise la différence entre les 2 contextes 
237          old_contexte_fichier_init et contexte_fichier_init
238          cad retourne la liste des sd qui ont disparu ou ne derivent pas 
239          de la meme classe et des sd qui ont ete remplacees
240      """
241      if not hasattr(self,'old_contexte_fichier_init'):return [],[]
242      l_sd_suppressed = []
243      l_sd_replaced = []
244      for old_key in self.old_contexte_fichier_init.keys():
245        if not self.contexte_fichier_init.has_key(old_key):
246          if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
247            l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
248        else:
249          if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
250             # Un concept de meme nom existe
251             old_class=self.old_contexte_fichier_init[old_key].__class__
252             if not isinstance(self.contexte_fichier_init[old_key],old_class):
253                # S'il n'est pas d'une classe derivee, on le supprime
254                l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
255             else:
256                l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
257      return l_sd_suppressed,l_sd_replaced
258       
259   def control_sdprods(self,d):
260       """
261           Cette methode doit verifier que les concepts produits par la 
262           commande ne sont pas incompatibles avec le contexte fourni (d).
263           Si c'est le cas, le concept produit doit etre supprime
264           Si la macro a elle meme des etapes, elle doit propager
265           le traitement (voir methode control_jdc_context_apres de I_JDC)
266       """
267       #print "I_MACRO_ETAPE.control_sdprods",d.keys(),self.nom,self.sd and self.sd.nom
268       if self.sd:
269         if d.has_key(self.sd.nom):
270            # Le concept est deja defini
271            if self.reuse and self.reuse is d[self.sd.nom]:
272               # Le concept est reutilise : situation normale
273               pass
274            else:
275               # Redefinition du concept, on l'annule
276               #XXX on pourrait simplement annuler son nom pour conserver les objets
277               # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
278               self.init_modif()
279               sd=self.sd
280               self.sd=self.reuse=self.sdnom=None
281               self.parent.delete_concept_after_etape(self,sd)
282               self.fin_modif()
283
284       # On verifie les concepts a droite du signe =
285       self.init_modif()
286       sdprods=self.sdprods[:]
287       self.sdprods=[]
288       for co in sdprods:
289         if d.has_key(co.nom) and co is not d[co.nom] :
290            #nettoie les mots cles de l'étape qui ont comme valeur co
291            self.delete_concept(co)
292            #supprime les references a co dans les etapes suivantes
293            self.parent.delete_concept_after_etape(self,co)
294         else:
295            self.sdprods.append(co)
296       self.fin_modif()
297        
298       for e in self.etapes:
299           e.control_sdprods(d)
300           e.update_context(d)
301
302   def supprime_sdprod(self,sd):
303       """
304          Supprime le concept produit sd s'il est produit par l'etape
305       """
306       if sd in self.sdprods:
307          self.init_modif()
308          self.parent.del_sdprod(sd)
309          self.sdprods.remove(sd)
310          self.fin_modif()
311          self.parent.delete_concept(sd)
312          return
313
314       if sd is not self.sd :return
315       if self.sd is not None :
316          self.init_modif()
317          self.parent.del_sdprod(sd)
318          self.sd=None
319          self.fin_modif()
320          self.parent.delete_concept(sd)
321
322   def supprime_sdprods(self):
323       """
324           Fonction: Lors de la destruction de la macro-etape, detruit tous les concepts produits
325           Un opérateur n a qu un concept produit
326           Une procedure n'en a aucun
327           Une macro en a en général plus d'un
328       """
329       #print "supprime_sdprods"
330       if self.reuse is not self.sd :
331          # l'étape n'est pas réentrante
332          # le concept retourné par l'étape est à supprimer car il était
333          # créé par l'étape
334          if self.sd != None :
335             self.parent.del_sdprod(self.sd)
336             self.parent.delete_concept(self.sd)
337       # On détruit les concepts à droite du signe =
338       for co in self.sdprods:
339          self.parent.del_sdprod(co)
340          self.parent.delete_concept(co)
341       # Si la macro a des etapes et des concepts inclus, on les detruit
342       for nom_sd,co in self.g_context.items():
343          if not isinstance(co,ASSD):continue
344          self.parent.del_sdprod(co)
345          self.parent.delete_concept(co)
346       # On met g_context à blanc
347       self.g_context={}
348
349   def close(self):
350       #print "close",self
351       if hasattr(self,"jdc_aux") and self.jdc_aux:
352          # La macro a un jdc auxiliaire inclus. On demande sa fermeture
353          self.jdc_aux.close()
354
355   def reset_context(self):
356       if hasattr(self,"jdc_aux") and self.jdc_aux:
357          # La macro a un jdc auxiliaire inclus. On demande la reinitialisation du contexte
358          self.jdc_aux.reset_context()
359
360   def update_concept(self,sd):
361       I_ETAPE.ETAPE.update_concept(self,sd)
362       for etape in self.etapes:
363           etape.update_concept(sd)
364
365   def delete_concept(self,sd):
366       """
367           Fonction : Mettre a jour les mots cles de l etape et eventuellement
368           le concept produit si reuse suite à la disparition du concept sd
369           Seuls les mots cles simples MCSIMP font un traitement autre
370           que de transmettre aux fils
371       """
372       #print "delete_concept",sd
373       I_ETAPE.ETAPE.delete_concept(self,sd)
374       for etape in self.etapes:
375          etape.delete_concept(sd)
376
377   def replace_concept(self,old_sd,sd):
378       """
379           Fonction : Mettre a jour les mots cles de l etape et le concept produit si reuse 
380           suite au remplacement  du concept old_sd par sd
381       """
382       #print "replace_concept",old_sd,sd
383       I_ETAPE.ETAPE.replace_concept(self,old_sd,sd)
384       for etape in self.etapes:
385          etape.replace_concept(old_sd,sd)
386          
387   def change_fichier_init(self,new_fic,text):
388     """
389        Tente de changer le fichier include. Le precedent include est conservé
390        dans old_xxx
391     """
392     #print "change_fichier_init",new_fic
393     if not hasattr(self,'fichier_ini'):
394        self.fichier_ini=None
395        self.fichier_text=None
396        self.fichier_err="Le fichier n'est pas defini"
397        self.contexte_fichier_init={}
398        self.recorded_units={}
399        self.jdc_aux=None
400        self.fichier_unite="PasDefini"
401        import Extensions.jdc_include
402        self.JdC_aux=Extensions.jdc_include.JdC_include
403
404     self.old_fic = self.fichier_ini
405     self.old_text = self.fichier_text
406     self.old_err = self.fichier_err
407     self.old_context=self.contexte_fichier_init
408     self.old_units=self.recorded_units
409     self.old_etapes=self.etapes
410     self.old_jdc_aux=self.jdc_aux
411
412     self.fichier_ini = new_fic
413     self.fichier_text=text
414
415     try:
416        self.make_contexte_include(new_fic,text)
417     except:
418        l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
419        self.fichier_err=string.join(l)
420        raise
421
422     # L'evaluation de text dans un JDC auxiliaire s'est bien passé
423     # on peut poursuivre le traitement
424     self.init_modif()
425     self.state="undetermined"
426     self.fichier_err=None
427     # On enregistre la modification de fichier
428     self.record_unite()
429     # Le contexte du parent doit etre reinitialise car les concepts produits ont changé
430     self.parent.reset_context()
431
432     # Si des concepts ont disparu lors du changement de fichier, on demande leur suppression
433     self.old_contexte_fichier_init=self.old_context
434     self.reevalue_sd_jdc()
435
436     self.fin_modif()
437     if self.old_jdc_aux:
438        self.old_jdc_aux.close()
439
440   def restore_fichier_init(self):
441     """
442        Restaure le fichier init enregistre dans old_xxx
443     """
444     self.fichier_ini=self.old_fic
445     self.fichier_text=self.old_text
446     self.fichier_err=self.old_err
447     self.contexte_fichier_init=self.old_context
448     self.recorded_units=self.old_units
449     self.etapes=self.old_etapes
450     self.jdc_aux=self.old_jdc_aux
451
452   def force_fichier_init(self):
453     """
454        Force le remplacement du fichier init meme si le remplacant est en erreur
455     """
456     # Reinitialisation complete du compte-rendu d'erreurs
457     self.jdc_aux.cr=self.jdc_aux.CR()
458     # On remplit le dictionnaire des concepts produits inclus
459     # en retirant les concepts présents dans le  contexte initial
460     # On ajoute egalement le concept produit dans le sds_dict du parent
461     # sans verification car on est sur (verification integrée) que
462     # le nommage est possible
463     j_context=self.jdc_aux.get_contexte_avant(None)
464     self.g_context.clear()
465     context_ini=self.jdc_aux.context_ini
466     for k,v in j_context.items():
467        if not context_ini.has_key(k) or context_ini[k] != v:
468            self.g_context[k]=v
469            self.parent.sds_dict[k]=v
470     # On recupere le contexte courant
471     self.current_context=self.jdc_aux.current_context
472     self.index_etape_courante=self.jdc_aux.index_etape_courante
473     self.contexte_fichier_init = j_context
474     self.fichier_err = None
475
476     # On enregistre la modification de fichier
477     self.init_modif()
478     self.state="undetermined"
479     self.record_unite()
480     # Le contexte du parent doit etre reinitialise car les concepts produits ont changé
481     self.parent.reset_context()
482
483     # On remplace les anciens concepts par les nouveaux (y compris ajouts 
484     # et suppression) et on propage les modifications aux etapes precedentes et suivantes
485     # reevalue_sd_jdc construit la liste des differences entre les contextes contexte_fichier_init
486     # et old_contexte_fichier_init et effectue les destructions et remplacements de concept
487     # necessaires
488     self.old_contexte_fichier_init=self.old_context
489     self.reevalue_sd_jdc()
490     self.fin_modif()
491     if self.old_jdc_aux:
492        self.old_jdc_aux.close()
493
494     self.jdc_aux.force_contexte(self.g_context)
495
496   def build_include(self,fichier,text):
497     import Extensions.jdc_include
498     self.JdC_aux=Extensions.jdc_include.JdC_include
499     # un include partage la table des unites avec son parent (jdc)
500     self.recorded_units=self.parent.recorded_units
501     self.build_jdcaux(fichier,text)
502
503   def build_poursuite(self,fichier,text):
504     import Extensions.jdc_include
505     self.JdC_aux=Extensions.jdc_include.JdC_poursuite
506     # une poursuite a sa propre table d'unites
507     self.recorded_units={}
508     self.build_jdcaux(fichier,text)
509
510   def build_jdcaux(self,fichier,text):
511     """
512          Cree un jdc auxiliaire initialise avec text. 
513          Initialise le nom du fichier associé avec fichier
514          N'enregistre pas d'association unite <-> fichier
515     """
516     self.fichier_ini = fichier
517     self.fichier_text= text
518     self.fichier_unite=None
519     self.fichier_err = None
520     try:
521        contexte = self.get_contexte_jdc(fichier,text)
522        if contexte is None :
523           # Impossible de construire le jdc auxiliaire (sortie par None)
524           # On simule une sortie par exception
525           raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
526        else:
527           # La construction du jdc auxiliaire est allée au bout
528           self.contexte_fichier_init = contexte
529        self.init_modif()
530        self.fin_modif()
531     except:
532        # Impossible de construire le jdc auxiliaire (sortie par exception)
533        l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
534        if self.jdc.appli:
535           self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
536                                         message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
537                                        )
538        self.g_context={}
539        self.etapes=[]
540        self.jdc_aux=None
541        self.fichier_err = string.join(l)
542        self.contexte_fichier_init={}
543        self.init_modif()
544        self.fin_modif()
545        raise
546
547   def make_contexte_include(self,fichier,text):
548     """
549         Cette méthode sert à créer un contexte en interprétant un texte source Python.
550     """
551     #print "make_contexte_include",fichier
552     # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
553     contexte = self.get_contexte_jdc(fichier,text)
554     if contexte == None :
555       raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
556     else:
557       # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
558       # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
559       # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
560       # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
561       # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
562       # g_context est utilisé pour avoir les concepts produits par la macro
563       # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
564       self.contexte_fichier_init = contexte
565
566   def reevalue_fichier_init_OBSOLETE(self):
567       """Recalcule les concepts produits par le fichier enregistre"""
568       #print "reevalue_fichier_init"
569       old_context=self.contexte_fichier_init
570       try:
571          self.make_contexte_include(self.fichier_ini ,self.fichier_text)
572       except:
573          l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
574          self.fichier_err = string.join(l)
575          self.g_context={}
576          self.etapes=[]
577          self.jdc_aux=None
578          self.old_contexte_fichier_init=old_context
579          self.contexte_fichier_init={}
580          self.reevalue_sd_jdc()
581          return
582
583       # L'evaluation s'est bien passee
584       self.fichier_err = None
585       self.old_contexte_fichier_init=old_context
586       self.reevalue_sd_jdc()
587
588   def update_fichier_init(self,unite):
589       """Reevalue le fichier init sans demander (dans la mesure du possible) a l'utilisateur 
590          les noms des fichiers
591          Ceci suppose que les relations entre unites et noms ont été memorisees préalablement
592          L'include a été initialisé précédemment. Le jdc auxiliaire existe.
593       """
594       #print "update_fichier_init",unite,self.fichier_unite 
595       self.old_contexte_fichier_init=self.contexte_fichier_init
596       old_fichier_ini=self.fichier_ini
597       if not hasattr(self,"jdc_aux"):self.jdc_aux=None
598       old_jdc_aux=self.jdc_aux
599
600       #print "update_fichier_init",self,self.parent,self.parent.recorded_units
601
602       if self.fichier_unite is None:
603          # L'unité n'était pas définie précédemment. On ne change que l'unite
604          #print "update_fichier_init","pas de changement dans include"
605          self.fichier_unite=unite
606          return
607       elif unite == self.fichier_unite :
608          # L'unité n'a pas changé
609          #print "update_fichier_init","pas de changement dans include 3"
610          return
611       elif unite != self.fichier_unite :
612          # L'unité était définie précédemment. On remplace l'include 
613          #
614          f,text=self.get_file_memo(unite=unite,fic_origine=self.parent.nom)
615          if f is None:
616             # Le fichier associé n'a pas pu etre defini
617             # on change l'unite associée mais pas l'include
618             #print "update_fichier_init","pas de changement dans include 2"
619             self.fichier_unite=unite
620             return
621          else:
622             self.fichier_ini = f
623             self.fichier_text=text
624             self.fichier_unite=unite
625          #print "update_fichier_init",self.recorded_units
626
627       #print "update_fichier_init",self.fichier_ini,self.fichier_text,self.fichier_unite
628
629       if old_fichier_ini == self.fichier_ini:
630          # Le fichier inclus n'a pas changé. On ne recrée pas le contexte
631          # mais on enregistre le changement d'association unite <-> fichier
632          #print "update_fichier_init.fichier inchange",self.jdc_aux.context_ini
633          self.parent.record_unit(unite,self)
634          return
635
636       try:
637         self.fichier_err=None
638         self.make_contexte_include(self.fichier_ini,self.fichier_text)
639         # Les 3 attributs fichier_ini fichier_text recorded_units doivent etre corrects
640         # avant d'appeler change_unit
641       except:
642         # Erreurs lors de l'evaluation de text dans un JDC auxiliaire
643         l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
644         # On conserve la memoire du nouveau fichier
645         # mais on n'utilise pas les concepts crees par ce fichier
646         # on met l'etape en erreur : fichier_err=string.join(l)
647         self.fichier_err=string.join(l)
648         self.g_context={}
649         self.etapes=[]
650         self.jdc_aux=None
651         self.contexte_fichier_init={}
652
653       if old_jdc_aux:
654          old_jdc_aux.close()
655       self.parent.record_unit(unite,self)
656       # Le contexte du parent doit etre reinitialise car les concepts 
657       # produits ont changé
658       self.parent.reset_context()
659       # Si des concepts ont disparu lors du changement de fichier, on 
660       # demande leur suppression
661       self.reevalue_sd_jdc()
662       #print "update_fichier_init",self.jdc_aux.context_ini.keys()
663
664   def record_unite(self):
665       #print "record_unite",self.nom
666       if self.nom == "POURSUITE":
667          self.parent.record_unit(None,self)
668       else:
669          if hasattr(self,'fichier_unite') : 
670             self.parent.record_unit(self.fichier_unite,self)
671
672   def get_file_memo(self,unite=None,fic_origine=''):
673       """Retourne le nom du fichier et le source correspondant a l'unite unite
674          Initialise en plus recorded_units
675       """
676       #print "get_file_memo",unite,fic_origine,self,self.parent
677       #print self.parent.recorded_units
678       if unite is None:
679          # On est dans le cas d'une poursuite. On ne reutilise aucune unite de parent
680          units={}
681       else:
682          # On est dans le cas d'un include. On reutilise toutes les unites de parent
683          units=self.parent.recorded_units
684
685       if self.parent.recorded_units.has_key(unite):
686          f,text,units=self.parent.recorded_units[unite]
687       elif self.jdc :
688          f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
689       else:
690          f,text=None,None
691
692       self.recorded_units=units
693       if f is None and self.jdc.appli:
694          self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
695                           message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
696       return f,text
697
698   def update_context(self,d):
699       """
700          Met à jour le contexte contenu dans le dictionnaire d
701          Une MACRO_ETAPE peut ajouter plusieurs concepts dans le contexte
702          Une fonction enregistree dans op_init peut egalement modifier le contexte
703       """
704       #print "update_context",self,self.nom,d.keys()
705       if hasattr(self,"jdc_aux") and self.jdc_aux:
706             #ATTENTION: update_context NE DOIT PAS appeler reset_context
707             # car il appelle directement ou indirectement update_context
708             # equivalent a reset_context. Evite les recursions
709             self.jdc_aux.context_ini=d.copy()
710             self.jdc_aux.current_context={}
711             self.jdc_aux.index_etape_courante=0
712             #ATTENTION: il ne faut pas utiliser self.jdc_aux.get_contexte_avant
713             #car cet appel conduit a des remontées multiples incohérentes dans le
714             # ou les parents. 
715             #get_context_avant appelle update_context qui NE DOIT PAS appeler get_contexte_avant
716             #On n'a besoin que d'un update local connaissant
717             # le contexte amont : d qui sert a reinitialiser self.context_ini
718             for e in self.etapes:
719                 e.update_context(d)
720             return
721
722       if type(self.definition.op_init) == types.FunctionType:
723         apply(self.definition.op_init,(self,d))
724       if self.sd != None:d[self.sd.nom]=self.sd
725       for co in self.sdprods:
726         d[co.nom]=co
727       #print "update_context.fin",d.keys()
728
729 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
730   def copy(self):
731       etape=Noyau.N_MACRO_ETAPE.MACRO_ETAPE.copy(self)
732       if hasattr(etape,"etapes") :etape.etapes=[]
733       if hasattr(etape,"jdc_aux") : 
734          etape.jdc_aux=None
735          del etape.fichier_ini
736       return etape
737
738   def supprime(self):
739       #print "supprime",self
740       if hasattr(self,"jdc_aux") and self.jdc_aux:
741          self.jdc_aux.supprime_aux()
742          self.jdc_aux=None
743       Noyau.N_MACRO_ETAPE.MACRO_ETAPE.supprime(self)
744   #    self.contexte_fichier_init={}
745   #    self.old_contexte_fichier_init={}
746   #    self.g_context={}
747   #    self.current_context={}
748   #    self.etapes=[]
749   #    self.mc_liste=[]
750
751 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
752   def get_file(self,unite=None,fic_origine=''):
753       """Retourne le nom du fichier et le source correspondant a l'unite unite
754       """
755       if self.jdc :
756          f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
757       else:
758          f,text=None,None
759       return f,text
760
761 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
762   def make_include(self,unite=None):
763       """
764           Inclut un fichier dont l'unite logique est unite
765           Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
766           Si l'INCLUDE est invalide, la methode doit produire une exception 
767           Sinon on retourne None. Les concepts produits par l'INCLUDE sont
768           pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
769       """
770       #print "make_include",unite
771       # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
772       # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
773       # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
774       if not unite : return
775
776       if not hasattr(self,'fichier_ini') : 
777          # Si le fichier n'est pas defini on le demande
778          f,text=self.get_file_memo(unite=unite,fic_origine=self.parent.nom)
779          # On memorise le fichier retourne
780          self.fichier_ini  = f
781          self.fichier_text = text
782          self.contexte_fichier_init={}
783          self.fichier_unite=unite
784          self.fichier_err=None
785          try:
786            import Extensions.jdc_include
787          except:
788            traceback.print_exc()
789            raise
790          self.JdC_aux=Extensions.jdc_include.JdC_include
791
792          #print "make_include",self.fichier_ini,self.fichier_text 
793          if f is None and not text:
794              self.fichier_err="Le fichier INCLUDE n est pas defini"
795              self.parent.record_unit(unite,self)
796              raise Exception(self.fichier_err)
797
798          try:
799            self.make_contexte_include(self.fichier_ini ,self.fichier_text)
800            self.parent.record_unit(unite,self)
801            #print "make_include.context_ini",self.jdc_aux.context_ini
802          except:
803            l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
804            if self.jdc.appli:
805               self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
806                                             message="Le contenu de ce fichier ne sera pas pris en compte\n"+string.join(l)
807                                            )
808            self.parent.record_unit(unite,self)
809            self.g_context={}
810            self.etapes=[]
811            self.jdc_aux=None
812            self.fichier_err = string.join(l)
813            self.contexte_fichier_init={}
814            raise
815
816       else:
817          # Si le fichier est deja defini on ne reevalue pas le fichier
818          # et on leve une exception si une erreur a été enregistrée
819          self.update_fichier_init(unite)
820          self.fichier_unite=unite
821          if self.fichier_err is not None: raise Exception(self.fichier_err)
822         
823
824 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
825   def make_contexte(self,fichier,text):
826     """
827         Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
828         en interprétant un texte source Python
829         Elle est appelee par la fonction sd_prod d'INCLUDE_MATERIAU
830     """
831     #print "make_contexte",fichier
832     # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
833     # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
834     if hasattr(self,'mat'):del self.mat
835     if not hasattr(self,'fichier_ini') or self.fichier_ini != fichier or self.fichier_mater != self.nom_mater: 
836        # le fichier est nouveau ou change
837        self.fichier_ini =fichier
838        self.fichier_unite =fichier
839        self.fichier_mater=self.nom_mater
840        self.fichier_text=text
841        self.fichier_err=None 
842        self.contexte_fichier_init={}
843        # On specifie la classe a utiliser pour le JDC auxiliaire
844        try:
845          import Extensions.jdc_include
846          self.JdC_aux=Extensions.jdc_include.JdC_include
847        except:
848          raise
849        try:
850           self.make_contexte_include(self.fichier_ini ,self.fichier_text)
851           if not self.g_context.has_key(self.nom_mater):
852              #Pour permettre de lire un jeu de commandes avec des INCLUDE_MATERIAU errones
853              self.g_context[self.nom_mater]=None
854              if self.parent: self.parent.g_context[self.nom_mater]=None
855        except:
856           l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
857           self.fichier_err = string.join(l)
858           self.g_context={}
859           #Pour permettre de lire un jeu de commandes avec des INCLUDE_MATERIAU errones
860           if self.parent:
861               self.parent.g_context[self.nom_mater]=None
862           self.g_context[self.nom_mater]=None
863           #-------------
864           self.etapes=[]
865           self.jdc_aux=None
866           self.contexte_fichier_init={}
867           raise
868     else:
869        # le fichier est le meme on ne le reevalue pas
870        # et on leve une exception si une erreur a été enregistrée
871        if self.fichier_err is not None: raise Exception(self.fichier_err)
872
873 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
874   def update_sdprod(self,cr='non'):
875      # Cette methode peut etre appelee dans EFICAS avec des mots cles de 
876      # la commande modifies. Ceci peut conduire a la construction ou
877      # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
878      # Il faut donc positionner le current_step avant l'appel
879      CONTEXT.unset_current_step()
880      CONTEXT.set_current_step(self)
881      valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
882      CONTEXT.unset_current_step()
883      return valid
884
885 #ATTENTION SURCHARGE: cette methode surcharge celle de Noyau a garder en synchro 
886   def Build_sd(self,nom):
887       """
888            Methode de Noyau surchargee pour poursuivre malgre tout
889            si une erreur se produit pendant la creation du concept produit
890       """
891       try:
892          sd=Noyau.N_MACRO_ETAPE.MACRO_ETAPE.Build_sd(self,nom)
893       except AsException,e:
894          # Une erreur s'est produite lors de la construction du concept
895          # Comme on est dans EFICAS, on essaie de poursuivre quand meme
896          # Si on poursuit, on a le choix entre deux possibilités :
897          # 1. on annule la sd associée à self
898          # 2. on la conserve mais il faut la retourner
899          # On choisit de l'annuler
900          # En plus il faut rendre coherents sdnom et sd.nom
901          self.sd=None
902          self.sdnom=None
903          self.state="unchanged"
904          self.valid=0
905
906       return self.sd
907
908 #ATTENTION SURCHARGE: cette methode surcharge celle de Noyau a garder en synchro 
909   def make_poursuite(self):
910       """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
911       """
912       #print "make_poursuite"
913       if not hasattr(self,'fichier_ini') :
914          # Si le fichier n'est pas defini on le demande
915          f,text=self.get_file_memo(fic_origine=self.parent.nom)
916          # On memorise le fichier retourne
917          self.fichier_ini = f
918          self.fichier_unite = None
919          self.fichier_text = text
920          self.fichier_err=None
921          try:
922            import Extensions.jdc_include
923          except:
924            traceback.print_exc()
925            raise
926          self.JdC_aux=Extensions.jdc_include.JdC_poursuite
927          self.contexte_fichier_init={}
928          #print "make_poursuite",self.fichier_ini,self.fichier_text
929
930          if f is None:
931              self.fichier_err="Le fichier POURSUITE n'est pas defini"
932              self.jdc_aux=None
933              self.parent.record_unit(None,self)
934              raise Exception(self.fichier_err)
935
936          try:
937            self.make_contexte_include(self.fichier_ini,self.fichier_text)
938            self.parent.record_unit(None,self)
939          except:
940            l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
941            if self.jdc.appli:
942               self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
943                                             message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
944                                            )
945            self.parent.record_unit(None,self)
946            self.g_context={}
947            self.etapes=[]
948            self.jdc_aux=None
949            self.fichier_err = string.join(l)
950            self.contexte_fichier_init={}
951            raise
952
953       else:
954          # Si le fichier est deja defini on ne reevalue pas le fichier
955          # et on leve une exception si une erreur a été enregistrée
956          self.update_fichier_init(None)
957          if self.fichier_err is not None: raise Exception(self.fichier_err)