Salome HOME
TypeInstance and basestring
[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 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.verifExistenceSd()
235
236       # On verifie que l'ajout d'objet est autorise
237       if self.ispermis(objet) == 0:
238         self.jdc.appli.afficheAlerte(tr("Erreur"),
239                                       tr("L'objet %(v_1)s ne peut  etre un fils de %(v_2)s",\
240                                       {'v_1': objet.nom, 'v_2': self.nom}))
241         self.finModif()
242         return 0
243
244       # On cherche s'il existe deja un mot cle de meme nom
245       old_obj = self.getChild(objet.nom,restreint = 'oui')
246       if not old_obj :
247          # on normalize l'objet
248          objet=objet.normalize()
249          # Le mot cle n'existe pas encore. On l'ajoute a la position
250          # demandee (pos)
251          if pos == None :
252            self.mcListe.append(objet)
253          else :
254            self.mcListe.insert(pos,objet)
255          # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
256          objet.reparent(self)
257          #objet.addPyxbObject(self.findRangObjetDsArbre(objet))
258          CONNECTOR.Emit(self,"add",objet)
259          objet.updateMcGlobal()
260          objet.updateConditionBloc()
261          self.finModif()
262          return objet
263       else:
264          # Le mot cle existe deja. Si le mot cle est repetable,
265          # on cree une liste d'objets. Dans le cas contraire,
266          # on emet un message d'erreur.
267          if not old_obj.isRepetable():
268             self.jdc.appli.afficheAlerte(tr("Erreur"),tr("L'objet %s ne peut pas etre repete", objet.nom))
269             self.finModif()
270             return 0
271          else:
272             # une liste d'objets de meme type existe deja
273             old_obj.addEntite(objet)
274             self.finModif()
275             return old_obj
276
277   def ispermis(self,fils):
278     """ 
279         Retourne 1 si l'objet de nom nom_fils 
280         est bien permis, cad peut bien etre un fils de self, 
281         Retourne 0 sinon 
282     """
283     if type(fils) == bytes or type(fils) == str :
284       # on veut juste savoir si self peut avoir un fils de nom 'fils'
285       if fils in self.definition.entites:
286         return 1
287       else :
288         return 0
289     #elif type(fils) == types.InstanceType:
290     elif isinstance(fils,object):
291       # fils est un objet (commande,mcf,mclist)
292       # on est dans le cas d'une tentative de copie de l'objet
293       # on veut savoir si l'objet peut bien etre un fils de self :
294       # la verification du nom de suffit pas (plusieurs commandes
295       # ont le meme mot-cle facteur AFFE ... et c'est l'utilisateur
296       # qui choisit le pere d'ou un risque d'erreur)
297       if not fils.nom in self.definition.entites:
298         return 0
299       else:
300         if fils.parent.nom != self.nom : return 0
301       return 1
302
303   def updateConcept(self,sd):
304     for child in self.mcListe :
305         child.updateConcept(sd)
306
307   def deleteConcept(self,sd):
308     """ 
309         Inputs :
310            - sd=concept detruit
311         Fonction :
312         Mettre a jour les fils de l objet suite a la disparition du
313         concept sd
314         Seuls les mots cles simples MCSIMP font un traitement autre que 
315         de transmettre aux fils
316     """
317     for child in self.mcListe :
318       child.deleteConcept(sd)
319
320   def replaceConcept(self,old_sd,sd):
321     """
322         Inputs :
323            - old_sd=concept remplace
324            - sd = nouveau concept
325         Fonction :
326         Mettre a jour les fils de l objet suite au remplacement  du
327         concept old_sd
328     """
329     for child in self.mcListe :
330       child.replaceConcept(old_sd,sd)
331
332   def getListeMcInconnus(self):
333      """
334      Retourne la liste des mots-cles inconnus dans self
335      """
336      l_mc = []
337      if self.reste_val != {}:
338         for k,v in self.reste_val.items() :
339             l_mc.append([self,k,v])
340      for child in self.mcListe :
341         if child.isValid() : continue
342         l_child = child.getListeMcInconnus()
343         for mc in l_child:
344            l = [self]
345            l.extend(mc)
346            l_mc.append(l)
347      return l_mc
348
349   def deepUpdateConditionBloc(self):
350      """
351         Parcourt l'arborescence des mcobject et realise l'update 
352         des blocs conditionnels par appel de la methode updateConditionBloc
353      """
354      self._updateConditionBloc()
355      for mcobj in self.mcListe:
356         if hasattr(mcobj,"deepUpdateConditionBloc"):
357            mcobj.deepUpdateConditionBloc()
358
359   def updateConditionBloc(self):
360      """
361         Realise l'update des blocs conditionnels fils de self
362         et propage au parent
363      """
364      self._updateConditionBloc()
365      if self.parent:self.parent.updateConditionBloc()
366
367   def _updateConditionBloc(self):
368      """
369         Realise l'update des blocs conditionnels fils de self
370      """
371      dict = self.creeDictCondition(self.mcListe,condition=1)
372      for k,v in self.definition.entites.items():
373         if v.label != 'BLOC' :continue
374         globs= self.jdc and self.jdc.condition_context or {}
375         bloc=self.getChild(k,restreint = 'oui')
376         presence=v.verifPresence(dict,globs)
377         if presence and not bloc:
378            # le bloc doit etre present
379            # mais le bloc n'est pas present et il doit etre cree
380            #print "AJOUT BLOC",k
381            pos=self.getIndexChild(k)
382            self.addEntite(k,pos)
383         if not presence and bloc:
384            # le bloc devrait etre absent
385            # le bloc est present : il faut l'enlever
386            #print "SUPPRESSION BLOC",k,bloc
387            self.suppEntite(bloc)
388
389   def verifConditionBloc(self):
390     """ 
391         Evalue les conditions de tous les blocs fils possibles 
392         (en fonction du catalogue donc de la definition) de self
393         et retourne deux listes :
394           - la premiere contient les noms des blocs a rajouter
395           - la seconde contient les noms des blocs a supprimer
396     """
397     liste_ajouts = []
398     liste_retraits = []
399     dict = self.creeDictCondition(self.mcListe,condition=1)
400     for k,v in self.definition.entites.items():
401       if v.label=='BLOC' :
402         globs= self.jdc and self.jdc.condition_context or {}
403         if v.verifPresence(dict,globs):
404           # le bloc doit etre present
405           if not self.getChild(k,restreint = 'oui'):
406             # le bloc n'est pas present et il doit etre cree
407             liste_ajouts.append(k)
408         else :
409           # le bloc doit etre absent
410           if self.getChild(k,restreint = 'oui'):
411             # le bloc est present : il faut l'enlever
412             liste_retraits.append(k)
413     return liste_ajouts,liste_retraits
414
415   def verifExistenceSd(self):
416      """
417         Verifie que les structures de donnees utilisees dans self existent bien dans le contexte
418         avant etape, sinon enleve la reference a ces concepts
419      """
420      for motcle in self.mcListe :
421          motcle.verifExistenceSd()
422
423   def updateMcGlobal(self):
424      """
425         Met a jour les mots cles globaux enregistres dans l'etape parente 
426         et dans le jdc parent.
427         Un mot cle compose ne peut pas etre global. Il se contente de passer
428         la requete a ses fils.
429      """
430      for motcle in self.mcListe :
431          motcle.updateMcGlobal()
432
433   def deleteMcGlobal(self):
434      for motcle in self.mcListe :
435          motcle.deleteMcGlobal()
436      try :
437          motcle.updateMcGlobal()
438      except :
439          pass
440
441   def initModifUp(self):
442     Validation.V_MCCOMPO.MCCOMPO.initModifUp(self)
443     CONNECTOR.Emit(self,"valid")
444