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