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
22 Ce module contient la classe MCCOMPO qui sert à factoriser les comportements
30 class MCCOMPO(N_OBJECT.OBJECT):
33 Classe support d'un OBJECT composite
39 Construit la liste des sous-entites du MCCOMPO
40 à partir du dictionnaire des arguments (valeur)
43 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
54 # On recopie le dictionnaire des arguments pour protéger l'original des
55 # delete (del args[k])
59 # On construit les sous entites presentes ou obligatoires
60 # 1- les entites présentes dans les arguments et dans la définition
61 # 2- les entités non présentes dans les arguments, présentes dans la définition avec un défaut
62 # Phase 1.1 : on traite d'abord les SIMP pour enregistrer les mots cles
64 for k, v in self.definition.entites.items():
67 if args.has_key(k) or v.statut == 'o':
69 # Creation par appel de la methode __call__ de la definition de la sous entite k de self
70 # si une valeur existe dans args ou est obligatoire (generique si toutes les
71 # entites ont l attribut statut )
73 objet = v(val=args.get(k, None), nom=k, parent=self)
74 mc_liste.append(objet)
75 # Si l'objet a une position globale on l'ajoute aux listes
77 if hasattr(objet.definition, 'position'):
78 if objet.definition.position == 'global':
79 self.append_mc_global(objet)
80 elif objet.definition.position == 'global_jdc':
81 self.append_mc_global_jdc(objet)
85 # Phase 1.2 : on traite les autres entites que SIMP
86 # (FACT en fait car un BLOC ne peut avoir le meme nom qu'un mot-clef)
87 for k, v in self.definition.entites.items():
90 if args.has_key(k) or v.statut == 'o':
92 # Creation par appel de la methode __call__ de la definition de la sous entite k de self
93 # si une valeur existe dans args ou est obligatoire (generique si toutes les
94 # entites ont l attribut statut )
96 objet = v(val=args.get(k, None), nom=k, parent=self)
97 mc_liste.append(objet)
102 # On construit les objets (en général, blocs) conditionnés par les mots-clés précédemment créés.
103 # A ce stade, mc_liste ne contient que les fils de l'objet courant
104 # args ne contient plus que des mots-clés qui n'ont pas été attribués car ils sont
105 # à attribuer à des blocs du niveau inférieur ou bien sont des mots-clés erronés
106 for k, v in self.definition.entites.items():
107 if v.label != 'BLOC': continue
109 # condition and a or b : Equivalent de l'expression : condition ?
111 #PNPN on recalcule dico_valeurs dans le for
112 # pour les globaux imbriques (exple Telemac Advection)
113 # avant le calcul etait avant le for
114 dico_valeurs = self.cree_dict_condition(mc_liste, condition=1)
115 globs = self.jdc and self.jdc.condition_context or {}
116 if v.verif_presence(dico_valeurs, globs):
117 # Si le bloc existe :
119 # 2- on l'ajoute à mc_liste
120 # 3- on récupère les arguments restant
121 # 4- on reconstruit le dictionnaire équivalent à mc_liste
122 bloc = v(nom=k, val=args, parent=self)
123 mc_liste.append(bloc)
124 args = bloc.reste_val
125 # On ne recalcule pas le contexte car on ne tient pas compte des blocs
126 # pour évaluer les conditions de présence des blocs
127 # dico_valeurs = self.cree_dict_valeurs(mc_liste)
129 # On conserve les arguments superflus dans l'attribut reste_val
130 self.reste_val = args
131 # On ordonne la liste ainsi créée suivant l'ordre du catalogue
132 # (utile seulement pour IHM graphique)
133 mc_liste = self.ordonne_liste(mc_liste)
134 # on retourne la liste ainsi construite
137 def ordonne_liste(self, mc_liste):
139 Ordonne la liste suivant l'ordre du catalogue.
140 Seulement pour IHM graphique
142 if self.jdc and self.jdc.cata_ordonne_dico != None:
143 liste_noms_mc_ordonnee = self.get_liste_mc_ordonnee_brute(
144 self.get_genealogie(), self.jdc.cata_ordonne_dico)
145 return self.ordonne_liste_mc(mc_liste, liste_noms_mc_ordonnee)
149 def cree_dict_valeurs(self, liste=[], condition=0):
151 Cette méthode crée un contexte (sous la forme d'un dictionnaire)
152 à partir des valeurs des mots clés contenus dans l'argument liste.
153 L'opération consiste à parcourir la liste (d'OBJECT) et à la
154 transformer en un dictionnaire dont les clés sont les noms des
155 mots clés et les valeurs dépendent du type d'OBJECT.
156 Ce dictionnaire servira de liste d'arguments d'appel pour les
157 fonctions sd_prod de commandes et ops de macros ou de contexte
158 d'évaluation des conditions de présence de BLOC.
160 Si l'argument condition de la méthode vaut 1, on ne
161 remonte pas les valeurs des mots clés contenus dans des blocs
162 pour eviter les bouclages.
164 Cette méthode réalise les opérations suivantes en plus de transformer
165 la liste en dictionnaire :
167 - ajouter tous les mots-clés non présents avec la valeur None
168 - ajouter tous les mots-clés globaux (attribut position = 'global'
171 L'argument liste est, en général, une mc_liste en cours de
172 construction, contenant les mots-clés locaux et les blocs déjà créés.
178 # Si v est un BLOC, on inclut ses items dans le dictionnaire
179 # représentatif du contexte. Les blocs sont retournés par get_valeur
180 # sous la forme d'un dictionnaire : les mots-clés fils de blocs sont
181 # donc remontés au niveau du contexte.
183 dadd = v.get_valeur()
184 assert intersection_vide(dico, dadd)
187 assert not dico.has_key(v.nom), "deja vu : %s" % v.nom
188 dico[v.nom] = v.get_valeur()
190 # On rajoute tous les autres mots-clés locaux possibles avec la valeur
192 # Pour les mots-clés facteurs, on ne traite que ceux avec statut défaut ('d')
194 # On n'ajoute aucune information sur les blocs. Ils n'ont pas de défaut seulement
196 # XXX remplacer le not has_key par un dico différent et faire dico2.update(dico)
197 # ce n'est qu'un pb de perf
198 for k, v in self.definition.entites.items():
199 if not dico.has_key(k):
200 if v.label == 'SIMP':
203 elif v.label == 'FACT':
204 if v.statut in ('c', 'd'):
205 # Mot clé facteur avec défaut ou caché provisoire
206 dico[k] = v(val=None, nom=k, parent=self)
207 # On demande la suppression des pointeurs arrieres
208 # pour briser les eventuels cycles
212 # A ce stade on a rajouté tous les mots-clés locaux possibles (fils directs) avec leur
213 # valeur par défaut ou la valeur None
215 # On rajoute les mots-clés globaux sans écraser les clés existantes
216 dico_mc = self.recherche_mc_globaux()
222 def cree_dict_toutes_valeurs(self):
223 """Semblable à `cree_dict_valeurs(liste=self.mc_liste)` en supprimant les
225 dico = self.cree_dict_valeurs(self.mc_liste, condition=0)
226 dico = dict([(k, v) for k, v in dico.items() if v is not None])
229 def cree_dict_condition(self, liste=[], condition=0):
231 Methode pour construire un contexte qui servira dans l'évaluation
232 des conditions de présence de blocs. Si une commande a un concept
233 produit réutilisé, on ajoute la clé 'reuse'
235 dico = self.cree_dict_valeurs(liste, condition=1)
236 # On ajoute la cle "reuse" pour les MCCOMPO qui ont un attribut reuse. A destination
237 # uniquement des commandes. Ne devrait pas etre dans cette classe mais
238 # dans une classe dérivée
239 if not dico.has_key('reuse') and hasattr(self, 'reuse'):
240 dico['reuse'] = self.reuse
243 def recherche_mc_globaux(self):
245 Retourne la liste des mots-clés globaux de l'étape à laquelle appartient self
246 et des mots-clés globaux du jdc
248 etape = self.get_etape()
250 dict_mc_globaux_fac = self.recherche_mc_globaux_facultatifs()
251 for k, v in etape.mc_globaux.items():
252 dict_mc_globaux_fac[k] = v.get_valeur()
254 for k, v in self.jdc.mc_globaux.items():
255 dict_mc_globaux_fac[k] = v.get_valeur()
256 return dict_mc_globaux_fac
260 def recherche_mc_globaux_facultatifs(self):
262 Cette méthode interroge la définition de self et retourne la liste des mots-clés fils
263 directs de self de type 'global'.
264 position='global' n'est donc possible (et n'a de sens) qu'au plus haut niveau.
267 etape = self.get_etape()
270 for k, v in etape.definition.entites.items():
271 if v.label != 'SIMP':
273 if v.position != 'global':
277 obj = v(val=None, nom=k, parent=etape)
278 dico[k] = obj.get_valeur()
283 Méthode qui supprime toutes les références arrières afin que l'objet puisse
284 etre correctement détruit par le garbage collector
286 N_OBJECT.OBJECT.supprime(self)
287 for child in self.mc_liste:
290 def __getitem__(self, key):
292 Cette méthode retourne la valeur d'un sous mot-clé (key)
294 return self.get_mocle(key)
296 def get_mocle(self, key):
298 Retourne la valeur du sous mot-clé key
299 Ce sous mot-clé peut exister, avoir une valeur par defaut ou etre
300 dans un BLOC fils de self
302 # on cherche dans les mots cles presents, le mot cle de nom key
303 # s'il est là on retourne sa valeur (méthode get_val)
304 for child in self.mc_liste:
306 return child.get_valeur()
307 # Si on n a pas trouve de mot cle present on retourne le defaut
308 # eventuel pour les mots cles accessibles dans la definition
311 d = self.definition.entites[key]
312 if d.label == 'SIMP':
314 elif d.label == 'FACT':
315 # il faut construire les objets necessaires pour
316 # evaluer les conditions des blocs eventuels (a faire)
319 if d.statut != 'c' and d.statut != 'd':
322 return d(val=None, nom=key, parent=self)
324 # le mot cle n est pas defini a ce niveau
326 # Si on a toujours rien trouve, on cherche dans les blocs presents
327 # On suppose que tous les blocs possibles ont ete crees meme ceux
328 # induits par un mot cle simple absent avec defaut (???)
329 for mc in self.mc_liste:
333 return mc.get_mocle(key)
335 # On n a rien trouve dans ce bloc, on passe au suivant
337 # On a rien trouve, le mot cle est absent.
338 # On leve une exception
339 raise IndexError, "Le mot cle %s n existe pas dans %s" % (key, self)
341 def get_child(self, name, restreint='non'):
343 Retourne le fils de self de nom name ou None s'il n'existe pas
344 Si restreint vaut oui : ne regarde que dans la mc_liste
345 Si restreint vaut non : regarde aussi dans les entites possibles
346 avec defaut (Ce dernier cas n'est utilisé que dans le catalogue)
348 for v in self.mc_liste:
351 if restreint == 'non':
353 entite = self.definition.entites[name]
354 if entite.label == 'SIMP' or (entite.label == 'FACT' and entite.statut in ('c', 'd')):
355 return entite(None, name, None)
361 def append_mc_global(self, mc):
363 Ajoute le mot-clé mc à la liste des mots-clés globaux de l'étape
365 etape = self.get_etape()
368 etape.mc_globaux[nom] = mc
370 def append_mc_global_jdc(self, mc):
372 Ajoute le mot-clé mc à la liste des mots-clés globaux du jdc
375 self.jdc.mc_globaux[nom] = mc
378 """ Retourne une copie de self """
379 objet = self.makeobjet()
380 # FR : attention !!! avec makeobjet, objet a le meme parent que self
381 # ce qui n'est pas du tout bon dans le cas d'une copie !!!!!!!
382 # FR : peut-on passer par là autrement que dans le cas d'une copie ???
383 # FR --> je suppose que non
384 # XXX CCAR : le pb c'est qu'on vérifie ensuite quel parent avait l'objet
385 # Il me semble preferable de changer le parent a la fin quand la copie
387 objet.valeur = copy(self.valeur)
388 objet.val = copy(self.val)
390 for obj in self.mc_liste:
392 new_obj.reparent(objet)
393 objet.mc_liste.append(new_obj)
396 def reparent(self, parent):
398 Cette methode sert a reinitialiser la parente de l'objet
401 self.jdc = parent.get_jdc_root()
402 self.etape = parent.etape
403 for mocle in self.mc_liste:
406 def get_sd_utilisees(self):
408 Retourne la liste des concepts qui sont utilisés à l'intérieur de self
409 ( comme valorisation d'un MCS)
412 for child in self.mc_liste:
413 l.extend(child.get_sd_utilisees())
416 def get_sd_mcs_utilisees(self):
418 Retourne la ou les SD utilisée par self sous forme d'un dictionnaire :
419 - Si aucune sd n'est utilisée, le dictionnaire est vide.
420 - Sinon, les clés du dictionnaire sont les mots-clés derrière lesquels on
421 trouve des sd ; la valeur est la liste des sd attenante.
424 { 'VALE_F': [ <Cata.cata.fonction_sdaster instance at 0x9419854>,
425 <Cata.cata.fonction_sdaster instance at 0x941a204> ],
426 'MODELE': [<Cata.cata.modele instance at 0x941550c>] }
429 for child in self.mc_liste:
430 daux = child.get_sd_mcs_utilisees()
431 for cle in daux.keys():
432 dico[cle] = dico.get(cle, [])
433 dico[cle].extend(daux[cle])
436 def get_mcs_with_co(self, co):
438 Cette methode retourne l'objet MCSIMP fils de self
439 qui a le concept co comme valeur.
440 En principe, elle ne doit etre utilisee que pour les concepts
441 instances de la classe CO
444 for child in self.mc_liste:
445 l.extend(child.get_mcs_with_co(co))
448 def get_all_co(self):
450 Cette methode retourne tous les concepts instances de CO
453 for child in self.mc_liste:
454 l.extend(child.get_all_co())
458 def intersection_vide(dict1, dict2):
459 """Verification qu'il n'y a pas de clé commune entre 'dict1' et 'dict2'."""
460 sk1 = set(dict1.keys())
461 sk2 = set(dict2.keys())
462 inter = sk1.intersection(sk2)
465 print 'ERREUR: Mot(s)-clef(s) vu(s) plusieurs fois :', tuple(inter)