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