Salome HOME
Version initiale de EFICAS 1.2
[tools/eficas.git] / Noyau / N_MCCOMPO.py
1 """ 
2     Ce module contient la classe MCCOMPO qui sert à factoriser les comportements 
3     des OBJECT composites
4 """
5
6 import types
7
8 import N_OBJECT
9
10 class MCCOMPO(N_OBJECT.OBJECT):
11    """
12       Classe support d'un OBJECT composite
13   
14    """
15
16    def build_mc(self):
17       """ 
18           Construit la liste des sous-entites du MCCOMPO
19           à partir du dictionnaire des arguments (valeur)
20       """
21       if CONTEXT.debug : print "MCCOMPO.build_mc ",self.nom
22       # Dans la phase de reconstruction args peut contenir des mots-clés
23       # qui ne sont pas dans le dictionnaire des entites de definition (self.definition.entites)
24       # de l'objet courant (self)
25       #  mais qui sont malgré tout des descendants de l'objet courant (petits-fils, ...)
26       args = self.valeur
27       if args == None : args ={}
28       mc_liste=[]
29
30       # On recopie le dictionnaire des arguments pour protéger l'original des delete (del args[k])
31       args = args.copy()
32
33       # Phase 1:
34       # On construit les sous entites presentes ou obligatoires
35       # 1- les entites présentes dans les arguments et dans la définition
36       # 2- les entités non présentes dans les arguments, présentes dans la définition avec un défaut
37       for k,v in self.definition.entites.items():
38         if args.has_key(k) or v.statut=='o' :
39           #
40           # Creation par appel de la methode __call__ de la definition de la sous entite k de self
41           # si une valeur existe dans args ou est obligatoire (generique si toutes les
42           # entites ont l attribut statut )
43           #
44           objet=self.definition.entites[k](val=args.get(k,None),nom=k,parent=self)
45           mc_liste.append(objet)
46           # Si l'objet a une position globale on l'ajoute aux listes correspondantes
47           if hasattr(objet.definition,'position'):
48             if objet.definition.position == 'global' :
49               self.append_mc_global(objet)
50             elif objet.definition.position == 'global_jdc' :
51               self.append_mc_global_jdc(objet)
52         if args.has_key(k):
53            del args[k]
54
55       # Phase 2:
56       # On construit les objets (en général, blocs) conditionnés par les mots-clés précédemment créés.
57       # A ce stade, mc_liste ne contient que les fils de l'objet courant
58       # args ne contient plus que des mots-clés qui n'ont pas été attribués car ils sont
59       #      à attribuer à des blocs du niveau inférieur ou bien sont des mots-clés erronés
60       dico_valeurs = self.cree_dict_valeurs(mc_liste)
61       for k,v in self.definition.entites.items():
62          if v.label != 'BLOC':continue
63          if v.verif_presence(dico_valeurs):
64             # Si le bloc existe :
65             #        1- on le construit
66             #        2- on l'ajoute à mc_liste
67             #        3- on récupère les arguments restant
68             #        4- on reconstruit le dictionnaire équivalent à mc_liste
69             bloc = v(nom=k,val=args,parent=self)
70             mc_liste.append(bloc)
71             args=bloc.reste_val
72             dico_valeurs = self.cree_dict_valeurs(mc_liste)
73
74       # On conserve les arguments superflus dans l'attribut reste_val
75       self.reste_val=args
76       # On ordonne la liste ainsi créée suivant l'ordre du catalogue 
77       # (utile seulement pour IHM graphique)
78       mc_liste = self.ordonne_liste(mc_liste)
79       # on retourne la liste ainsi construite
80       return mc_liste
81
82    def ordonne_liste(self,mc_liste):
83       """
84          Ordonne la liste suivant l'ordre du catalogue.
85          Seulement pour IHM graphique
86       """
87       if self.jdc and self.jdc.cata_ordonne_dico != None :
88          liste_noms_mc_ordonnee = self.get_liste_mc_ordonnee_brute(
89                        self.get_genealogie(),self.jdc.cata_ordonne_dico)
90          return self.ordonne_liste_mc(mc_liste,liste_noms_mc_ordonnee)
91       else:
92          return mc_liste
93
94    def cree_dict_valeurs(self,liste=[]):
95       """ 
96         Cette méthode crée le contexte de l'objet courant sous la forme 
97         d'un dictionnaire.
98         L'opération consiste à transformer une liste d'OBJECT en un 
99         dictionnaire.
100         Ce dictionnaire servira de contexte pour évaluer les conditions des 
101         blocs fils.
102
103         Cette méthode réalise les opérations suivantes en plus de transformer 
104         la liste en dictionnaire :
105
106         - ajouter tous les mots-clés non présents avec la valeur None
107
108         - ajouter tous les mots-clés globaux (attribut position = 'global' 
109           et 'global_jdc')
110
111         ATTENTION : -- on ne remonte pas (semble en contradiction avec la 
112                       programmation de la méthode get_valeur du bloc) les 
113                       mots-clé fils d'un bloc au niveau du
114                       contexte car celà peut générer des erreurs.
115
116         L'argument liste est, en général, une mc_liste en cours de 
117         construction, contenant les mots-clés locaux et les blocs déjà créés.
118
119       """
120       dico={}
121       for v in liste:
122         k=v.nom
123         val = v.get_valeur()
124         # Si val est un dictionnaire, on inclut ses items dans le dictionnaire
125         # représentatif du contexte. Les blocs sont retournés par get_valeur
126         # sous la forme d'un dictionnaire : les mots-clés fils de blocs sont
127         # donc remontés au niveau du contexte.
128         if type(val)==types.DictionaryType:
129           for i,w in val.items():
130             dico[i]=w
131         else:
132           dico[k]=val
133       # on rajoute tous les autres mots-clés locaux possibles avec la valeur 
134       # par défaut ou None
135       # Pour les mots-clés facteurs, on ne tient pas compte du défaut 
136       # (toujours None)
137       for k,v in self.definition.entites.items():
138         if not dico.has_key(k):
139            if v.label == 'SIMP':
140               dico[k]=v.defaut
141               # S il est declare global il n est pas necessaire de l ajouter
142               # aux mots cles globaux de l'etape
143               # car la methode recherche_mc_globaux les rajoutera
144            elif v.label == 'FACT' and v.statut in ('c','d') :
145               dico[k]=v(val=None,nom=k,parent=self)
146               # On demande la suppression des pointeurs arrieres
147               # pour briser les eventuels cycles
148               dico[k].supprime()
149            elif v.label != 'BLOC':
150               dico[k]=None
151       # A ce stade on a rajouté tous les mots-clés locaux possibles (fils directs) avec leur
152       # valeur par défaut ou la valeur None
153       # on rajoute les mots-clés globaux ...
154       dico_mc = self.recherche_mc_globaux()
155       for nom,mc in dico_mc.items() :
156         if not dico.has_key(nom) : dico[nom]=mc.valeur
157       # Il nous reste à évaluer la présence des blocs en fonction du contexte qui a changé
158       for k,v in self.definition.entites.items():
159         if v.label != 'BLOC' : continue
160         if v.verif_presence(dico):
161           # le bloc k doit être présent : on crée temporairement l'objet MCBLOC correspondant
162           # on lui passe un parent égal à None pour qu'il ne soit pas enregistré
163           bloc = v(nom=k,val=None,parent=None)
164           dico_bloc = bloc.cree_dict_valeurs()
165           bloc.supprime()
166           # on va updater dico avec dico_bloc en veillant à ne pas écraser
167           # des valeurs déjà présentes
168           for cle in dico_bloc.keys():
169             if not dico.has_key(cle):
170               dico[cle]=dico_bloc[cle]
171       return dico
172
173    def recherche_mc_globaux(self):
174       """ 
175           Retourne la liste des mots-clés globaux de l'étape à laquelle appartient self
176           et des mots-clés globaux du jdc
177       """
178       etape = self.get_etape()
179       if etape :
180         dict_mc_globaux_fac = self.recherche_mc_globaux_facultatifs()
181         dict_mc_globaux_fac.update(etape.mc_globaux)
182         if self.jdc : dict_mc_globaux_fac.update(self.jdc.mc_globaux)
183         return dict_mc_globaux_fac
184       else :
185         return {}
186
187    def recherche_mc_globaux_facultatifs(self):
188       """ 
189           Cette méthode interroge la définition de self et retourne la liste des mots-clés fils
190           directs de self de type 'global'
191       """
192       dico={}
193       etape = self.get_etape()
194       if not etape : return {}
195       for k,v in etape.definition.entites.items():
196          if v.label != 'SIMP' : continue
197          if v.position != 'global' : continue
198          if v.statut == 'o':continue
199          obj = v(val=None,nom=k,parent=etape)
200          dico[k]=obj
201       return dico
202
203    def supprime(self):
204       """ 
205          Méthode qui supprime toutes les références arrières afin que l'objet puisse
206          être correctement détruit par le garbage collector
207       """
208       N_OBJECT.OBJECT.supprime(self)
209       for child in self.mc_liste :
210          child.supprime()
211
212    def __getitem__(self,key):
213       """
214          Cette méthode retourne la valeur d'un sous mot-clé (key)
215       """
216       return self.get_mocle(key)
217
218    def get_mocle(self,key):
219       """
220           Retourne la valeur du sous mot-clé key 
221           Ce sous mot-clé peut exister, avoir une valeur par defaut ou etre 
222           dans un BLOC fils de self
223       """
224       # on cherche dans les mots cles presents, le mot cle de nom key
225       # s'il est là on retourne sa valeur (méthode get_val)
226       for child in self.mc_liste:
227         if child.nom == key : return child.get_val()
228       #  Si on n a pas trouve de mot cle present on retourne le defaut
229       #  eventuel pour les mots cles accessibles dans la definition
230       #  a ce niveau
231       try:
232         d=self.definition.entites[key]
233         if d.label == 'SIMP':
234           return d.defaut
235         elif d.label == 'FACT':
236           # il faut construire les objets necessaires pour
237           # evaluer les conditions des blocs eventuels (a faire)
238           if d.statut == 'o' :return None
239           if d.statut != 'c' and d.statut != 'd' :
240              return None
241           else :
242              return d(val=None,nom=key,parent=self)
243       except KeyError:
244         # le mot cle n est pas defini a ce niveau
245         pass
246       #  Si on a toujours rien trouve, on cherche dans les blocs presents
247       #  On suppose que tous les blocs possibles ont ete crees meme ceux
248       #  induits par un mot cle simple absent avec defaut (???)
249       for mc in self.mc_liste :
250         if not mc.isBLOC() : continue
251         try:
252           return mc.get_mocle(key)
253         except: 
254           # On n a rien trouve dans ce bloc, on passe au suivant
255           pass
256       #  On a rien trouve, le mot cle est absent.
257       #  On leve une exception
258       raise IndexError,"Le mot cle %s n existe pas dans %s" % (key,self)
259
260    def get_child(self,name,restreint = 'non'):
261       """ 
262           Retourne le fils de self de nom name ou None s'il n'existe pas
263           Si restreint vaut oui : ne regarde que dans la mc_liste
264           Si restreint vaut non : regarde aussi dans les entites possibles 
265           avec defaut    
266            (Ce dernier cas n'est utilisé que dans le catalogue)
267       """
268       for v in self.mc_liste:
269         if v.nom == name : return v
270       if restreint == 'non' :
271         for k,v in self.definition.entites.items():
272           if k == name:
273             if v.valeur != None : return v(None,k,None)
274       return None
275
276    def append_mc_global(self,mc):
277       """
278          Ajoute le mot-clé mc à la liste des mots-clés globaux de l'étape
279       """
280       etape = self.get_etape()
281       if etape :
282         nom = mc.nom
283         etape.mc_globaux[nom]=mc
284
285    def append_mc_global_jdc(self,mc):
286       """ 
287           Ajoute le mot-clé mc à la liste des mots-clés globaux du jdc 
288       """
289       nom = mc.nom
290       self.jdc.mc_globaux[nom]=mc
291
292
293