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