Salome HOME
.gitignore: test hook.
[tools/eficas.git] / Ihm / I_MCCOMPO.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2017   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 findRangObjetDsArbre(self,objet) :
167   # uniquement pour Pyxb
168   # parcourt les Blocs
169       leRang=0
170       pos=self.mcListe.index(objet)
171       i=0
172       while (i+1) < pos :
173         leRang= leRang + self.mcListe[i].longueurDsArbre()
174         i=i+1
175       return leRang
176  
177
178   def ordonneListeMc(self,listeMc_a_ordonner,liste_noms_mc_ordonnee):
179     """
180         Retourne listeMc_a_ordonner ordonnee suivant l'ordre 
181         donne par liste_noms_mc_ordonnee
182     """
183     liste = []
184     # on transforme liste_a_ordonner en un dictionnaire (plus facile a consulter)
185     d_mc = {}
186     for mc in listeMc_a_ordonner:
187       d_mc[mc.nom]=mc
188     # on construit la liste des objets ordonnes
189     for nom_mc in liste_noms_mc_ordonnee:
190       if nom_mc in d_mc:
191         liste.append(d_mc.get(nom_mc))
192     # on la retourne
193     return liste
194
195   def suppEntite(self,objet) :
196     """ 
197         Supprime le fils 'objet' de self : 
198         Retourne 1 si la suppression a pu etre effectuee,
199         Retourne 0 dans le cas contraire
200     """
201     if not objet in self.mcListe:
202        # Impossible de supprimer objet. Il n'est pas dans mcListe
203        return 0
204
205     self.initModif()
206     #objet.deletePyxbObject()
207     self.mcListe.remove(objet)
208     CONNECTOR.Emit(self,"supp",objet)
209     objet.deleteMcGlobal()
210     objet.updateConditionBloc()
211     objet.supprime()
212     self.etape.modified()
213     self.finModif()
214     return 1
215
216   def isOblig(self):
217       return 0
218
219   def addEntite(self,name,pos=None):
220       """ 
221           Ajoute le mot-cle name a la liste des mots-cles de
222           l'objet MCCOMPOSE
223       """
224       self.initModif()
225       if type(name)==bytes or type(name) == str :
226         # on est en mode creation d'un motcle 
227         if self.ispermis(name) == 0 : return 0
228         objet=self.definition.entites[name](val=None,nom=name,parent=self)
229       else :
230         # dans ce cas on est en mode copie d'un motcle
231         # Appel de la methode qui fait le menage dans les references
232         # sur les concepts produits (verification que les concepts existent
233         # dans le contexte de la commande courante).
234         objet = name
235         objet.verifExistenceSd()
236
237       # On verifie que l'ajout d'objet est autorise
238       if self.ispermis(objet) == 0:
239         self.jdc.appli.afficheAlerte(tr("Erreur"),
240                                       tr("L'objet %(v_1)s ne peut  etre un fils de %(v_2)s",\
241                                       {'v_1': objet.nom, 'v_2': self.nom}))
242         self.finModif()
243         return 0
244
245       # On cherche s'il existe deja un mot cle de meme nom
246       old_obj = self.getChild(objet.nom,restreint = 'oui')
247       if not old_obj :
248          # on normalize l'objet
249          objet=objet.normalize()
250          # Le mot cle n'existe pas encore. On l'ajoute a la position
251          # demandee (pos)
252          if pos == None :
253            self.mcListe.append(objet)
254          else :
255            self.mcListe.insert(pos,objet)
256          # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
257          objet.reparent(self)
258          #objet.addPyxbObject(self.findRangObjetDsArbre(objet))
259          CONNECTOR.Emit(self,"add",objet)
260          objet.updateMcGlobal()
261          objet.updateConditionBloc()
262          self.finModif()
263          return objet
264       else:
265          # Le mot cle existe deja. Si le mot cle est repetable,
266          # on cree une liste d'objets. Dans le cas contraire,
267          # on emet un message d'erreur.
268          if not old_obj.isRepetable():
269             self.jdc.appli.afficheAlerte(tr("Erreur"),tr("L'objet %s ne peut pas etre repete", objet.nom))
270             self.finModif()
271             return 0
272          else:
273             # une liste d'objets de meme type existe deja
274             old_obj.addEntite(objet)
275             self.finModif()
276             return old_obj
277
278   def ispermis(self,fils):
279     """ 
280         Retourne 1 si l'objet de nom nom_fils 
281         est bien permis, cad peut bien etre un fils de self, 
282         Retourne 0 sinon 
283     """
284     if type(fils) == bytes or type(fils) == str :
285       # on veut juste savoir si self peut avoir un fils de nom 'fils'
286       if fils in self.definition.entites:
287         return 1
288       else :
289         return 0
290     #elif type(fils) == types.InstanceType:
291     elif isinstance(fils,object):
292       # fils est un objet (commande,mcf,mclist)
293       # on est dans le cas d'une tentative de copie de l'objet
294       # on veut savoir si l'objet peut bien etre un fils de self :
295       # la verification du nom de suffit pas (plusieurs commandes
296       # ont le meme mot-cle facteur AFFE ... et c'est l'utilisateur
297       # qui choisit le pere d'ou un risque d'erreur)
298       if not fils.nom in self.definition.entites:
299         return 0
300       else:
301         if fils.parent.nom != self.nom : return 0
302       return 1
303
304   def updateConcept(self,sd):
305     for child in self.mcListe :
306         child.updateConcept(sd)
307
308   def deleteConcept(self,sd):
309     """ 
310         Inputs :
311            - sd=concept detruit
312         Fonction :
313         Mettre a jour les fils de l objet suite a la disparition du
314         concept sd
315         Seuls les mots cles simples MCSIMP font un traitement autre que 
316         de transmettre aux fils
317     """
318     for child in self.mcListe :
319       child.deleteConcept(sd)
320
321   def replaceConcept(self,old_sd,sd):
322     """
323         Inputs :
324            - old_sd=concept remplace
325            - sd = nouveau concept
326         Fonction :
327         Mettre a jour les fils de l objet suite au remplacement  du
328         concept old_sd
329     """
330     for child in self.mcListe :
331       child.replaceConcept(old_sd,sd)
332
333   def getListeMcInconnus(self):
334      """
335      Retourne la liste des mots-cles inconnus dans self
336      """
337      l_mc = []
338      if self.reste_val != {}:
339         for k,v in self.reste_val.items() :
340             l_mc.append([self,k,v])
341      for child in self.mcListe :
342         if child.isValid() : continue
343         l_child = child.getListeMcInconnus()
344         for mc in l_child:
345            l = [self]
346            l.extend(mc)
347            l_mc.append(l)
348      return l_mc
349
350   def deepUpdateConditionBloc(self):
351      """
352         Parcourt l'arborescence des mcobject et realise l'update 
353         des blocs conditionnels par appel de la methode updateConditionBloc
354      """
355      self._updateConditionBloc()
356      for mcobj in self.mcListe:
357         if hasattr(mcobj,"deepUpdateConditionBloc"):
358            mcobj.deepUpdateConditionBloc()
359
360   def updateConditionBloc(self):
361      """
362         Realise l'update des blocs conditionnels fils de self
363         et propage au parent
364      """
365      self._updateConditionBloc()
366      if self.parent:self.parent.updateConditionBloc()
367
368   def _updateConditionBloc(self):
369      """
370         Realise l'update des blocs conditionnels fils de self
371      """
372      dict = self.creeDictCondition(self.mcListe,condition=1)
373      for k,v in self.definition.entites.items():
374         if v.label != 'BLOC' :continue
375         globs= self.jdc and self.jdc.condition_context or {}
376         bloc=self.getChild(k,restreint = 'oui')
377         presence=v.verifPresence(dict,globs)
378         if presence and not bloc:
379            # le bloc doit etre present
380            # mais le bloc n'est pas present et il doit etre cree
381            #print "AJOUT BLOC",k
382            pos=self.getIndexChild(k)
383            self.addEntite(k,pos)
384         if not presence and bloc:
385            # le bloc devrait etre absent
386            # le bloc est present : il faut l'enlever
387            #print "SUPPRESSION BLOC",k,bloc
388            self.suppEntite(bloc)
389
390   def verifConditionBloc(self):
391     """ 
392         Evalue les conditions de tous les blocs fils possibles 
393         (en fonction du catalogue donc de la definition) de self
394         et retourne deux listes :
395           - la premiere contient les noms des blocs a rajouter
396           - la seconde contient les noms des blocs a supprimer
397     """
398     liste_ajouts = []
399     liste_retraits = []
400     dict = self.creeDictCondition(self.mcListe,condition=1)
401     for k,v in self.definition.entites.items():
402       if v.label=='BLOC' :
403         globs= self.jdc and self.jdc.condition_context or {}
404         if v.verifPresence(dict,globs):
405           # le bloc doit etre present
406           if not self.getChild(k,restreint = 'oui'):
407             # le bloc n'est pas present et il doit etre cree
408             liste_ajouts.append(k)
409         else :
410           # le bloc doit etre absent
411           if self.getChild(k,restreint = 'oui'):
412             # le bloc est present : il faut l'enlever
413             liste_retraits.append(k)
414     return liste_ajouts,liste_retraits
415
416   def verifExistenceSd(self):
417      """
418         Verifie que les structures de donnees utilisees dans self existent bien dans le contexte
419         avant etape, sinon enleve la reference a ces concepts
420      """
421      for motcle in self.mcListe :
422          motcle.verifExistenceSd()
423
424   def updateMcGlobal(self):
425      """
426         Met a jour les mots cles globaux enregistres dans l'etape parente 
427         et dans le jdc parent.
428         Un mot cle compose ne peut pas etre global. Il se contente de passer
429         la requete a ses fils.
430      """
431      for motcle in self.mcListe :
432          motcle.updateMcGlobal()
433
434   def deleteMcGlobal(self):
435      for motcle in self.mcListe :
436          motcle.deleteMcGlobal()
437      try :
438          motcle.updateMcGlobal()
439      except :
440          pass
441
442   def initModifUp(self):
443     Validation.V_MCCOMPO.MCCOMPO.initModifUp(self)
444     CONNECTOR.Emit(self,"valid")
445