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