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