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.
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.
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.
20 # ======================================================================
24 import types,traceback
25 import string,linecache
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
35 class JDC(I_OBJECT.OBJECT):
40 self.etapes_niveaux=[]
44 self._etape_context=None
45 self.recorded_units={}
46 self.old_recorded_units={}
48 def get_index(self,objet):
50 Retourne la position d'objet dans la liste self
52 return self.etapes.index(objet)
54 def get_sd_avant_du_bon_type(self,etape,types_permis):
56 Retourne la liste des concepts avant etape d'un type acceptable
58 d=self.get_contexte_avant(etape)
61 if type(v) != types.InstanceType : continue
62 # On considère que seul assd indique un type quelconque pas CO
63 elif self.assd in types_permis :
65 elif self.est_permis(v,types_permis):
70 def est_permis(self,v,types_permis):
71 for type_ok in types_permis:
72 if type_ok in ('R','I','C','TXM') and v in self.params :
74 elif type_ok == 'R' and v.__class__.__name__ == 'reel' :
76 elif type_ok == 'I' and v.__class__.__name__ == 'entier' :
78 elif type_ok == 'C' and v.__class__.__name__ == 'complexe' :
80 elif type_ok == 'TXM' and v.__class__.__name__ == 'chaine' :
82 elif type(type_ok) != types.ClassType :
84 elif v.__class__ == type_ok or issubclass(v.__class__,type_ok):
88 def addentite(self,name,pos):
91 Si name est le nom d une commande ou un commentaire ajoute
93 Sinon remonte une erreur
97 if name == "COMMENTAIRE" :
98 # ajout d'un commentaire
99 self.set_current_step()
101 for child in self.etapes :
102 if isinstance(child,commentaire.COMMENTAIRE):
104 objet = commentaire.COMMENTAIRE('',parent=self)
105 objet.nom = "_comm_"+`ind`
106 if pos == None : pos = 0
107 self.etapes.insert(pos,objet)
110 CONNECTOR.Emit(self,"add",objet)
113 elif name == "PARAMETRE":
114 # ajout d'un parametre
115 self.set_current_step()
116 nom_param = '_param_'+str(len(self.params)+1)
117 objet = parametre.PARAMETRE(nom=nom_param)
118 if pos == None : pos = 0
119 self.etapes.insert(pos,objet)
123 CONNECTOR.Emit(self,"add",objet)
126 elif name == "PARAMETRE_EVAL":
127 # ajout d'un parametre EVAL
128 self.set_current_step()
129 nom_param = '_param_'+str(len(self.params)+1)
130 objet = parametre_eval.PARAMETRE_EVAL(nom=nom_param)
131 if pos == None : pos = 0
132 self.etapes.insert(pos,objet)
136 CONNECTOR.Emit(self,"add",objet)
139 elif type(name)==types.InstanceType:
140 # on est dans le cas où on veut ajouter une commande déjà
141 # existante (par copie donc)
142 # on est donc nécessairement en mode editeur ...
144 # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
145 #if hasattr(objet,'sd'):print "addentite",objet.sd
147 #if hasattr(objet,'sd'):print "addentite",objet.sd
148 self.set_current_step()
149 if isinstance(objet,ETAPE):
150 if objet.nom_niveau_definition == 'JDC':
151 # l'objet dépend directement du JDC
154 # l'étape dépend d'un niveau et non directement du JDC :
155 # il faut l'enregistrer dans le niveau de parent
156 objet.parent.dict_niveaux[objet.nom_niveau_definition].register(objet)
157 objet.niveau = objet.parent.dict_niveaux[objet.nom_niveau_definition]
158 self.etapes.insert(pos,objet)
159 # il faut vérifier que les concepts utilisés par objet existent bien
160 # à ce niveau d'arborescence
161 #if hasattr(objet,'sd'):print "addentite",objet.sd
162 objet.verif_existence_sd()
166 #print "addentite",self.etapes
167 CONNECTOR.Emit(self,"add",objet)
171 # On veut ajouter une nouvelle commande
173 self.set_current_step()
174 cmd=self.get_cmd(name)
175 # L'appel a make_objet n'a pas pour effet d'enregistrer l'étape
176 # auprès du step courant car editmode vaut 1
177 # Par contre elle a le bon parent grace a set_current_step
179 if pos == None : pos = 0
180 self.etapes.insert(pos,e)
181 self.reset_current_step()
185 #print "addentite",self.etapes
186 CONNECTOR.Emit(self,"add",e)
189 except AsException,e:
190 self.reset_current_step()
192 raise AsException("Impossible d ajouter la commande "+name + '\n' +str(e))
194 traceback.print_exc()
195 self.reset_current_step()
197 raise AsException("Impossible d ajouter la commande "+name)
199 def set_current_step(self):
200 CONTEXT.unset_current_step()
201 CONTEXT.set_current_step(self)
203 def reset_current_step(self):
204 CONTEXT.unset_current_step()
206 def liste_mc_presents(self):
209 def get_sd_avant_etape(self,nom_sd,etape):
210 return self.get_contexte_avant(etape).get(nom_sd,None)
212 def get_sd_apres_etape_avec_detruire(self,nom_sd,sd,etape,avec='non'):
214 Cette méthode retourne la SD sd de nom nom_sd qui est éventuellement
215 définie apres etape en tenant compte des concepts detruits
216 Si avec vaut 'non' exclut etape de la recherche
218 ietap=self.etapes.index(etape)
219 if avec == 'non':ietap=ietap+1
221 for e in self.etapes[ietap:]:
224 autre_sd=d.get(nom_sd,None)
226 # Le concept a ete detruit
228 if autre_sd is not sd :
229 # L'etape produit un concept de meme nom
230 if hasattr(e,'reuse') and e.reuse == autre_sd:
231 # Le concept etant reutilise, on interrompt la recherche.
232 # On considere qu'il n'y a pas de nouveau concept defini
233 # meme si dans les etapes suivantes le concept est detruit
234 # et un concept de meme nom créé.
237 # Le concept est produit par l'etape
239 # On n'a rien trouve. Pas de concept de nom nom_sd
242 def get_sd_apres_etape(self,nom_sd,etape,avec='non'):
244 Cette méthode retourne la SD de nom nom_sd qui est éventuellement
246 Si avec vaut 'non' exclut etape de la recherche
248 ietap=self.etapes.index(etape)
249 if avec == 'non':ietap=ietap+1
250 for e in self.etapes[ietap:]:
251 sd=e.get_sdprods(nom_sd)
253 if hasattr(e,'reuse'):
258 def get_sd_autour_etape(self,nom_sd,etape,avec='non'):
260 Fonction: retourne la SD de nom nom_sd qui est éventuellement
261 définie avant ou apres etape
262 Permet de vérifier si un concept de meme nom existe dans le périmètre
264 Si avec vaut 'non' exclut etape de la recherche
266 sd=self.get_sd_avant_etape(nom_sd,etape)
268 return self.get_sd_apres_etape(nom_sd,etape,avec)
270 def get_contexte_apres(self,etape):
272 Retourne le dictionnaire des concepts connus apres etape
273 On tient compte des commandes qui modifient le contexte
274 comme DETRUIRE ou les macros
275 Si etape == None, on retourne le contexte en fin de JDC
277 if not etape: return self.get_contexte_avant(etape)
279 d=self.get_contexte_avant(etape)
280 if etape.isactif():etape.update_context(d)
281 self.index_etape_courante=self.index_etape_courante+1
284 def active_etapes(self):
286 Cette méthode a pour fonction de désactiver les étapes qui doivent
287 l'être cad, dans le cas d'ASTER, les étapes qui ne sont pas
288 comprises entre le premier DEBUT/POURSUITE et le premier FIN
289 et rendre actives les autres
291 if self.definition.code == 'ASTER' :
292 # Seulement pour ASTER :
293 # Avant DEBUT actif vaut 0
294 # Apres DEBUT et avant le 1er FIN actif vaut 1
295 # Apres le 1er FIN actif vaut -1
299 for etape in self.etapes:
300 if actif == 0 and etape.nom in ['DEBUT','POURSUITE']:actif=1
305 if etape.nom == 'FIN':actif=-1
307 def suppentite(self,etape) :
309 Cette methode a pour fonction de supprimer une étape dans
311 Retourne 1 si la suppression a pu être effectuée,
312 Retourne 0 dans le cas contraire
314 #print "suppentite",self
316 # On memorise le contexte avant l'etape a supprimer
317 d=self.get_contexte_avant(etape)
318 index_etape=self.etapes.index(etape)
319 #print "suppentite",index_etape,d
321 self.etapes.remove(etape)
322 if etape.niveau is not self:
323 # Dans ce cas l'étape est enregistrée dans un niveau
324 # Il faut la désenregistrer
325 etape.niveau.unregister(etape)
326 etape.supprime_sdprods()
329 # Apres suppression de l'etape il faut controler que les etapes
330 # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape
331 for e in self.etapes[index_etape:]:
335 CONNECTOR.Emit(self,"supp",etape)
341 if not self.cr.estvide():return
345 def register_parametre(self,param):
347 Cette méthode sert à ajouter un paramètre dans la liste des paramètres
349 self.params.append(param)
351 def register_fonction(self,fonction):
353 Cette méthode sert à ajouter une fonction dans la liste des fonctions
355 self.fonctions.append(fonction)
357 def delete_param(self,param):
359 Supprime le paramètre param de la liste des paramètres
362 if param in self.params : self.params.remove(param)
363 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
365 def get_parametres_fonctions_avant_etape(self,etape):
367 Retourne deux éléments :
368 - une liste contenant les noms des paramètres (constantes ou EVAL)
370 - une liste contenant les formules définies avant etape
374 # on récupère le contexte avant etape
375 # on ne peut mettre dans les deux listes que des éléments de ce contexte
376 d=self.get_contexte_avant(etape)
377 # construction de l_constantes
378 for param in self.params:
380 if not nom : continue
381 if d.has_key(nom): l_constantes.append(nom)
382 # construction de l_fonctions
383 for form in self.fonctions:
385 if not nom : continue
386 if d.has_key(nom): l_fonctions.append(form.get_formule())
388 # on ajoute les concepts produits par DEFI_VALEUR
389 # XXX On pourrait peut etre faire plutot le test sur le type
390 # de concept : entier, reel, complexe, etc.
391 for k,v in d.items():
392 if hasattr(v,'etape') and v.etape.nom in ('DEFI_VALEUR',):
393 l_constantes.append(k)
395 # on retourne les deux listes
396 return l_constantes,l_fonctions
398 def get_nb_etapes_avant(self,niveau):
400 Retourne le nombre d etapes avant le debut de niveau
403 for niv in self.etapes_niveaux:
404 if niv == niveau:break
405 nb=nb+len(niv.etapes)
408 def send_message(self,message):
410 self.appli.send_message(message)
412 def init_modif(self):
414 Méthode appelée au moment où une modification va être faite afin de
415 déclencher d'éventuels traitements pré-modification
417 #print "init_modif",self
418 self.state = 'modified'
421 #print "fin_modif",self
422 CONNECTOR.Emit(self,"valid")
426 def deep_update_condition_bloc(self):
427 # pour le moment, on ne fait rien
428 raise "Not implemented"
430 def update_condition_bloc(self):
431 # pour le moment, on ne fait rien
432 raise "Not implemented"
434 def get_liste_mc_inconnus(self):
436 Retourne une liste contenant les mots-clés inconnus à la relecture du JDC
438 # cette liste a le format suivant : [etape,(bloc,mcfact,...),nom_mc,valeur_mc]
440 for etape in self.etapes :
442 if not etape.isvalid() :
443 l = etape.get_liste_mc_inconnus()
444 if l : l_mc.extend(l)
447 def get_genealogie(self):
449 Retourne la liste des noms des ascendants de l'objet self
450 jusqu'à la première ETAPE parent.
454 def get_liste_cmd(self):
456 Retourne la liste des commandes du catalogue
458 return self.niveau.definition.get_liste_cmd()
460 def get_groups(self):
462 Retourne la liste des groupes
464 return self.niveau.definition.liste_groupes,self.niveau.definition.dict_groupes
466 def set_etape_context(self,etape):
468 Positionne l'etape qui sera utilisee dans NommerSdProd pour
469 decider si le concept passé pourra etre nommé
471 self._etape_context=etape
473 def reset_context(self):
475 Cette methode reinitialise le contexte glissant pour pouvoir
476 tenir compte des modifications de l'utilisateur : création
477 de commandes, nommage de concepts, etc.
479 self.current_context={}
480 self.index_etape_courante=0
482 def del_sdprod(self,sd):
484 Supprime la SD sd de la liste des sd et des dictionnaires de contexte
486 #print "del_sdprod",self,sd
487 #print "del_sdprod",self.sds
488 #print "del_sdprod",self.g_context
489 #print "del_sdprod",self.sds_dict
490 if sd in self.sds : self.sds.remove(sd)
491 if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
492 if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
494 def del_param(self,param):
496 Supprime le paramètre param de la liste des paramètres
499 if param in self.params : self.params.remove(param)
500 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
502 def del_fonction(self,fonction):
504 Supprime la fonction fonction de la liste des fonctions
507 if fonction in self.fonctions : self.fonctions.remove(fonction)
508 if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
510 def append_sdprod(self,sd):
512 Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
513 même nom n'existe pas déjà
515 if sd == None or sd.nom == None:return
517 o=self.sds_dict.get(sd.nom,None)
518 if isinstance(o,ASSD):
519 raise AsException("Nom de concept deja defini : %s" % sd.nom)
520 self.sds_dict[sd.nom]=sd
521 self.g_context[sd.nom] = sd
522 if sd not in self.sds : self.sds.append(sd)
524 def append_param(self,param):
526 Ajoute le paramètre param à la liste des params
527 et au contexte global
529 # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
530 if param not in self.params : self.params.append(param)
531 self.g_context[param.nom]=param
533 def append_fonction(self,fonction):
535 Ajoute la fonction fonction à la liste des fonctions
536 et au contexte global
538 # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
539 if fonction not in self.fonctions : self.fonctions.append(fonction)
540 self.g_context[fonction.nom]=fonction
542 def delete_concept(self,sd):
547 Mettre a jour les etapes du JDC suite à la disparition du
549 Seuls les mots cles simples MCSIMP font un traitement autre
550 que de transmettre aux fils
552 #print "delete_concept",self,sd
553 for etape in self.etapes :
554 etape.delete_concept(sd)
556 def replace_concept_after_etape(self,etape,old_sd,sd):
558 Met à jour les étapes du JDC qui sont après etape en fonction
559 du remplacement du concept sd
561 index = self.etapes.index(etape)+1
562 if index == len(self.etapes) :
563 return # etape est la dernière étape du jdc ...on ne fait rien !
564 for child in self.etapes[index:]:
565 child.replace_concept(old_sd,sd)
567 def dump_state(self):
569 print "JDC.state: ",self.state
570 for etape in self.etapes :
571 print etape.nom+".state: ",etape.state
573 def change_unit(self,unit,etape,old_unit):
574 #print "change_unit",unit,etape,old_unit
575 #print id(self.recorded_units),self.recorded_units
576 #if self.recorded_units.has_key(old_unit):del self.recorded_units[old_unit]
577 self.record_unit(unit,etape)
579 def record_unit(self,unit,etape):
580 """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
581 #print "record_unit",unit,etape
584 self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
586 self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
587 #print id(self.recorded_units),self.recorded_units
588 #print self.recorded_units.get(None,(None,"",{}))[2]
589 #print self.recorded_units.get(None,(None,"",{}))[2].get(None,(None,"",{}))
591 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
592 def register(self,etape):
594 Cette méthode ajoute etape dans la liste
595 des etapes self.etapes et retourne l identificateur d'étape
596 fourni par l appel a g_register
598 A quoi sert editmode ?
599 - Si editmode vaut 1, on est en mode edition de JDC. On cherche
600 à enregistrer une étape que l'on a créée avec eficas (en passant
601 par addentite) auquel cas on ne veut récupérer que son numéro
602 d'enregistrement et c'est addentité qui l'enregistre dans
603 self.etapes à la bonne place...
604 - Si editmode vaut 0, on est en mode relecture d'un fichier de
605 commandes et on doit enregistrer l'étape à la fin de self.etapes
606 (dans ce cas l'ordre des étapes est bien l'ordre chronologique
609 if not self.editmode:
610 self.etapes.append(etape)
613 return self.g_register(etape)
615 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
616 def NommerSdprod(self,sd,sdnom,restrict='non'):
618 Nomme la SD apres avoir verifie que le nommage est possible :
620 Si le nom est deja utilise, leve une exception
621 Met le concept créé dans le concept global g_context
623 # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
624 # Le dictionnaire g_context ne représente pas le contexte
625 # effectif avant une étape.
626 # Il faut utiliser get_contexte_avant avec indication de l'étape
628 # Cette etape est indiquee par l'attribut _etape_context qui a ete
629 # positionné préalablement par un appel à set_etape_context
631 if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
633 if self._etape_context:
634 o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
636 o=self.sds_dict.get(sdnom,None)
638 if isinstance(o,ASSD):
639 raise AsException("Nom de concept deja defini : %s" % sdnom)
641 # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
642 # Ajoute a la creation (appel de reg_sd).
643 self.sds_dict[sdnom]=sd
646 # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
647 if restrict == 'non':
648 self.g_context[sdnom]=sd
650 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
651 def delete_concept_after_etape(self,etape,sd):
653 Met à jour les étapes du JDC qui sont après etape en fonction
654 de la disparition du concept sd
656 index = self.etapes.index(etape)+1
657 if index == len(self.etapes) :
658 return # etape est la dernière étape du jdc ...on ne fait rien !
659 for child in self.etapes[index:]:
660 child.delete_concept(sd)
662 #ATTENTION SURCHARGE : les methodes ci-dessous surchargent des methodes de Noyau et Validation : a reintegrer