Salome HOME
correction pb condition_context avec newJDC
[tools/eficas.git] / Ihm / I_JDC.py
1 # -*- coding: utf-8 -*-
2 #            CONFIGURATION MANAGEMENT OF EDF VERSION
3 # ======================================================================
4 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
5 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
6 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
7 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
8 # (AT YOUR OPTION) ANY LATER VERSION.
9 #
10 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
11 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
12 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
13 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
14 #
15 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
16 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
17 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
18 #
19 #
20 # ======================================================================
21 """
22 """
23 # Modules Python
24 import types,traceback
25 import string,linecache
26
27 # Modules Eficas
28 import I_OBJECT
29 from Noyau.N_ASSD import ASSD
30 from Noyau.N_ETAPE import ETAPE
31 from Noyau.N_Exception import AsException
32 from Extensions import commentaire,parametre,parametre_eval
33
34 class JDC(I_OBJECT.OBJECT):
35    """
36    """
37    def __init__(self):
38       self.editmode=0
39       self.etapes_niveaux=[]
40       self.niveau=self
41       self.params=[]
42       self.fonctions=[]
43       self._etape_context=None
44       self.recorded_units={}
45       self.old_recorded_units={}
46
47    def get_sd_avant_du_bon_type(self,etape,types_permis):
48       """
49           Retourne la liste des concepts avant etape d'un type acceptable
50       """
51       d=self.get_contexte_avant(etape)
52       l=[]
53       for k,v in d.items():
54         if type(v) != types.InstanceType : continue
55         # On considère que seul assd indique un type quelconque pas CO
56         elif self.assd in types_permis :
57            l.append(k)
58         elif self.est_permis(v,types_permis):
59            l.append(k)
60       l.sort()
61       return l
62
63    def est_permis(self,v,types_permis):
64       for type_ok in types_permis:
65           if type_ok in ('R','I','C','TXM') and v in self.params : 
66              return 1
67           elif type_ok == 'R' and v.__class__.__name__ == 'reel' : 
68              return 1
69           elif type_ok == 'I' and v.__class__.__name__ == 'entier' : 
70              return 1
71           elif type_ok == 'C' and v.__class__.__name__ == 'complexe' : 
72              return 1
73           elif type_ok == 'TXM' and v.__class__.__name__ == 'chaine' : 
74              return 1
75           elif type(type_ok) != types.ClassType : 
76              continue
77           elif v.__class__ == type_ok or issubclass(v.__class__,type_ok):
78              return 1
79       return 0
80
81    def addentite(self,name,pos):
82       """
83           Ajoute une entite :
84           Si name est le nom d une commande ou un commentaire ajoute 
85           une etape au JDC
86           Sinon remonte une erreur
87       """
88       self.init_modif()
89       self.editmode=1
90       if name == "COMMENTAIRE" :
91         # ajout d'un commentaire
92         self.set_current_step()
93         ind = 1
94         for child in self.etapes :
95           if isinstance(child,commentaire.COMMENTAIRE):
96             ind = ind+1
97         objet = commentaire.COMMENTAIRE('',parent=self)
98         objet.nom = "_comm_"+`ind`
99         if pos == None : pos = 0
100         self.etapes.insert(pos,objet)
101         self.editmode=0
102         self.active_etapes()
103         self.fin_modif()
104         return objet
105       elif name == "PARAMETRE":
106         # ajout d'un parametre
107         self.set_current_step()
108         nom_param = '_param_'+str(len(self.params)+1)
109         objet = parametre.PARAMETRE(nom=nom_param)
110         if pos == None : pos = 0
111         self.etapes.insert(pos,objet)
112         self.editmode=0
113         self.reset_context()
114         self.active_etapes()
115         self.fin_modif()
116         return objet
117       elif name == "PARAMETRE_EVAL":
118         # ajout d'un parametre EVAL
119         self.set_current_step()
120         nom_param = '_param_'+str(len(self.params)+1)
121         objet = parametre_eval.PARAMETRE_EVAL(nom=nom_param)
122         if pos == None : pos = 0
123         self.etapes.insert(pos,objet)
124         self.editmode=0
125         self.reset_context()
126         self.active_etapes()
127         self.fin_modif()
128         return objet
129       elif type(name)==types.InstanceType:
130         # on est dans le cas où on veut ajouter une commande déjà 
131         # existante (par copie donc)
132         # on est donc nécessairement en mode editeur ...
133         objet = name
134         # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
135         objet.reparent(self)
136         self.set_current_step()
137         if isinstance(objet,ETAPE):
138           if objet.nom_niveau_definition == 'JDC':
139             # l'objet dépend directement du JDC
140             objet.niveau = self
141           else:
142             # l'étape dépend d'un niveau et non directement du JDC :
143             # il faut l'enregistrer dans le niveau de parent
144             objet.parent.dict_niveaux[objet.nom_niveau_definition].register(objet)
145             objet.niveau = objet.parent.dict_niveaux[objet.nom_niveau_definition]
146         self.etapes.insert(pos,objet)
147         # il faut vérifier que les concepts utilisés par objet existent bien
148         # à ce niveau d'arborescence
149         objet.verif_existence_sd()
150         self.active_etapes()
151         self.editmode=0
152         self.reset_context()
153         print "addentite",self.etapes
154         self.fin_modif()
155         return objet
156       else :
157         # On veut ajouter une nouvelle commande
158         try:
159           self.set_current_step()
160           cmd=self.get_cmd(name)
161           # L'appel a make_objet n'a pas pour effet d'enregistrer l'étape
162           # auprès du step courant car editmode vaut 1
163           # Par contre elle a le bon parent grace a set_current_step
164           e=cmd.make_objet()
165           if pos == None : pos = 0
166           self.etapes.insert(pos,e)
167           self.reset_current_step()
168           self.editmode=0
169           self.reset_context()
170           self.active_etapes()
171           print "addentite",self.etapes
172           self.fin_modif()
173           return e
174         except AsException,e:
175           self.reset_current_step()
176           self.editmode=0
177           raise AsException("Impossible d ajouter la commande "+name + '\n' +str(e))
178         except:
179           traceback.print_exc()
180           self.reset_current_step()
181           self.editmode=0
182           raise AsException("Impossible d ajouter la commande "+name)
183
184    def set_current_step(self):
185       CONTEXT.unset_current_step()
186       CONTEXT.set_current_step(self)
187
188    def reset_current_step(self):
189       CONTEXT.unset_current_step()
190
191    def liste_mc_presents(self):
192       return []
193
194    def get_sd_avant_etape(self,nom_sd,etape):
195       return self.get_contexte_avant(etape).get(nom_sd,None)
196
197    def get_sd_apres_etape_avec_detruire(self,nom_sd,sd,etape,avec='non'):
198       """ 
199            Cette méthode retourne la SD sd de nom nom_sd qui est éventuellement
200            définie apres etape en tenant compte des concepts detruits
201            Si avec vaut 'non' exclut etape de la recherche
202       """
203       ietap=self.etapes.index(etape)
204       if avec == 'non':ietap=ietap+1
205       d={nom_sd:sd}
206       for e in self.etapes[ietap:]:
207          if e.isactif():
208             e.update_context(d)
209             autre_sd=d.get(nom_sd,None)
210             if autre_sd is None:
211               # Le concept a ete detruit
212               return None
213             if autre_sd is not sd :
214               # L'etape produit un concept de meme nom
215               if hasattr(e,'reuse') and e.reuse == autre_sd:
216                  # Le concept etant reutilise, on interrompt la recherche. 
217                  # On considere qu'il n'y a pas de nouveau concept defini
218                  # meme si dans les etapes suivantes le concept est detruit
219                  # et un concept de meme nom créé.
220                  return None
221               else:
222                  # Le concept est produit par l'etape
223                  return autre_sd
224       # On n'a rien trouve. Pas de concept de nom nom_sd
225       return None
226
227    def get_sd_apres_etape(self,nom_sd,etape,avec='non'):
228       """ 
229            Cette méthode retourne la SD de nom nom_sd qui est éventuellement
230            définie apres etape 
231            Si avec vaut 'non' exclut etape de la recherche
232       """
233       ietap=self.etapes.index(etape)
234       if avec == 'non':ietap=ietap+1
235       for e in self.etapes[ietap:]:
236         sd=e.get_sdprods(nom_sd)
237         if sd:
238           if hasattr(e,'reuse'):
239             if e.reuse != sd:
240               return sd
241       return None
242
243    def get_sd_autour_etape(self,nom_sd,etape,avec='non'):
244       """
245            Fonction: retourne la SD de nom nom_sd qui est éventuellement
246            définie avant ou apres etape
247            Permet de vérifier si un concept de meme nom existe dans le périmètre 
248            d'une étape
249            Si avec vaut 'non' exclut etape de la recherche
250       """
251       sd=self.get_sd_avant_etape(nom_sd,etape)
252       if sd:return sd
253       return self.get_sd_apres_etape(nom_sd,etape,avec)
254
255    def get_contexte_apres(self,etape):
256       """
257          Retourne le dictionnaire des concepts connus apres etape
258          On tient compte des commandes qui modifient le contexte
259          comme DETRUIRE ou les macros
260          Si etape == None, on retourne le contexte en fin de JDC
261       """
262       if not etape: return self.get_contexte_avant(etape)
263
264       d=self.get_contexte_avant(etape)
265       if etape.isactif():etape.update_context(d)
266       self.index_etape_courante=self.index_etape_courante+1
267       return d
268
269    def active_etapes(self):
270       """
271           Cette méthode a pour fonction de désactiver les étapes qui doivent
272           l'être cad, dans le cas d'ASTER, les étapes qui ne sont pas 
273           comprises entre le premier DEBUT/POURSUITE et le premier FIN 
274           et rendre actives les autres
275       """
276       if self.definition.code == 'ASTER' :
277          # Seulement pour ASTER :
278          # Avant DEBUT actif vaut 0
279          # Apres DEBUT et avant le 1er FIN actif vaut 1
280          # Apres le 1er FIN actif vaut -1
281          actif=0
282       else:
283          actif=1
284       for etape in self.etapes:
285         if actif == 0 and etape.nom in ['DEBUT','POURSUITE']:actif=1
286         if actif == 1:
287            etape.active()
288         else:
289            etape.inactive()
290         if etape.nom == 'FIN':actif=-1
291
292    def suppentite(self,etape) :
293       """  
294           Cette methode a pour fonction de supprimer une étape dans 
295           un jeu de commandes
296           Retourne 1 si la suppression a pu être effectuée,
297           Retourne 0 dans le cas contraire
298       """
299       self.init_modif()
300       # On memorise le contexte avant l'etape a supprimer
301       d=self.get_contexte_avant(etape)
302       index_etape=self.etapes.index(etape)
303
304       self.etapes.remove(etape)
305       if etape.niveau is not self:
306         # Dans ce cas l'étape est enregistrée dans un niveau
307         # Il faut la désenregistrer
308         etape.niveau.unregister(etape)
309       etape.supprime_sdprods()
310       self.active_etapes()
311
312       # Apres suppression de l'etape il faut controler que les etapes
313       # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape
314       for e in self.etapes[index_etape:]:
315          e.control_sdprods(d)
316       
317       self.reset_context()
318       self.fin_modif()
319       return 1
320
321    def analyse(self):
322       self.compile()
323       if not self.cr.estvide():return
324       self.exec_compile()
325       self.active_etapes()
326
327    def register_parametre(self,param):
328       """
329           Cette méthode sert à ajouter un paramètre dans la liste des paramètres
330       """
331       self.params.append(param)
332
333    def register_fonction(self,fonction):
334       """
335           Cette méthode sert à ajouter une fonction dans la liste des fonctions
336       """
337       self.fonctions.append(fonction)
338
339    def delete_param(self,param):
340       """
341           Supprime le paramètre param de la liste des paramètres
342           et du contexte gobal
343       """
344       if param in self.params : self.params.remove(param)
345       if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
346
347    def get_parametres_fonctions_avant_etape(self,etape):
348       """
349           Retourne deux éléments :
350           - une liste contenant les noms des paramètres (constantes ou EVAL) 
351             définis avant etape
352           - une liste contenant les formules définies avant etape
353       """
354       l_constantes = []
355       l_fonctions = []
356       # on récupère le contexte avant etape
357       # on ne peut mettre dans les deux listes que des éléments de ce contexte
358       d=self.get_contexte_avant(etape)
359       # construction de l_constantes
360       for param in self.params:
361         nom = param.nom
362         if not nom : continue
363         if d.has_key(nom): l_constantes.append(nom)
364       # construction de l_fonctions
365       for form in self.fonctions:
366         nom = form.nom
367         if not nom : continue
368         if d.has_key(nom): l_fonctions.append(form.get_formule())
369
370       # on ajoute les concepts produits par DEFI_VALEUR
371       # XXX On pourrait peut etre faire plutot le test sur le type
372       # de concept : entier, reel, complexe, etc.
373       for k,v in d.items():
374          if hasattr(v,'etape') and v.etape.nom in ('DEFI_VALEUR',):
375             l_constantes.append(k)
376
377       # on retourne les deux listes
378       return l_constantes,l_fonctions
379
380    def get_nb_etapes_avant(self,niveau):
381       """ 
382           Retourne le nombre d etapes avant le debut de niveau
383       """
384       nb=0
385       for niv in self.etapes_niveaux:
386         if niv == niveau:break
387         nb=nb+len(niv.etapes)
388       return nb
389
390    def send_message(self,message):
391       if self.appli:
392          self.appli.send_message(message)
393
394    def init_modif(self):
395       """
396       Méthode appelée au moment où une modification va être faite afin de 
397       déclencher d'éventuels traitements pré-modification
398       """
399       print "init_modif",self
400       self.state = 'modified'
401
402    def fin_modif(self):
403       print "fin_modif",self
404       self.isvalid()
405       pass
406
407    def get_liste_mc_inconnus(self):
408      """
409      Retourne une liste contenant les mots-clés inconnus à la relecture du JDC
410      """
411      # cette liste a le format suivant : [etape,(bloc,mcfact,...),nom_mc,valeur_mc]
412      l_mc = []
413      for etape in self.etapes :
414          if etape.isactif() :
415             if not etape.isvalid() :
416                l = etape.get_liste_mc_inconnus()
417                if l : l_mc.extend(l)
418      return l_mc    
419
420    def get_genealogie(self):
421       """
422           Retourne la liste des noms des ascendants de l'objet self
423           jusqu'à la première ETAPE parent.
424       """
425       return []
426
427    def get_liste_cmd(self):
428       """
429           Retourne la liste des commandes du catalogue
430       """
431       return self.niveau.definition.get_liste_cmd()
432
433    def get_groups(self):
434       """
435           Retourne la liste des groupes
436       """
437       return self.niveau.definition.liste_groupes,self.niveau.definition.dict_groupes
438
439    def set_etape_context(self,etape):
440       """
441           Positionne l'etape qui sera utilisee dans NommerSdProd pour
442           decider si le concept passé pourra etre  nommé
443       """
444       self._etape_context=etape
445
446    def reset_context(self):
447       """ 
448           Cette methode reinitialise le contexte glissant pour pouvoir
449           tenir compte des modifications de l'utilisateur : création
450           de commandes, nommage de concepts, etc.
451       """
452       self.current_context={}
453       self.index_etape_courante=0
454
455    def del_sdprod(self,sd):
456       """
457           Supprime la SD sd de la liste des sd et des dictionnaires de contexte
458       """
459       if sd in self.sds : self.sds.remove(sd)
460       if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
461       if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
462
463    def del_param(self,param):
464       """
465           Supprime le paramètre param de la liste des paramètres
466           et du contexte gobal
467       """
468       if param in self.params : self.params.remove(param)
469       if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
470
471    def del_fonction(self,fonction):
472       """
473           Supprime la fonction fonction de la liste des fonctions
474           et du contexte gobal
475       """
476       if fonction in self.fonctions : self.fonctions.remove(fonction)
477       if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
478
479    def append_sdprod(self,sd):
480       """
481           Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
482           même nom n'existe pas déjà
483       """
484       if sd == None or sd.nom == None:return
485
486       o=self.sds_dict.get(sd.nom,None)
487       if isinstance(o,ASSD):
488          raise AsException("Nom de concept deja defini : %s" % sd.nom)
489       self.sds_dict[sd.nom]=sd
490       self.g_context[sd.nom] = sd
491       if sd not in self.sds : self.sds.append(sd)
492
493    def append_param(self,param):
494       """
495           Ajoute le paramètre param à la liste des params
496           et au contexte global
497       """
498       # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
499       if param not in self.params : self.params.append(param)
500       self.g_context[param.nom]=param
501
502    def append_fonction(self,fonction):
503       """
504           Ajoute la fonction fonction à la liste des fonctions
505           et au contexte global
506       """
507       # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
508       if fonction not in self.fonctions : self.fonctions.append(fonction)
509       self.g_context[fonction.nom]=fonction
510
511    def delete_concept(self,sd):
512       """
513           Inputs :
514              - sd=concept detruit
515           Fonction :
516           Mettre a jour les etapes du JDC suite à la disparition du
517           concept sd
518           Seuls les mots cles simples MCSIMP font un traitement autre
519           que de transmettre aux fils
520       """
521       for etape in self.etapes :
522         etape.delete_concept(sd)
523
524    def replace_concept_after_etape(self,etape,old_sd,sd):
525       """
526           Met à jour les étapes du JDC qui sont après etape en fonction
527           du remplacement du concept sd
528       """
529       index = self.etapes.index(etape)+1
530       if index == len(self.etapes) :
531          return # etape est la dernière étape du jdc ...on ne fait rien !
532       for child in self.etapes[index:]:
533         child.replace_concept(old_sd,sd)
534
535    def dump_state(self):
536       print "dump_state"
537       print "JDC.state: ",self.state
538       for etape in self.etapes :
539          print etape.nom+".state: ",etape.state
540       
541    def change_unit(self,unit,etape,old_unit):
542       #print "change_unit",unit,etape,old_unit
543       #print id(self.recorded_units),self.recorded_units
544       #if self.recorded_units.has_key(old_unit):del self.recorded_units[old_unit]
545       self.record_unit(unit,etape)
546
547    def record_unit(self,unit,etape):
548       """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
549       #print "record_unit",unit,etape
550       if unit is None:
551          # Cas de POURSUITE
552          self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
553       else:
554          self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
555       #print id(self.recorded_units),self.recorded_units
556       #print self.recorded_units.get(None,(None,"",{}))[2]
557       #print self.recorded_units.get(None,(None,"",{}))[2].get(None,(None,"",{}))
558
559 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
560    def register(self,etape):
561       """
562            Cette méthode ajoute  etape dans la liste
563            des etapes self.etapes et retourne l identificateur d'étape
564            fourni par l appel a g_register
565
566            A quoi sert editmode ?
567               - Si editmode vaut 1, on est en mode edition de JDC. On cherche
568                 à enregistrer une étape que l'on a créée avec eficas (en passant
569                 par addentite) auquel cas on ne veut récupérer que son numéro
570                 d'enregistrement et c'est addentité qui l'enregistre dans
571                 self.etapes à la bonne place...
572               - Si editmode vaut 0, on est en mode relecture d'un fichier de
573                 commandes et on doit enregistrer l'étape à la fin de self.etapes
574                 (dans ce cas l'ordre des étapes est bien l'ordre chronologique
575                 de leur création   )
576       """
577       if not self.editmode:
578          self.etapes.append(etape)
579       else:
580          pass
581       return self.g_register(etape)
582
583 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
584    def NommerSdprod(self,sd,sdnom,restrict='non'):
585       """
586           Nomme la SD apres avoir verifie que le nommage est possible :
587           nom non utilise
588           Si le nom est deja utilise, leve une exception
589           Met le concept créé dans le concept global g_context
590       """
591       # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
592       # Le dictionnaire g_context ne représente pas le contexte
593       # effectif avant une étape.
594       # Il faut utiliser get_contexte_avant avec indication de l'étape
595       # traitée.
596       # Cette etape est indiquee par l'attribut _etape_context qui a ete
597       # positionné préalablement par un appel à set_etape_context
598
599       if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
600
601       if self._etape_context:
602          o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
603       else:
604          o=self.sds_dict.get(sdnom,None)
605
606       if isinstance(o,ASSD):
607          raise AsException("Nom de concept deja defini : %s" % sdnom)
608
609       # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
610       # Ajoute a la creation (appel de reg_sd).
611       self.sds_dict[sdnom]=sd
612       sd.nom=sdnom
613
614       # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
615       if restrict == 'non':
616          self.g_context[sdnom]=sd
617
618 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
619    def delete_concept_after_etape(self,etape,sd):
620       """
621           Met à jour les étapes du JDC qui sont après etape en fonction
622           de la disparition du concept sd
623       """
624       index = self.etapes.index(etape)+1
625       if index == len(self.etapes) :
626          return # etape est la dernière étape du jdc ...on ne fait rien !
627       for child in self.etapes[index:]:
628         child.delete_concept(sd)
629
630 #ATTENTION SURCHARGE : les methodes ci-dessous surchargent des methodes de Noyau et Validation : a reintegrer
631