1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2021 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 from __future__ import absolute_import
23 from __future__ import print_function
24 import string,types,sys
29 from Extensions.i18n import tr
30 from Noyau.N_MCSIMP import MCSIMP
31 from Noyau.N_MCFACT import MCFACT
32 from Noyau.N_MCBLOC import MCBLOC
33 from Noyau.N_MCLIST import MCList
34 from . import I_OBJECT
36 from . import CONNECTOR
38 class MCCOMPO(I_OBJECT.OBJECT):
39 def getLabelText(self):
41 Retourne le label de self
42 utilise pour l'affichage dans l'arbre
46 def getListeMcOrdonnee(self,liste,dico):
48 Retourne la liste ordonnee (suivant le catalogue) des mots-cles
49 d'une entite composee dont le chemin complet est donne sous forme
50 d'une liste du type :ETAPE + MCFACT ou MCBLOC + ...
51 il faut encore rearranger cette liste (certains mots-cles deja
52 presents ne doivent plus etre proposes, regles ...)
54 return self.filtreListeMc(self.getListeMcOrdonneeBrute(liste,dico))
56 def getListeMcOrdonneeBrute(self,liste,dico):
58 Retourne la liste ordonnee (suivant le catalogue) BRUTE des mots-cles
59 d'une entite composee dont le chemin complet est donne sous forme
60 d'une liste du type :ETAPE + MCFACT ou MCBLOC + ...
63 objet_cata = dico[arg]
64 dico=objet_cata.entites
67 for obj in list(dico.keys()) :
68 if not(hasattr(dico[obj],'cache')) or dico[obj].cache==0 :
72 if specifique == 1 : return l
73 return objet_cata.ordre_mc
75 def filtreListeMc(self,liste_brute):
77 Cette methode est appelee par EFICAS afin de presenter a
78 l'utilisateur la liste des enfants possibles de self actualisee
79 en fonction du contexte de self. En clair, sont supprimes de la
80 liste des possibles (fournie par la definition), les mots-cles
81 exclus par les regles de self et les mots-cles ne pouvant plus
84 liste = copy(liste_brute)
85 listeMcPresents = self.listeMcPresents()
86 # on enleve les mots-cles non permis par les regles
87 for regle in self.definition.regles:
88 # la methode purgeListe est a developper pour chaque regle qui
89 # influe sur la liste de choix a proposer a l'utilisateur
90 # --> EXCLUS,UN_PARMI,PRESENT_ABSENT
91 liste = regle.purgeListe(liste,listeMcPresents)
92 # on enleve les mots-cles dont l'occurrence est deja atteinte
93 liste_copy = copy(liste)
95 objet = self.getChild(k,restreint = 'oui')
97 # l'objet est deja present : il faut distinguer plusieurs cas
98 if isinstance(objet,MCSIMP):
99 # un mot-cle simple ne peut pas etre repete
101 elif isinstance(objet,MCBLOC):
102 # un bloc conditionnel ne doit pas apparaitre dans la liste de choix
104 elif isinstance(objet,MCFACT):
105 # un mot-cle facteur ne peut pas etre repete plus de self.max fois
106 if objet.definition.max == 1:
108 elif isinstance(objet,MCList):
110 nb_occur_maxi = objet[0].definition.max
111 if len(objet) >= nb_occur_maxi:
116 #XXX CCAR : les MCNUPLET ne sont pas traites
117 if CONTEXT.debug : print(' ',k,' est un objet de type inconnu :',type(objet))
119 # l'objet est absent : on enleve de la liste les blocs
120 if self.definition.entites[k].statut=='c' :
122 if self.definition.entites[k].label=='BLOC':
124 # Pour corriger les exces qui pourraient etre commis dans la methode purgeListe
125 # des regles, on essaie de compenser comme suit :
126 # on ajoute les mots cles facteurs presents dont l'occurence n'est pas atteinte
127 for k in listeMcPresents:
128 if k in liste:continue
129 objet = self.getChild(k,restreint = 'oui')
130 if isinstance(objet,MCFACT):
131 # un mot-cle facteur ne peut pas etre repete plus de self.max fois
132 if objet.definition.max > 1:
134 elif isinstance(objet,MCList):
135 nb_occur_maxi = objet[0].definition.max
136 if len(objet) < nb_occur_maxi:
140 def listeMcPresents(self):
142 Retourne la liste des noms des mots-cles fils de self presents construite
143 a partir de self.mcListe
146 for v in self.mcListe:
151 def getIndexChild(self,nom_fils):
153 Retourne l'index dans la liste des fils de self du nouveau fils de nom nom_fils
154 Permet de savoir a quelle position il faut ajouter un nouveau mot-cle
156 cata_ordonne = self.jdc.cata_ordonne_dico
157 liste_noms_mc_ordonnee = self.getListeMcOrdonneeBrute(self.getGenealogie(),cata_ordonne)
158 liste_noms_mc_presents = self.listeMcPresents()
160 for nom in liste_noms_mc_ordonnee:
161 if nom == nom_fils:break
162 if nom not in liste_noms_mc_presents :continue
166 def chercheIndiceDsLeContenu(self,objet) :
167 # uniquement pour Pyxb
168 # ajoute la taille des les Blocs
169 # faut -il chercher plus loin ds les petits-enfants ?
170 if objet.nature == 'MCList' : objet=objet[0]
174 positionDsLaListe=self.mcListe.index(objet)
175 positionDsLaListeDeFactSiFact =0
177 for mc in self.mcListe:
178 if mc.nature == 'MCList':
180 positionDsLaListeDeFactSiFact=mc.index(objet)
183 positionDsLaListe=positionDsLaListe+1
184 else : positionDsLaListe=positionDsLaListe+1
186 while i < positionDsLaListe :
187 leRang= leRang + self.mcListe[i].longueurDsArbre()
189 leRang=leRang+positionDsLaListeDeFactSiFact
193 def ordonneListeMc(self,listeMc_a_ordonner,liste_noms_mc_ordonnee):
195 Retourne listeMc_a_ordonner ordonnee suivant l'ordre
196 donne par liste_noms_mc_ordonnee
199 # on transforme liste_a_ordonner en un dictionnaire (plus facile a consulter)
201 for mc in listeMc_a_ordonner:
203 # on construit la liste des objets ordonnes
204 for nom_mc in liste_noms_mc_ordonnee:
206 liste.append(d_mc.get(nom_mc))
210 def suppEntite(self,objet) :
212 Supprime le fils 'objet' de self :
213 Retourne 1 si la suppression a pu etre effectuee,
214 Retourne 0 dans le cas contraire
216 #print ('suppEntite', self.nom,objet.nom)
217 if not objet in self.mcListe:
218 # Impossible de supprimer objet. Il n'est pas dans mcListe
224 self.mcListe.remove(objet)
225 CONNECTOR.Emit(self,"supp",objet)
226 objet.deleteMcGlobal()
227 objet.updateConditionBloc()
229 while self.etape.doitEtreRecalculee == True :
230 #print (' je suis dans le while')
231 self.etape.doitEtreRecalculee = False
232 self.etape.deepUpdateConditionBlocApresSuppression()
233 self.etape.modified()
240 def addEntite(self,name,pos=None):
242 Ajoute le mot-cle name a la liste des mots-cles de
245 #print ('addEntite', name, pos)
247 if type(name)==bytes or type(name) == str :
248 # on est en mode creation d'un motcle
249 if self.ispermis(name) == 0 : return 0
250 objet=self.definition.entites[name](val=None,nom=name,parent=self)
252 # dans ce cas on est en mode copie d'un motcle
254 # Appel de la methode qui fait le menage dans les references
255 # sur les concepts produits (verification que les concepts existent
256 # dans le contexte de la commande courante).
257 objet.verifExistenceSd()
259 # On verifie que l'ajout d'objet est autorise
260 if self.ispermis(objet) == 0:
261 self.jdc.editor.afficheAlerte(tr("Erreur"),
262 tr("L'objet %(v_1)s ne peut etre un fils de %(v_2)s",\
263 {'v_1': objet.nom, 'v_2': self.nom}))
267 # On cherche s'il existe deja un mot cle de meme nom
268 old_obj = self.getChild(objet.nom,restreint = 'oui')
270 # on normalize l'objet
271 objet=objet.normalize()
272 # Le mot cle n'existe pas encore. On l'ajoute a la position
275 self.mcListe.append(objet)
277 self.mcListe.insert(pos,objet)
278 # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
280 if self.cata.modeleMetier :
281 if isinstance(objet,MCList): objet[0].addObjPyxb(self.chercheIndiceDsLeContenu(objet))
282 else : objet.addObjPyxb(self.chercheIndiceDsLeContenu(objet))
283 CONNECTOR.Emit(self,"add",objet)
284 objet.updateMcGlobal()
285 objet.updateConditionBloc()
289 # Le mot cle existe deja. Si le mot cle est repetable,
290 # on cree une liste d'objets. Dans le cas contraire,
291 # on emet un message d'erreur.
292 if not old_obj.isRepetable():
293 self.jdc.editor.afficheAlerte(tr("Erreur"),tr("L'objet %s ne peut pas etre repete", objet.nom))
297 # une liste d'objets de meme type existe deja
298 old_obj.addEntite(objet)
299 if self.cata.modeleMetier :
300 if isinstance(objet,MCList): objet[0].addObjPyxb(self.chercheIndiceDsLeContenu(objet))
301 else : objet.addObjPyxb(self.chercheIndiceDsLeContenu(objet))
305 def ispermis(self,fils):
307 Retourne 1 si l'objet de nom nom_fils
308 est bien permis, cad peut bien etre un fils de self,
311 if type(fils) == bytes or type(fils) == str :
312 # on veut juste savoir si self peut avoir un fils de nom 'fils'
313 if fils in self.definition.entites:
317 #elif type(fils) == types.InstanceType:
318 elif isinstance(fils,object):
319 # fils est un objet (commande,mcf,mclist)
320 # on est dans le cas d'une tentative de copie de l'objet
321 # on veut savoir si l'objet peut bien etre un fils de self :
322 # la verification du nom de suffit pas (plusieurs commandes
323 # ont le meme mot-cle facteur AFFE ... et c'est l'utilisateur
324 # qui choisit le pere d'ou un risque d'erreur)
325 if not fils.nom in self.definition.entites:
328 if fils.parent.nom != self.nom : return 0
331 def updateConcept(self,sd):
332 for child in self.mcListe :
333 child.updateConcept(sd)
335 def deleteConcept(self,sd):
340 Mettre a jour les fils de l objet suite a la disparition du
342 Seuls les mots cles simples MCSIMP font un traitement autre que
343 de transmettre aux fils
345 for child in self.mcListe :
346 child.deleteConcept(sd)
348 def replaceConcept(self,old_sd,sd):
351 - old_sd=concept remplace
352 - sd = nouveau concept
354 Mettre a jour les fils de l objet suite au remplacement du
357 for child in self.mcListe :
358 child.replaceConcept(old_sd,sd)
360 def getListeMcInconnus(self):
362 Retourne la liste des mots-cles inconnus dans self
365 if self.reste_val != {}:
366 for k,v in self.reste_val.items() :
367 l_mc.append([self,k,v])
368 for child in self.mcListe :
369 if child.isValid() : continue
370 l_child = child.getListeMcInconnus()
377 def deepUpdateConditionBlocApresSuppression(self):
378 self._updateConditionBloc()
379 for mcobj in self.mcListe:
380 if mcobj.nature=="MCList" :
382 obj.deepUpdateConditionBlocApresSuppression()
384 elif hasattr(mcobj,"deepUpdateConditionBlocApresSuppression"):
385 mcobj.deepUpdateConditionBlocApresSuppression()
388 def deepUpdateConditionBlocApresCreation(self):
389 # idem deepUpdateConditionBloc sauf qu on cherche les MC qui
390 # avait ete laisse de cote par la construction
391 # Comme on est en construction, on ne devrait pas avoir a detruire de bloc
392 # si on vient d un xml invalide, il faudra probablement traiter les blocs deja crees
393 # reste_val est au niveau du MCCompo, il faut donc tout parcourir
394 #print ('dans deepUpdateConditionBlocApresCreation pour', self.nom)
395 if self.reste_val != {} : self.buildMcApresGlobalEnCreation()
396 for mcobj in self.mcListe:
397 if mcobj.nature=="MCList" :
399 obj.deepUpdateConditionBlocApresCreation()
401 elif hasattr(mcobj,"deepUpdateConditionBlocApresCreation"):
402 mcobj.deepUpdateConditionBlocApresCreation()
403 mcobj.state='modified'
404 self.state='modified'
406 def deepUpdateConditionBloc(self):
408 Parcourt l'arborescence des mcobject et realise l'update
409 des blocs conditionnels par appel de la methode updateConditionBloc
411 self._updateConditionBloc()
412 for mcobj in self.mcListe:
413 if hasattr(mcobj,"deepUpdateConditionBloc"):
414 mcobj.deepUpdateConditionBloc()
415 mcobj.state='modified'
416 if self.nature == 'PROCEDURE' :
417 if self.doitEtreRecalculee :
418 self.doitEtreRecalculee = False
419 self.deepUpdateConditionBloc()
421 def updateConditionBloc(self):
423 Realise l'update des blocs conditionnels fils de self
426 self._updateConditionBloc()
427 if self.parent:self.parent.updateConditionBloc()
429 def _updateConditionBloc(self):
431 Realise l'update des blocs conditionnels fils de self
433 dict = self.creeDictCondition(self.mcListe,condition=1)
434 doitEtreReecrit=False
435 for k,v in self.definition.entites.items():
436 if v.label != 'BLOC' :continue
437 globs= self.jdc and self.jdc.condition_context or {}
438 bloc=self.getChild(k,restreint = 'oui')
439 presence=v.verifPresence(dict,globs)
440 if presence and not bloc:
441 # le bloc doit etre present
442 # mais le bloc n'est pas present et il doit etre cree
443 pos=self.getIndexChild(k)
444 self.addEntite(k,pos)
445 #print ("AJOUT",k,pos)
446 if not presence and bloc:
447 # le bloc devrait etre absent
448 # le bloc est present : il faut l'enlever
449 #print ("SUPPRESSION BLOC",k,bloc)
450 self.suppEntite(bloc)
453 def verifConditionBloc(self):
456 Evalue les conditions de tous les blocs fils possibles
457 (en fonction du catalogue donc de la definition) de self
458 et retourne deux listes :
459 - la premiere contient les noms des blocs a rajouter
460 - la seconde contient les noms des blocs a supprimer
464 dict = self.creeDictCondition(self.mcListe,condition=1)
465 for k,v in self.definition.entites.items():
467 globs= self.jdc and self.jdc.condition_context or {}
468 if v.verifPresence(dict,globs):
469 # le bloc doit etre present
470 if not self.getChild(k,restreint = 'oui'):
471 # le bloc n'est pas present et il doit etre cree
472 liste_ajouts.append(k)
474 # le bloc doit etre absent
475 if self.getChild(k,restreint = 'oui'):
476 # le bloc est present : il faut l'enlever
477 liste_retraits.append(k)
478 return liste_ajouts,liste_retraits
480 def verifExistenceSd(self):
482 Verifie que les structures de donnees utilisees dans self existent bien dans le contexte
483 avant etape, sinon enleve la reference a ces concepts
485 for motcle in self.mcListe :
486 motcle.verifExistenceSd()
488 def updateMcGlobal(self):
490 Met a jour les mots cles globaux enregistres dans l'etape parente
491 et dans le jdc parent.
492 Un mot cle compose ne peut pas etre global. Il se contente de passer
493 la requete a ses fils.
495 for motcle in self.mcListe :
496 motcle.updateMcGlobal()
498 def deleteMcGlobal(self):
499 for motcle in self.mcListe :
500 motcle.deleteMcGlobal()
501 # PN : je ne comprends pas les 4 lignes suivantes
502 # du coup je les vire
503 # surtout en dehors dans le for ?
507 # motcle.updateMcGlobal()
511 def supprimeUserAssd(self):
512 for objUserAssd in self.userASSDCrees:
513 objUserAssd.supprime(self)
515 def initModifUp(self):
516 Validation.V_MCCOMPO.MCCOMPO.initModifUp(self)
517 CONNECTOR.Emit(self,"valid")