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