Salome HOME
premiere version
[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 import string,types,sys
23 from copy import copy
24 import traceback
25
26 from Extensions.i18n import tr
27 from Noyau.N_MCLIST import MCList
28 from Noyau.N_MCSIMP import MCSIMP
29 from Noyau.N_MCFACT import MCFACT
30 from Noyau.N_MCBLOC import MCBLOC
31 import I_OBJECT
32 import Validation
33
34 import CONNECTOR
35
36 class MCCOMPO(I_OBJECT.OBJECT):
37   def getlabeltext(self):
38     """ 
39        Retourne le label de self 
40        utilise pour l'affichage dans l'arbre
41     """
42     return self.nom
43
44   def get_liste_mc_ordonnee(self,liste,dico):
45     """
46        Retourne la liste ordonnee (suivant le catalogue) des mots-cles
47        d'une entite composee dont le chemin complet est donne sous forme
48        d'une liste du type :ETAPE + MCFACT ou MCBLOC + ...
49        il faut encore rearranger cette liste (certains mots-cles deja
50        presents ne doivent plus etre proposes, regles ...)
51     """
52     return self.filtre_liste_mc(self.get_liste_mc_ordonnee_brute(liste,dico))
53
54   def get_liste_mc_ordonnee_brute(self,liste,dico):
55     """
56        Retourne la liste ordonnee (suivant le catalogue) BRUTE des mots-cles
57        d'une entite composee dont le chemin complet est donne sous forme
58        d'une liste du type :ETAPE + MCFACT ou MCBLOC + ...
59     """
60     for arg in liste:
61         objet_cata = dico[arg]
62         dico=objet_cata.entites
63         l=[]
64         specifique=0
65         for obj in dico.keys() :
66             if not(hasattr(dico[obj],'cache')) or dico[obj].cache==0 :
67                l.append(obj)
68             else :
69                specifique=1
70         if specifique == 1 : return l    
71     return objet_cata.ordre_mc
72
73   def filtre_liste_mc(self,liste_brute):
74     """ 
75        Cette methode est appelee par EFICAS afin de presenter a 
76        l'utilisateur la liste des enfants possibles de self actualisee 
77        en fonction du contexte de self. En clair, sont supprimes de la
78        liste des possibles (fournie par la definition), les mots-cles
79        exclus par les regles de self et les mots-cles ne pouvant plus 
80        etre repetes
81     """
82     liste = copy(liste_brute)
83     liste_mc_presents = self.liste_mc_presents()
84     # on enleve les mots-cles non permis par les regles
85     for regle in self.definition.regles:
86        # la methode purge_liste est a developper pour chaque regle qui
87        # influe sur la liste de choix a proposer a l'utilisateur
88        # --> EXCLUS,UN_PARMI,PRESENT_ABSENT
89        liste = regle.purge_liste(liste,liste_mc_presents)
90     # on enleve les mots-cles dont l'occurrence est deja atteinte
91     liste_copy = copy(liste)
92     for k in liste_copy:
93       objet = self.get_child(k,restreint = 'oui')
94       if objet != None :
95         # l'objet est deja present : il faut distinguer plusieurs cas
96         if isinstance(objet,MCSIMP):
97           # un mot-cle simple ne peut pas etre repete
98           liste.remove(k)
99         elif isinstance(objet,MCBLOC):
100           # un bloc conditionnel ne doit pas apparaitre dans la liste de choix
101           liste.remove(k)
102         elif isinstance(objet,MCFACT):
103           # un mot-cle facteur ne peut pas etre repete plus de self.max fois
104           if objet.definition.max == 1:
105             liste.remove(k)
106         elif isinstance(objet,MCList):
107           try :
108             nb_occur_maxi = objet[0].definition.max
109             if len(objet) >= nb_occur_maxi:
110               liste.remove(k)
111           except:
112             pass
113         else :
114           #XXX CCAR : les MCNUPLET ne sont pas traites
115           if CONTEXT.debug : print '   ',k,' est un objet de type inconnu :',type(objet)
116       else :
117         # l'objet est absent : on enleve de la liste les blocs
118         if self.definition.entites[k].statut=='c' :
119           liste.remove(k)
120         if self.definition.entites[k].label=='BLOC':
121           liste.remove(k)
122     # Pour corriger les exces qui pourraient etre commis dans la methode purge_liste
123     # des regles, on essaie de compenser comme suit :
124     # on ajoute les mots cles facteurs presents dont l'occurence n'est pas atteinte
125     for k in liste_mc_presents:
126       if k in liste:continue
127       objet = self.get_child(k,restreint = 'oui')
128       if isinstance(objet,MCFACT):
129           # un mot-cle facteur ne peut pas etre repete plus de self.max fois
130           if objet.definition.max > 1:
131              liste.append(k)
132       elif isinstance(objet,MCList):
133           nb_occur_maxi = objet[0].definition.max
134           if len(objet) < nb_occur_maxi:
135               liste.append(k)
136     return liste
137
138   def liste_mc_presents(self):
139     """ 
140        Retourne la liste des noms des mots-cles fils de self presents construite
141        a partir de self.mc_liste 
142     """
143     l=[]
144     for v in self.mc_liste:
145       k=v.nom
146       l.append(k)
147     return l
148
149   def get_index_child(self,nom_fils):
150       """
151         Retourne l'index dans la liste des fils de self du nouveau fils de nom nom_fils
152         Permet de savoir a quelle position il faut ajouter un nouveau mot-cle
153       """
154       cata_ordonne = self.jdc.cata_ordonne_dico
155       liste_noms_mc_ordonnee = self.get_liste_mc_ordonnee_brute(self.get_genealogie(),cata_ordonne)
156       liste_noms_mc_presents = self.liste_mc_presents()
157       index=0
158       for nom in liste_noms_mc_ordonnee:
159           if nom == nom_fils:break
160           if nom not in liste_noms_mc_presents :continue
161           index=index+1
162       return index
163           
164   def ordonne_liste_mc(self,liste_mc_a_ordonner,liste_noms_mc_ordonnee):
165     """
166         Retourne liste_mc_a_ordonner ordonnee suivant l'ordre 
167         donne par liste_noms_mc_ordonnee
168     """
169     liste = []
170     # on transforme liste_a_ordonner en un dictionnaire (plus facile a consulter)
171     d_mc = {}
172     for mc in liste_mc_a_ordonner:
173       d_mc[mc.nom]=mc
174     # on construit la liste des objets ordonnes
175     for nom_mc in liste_noms_mc_ordonnee:
176       if d_mc.has_key(nom_mc):
177         liste.append(d_mc.get(nom_mc))
178     # on la retourne
179     return liste
180
181   def suppentite(self,objet) :
182     """ 
183         Supprime le fils 'objet' de self : 
184         Retourne 1 si la suppression a pu etre effectuee,
185         Retourne 0 dans le cas contraire
186     """
187     if not objet in self.mc_liste:
188        # Impossible de supprimer objet. Il n'est pas dans mc_liste
189        return 0
190
191     self.init_modif()
192     self.mc_liste.remove(objet)
193     CONNECTOR.Emit(self,"supp",objet)
194     objet.delete_mc_global()
195     objet.update_condition_bloc()
196     objet.supprime()
197     self.etape.modified()
198     self.fin_modif()
199     return 1
200
201   def isoblig(self):
202       return 0
203
204   def addentite(self,name,pos=None):
205       """ 
206           Ajoute le mot-cle name a la liste des mots-cles de
207           l'objet MCCOMPOSE
208       """
209       self.init_modif()
210       if type(name)==types.StringType :
211         # on est en mode creation d'un motcle 
212         if self.ispermis(name) == 0 : return 0
213         objet=self.definition.entites[name](val=None,nom=name,parent=self)
214       else :
215         # dans ce cas on est en mode copie d'un motcle
216         objet = name
217         # Appel de la methode qui fait le menage dans les references
218         # sur les concepts produits (verification que les concepts existent
219         # dans le contexte de la commande courante).
220         objet.verif_existence_sd()
221
222       # On verifie que l'ajout d'objet est autorise
223       if self.ispermis(objet) == 0:
224         self.jdc.appli.affiche_alerte(tr("Erreur"),
225                                       tr("L'objet %(v_1)s ne peut  etre un fils de %(v_2)s",\
226                                       {'v_1': objet.nom, 'v_2': self.nom}))
227         self.fin_modif()
228         return 0
229
230       # On cherche s'il existe deja un mot cle de meme nom
231       old_obj = self.get_child(objet.nom,restreint = 'oui')
232       if not old_obj :
233          # on normalize l'objet
234          objet=objet.normalize()
235          # Le mot cle n'existe pas encore. On l'ajoute a la position
236          # demandee (pos)
237          if pos == None :
238            self.mc_liste.append(objet)
239          else :
240            self.mc_liste.insert(pos,objet)
241          # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
242          objet.reparent(self)
243          CONNECTOR.Emit(self,"add",objet)
244          objet.update_mc_global()
245          objet.update_condition_bloc()
246          self.fin_modif()
247          return objet
248       else:
249          # Le mot cle existe deja. Si le mot cle est repetable,
250          # on cree une liste d'objets. Dans le cas contraire,
251          # on emet un message d'erreur.
252          if not old_obj.isrepetable():
253             self.jdc.appli.affiche_alerte(tr("Erreur"),tr("L'objet %s ne peut pas etre repete", objet.nom))
254             self.fin_modif()
255             return 0
256          else:
257             # une liste d'objets de meme type existe deja
258             old_obj.addentite(objet)
259             self.fin_modif()
260             return old_obj
261
262   def ispermis(self,fils):
263     """ 
264         Retourne 1 si l'objet de nom nom_fils 
265         est bien permis, cad peut bien etre un fils de self, 
266         Retourne 0 sinon 
267     """
268     if type(fils) == types.StringType :
269       # on veut juste savoir si self peut avoir un fils de nom 'fils'
270       if self.definition.entites.has_key(fils):
271         return 1
272       else :
273         return 0
274     elif type(fils) == types.InstanceType:
275       # fils est un objet (commande,mcf,mclist)
276       # on est dans le cas d'une tentative de copie de l'objet
277       # on veut savoir si l'objet peut bien etre un fils de self :
278       # la verification du nom de suffit pas (plusieurs commandes
279       # ont le meme mot-cle facteur AFFE ... et c'est l'utilisateur
280       # qui choisit le pere d'ou un risque d'erreur)
281       if not self.definition.entites.has_key(fils.nom):
282         return 0
283       else:
284         if fils.parent.nom != self.nom : return 0
285       return 1
286
287   def update_concept(self,sd):
288     for child in self.mc_liste :
289         child.update_concept(sd)
290
291   def delete_concept(self,sd):
292     """ 
293         Inputs :
294            - sd=concept detruit
295         Fonction :
296         Mettre a jour les fils de l objet suite a la disparition du
297         concept sd
298         Seuls les mots cles simples MCSIMP font un traitement autre que 
299         de transmettre aux fils
300     """
301     for child in self.mc_liste :
302       child.delete_concept(sd)
303
304   def replace_concept(self,old_sd,sd):
305     """
306         Inputs :
307            - old_sd=concept remplace
308            - sd = nouveau concept
309         Fonction :
310         Mettre a jour les fils de l objet suite au remplacement  du
311         concept old_sd
312     """
313     for child in self.mc_liste :
314       child.replace_concept(old_sd,sd)
315
316   def get_liste_mc_inconnus(self):
317      """
318      Retourne la liste des mots-cles inconnus dans self
319      """
320      l_mc = []
321      if self.reste_val != {}:
322         for k,v in self.reste_val.items() :
323             l_mc.append([self,k,v])
324      for child in self.mc_liste :
325         if child.isvalid() : continue
326         l_child = child.get_liste_mc_inconnus()
327         for mc in l_child:
328            l = [self]
329            l.extend(mc)
330            l_mc.append(l)
331      return l_mc
332
333   def deep_update_condition_bloc(self):
334      """
335         Parcourt l'arborescence des mcobject et realise l'update 
336         des blocs conditionnels par appel de la methode update_condition_bloc
337      """
338      self._update_condition_bloc()
339      for mcobj in self.mc_liste:
340         if hasattr(mcobj,"deep_update_condition_bloc"):
341            mcobj.deep_update_condition_bloc()
342
343   def update_condition_bloc(self):
344      """
345         Realise l'update des blocs conditionnels fils de self
346         et propage au parent
347      """
348      self._update_condition_bloc()
349      if self.parent:self.parent.update_condition_bloc()
350
351   def _update_condition_bloc(self):
352      """
353         Realise l'update des blocs conditionnels fils de self
354      """
355      dict = self.cree_dict_condition(self.mc_liste,condition=1)
356      for k,v in self.definition.entites.items():
357         if v.label != 'BLOC' :continue
358         globs= self.jdc and self.jdc.condition_context or {}
359         bloc=self.get_child(k,restreint = 'oui')
360         presence=v.verif_presence(dict,globs)
361         if presence and not bloc:
362            # le bloc doit etre present
363            # mais le bloc n'est pas present et il doit etre cree
364            #print "AJOUT BLOC",k
365            pos=self.get_index_child(k)
366            self.addentite(k,pos)
367         if not presence and bloc:
368            # le bloc devrait etre absent
369            # le bloc est present : il faut l'enlever
370            #print "SUPPRESSION BLOC",k,bloc
371            self.suppentite(bloc)
372
373   def verif_condition_bloc(self):
374     """ 
375         Evalue les conditions de tous les blocs fils possibles 
376         (en fonction du catalogue donc de la definition) de self
377         et retourne deux listes :
378           - la premiere contient les noms des blocs a rajouter
379           - la seconde contient les noms des blocs a supprimer
380     """
381     liste_ajouts = []
382     liste_retraits = []
383     dict = self.cree_dict_condition(self.mc_liste,condition=1)
384     for k,v in self.definition.entites.items():
385       if v.label=='BLOC' :
386         globs= self.jdc and self.jdc.condition_context or {}
387         if v.verif_presence(dict,globs):
388           # le bloc doit etre present
389           if not self.get_child(k,restreint = 'oui'):
390             # le bloc n'est pas present et il doit etre cree
391             liste_ajouts.append(k)
392         else :
393           # le bloc doit etre absent
394           if self.get_child(k,restreint = 'oui'):
395             # le bloc est present : il faut l'enlever
396             liste_retraits.append(k)
397     return liste_ajouts,liste_retraits
398
399   def verif_existence_sd(self):
400      """
401         Verifie que les structures de donnees utilisees dans self existent bien dans le contexte
402         avant etape, sinon enleve la reference a ces concepts
403      """
404      for motcle in self.mc_liste :
405          motcle.verif_existence_sd()
406
407   def update_mc_global(self):
408      """
409         Met a jour les mots cles globaux enregistres dans l'etape parente 
410         et dans le jdc parent.
411         Un mot cle compose ne peut pas etre global. Il se contente de passer
412         la requete a ses fils.
413      """
414      for motcle in self.mc_liste :
415          motcle.update_mc_global()
416
417   def delete_mc_global(self):
418      for motcle in self.mc_liste :
419          motcle.delete_mc_global()
420      try :
421          motcle.update_mc_global()
422      except :
423         pass
424
425   def init_modif_up(self):
426     Validation.V_MCCOMPO.MCCOMPO.init_modif_up(self)
427     CONNECTOR.Emit(self,"valid")
428