Salome HOME
bug 53033
[tools/eficas.git] / Ihm / I_ETAPE.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 # Modules Python
23 import sys,re
24 import string,types
25 from copy import copy
26
27 from Extensions.i18n import tr
28 from Extensions.eficas_exception import EficasException
29
30 # Objet re pour controler les identificateurs Python
31 concept_re=re.compile(r'[a-zA-Z_]\w*$')
32
33 # import rajoute suite a l'ajout de Build_sd --> a resorber
34 import traceback
35 import Noyau
36 from Noyau import N_Exception
37 from Noyau.N_Exception import AsException
38 import Validation
39 # fin import a resorber
40
41 # Modules EFICAS
42 import I_MCCOMPO
43 import CONNECTOR
44 from Extensions import commande_comm
45
46 class ETAPE(I_MCCOMPO.MCCOMPO):
47
48    def ident(self):
49       return self.nom
50
51    def get_sdname(self):
52       #print "SDNAME ",self.reuse,self.sd,self.sd.get_name()
53       if CONTEXT.debug : 
54           print "SDNAME ",  self.reuse,  self.sd,  self.sd.get_name()
55       sdname=''
56       if self.reuse != None:
57         sdname= self.reuse.get_name()
58       else:
59         if self.sd:sdname=self.sd.get_name()
60       if string.find(sdname,'sansnom') != -1 or string.find(sdname,'SD_') != -1:
61         # dans le cas ou la SD est 'sansnom' ou 'SD_' on retourne la chaine vide
62         return ''
63       return sdname
64
65    def is_reentrant(self):
66       """ 
67           Indique si la commande est reentrante
68       """
69       return self.definition.reentrant == 'o' 
70
71    def init_modif(self):
72       """
73          Met l'etat de l'etape a : modifie
74          Propage la modification au parent
75       """
76       # init_modif doit etre appele avant de realiser une modification
77       # La validite devra etre recalculee apres cette modification
78       # mais dans l'appel a fin_modif pour preserver l'etat modified
79       # de tous les objets entre temps
80       #print "init_modif",self,self.parent
81       self.state = 'modified'
82       if self.parent:
83         self.parent.init_modif()
84
85    def fin_modif(self):
86       """
87           Methode appelee une fois qu'une modification a ete faite afin de 
88           declencher d'eventuels traitements post-modification
89           ex : INCLUDE et POURSUITE
90           Ne pas mettre de traitement qui risque d'induire des recursions (soit a peu pres rien)
91       """
92       CONNECTOR.Emit(self,"valid")
93       if self.parent:
94         self.parent.fin_modif()
95
96    def nomme_sd(self,nom) :
97       """
98           Cette methode a pour fonction de donner un nom (nom) au concept 
99           produit par l'etape (self).
100             - si le concept n'existe pas, on essaye de le creer a condition que l'etape soit valide ET non reentrante)
101             - si il existe dea, on le renomme et on repercute les changements dans les autres etapes    
102           Les valeurs de retour sont :
103             - 0 si le nommage n'a pas pu etre menea son terme,
104             - 1 dans le cas contraire
105       """
106       # Le nom d'un concept doit etre un identificateur Python (toujours vrai ?)
107       if not concept_re.match(nom):
108          return 0, tr("Un nom de concept doit etre un identificateur Python")
109
110       #if len(nom) > 8 and self.jdc.definition.code == 'ASTER':
111       #  return 0, tr("Nom de concept trop long (maxi 8 caracteres)")
112
113       self.init_modif()
114       #
115       # On verifie d'abord si les mots cles sont valides
116       #
117       if not self.isvalid(sd='non') : return 0,"Nommage du concept refuse : l'operateur n'est pas valide"
118       #
119       # Cas particulier des operateurs obligatoirement reentrants
120       #
121       if self.definition.reentrant == 'o':
122         self.sd = self.reuse = self.jdc.get_sd_avant_etape(nom,self)
123         if self.sd != None :
124           self.sdnom=self.sd.nom
125           self.fin_modif()
126           return 1, tr("Concept existant")
127         else:
128           return 0, tr("Operateur reentrant mais concept non existant")
129       #
130       # Cas particulier des operateurs facultativement reentrants
131       #
132       old_reuse=None
133       if self.definition.reentrant == 'f' :
134         sd = self.jdc.get_sd_avant_etape(nom,self)
135         if sd != None :
136           if isinstance(sd,self.get_type_produit()) :
137              self.sd = self.reuse = sd
138              self.sdnom = sd.nom
139              self.fin_modif()
140              return 1, tr("Operateur reentrant et concept existant trouve")
141           else:
142              return 0, tr("Concept deja existant et de mauvais type")
143         else :
144           # il faut enlever le lien vers une SD existante car si on passe ici
145           # cela signifie que l'operateur n'est pas utilise en mode reentrant.
146           # Si on ne fait pas cela, on risque de modifier une SD produite par un autre operateur
147           if self.reuse :
148              old_reuse=self.reuse
149              self.sd = self.reuse = self.sdnom = None
150       #
151       # On est dans le cas ou l'operateur n'est pas reentrant ou est facultativement reentrant
152       # mais est utilise en mode non reentrant
153       #
154       if self.sd == None :
155           #Pas de concept produit preexistant
156           if self.parent.get_sd_autour_etape(nom,self):
157             # Un concept de ce nom existe dans le voisinage de l'etape courante
158             # On retablit l'ancien concept reentrant s'il existait
159             if old_reuse:
160                self.sd=self.reuse=old_reuse
161                self.sdnom=old_reuse.nom
162             return 0, tr("Nommage du concept refuse : un concept de meme nom existe deja")
163           else:
164             # Il n'existe pas de concept de ce nom dans le voisinage de l'etape courante
165             # On peut donc creer le concept retourne
166             # Il est cree sans nom mais enregistre dans la liste des concepts existants
167             try:
168                self.get_sd_prod()
169                # Renommage du concept : Il suffit de changer son attribut nom pour le nommer
170                self.sd.nom = nom
171                self.sdnom=nom
172                self.parent.update_concept_after_etape(self,self.sd)
173                self.fin_modif()
174                return 1, tr("Nommage du concept effectue")
175             except:
176                return 0, tr("Nommage impossible %s", str(sys.exc_info()[1]))
177       else :
178           #Un concept produit preexiste
179           old_nom=self.sd.nom
180           if string.find(old_nom,'sansnom') :
181             # Dans le cas ou old_nom == sansnom, isvalid retourne 0 alors que ...
182             # par contre si le concept existe et qu'il s'appelle sansnom c'est que l'etape est valide
183             # on peut donc le nommer sans test prealable
184             if self.parent.get_sd_autour_etape(nom,self):
185               return 0, tr("Nommage du concept refuse : un concept de meme nom existe deja")
186             else:
187               # Renommage du concept : Il suffit de changer son attribut nom pour le nommer
188               self.sd.nom=nom
189               self.sdnom=nom
190               self.parent.update_concept_after_etape(self,self.sd)
191               self.fin_modif()
192               return 1, tr("Nommage du concept effectue")
193           if self.isvalid() :
194             # Normalement l appel de isvalid a mis a jour le concept produit (son type)
195             # Il suffit de specifier l attribut nom de sd pour le nommer si le nom n est pas
196             # deja attribue
197             if self.parent.get_sd_autour_etape(nom,self):
198               return 0, tr("Nommage du concept refuse : un concept de meme nom existe deja")
199             else:
200               # Renommage du concept : Il suffit de changer son attribut nom pour le nommer
201               self.sd.nom=nom
202               self.sdnom=nom
203               self.parent.update_concept_after_etape(self,self.sd)
204               self.fin_modif()
205               return 1, tr("Nommage du concept effectue")
206           else:
207             # Normalement on ne devrait pas passer ici
208             return 0, 'Normalement on ne devrait pas passer ici'
209
210    def get_sdprods(self,nom_sd):
211       """ 
212          Fonction : retourne le concept produit par l etape de nom nom_sd
213          s il existe sinon None
214       """
215       if self.sd:
216         if self.sd.nom == nom_sd:return self.sd
217
218    def active(self):
219       """
220           Rend l'etape courante active.
221           Il faut ajouter la sd si elle existe au contexte global du JDC
222           et a la liste des sd
223       """
224       if self.actif:return
225       self.actif = 1
226       self.init_modif()
227       if self.sd :
228         try:
229           self.jdc.append_sdprod(self.sd)
230         except:
231           pass
232       CONNECTOR.Emit(self,"add",None)
233       CONNECTOR.Emit(self,"valid")
234
235    def inactive(self):
236       """
237           Rend l'etape courante inactive
238           Il faut supprimer la sd du contexte global du JDC
239           et de la liste des sd
240       """
241       self.actif = 0
242       self.init_modif()
243       if self.sd :
244          self.jdc.del_sdprod(self.sd)
245          self.jdc.delete_concept_after_etape(self,self.sd)
246       CONNECTOR.Emit(self,"supp",None)
247       CONNECTOR.Emit(self,"valid")
248
249    def control_sdprods(self,d):
250       """
251           Cette methode doit verifier que ses concepts produits ne sont pas
252           deja definis dans le contexte
253           Si c'est le cas, les concepts produits doivent etre supprimes
254       """
255       #print "control_sdprods",d.keys(),self.sd and self.sd.nom,self.nom
256       if self.sd:
257         if d.has_key(self.sd.nom):
258            # Le concept est deja defini
259            if self.reuse and self.reuse is d[self.sd.nom]:
260               # Le concept est reutilise : situation normale
261               pass
262            else:
263               # Redefinition du concept, on l'annule
264               #XXX on pourrait simplement annuler son nom pour conserver les objets
265               # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
266               self.init_modif()
267               sd=self.sd
268               self.sd=self.reuse=self.sdnom=None
269               #supprime les references a sd dans les etapes suivantes
270               self.parent.delete_concept_after_etape(self,sd)
271               self.fin_modif()
272
273    def supprime_sdprod(self,sd):
274       """
275          Supprime le concept produit sd s'il est produit par l'etape
276       """
277       if sd is not self.sd:return
278       if self.sd != None :
279          self.init_modif()
280          self.parent.del_sdprod(sd)
281          self.sd=None
282          self.fin_modif()
283          self.parent.delete_concept(sd)
284
285    def supprime_sdprods(self):
286       """ 
287             Fonction:
288             Lors d'une destruction d'etape, detruit tous les concepts produits
289             Un operateur n a qu un concept produit 
290             Une procedure n'en a aucun
291             Une macro en a en general plus d'un
292       """
293       #print "supprime_sdprods",self
294       if self.reuse is self.sd :return
295       # l'etape n'est pas reentrante
296       # le concept retourne par l'etape est a supprimer car il etait 
297       # cree par l'etape
298       if self.sd != None :
299          self.parent.del_sdprod(self.sd)
300          self.parent.delete_concept(self.sd)
301
302    def close(self):
303       return
304
305    def update_concept(self,sd):
306       for child in self.mc_liste :
307           child.update_concept(sd)
308
309    def delete_concept(self,sd):
310       """ 
311           Inputs :
312              - sd=concept detruit
313           Fonction :
314           Mettre a jour les mots cles de l etape et eventuellement 
315           le concept produit si reuse
316           suite a la disparition du concept sd
317           Seuls les mots cles simples MCSIMP font un traitement autre 
318           que de transmettre aux fils
319       """
320       if self.reuse and self.reuse == sd:
321         self.sd=self.reuse=None
322         self.init_modif()
323       for child in self.mc_liste :
324         child.delete_concept(sd)
325
326    def replace_concept(self,old_sd,sd):
327       """
328           Inputs :
329              - old_sd=concept remplace
330              - sd = nouveau concept 
331           Fonction :
332           Mettre a jour les mots cles de l etape et eventuellement
333           le concept produit si reuse
334           suite au remplacement  du concept old_sd
335       """
336       if self.reuse and self.reuse == old_sd:
337         self.sd=self.reuse=sd
338         self.init_modif()
339       for child in self.mc_liste :
340         child.replace_concept(old_sd,sd)
341
342    def reset_context(self):
343       pass
344
345    def get_noms_sd_oper_reentrant(self):
346       """ 
347           Retourne la liste des noms de concepts utilisesa l'interieur de la commande
348           qui sont du type que peut retourner cette commande 
349       """
350       liste_sd = self.get_sd_utilisees()
351       l_noms = []
352       if type(self.definition.sd_prod) == types.FunctionType:
353         d=self.cree_dict_valeurs(self.mc_liste)
354         try:
355           classe_sd_prod = apply(self.definition.sd_prod,(),d)
356         except:
357           return []
358       else:
359         classe_sd_prod = self.definition.sd_prod
360       for sd in liste_sd :
361         if sd.__class__ is classe_sd_prod : l_noms.append(sd.nom)
362       l_noms.sort()
363       return l_noms
364
365    def get_genealogie(self):
366       """ 
367           Retourne la liste des noms des ascendants de l'objet self
368           en s'arretant a la premiere ETAPE rencontree
369       """
370       return [self.nom]
371
372    def verif_existence_sd(self):
373      """
374         Verifie que les structures de donnees utilisees dans self existent bien dans le contexte
375         avant etape, sinon enleve la referea ces concepts
376      """
377      #print "verif_existence_sd",self.sd
378      for motcle in self.mc_liste :
379          motcle.verif_existence_sd()
380
381    def update_mc_global(self):
382      """
383         Met a jour les mots cles globaux enregistres dans l'etape
384         et dans le jdc parent.
385         Une etape ne peut pas etre globale. Elle se contente de passer
386         la requete a ses fils apres avoir reinitialise le dictionnaire 
387         des mots cles globaux.
388      """
389      self.mc_globaux={}
390      I_MCCOMPO.MCCOMPO.update_mc_global(self)
391
392    def update_condition_bloc(self):
393      """
394         Realise l'update des blocs conditionnels fils de self
395      """
396      self._update_condition_bloc()
397
398    def get_objet_commentarise(self,format):
399       """
400           Cette methode retourne un objet commande commentarisee
401           representant la commande self
402       """
403       import generator
404       g=generator.plugins[format]()
405       texte_commande = g.gener(self,format='beautifie')
406       # Il faut enlever la premiere ligne vide de texte_commande que
407       # rajoute le generator
408       #rebut,texte_commande = string.split(texte_commande,'\n',1)
409       # on construit l'objet COMMANDE_COMM repesentatif de self mais non
410       # enregistre dans le jdc (pas ajoute dans jdc.etapes)
411       parent=self.parent
412       pos=self.parent.etapes.index(self)
413       # on ajoute une fin à la commande pour pouvoir en commenter 2
414       texte_commande+='\nFin Commentaire'
415       commande_comment = commande_comm.COMMANDE_COMM(texte=texte_commande,
416                                                      reg='non',
417                                                      parent=parent)
418       self.parent.suppentite(self)
419       parent.addentite(commande_comment,pos)
420
421       return commande_comment
422
423    def modified(self):
424       """Le contenu de l'etape (mots cles, ...) a ete modifie"""
425       if self.nom=="DETRUIRE":
426         self.parent.control_context_apres(self)
427
428
429      
430 #ATTENTION SURCHARGE: a garder en synchro ou a reintegrer dans le Noyau
431    def Build_sd(self,nom):
432       """
433            Methode de Noyau surchargee pour poursuivre malgre tout
434            si une erreur se produit pendant la creation du concept produit
435       """
436       try:
437          sd=Noyau.N_ETAPE.ETAPE.Build_sd(self,nom)
438       except AsException,e :
439          # Une erreur s'est produite lors de la construction du concept
440          # Comme on est dans EFICAS, on essaie de poursuivre quand meme
441          # Si on poursuit, on a le choix entre deux possibilites :
442          # 1. on annule la sd associee a self
443          # 2. on la conserve mais il faut la retourner
444          # En plus il faut rendre coherents sdnom et sd.nom
445          self.sd=None
446          self.sdnom=None
447          self.state="unchanged"
448          self.valid=0
449
450       return self.sd
451
452 #ATTENTION SURCHARGE: cette methode doit etre gardee en synchronisation avec Noyau
453    def make_register(self):
454       """
455          Initialise les attributs jdc, id, niveau et realise les
456          enregistrements necessaires
457          Pour EFICAS, on tient compte des niveaux
458          Surcharge la methode make_register du package Noyau
459       """
460       if self.parent :
461          self.jdc = self.parent.get_jdc_root()
462          self.id=   self.parent.register(self)
463          self.UserError=self.jdc.UserError
464          if self.definition.niveau :
465             # La definition est dans un niveau. En plus on
466             # l'enregistre dans le niveau
467             self.nom_niveau_definition = self.definition.niveau.nom
468             self.niveau = self.parent.dict_niveaux[self.nom_niveau_definition]
469             self.niveau.register(self)
470          else:
471             # La definition est au niveau global
472             self.nom_niveau_definition = 'JDC'
473             self.niveau=self.parent
474       else:
475          self.jdc = self.parent =None
476          self.id=None
477          self.niveau=None
478          self.UserError="UserError"
479
480    def report(self):
481      cr= Validation.V_ETAPE.ETAPE.report(self)
482      #rafraichisst de la validite de l'etape (probleme avec l'ordre dans les macros : etape puis mots cles)
483      self.isvalid()
484      if not self.isvalid() and self.nom == "INCLUDE" :
485         self.cr.fatal(('Etape : %s ligne : %r  %s'),
486         self.nom, self.appel[0],  tr("\n   Include Invalide. \n  ne sera pas pris en compte"))
487      return cr
488