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