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