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