Salome HOME
2205ae343a94a3299afdc3ff4d6e6dfb9fb76d73
[tools/eficas.git] / Noyau / N_MCCOMPO.py
1 #@ MODIF N_MCCOMPO Noyau  DATE 16/05/2007   AUTEUR COURTOIS M.COURTOIS 
2 # -*- coding: iso-8859-1 -*-
3 #            CONFIGURATION MANAGEMENT OF EDF VERSION
4 # ======================================================================
5 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
6 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
7 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
8 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR   
9 # (AT YOUR OPTION) ANY LATER VERSION.                                 
10 #
11 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT 
12 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF          
13 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU    
14 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.                            
15 #
16 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE   
17 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,       
18 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.      
19 #                                                                       
20 #                                                                       
21 # ======================================================================
22
23
24 """ 
25     Ce module contient la classe MCCOMPO qui sert à factoriser les comportements 
26     des OBJECT composites
27 """
28
29 from copy import copy
30 import N_OBJECT
31
32 class MCCOMPO(N_OBJECT.OBJECT):
33    """
34       Classe support d'un OBJECT composite
35   
36    """
37
38    def build_mc(self):
39       """ 
40           Construit la liste des sous-entites du MCCOMPO
41           à partir du dictionnaire des arguments (valeur)
42       """
43       if CONTEXT.debug : print "MCCOMPO.build_mc ",self.nom
44       # Dans la phase de reconstruction args peut contenir des mots-clés
45       # qui ne sont pas dans le dictionnaire des entites de definition (self.definition.entites)
46       # de l'objet courant (self)
47       #  mais qui sont malgré tout des descendants de l'objet courant (petits-fils, ...)
48       args = self.valeur
49       if args == None : args ={}
50       mc_liste=[]
51
52       # On recopie le dictionnaire des arguments pour protéger l'original des delete (del args[k])
53       args = args.copy()
54
55       # Phase 1:
56       # On construit les sous entites presentes ou obligatoires
57       # 1- les entites présentes dans les arguments et dans la définition
58       # 2- les entités non présentes dans les arguments, présentes dans la définition avec un défaut
59       # Phase 1.1 : on traite d'abord les SIMP pour enregistrer les mots cles globaux
60       for k,v in self.definition.entites.items():
61         if v.label != 'SIMP':continue
62         if args.has_key(k) or v.statut=='o' :
63           #
64           # Creation par appel de la methode __call__ de la definition de la sous entite k de self
65           # si une valeur existe dans args ou est obligatoire (generique si toutes les
66           # entites ont l attribut statut )
67           #
68           objet=self.definition.entites[k](val=args.get(k,None),nom=k,parent=self)
69           mc_liste.append(objet)
70           # Si l'objet a une position globale on l'ajoute aux listes correspondantes
71           if hasattr(objet.definition,'position'):
72             if objet.definition.position == 'global' :
73               self.append_mc_global(objet)
74             elif objet.definition.position == 'global_jdc' :
75               self.append_mc_global_jdc(objet)
76         if args.has_key(k):
77            del args[k]
78
79       # Phase 1.2 : on traite les autres entites que SIMP 
80       for k,v in self.definition.entites.items():
81         if v.label == 'SIMP':continue
82         if args.has_key(k) or v.statut=='o' :
83           #
84           # Creation par appel de la methode __call__ de la definition de la sous entite k de self
85           # si une valeur existe dans args ou est obligatoire (generique si toutes les
86           # entites ont l attribut statut )
87           #
88           objet=self.definition.entites[k](val=args.get(k,None),nom=k,parent=self)
89           mc_liste.append(objet)
90         if args.has_key(k):
91            del args[k]
92
93       # Phase 2:
94       # On construit les objets (en général, blocs) conditionnés par les mots-clés précédemment créés.
95       # A ce stade, mc_liste ne contient que les fils de l'objet courant
96       # args ne contient plus que des mots-clés qui n'ont pas été attribués car ils sont
97       #      à attribuer à des blocs du niveau inférieur ou bien sont des mots-clés erronés
98       dico_valeurs = self.cree_dict_condition(mc_liste,condition=1)
99       for k,v in self.definition.entites.items():
100          if v.label != 'BLOC':continue
101          # condition and a or b  : Equivalent de l'expression :  condition ? a : b du langage C
102          globs= self.jdc and self.jdc.condition_context or {}
103          if v.verif_presence(dico_valeurs,globs):
104             # Si le bloc existe :
105             #        1- on le construit
106             #        2- on l'ajoute à mc_liste
107             #        3- on récupère les arguments restant
108             #        4- on reconstruit le dictionnaire équivalent à mc_liste
109             bloc = v(nom=k,val=args,parent=self)
110             mc_liste.append(bloc)
111             args=bloc.reste_val
112             # On ne recalcule pas le contexte car on ne tient pas compte des blocs
113             # pour évaluer les conditions de présence des blocs
114             #dico_valeurs = self.cree_dict_valeurs(mc_liste)
115
116       # On conserve les arguments superflus dans l'attribut reste_val
117       self.reste_val=args
118       # On ordonne la liste ainsi créée suivant l'ordre du catalogue 
119       # (utile seulement pour IHM graphique)
120       mc_liste = self.ordonne_liste(mc_liste)
121       # on retourne la liste ainsi construite
122       return mc_liste
123
124    def ordonne_liste(self,mc_liste):
125       """
126          Ordonne la liste suivant l'ordre du catalogue.
127          Seulement pour IHM graphique
128       """
129       if self.jdc and self.jdc.cata_ordonne_dico != None :
130          liste_noms_mc_ordonnee = self.get_liste_mc_ordonnee_brute(
131                        self.get_genealogie(),self.jdc.cata_ordonne_dico)
132          return self.ordonne_liste_mc(mc_liste,liste_noms_mc_ordonnee)
133       else:
134          return mc_liste
135
136    def cree_dict_valeurs(self,liste=[],condition=0):
137       """ 
138         Cette méthode crée un contexte (sous la forme d'un dictionnaire)
139         à partir des valeurs des mots clés contenus dans l'argument liste.
140         L'opération consiste à parcourir la liste (d'OBJECT) et à la 
141         transformer en un dictionnaire dont les clés sont les noms des
142         mots clés et les valeurs dépendent du type d'OBJECT.
143         Ce dictionnaire servira de liste d'arguments d'appel pour les
144         fonctions sd_prod de commandes et ops de macros ou de contexte
145         d'évaluation des conditions de présence de BLOC.
146
147         Si l'argument condition de la méthode vaut 1, on ne 
148         remonte pas les valeurs des mots clés contenus dans des blocs
149         pour eviter les bouclages.
150
151         Cette méthode réalise les opérations suivantes en plus de transformer 
152         la liste en dictionnaire :
153
154            - ajouter tous les mots-clés non présents avec la valeur None
155            - ajouter tous les mots-clés globaux (attribut position = 'global' 
156              et 'global_jdc')
157
158         L'argument liste est, en général, une mc_liste en cours de 
159         construction, contenant les mots-clés locaux et les blocs déjà créés.
160
161       """
162       dico={}
163       for v in liste:
164         if v.isBLOC():
165            # Si v est un BLOC, on inclut ses items dans le dictionnaire
166            # représentatif du contexte. Les blocs sont retournés par get_valeur
167            # sous la forme d'un dictionnaire : les mots-clés fils de blocs sont
168            # donc remontés au niveau du contexte.
169            if not condition:dico.update(v.get_valeur())
170         else:
171            dico[v.nom]=v.get_valeur()
172
173       # On rajoute tous les autres mots-clés locaux possibles avec la valeur 
174       # par défaut ou None
175       # Pour les mots-clés facteurs, on ne traite que ceux avec statut défaut ('d')
176       # et caché ('c')
177       # On n'ajoute aucune information sur les blocs. Ils n'ont pas de défaut seulement
178       # une condition.
179       for k,v in self.definition.entites.items():
180         if not dico.has_key(k):
181            if v.label == 'SIMP':
182               # Mot clé simple
183               dico[k]=v.defaut
184            elif v.label == 'FACT' :
185               if v.statut in ('c','d') :
186                  # Mot clé facteur avec défaut ou caché provisoire
187                  dico[k]=v(val=None,nom=k,parent=self)
188                  # On demande la suppression des pointeurs arrieres
189                  # pour briser les eventuels cycles
190                  dico[k].supprime()
191               else:
192                  dico[k]=None
193       # A ce stade on a rajouté tous les mots-clés locaux possibles (fils directs) avec leur
194       # valeur par défaut ou la valeur None
195
196       # On rajoute les mots-clés globaux sans écraser les clés existantes
197       dico_mc = self.recherche_mc_globaux()
198       dico_mc.update(dico)
199       dico=dico_mc
200
201       return dico
202
203    def cree_dict_condition(self,liste=[],condition=0):
204       """
205           Methode pour construire un contexte qui servira dans l'évaluation
206           des conditions de présence de blocs. Si une commande a un concept
207           produit réutilisé, on ajoute la clé 'reuse'
208       """
209       dico=self.cree_dict_valeurs(liste,condition=1)
210       # On ajoute la cle "reuse" pour les MCCOMPO qui ont un attribut reuse. A destination
211       # uniquement des commandes. Ne devrait pas etre dans cette classe mais dans une classe dérivée
212       if not dico.has_key('reuse') and hasattr(self,'reuse'):
213          dico['reuse']=self.reuse
214       return dico
215
216    def recherche_mc_globaux(self):
217       """ 
218           Retourne la liste des mots-clés globaux de l'étape à laquelle appartient self
219           et des mots-clés globaux du jdc
220       """
221       etape = self.get_etape()
222       if etape :
223         dict_mc_globaux_fac = self.recherche_mc_globaux_facultatifs()
224         for k,v in etape.mc_globaux.items():
225            dict_mc_globaux_fac[k]=v.get_valeur()
226         if self.jdc : 
227            for k,v in self.jdc.mc_globaux.items():
228               dict_mc_globaux_fac[k]=v.get_valeur()
229         return dict_mc_globaux_fac
230       else :
231         return {}
232
233    def recherche_mc_globaux_facultatifs(self):
234       """ 
235           Cette méthode interroge la définition de self et retourne la liste des mots-clés fils
236           directs de self de type 'global'
237       """
238       dico={}
239       etape = self.get_etape()
240       if not etape : return {}
241       for k,v in etape.definition.entites.items():
242          if v.label != 'SIMP' : continue
243          if v.position != 'global' : continue
244          if v.statut == 'o':continue
245          obj = v(val=None,nom=k,parent=etape)
246          dico[k]=obj.get_valeur()
247       return dico
248
249    def supprime(self):
250       """ 
251          Méthode qui supprime toutes les références arrières afin que l'objet puisse
252          etre correctement détruit par le garbage collector
253       """
254       N_OBJECT.OBJECT.supprime(self)
255       for child in self.mc_liste :
256          child.supprime()
257
258    def __getitem__(self,key):
259       """
260          Cette méthode retourne la valeur d'un sous mot-clé (key)
261       """
262       return self.get_mocle(key)
263
264    def get_mocle(self,key):
265       """
266           Retourne la valeur du sous mot-clé key 
267           Ce sous mot-clé peut exister, avoir une valeur par defaut ou etre 
268           dans un BLOC fils de self
269       """
270       # on cherche dans les mots cles presents, le mot cle de nom key
271       # s'il est là on retourne sa valeur (méthode get_val)
272       for child in self.mc_liste:
273         if child.nom == key : return child.get_val()
274       #  Si on n a pas trouve de mot cle present on retourne le defaut
275       #  eventuel pour les mots cles accessibles dans la definition
276       #  a ce niveau
277       try:
278         d=self.definition.entites[key]
279         if d.label == 'SIMP':
280           return d.defaut
281         elif d.label == 'FACT':
282           # il faut construire les objets necessaires pour
283           # evaluer les conditions des blocs eventuels (a faire)
284           if d.statut == 'o' :return None
285           if d.statut != 'c' and d.statut != 'd' :
286              return None
287           else :
288              return d(val=None,nom=key,parent=self)
289       except KeyError:
290         # le mot cle n est pas defini a ce niveau
291         pass
292       #  Si on a toujours rien trouve, on cherche dans les blocs presents
293       #  On suppose que tous les blocs possibles ont ete crees meme ceux
294       #  induits par un mot cle simple absent avec defaut (???)
295       for mc in self.mc_liste :
296         if not mc.isBLOC() : continue
297         try:
298           return mc.get_mocle(key)
299         except: 
300           # On n a rien trouve dans ce bloc, on passe au suivant
301           pass
302       #  On a rien trouve, le mot cle est absent.
303       #  On leve une exception
304       raise IndexError,"Le mot cle %s n existe pas dans %s" % (key,self)
305
306    def get_child(self,name,restreint = 'non'):
307       """ 
308           Retourne le fils de self de nom name ou None s'il n'existe pas
309           Si restreint vaut oui : ne regarde que dans la mc_liste
310           Si restreint vaut non : regarde aussi dans les entites possibles 
311           avec defaut (Ce dernier cas n'est utilisé que dans le catalogue)
312       """
313       for v in self.mc_liste:
314         if v.nom == name : return v
315       if restreint == 'non' :
316         try:
317            entite=self.definition.entites[name]
318            if entite.label == 'SIMP' or (entite.label == 'FACT' and entite.statut in ( 'c', 'd')):
319               return entite(None,name,None)
320         except:
321            pass
322
323       return None
324
325    def append_mc_global(self,mc):
326       """
327          Ajoute le mot-clé mc à la liste des mots-clés globaux de l'étape
328       """
329       etape = self.get_etape()
330       if etape :
331         nom = mc.nom
332         etape.mc_globaux[nom]=mc
333
334    def append_mc_global_jdc(self,mc):
335       """ 
336           Ajoute le mot-clé mc à la liste des mots-clés globaux du jdc 
337       """
338       nom = mc.nom
339       self.jdc.mc_globaux[nom]=mc
340
341    def copy(self):
342     """ Retourne une copie de self """
343     objet = self.makeobjet()
344     # FR : attention !!! avec makeobjet, objet a le meme parent que self
345     # ce qui n'est pas du tout bon dans le cas d'une copie !!!!!!!
346     # FR : peut-on passer par là autrement que dans le cas d'une copie ???
347     # FR --> je suppose que non
348     # XXX CCAR : le pb c'est qu'on vérifie ensuite quel parent avait l'objet
349     # Il me semble preferable de changer le parent a la fin quand la copie est acceptee
350     objet.valeur = copy(self.valeur)
351     objet.val = copy(self.val)
352     objet.mc_liste=[]
353     for obj in self.mc_liste:
354       new_obj = obj.copy()
355       new_obj.reparent(objet)
356       objet.mc_liste.append(new_obj)
357     return objet
358
359    def reparent(self,parent):
360      """
361          Cette methode sert a reinitialiser la parente de l'objet
362      """
363      self.parent=parent
364      self.jdc=parent.get_jdc_root()
365      self.etape=parent.etape
366      for mocle in self.mc_liste:
367         mocle.reparent(self)
368
369    def get_sd_utilisees(self):
370     """ 
371         Retourne la liste des concepts qui sont utilisés à l'intérieur de self
372         ( comme valorisation d'un MCS) 
373     """
374     l=[]
375     for child in self.mc_liste:
376       l.extend(child.get_sd_utilisees())
377     return l
378
379    def get_sd_mcs_utilisees(self):
380     """ 
381           Retourne la ou les SD utilisée par self sous forme d'un dictionnaire :
382             - Si aucune sd n'est utilisée, le dictionnaire est vide.
383             - Sinon, les clés du dictionnaire sont les mots-clés derrière lesquels on
384               trouve des sd ; la valeur est la liste des sd attenante.
385               Exemple ::
386               
387                 { 'VALE_F': [ <Cata.cata.para_sensi instance at 0x9419854>,
388                               <Cata.cata.para_sensi instance at 0x941a204> ],
389                   'MODELE': [<Cata.cata.modele instance at 0x941550c>] }
390     """
391     dico = {}
392     for child in self.mc_liste:
393       daux = child.get_sd_mcs_utilisees()
394       for cle in daux.keys():
395         dico[cle] = daux[cle]
396     return dico
397
398    def get_mcs_with_co(self,co):
399       """
400          Cette methode retourne l'objet MCSIMP fils de self 
401          qui a le concept co comme valeur.
402          En principe, elle ne doit etre utilisee que pour les concepts
403          instances de la classe CO
404       """
405       l=[]
406       for child in self.mc_liste:
407         l.extend(child.get_mcs_with_co(co))
408       return l
409
410    def get_all_co(self):
411       """
412          Cette methode retourne tous les concepts instances de CO
413       """
414       l=[]
415       for child in self.mc_liste:
416         l.extend(child.get_all_co())
417       return l