Salome HOME
chgt Copyrigth
[tools/eficas.git] / Ihm / I_MCCOMPO.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2021   EDF R&D
3 #
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.
8 #
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.
13 #
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
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20 """
21 """
22 from __future__ import absolute_import
23 from __future__ import print_function
24 import string,types,sys
25 from copy import copy
26 import traceback
27
28 import Validation
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
35
36 from . import CONNECTOR
37
38 class MCCOMPO(I_OBJECT.OBJECT):
39   def getLabelText(self):
40     """ 
41        Retourne le label de self 
42        utilise pour l'affichage dans l'arbre
43     """
44     return tr(self.nom)
45
46   def getListeMcOrdonnee(self,liste,dico):
47     """
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 ...)
53     """
54     return self.filtreListeMc(self.getListeMcOrdonneeBrute(liste,dico))
55
56   def getListeMcOrdonneeBrute(self,liste,dico):
57     """
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 + ...
61     """
62     for arg in liste:
63         objet_cata = dico[arg]
64         dico=objet_cata.entites
65         l=[]
66         specifique=0
67         for obj in list(dico.keys()) :
68             if not(hasattr(dico[obj],'cache')) or dico[obj].cache==0 :
69                l.append(obj)
70             else :
71                specifique=1
72         if specifique == 1 : return l    
73     return objet_cata.ordre_mc
74
75   def filtreListeMc(self,liste_brute):
76     """ 
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 
82        etre repetes
83     """
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)
94     for k in liste_copy:
95       objet = self.getChild(k,restreint = 'oui')
96       if objet != None :
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
100           liste.remove(k)
101         elif isinstance(objet,MCBLOC):
102           # un bloc conditionnel ne doit pas apparaitre dans la liste de choix
103           liste.remove(k)
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:
107             liste.remove(k)
108         elif isinstance(objet,MCList):
109           try :
110             nb_occur_maxi = objet[0].definition.max
111             if len(objet) >= nb_occur_maxi:
112               liste.remove(k)
113           except:
114             pass
115         else :
116           #XXX CCAR : les MCNUPLET ne sont pas traites
117           if CONTEXT.debug : print('   ',k,' est un objet de type inconnu :',type(objet))
118       else :
119         # l'objet est absent : on enleve de la liste les blocs
120         if self.definition.entites[k].statut=='c' :
121           liste.remove(k)
122         if self.definition.entites[k].label=='BLOC':
123           liste.remove(k)
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:
133              liste.append(k)
134       elif isinstance(objet,MCList):
135           nb_occur_maxi = objet[0].definition.max
136           if len(objet) < nb_occur_maxi:
137               liste.append(k)
138     return liste
139
140   def listeMcPresents(self):
141     """ 
142        Retourne la liste des noms des mots-cles fils de self presents construite
143        a partir de self.mcListe 
144     """
145     l=[]
146     for v in self.mcListe:
147       k=v.nom
148       l.append(k)
149     return l
150
151   def getIndexChild(self,nom_fils):
152       """
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
155       """
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()
159       index=0
160       for nom in liste_noms_mc_ordonnee:
161           if nom == nom_fils:break
162           if nom not in liste_noms_mc_presents :continue
163           index=index+1
164       return index
165           
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]
171       leRang=0
172       positionDsLaListe=0
173       try :
174         positionDsLaListe=self.mcListe.index(objet)
175         positionDsLaListeDeFactSiFact =0
176       except :
177         for mc in self.mcListe:
178            if mc.nature == 'MCList':
179               try :
180                 positionDsLaListeDeFactSiFact=mc.index(objet)
181                 break
182               except :
183                 positionDsLaListe=positionDsLaListe+1
184            else : positionDsLaListe=positionDsLaListe+1
185       i=0
186       while i < positionDsLaListe :
187         leRang= leRang + self.mcListe[i].longueurDsArbre()
188         i=i+1
189       leRang=leRang+positionDsLaListeDeFactSiFact
190       return leRang
191  
192
193   def ordonneListeMc(self,listeMc_a_ordonner,liste_noms_mc_ordonnee):
194     """
195         Retourne listeMc_a_ordonner ordonnee suivant l'ordre 
196         donne par liste_noms_mc_ordonnee
197     """
198     liste = []
199     # on transforme liste_a_ordonner en un dictionnaire (plus facile a consulter)
200     d_mc = {}
201     for mc in listeMc_a_ordonner:
202       d_mc[mc.nom]=mc
203     # on construit la liste des objets ordonnes
204     for nom_mc in liste_noms_mc_ordonnee:
205       if nom_mc in d_mc:
206         liste.append(d_mc.get(nom_mc))
207     # on la retourne
208     return liste
209
210   def suppEntite(self,objet) :
211     """ 
212         Supprime le fils 'objet' de self : 
213         Retourne 1 si la suppression a pu etre effectuee,
214         Retourne 0 dans le cas contraire
215     """
216     if not objet in self.mcListe:
217        # Impossible de supprimer objet. Il n'est pas dans mcListe
218        return 0
219
220     self.initModif()
221     objet.delObjPyxb()
222 # PNPNPN a corriger
223     try :
224       objet.deleteRef()
225     except : pass
226     self.mcListe.remove(objet)
227     CONNECTOR.Emit(self,"supp",objet)
228     objet.deleteMcGlobal()
229     objet.updateConditionBloc()
230     objet.supprime()
231     self.etape.modified()
232     self.finModif()
233     return 1
234
235   def isOblig(self):
236       return 0
237
238   def addEntite(self,name,pos=None):
239       """ 
240           Ajoute le mot-cle name a la liste des mots-cles de
241           l'objet MCCOMPOSE
242       """
243       #print ('addEntite', name, pos)
244       self.initModif()
245       if type(name)==bytes or type(name) == str :
246         # on est en mode creation d'un motcle 
247         if self.ispermis(name) == 0 : return 0
248         objet=self.definition.entites[name](val=None,nom=name,parent=self)
249       else :
250         # dans ce cas on est en mode copie d'un motcle
251         objet = name
252         # Appel de la methode qui fait le menage dans les references
253         # sur les concepts produits (verification que les concepts existent
254         # dans le contexte de la commande courante).
255         objet.verifExistenceSd()
256
257       # On verifie que l'ajout d'objet est autorise
258       if self.ispermis(objet) == 0:
259         self.jdc.editor.afficheAlerte(tr("Erreur"),
260                                       tr("L'objet %(v_1)s ne peut  etre un fils de %(v_2)s",\
261                                       {'v_1': objet.nom, 'v_2': self.nom}))
262         self.finModif()
263         return 0
264
265       # On cherche s'il existe deja un mot cle de meme nom
266       old_obj = self.getChild(objet.nom,restreint = 'oui')
267       if not old_obj :
268          # on normalize l'objet
269          objet=objet.normalize()
270          # Le mot cle n'existe pas encore. On l'ajoute a la position
271          # demandee (pos)
272          if pos == None :
273            self.mcListe.append(objet)
274          else :
275            self.mcListe.insert(pos,objet)
276          # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
277          objet.reparent(self)
278          if  self.cata.modeleMetier :
279              if isinstance(objet,MCList): objet[0].addObjPyxb(self.chercheIndiceDsLeContenu(objet))
280              else : objet.addObjPyxb(self.chercheIndiceDsLeContenu(objet))
281          CONNECTOR.Emit(self,"add",objet)
282          objet.updateMcGlobal()
283          objet.updateConditionBloc()
284          self.finModif()
285          return objet
286       else:
287          # Le mot cle existe deja. Si le mot cle est repetable,
288          # on cree une liste d'objets. Dans le cas contraire,
289          # on emet un message d'erreur.
290          if not old_obj.isRepetable():
291             self.jdc.editor.afficheAlerte(tr("Erreur"),tr("L'objet %s ne peut pas etre repete", objet.nom))
292             self.finModif()
293             return 0
294          else:
295             # une liste d'objets de meme type existe deja
296             old_obj.addEntite(objet)
297             if  self.cata.modeleMetier :
298              if isinstance(objet,MCList): objet[0].addObjPyxb(self.chercheIndiceDsLeContenu(objet))
299              else : objet.addObjPyxb(self.chercheIndiceDsLeContenu(objet))
300             self.finModif()
301             return old_obj
302
303   def ispermis(self,fils):
304     """ 
305         Retourne 1 si l'objet de nom nom_fils 
306         est bien permis, cad peut bien etre un fils de self, 
307         Retourne 0 sinon 
308     """
309     if type(fils) == bytes or type(fils) == str  :
310       # on veut juste savoir si self peut avoir un fils de nom 'fils'
311       if fils in self.definition.entites:
312         return 1
313       else :
314         return 0
315     #elif type(fils) == types.InstanceType:
316     elif isinstance(fils,object):
317       # fils est un objet (commande,mcf,mclist)
318       # on est dans le cas d'une tentative de copie de l'objet
319       # on veut savoir si l'objet peut bien etre un fils de self :
320       # la verification du nom de suffit pas (plusieurs commandes
321       # ont le meme mot-cle facteur AFFE ... et c'est l'utilisateur
322       # qui choisit le pere d'ou un risque d'erreur)
323       if not fils.nom in self.definition.entites:
324         return 0
325       else:
326         if fils.parent.nom != self.nom : return 0
327       return 1
328
329   def updateConcept(self,sd):
330     for child in self.mcListe :
331         child.updateConcept(sd)
332
333   def deleteConcept(self,sd):
334     """ 
335         Inputs :
336            - sd=concept detruit
337         Fonction :
338         Mettre a jour les fils de l objet suite a la disparition du
339         concept sd
340         Seuls les mots cles simples MCSIMP font un traitement autre que 
341         de transmettre aux fils
342     """
343     for child in self.mcListe :
344       child.deleteConcept(sd)
345
346   def replaceConcept(self,old_sd,sd):
347     """
348         Inputs :
349            - old_sd=concept remplace
350            - sd = nouveau concept
351         Fonction :
352         Mettre a jour les fils de l objet suite au remplacement  du
353         concept old_sd
354     """
355     for child in self.mcListe :
356       child.replaceConcept(old_sd,sd)
357
358   def getListeMcInconnus(self):
359      """
360      Retourne la liste des mots-cles inconnus dans self
361      """
362      l_mc = []
363      if self.reste_val != {}:
364         for k,v in self.reste_val.items() :
365             l_mc.append([self,k,v])
366      for child in self.mcListe :
367         if child.isValid() : continue
368         l_child = child.getListeMcInconnus()
369         for mc in l_child:
370            l = [self]
371            l.extend(mc)
372            l_mc.append(l)
373      return l_mc
374
375   def deepUpdateConditionBlocApresCreation(self):
376      # idem deepUpdateConditionBloc sauf qu on cherche les MC qui
377      # avait ete laisse de cote par la construction
378      #print ('Ihm deepUpdateConditionBloc', self.nom, self.reste_val)
379      if self.reste_val != {} : self.buildMcApresGlobal()
380      for mcobj in self.mcListe:
381         if mcobj.nature=="MCList" :
382            for obj in mcobj : obj.deepUpdateConditionBlocApresCreation() 
383         elif hasattr(mcobj,"deepUpdateConditionBlocApresCreation"):
384            mcobj.deepUpdateConditionBlocApresCreation()
385      
386
387   def deepUpdateConditionBloc(self):
388      """
389         Parcourt l'arborescence des mcobject et realise l'update 
390         des blocs conditionnels par appel de la methode updateConditionBloc
391      """
392      self._updateConditionBloc()
393      for mcobj in self.mcListe:
394         if hasattr(mcobj,"deepUpdateConditionBloc"):
395            mcobj.deepUpdateConditionBloc()
396
397   def updateConditionBloc(self):
398      """
399         Realise l'update des blocs conditionnels fils de self
400         et propage au parent
401      """
402      self._updateConditionBloc()
403      if self.parent:self.parent.updateConditionBloc()
404
405   def _updateConditionBloc(self):
406      """
407         Realise l'update des blocs conditionnels fils de self
408      """
409      dict = self.creeDictCondition(self.mcListe,condition=1)
410      #print ('_updateConditionBloc', dict)
411      for k,v in self.definition.entites.items():
412         if v.label != 'BLOC' :continue
413         globs= self.jdc and self.jdc.condition_context or {}
414         bloc=self.getChild(k,restreint = 'oui')
415         presence=v.verifPresence(dict,globs)
416         if presence and not bloc:
417            # le bloc doit etre present
418            # mais le bloc n'est pas present et il doit etre cree
419            #print "AJOUT BLOC",k
420            pos=self.getIndexChild(k)
421            self.addEntite(k,pos)
422         if not presence and bloc:
423            # le bloc devrait etre absent
424            # le bloc est present : il faut l'enlever
425            #print "SUPPRESSION BLOC",k,bloc
426            self.suppEntite(bloc)
427
428   def verifConditionBloc(self):
429     """ 
430         Evalue les conditions de tous les blocs fils possibles 
431         (en fonction du catalogue donc de la definition) de self
432         et retourne deux listes :
433           - la premiere contient les noms des blocs a rajouter
434           - la seconde contient les noms des blocs a supprimer
435     """
436     liste_ajouts = []
437     liste_retraits = []
438     dict = self.creeDictCondition(self.mcListe,condition=1)
439     for k,v in self.definition.entites.items():
440       if v.label=='BLOC' :
441         globs= self.jdc and self.jdc.condition_context or {}
442         if v.verifPresence(dict,globs):
443           # le bloc doit etre present
444           if not self.getChild(k,restreint = 'oui'):
445             # le bloc n'est pas present et il doit etre cree
446             liste_ajouts.append(k)
447         else :
448           # le bloc doit etre absent
449           if self.getChild(k,restreint = 'oui'):
450             # le bloc est present : il faut l'enlever
451             liste_retraits.append(k)
452     return liste_ajouts,liste_retraits
453
454   def verifExistenceSd(self):
455      """
456         Verifie que les structures de donnees utilisees dans self existent bien dans le contexte
457         avant etape, sinon enleve la reference a ces concepts
458      """
459      for motcle in self.mcListe :
460          motcle.verifExistenceSd()
461
462   def updateMcGlobal(self):
463      """
464         Met a jour les mots cles globaux enregistres dans l'etape parente 
465         et dans le jdc parent.
466         Un mot cle compose ne peut pas etre global. Il se contente de passer
467         la requete a ses fils.
468      """
469      for motcle in self.mcListe :
470          motcle.updateMcGlobal()
471
472   def deleteMcGlobal(self):
473      for motcle in self.mcListe :
474          motcle.deleteMcGlobal()
475      try :
476          motcle.updateMcGlobal()
477      except :
478          pass
479
480   def initModifUp(self):
481     Validation.V_MCCOMPO.MCCOMPO.initModifUp(self)
482     CONNECTOR.Emit(self,"valid")
483
484