Salome HOME
import, formule, param et etc
[tools/eficas.git] / Ihm / I_FORM_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 import string,traceback,re
23 identifier = re.compile(r"^[^\d\W]\w*\Z", re.UNICODE)
24
25
26 from Extensions.i18n import tr
27 from I_MACRO_ETAPE import MACRO_ETAPE
28 from Extensions import interpreteur_formule
29 from Editeur import analyse_catalogue
30
31 analyse_catalogue.l_noms_commandes.append('FORM') # déclare le nom FORM à l'analyseur de catalogue
32
33
34 class FORM_ETAPE(MACRO_ETAPE):
35
36     interpreteur = interpreteur_formule.Interpreteur_Formule
37
38     def McBuild(self):
39         self.mc_liste=self.build_mc()
40         # on crée la liste des types autorisés (liste des noms de mots-clés
41         # simples dans le catalogue de FORMULE)
42         self.l_types_autorises = self.definition.entites.keys()
43         # en plus de la construction traditionnelle des fils de self
44         # il faut pour les FORMULE décortiquer l'expression ...
45         self.type_retourne,self.arguments,self.corps = self.analyse_formule()
46
47
48     def analyse_formule(self):
49         """
50         Cette méthode décortique l'expression de la FORMULE.
51         Elle retourne 3 valeurs:
52             - le type retourné par la FORMULE
53             - les arguments de la FORMULE
54             - le corps de la FORMULE, cad son expression
55         """
56         if len(self.mc_liste) == 0:
57             # pas de fils pour self --> la FORMULE est incomplète
58             return None,None,None
59         type_retourne="REEL"
60         if len(self.mc_liste) > 0:
61            child = self.mc_liste[0] # child est un MCSIMP 
62            corps = child.getval()
63         else:
64            corps = None
65         if len(self.mc_liste) > 1:
66            child = self.mc_liste[1]
67            l_args= child.getval()
68         else :
69            l_args=None
70         return type_retourne,l_args,corps
71
72     def get_nom(self):
73         """
74         Retourne le nom de la FORMULE, cad le nom de la SD si elle existe,
75         la string vide sinon
76         """
77         if self.sd :
78             return self.sd.get_name()
79         else:
80             return ''
81
82     def get_formule(self):
83         """
84         Retourne un tuple décrivant la formule :
85         (nom,type_retourne,arguments,corps)
86         """
87         t,a,c = self.analyse_formule()
88         n = self.get_nom()
89         return (n,t,a,c)
90
91     def verif_arguments(self,arguments = None):
92         """
93         Vérifie si les arguments passés en argument (si aucun prend les arguments courants)
94         sont des arguments valide pour une FORMULE.
95         Retourne :
96             - un booléen, qui vaut 1 si arguments licites, 0 sinon
97             - un message d'erreurs ('' si illicites)
98         """
99         if not arguments :
100             arguments = self.arguments
101         if not arguments :
102             return 0,"Une formule doit avoir au minimum un argument"
103         # il faut au préalable enlever les parenthèses ouvrantes et fermantes
104         # encadrant les arguments
105         arguments = string.strip(arguments)
106         if arguments[0] != '(':
107             return 0,tr("La liste des arguments d'une formule doit etre entre parentheses : parenthese ouvrante manquante")
108         if arguments[-1] != ')':
109             return 0,tr("La liste des arguments d'une formule doit etre entre parentheses : parenthese fermante manquante")
110         # on peut tester la syntaxe de chaque argument maintenant
111         erreur=''
112         test = 1
113         arguments = arguments[1:-1] # on enlève les parenthèses ouvrante et fermante
114         l_arguments = string.split(arguments,',')
115         for a in l_arguments :
116             if not re.match(identifier,str(a)) : return 0, str(a)+" n est pas un identifiant"
117         return test,erreur
118
119     def verif_corps(self,corps=None,arguments=None):
120         """
121         Cette méthode a pour but de vérifier si le corps de la FORMULE
122         est syntaxiquement correct.
123         Retourne :
124             - un booléen, qui vaut 1 si corps de FORMULE licite, 0 sinon
125             - un message d'erreurs ('' si illicite)
126         """
127         if not corps :
128             corps = self.corps
129         if not arguments :
130             arguments = self.arguments
131         formule=(self.get_nom(),self.type_retourne,arguments,corps)
132         # on récupère la liste des constantes et des autres fonctions prédéfinies
133         # et qui peuvent être utilisées dans le corps de la formule courante
134         l_ctes,l_form = self.jdc.get_parametres_fonctions_avant_etape(self)
135         # on crée un objet vérificateur
136         try:
137             verificateur = self.interpreteur(formule=formule,
138                                              constantes = l_ctes,
139                                              fonctions = l_form)
140         except :
141             traceback.print_exc()
142             return 0,tr("Impossible de realiser la verification de la formule")
143         return verificateur.isvalid(),verificateur.report()
144
145     def verif_nom(self,nom=None):
146         """
147         Vérifie si le nom passé en argument (si aucun prend le nom courant)
148         est un nom valide pour une FORMULE.
149         Retourne :
150             - un booléen, qui vaut 1 si nom licite, 0 sinon
151             - un message d'erreurs ('' si illicite)
152         """
153         if not nom :
154             nom = self.get_nom()
155         if nom == "" :
156             return 0,tr("Pas de nom donne a la FORMULE")
157         if len(nom) > 8 :
158             return 0,tr("Un nom de FORMULE ne peut depasser 8 caracteres")
159         if nom[0] > "0" and nom[0] < "9" :
160             return 0,tr("Un nom de FORMULE ne peut pas commencer par un chiffre")
161         sd = self.parent.get_sd_autour_etape(nom,self)
162         if sd :
163             return 0,tr("Un concept de nom %s existe deja !" %nom)
164         return 1,''
165
166     def verif_type(self,type=None):
167         """
168         Vérifie si le type passé en argument (si aucun prend le type courant)
169         est un type valide pour une FORMULE.
170         Retourne :
171             - un booléen, qui vaut 1 si type licite, 0 sinon
172             - un message d'erreurs ('' si illicite)
173         """
174         if not type:
175             type = self.type_retourne
176         if not type :
177             return 0,tr("Le type de la valeur retournee n'est pas specifie")
178         if type not in self.l_types_autorises:
179             return 0,tr("Une formule ne peut retourner une valeur de type : %s" %type)
180         return 1,''
181
182     def verif_formule(self,formule=None):
183         """
184         Vérifie la validité de la formule passée en argument.
185         Cette nouvelle formule est passée sous la forme d'un tuple : (nom,type_retourne,arguments,corps)
186         Si aucune formule passée, prend les valeurs courantes de la formule
187         Retourne :
188             - un booléen, qui vaut 1 si formule licite, 0 sinon
189             - un message d'erreurs ('' si illicite)
190         """
191         if not formule :
192             formule = (None,None,None,None)
193         test_nom,erreur_nom = self.verif_nom(formule[0])
194         test_type,erreur_type = self.verif_type(formule[1])
195         if formule[2]:
196             args = '('+formule[2]+')'
197         else:
198             args = None
199         test_arguments,erreur_arguments = self.verif_arguments(args)
200         test_corps,erreur_corps = self.verif_corps(corps = formule[3], arguments = args)
201         # test global = produit des tests partiels
202         test = test_nom*test_type*test_arguments*test_corps
203         # message d'erreurs global = concaténation des messages partiels
204         erreur = ''
205         if not test :
206             for mess in (erreur_nom,erreur_type,erreur_arguments,erreur_corps):
207                 erreur = erreur+(len(mess) > 0)*'\n'+mess
208         return test,erreur
209
210     def verif_formule_python(self,formule=None):
211         """
212         Pour l instant ne fait qu un compile python
213         il serait possible d ajouter des tests sur les arguments
214         ou le type retourne mais ...
215         """
216         if not formule :
217             formule = (None,None,None,None)
218         test_nom,erreur_nom = self.verif_nom(formule[0])
219         if formule[2]:
220             args = '('+formule[2]+')'
221         else:
222             args = None
223         test_arguments,erreur_arguments = self.verif_arguments(args)
224         corps=formule[3]
225         erreur_formule= ''
226         test_formule=1
227         try :
228             compile(corps,'<string>','eval')
229         except :
230             erreur_formule= "le corps de la formule n'est pas une formule python valide"
231             test_formule=0
232         erreur = ''
233         test = test_nom*test_arguments*test_formule
234         if not test :
235             for mess in (erreur_nom,erreur_arguments,erreur_formule):
236                 erreur = erreur+(len(mess) > 0)*'\n'+mess
237         return test,erreur
238
239
240     def update(self,formule):
241         """
242         Méthode externe.
243         Met à jour les champs nom, type_retourne,arguments et corps de la FORMULE
244         par les nouvelles valeurs passées dans le tuple formule.
245         On stocke les valeurs SANS vérifications.
246         """
247         self.type_retourne = formule[1]
248         self.arguments = '('+formule[2]+')'
249         self.corps = formule[3]
250         # il faut ajouter le mot-clé simple correspondant dans mc_liste
251         # pour cela on utilise la méthode générale build_mc
252         # du coup on est obligé de modifier le dictionnaire valeur de self ...
253         self.valeur = {}
254         self.valeur[self.type_retourne] = self.arguments+' = ' + self.corps
255         self.McBuild()
256         sd = self.get_sd_prod()
257         if sd:
258             sd.nom = formule[0]
259
260     # bidouille PN 
261     # Il faut que formule soit constituee de 
262     # nom de la formule
263     # type retourne
264     # parametres
265     # corps de la fonction
266     # il faut aussi que les arguments soient sous forme de tuple
267     def update_formule_python(self,formule):
268         self.build_mc()
269         self.mc_liste=[]
270         if len(formule) < 4 :
271            return 0
272         arguments=formule[3]
273         if arguments[0] == '(' :
274            arguments=arguments[1:]
275         if arguments[-1] == ')' :
276            arguments=arguments[:-1]
277         self.arguments=tuple(arguments.split(','))
278
279         mocles={"NOM_PARA":self.arguments}
280         if formule[1] == "REEL":
281           mocles["VALE"]=formule[2]
282         if formule[1] == "COMPLEXE":
283           mocles["VALE_C"]=formule[2]
284
285         for k,v in self.definition.entites.items():
286             if not mocles.has_key(k):continue
287             child=self.definition.entites[k](None,nom=k,parent=self)
288             child.valeur=mocles[k]
289             child.state = 'modified'
290             self.mc_liste.append(child)
291            
292         self.corps = formule[2]
293         self.type_retourne = formule[1]
294         sd = self.get_sd_prod()
295         if sd:
296             sd.nom = formule[0]
297         self.init_modif()
298         return 1
299
300     def active(self):
301         """
302         Rend l'etape courante active.
303         Il faut ajouter la formule au contexte global du JDC
304         """
305         self.actif = 1
306         self.init_modif()
307         nom = self.get_nom()
308         if nom == '' : return
309         try:
310             self.jdc.append_fonction(self.sd)
311         except:
312             pass
313
314     def inactive(self):
315         """
316         Rend l'etape courante inactive
317         Il faut supprimer la formule du contexte global du JDC
318         """
319         self.actif = 0
320         self.init_modif()
321         if not self.sd : return
322         self.jdc.del_fonction(self.sd)
323
324     def update_concept(self,sd):
325         return
326
327     def delete_concept(self,sd):
328         """ 
329          Inputs :
330            - sd=concept detruit
331          Fonction :
332          Mettre a jour les mots cles de l etape et eventuellement le concept produit si reuse
333          suite à la disparition du concept sd
334          Seuls les mots cles simples MCSIMP font un traitement autre que de transmettre aux fils,
335          sauf les objets FORM_ETAPE qui doivent vérifier que le concept détruit n'est pas 
336          utilisé dans le corps de la fonction
337         """
338         self.init_modif()
339          
340     def replace_concept(self,old_sd,sd):
341         """
342          Inputs :
343            - old_sd=concept remplace
344            - sd = nouveau concept
345          Fonction :
346          Les objets FORM_ETAPE devraient vérifier que le concept remplacé n'est pas
347          utilisé dans le corps de la fonction
348         """
349         self.init_modif()
350