]> SALOME platform Git repositories - tools/eficas.git/blob - Ihm/I_JDC.py
Salome HOME
104ee1c6a36b43190b951a9acedff53f168740a4
[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.appli :
445          # Si le JDC est relié à une application maitre, on délègue la recherche
446          file,text = self.appli.get_file(unite,fic_origine)
447       else:
448          file = None
449          if unite != None:
450             if os.path.exists("fort."+str(unite)):
451                file= "fort."+str(unite)
452          if file == None :
453             raise AsException("Impossible de trouver le fichier correspondant \
454                                a l unite %s" % unite)
455          if not os.path.exists(file):
456             raise AsException("%s n'est pas un fichier existant" % unite)
457          fproc=open(file,'r')
458          text=fproc.read()
459          fproc.close()
460       if file == None : return None,None
461       text=string.replace(text,'\r\n','\n')
462       linecache.cache[file]=0,0,string.split(text,'\n'),file
463       return file,text
464
465
466    def get_genealogie(self):
467       """
468           Retourne la liste des noms des ascendants de l'objet self
469           jusqu'à la première ETAPE parent.
470       """
471       return []
472
473    def NommerSdprod(self,sd,sdnom,restrict='non'):
474       """
475           Nomme la SD apres avoir verifie que le nommage est possible : 
476           nom non utilise
477           Si le nom est deja utilise, leve une exception
478           Met le concept créé dans le concept global g_context
479       """
480       # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
481       # Le dictionnaire g_context ne représente pas le contexte
482       # effectif avant une étape.
483       # Il faut utiliser get_contexte_avant avec indication de l'étape
484       # traitée. 
485       # Cette etape est indiquee par l'attribut _etape_context qui a ete 
486       # positionné préalablement par un appel à set_etape_context
487
488       if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
489
490       if self._etape_context:
491          o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
492       else:
493          o=self.sds_dict.get(sdnom,None)
494
495       if isinstance(o,ASSD):
496          raise AsException("Nom de concept deja defini : %s" % sdnom)
497
498       # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
499       # Ajoute a la creation (appel de reg_sd).
500       self.sds_dict[sdnom]=sd
501       sd.nom=sdnom
502
503    def set_etape_context(self,etape):
504       """
505           Positionne l'etape qui sera utilisee dans NommerSdProd pour
506           decider si le concept passé pourra etre  nommé
507       """
508       self._etape_context=etape
509
510    def reset_context(self):
511       """ 
512           Cette methode reinitialise le contexte glissant pour pouvoir
513           tenir compte des modifications de l'utilisateur : création
514           de commandes, nommage de concepts, etc.
515       """
516       self.current_context={}
517       self.index_etape_courante=0
518
519    def del_sdprod(self,sd):
520       """
521           Supprime la SD sd de la liste des sd et des dictionnaires de contexte
522       """
523       if sd in self.sds : self.sds.remove(sd)
524       if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
525       if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
526
527    def del_param(self,param):
528       """
529           Supprime le paramètre param de la liste des paramètres
530           et du contexte gobal
531       """
532       if param in self.params : self.params.remove(param)
533       if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
534
535    def del_fonction(self,fonction):
536       """
537           Supprime la fonction fonction de la liste des fonctions
538           et du contexte gobal
539       """
540       if fonction in self.fonctions : self.fonctions.remove(fonction)
541       if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
542
543    def append_sdprod(self,sd):
544       """
545           Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
546           même nom n'existe pas déjà
547       """
548       if sd == None or sd.nom == None:return
549
550       o=self.sds_dict.get(sd.nom,None)
551       if isinstance(o,ASSD):
552          raise AsException("Nom de concept deja defini : %s" % sd.nom)
553       self.sds_dict[sd.nom]=sd
554       self.g_context[sd.nom] = sd
555       if sd not in self.sds : self.sds.append(sd)
556
557    def append_param(self,param):
558       """
559           Ajoute le paramètre param à la liste des params
560           et au contexte global
561       """
562       # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
563       if param not in self.params : self.params.append(param)
564       self.g_context[param.nom]=param
565
566    def append_fonction(self,fonction):
567       """
568           Ajoute la fonction fonction à la liste des fonctions
569           et au contexte global
570       """
571       # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
572       if fonction not in self.fonctions : self.fonctions.append(fonction)
573       self.g_context[fonction.nom]=fonction
574
575    def delete_concept_after_etape(self,etape,sd):
576       """
577           Met à jour les étapes du JDC qui sont après etape en fonction
578           de la disparition du concept sd
579       """
580       index = self.etapes.index(etape)+1
581       if index == len(self.etapes) : 
582          return # etape est la dernière étape du jdc ...on ne fait rien !
583       for child in self.etapes[index:]:
584         child.delete_concept(sd)
585
586    def delete_concept(self,sd):
587       """
588           Inputs :
589              sd=concept detruit
590           Fonction :
591              Mettre a jour les etapes du JDC suite à la disparition du
592              concept sd
593              Seuls les mots cles simples MCSIMP font un traitement autre
594              que de transmettre aux fils
595       """
596       for etape in self.etapes :
597         etape.delete_concept(sd)
598
599    def replace_concept_after_etape(self,etape,old_sd,sd):
600       """
601           Met à jour les étapes du JDC qui sont après etape en fonction
602           du remplacement du concept sd
603       """
604       index = self.etapes.index(etape)+1
605       if index == len(self.etapes) :
606          return # etape est la dernière étape du jdc ...on ne fait rien !
607       for child in self.etapes[index:]:
608         child.replace_concept(old_sd,sd)
609
610    def dump_state(self):
611       print "dump_state"
612       print "JDC.state: ",self.state
613       for etape in self.etapes :
614          print etape.nom+".state: ",etape.state
615       
616    def change_unit(self,unit,etape,old_unit):
617       if self.recorded_units.has_key(old_unit):del self.recorded_units[old_unit]
618       self.record_unit(unit,etape)
619
620    def record_unit(self,unit,etape):
621       """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
622       if unit is None:
623          # Cas de POURSUITE
624          self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
625       else:
626          self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
627
628 #ATTENTION cette methode surcharge la methode du package Validation : a reintegrer
629    def isvalid(self,cr='non'):
630       """
631         Méthode booléenne qui retourne 0 si le JDC est invalide, 1 sinon
632       """
633       # FR : on prend en compte l'état du JDC ('unchanged','modified','undetermined')
634       # afin d'accélérer le test de validité du JDC
635       if self.state == 'unchanged':
636         return self.valid
637       else:
638         valid = 1
639         texte,test = self.verif_regles()
640         if test == 0:
641           if cr == 'oui': self.cr.fatal(string.strip(texte))
642           valid = 0
643         if valid :
644           for e in self.etapes:
645             if not e.isactif() : continue
646             if not e.isvalid():
647               valid = 0
648               break
649         self.state="unchanged"
650         self.valid = valid
651         return self.valid
652