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