Salome HOME
bb77a945d3be8fd6bebcb94fe5327d1ed3b75400
[tools/eficas.git] / Noyau / N_MCCOMPO.py
1 #@ MODIF N_MCCOMPO Noyau  DATE 28/10/2003   AUTEUR DURAND C.DURAND 
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     Ce module contient la classe MCCOMPO qui sert à factoriser les comportements 
23     des OBJECT composites
24 """
25
26 import types
27 from copy import copy
28 import N_OBJECT
29
30 class MCCOMPO(N_OBJECT.OBJECT):
31    """
32       Classe support d'un OBJECT composite
33   
34    """
35
36    def build_mc(self):
37       """ 
38           Construit la liste des sous-entites du MCCOMPO
39           à partir du dictionnaire des arguments (valeur)
40       """
41       if CONTEXT.debug : print "MCCOMPO.build_mc ",self.nom
42       # Dans la phase de reconstruction args peut contenir des mots-clés
43       # qui ne sont pas dans le dictionnaire des entites de definition (self.definition.entites)
44       # de l'objet courant (self)
45       #  mais qui sont malgré tout des descendants de l'objet courant (petits-fils, ...)
46       args = self.valeur
47       if args == None : args ={}
48       mc_liste=[]
49
50       # On recopie le dictionnaire des arguments pour protéger l'original des delete (del args[k])
51       args = args.copy()
52
53       # Phase 1:
54       # On construit les sous entites presentes ou obligatoires
55       # 1- les entites présentes dans les arguments et dans la définition
56       # 2- les entités non présentes dans les arguments, présentes dans la définition avec un défaut
57       for k,v in self.definition.entites.items():
58         if args.has_key(k) or v.statut=='o' :
59           #
60           # Creation par appel de la methode __call__ de la definition de la sous entite k de self
61           # si une valeur existe dans args ou est obligatoire (generique si toutes les
62           # entites ont l attribut statut )
63           #
64           objet=self.definition.entites[k](val=args.get(k,None),nom=k,parent=self)
65           mc_liste.append(objet)
66           # Si l'objet a une position globale on l'ajoute aux listes correspondantes
67           if hasattr(objet.definition,'position'):
68             if objet.definition.position == 'global' :
69               self.append_mc_global(objet)
70             elif objet.definition.position == 'global_jdc' :
71               self.append_mc_global_jdc(objet)
72         if args.has_key(k):
73            del args[k]
74
75       # Phase 2:
76       # On construit les objets (en général, blocs) conditionnés par les mots-clés précédemment créés.
77       # A ce stade, mc_liste ne contient que les fils de l'objet courant
78       # args ne contient plus que des mots-clés qui n'ont pas été attribués car ils sont
79       #      à attribuer à des blocs du niveau inférieur ou bien sont des mots-clés erronés
80       dico_valeurs = self.cree_dict_condition(mc_liste,condition=1)
81       for k,v in self.definition.entites.items():
82          if v.label != 'BLOC':continue
83          # condition and a or b  : Equivalent de l'expression :  condition ? a : b du langage C
84          globs= self.jdc and self.jdc.condition_context or {}
85          if v.verif_presence(dico_valeurs,globs):
86             # Si le bloc existe :
87             #        1- on le construit
88             #        2- on l'ajoute à mc_liste
89             #        3- on récupère les arguments restant
90             #        4- on reconstruit le dictionnaire équivalent à mc_liste
91             bloc = v(nom=k,val=args,parent=self)
92             mc_liste.append(bloc)
93             args=bloc.reste_val
94             # On ne recalcule pas le contexte car on ne tient pas compte des blocs
95             # pour évaluer les conditions de présence des blocs
96             #dico_valeurs = self.cree_dict_valeurs(mc_liste)
97
98       # On conserve les arguments superflus dans l'attribut reste_val
99       self.reste_val=args
100       # On ordonne la liste ainsi créée suivant l'ordre du catalogue 
101       # (utile seulement pour IHM graphique)
102       mc_liste = self.ordonne_liste(mc_liste)
103       # on retourne la liste ainsi construite
104       return mc_liste
105
106    def ordonne_liste(self,mc_liste):
107       """
108          Ordonne la liste suivant l'ordre du catalogue.
109          Seulement pour IHM graphique
110       """
111       if self.jdc and self.jdc.cata_ordonne_dico != None :
112          liste_noms_mc_ordonnee = self.get_liste_mc_ordonnee_brute(
113                        self.get_genealogie(),self.jdc.cata_ordonne_dico)
114          return self.ordonne_liste_mc(mc_liste,liste_noms_mc_ordonnee)
115       else:
116          return mc_liste
117
118    def cree_dict_valeurs(self,liste=[],condition=0):
119       """ 
120         Cette méthode crée un contexte (sous la forme d'un dictionnaire)
121         à partir des valeurs des mots clés contenus dans l'argument liste.
122         L'opération consiste à parcourir la liste (d'OBJECT) et à la 
123         transformer en un dictionnaire dont les clés sont les noms des
124         mots clés et les valeurs dépendent du type d'OBJECT.
125         Ce dictionnaire servira de liste d'arguments d'appel pour les
126         fonctions sd_prod de commandes et ops de macros ou de contexte
127         d'évaluation des conditions de présence de BLOC.
128
129         Si l'argument condition de la méthode vaut 1, on ne 
130         remonte pas les valeurs des mots clés contenus dans des blocs
131         pour eviter les bouclages.
132
133         Cette méthode réalise les opérations suivantes en plus de transformer 
134         la liste en dictionnaire :
135
136            - ajouter tous les mots-clés non présents avec la valeur None
137            - ajouter tous les mots-clés globaux (attribut position = 'global' 
138              et 'global_jdc')
139
140         L'argument liste est, en général, une mc_liste en cours de 
141         construction, contenant les mots-clés locaux et les blocs déjà créés.
142
143       """
144       dico={}
145       for v in liste:
146         if v.isBLOC():
147            # Si v est un BLOC, on inclut ses items dans le dictionnaire
148            # représentatif du contexte. Les blocs sont retournés par get_valeur
149            # sous la forme d'un dictionnaire : les mots-clés fils de blocs sont
150            # donc remontés au niveau du contexte.
151            if not condition:dico.update(v.get_valeur())
152         else:
153            dico[v.nom]=v.get_valeur()
154
155       # On rajoute tous les autres mots-clés locaux possibles avec la valeur 
156       # par défaut ou None
157       # Pour les mots-clés facteurs, on ne traite que ceux avec statut défaut ('d')
158       # et caché ('c')
159       # On n'ajoute aucune information sur les blocs. Ils n'ont pas de défaut seulement
160       # une condition.
161       for k,v in self.definition.entites.items():
162         if not dico.has_key(k):
163            if v.label == 'SIMP':
164               # Mot clé simple
165               dico[k]=v.defaut
166            elif v.label == 'FACT' :
167               if v.statut in ('c','d') :
168                  # Mot clé facteur avec défaut ou caché provisoire
169                  dico[k]=v(val=None,nom=k,parent=self)
170                  # On demande la suppression des pointeurs arrieres
171                  # pour briser les eventuels cycles
172                  dico[k].supprime()
173               else:
174                  dico[k]=None
175       # A ce stade on a rajouté tous les mots-clés locaux possibles (fils directs) avec leur
176       # valeur par défaut ou la valeur None
177
178       # On rajoute les mots-clés globaux sans écraser les clés existantes
179       dico_mc = self.recherche_mc_globaux()
180       dico_mc.update(dico)
181       dico=dico_mc
182
183       return dico
184
185    def cree_dict_condition(self,liste=[],condition=0):
186       """
187           Methode pour construire un contexte qui servira dans l'évaluation
188           des conditions de présence de blocs. Si une commande a un concept
189           produit réutilisé, on ajoute la clé 'reuse'
190       """
191       dico=self.cree_dict_valeurs(liste,condition=1)
192       # On ajoute la cle "reuse" pour les MCCOMPO qui ont un attribut reuse. A destination
193       # uniquement des commandes. Ne devrait pas etre dans cette classe mais dans une classe dérivée
194       if not dico.has_key('reuse') and hasattr(self,'reuse'):
195          dico['reuse']=self.reuse
196       return dico
197
198    def recherche_mc_globaux(self):
199       """ 
200           Retourne la liste des mots-clés globaux de l'étape à laquelle appartient self
201           et des mots-clés globaux du jdc
202       """
203       etape = self.get_etape()
204       if etape :
205         dict_mc_globaux_fac = self.recherche_mc_globaux_facultatifs()
206         dict_mc_globaux_fac.update(etape.mc_globaux)
207         if self.jdc : dict_mc_globaux_fac.update(self.jdc.mc_globaux)
208         return dict_mc_globaux_fac
209       else :
210         return {}
211
212    def recherche_mc_globaux_facultatifs(self):
213       """ 
214           Cette méthode interroge la définition de self et retourne la liste des mots-clés fils
215           directs de self de type 'global'
216       """
217       dico={}
218       etape = self.get_etape()
219       if not etape : return {}
220       for k,v in etape.definition.entites.items():
221          if v.label != 'SIMP' : continue
222          if v.position != 'global' : continue
223          if v.statut == 'o':continue
224          obj = v(val=None,nom=k,parent=etape)
225          dico[k]=obj
226       return dico
227
228    def supprime(self):
229       """ 
230          Méthode qui supprime toutes les références arrières afin que l'objet puisse
231          etre correctement détruit par le garbage collector
232       """
233       N_OBJECT.OBJECT.supprime(self)
234       for child in self.mc_liste :
235          child.supprime()
236
237    def __getitem__(self,key):
238       """
239          Cette méthode retourne la valeur d'un sous mot-clé (key)
240       """
241       return self.get_mocle(key)
242
243    def get_mocle(self,key):
244       """
245           Retourne la valeur du sous mot-clé key 
246           Ce sous mot-clé peut exister, avoir une valeur par defaut ou etre 
247           dans un BLOC fils de self
248       """
249       # on cherche dans les mots cles presents, le mot cle de nom key
250       # s'il est là on retourne sa valeur (méthode get_val)
251       for child in self.mc_liste:
252         if child.nom == key : return child.get_val()
253       #  Si on n a pas trouve de mot cle present on retourne le defaut
254       #  eventuel pour les mots cles accessibles dans la definition
255       #  a ce niveau
256       try:
257         d=self.definition.entites[key]
258         if d.label == 'SIMP':
259           return d.defaut
260         elif d.label == 'FACT':
261           # il faut construire les objets necessaires pour
262           # evaluer les conditions des blocs eventuels (a faire)
263           if d.statut == 'o' :return None
264           if d.statut != 'c' and d.statut != 'd' :
265              return None
266           else :
267              return d(val=None,nom=key,parent=self)
268       except KeyError:
269         # le mot cle n est pas defini a ce niveau
270         pass
271       #  Si on a toujours rien trouve, on cherche dans les blocs presents
272       #  On suppose que tous les blocs possibles ont ete crees meme ceux
273       #  induits par un mot cle simple absent avec defaut (???)
274       for mc in self.mc_liste :
275         if not mc.isBLOC() : continue
276         try:
277           return mc.get_mocle(key)
278         except: 
279           # On n a rien trouve dans ce bloc, on passe au suivant
280           pass
281       #  On a rien trouve, le mot cle est absent.
282       #  On leve une exception
283       raise IndexError,"Le mot cle %s n existe pas dans %s" % (key,self)
284
285    def get_child(self,name,restreint = 'non'):
286       """ 
287           Retourne le fils de self de nom name ou None s'il n'existe pas
288           Si restreint vaut oui : ne regarde que dans la mc_liste
289           Si restreint vaut non : regarde aussi dans les entites possibles 
290           avec defaut    
291            (Ce dernier cas n'est utilisé que dans le catalogue)
292       """
293       for v in self.mc_liste:
294         if v.nom == name : return v
295       if restreint == 'non' :
296         try:
297            entite=self.definition.entites[name]
298            if entite.label == 'SIMP' or (entite.label == 'FACT' and entite.statut in ( 'c', 'd')):
299               return entite(None,name,None)
300         except:
301            pass
302
303       return None
304
305    def append_mc_global(self,mc):
306       """
307          Ajoute le mot-clé mc à la liste des mots-clés globaux de l'étape
308       """
309       etape = self.get_etape()
310       if etape :
311         nom = mc.nom
312         etape.mc_globaux[nom]=mc
313
314    def append_mc_global_jdc(self,mc):
315       """ 
316           Ajoute le mot-clé mc à la liste des mots-clés globaux du jdc 
317       """
318       nom = mc.nom
319       self.jdc.mc_globaux[nom]=mc
320
321    def copy(self):
322     """ Retourne une copie de self """
323     objet = self.makeobjet()
324     # FR : attention !!! avec makeobjet, objet a le meme parent que self
325     # ce qui n'est pas du tout bon dans le cas d'une copie !!!!!!!
326     # FR : peut-on passer par là autrement que dans le cas d'une copie ???
327     # FR --> je suppose que non
328     # XXX CCAR : le pb c'est qu'on vérifie ensuite quel parent avait l'objet
329     # Il me semble preferable de changer le parent a la fin quand la copie est acceptee
330     objet.valeur = copy(self.valeur)
331     objet.val = copy(self.val)
332     objet.mc_liste=[]
333     for obj in self.mc_liste:
334       new_obj = obj.copy()
335       new_obj.reparent(objet)
336       objet.mc_liste.append(new_obj)
337     return objet
338
339    def reparent(self,parent):
340      """
341          Cette methode sert a reinitialiser la parente de l'objet
342      """
343      self.parent=parent
344      self.jdc=parent.get_jdc_root()
345      self.etape=parent.etape
346      for mocle in self.mc_liste:
347         mocle.reparent(self)
348
349    def get_sd_utilisees(self):
350     """ 
351         Retourne la liste des concepts qui sont utilisés à l'intérieur de self
352         ( comme valorisation d'un MCS) 
353     """
354     l=[]
355     for child in self.mc_liste:
356       l.extend(child.get_sd_utilisees())
357     return l