Salome HOME
c241e857c6e1c39148fe123746bdfcb648d3da84
[tools/eficas.git] / Ihm / I_VALIDATOR.py
1 """
2    Ce module contient des classes permettant de définir des validateurs
3    pour EFICAS. Ces classes constituent un complément à des classes existantes
4    dans Noyau/N_VALIDATOR.py ou de nouvelles classes de validation.
5    Ces classes complémentaires ne servent que pour l'IHM d'EFICAS.
6    Elles servent essentiellement à ajouter des comportements spécifiques
7    IHM aux classes existantes dans le Noyau.
8    Ces comportements pourront etre rapatries dans le Noyau quand leur
9    interface sera stabilisée.
10 """
11
12 import types
13 import Noyau.N_VALIDATOR
14
15 class Valid:
16    """
17         Cette classe est la classe mere de toutes les classes complémentaires
18         que l'on trouve dans Ihm.
19         Elle porte les comportements par défaut des méthodes des validateurs.
20    """
21
22    def info_erreur_item(self):
23        """
24           Cette méthode permet d'avoir un message d'erreur pour un item
25           dans une liste dans le cas ou le validateur fait des vérifications
26           sur les items d'une liste. Si le validateur fait des vérifications 
27           sur la liste elle meme et non sur ses items, la méthode
28           doit retourner une chaine vide.
29        """
30        return ""
31
32    def aide(self):
33        """
34           Cette methode retourne une chaine de caractère qui permet à EFICAS de construire
35           un message d'aide en ligne
36           En général, le message retourné est le meme que celui retourné par la 
37           méthode info
38        """
39        return self.info()
40
41    def info_erreur_liste(self):
42        """
43           Cette méthode a un comportement complémentaire de celui de info_erreur_item.
44           Elle retourne un message d'erreur lié uniquement aux vérifications sur la liste
45           elle meme et pas sur ses items. Dans le cas où le validateur ne fait pas de vérification
46           sur des listes, elle retourne une chaine vide
47        """
48        return ""
49
50    def is_list(self):
51        """
52           Cette méthode retourne un entier qui indique si le validateur permet les listes (valeur 1)
53           ou ne les permet pas (valeur 0).
54           Par défaut, un validateur n'autorise que des scalaires.
55        """
56        return 0
57
58    def has_into(self):
59        """
60           Cette méthode retourne un entier qui indique si le validateur propose une liste de choix (valeur 1)
61           ou n'en propose pas.
62           Par défaut, un validateur n'en propose pas.
63        """
64        return 0
65
66    def valide_liste_partielle(self,liste_courante):
67        return 0
68
69    def verif_item(self,valeur):
70        """
71           La methode verif du validateur effectue une validation complete de la valeur.
72           valeur peut etre un scalaire ou une liste. Le validateur doit traiter les 2
73           aspects s'il accepte des listes (dans ce cas la methode is_list doit retourner 1).
74           La methode valid_item sert pour effectuer des validations partielles de liste
75           Elle doit uniquement verifier la validite d'un item de liste mais pas les caracteristiques
76           de la liste
77        """
78        return 0
79
80    def get_into(self,liste_courante=None,into_courant=None):
81        """
82           Cette méthode retourne la liste de choix proposée par le validateur. Si le validateur ne propose
83           pas de liste de choix, la méthode retourne None.
84           L'argument d'entrée liste_courante, s'il est différent de None, donne la liste des choix déjà
85           effectués par l'utilisateur. Dans ce cas, la méthode get_into doit calculer la liste des choix
86           en en tenant compte. Par exemple, si le validateur n'autorise pas les répétitions, la liste des
87           choix retournée ne doit pas contenir les choix déjà contenus dans liste_courante.
88           L'argument d'entrée into_courant, s'il est différent de None, donne la liste des choix proposés
89           par d'autres validateurs. Dans ce cas, la méthode get_into doit calculer la liste des choix à retourner
90           en se limitant à cette liste initiale. Par exemple, si into_courant vaut (1,2,3) et que le validateur
91           propose la liste de choix (3,4,5), la méthode ne doit retourner que (3,).
92
93           La méthode get_into peut retourner une liste vide [], ce qui veut dire qu'il n'y a pas (ou plus) de choix possible
94           Cette situation peut etre normale : l''utilisateur a utilisé tous les choix, ou résulter d'une incohérence 
95           des validateurs : choix parmi (1,2,3) ET choix parmi (4,5,6). Il est impossible de faire la différence entre
96           ces deux situations.
97        """
98        return into_courant
99
100    def is_eval(self,valeur):
101        """
102            Cette méthode indique si valeur est un objet de type EVAL ou autre
103            que l'on ne cherchera pas à evaluer et qui doit etre considere comme toujours valide
104            Si c'est un objet de ce type elle retourne la valeur 1 sinon la valeur 0
105        """
106        if type(valeur) == types.InstanceType :
107           if valeur.__class__.__name__ in ('EVAL','entier','reel','chaine','complexe','liste','PARAMETRE_EVAL') :
108              return 1
109        return 0
110
111    def is_param(self,valeur):
112        """
113            Cette méthode indique si valeur est un objet de type PARAMETRE
114            dont on cherchera à evaluer la valeur (valeur.valeur)
115        """
116        if type(valeur) == types.InstanceType :
117           if valeur.__class__.__name__ in ('PARAMETRE',):
118              return 1
119        return 0
120
121    def is_unknown(self,valeur):
122        """
123            Cette méthode indique si valeur est un objet de type inconnu
124            c'est à dire ni de type EVAL ni de type PARAMETRE
125        """
126        if type(valeur) == types.InstanceType :
127           if not self.is_eval(valeur) and not self.is_param(valeur):
128              return 1
129        return 0
130
131    def surcharge_verif(self,methode_verif_initiale,valeur):
132        if type(valeur) == types.InstanceType :
133           #CCAR: pour le moment on fait comme dans is_entier de V_MCSIMP.py
134           # mais il serait préférable d'appeler une méthode de valeur : valeur.AsType()
135           # qui donnerait le type générique de l'objet.
136           # Pour un objet de "type" entier on obtiendrait par exemple 'I'
137           if valeur.__class__.__name__ in ('EVAL','entier','reel','chaine','complexe','liste','PARAMETRE_EVAL') :
138              # On ne vérifie pas le type d'un EVAL ou d'un objet de classe entier, .... C'est toujours valide
139              return 1
140           elif valeur.__class__.__name__ in ('PARAMETRE',):
141              # Dans le cas d'un parametre, il faut tester si la valeur du parametre est un entier
142              valeur=valeur.valeur
143           else:
144              # Objet inconnu : invalide
145              print "Objet non reconnu dans surcharge_verif : %s" %`valeur`
146              return 0
147
148        return methode_verif_initiale(self,valeur)
149
150 class FunctionVal(Valid):pass
151
152 class OrVal(Valid):
153    def verif_item(self,valeur):
154        for validator in self.validators:
155            v=validator.verif_item(valeur)
156            if v :
157               return 1
158        return 0
159
160    def info_erreur_item(self):
161        chaine=""
162        a=1
163        for v in self.validators:
164            if v.info_erreur_item() != "" :
165               if a==1:
166                  chaine=v.info_erreur_item()
167                  a=0
168               else:
169                  chaine=chaine+" \n ou "+ v.info_erreur_item()
170        return chaine
171
172    def info_erreur_liste(self):
173        chaine=""
174        a=1
175        for v in self.validators:
176            if v.info_erreur_liste() != "" :
177               if a==1:
178                  chaine=v.info_erreur_liste()
179                  a=0
180               else:
181                  chaine=chaine+" \n ou "+v.info_erreur_liste()
182
183    def is_list(self):
184        """
185           Si plusieurs validateurs sont reliés par un OU
186           il suffit qu'un seul des validateurs attende une liste
187           pour qu'on considère que leur union attende une liste.
188        """
189        for validator in self.validators:
190            v=validator.is_list()
191            if v :
192               return 1
193        return 0
194
195    def has_into(self):
196        """
197           Dans le cas ou plusieurs validateurs sont reliés par un OU
198           il faut que tous les validateurs proposent un choix pour 
199           qu'on considère que leur union propose un choix.
200           Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
201           En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un choix (1,2,3,4,5,6)
202        """
203        for validator in self.validators:
204            v=validator.has_into()
205            if not v :
206               return 0
207        return 1
208
209    def get_into(self,liste_courante=None,into_courant=None):
210        """
211           Dans le cas ou plusieurs validateurs sont reliés par un OU
212           tous les validateurs doivent proposer un choix pour 
213           qu'on considère que leur union propose un choix.
214           Tous les choix proposés par les validateurs sont réunis (opérateur d'union)
215           Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
216           En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un choix (1,2,3,4,5,6)
217        """
218        validator_into=[]
219        for validator in self.validators:
220            v_into=validator.get_into(liste_courante,into_courant)
221            if v_into is None:
222               return v_into
223            validator_into.extend(v_into)
224        return validator_into
225     
226
227 class AndVal(Valid):
228    def info(self):
229        return "\n et ".join([v.info() for v in self.validators])
230
231    def info_erreur_item(self):
232        chaine=""
233        a=1
234        for v in self.validators:
235            if v.info_erreur_item() != "" :
236               if a==1:
237                  chaine=v.info_erreur_item()
238                  a=0
239               else:
240                  chaine=chaine+" \n et "+v.info_erreur_item()
241        return chaine
242
243    def info_erreur_liste(self):
244        a=1
245        for v in self.validators:
246            if v.info_erreur_liste() != "" :
247               if a==1:
248                  chaine=v.info_erreur_liste()
249                  a=0
250               else:
251                  chaine=chaine+" \n et "+v.info_erreur_liste()
252        return chaine
253
254    def verif_item(self,valeur):
255        for validator in self.validators:
256            v=validator.verif_item(valeur)
257            if not v :
258               # L'info n'est probablement pas la meme que pour verif ???
259               self.local_info=validator.info()
260               return 0
261        return 1
262
263    def is_list(self):
264        """
265           Si plusieurs validateurs sont reliés par un ET
266           il faut que tous les validateurs attendent une liste
267           pour qu'on considère que leur intersection attende une liste.
268           Exemple Range(2,5) ET Card(1) n'attend pas une liste
269           Range(2,5) ET Pair attend une liste
270        """
271        for validator in self.validators:
272            v=validator.is_list()
273            if v == 0 :
274               return 0
275        return 1
276
277    def has_into(self):
278        """
279           Dans le cas ou plusieurs validateurs sont reliés par un ET
280           il suffit qu'un seul validateur propose un choix pour 
281           qu'on considère que leur intersection propose un choix.
282           Exemple : Enum(1,2,3) ET entier pair, propose un choix
283           En revanche, entier pair ET superieur à 10 ne propose pas de choix 
284        """
285        for validator in self.validators:
286            v=validator.has_into()
287            if v :
288               return 1
289        return 0
290
291
292    def get_into(self,liste_courante=None,into_courant=None):
293        """
294           Dans le cas ou plusieurs validateurs sont reliés par un ET
295           il suffit qu'un seul validateur propose un choix pour 
296           qu'on considère que leur intersection propose un choix.
297
298           Tous les choix proposés par les validateurs sont croisés (opérateur d'intersection)
299           Exemple : Enum(1,2,3) ET entier pair, propose un choix (2,)
300           En revanche, Enum(1,2,3) ET Enum(4,5,6) ne propose pas de choix
301        """
302        for validator in self.validators:
303            into_courant=validator.get_into(liste_courante,into_courant)
304            if into_courant in ([],None):
305               return into_courant
306        return into_courant
307
308 class CardVal(Valid):
309    def info(self):
310        return "longueur de liste comprise entre  %s et %s" % (self.min,self.max)
311
312    def is_list(self):
313        if self.max == '**' or self.max > 1:
314              return 1
315        else:
316              return 0
317
318    def verif_item(self,valeur):
319        return 1
320
321    def valide_liste_partielle(self,liste_courante=None):
322         validite=1
323         print liste_courante
324         if liste_courante != None :
325            if len(liste_courante) > self.max :
326               validite=0
327         return validite
328
329    def get_into(self,liste_courante=None,into_courant=None):
330        if into_courant is None:
331           return None
332        elif liste_courante is None:
333           return into_courant
334        elif self.max == '**':
335           return into_courant
336        elif len(liste_courante) < self.max:
337           return into_courant
338        else:
339           return []
340
341    def info_erreur_liste(self):
342        return "La cardinalité de la liste doit être comprise entre %s et %s" % (self.min,self.max)
343
344 class ListVal(Valid):
345    def is_list(self):
346        return 1
347
348    def get_into(self,liste_courante=None,into_courant=None):
349        """
350           Cette méthode get_into effectue un traitement général qui consiste
351           a filtrer la liste de choix into_courant, si elle existe, en ne conservant
352           que les valeurs valides (appel de la méthode valid)
353        """
354        if into_courant is None:
355           return None
356        else:
357           liste_choix=[]
358           for e in into_courant:
359               if self.verif(e):
360                  liste_choix.append(e)
361           return liste_choix
362
363 class EnumVal(ListVal):
364    def verif_item(self,valeur):
365        if valeur not in self.into:return 0
366        return 1
367
368    def has_into(self):
369        return 1
370  
371    def get_into(self,liste_courante=None,into_courant=None):
372        if into_courant is None:
373           liste_choix= list(self.into)
374        else:
375           liste_choix=[]
376           for e in into_courant:
377               if e in self.into:
378                  liste_choix.append(e)
379        return liste_choix
380
381    def info_erreur_item(self):
382        return "La valeur n'est pas dans la liste des choix possibles"
383           
384 class LongStr(ListVal):
385    def info_erreur_item(self):
386        return "Longueur de la chaine incorrecte"
387
388    def verif_item(self,valeur):
389        low=self.low
390        high=self.high
391        if valeur[0]=="'" and valeur[-1]=="'" :
392           low=low+2
393           high=high+2
394        if len(valeur) < low :return 0
395        if len(valeur) > high:return 0
396        return 1
397  
398 class RangeVal(ListVal):
399    def verif_item(self,valeur):
400        if valeur < self.low :return 0
401        if valeur > self.high:return 0
402        return 1
403
404    def info_erreur_item(self) :
405        return "La valeur doit être comprise entre %s et %s" % (self.low,self.high)
406
407 class TypeVal(ListVal):
408    def verif_item(self,valeur):
409        try:
410           self.coerce(valeur)
411        except:
412           return 0
413        return 1
414
415 class PairVal(ListVal):
416
417    def info_erreur_item(self):
418        return "La valeur saisie doit être paire"
419
420    #ATTENTION METHODE SURCHARGEE: a resorber dans une future version
421    def verif_item(self,valeur):
422        if self.is_eval(valeur):
423           return 1
424        elif self.is_param(valeur):
425           valeur=valeur.valeur
426        elif self.is_unknown(valeur):
427           return 0
428        return valeur % 2 == 0
429
430    def verif(self,valeur):
431           if self.is_param(valeur):
432              valeur=valeur.valeur
433           if type(valeur) in (types.ListType,types.TupleType):
434              for val in valeur:
435                 if not self.verif_item(val):
436                    return 0
437              return 1
438           else:
439              return self.verif_item(valeur)
440
441    def verif_old(self,valeur):
442        print "Ihm.I_MCSIMP.PairVal.verif: ",valeur
443        return self.surcharge_verif(Noyau.N_VALIDATOR.PairVal.verif,valeur)
444
445 class InstanceVal(ListVal):
446    def verif_item(self,valeur):
447        if not isinstance(valeur,self.aClass): return 0
448        return 1
449
450 class NoRepeat(ListVal):
451    def info(self):
452        return "pas de presence de doublon dans la liste"
453
454    def info_erreur_liste(self):
455        return "Les doublons ne sont pas permis"
456
457    def verif_item(self,valeur):
458        return 1
459
460    def get_into(self,liste_courante=None,into_courant=None):
461        """
462           Methode get_into spécifique pour validateur NoRepeat
463           on retourne une liste de choix qui ne contient aucune valeur de into_courant
464           déjà contenue dans liste_courante
465        """
466        if into_courant is None:
467           return None
468        else:
469           liste_choix=[]
470           for e in into_courant:
471               if e in liste_choix: continue
472               if liste_courante is not None and e in liste_courante: continue
473               liste_choix.append(e)
474           return liste_choix
475  
476 class OrdList(ListVal):
477    def verif_item(self,valeur):
478        return 1
479
480    def get_into(self,liste_courante=None,into_courant=None):
481        """
482           Methode get_into spécifique pour validateur OrdList 
483           on retourne une liste de choix qui ne contient aucune valeur de into_courant
484           dont la valeur est inférieure à la dernière valeur de liste_courante, si
485           elle est différente de None.
486        """
487        if into_courant is None:
488           return None
489        elif not liste_courante :
490           return into_courant
491        else:
492           liste_choix=[]
493           last_val=liste_choix[-1]
494           for e in into_courant:
495               if self.ord=='croissant' and e <= last_val:continue
496               if self.ord=='decroissant' and e >= last_val:continue
497               liste_choix.append(e)
498           return liste_choix
499
500    def info_erreur_liste(self) :
501        return "La liste doit être en ordre "+self.ord
502