Salome HOME
.gitignore: test hook.
[tools/eficas.git] / Ihm / I_ETAPE.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 # 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 buildSd --> 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 getSdname(self):
54       #print "SDNAME ",self.reuse,self.sd,self.sd.getName()
55       if CONTEXT.debug : 
56           print(("SDNAME ",  self.reuse,  self.sd,  self.sd.getName()))
57       sdname=''
58       if self.reuse != None:
59         sdname= self.reuse.getName()
60       else:
61         if self.sd:sdname=self.sd.getName()
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 isReentrant(self):
68       """ 
69           Indique si la commande est reentrante
70       """
71       return self.definition.reentrant == 'o' 
72
73    def initModif(self):
74       """
75          Met l'etat de l'etape a : modifie
76          Propage la modification au parent
77       """
78       # initModif doit etre appele avant de realiser une modification
79       # La validite devra etre recalculee apres cette modification
80       # mais dans l'appel a finModif pour preserver l'etat modified
81       # de tous les objets entre temps
82       #print "initModif",self,self.parent
83       self.state = 'modified'
84       if self.parent:
85         self.parent.initModif()
86
87    def finModif(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.finModif()
97
98    def nommeSd(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       # pour eviter que le nom du concept soit le nom de la classe --> souci pour utiliser le concept
113       if (nom == self.definition.nom) : return  (0, tr("un concept de type ")+ nom + tr(" ne peut pas se nommer ") +  nom)
114       if ( nom in dir(self.jdc.cata)) : return (0, nom + tr("est un not reserve"))
115       #if (not isinstance(nom,str)) : return (0, tr("Le nom ") + nom + tr(" est un mot reserve"))
116       #if len(nom) > 8 and self.jdc.definition.code == 'ASTER':
117       #  return 0, tr("Nom de concept trop long (maxi 8 caracteres)")
118
119       self.initModif()
120       #
121       # On verifie d'abord si les mots cles sont valides
122       #
123       if not self.isValid(sd='non') : return 0,"Nommage du concept refuse : l'operateur n'est pas valide"
124       #
125       # Cas particulier des operateurs obligatoirement reentrants
126       #
127       if self.definition.reentrant == 'o':
128         self.sd = self.reuse = self.jdc.getSdAvantEtape(nom,self)
129         if self.sd != None :
130           self.sdnom=self.sd.nom
131           self.finModif()
132           return 1, tr("Concept existant")
133         else:
134           return 0, tr("Operateur reentrant mais concept non existant")
135       #
136       # Cas particulier des operateurs facultativement reentrants
137       #
138       old_reuse=None
139       if self.definition.reentrant == 'f' :
140         sd = self.jdc.getSdAvantEtape(nom,self)
141         if sd != None :
142           if isinstance(sd,self.getType_produit()) :
143              self.sd = self.reuse = sd
144              self.sdnom = sd.nom
145              self.finModif()
146              return 1, tr("Operateur reentrant et concept existant trouve")
147           else:
148              return 0, tr("Concept deja existant et de mauvais type")
149         else :
150           # il faut enlever le lien vers une SD existante car si on passe ici
151           # cela signifie que l'operateur n'est pas utilise en mode reentrant.
152           # Si on ne fait pas cela, on risque de modifier une SD produite par un autre operateur
153           if self.reuse :
154              old_reuse=self.reuse
155              self.sd = self.reuse = self.sdnom = None
156       #
157       # On est dans le cas ou l'operateur n'est pas reentrant ou est facultativement reentrant
158       # mais est utilise en mode non reentrant
159       #
160       if self.sd == None :
161           #Pas de concept produit preexistant
162           if self.parent.getSdAutourEtape(nom,self):
163             # Un concept de ce nom existe dans le voisinage de l'etape courante
164             # On retablit l'ancien concept reentrant s'il existait
165             if old_reuse:
166                self.sd=self.reuse=old_reuse
167                self.sdnom=old_reuse.nom
168             return 0, tr("Nommage du concept refuse : un concept de meme nom existe deja")
169           else:
170             # Il n'existe pas de concept de ce nom dans le voisinage de l'etape courante
171             # On peut donc creer le concept retourne
172             # Il est cree sans nom mais enregistre dans la liste des concepts existants
173             try:
174                self.getSdProd()
175                # Renommage du concept : Il suffit de changer son attribut nom pour le nommer
176                self.sd.nom = nom
177                self.sdnom=nom
178                self.parent.updateConceptAfterEtape(self,self.sd)
179                self.finModif()
180                return 1, tr("Nommage du concept effectue")
181             except:
182                return 0, tr("Nommage impossible %s", str(sys.exc_info()[1]))
183       else :
184           #Un concept produit preexiste
185           old_nom=self.sd.nom
186           if old_nom.find('sansnom') :
187             # Dans le cas ou old_nom == sansnom, isValid retourne 0 alors que ...
188             # par contre si le concept existe et qu'il s'appelle sansnom c'est que l'etape est valide
189             # on peut donc le nommer sans test prealable
190             if self.parent.getSdAutourEtape(nom,self):
191               return 0, tr("Nommage du concept refuse : un concept de meme nom existe deja")
192             else:
193               # Renommage du concept : Il suffit de changer son attribut nom pour le nommer
194               self.sd.nom=nom
195               self.sdnom=nom
196               self.parent.updateConceptAfterEtape(self,self.sd)
197               self.finModif()
198               return 1, tr("Nommage du concept effectue")
199           if self.isValid() :
200             # Normalement l appel de isValid a mis a jour le concept produit (son type)
201             # Il suffit de specifier l attribut nom de sd pour le nommer si le nom n est pas
202             # deja attribue
203             if self.parent.getSdAutourEtape(nom,self):
204               return 0, tr("Nommage du concept refuse : un concept de meme nom existe deja")
205             else:
206               # Renommage du concept : Il suffit de changer son attribut nom pour le nommer
207               self.sd.nom=nom
208               self.sdnom=nom
209               self.parent.updateConceptAfterEtape(self,self.sd)
210               self.finModif()
211               return 1, tr("Nommage du concept effectue")
212           else:
213             # Normalement on ne devrait pas passer ici
214             return 0, 'Normalement on ne devrait pas passer ici'
215
216    def getSdprods(self,nom_sd):
217       """ 
218          Fonction : retourne le concept produit par l etape de nom nom_sd
219          s il existe sinon None
220       """
221       if self.sd:
222         if self.sd.nom == nom_sd:return self.sd
223
224    def active(self):
225       """
226           Rend l'etape courante active.
227           Il faut ajouter la sd si elle existe au contexte global du JDC
228           et a la liste des sd
229       """
230       if self.actif:return
231       self.actif = 1
232       self.initModif()
233       if self.sd :
234         try:
235           self.jdc.appendSdProd(self.sd)
236         except:
237           pass
238       CONNECTOR.Emit(self,"add",None)
239       CONNECTOR.Emit(self,"valid")
240
241    def inactive(self):
242       """
243           Rend l'etape courante inactive
244           Il faut supprimer la sd du contexte global du JDC
245           et de la liste des sd
246       """
247       self.actif = 0
248       self.initModif()
249       if self.sd :
250          self.jdc.delSdprod(self.sd)
251          self.jdc.deleteConceptAfterEtape(self,self.sd)
252       CONNECTOR.Emit(self,"supp",None)
253       CONNECTOR.Emit(self,"valid")
254
255    def controlSdprods(self,d):
256       """
257           Cette methode doit verifier que ses concepts produits ne sont pas
258           deja definis dans le contexte
259           Si c'est le cas, les concepts produits doivent etre supprimes
260       """
261       #print "controlSdprods",d.keys(),self.sd and self.sd.nom,self.nom
262       if self.sd:
263         if self.sd.nom in d :
264            # Le concept est deja defini
265            if self.reuse and self.reuse is d[self.sd.nom]:
266               # Le concept est reutilise : situation normale
267               pass
268            else:
269               # Redefinition du concept, on l'annule
270               #XXX on pourrait simplement annuler son nom pour conserver les objets
271               # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
272               self.initModif()
273               sd=self.sd
274               self.sd=self.reuse=self.sdnom=None
275               #supprime les references a sd dans les etapes suivantes
276               self.parent.deleteConceptAfterEtape(self,sd)
277               self.finModif()
278
279    def supprimeSdprod(self,sd):
280       """
281          Supprime le concept produit sd s'il est produit par l'etape
282       """
283       if sd is not self.sd:return
284       if self.sd != None :
285          self.initModif()
286          self.parent.delSdprod(sd)
287          self.sd=None
288          self.finModif()
289          self.parent.deleteConcept(sd)
290
291    def supprimeSdProds(self):
292       """ 
293             Fonction:
294             Lors d'une destruction d'etape, detruit tous les concepts produits
295             Un operateur n a qu un concept produit 
296             Une procedure n'en a aucun
297             Une macro en a en general plus d'un
298       """
299       #print "supprimeSdProds",self
300       if self.reuse is self.sd :return
301       # l'etape n'est pas reentrante
302       # le concept retourne par l'etape est a supprimer car il etait 
303       # cree par l'etape
304       if self.sd != None :
305          self.parent.delSdprod(self.sd)
306          self.parent.deleteConcept(self.sd)
307
308    def close(self):
309       return
310
311    def updateConcept(self,sd):
312       for child in self.mcListe :
313           child.updateConcept(sd)
314
315    def deleteConcept(self,sd):
316       """ 
317           Inputs :
318              - sd=concept detruit
319           Fonction :
320           Mettre a jour les mots cles de l etape et eventuellement 
321           le concept produit si reuse
322           suite a la disparition du concept sd
323           Seuls les mots cles simples MCSIMP font un traitement autre 
324           que de transmettre aux fils
325       """
326       if self.reuse and self.reuse == sd:
327         self.sd=self.reuse=None
328         self.initModif()
329       for child in self.mcListe :
330         child.deleteConcept(sd)
331
332    def replaceConcept(self,old_sd,sd):
333       """
334           Inputs :
335              - old_sd=concept remplace
336              - sd = nouveau concept 
337           Fonction :
338           Mettre a jour les mots cles de l etape et eventuellement
339           le concept produit si reuse
340           suite au remplacement  du concept old_sd
341       """
342       if self.reuse and self.reuse == old_sd:
343         self.sd=self.reuse=sd
344         self.initModif()
345       for child in self.mcListe :
346         child.replaceConcept(old_sd,sd)
347
348    def resetContext(self):
349       pass
350
351    def getNomsSdOperReentrant(self):
352       """ 
353           Retourne la liste des noms de concepts utilisesa l'interieur de la commande
354           qui sont du type que peut retourner cette commande 
355       """
356       liste_sd = self.getSd_utilisees()
357       l_noms = []
358       if type(self.definition.sd_prod) == types.FunctionType:
359         d=self.creeDictValeurs(self.mcListe)
360         try:
361           classe_sd_prod = self.definition.sd_prod(*(), **d)
362         except:
363           return []
364       else:
365         classe_sd_prod = self.definition.sd_prod
366       for sd in liste_sd :
367         if sd.__class__ is classe_sd_prod : l_noms.append(sd.nom)
368       l_noms.sort()
369       return l_noms
370
371    def getGenealogiePrecise(self):
372       return [self.nom]
373
374    def getGenealogie(self):
375       """ 
376           Retourne la liste des noms des ascendants de l'objet self
377           en s'arretant a la premiere ETAPE rencontree
378       """
379       return [self.nom]
380
381    def verifExistenceSd(self):
382      """
383         Verifie que les structures de donnees utilisees dans self existent bien dans le contexte
384         avant etape, sinon enleve la referea ces concepts
385      """
386      #print "verifExistenceSd",self.sd
387      for motcle in self.mcListe :
388          motcle.verifExistenceSd()
389
390    def updateMcGlobal(self):
391      """
392         Met a jour les mots cles globaux enregistres dans l'etape
393         et dans le jdc parent.
394         Une etape ne peut pas etre globale. Elle se contente de passer
395         la requete a ses fils apres avoir reinitialise le dictionnaire 
396         des mots cles globaux.
397      """
398      self.mc_globaux={}
399      I_MCCOMPO.MCCOMPO.updateMcGlobal(self)
400
401    def updateConditionBloc(self):
402      """
403         Realise l'update des blocs conditionnels fils de self
404      """
405      self._updateConditionBloc()
406
407    def getObjetCommentarise(self,format):
408       """
409           Cette methode retourne un objet commande commentarisee
410           representant la commande self
411       """
412       import generator
413       g=generator.plugins[format]()
414       texte_commande = g.gener(self,format='beautifie')
415       # Il faut enlever la premiere ligne vide de texte_commande que
416       # rajoute le generator
417       # on construit l'objet COMMANDE_COMM repesentatif de self mais non
418       # enregistre dans le jdc (pas ajoute dans jdc.etapes)
419       parent=self.parent
420       pos=self.parent.etapes.index(self)
421       # on ajoute une fin à la commande pour pouvoir en commenter 2
422       texte_commande+='\nFin Commentaire'
423       commande_comment = commande_comm.COMMANDE_COMM(texte=texte_commande,
424                                                      reg='non',
425                                                      parent=parent)
426       self.parent.suppEntite(self)
427       parent.addEntite(commande_comment,pos)
428
429       return commande_comment
430
431    def modified(self):
432       """Le contenu de l'etape (mots cles, ...) a ete modifie"""
433       if self.nom=="DETRUIRE":
434         self.parent.controlContextApres(self)
435
436
437      
438 #ATTENTION SURCHARGE: a garder en synchro ou a reintegrer dans le Noyau
439    def buildSd(self,nom):
440       """
441            Methode de Noyau surchargee pour poursuivre malgre tout
442            si une erreur se produit pendant la creation du concept produit
443       """
444       try:
445          sd=Noyau.N_ETAPE.ETAPE.buildSd(self,nom)
446       except AsException as e :
447          # Une erreur s'est produite lors de la construction du concept
448          # Comme on est dans EFICAS, on essaie de poursuivre quand meme
449          # Si on poursuit, on a le choix entre deux possibilites :
450          # 1. on annule la sd associee a self
451          # 2. on la conserve mais il faut la retourner
452          # En plus il faut rendre coherents sdnom et sd.nom
453          self.sd=None
454          self.sdnom=None
455          self.state="unchanged"
456          self.valid=0
457
458       return self.sd
459
460 #ATTENTION SURCHARGE: cette methode doit etre gardee en synchronisation avec Noyau
461    def makeRegister(self):
462       """
463          Initialise les attributs jdc, id, niveau et realise les
464          enregistrements necessaires
465          Pour EFICAS, on tient compte des niveaux
466          Surcharge la methode makeRegister du package Noyau
467       """
468       if self.parent :
469          self.jdc = self.parent.getJdcRoot()
470          self.id=   self.parent.register(self)
471          self.UserError=self.jdc.UserError
472          if self.definition.niveau :
473             # La definition est dans un niveau. En plus on
474             # l'enregistre dans le niveau
475             self.nom_niveau_definition = self.definition.niveau.nom
476             self.niveau = self.parent.dict_niveaux[self.nom_niveau_definition]
477             self.niveau.register(self)
478          else:
479             # La definition est au niveau global
480             self.nom_niveau_definition = 'JDC'
481             self.niveau=self.parent
482       else:
483          self.jdc = self.parent =None
484          self.id=None
485          self.niveau=None
486          self.UserError="UserError"
487
488    def report(self):
489      cr= Validation.V_ETAPE.ETAPE.report(self)
490      #rafraichisst de la validite de l'etape (probleme avec l'ordre dans les macros : etape puis mots cles)
491      self.isValid()
492      if not self.isValid() and self.nom == "INCLUDE" :
493         self.cr.fatal(('Etape : %s ligne : %r  %s'),
494         self.nom, self.appel[0],  tr("\n   Include Invalide. \n  ne sera pas pris en compte"))
495      return cr
496