Salome HOME
PN :pour notation scientifique
[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 etant reutilise, on interrompt la recherche. 
210                  # On considere qu'il n'y a pas de nouveau concept defini
211                  # meme si dans les etapes suivantes le concept est detruit
212                  # et un concept de meme nom créé.
213                  return None
214               else:
215                  # Le concept est produit par l'etape
216                  return autre_sd
217       # On n'a rien trouve. Pas de concept de nom nom_sd
218       return None
219
220    def get_sd_apres_etape(self,nom_sd,etape,avec='non'):
221       """ 
222            Cette méthode retourne la SD de nom nom_sd qui est éventuellement
223            définie apres etape 
224            Si avec vaut 'non' exclut etape de la recherche
225       """
226       ietap=self.etapes.index(etape)
227       if avec == 'non':ietap=ietap+1
228       for e in self.etapes[ietap:]:
229         sd=e.get_sdprods(nom_sd)
230         if sd:
231           if hasattr(e,'reuse'):
232             if e.reuse != sd:
233               return sd
234       return None
235
236    def get_sd_autour_etape(self,nom_sd,etape,avec='non'):
237       """
238            Fonction: retourne la SD de nom nom_sd qui est éventuellement
239            définie avant ou apres etape
240            Permet de vérifier si un concept de meme nom existe dans le périmètre 
241            d'une étape
242            Si avec vaut 'non' exclut etape de la recherche
243       """
244       sd=self.get_sd_avant_etape(nom_sd,etape)
245       if sd:return sd
246       return self.get_sd_apres_etape(nom_sd,etape,avec)
247
248    def get_contexte_apres(self,etape):
249       """
250          Retourne le dictionnaire des concepts connus apres etape
251          On tient compte des commandes qui modifient le contexte
252          comme DETRUIRE ou les macros
253          Si etape == None, on retourne le contexte en fin de JDC
254       """
255       if not etape: return self.get_contexte_avant(etape)
256
257       d=self.get_contexte_avant(etape)
258       if etape.isactif():etape.update_context(d)
259       self.index_etape_courante=self.index_etape_courante+1
260       return d
261
262    def active_etapes(self):
263       """
264           Cette méthode a pour fonction de désactiver les étapes qui doivent
265           l'être cad, dans le cas d'ASTER, les étapes qui ne sont pas 
266           comprises entre le premier DEBUT/POURSUITE et le premier FIN 
267           et rendre actives les autres
268       """
269       if self.definition.code == 'ASTER' :
270          # Seulement pour ASTER :
271          # Avant DEBUT actif vaut 0
272          # Apres DEBUT et avant le 1er FIN actif vaut 1
273          # Apres le 1er FIN actif vaut -1
274          actif=0
275       else:
276          actif=1
277       for etape in self.etapes:
278         if actif == 0 and etape.nom in ['DEBUT','POURSUITE']:actif=1
279         if actif == 1:
280            etape.active()
281         else:
282            etape.inactive()
283         if etape.nom == 'FIN':actif=-1
284
285    def suppentite(self,etape) :
286       """  
287           Cette methode a pour fonction de supprimer une étape dans 
288           un jeu de commandes
289           Retourne 1 si la suppression a pu être effectuée,
290           Retourne 0 dans le cas contraire
291       """
292       self.init_modif()
293       # On memorise le contexte avant l'etape a supprimer
294       d=self.get_contexte_avant(etape)
295       index_etape=self.etapes.index(etape)
296
297       self.etapes.remove(etape)
298       if etape.niveau is not self:
299         # Dans ce cas l'étape est enregistrée dans un niveau
300         # Il faut la désenregistrer
301         etape.niveau.unregister(etape)
302       etape.supprime_sdprods()
303       self.active_etapes()
304
305       # Apres suppression de l'etape il faut controler que les etapes
306       # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape
307       for e in self.etapes[index_etape:]:
308          e.control_sdprods(d)
309       
310       self.reset_context()
311       self.fin_modif()
312       return 1
313
314    def analyse(self):
315       self.compile()
316       if not self.cr.estvide():return
317       self.exec_compile()
318       self.active_etapes()
319
320    def register_parametre(self,param):
321       """
322           Cette méthode sert à ajouter un paramètre dans la liste des paramètres
323       """
324       self.params.append(param)
325
326    def register_fonction(self,fonction):
327       """
328           Cette méthode sert à ajouter une fonction dans la liste des fonctions
329       """
330       self.fonctions.append(fonction)
331
332    def delete_param(self,param):
333       """
334           Supprime le paramètre param de la liste des paramètres
335           et du contexte gobal
336       """
337       if param in self.params : self.params.remove(param)
338       if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
339
340    def get_parametres_fonctions_avant_etape(self,etape):
341       """
342           Retourne deux éléments :
343           - une liste contenant les noms des paramètres (constantes ou EVAL) 
344             définis avant etape
345           - une liste contenant les formules définies avant etape
346       """
347       l_constantes = []
348       l_fonctions = []
349       # on récupère le contexte avant etape
350       # on ne peut mettre dans les deux listes que des éléments de ce contexte
351       d=self.get_contexte_avant(etape)
352       # construction de l_constantes
353       for param in self.params:
354         nom = param.nom
355         if not nom : continue
356         if d.has_key(nom): l_constantes.append(nom)
357       # construction de l_fonctions
358       for form in self.fonctions:
359         nom = form.nom
360         if not nom : continue
361         if d.has_key(nom): l_fonctions.append(form.get_formule())
362
363       # on ajoute les concepts produits par DEFI_VALEUR
364       # XXX On pourrait peut etre faire plutot le test sur le type
365       # de concept : entier, reel, complexe, etc.
366       for k,v in d.items():
367          if hasattr(v,'etape') and v.etape.nom in ('DEFI_VALEUR',):
368             l_constantes.append(k)
369
370       # on retourne les deux listes
371       return l_constantes,l_fonctions
372
373    def get_nb_etapes_avant(self,niveau):
374       """ 
375           Retourne le nombre d etapes avant le debut de niveau
376       """
377       nb=0
378       for niv in self.etapes_niveaux:
379         if niv == niveau:break
380         nb=nb+len(niv.etapes)
381       return nb
382
383    def send_message(self,message):
384       if self.appli:
385          self.appli.send_message(message)
386
387    def init_modif(self):
388       """
389       Méthode appelée au moment où une modification va être faite afin de 
390       déclencher d'éventuels traitements pré-modification
391       """
392       self.state = 'modified'
393
394    def fin_modif(self):
395       self.isvalid()
396       pass
397
398    def get_liste_mc_inconnus(self):
399      """
400      Retourne une liste contenant les mots-clés inconnus à la relecture du JDC
401      """
402      # cette liste a le format suivant : [etape,(bloc,mcfact,...),nom_mc,valeur_mc]
403      l_mc = []
404      for etape in self.etapes :
405          if etape.isactif() :
406             if not etape.isvalid() :
407                l = etape.get_liste_mc_inconnus()
408                if l : l_mc.extend(l)
409      return l_mc    
410
411    def get_genealogie(self):
412       """
413           Retourne la liste des noms des ascendants de l'objet self
414           jusqu'à la première ETAPE parent.
415       """
416       return []
417
418    def set_etape_context(self,etape):
419       """
420           Positionne l'etape qui sera utilisee dans NommerSdProd pour
421           decider si le concept passé pourra etre  nommé
422       """
423       self._etape_context=etape
424
425    def reset_context(self):
426       """ 
427           Cette methode reinitialise le contexte glissant pour pouvoir
428           tenir compte des modifications de l'utilisateur : création
429           de commandes, nommage de concepts, etc.
430       """
431       self.current_context={}
432       self.index_etape_courante=0
433
434    def del_sdprod(self,sd):
435       """
436           Supprime la SD sd de la liste des sd et des dictionnaires de contexte
437       """
438       if sd in self.sds : self.sds.remove(sd)
439       if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
440       if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
441
442    def del_param(self,param):
443       """
444           Supprime le paramètre param de la liste des paramètres
445           et du contexte gobal
446       """
447       if param in self.params : self.params.remove(param)
448       if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
449
450    def del_fonction(self,fonction):
451       """
452           Supprime la fonction fonction de la liste des fonctions
453           et du contexte gobal
454       """
455       if fonction in self.fonctions : self.fonctions.remove(fonction)
456       if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
457
458    def append_sdprod(self,sd):
459       """
460           Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
461           même nom n'existe pas déjà
462       """
463       if sd == None or sd.nom == None:return
464
465       o=self.sds_dict.get(sd.nom,None)
466       if isinstance(o,ASSD):
467          raise AsException("Nom de concept deja defini : %s" % sd.nom)
468       self.sds_dict[sd.nom]=sd
469       self.g_context[sd.nom] = sd
470       if sd not in self.sds : self.sds.append(sd)
471
472    def append_param(self,param):
473       """
474           Ajoute le paramètre param à la liste des params
475           et au contexte global
476       """
477       # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
478       if param not in self.params : self.params.append(param)
479       self.g_context[param.nom]=param
480
481    def append_fonction(self,fonction):
482       """
483           Ajoute la fonction fonction à la liste des fonctions
484           et au contexte global
485       """
486       # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
487       if fonction not in self.fonctions : self.fonctions.append(fonction)
488       self.g_context[fonction.nom]=fonction
489
490    def delete_concept(self,sd):
491       """
492           Inputs :
493              - sd=concept detruit
494           Fonction :
495           Mettre a jour les etapes du JDC suite à la disparition du
496           concept sd
497           Seuls les mots cles simples MCSIMP font un traitement autre
498           que de transmettre aux fils
499       """
500       for etape in self.etapes :
501         etape.delete_concept(sd)
502
503    def replace_concept_after_etape(self,etape,old_sd,sd):
504       """
505           Met à jour les étapes du JDC qui sont après etape en fonction
506           du remplacement du concept sd
507       """
508       index = self.etapes.index(etape)+1
509       if index == len(self.etapes) :
510          return # etape est la dernière étape du jdc ...on ne fait rien !
511       for child in self.etapes[index:]:
512         child.replace_concept(old_sd,sd)
513
514    def dump_state(self):
515       print "dump_state"
516       print "JDC.state: ",self.state
517       for etape in self.etapes :
518          print etape.nom+".state: ",etape.state
519       
520    def change_unit(self,unit,etape,old_unit):
521       if self.recorded_units.has_key(old_unit):del self.recorded_units[old_unit]
522       self.record_unit(unit,etape)
523
524    def record_unit(self,unit,etape):
525       """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
526       if unit is None:
527          # Cas de POURSUITE
528          self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
529       else:
530          self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
531
532 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
533    def register(self,etape):
534       """
535            Cette méthode ajoute  etape dans la liste
536            des etapes self.etapes et retourne l identificateur d'étape
537            fourni par l appel a g_register
538
539            A quoi sert editmode ?
540               - Si editmode vaut 1, on est en mode edition de JDC. On cherche
541                 à enregistrer une étape que l'on a créée avec eficas (en passant
542                 par addentite) auquel cas on ne veut récupérer que son numéro
543                 d'enregistrement et c'est addentité qui l'enregistre dans
544                 self.etapes à la bonne place...
545               - Si editmode vaut 0, on est en mode relecture d'un fichier de
546                 commandes et on doit enregistrer l'étape à la fin de self.etapes
547                 (dans ce cas l'ordre des étapes est bien l'ordre chronologique
548                 de leur création   )
549       """
550       if not self.editmode:
551          self.etapes.append(etape)
552       else:
553          pass
554       return self.g_register(etape)
555
556 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
557    def NommerSdprod(self,sd,sdnom,restrict='non'):
558       """
559           Nomme la SD apres avoir verifie que le nommage est possible :
560           nom non utilise
561           Si le nom est deja utilise, leve une exception
562           Met le concept créé dans le concept global g_context
563       """
564       # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
565       # Le dictionnaire g_context ne représente pas le contexte
566       # effectif avant une étape.
567       # Il faut utiliser get_contexte_avant avec indication de l'étape
568       # traitée.
569       # Cette etape est indiquee par l'attribut _etape_context qui a ete
570       # positionné préalablement par un appel à set_etape_context
571
572       if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
573
574       if self._etape_context:
575          o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
576       else:
577          o=self.sds_dict.get(sdnom,None)
578
579       if isinstance(o,ASSD):
580          raise AsException("Nom de concept deja defini : %s" % sdnom)
581
582       # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
583       # Ajoute a la creation (appel de reg_sd).
584       self.sds_dict[sdnom]=sd
585       sd.nom=sdnom
586
587       # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
588       if restrict == 'non':
589          self.g_context[sdnom]=sd
590
591 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
592    def delete_concept_after_etape(self,etape,sd):
593       """
594           Met à jour les étapes du JDC qui sont après etape en fonction
595           de la disparition du concept sd
596       """
597       index = self.etapes.index(etape)+1
598       if index == len(self.etapes) :
599          return # etape est la dernière étape du jdc ...on ne fait rien !
600       for child in self.etapes[index:]:
601         child.delete_concept(sd)
602
603 #ATTENTION SURCHARGE : les methodes ci-dessous surchargent des methodes de Noyau et Validation : a reintegrer
604