Salome HOME
CCAR: diverses corrections lies aux validateurs
[tools/eficas.git] / Ihm / I_MCSIMP.py
1 #            CONFIGURATION MANAGEMENT OF EDF VERSION
2 # ======================================================================
3 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
4 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
5 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
6 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
7 # (AT YOUR OPTION) ANY LATER VERSION.
8 #
9 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
10 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
11 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
12 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
13 #
14 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
15 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
16 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
17 #
18 #
19 # ======================================================================
20 import types,string
21 import traceback
22 from copy import copy
23 from repr import Repr
24 myrepr = Repr()
25 myrepr.maxstring = 100
26 myrepr.maxother = 100
27
28 from Noyau.N_utils import repr_float
29
30 # Attention : les classes ASSD,.... peuvent etre surchargées
31 # dans le package Accas. Il faut donc prendre des précautions si
32 # on utilise les classes du Noyau pour faire des tests (isxxxx, ...)
33 # Si on veut créer des objets comme des CO avec les classes du noyau
34 # ils n'auront pas les conportements des autres packages (pb!!!)
35 # Il vaut mieux les importer d'Accas mais problème d'import circulaire,
36 # on ne peut pas les importer au début.
37 # On fait donc un import local quand c'est nécessaire (peut occasionner
38 # des pbs de prformance).
39 from Noyau.N_ASSD import ASSD,assd
40 from Noyau.N_GEOM import GEOM,geom
41 from Noyau.N_CO import CO
42 # fin attention
43
44 from Extensions import parametre
45 import I_OBJECT
46
47 class MCSIMP(I_OBJECT.OBJECT):
48   def GetText(self):
49     """
50         Retourne le texte à afficher dans l'arbre représentant la valeur de l'objet
51         pointé par self
52     """
53     if self.valeur == None : 
54       return None
55     elif type(self.valeur) == types.FloatType : 
56       # Traitement d'un flottant isolé
57       #txt = repr_float(self.valeur)
58       # Normalement str fait un travail correct
59       txt = str(self.valeur)
60     elif type(self.valeur) in (types.ListType,types.TupleType) :
61       # Traitement des listes
62       txt='('
63       i=0
64       for val in self.valeur:
65         if type(val) == types.FloatType : 
66            # CCAR : Normalement str fait un travail correct
67            #txt=txt + i*',' + repr_float(val)
68            txt=txt + i*',' + str(val)
69         elif isinstance(val,ASSD): 
70            txt = txt + i*',' + val.get_name()
71     #PN
72     # ajout du elif
73         elif type(val) == types.InstanceType and val.__class__.__name__ in  ('PARAMETRE','PARAMETRE_EVAL'):
74            txt = txt + i*','+ str(val) 
75         else: 
76            txt = txt + i*','+ myrepr.repr(val)
77         i=1
78       txt=txt+')'
79     else:
80       # Traitement des autres cas
81       txt = self.getval()
82
83       if type(txt) == types.InstanceType:
84         if isinstance(txt,parametre.PARAMETRE):
85           txt= str(txt)
86       else:
87         txt=repr(txt)
88
89     # txt peut etre une longue chaine sur plusieurs lignes.
90     # Il est possible de tronquer cette chaine au premier \n et 
91     # de limiter la longueur de la chaine a 30 caracteres. Cependant
92     # ceci provoque une perte d'information pour l'utilisateur
93     # Pour le moment on retourne la chaine telle que
94     return txt
95
96   def getval(self):
97     """ 
98        Retourne une chaîne de caractère représentant la valeur de self 
99     """
100     val=self.valeur
101     if type(val) != types.TupleType :
102       try:
103         return val.get_name()
104       except:
105         return val
106     else :
107       s='( '
108       for item in val :
109         try :
110           s=s+item.get_name()+','
111         except:
112           s=s+`item`+','
113       s=s+' )'
114       return s
115
116   def wait_co(self):
117     """
118         Méthode booléenne qui retourne 1 si l'objet attend un objet ASSD 
119         qui n'existe pas encore (type CO()), 0 sinon
120     """
121     for typ in self.definition.type:
122       if type(typ) == types.ClassType :
123         if issubclass(typ,CO) :
124            return 1
125     return 0
126
127   def wait_assd(self):
128     """ 
129         Méthode booléenne qui retourne 1 si le MCS attend un objet de type ASSD 
130         ou dérivé, 0 sinon
131     """
132     for typ in self.definition.type:
133       if type(typ) == types.ClassType :
134         if issubclass(typ,ASSD) and not issubclass(typ,GEOM):
135           return 1
136     return 0
137
138   def wait_assd_or_geom(self):
139     """ 
140          Retourne 1 si le mot-clé simple attend un objet de type
141          assd, ASSD, geom ou GEOM
142          Retourne 0 dans le cas contraire
143     """
144     for typ in self.definition.type:
145       if type(typ) == types.ClassType :
146         if typ.__name__ in ("GEOM","ASSD","geom","assd") or issubclass(typ,GEOM) :
147           return 1
148     return 0
149
150   def wait_geom(self):
151     """ 
152          Retourne 1 si le mot-clé simple attend un objet de type GEOM
153          Retourne 0 dans le cas contraire
154     """
155     for typ in self.definition.type:
156       if type(typ) == types.ClassType :
157         if issubclass(typ,GEOM) : return 1
158     return 0
159
160   def wait_TXM(self):
161     """ 
162          Retourne 1 si le mot-clé simple attend un objet de type TXM
163          Retourne 0 dans le cas contraire
164     """
165     for typ in self.definition.type:
166       if typ == 'TXM' :return 1
167     return 0
168
169   def get_liste_valeurs(self):
170     """
171     """
172     if self.valeur == None:
173       return []
174     elif type(self.valeur) == types.TupleType:
175       return list(self.valeur)
176     elif type(self.valeur) == types.ListType:
177       return self.valeur
178     else:
179       return [self.valeur]
180
181   def isoblig(self):
182     return self.definition.statut=='o'
183
184 #  def set_valeur(self,new_valeur,evaluation='oui'):
185 #    """
186 #        Remplace la valeur de self(si elle existe) par new_valeur
187 #            - si evaluation = 'oui' : 
188 #                        essaie d'évaluer new_valeur dans le contexte
189 #            - si evaluation = 'non' : 
190 #                        n'essaie pas d'évaluer (on stocke une string ou 
191 #                        une valeur de la liste into )
192 #    """
193 #    if evaluation == 'oui' and not self.wait_assd_or_geom():
194 #      valeur,test = self.eval_valeur(new_valeur)
195 #      if test :
196 #        self.val = new_valeur
197 #        self.valeur = valeur
198 #        self.init_modif()
199 #        self.fin_modif()
200 #        return 1
201 #      else:
202 #        # On n'a pas trouve de concept ni réussi à évaluer la valeur 
203 #        # dans le contexte
204 #        # Si le mot cle simple attend un type CO on crée un objet de ce 
205 #        # type de nom new_valeur
206 #        if self.wait_co():
207 #          try:
208 #            # Pour avoir la classe CO avec tous ses comportements
209 #            from Accas import CO
210 #            self.valeur=CO(new_valeur)
211 #          except:
212 #            traceback.print_exc()
213 #            return 0
214 #          self.init_modif()
215 #          self.val=self.valeur
216 #          self.fin_modif()
217 #          return 1
218 #        elif type(new_valeur)==types.StringType and self.wait_TXM():
219 #          self.init_modif()
220 #          self.val = new_valeur
221 #          self.valeur = new_valeur
222 #          self.fin_modif()
223 #          return 1
224 #        else:
225 #          return 0
226 #    else :
227       # on ne fait aucune vérification ...
228   def set_valeur(self,new_valeur,evaluation='oui'):
229         self.init_modif()
230         self.valeur = new_valeur
231         self.val = new_valeur
232         self.fin_modif()
233         return 1
234
235   def eval_valeur(self,new_valeur):
236     """
237         Essaie d'évaluer new_valeur comme une SD, une déclaration Python 
238         ou un EVAL: Retourne la valeur évaluée (ou None) et le test de réussite (1 ou 0)
239     """
240     sd = self.jdc.get_contexte_avant(self.etape).get(new_valeur,None)
241     if sd :
242       return sd,1
243     else:
244       d={}
245       # On veut EVAL avec tous ses comportements. On utilise Accas. Perfs ??
246       from Accas import EVAL
247       d['EVAL']=EVAL
248       try :
249         objet = eval(new_valeur,d)
250         return objet,1
251       except Exception:
252         if CONTEXT.debug : traceback.print_exc()
253         return None,0
254
255   def delete_concept(self,sd):
256     """ 
257         Inputs :
258            - sd=concept detruit
259         Fonction :
260         Met a jour la valeur du mot cle simple suite à la disparition 
261         du concept sd
262     """
263     if type(self.valeur) == types.TupleType :
264       if sd in self.valeur:
265         self.valeur=list(self.valeur)
266         self.valeur.remove(sd)
267         self.init_modif()
268     elif type(self.valeur) == types.ListType:
269       if sd in self.valeur:
270         self.valeur.remove(sd)
271         self.init_modif()
272     else:
273       if self.valeur == sd:
274         self.valeur=None
275         self.val=None
276         self.init_modif()
277
278   def replace_concept(self,old_sd,sd):
279     """
280         Inputs :
281            - old_sd=concept remplacé
282            - sd=nouveau concept
283         Fonction :
284         Met a jour la valeur du mot cle simple suite au remplacement 
285         du concept old_sd
286     """
287     if type(self.valeur) == types.TupleType :
288       if old_sd in self.valeur:
289         self.valeur=list(self.valeur)
290         i=self.valeur.index(old_sd)
291         self.valeur[i]=sd
292         self.init_modif()
293     elif type(self.valeur) == types.ListType:
294       if old_sd in self.valeur:
295         i=self.valeur.index(old_sd)
296         self.valeur[i]=sd
297         self.init_modif()
298     else:
299       if self.valeur == old_sd:
300         self.valeur=sd
301         self.val=sd
302         self.init_modif()
303
304   def copy(self):
305     """ Retourne une copie de self """
306     objet = self.makeobjet()
307     # il faut copier les listes et les tuples mais pas les autres valeurs
308     # possibles (réel,SD,...)
309     if type(self.valeur) in (types.ListType,types.TupleType):
310        objet.valeur = copy(self.valeur)
311     else:
312        objet.valeur = self.valeur
313     objet.val = objet.valeur
314     return objet
315
316   def makeobjet(self):
317     return self.definition(val = None, nom = self.nom,parent = self.parent)
318
319   def get_sd_utilisees(self):
320     """ 
321         Retourne une liste qui contient la SD utilisée par self si c'est le cas
322         ou alors une liste vide
323     """
324     l=[]
325     if type(self.valeur) == types.InstanceType:
326       #XXX Est ce différent de isinstance(self.valeur,ASSD) ??
327       if issubclass(self.valeur.__class__,ASSD) : l.append(self.valeur)
328     return l
329
330
331   def set_valeur_co(self,nom_co):
332       """
333           Affecte à self l'objet de type CO et de nom nom_co
334       """
335       step=self.etape.parent
336       if nom_co == None or nom_co == '':
337          new_objet=None
338       else:
339          # Pour le moment on importe en local le CO de Accas.
340          # Si problème de perfs, il faudra faire autrement
341          from Accas import CO
342          # Avant de créer un concept il faut s'assurer du contexte : step 
343          # courant
344          sd= step.get_sd_autour_etape(nom_co,self.etape,avec='oui')
345          if sd:
346             # Si un concept du meme nom existe deja dans la portée de l'étape
347             # on ne crée pas le concept
348             return 0,"un concept de meme nom existe deja"
349          # Il n'existe pas de concept de meme nom. On peut donc le créer 
350          # Il faut néanmoins que la méthode NommerSdProd de step gère les 
351          # contextes en mode editeur
352          # Normalement la méthode  du Noyau doit etre surchargée
353          # On déclare l'étape du mot clé comme etape courante pour NommerSdprod
354          cs= CONTEXT.get_current_step()
355          CONTEXT.unset_current_step()
356          CONTEXT.set_current_step(step)
357          step.set_etape_context(self.etape)
358          new_objet = CO(nom_co)
359          CONTEXT.unset_current_step()
360          CONTEXT.set_current_step(cs)
361       self.init_modif()
362       self.valeur = new_objet
363       self.val = new_objet
364       self.fin_modif()
365       step.reset_context()
366       # On force l'enregistrement de new_objet en tant que concept produit 
367       # de la macro en appelant get_type_produit avec force=1
368       self.etape.get_type_produit(force=1)
369       return 1,"Concept créé"
370         
371   def reparent(self,parent):
372      """
373          Cette methode sert a reinitialiser la parente de l'objet
374      """
375      self.parent=parent
376      self.jdc=parent.jdc
377      self.etape=parent.etape
378
379   def verif_existence_sd(self):
380      """
381         Vérifie que les structures de données utilisées dans self existent bien dans le contexte
382         avant étape, sinon enlève la référence à ces concepts
383      """
384      l_sd_avant_etape = self.jdc.get_contexte_avant(self.etape).values()  
385      if type(self.valeur) in (types.TupleType,types.ListType) :
386        l=[]
387        for sd in self.valeur:
388          if isinstance(sd,ASSD) :
389             if sd in l_sd_avant_etape :
390                l.append(sd)
391          else:
392             l.append(sd)
393        self.valeur=tuple(l)
394        # Est ce init_modif ou init_modif_up
395        # Normalement init_modif va avec fin_modif
396        self.init_modif()
397        self.fin_modif()
398      else:
399        if isinstance(self.valeur,ASSD) :
400           if self.valeur not in l_sd_avant_etape :
401              self.valeur = None
402              self.init_modif()
403              self.fin_modif()
404  
405   def get_min_max(self):
406      """
407      Retourne les valeurs min et max admissibles pour la valeur de self
408      """
409      return self.definition.min,self.definition.max
410
411
412   def get_type(self):
413      """
414      Retourne le type attendu par le mot-clé simple
415      """
416      return self.definition.type
417  
418 #ATTENTION SURCHARGE : toutes les methodes ci apres sont des surcharges du Noyau et de Validation
419 # Elles doivent etre reintegrees des que possible
420
421   def is_complexe(self,valeur):
422       """ Retourne 1 si valeur est un complexe, 0 sinon """
423       if type(valeur) == types.InstanceType :
424         #XXX je n'y touche pas pour ne pas tout casser mais il serait
425         #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('C'), par exemple
426         if valeur.__class__.__name__ in ('EVAL','complexe','PARAMETRE_EVAL'):
427           return 1
428         elif valeur.__class__.__name__ in ('PARAMETRE',):
429           # il faut tester si la valeur du parametre est un entier
430           #XXX ne serait ce pas plutot complexe ???? sinon expliquer
431           return self.is_complexe(valeur.valeur)
432         else:
433           print "Objet non reconnu dans is_complexe %s" %`valeur`
434           return 0
435       # Pour permettre l'utilisation de complexes Python
436       #elif type(valeur) == types.ComplexType:
437         #return 1
438       elif type(valeur) == types.ListType :
439         # On n'autorise pas les listes de complexes
440         return 0
441       elif type(valeur) != types.TupleType :
442         # Un complexe doit etre un tuple
443         return 0
444       else:
445         if len(valeur) != 3 :
446           return 0
447         else:
448           if type(valeur[0]) != types.StringType : return 0
449           if string.strip(valeur[0]) not in ('RI','MP'):
450             return 0
451           else:
452             if not self.is_reel(valeur[1]) or not self.is_reel(valeur[2]) : return 0
453             else: return 1
454
455   def is_reel(self,valeur):
456       """
457       Retourne 1 si valeur est un reel, 0 sinon
458       """
459       if type(valeur) == types.InstanceType :
460         #XXX je n'y touche pas pour ne pas tout casser mais il serait
461         #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('R'), par exemple
462         #XXX ou valeur.is_reel()
463         #XXX ou encore valeur.compare(self.is_reel)
464         if valeur.__class__.__name__ in ('EVAL','reel','PARAMETRE_EVAL') :
465           return 1
466         elif valeur.__class__.__name__ in ('PARAMETRE',):
467           # il faut tester si la valeur du parametre est un réel
468           return self.is_reel(valeur.valeur)
469         else:
470           print "Objet non reconnu dans is_reel %s" %`valeur`
471           return 0
472       elif type(valeur) not in (types.IntType,types.FloatType,types.LongType):
473         # ce n'est pas un réel
474         return 0
475       else:
476         return 1
477
478   def is_entier(self,valeur):
479       """ Retourne 1 si valeur est un entier, 0 sinon """
480       if type(valeur) == types.InstanceType :
481         #XXX je n'y touche pas pour ne pas tout casser mais il serait
482         #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('I'), par exemple
483         if valeur.__class__.__name__ in ('EVAL','entier','PARAMETRE_EVAL') :
484           return 1
485         elif valeur.__class__.__name__ in ('PARAMETRE',):
486           # il faut tester si la valeur du parametre est un entier
487           return self.is_entier(valeur.valeur)
488         else:
489           print "Objet non reconnu dans is_reel %s" %`valeur`
490           return 0
491       elif type(valeur) not in (types.IntType,types.LongType):
492         # ce n'est pas un entier
493         return 0
494       else:
495         return 1
496
497   def is_object_from(self,objet,classe):
498       """
499            Retourne 1 si valeur est un objet de la classe classe ou d'une 
500            sous-classe de classe, 0 sinon
501       """
502       if type(objet) != types.InstanceType :
503           return 0
504       if not objet.__class__ == classe and not issubclass(objet.__class__,classe):
505         return 0
506       else:
507         return 1
508
509   def get_valid(self):
510        if hasattr(self,'valid'):
511           return self.valid
512        else:
513           self.valid=None
514           return None
515
516   def set_valid(self,valid):
517        old_valid=self.get_valid()
518        self.valid = valid
519        self.state = 'unchanged'
520        if not old_valid or old_valid != self.valid :
521            self.init_modif_up()
522
523   def isvalid(self,cr='non'):
524       """
525          Cette méthode retourne un indicateur de validité de l'objet de type MCSIMP
526
527            - 0 si l'objet est invalide
528            - 1 si l'objet est valide
529
530          Le paramètre cr permet de paramétrer le traitement. Si cr == 'oui'
531          la méthode construit également un comte-rendu de validation
532          dans self.cr qui doit avoir été créé préalablement.
533       """
534       if self.state == 'unchanged':
535         return self.valid
536       else:
537         v=self.valeur
538         valid = 1
539         #  verifiaction presence
540         if self.isoblig() and v == None :
541           if cr == 'oui' :
542             self.cr.fatal(string.join(("Mot-clé : ",self.nom," obligatoire non valorisé")))
543           valid = 0
544
545         if v is None:
546           valid=0
547           if cr == 'oui' :
548              self.cr.fatal("None n'est pas une valeur autorisée")
549         else:
550           # type,into ...
551           valid = self.verif_type(val=v,cr=cr)*self.verif_into(cr=cr)*self.verif_card(cr=cr)
552           #
553           # On verifie les validateurs s'il y en a et si necessaire (valid == 1)
554           #
555           if valid and self.definition.validators and not self.definition.validators.verif(self.valeur):
556             if cr == 'oui' :
557               self.cr.fatal(string.join(("Mot-clé : ",self.nom,"devrait avoir ",self.definition.validators.info())))
558             valid=0
559           # fin des validateurs
560           #
561
562         self.set_valid(valid)
563         return self.valid
564
565   def verif_into(self,cr='non'):
566       """
567       Vérifie si la valeur de self est bien dans l'ensemble discret de valeurs
568       donné dans le catalogue derrière l'attribut into ou vérifie que valeur est bien compris
569       entre val_min et val_max
570       """
571       if self.definition.into == None :
572         #on est dans le cas d'un ensemble continu de valeurs possibles (intervalle)
573         if type(self.valeur)==types.TupleType :
574           test = 1
575           for val in self.valeur :
576             if type(val)!=types.StringType and type(val)!=types.InstanceType:
577               test = test*self.isinintervalle(val,cr=cr)
578           return test
579         else :
580           val = self.valeur
581           if type(val)!=types.StringType and type(val)!=types.InstanceType:
582             return self.isinintervalle(self.valeur,cr=cr)
583           else :
584             return 1
585       else :
586         # on est dans le cas d'un ensemble discret de valeurs possibles (into)
587         # PN : pour résoudre le pb du copier /coller de la liste Ordonnee
588         # if type(self.valeur) == types.TupleType :
589         if type(self.valeur) in (types.ListType,types.TupleType) :
590           for e in self.valeur:
591             if e not in self.definition.into:
592               if cr=='oui':
593                 self.cr.fatal(string.join(("La valeur :",`e`," n'est pas permise pour le mot-clé :",self.nom)))
594               return 0
595         else:
596           if self.valeur == None or self.valeur not in self.definition.into:
597             if cr=='oui':
598               self.cr.fatal(string.join(("La valeur :",`self.valeur`," n'est pas permise pour le mot-clé :",self.nom)))
599             return 0
600         return 1
601