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