1 # -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2007-2013 EDF R&D
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License.
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 Ce module contient la classe MCCOMPO qui sert à factoriser les comportements
30 class MCCOMPO(N_OBJECT.OBJECT):
32 Classe support d'un OBJECT composite
38 Construit la liste des sous-entites du MCCOMPO
39 à partir du dictionnaire des arguments (valeur)
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, ...)
47 if args == None : args ={}
50 # On recopie le dictionnaire des arguments pour protéger l'original des delete (del args[k])
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 # Phase 1.1 : on traite d'abord les SIMP pour enregistrer les mots cles globaux
58 for k,v in self.definition.entites.items():
59 if v.label != 'SIMP':continue
60 if args.has_key(k) or v.statut=='o' :
62 # Creation par appel de la methode __call__ de la definition de la sous entite k de self
63 # si une valeur existe dans args ou est obligatoire (generique si toutes les
64 # entites ont l attribut statut )
66 objet=v(val=args.get(k,None),nom=k,parent=self)
67 mc_liste.append(objet)
68 # Si l'objet a une position globale on l'ajoute aux listes correspondantes
69 if hasattr(objet.definition,'position'):
70 if objet.definition.position == 'global' :
71 self.append_mc_global(objet)
72 elif objet.definition.position == 'global_jdc' :
73 self.append_mc_global_jdc(objet)
77 # Phase 1.2 : on traite les autres entites que SIMP
78 # (FACT en fait car un BLOC ne peut avoir le meme nom qu'un mot-clef)
79 for k,v in self.definition.entites.items():
80 if v.label == 'SIMP':continue
81 if args.has_key(k) or v.statut=='o' :
83 # Creation par appel de la methode __call__ de la definition de la sous entite k de self
84 # si une valeur existe dans args ou est obligatoire (generique si toutes les
85 # entites ont l attribut statut )
87 objet=v(val=args.get(k,None),nom=k,parent=self)
88 mc_liste.append(objet)
93 # On construit les objets (en général, blocs) conditionnés par les mots-clés précédemment créés.
94 # A ce stade, mc_liste ne contient que les fils de l'objet courant
95 # args ne contient plus que des mots-clés qui n'ont pas été attribués car ils sont
96 # à attribuer à des blocs du niveau inférieur ou bien sont des mots-clés erronés
97 dico_valeurs = self.cree_dict_condition(mc_liste,condition=1)
98 for k,v in self.definition.entites.items():
99 if v.label != 'BLOC':continue
100 # condition and a or b : Equivalent de l'expression : condition ? a : b du langage C
101 globs= self.jdc and self.jdc.condition_context or {}
102 if v.verif_presence(dico_valeurs,globs):
103 # Si le bloc existe :
105 # 2- on l'ajoute à mc_liste
106 # 3- on récupère les arguments restant
107 # 4- on reconstruit le dictionnaire équivalent à mc_liste
108 bloc = v(nom=k,val=args,parent=self)
109 mc_liste.append(bloc)
111 # On ne recalcule pas le contexte car on ne tient pas compte des blocs
112 # pour évaluer les conditions de présence des blocs
113 #dico_valeurs = self.cree_dict_valeurs(mc_liste)
115 # On conserve les arguments superflus dans l'attribut reste_val
117 # On ordonne la liste ainsi créée suivant l'ordre du catalogue
118 # (utile seulement pour IHM graphique)
119 mc_liste = self.ordonne_liste(mc_liste)
120 # on retourne la liste ainsi construite
123 def ordonne_liste(self,mc_liste):
125 Ordonne la liste suivant l'ordre du catalogue.
126 Seulement pour IHM graphique
128 if self.jdc and self.jdc.cata_ordonne_dico != None :
129 liste_noms_mc_ordonnee = self.get_liste_mc_ordonnee_brute(
130 self.get_genealogie(),self.jdc.cata_ordonne_dico)
131 return self.ordonne_liste_mc(mc_liste,liste_noms_mc_ordonnee)
135 def cree_dict_valeurs(self,liste=[],condition=0):
137 Cette méthode crée un contexte (sous la forme d'un dictionnaire)
138 à partir des valeurs des mots clés contenus dans l'argument liste.
139 L'opération consiste à parcourir la liste (d'OBJECT) et à la
140 transformer en un dictionnaire dont les clés sont les noms des
141 mots clés et les valeurs dépendent du type d'OBJECT.
142 Ce dictionnaire servira de liste d'arguments d'appel pour les
143 fonctions sd_prod de commandes et ops de macros ou de contexte
144 d'évaluation des conditions de présence de BLOC.
146 Si l'argument condition de la méthode vaut 1, on ne
147 remonte pas les valeurs des mots clés contenus dans des blocs
148 pour eviter les bouclages.
150 Cette méthode réalise les opérations suivantes en plus de transformer
151 la liste en dictionnaire :
153 - ajouter tous les mots-clés non présents avec la valeur None
154 - ajouter tous les mots-clés globaux (attribut position = 'global'
157 L'argument liste est, en général, une mc_liste en cours de
158 construction, contenant les mots-clés locaux et les blocs déjà créés.
164 # Si v est un BLOC, on inclut ses items dans le dictionnaire
165 # représentatif du contexte. Les blocs sont retournés par get_valeur
166 # sous la forme d'un dictionnaire : les mots-clés fils de blocs sont
167 # donc remontés au niveau du contexte.
169 dadd = v.get_valeur()
170 assert intersection_vide(dico, dadd)
173 assert not dico.has_key(v.nom), "deja vu : %s" % v.nom
174 dico[v.nom]=v.get_valeur()
176 # On rajoute tous les autres mots-clés locaux possibles avec la valeur
178 # Pour les mots-clés facteurs, on ne traite que ceux avec statut défaut ('d')
180 # On n'ajoute aucune information sur les blocs. Ils n'ont pas de défaut seulement
182 #XXX remplacer le not has_key par un dico différent et faire dico2.update(dico)
183 # ce n'est qu'un pb de perf
184 for k,v in self.definition.entites.items():
185 if not dico.has_key(k):
186 if v.label == 'SIMP':
189 elif v.label == 'FACT' :
190 if v.statut in ('c','d') :
191 # Mot clé facteur avec défaut ou caché provisoire
192 dico[k]=v(val=None,nom=k,parent=self)
193 # On demande la suppression des pointeurs arrieres
194 # pour briser les eventuels cycles
198 # A ce stade on a rajouté tous les mots-clés locaux possibles (fils directs) avec leur
199 # valeur par défaut ou la valeur None
201 # On rajoute les mots-clés globaux sans écraser les clés existantes
202 dico_mc = self.recherche_mc_globaux()
208 def cree_dict_toutes_valeurs(self):
209 """Semblable à `cree_dict_valeurs(liste=self.mc_liste)` en supprimant les
211 dico = self.cree_dict_valeurs(self.mc_liste, condition=0)
212 dico = dict([(k, v) for k, v in dico.items() if v is not None])
215 def cree_dict_condition(self,liste=[],condition=0):
217 Methode pour construire un contexte qui servira dans l'évaluation
218 des conditions de présence de blocs. Si une commande a un concept
219 produit réutilisé, on ajoute la clé 'reuse'
221 dico=self.cree_dict_valeurs(liste,condition=1)
222 # On ajoute la cle "reuse" pour les MCCOMPO qui ont un attribut reuse. A destination
223 # uniquement des commandes. Ne devrait pas etre dans cette classe mais dans une classe dérivée
224 if not dico.has_key('reuse') and hasattr(self,'reuse'):
225 dico['reuse']=self.reuse
228 def recherche_mc_globaux(self):
230 Retourne la liste des mots-clés globaux de l'étape à laquelle appartient self
231 et des mots-clés globaux du jdc
233 etape = self.get_etape()
235 dict_mc_globaux_fac = self.recherche_mc_globaux_facultatifs()
236 for k,v in etape.mc_globaux.items():
237 dict_mc_globaux_fac[k]=v.get_valeur()
239 for k,v in self.jdc.mc_globaux.items():
240 dict_mc_globaux_fac[k]=v.get_valeur()
241 return dict_mc_globaux_fac
245 def recherche_mc_globaux_facultatifs(self):
247 Cette méthode interroge la définition de self et retourne la liste des mots-clés fils
248 directs de self de type 'global'.
249 position='global' n'est donc possible (et n'a de sens) qu'au plus haut niveau.
252 etape = self.get_etape()
253 if not etape : return {}
254 for k,v in etape.definition.entites.items():
255 if v.label != 'SIMP' : continue
256 if v.position != 'global' : continue
257 if v.statut == 'o':continue
258 obj = v(val=None,nom=k,parent=etape)
259 dico[k]=obj.get_valeur()
264 Méthode qui supprime toutes les références arrières afin que l'objet puisse
265 etre correctement détruit par le garbage collector
267 N_OBJECT.OBJECT.supprime(self)
268 for child in self.mc_liste :
271 def __getitem__(self,key):
273 Cette méthode retourne la valeur d'un sous mot-clé (key)
275 return self.get_mocle(key)
277 def get_mocle(self,key):
279 Retourne la valeur du sous mot-clé key
280 Ce sous mot-clé peut exister, avoir une valeur par defaut ou etre
281 dans un BLOC fils de self
283 # on cherche dans les mots cles presents, le mot cle de nom key
284 # s'il est là on retourne sa valeur (méthode get_val)
285 for child in self.mc_liste:
286 if child.nom == key : return child.get_valeur()
287 # Si on n a pas trouve de mot cle present on retourne le defaut
288 # eventuel pour les mots cles accessibles dans la definition
291 d=self.definition.entites[key]
292 if d.label == 'SIMP':
294 elif d.label == 'FACT':
295 # il faut construire les objets necessaires pour
296 # evaluer les conditions des blocs eventuels (a faire)
297 if d.statut == 'o' :return None
298 if d.statut != 'c' and d.statut != 'd' :
301 return d(val=None,nom=key,parent=self)
303 # le mot cle n est pas defini a ce niveau
305 # Si on a toujours rien trouve, on cherche dans les blocs presents
306 # On suppose que tous les blocs possibles ont ete crees meme ceux
307 # induits par un mot cle simple absent avec defaut (???)
308 for mc in self.mc_liste :
309 if not mc.isBLOC() : continue
311 return mc.get_mocle(key)
313 # On n a rien trouve dans ce bloc, on passe au suivant
315 # On a rien trouve, le mot cle est absent.
316 # On leve une exception
317 raise IndexError,"Le mot cle %s n existe pas dans %s" % (key,self)
319 def get_child(self,name,restreint = 'non'):
321 Retourne le fils de self de nom name ou None s'il n'existe pas
322 Si restreint vaut oui : ne regarde que dans la mc_liste
323 Si restreint vaut non : regarde aussi dans les entites possibles
324 avec defaut (Ce dernier cas n'est utilisé que dans le catalogue)
326 for v in self.mc_liste:
327 if v.nom == name : return v
328 if restreint == 'non' :
330 entite=self.definition.entites[name]
331 if entite.label == 'SIMP' or (entite.label == 'FACT' and entite.statut in ( 'c', 'd')):
332 return entite(None,name,None)
338 def append_mc_global(self,mc):
340 Ajoute le mot-clé mc à la liste des mots-clés globaux de l'étape
342 etape = self.get_etape()
345 etape.mc_globaux[nom]=mc
347 def append_mc_global_jdc(self,mc):
349 Ajoute le mot-clé mc à la liste des mots-clés globaux du jdc
352 self.jdc.mc_globaux[nom]=mc
355 """ Retourne une copie de self """
356 objet = self.makeobjet()
357 # FR : attention !!! avec makeobjet, objet a le meme parent que self
358 # ce qui n'est pas du tout bon dans le cas d'une copie !!!!!!!
359 # FR : peut-on passer par là autrement que dans le cas d'une copie ???
360 # FR --> je suppose que non
361 # XXX CCAR : le pb c'est qu'on vérifie ensuite quel parent avait l'objet
362 # Il me semble preferable de changer le parent a la fin quand la copie est acceptee
363 objet.valeur = copy(self.valeur)
364 objet.val = copy(self.val)
366 for obj in self.mc_liste:
368 new_obj.reparent(objet)
369 objet.mc_liste.append(new_obj)
372 def reparent(self,parent):
374 Cette methode sert a reinitialiser la parente de l'objet
377 self.jdc=parent.get_jdc_root()
378 self.etape=parent.etape
379 for mocle in self.mc_liste:
382 def get_sd_utilisees(self):
384 Retourne la liste des concepts qui sont utilisés à l'intérieur de self
385 ( comme valorisation d'un MCS)
388 for child in self.mc_liste:
389 l.extend(child.get_sd_utilisees())
392 def get_sd_mcs_utilisees(self):
394 Retourne la ou les SD utilisée par self sous forme d'un dictionnaire :
395 - Si aucune sd n'est utilisée, le dictionnaire est vide.
396 - Sinon, les clés du dictionnaire sont les mots-clés derrière lesquels on
397 trouve des sd ; la valeur est la liste des sd attenante.
400 { 'VALE_F': [ <Cata.cata.fonction_sdaster instance at 0x9419854>,
401 <Cata.cata.fonction_sdaster instance at 0x941a204> ],
402 'MODELE': [<Cata.cata.modele instance at 0x941550c>] }
405 for child in self.mc_liste:
406 daux = child.get_sd_mcs_utilisees()
407 for cle in daux.keys():
408 dico[cle] = dico.get(cle, [])
409 dico[cle].extend(daux[cle])
412 def get_mcs_with_co(self,co):
414 Cette methode retourne l'objet MCSIMP fils de self
415 qui a le concept co comme valeur.
416 En principe, elle ne doit etre utilisee que pour les concepts
417 instances de la classe CO
420 for child in self.mc_liste:
421 l.extend(child.get_mcs_with_co(co))
424 def get_all_co(self):
426 Cette methode retourne tous les concepts instances de CO
429 for child in self.mc_liste:
430 l.extend(child.get_all_co())
434 def intersection_vide(dict1, dict2):
435 """Verification qu'il n'y a pas de clé commune entre 'dict1' et 'dict2'."""
436 sk1 = set(dict1.keys())
437 sk2 = set(dict2.keys())
438 inter = sk1.intersection(sk2)
441 print 'ERREUR: Mot(s)-clef(s) vu(s) plusieurs fois :', tuple(inter)