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