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