Salome HOME
fin portage python 3
[tools/eficas.git] / Ihm / I_JDC.py
1 # -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2007-2013   EDF R&D
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20 """
21 """
22 # Modules Python
23 from __future__ import absolute_import
24 from __future__ import print_function
25 import types,traceback,sys,os
26 import linecache
27 from Extensions.i18n import tr
28 from Extensions.eficas_exception import EficasException
29
30
31 # Modules Eficas
32 from . import I_OBJECT
33 import Noyau
34 from Noyau.N_ASSD import ASSD
35 #from Noyau.N_LASSD import LASSD
36 from Noyau.N_ETAPE import ETAPE
37 from Noyau.N_Exception import AsException
38 from Extensions import commentaire,parametre,parametre_eval
39 from . import CONNECTOR
40 import Validation
41
42 class LASSD:
43    pass
44
45 class JDC(I_OBJECT.OBJECT):
46    """
47    """
48    def __init__(self):
49       self.editmode=0
50       self.etapes_niveaux=[]
51       self.niveau=self
52       self.params=[]
53       self.fonctions=[]
54       self._etape_context=None
55       self.recorded_units={}
56       self.old_recorded_units={}
57  
58
59    def get_index(self,objet):
60       """
61         Retourne la position d'objet dans la liste self
62       """
63       return self.etapes.index(objet)
64
65    def get_sd_avant_du_bon_type(self,etape,types_permis):
66       """
67           Retourne la liste des concepts avant etape d'un type acceptable
68       """
69       d=self.get_contexte_avant(etape)
70       
71       
72       l=[]
73       for k,v in d.items():
74         if type(v) != types.InstanceType and not isinstance(v,object): continue
75         # On considere que seul assd indique un type quelconque pas CO
76         elif self.assd in types_permis :
77            if v.etape.sdnom != "sansnom" : l.append(k)
78         elif self.est_permis(v,types_permis):
79            if v.etape.sdnom != "sansnom" : l.append(k)
80       l.sort()
81       return l
82
83    def get_variables(self,etape):
84       etapeStop=etape
85       l=[]
86       for etapeTraitee in self.etapes :
87           if etapeTraitee==etapeStop:
88              break
89           if etapeTraitee.nom == 'VARIABLE' :
90              variable=etapeTraitee.get_mocle('ModelVariable')
91              if variable != None :
92                 l.append(variable.nom)
93       return l
94
95    def get_distributions(self,etape):
96       etapeStop=etape
97       l=[]
98       for etapeTraitee in self.etapes :
99           if etapeTraitee==etapeStop: break
100           if etapeTraitee.nom == 'DISTRIBUTION' and etapeTraitee.sd !=None : l.append(etapeTraitee.sd.nom)
101       return l
102
103
104    #def set_Copules_recalcule_etat(self):
105    #   for etapeTraitee in self.etapes :
106    #       if etapeTraitee.nom == 'CORRELATION' :
107              #Matrix=etapeTraitee.get_child('Matrix')
108              #if Matrix !=None :
109    #             Correlation=etapeTraitee.get_child('CorrelationMatrix')
110    #             if Correlation !=None : Correlation.state='arecalculer'
111              #   Matrix.state='arecalculer'
112      
113    #def recalcule_etat_correlation(self):
114    #   for etapeTraitee in self.etapes :
115    #       if etapeTraitee.nom == 'CORRELATION' :
116              #Matrix=etapeTraitee.get_child('Matrix')
117              #if Matrix !=None :
118    #             Matrix.state='arecalculer'
119    #             Correlation=Matrix.get_child('CorrelationMatrix')
120    #             if Correlation !=None : Correlation.state='arecalculer'
121    #                Correlation.isvalid()
122    #             Matrix.isvalid()
123    #             etapeTraitee.state='arecalculer'
124    #          if etapeTraitee.state=='arecalculer': etapeTraitee.isvalid()
125                 
126    def recalcule_etat_correlation(self):
127       for etapeTraitee in self.etapes :
128           if etapeTraitee.nom == 'CORRELATION' :
129              Correlation=etapeTraitee.get_child('CorrelationMatrix')
130              if Correlation !=None : 
131                   Correlation.state='arecalculer'
132                   Correlation.isvalid()
133              etapeTraitee.isvalid()
134
135    def recalcule_validite_apres_changement_global_jdc(self):
136         #print "je passe dans recalcule_validite_apres_changement_global_jdc"
137         try :
138           liste=self.get_jdc_root().cata[0].liste_condition
139         except :
140           liste=()
141         for etapeTraitee in self.etapes :
142            if etapeTraitee.nom not in liste: continue
143            self.forceRecalculBloc(etapeTraitee)
144            etapeTraitee.state='arecalculer'
145            etapeTraitee.isvalid()
146
147         
148    def forceRecalculBloc(self,objet):
149        # Attention : certains objets deviennent None quand on recalcule 
150        # les conditions d existence des blocs
151        if objet != None:  objet.state='arecalculer'
152        if hasattr(objet,'liste_mc_presents'):
153           for childNom in objet.liste_mc_presents():
154               child=objet.get_child(childNom)
155               if hasattr(objet,'_update_condition_bloc'):objet._update_condition_bloc()
156               self.forceRecalculBloc(child)
157        
158    
159    def get_sd_avant_du_bon_type_pour_type_de_base(self,etape,type):
160       """
161           Retourne la liste des concepts avant etape d'1 type de base acceptable
162           Attention different de la routine precedente : 1 seul type passe en parametre
163           Teste sur issubclass et par sur le type permis
164       """
165       d=self.get_contexte_avant(etape)
166       l=[]
167       try :
168          typeverif=self.cata[0].__dict__[type]
169       except :
170          return l
171       for k,v in d.items():
172         if issubclass(v.__class__,typeverif): 
173            l.append(k)
174       l.sort()
175       return l
176
177    def cherche_list_avant(self,etape,valeur):
178        d=self.get_contexte_avant(etape)
179        for k,v in d.items():
180           if issubclass(v.__class__,LASSD):
181              if k == valeur :
182                 return k
183         # Attention pour enlever les . a la fin des pretendus reels
184              if k == valeur[0:-1] :
185                 return v
186        return None
187
188    def est_permis(self,v,types_permis):
189       for type_ok in types_permis:
190           if type_ok in ('R','I','C','TXM') and v in self.params : 
191              return 1
192           elif type_ok == 'R' and v.__class__.__name__ == 'reel' : 
193              return 1
194           elif type_ok == 'I' and v.__class__.__name__ == 'entier' : 
195              return 1
196           elif type_ok == 'C' and v.__class__.__name__ == 'complexe' : 
197              return 1
198           elif type_ok == 'TXM' and v.__class__.__name__ == 'chaine' : 
199              return 1
200           elif type(type_ok) != type and not isinstance(type_ok,type): 
201              continue
202           elif v.__class__ == type_ok or issubclass(v.__class__,type_ok):
203              return 1
204       return 0
205
206    def addentite(self,name,pos):
207       """
208           Ajoute une entite :
209           Si name est le nom d une commande ou un commentaire ajoute 
210           une etape au JDC
211           Sinon remonte une erreur
212       """
213       self.init_modif()
214       self.editmode=1
215       if name == "COMMENTAIRE" :
216         # ajout d'un commentaire
217         self.set_current_step()
218         ind = 1
219         for child in self.etapes :
220           from Extensions import commentaire
221           if isinstance(child,commentaire.COMMENTAIRE):
222             ind = ind+1
223         objet = commentaire.COMMENTAIRE('',parent=self)
224         objet.nom = "_comm_"+repr(ind)
225         if pos == None : pos = 0
226         self.etapes.insert(pos,objet)
227         self.reset_context()
228         self.editmode=0
229         self.active_etapes()
230         CONNECTOR.Emit(self,"add",objet)
231         self.fin_modif()
232         return objet
233       elif name == "PARAMETRE":
234         # ajout d'un parametre
235         self.set_current_step()
236         nom_param = '_param_'+str(len(self.params)+1)
237         objet = parametre.PARAMETRE(nom=nom_param)
238         if pos == None : pos = 0
239         self.etapes.insert(pos,objet)
240         self.reset_context()
241         self.editmode=0
242         self.active_etapes()
243         CONNECTOR.Emit(self,"add",objet)
244         self.fin_modif()
245         return objet
246       elif name == "PARAMETRE_EVAL":
247         # ajout d'un parametre EVAL
248         self.set_current_step()
249         nom_param = '_param_'+str(len(self.params)+1)
250         objet = parametre_eval.PARAMETRE_EVAL(nom=nom_param)
251         if pos == None : pos = 0
252         self.etapes.insert(pos,objet)
253         self.reset_context()
254         self.editmode=0
255         self.active_etapes()
256         CONNECTOR.Emit(self,"add",objet)
257         self.fin_modif()
258         return objet
259       elif type(name)==types.InstanceType:
260         # on est dans le cas ou on veut ajouter une commande deja 
261         # existante (par copie donc)
262         # on est donc necessairement en mode editeur ...
263         objet = name
264         # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
265         from Extensions import commentaire
266         if not( isinstance (objet,commentaire.COMMENTAIRE)):
267            objet.reparent(self)
268         self.set_current_step()
269         if isinstance(objet,ETAPE):
270           if objet.nom_niveau_definition == 'JDC':
271             # l'objet depend directement du JDC
272             objet.niveau = self
273           else:
274             # l'etape depend d'un niveau et non directement du JDC :
275             # il faut l'enregistrer dans le niveau de parent
276             objet.parent.dict_niveaux[objet.nom_niveau_definition].register(objet)
277             objet.niveau = objet.parent.dict_niveaux[objet.nom_niveau_definition]
278         self.etapes.insert(pos,objet)
279         self.reset_context()
280         # il faut verifier que les concepts utilises par objet existent bien
281         # a ce niveau d'arborescence
282         objet.verif_existence_sd()
283         objet.update_mc_global()
284         self.editmode=0
285         self.active_etapes()
286         CONNECTOR.Emit(self,"add",objet)
287         self.fin_modif()
288         return objet
289       else :
290         # On veut ajouter une nouvelle commande
291         try:
292           self.set_current_step()
293           cmd=self.get_cmd(name)
294           # L'appel a make_objet n'a pas pour effet d'enregistrer l'etape
295           # aupres du step courant car editmode vaut 1
296           # Par contre elle a le bon parent grace a set_current_step
297           e=cmd.make_objet()
298           if pos == None : pos = 0
299           self.etapes.insert(pos,e)
300           self.reset_current_step()
301           self.reset_context()
302           self.editmode=0
303           self.active_etapes()
304           CONNECTOR.Emit(self,"add",e)
305           self.fin_modif()
306           return e
307         except AsException as e:
308           traceback.print_exc()
309           self.reset_current_step()
310           self.editmode=0
311           raise AsException(tr("Impossible d'ajouter la commande")+name + '\n')
312         except:
313         #else :
314           traceback.print_exc()
315           self.reset_current_step()
316           self.editmode=0
317           raise AsException(tr("Impossible d ajouter la commande")+name)
318
319    def close(self):
320       #print "JDC.close",self
321       for etape in self.etapes:
322           if hasattr(etape,"close"):etape.close()
323       CONNECTOR.Emit(self,"close")
324
325    def set_current_step(self):
326       CONTEXT.unset_current_step()
327       CONTEXT.set_current_step(self)
328
329    def reset_current_step(self):
330       CONTEXT.unset_current_step()
331
332    def liste_mc_presents(self):
333       return []
334
335    def get_sd_avant_etape(self,nom_sd,etape):
336       return self.get_contexte_avant(etape).get(nom_sd,None)
337
338    def get_sd_apres_etape_avec_detruire(self,nom_sd,sd,etape,avec='non'):
339       """ 
340            Cette methode retourne la SD sd de nom nom_sd qui est eventuellement
341            definie apres etape en tenant compte des concepts detruits
342            Si avec vaut 'non' exclut etape de la recherche
343       """
344       #print "JDC.get_sd_apres_etape_avec_detruire",nom_sd,sd
345       ietap=self.etapes.index(etape)
346       if avec == 'non':ietap=ietap+1
347       d={nom_sd:sd}
348       for e in self.etapes[ietap:]:
349          if e.isactif():
350             e.update_context(d)
351             autre_sd=d.get(nom_sd,None)
352             if autre_sd is None:
353               # Le concept a ete detruit. On interrompt la recherche car il n'y a
354               # pas eu de redefinition du concept (il n'y a pas de conflit potentiel).
355               return None
356             if autre_sd is not sd :
357               # L'etape produit un concept different de meme nom. La situation n'est
358               # pas saine (sauf peut etre si reuse ???)
359               if hasattr(e,'reuse') and e.reuse == autre_sd:
360                  # Le concept etant reutilise, on interrompt la recherche. 
361                  # On considere qu'il n'y a pas de nouveau concept defini
362                  # meme si dans les etapes suivantes le concept est detruit
363                  # et un concept de meme nom cree.
364                  # AVERIFIER : avec reuse le concept devrait etre le meme
365                  # le passage par ici est tres improbable
366                  return None
367               else:
368                  # Le concept est produit par l'etape (Il y a conflit potentiel).
369                  # Le concept est redefini par une etape posterieure.
370                  return autre_sd
371       # Pas de destruction du concept ni de redefinition. On retourne le
372       # concept initial
373       return sd
374
375    def get_sd_apres_etape(self,nom_sd,etape,avec='non'):
376       """ 
377            Cette methode retourne la SD de nom nom_sd qui est eventuellement
378            definie apres etape 
379            Si avec vaut 'non' exclut etape de la recherche
380       """
381       ietap=self.etapes.index(etape)
382       if avec == 'non':ietap=ietap+1
383       for e in self.etapes[ietap:]:
384         sd=e.get_sdprods(nom_sd)
385         if sd:
386           if hasattr(e,'reuse'):
387             if e.reuse != sd:
388               return sd
389       return None
390
391    def get_sd_autour_etape(self,nom_sd,etape,avec='non'):
392       """
393            Fonction: retourne la SD de nom nom_sd qui est eventuellement
394            definie avant ou apres etape
395            Permet de verifier si un concept de meme nom existe dans le perimetre 
396            d'une etape
397            Si avec vaut 'non' exclut etape de la recherche
398       """
399       sd=self.get_sd_avant_etape(nom_sd,etape)
400       if sd:return sd
401       return self.get_sd_apres_etape(nom_sd,etape,avec)
402
403    def get_contexte_apres(self,etape):
404       """
405          Retourne le dictionnaire des concepts connus apres etape
406          On tient compte des commandes qui modifient le contexte
407          comme DETRUIRE ou les macros
408          Si etape == None, on retourne le contexte en fin de JDC
409       """
410       if not etape: return self.get_contexte_avant(etape)
411
412       d=self.get_contexte_avant(etape)
413       if etape.isactif():etape.update_context(d)
414       self.index_etape_courante=self.index_etape_courante+1
415       return d
416
417    def active_etapes(self):
418       """
419           Cette methode a pour fonction de desactiver les etapes qui doivent
420           l'etre cad, dans le cas d'ASTER, les etapes qui ne sont pas 
421           comprises entre le premier DEBUT/POURSUITE et le premier FIN 
422           et rendre actives les autres
423       """
424       if self.definition.code == 'ASTER' :
425          # Seulement pour ASTER :
426          # Avant DEBUT actif vaut 0
427          # Apres DEBUT et avant le 1er FIN actif vaut 1
428          # Apres le 1er FIN actif vaut -1
429          actif=0
430       else:
431          actif=1
432       for etape in self.etapes:
433         if actif == 0 and etape.nom in ['DEBUT','POURSUITE']:actif=1
434         if actif == 1:
435            etape.active()
436         else:
437            etape.inactive()
438         if etape.nom == 'FIN':actif=-1
439
440    def deplaceEntite(self,indexNoeudACopier,indexNoeudOuColler,pos):
441       """
442           Pour le cut
443       """
444       if indexNoeudACopier==indexNoeudOuColler:return
445       etapeACopier=self.etapes[indexNoeudACopier]
446       try :
447         sd=self.etapes[indexNoeudACopier].sd
448       except :
449         sd=None
450       if pos=='before' and indexNoeudOuColler==0 : 
451          self.etapes2=[etapeACopier,]+self.etapes[0:indexNoeudACopier]+self.etapes[indexNoeudACopier+1:]
452       elif indexNoeudACopier < indexNoeudOuColler :
453          self.etapes2=self.etapes[0:indexNoeudACopier]+self.etapes[indexNoeudACopier+1:indexNoeudOuColler+1]+[etapeACopier,]+self.etapes[indexNoeudOuColler+1:]
454       else:
455          self.etapes2=self.etapes[0:indexNoeudOuColler+1]+[etapeACopier,]+self.etapes[indexNoeudOuColler+1:indexNoeudACopier]+self.etapes[indexNoeudACopier+1:]
456       self.etapes=self.etapes2
457       if indexNoeudACopier < indexNoeudOuColler :
458         self.delete_concept_entre_etapes(indexNoeudACopier,indexNoeudOuColler,sd)
459       self.reset_context()
460       for e in self.etapes :
461          e.state = 'modified'
462       self.control_context_apres(None)
463       return 1
464
465
466    def suppentite(self,etape) :
467       """  
468           Cette methode a pour fonction de supprimer une etape dans 
469           un jeu de commandes
470           Retourne 1 si la suppression a pu etre effectuee,
471           Retourne 0 dans le cas contraire
472       """
473       #PN correction de bugs 
474       if etape not in self.etapes: return 0
475
476       self.init_modif()
477       index_etape=self.etapes.index(etape)
478
479       self.etapes.remove(etape)
480
481       if etape.niveau is not self:
482         # Dans ce cas l'etape est enregistree dans un niveau
483         # Il faut la desenregistrer
484         etape.niveau.unregister(etape)
485
486       etape.supprime_sdprods()
487       etape.close()
488       etape.supprime()
489       self.active_etapes()
490
491       # Apres suppression de l'etape il faut controler que les etapes
492       # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape
493       if index_etape > 0: 
494          index_etape=index_etape-1
495          etape=self.etapes[index_etape]
496       else:
497          etape=None
498       self.control_context_apres(etape)
499      
500       self.reset_context()
501       CONNECTOR.Emit(self,"supp",etape)
502       self.fin_modif()
503       return 1
504
505    def control_context_apres(self,etape):
506       """
507          Cette methode verifie que les etapes apres l'etape etape
508          ont bien des concepts produits acceptables (pas de conflit de 
509          nom principalement)
510          Si des concepts produits ne sont pas acceptables ils sont supprimes.
511          Effectue les verifications sur les etapes du jdc mais aussi sur les
512          jdc parents s'ils existent.
513       """
514       #print "control_context_apres",self,etape
515       #Regularise les etapes du jdc apres l'etape etape
516       self.control_jdc_context_apres(etape)
517
518    def control_jdc_context_apres(self,etape):
519       """
520           Methode semblable a control_context_apres mais ne travaille
521           que sur les etapes et sous etapes du jdc
522       """
523       #print "control_jdc_context_apres",self,etape
524       if etape is None:
525          # on demarre de la premiere etape
526          index_etape=0
527       else:
528          index_etape=self.etapes.index(etape)+1
529
530       try:
531          etape=self.etapes[index_etape]
532       except:
533          #derniere etape du jdc : rien a faire
534          return
535
536       context=self.get_contexte_avant(etape)
537
538       for e in self.etapes[index_etape:]:
539           e.control_sdprods(context)
540           e.update_context(context)
541
542    def analyse(self):
543       self.compile()
544       if not self.cr.estvide():return
545       self.exec_compile()
546       self.active_etapes()
547
548    def register_parametre(self,param):
549       """
550           Cette methode sert a ajouter un parametre dans la liste des parametres
551       """
552       self.params.append(param)
553
554    def register_fonction(self,fonction):
555       """
556           Cette methode sert a ajouter une fonction dans la liste des fonctions
557       """
558       self.fonctions.append(fonction)
559
560    def delete_param(self,param):
561       """
562           Supprime le parametre param de la liste des parametres
563           et du contexte gobal
564       """
565       if param in self.params : self.params.remove(param)
566       if param.nom in self.g_context : del self.g_context[param.nom]
567
568    def get_parametres_fonctions_avant_etape(self,etape):
569       """
570           Retourne deux elements :
571           - une liste contenant les noms des parametres (constantes ou EVAL) 
572             definis avant etape
573           - une liste contenant les formules definies avant etape
574       """
575       l_constantes = []
576       l_fonctions = []
577       # on recupere le contexte avant etape
578       # on ne peut mettre dans les deux listes que des elements de ce contexte
579       d=self.get_contexte_avant(etape)
580       # construction de l_constantes
581       for param in self.params:
582         nom = param.nom
583         if not nom : continue
584         if nom in d: l_constantes.append(nom)
585       # construction de l_fonctions
586       for form in self.fonctions:
587         nom = form.nom
588         if not nom : continue
589         if nom in d: l_fonctions.append(form.get_formule())
590
591       # on ajoute les concepts produits par DEFI_VALEUR
592       # XXX On pourrait peut etre faire plutot le test sur le type
593       # de concept : entier, reel, complexe, etc.
594       for k,v in d.items():
595          if hasattr(v,'etape') and v.etape.nom in ('DEFI_VALEUR',):
596             l_constantes.append(k)
597
598       # on retourne les deux listes
599       return l_constantes,l_fonctions
600
601    def get_nb_etapes_avant(self,niveau):
602       """ 
603           Retourne le nombre d etapes avant le debut de niveau
604       """
605       nb=0
606       for niv in self.etapes_niveaux:
607         if niv == niveau:break
608         nb=nb+len(niv.etapes)
609       return nb
610
611    def init_modif(self):
612       """
613       Methode appelee au moment ou une modification va etre faite afin de 
614       declencher d'eventuels traitements pre-modification
615       """
616       #print "init_modif",self
617       self.state = 'modified'
618
619    def fin_modif(self):
620       #print "fin_modif",self
621       CONNECTOR.Emit(self,"valid")
622       self.isvalid()
623       pass
624
625    def deep_update_condition_bloc(self):
626       # pour le moment, on ne fait rien
627       self.get_jdc_root().recalcule_validite_apres_changement_global_jdc()
628       #raise EficasException(tr("Pas implemente"))
629
630    def update_condition_bloc(self):
631       # pour le moment, on ne fait rien
632       raise EficasException(tr("Pas implemente"))
633
634    def get_liste_mc_inconnus(self):
635      """
636      Retourne une liste contenant les mots-cles inconnus a la relecture du JDC
637      """
638      # cette liste a le format suivant : [etape,(bloc,mcfact,...),nom_mc,valeur_mc]
639      l_mc = []
640      for etape in self.etapes :
641          if etape.isactif() :
642             if not etape.isvalid() :
643                l = etape.get_liste_mc_inconnus()
644                if l : l_mc.extend(l)
645      return l_mc    
646
647    def get_genealogie_precise(self):
648       return []
649
650    def get_genealogie(self):
651       """
652           Retourne la liste des noms des ascendants de l'objet self
653           jusqu'a la premiere ETAPE parent.
654       """
655       return []
656
657    def get_liste_cmd(self):
658       """
659           Retourne la liste des commandes du catalogue
660       """
661       return self.niveau.definition.get_liste_cmd()
662
663    def get_groups(self):
664       """
665           Retourne la liste des groupes
666       """
667       return self.niveau.definition.liste_groupes,self.niveau.definition.dict_groupes
668
669    def set_etape_context(self,etape):
670       """
671           Positionne l'etape qui sera utilisee dans NommerSdProd pour
672           decider si le concept passe pourra etre  nomme
673       """
674       self._etape_context=etape
675
676    def reset_context(self):
677       """ 
678           Cette methode reinitialise le contexte glissant pour pouvoir
679           tenir compte des modifications de l'utilisateur : craation
680           de commandes, nommage de concepts, etc.
681       """
682       #print "reset_context",self,self.nom
683       self.current_context={}
684       self.index_etape_courante=0
685       ind={}
686       for i,etape in enumerate(self.etapes):
687         ind[etape]=i
688       self.index_etapes=ind
689
690    #   for etape in self.etapes:
691    #       etape.reset_context()
692
693    def del_sdprod(self,sd):
694       """
695           Supprime la SD sd de la liste des sd et des dictionnaires de contexte
696       """
697       #print "del_sdprod",self,sd
698       #print "del_sdprod",self.sds
699       #print "del_sdprod",self.g_context
700       #print "del_sdprod",self.sds_dict
701       #if sd in self.sds : self.sds.remove(sd)
702       if sd.nom in self.g_context : del self.g_context[sd.nom]
703       if sd.nom in self.sds_dict : del self.sds_dict[sd.nom]
704
705    def del_param(self,param):
706       """
707           Supprime le parametre param de la liste des paramatres
708           et du contexte gobal
709       """
710       if param in self.params : self.params.remove(param)
711       if param.nom in self.g_context : del self.g_context[param.nom]
712
713    def del_fonction(self,fonction):
714       """
715           Supprime la fonction fonction de la liste des fonctions
716           et du contexte gobal
717       """
718       if fonction in self.fonctions : self.fonctions.remove(fonction)
719       if fonction.nom in self.g_context: del self.g_context[fonction.nom]
720
721    def append_sdprod(self,sd):
722       """
723           Ajoute la SD sd a la liste des sd en verifiant au prealable qu'une SD de
724           meme nom n'existe pas deja
725       """
726       if sd == None or sd.nom == None:return
727
728       o=self.sds_dict.get(sd.nom,None)
729       if isinstance(o,ASSD):
730          raise AsException(tr("Nom de concept deja defini "+ sd.nom))
731       self.sds_dict[sd.nom]=sd
732       self.g_context[sd.nom] = sd
733       #if sd not in self.sds : self.sds.append(sd)
734
735    def append_param(self,param):
736       """
737           Ajoute le parametre param a la liste des params
738           et au contexte global
739       """
740       # il faudrait verifier qu'un parametre de meme nom n'existe pas deja !!!
741       if param not in self.params : self.params.append(param)
742       self.g_context[param.nom]=param
743
744    def append_fonction(self,fonction):
745       """
746           Ajoute la fonction fonction a la liste des fonctions
747           et au contexte global
748       """
749       # il faudrait verifier qu'une fonction de meme nom n'existe pas deja !!!
750       if fonction not in self.fonctions : self.fonctions.append(fonction)
751       self.g_context[fonction.nom]=fonction
752
753    def delete_concept(self,sd):
754       """
755           Inputs :
756              - sd=concept detruit
757           Fonction :
758           Mettre a jour les etapes du JDC suite a la disparition du
759           concept sd
760           Seuls les mots cles simples MCSIMP font un traitement autre
761           que de transmettre aux fils
762       """
763       for etape in self.etapes :
764         etape.delete_concept(sd)
765         #PN PN PN pour les matrices ????
766         #self.get_variables_avant(etape)
767
768    def replace_concept_after_etape(self,etape,old_sd,sd):
769       """
770           Met a jour les etapes du JDC qui sont apres etape en fonction
771           du remplacement du concept sd
772       """
773       index = self.etapes.index(etape)+1
774       if index == len(self.etapes) :
775          return # etape est la derniere etape du jdc ...on ne fait rien !
776       for child in self.etapes[index:]:
777         child.replace_concept(old_sd,sd)
778
779    def update_concept_after_etape(self,etape,sd):
780       """
781           Met a jour les etapes du JDC qui sont apres etape en fonction
782           de la modification (principalement nommage) du concept sd
783       """
784       if etape is None:
785          #On traite toutes les etapes
786          index=0
787       else:
788          index = self.etapes.index(etape)+1
789       if index == len(self.etapes) :
790          return # etape est la derniere etape du jdc ...on ne fait rien !
791       for child in self.etapes[index:]:
792         child.update_concept(sd)
793
794    def dump_state(self):
795       print(("JDC.state: ",self.state))
796       for etape in self.etapes :
797          print((etape.nom+".state: ",etape.state))
798       
799    def change_unit(self,unit,etape,old_unit):
800       #print "change_unit",unit,etape,old_unit
801       #print id(self.recorded_units),self.recorded_units
802       #if self.recorded_units.has_key(old_unit):del self.recorded_units[old_unit]
803       self.record_unit(unit,etape)
804
805    def record_unit(self,unit,etape):
806       """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
807       #print "record_unit",unit,etape
808       if unit is None:
809          # Cas de POURSUITE
810          self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
811       else:
812          self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
813       #print id(self.recorded_units),self.recorded_units
814       #print self.recorded_units.get(None,(None,"",{}))[2]
815       #print self.recorded_units.get(None,(None,"",{}))[2].get(None,(None,"",{}))
816
817    def changefichier(self,fichier):
818        self.fin_modif()
819
820    def eval_in_context(self,valeur,etape):
821       """ Tente d'evaluer valeur dans le contexte courant de etape
822           Retourne le parametre valeur inchange si l'evaluation est impossible
823       """
824       #contexte initial du jdc
825       context=self.condition_context.copy()
826       #contexte courant des concepts. Il contient les parametres
827       context.update(self.get_contexte_avant(etape))
828       try :
829          objet = eval(valeur,context)
830          return objet
831       except:
832          #traceback.print_exc()
833          pass
834       return valeur
835
836 #ATTENTION SURCHARGE : cette methode doit etre gardee en synchronisation avec celle de Noyau
837    def supprime(self):
838       Noyau.N_JDC.JDC.supprime(self)
839       for etape in self.etapes:
840          etape.supprime()
841       self.appli=None
842       self.g_context={}
843       self.const_context={}
844       self.sds_dict={}
845       self.mc_globaux={}
846       self.current_context={}
847       self.condition_context={}
848       self.etapes_niveaux=[]
849       self.niveau=None
850       self.params=[]
851       self.fonctions=[]
852       self._etape_context=None
853       self.etapes=[]
854        
855 #ATTENTION SURCHARGE : cette methode doit etre gardee en synchronisation avec celle de Noyau
856    def register(self,etape):
857       """
858            Cette methode ajoute  etape dans la liste
859            des etapes self.etapes et retourne l identificateur d'etape
860            fourni par l appel a g_register
861
862            A quoi sert editmode ?
863               - Si editmode vaut 1, on est en mode edition de JDC. On cherche
864                 a enregistrer une etape que l'on a creee avec eficas (en passant
865                 par addentite) auquel cas on ne veut recuperer que son numero
866                 d'enregistrement et c'est addentite qui l'enregistre dans
867                 self.etapes a la bonne place...
868               - Si editmode vaut 0, on est en mode relecture d'un fichier de
869                 commandes et on doit enregistrer l'etape a la fin de self.etapes
870                 (dans ce cas l'ordre des etapes est bien l'ordre chronologique
871                 de leur creation   )
872       """
873       if not self.editmode:
874          self.etapes.append(etape)
875          self.index_etapes[etape] = len(self.etapes) - 1
876       else:
877          pass
878       return self.g_register(etape)
879
880 #ATTENTION SURCHARGE : cette methode doit etre gardee en synchronisation avec celle de Noyau
881    def NommerSdprod(self,sd,sdnom,restrict='non'):
882       """
883           Nomme la SD apres avoir verifie que le nommage est possible :
884           nom non utilise
885           Si le nom est deja utilise, leve une exception
886           Met le concept cree dans le concept global g_context
887       """
888       # XXX En mode editeur dans EFICAS, le nommage doit etre gere differemment
889       # Le dictionnaire g_context ne represente pas le contexte
890       # effectif avant une etape.
891       # Il faut utiliser get_contexte_avant avec indication de l'etape
892       # traitee.
893       # Cette etape est indiquee par l'attribut _etape_context qui a ete
894       # positionne prealablement par un appel a set_etape_context
895
896       if CONTEXT.debug : print(("JDC.NommerSdprod ",sd,sdnom))
897
898       if self._etape_context:
899          o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
900       else:
901          o=self.sds_dict.get(sdnom,None)
902
903       if isinstance(o,ASSD):
904          raise AsException(tr(" Nom de concept deja  defini : "+ sdnom))
905
906       # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
907       # Ajoute a la creation (appel de reg_sd).
908       self.sds_dict[sdnom]=sd
909       sd.nom=sdnom
910
911       # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
912       if restrict == 'non':
913          self.g_context[sdnom]=sd
914
915    def delete_concept_entre_etapes(self,index1,index2,sd):
916       if index2 <= index1 :return
917       for child in self.etapes[index1:index2]:
918         child.delete_concept(sd)
919
920    def delete_concept_after_etape(self,etape,sd):
921       """
922           Met a jour les etapes du JDC qui sont apres etape en fonction
923           de la disparition du concept sd
924       """
925       index = self.etapes.index(etape)+1
926       if index == len(self.etapes) :
927          return # etape est la derniere etape du jdc ...on ne fait rien !
928       for child in self.etapes[index:]:
929         child.delete_concept(sd)
930
931 #ATTENTION SURCHARGE : les methodes ci-dessus surchargent des methodes de Noyau et Validation : a reintegrer
932
933    def get_file(self,unite=None,fic_origine=''):
934       """
935           Retourne le nom du fichier correspondant a un numero d'unite
936           logique (entier) ainsi que le source contenu dans le fichier
937       """
938       if self.appli is not None:
939          # Si le JDC est relie a une application maitre, on delegue la recherche
940          file,text= self.appli.get_file(unite,fic_origine)
941       else:
942          file = None
943          if unite != None:
944             if os.path.exists(u"fort."+str(unite)):
945                file= "fort."+str(unite)
946          if file == None :
947             raise AsException(tr("Impossible de trouver le fichier correspondant a l'unite "+str( unite)))
948          if not os.path.exists(file):
949             raise AsException(str(unite)+ tr(" n'est pas un fichier existant"))
950          fproc=open(file,'r')
951          text=fproc.read()
952          fproc.close()
953       #if file == None : return None,None
954       text=text.replace('\r\n','\n')
955       if file:
956          linecache.cache[file]=0,0,text.split('\n'),file
957       return file,text
958
959    def isvalid(self,cr='non'):
960      if hasattr(self,'valid'): old_valid=self.valid
961      else:old_valid=0
962      valid=Validation.V_JDC.JDC.isvalid(self,cr)
963      if valid != old_valid:
964        CONNECTOR.Emit(self,"valid")
965      return valid
966
967    def get_l_noms_etapes(self):
968       """ 
969           Retourne la liste des noms des etapes de self 
970       """
971       l=[]
972       for etape in self.etapes:
973         l.append(etape.nom)
974       return l