Salome HOME
b8b076bf1d3c4bf3ade6eeb0f8961f08aa535058
[tools/eficas.git] / Ihm / I_ETAPE.py
1 # -*- coding: utf-8 -*-
2 #            CONFIGURATION MANAGEMENT OF EDF VERSION
3 # ======================================================================
4 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
5 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
6 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
7 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
8 # (AT YOUR OPTION) ANY LATER VERSION.
9 #
10 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
11 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
12 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
13 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
14 #
15 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
16 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
17 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
18 #
19 #
20 # ======================================================================
21 """
22 """
23 # Modules Python
24 import sys,re
25 import string,types
26 from copy import copy
27
28 # Objet re pour controler les identificateurs Python
29 concept_re=re.compile(r'[a-zA-Z_]\w*$')
30
31 # import rajoutés suite à l'ajout de Build_sd --> à résorber
32 import traceback
33 import Noyau
34 from Noyau import N_Exception
35 from Noyau.N_Exception import AsException
36 import Validation
37 # fin import à résorber
38
39 # Modules EFICAS
40 import I_MCCOMPO
41 import CONNECTOR
42 from Extensions import commande_comm
43
44 class ETAPE(I_MCCOMPO.MCCOMPO):
45
46    def ident(self):
47       return self.nom
48
49    def get_sdname(self):
50       if CONTEXT.debug : print "SDNAME ",self.reuse,self.sd,self.sd.get_name()
51       sdname=''
52       if self.reuse != None:
53         sdname= self.reuse.get_name()
54       else:
55         if self.sd:sdname=self.sd.get_name()
56       if string.find(sdname,'sansnom') != -1 or string.find(sdname,'SD_') != -1:
57         # dans le cas où la SD est 'sansnom' ou 'SD_' on retourne la chaîne vide
58         return ''
59       return sdname
60
61    def is_reentrant(self):
62       """ 
63           Indique si la commande est reentrante
64       """
65       return self.definition.reentrant == 'o' 
66
67    def init_modif(self):
68       """
69          Met l'état de l'étape à : modifié
70          Propage la modification au parent
71       """
72       # init_modif doit etre appelé avant de réaliser une modification
73       # La validité devra etre recalculée apres cette modification
74       # mais dans l'appel à fin_modif pour préserver l'état modified
75       # de tous les objets entre temps
76       #print "init_modif",self,self.parent
77       self.state = 'modified'
78       if self.parent:
79         self.parent.init_modif()
80
81    def fin_modif(self):
82       """
83           Méthode appelée une fois qu'une modification a été faite afin de 
84           déclencher d'éventuels traitements post-modification
85           ex : INCLUDE et POURSUITE
86           Ne pas mettre de traitement qui risque d'induire des recursions (soit a peu pres rien)
87       """
88       CONNECTOR.Emit(self,"valid")
89       if self.parent:
90         self.parent.fin_modif()
91
92    def nomme_sd(self,nom) :
93       """
94           Cette méthode a pour fonction de donner un nom (nom) au concept 
95           produit par l'étape (self).
96             - si le concept n'existe pas, on essaye de le créer (à condition que l'étape soit valide ET non réentrante)
97             - si il existe déjà, on le renomme et on répercute les changements dans les autres étapes    
98           Les valeurs de retour sont :
99             - 0 si le nommage n'a pas pu etre mené à son terme,
100             - 1 dans le cas contraire
101       """
102       # Le nom d'un concept doit etre un identificateur Python (toujours vrai ?)
103       if not concept_re.match(nom):
104          return 0,"Un nom de concept doit etre un identificateur Python"
105
106       if len(nom) > 8 and self.jdc.definition.code == 'ASTER':
107         return 0,"Nom de concept trop long (maxi 8 caractères)"
108
109       self.init_modif()
110       #
111       # On verifie d'abord si les mots cles sont valides
112       #
113       if not self.isvalid(sd='non') : return 0,"Nommage du concept refusé : l'opérateur n'est pas valide"
114       #
115       # Cas particulier des opérateurs obligatoirement réentrants
116       #
117       if self.definition.reentrant == 'o':
118         self.sd = self.reuse = self.jdc.get_sd_avant_etape(nom,self)
119         if self.sd != None :
120           self.sdnom=self.sd.nom
121           self.fin_modif()
122           return 1,"Concept existant"
123         else:
124           return 0,"Opérateur réentrant mais concept non existant"
125       #
126       # Cas particulier des opérateurs facultativement réentrants
127       #
128       old_reuse=None
129       if self.definition.reentrant == 'f' :
130         sd = self.jdc.get_sd_avant_etape(nom,self)
131         if sd != None :
132           # FR : il faut tester que la sd trouvée est du bon type !!!!!!!!!!!!!!!!!
133           if isinstance(sd,self.get_type_produit()) :
134              self.sd = self.reuse = sd
135              self.sdnom = sd.nom
136              self.fin_modif()
137              return 1,"Opérateur facultativement réentrant et concept existant trouvé"
138           else:
139              return 0,"Concept déjà existant et de mauvais type"
140         else :
141           # il faut enlever le lien vers une SD existante car si on passe ici
142           # cela signifie que l'opérateur n'est pas utilisé en mode réentrant.
143           # Si on ne fait pas cela, on risque de modifier une SD produite par un autre opérateur
144           if self.reuse :
145              old_reuse=self.reuse
146              self.sd = self.reuse = self.sdnom = None
147       #
148       # On est dans le cas ou l'opérateur n'est pas réentrant ou est facultativement reentrant
149       # mais est utilisé en mode non réentrant
150       #
151       if self.sd == None :
152           #Pas de concept produit preexistant
153           if self.parent.get_sd_autour_etape(nom,self):
154             # Un concept de ce nom existe dans le voisinage de l'etape courante
155             # On retablit l'ancien concept reentrant s'il existait
156             if old_reuse:
157                self.sd=self.reuse=old_reuse
158                self.sdnom=old_reuse.nom
159             return 0,"Nommage du concept refuse : un concept de meme nom existe deja"
160           else:
161             # Il n'existe pas de concept de ce nom dans le voisinage de l'etape courante
162             # On peut donc créer le concept retourné.
163             # Il est créé sans nom mais enregistré dans la liste des concepts existants
164             try:
165                self.get_sd_prod()
166                # Renommage du concept : Il suffit de changer son attribut nom pour le nommer
167                self.sd.nom = nom
168                self.sdnom=nom
169                self.parent.update_concept_after_etape(self,self.sd)
170                self.fin_modif()
171                return 1,"Nommage du concept effectué"
172             except:
173                return 0,"Nommage impossible"+str(sys.exc_info()[1])
174       else :
175           #Un concept produit preexiste
176           old_nom=self.sd.nom
177           if string.find(old_nom,'sansnom') :
178             # Dans le cas où old_nom == sansnom, isvalid retourne 0 alors que ...
179             # par contre si le concept existe et qu'il s'appelle sansnom c'est que l'étape est valide
180             # on peut donc le nommer sans test préalable
181             if self.parent.get_sd_autour_etape(nom,self):
182               return 0,"Nommage du concept refuse : un concept de meme nom existe deja"
183             else:
184               # Renommage du concept : Il suffit de changer son attribut nom pour le nommer
185               self.sd.nom=nom
186               self.sdnom=nom
187               self.parent.update_concept_after_etape(self,self.sd)
188               self.fin_modif()
189               return 1,"Nommage du concept effectué"
190           if self.isvalid() :
191             # Normalement l appel de isvalid a mis a jour le concept produit (son type)
192             # Il suffit de spécifier l attribut nom de sd pour le nommer si le nom n est pas
193             # deja attribué
194             if self.parent.get_sd_autour_etape(nom,self):
195               return 0,"Nommage du concept refuse : un concept de meme nom existe deja"
196             else:
197               # Renommage du concept : Il suffit de changer son attribut nom pour le nommer
198               self.sd.nom=nom
199               self.sdnom=nom
200               self.parent.update_concept_after_etape(self,self.sd)
201               self.fin_modif()
202               return 1,"Nommage du concept effectué"
203           else:
204             # Normalement on ne devrait pas passer ici
205             return 0,'Normalement on ne devrait pas passer ici'
206
207    def get_sdprods(self,nom_sd):
208       """ 
209          Fonction : retourne le concept produit par l etape de nom nom_sd
210          s il existe sinon None
211       """
212       if self.sd:
213         if self.sd.nom == nom_sd:return self.sd
214
215    def active(self):
216       """
217           Rend l'etape courante active.
218           Il faut ajouter la sd si elle existe au contexte global du JDC
219           et à la liste des sd
220       """
221       if self.actif:return
222       self.actif = 1
223       self.init_modif()
224       if self.sd :
225         try:
226           self.jdc.append_sdprod(self.sd)
227         except:
228           pass
229       CONNECTOR.Emit(self,"add",None)
230       CONNECTOR.Emit(self,"valid")
231
232    def inactive(self):
233       """
234           Rend l'etape courante inactive
235           Il faut supprimer la sd du contexte global du JDC
236           et de la liste des sd
237       """
238       self.actif = 0
239       self.init_modif()
240       if self.sd :
241          self.jdc.del_sdprod(self.sd)
242          self.jdc.delete_concept_after_etape(self,self.sd)
243       CONNECTOR.Emit(self,"supp",None)
244       CONNECTOR.Emit(self,"valid")
245
246    def control_sdprods(self,d):
247       """
248           Cette methode doit verifier que ses concepts produits ne sont pas
249           deja definis dans le contexte
250           Si c'est le cas, les concepts produits doivent etre supprimes
251       """
252       #print "control_sdprods",d.keys(),self.sd and self.sd.nom,self.nom
253       if self.sd:
254         if d.has_key(self.sd.nom):
255            # Le concept est deja defini
256            if self.reuse and self.reuse is d[self.sd.nom]:
257               # Le concept est reutilise : situation normale
258               pass
259            else:
260               # Redefinition du concept, on l'annule
261               #XXX on pourrait simplement annuler son nom pour conserver les objets
262               # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
263               self.init_modif()
264               sd=self.sd
265               self.sd=self.reuse=self.sdnom=None
266               #supprime les references a sd dans les etapes suivantes
267               self.parent.delete_concept_after_etape(self,sd)
268               self.fin_modif()
269
270    def supprime_sdprod(self,sd):
271       """
272          Supprime le concept produit sd s'il est produit par l'etape
273       """
274       if sd is not self.sd:return
275       if self.sd != None :
276          self.init_modif()
277          self.parent.del_sdprod(sd)
278          self.sd=None
279          self.fin_modif()
280          self.parent.delete_concept(sd)
281
282    def supprime_sdprods(self):
283       """ 
284             Fonction:
285             Lors d'une destruction d'etape, detruit tous les concepts produits
286             Un opérateur n a qu un concept produit 
287             Une procedure n'en a aucun
288             Une macro en a en général plus d'un
289       """
290       #print "supprime_sdprods",self
291       if self.reuse is self.sd :return
292       # l'étape n'est pas réentrante
293       # le concept retourné par l'étape est à supprimer car il était 
294       # créé par l'étape
295       if self.sd != None :
296          self.parent.del_sdprod(self.sd)
297          self.parent.delete_concept(self.sd)
298
299    def close(self):
300       return
301
302    def update_concept(self,sd):
303       for child in self.mc_liste :
304           child.update_concept(sd)
305
306    def delete_concept(self,sd):
307       """ 
308           Inputs :
309              - sd=concept detruit
310           Fonction :
311           Mettre a jour les mots cles de l etape et eventuellement 
312           le concept produit si reuse
313           suite à la disparition du concept sd
314           Seuls les mots cles simples MCSIMP font un traitement autre 
315           que de transmettre aux fils
316       """
317       if self.reuse and self.reuse == sd:
318         self.sd=self.reuse=None
319         self.init_modif()
320       for child in self.mc_liste :
321         child.delete_concept(sd)
322
323    def replace_concept(self,old_sd,sd):
324       """
325           Inputs :
326              - old_sd=concept remplace
327              - sd = nouveau concept 
328           Fonction :
329           Mettre a jour les mots cles de l etape et eventuellement
330           le concept produit si reuse
331           suite au remplacement  du concept old_sd
332       """
333       if self.reuse and self.reuse == old_sd:
334         self.sd=self.reuse=sd
335         self.init_modif()
336       for child in self.mc_liste :
337         child.replace_concept(old_sd,sd)
338
339    def reset_context(self):
340       pass
341
342    def get_noms_sd_oper_reentrant(self):
343       """ 
344           Retourne la liste des noms de concepts utilisés à l'intérieur de la commande
345           qui sont du type que peut retourner cette commande 
346       """
347       liste_sd = self.get_sd_utilisees()
348       l_noms = []
349       if type(self.definition.sd_prod) == types.FunctionType:
350         d=self.cree_dict_valeurs(self.mc_liste)
351         try:
352           classe_sd_prod = apply(self.definition.sd_prod,(),d)
353         except:
354           return []
355       else:
356         classe_sd_prod = self.definition.sd_prod
357       for sd in liste_sd :
358         if sd.__class__ is classe_sd_prod : l_noms.append(sd.nom)
359       l_noms.sort()
360       return l_noms
361
362    def get_genealogie(self):
363       """ 
364           Retourne la liste des noms des ascendants de l'objet self
365           en s'arretant à la première ETAPE rencontrée
366       """
367       return [self.nom]
368
369    def verif_existence_sd(self):
370      """
371         Vérifie que les structures de données utilisées dans self existent bien dans le contexte
372         avant étape, sinon enlève la référence à ces concepts
373      """
374      #print "verif_existence_sd",self.sd
375      for motcle in self.mc_liste :
376          motcle.verif_existence_sd()
377
378    def update_mc_global(self):
379      """
380         Met a jour les mots cles globaux enregistrés dans l'étape
381         et dans le jdc parent.
382         Une etape ne peut pas etre globale. Elle se contente de passer
383         la requete a ses fils apres avoir reinitialisé le dictionnaire 
384         des mots cles globaux.
385      """
386      self.mc_globaux={}
387      I_MCCOMPO.MCCOMPO.update_mc_global(self)
388
389    def update_condition_bloc(self):
390      """
391         Realise l'update des blocs conditionnels fils de self
392      """
393      self._update_condition_bloc()
394
395    def get_objet_commentarise(self,format):
396       """
397           Cette méthode retourne un objet commande commentarisée
398           representant la commande self
399       """
400       import generator
401       g=generator.plugins[format]()
402       texte_commande = g.gener(self,format='beautifie')
403       # Il faut enlever la première ligne vide de texte_commande que
404       # rajoute le generator
405       #rebut,texte_commande = string.split(texte_commande,'\n',1)
406       # on construit l'objet COMMANDE_COMM repésentatif de self mais non
407       # enregistré dans le jdc (pas ajouté dans jdc.etapes)
408       parent=self.parent
409       pos=self.parent.etapes.index(self)
410       commande_comment = commande_comm.COMMANDE_COMM(texte=texte_commande,
411                                                      reg='non',
412                                                      parent=parent)
413       self.parent.suppentite(self)
414       parent.addentite(commande_comment,pos)
415
416       return commande_comment
417
418    def modified(self):
419       """Le contenu de l'etape (mots cles, ...) a ete modifie"""
420       if self.nom=="DETRUIRE":
421         self.parent.control_context_apres(self)
422
423      
424 #ATTENTION SURCHARGE: a garder en synchro ou a reintegrer dans le Noyau
425    def Build_sd(self,nom):
426       """
427            Methode de Noyau surchargee pour poursuivre malgre tout
428            si une erreur se produit pendant la creation du concept produit
429       """
430       try:
431          sd=Noyau.N_ETAPE.ETAPE.Build_sd(self,nom)
432       except AsException,e:
433          # Une erreur s'est produite lors de la construction du concept
434          # Comme on est dans EFICAS, on essaie de poursuivre quand meme
435          # Si on poursuit, on a le choix entre deux possibilités :
436          # 1. on annule la sd associée à self
437          # 2. on la conserve mais il faut la retourner
438          # En plus il faut rendre coherents sdnom et sd.nom
439          self.sd=None
440          self.sdnom=None
441          self.state="unchanged"
442          self.valid=0
443
444       return self.sd
445
446 #ATTENTION SURCHARGE: cette methode doit etre gardée en synchronisation avec Noyau
447    def make_register(self):
448       """
449          Initialise les attributs jdc, id, niveau et réalise les
450          enregistrements nécessaires
451          Pour EFICAS, on tient compte des niveaux
452          Surcharge la methode make_register du package Noyau
453       """
454       if self.parent :
455          self.jdc = self.parent.get_jdc_root()
456          self.id=   self.parent.register(self)
457          self.UserError=self.jdc.UserError
458          if self.definition.niveau :
459             # La définition est dans un niveau. En plus on
460             # l'enregistre dans le niveau
461             self.nom_niveau_definition = self.definition.niveau.nom
462             self.niveau = self.parent.dict_niveaux[self.nom_niveau_definition]
463             self.niveau.register(self)
464          else:
465             # La définition est au niveau global
466             self.nom_niveau_definition = 'JDC'
467             self.niveau=self.parent
468       else:
469          self.jdc = self.parent =None
470          self.id=None
471          self.niveau=None
472          self.UserError="UserError"
473
474    def report(self):
475      cr= Validation.V_ETAPE.ETAPE.report(self)
476      #rafraichissement de la validité de l'etape (probleme avec l'ordre dans les macros : etape puis mots cles)
477      self.isvalid()
478      return cr
479