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