Salome HOME
c8302746b295943442f01e8751ff5576f0172457
[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 hasattr(valeur,'__class__'):
108           if valeur.__class__.__name__ in ('EVAL','entier','reel','chaine','complexe','liste','PARAMETRE_EVAL') :
109              return 1
110        return 0
111
112    def is_param(self,valeur):
113        """
114            Cette méthode indique si valeur est un objet de type PARAMETRE
115            dont on cherchera à evaluer la valeur (valeur.valeur)
116        """
117        if type(valeur) == types.InstanceType :
118           if valeur.__class__.__name__ in ('PARAMETRE',):
119              return 1
120        return 0
121
122    def is_unknown(self,valeur):
123        """
124            Cette méthode indique si valeur est un objet de type inconnu
125            c'est à dire ni de type EVAL ni de type PARAMETRE
126        """
127        if type(valeur) == types.InstanceType :
128           if not self.is_eval(valeur) and not self.is_param(valeur):
129              return 1
130        return 0
131
132    def surcharge_verif(self,methode_verif_initiale,valeur):
133        if type(valeur) == types.InstanceType :
134           #CCAR: pour le moment on fait comme dans is_entier de V_MCSIMP.py
135           # mais il serait préférable d'appeler une méthode de valeur : valeur.AsType()
136           # qui donnerait le type générique de l'objet.
137           # Pour un objet de "type" entier on obtiendrait par exemple 'I'
138           if valeur.__class__.__name__ in ('EVAL','entier','reel','chaine','complexe','liste','PARAMETRE_EVAL') :
139              # On ne vérifie pas le type d'un EVAL ou d'un objet de classe entier, .... C'est toujours valide
140              return 1
141           elif valeur.__class__.__name__ in ('PARAMETRE',):
142              # Dans le cas d'un parametre, il faut tester si la valeur du parametre est un entier
143              valeur=valeur.valeur
144           else:
145              # Objet inconnu : invalide
146              print "Objet non reconnu dans surcharge_verif : %s" %`valeur`
147              return 0
148
149        return methode_verif_initiale(self,valeur)
150
151 class FunctionVal(Valid):pass
152
153 class OrVal(Valid):
154    def verif_item(self,valeur):
155        for validator in self.validators:
156            v=validator.verif_item(valeur)
157            if v :
158               return 1
159        return 0
160
161    def info_erreur_item(self):
162        chaine=""
163        a=1
164        for v in self.validators:
165            if v.info_erreur_item() != " " :
166               if a==1:
167                  chaine=v.info_erreur_item()
168                  a=0
169               else:
170                  chaine=chaine+" \n ou "+ v.info_erreur_item()
171        return chaine
172
173    def info_erreur_liste(self):
174        chaine=""
175        a=1
176        for v in self.validators:
177            if v.info_erreur_liste() != " " :
178               if a==1:
179                  chaine=v.info_erreur_liste()
180                  a=0
181               else:
182                  chaine=chaine+" \n ou "+v.info_erreur_liste()
183
184    def is_list(self):
185        """
186           Si plusieurs validateurs sont reliés par un OU
187           il suffit qu'un seul des validateurs attende une liste
188           pour qu'on considère que leur union attende une liste.
189        """
190        for validator in self.validators:
191            v=validator.is_list()
192            if v :
193               return 1
194        return 0
195
196    def has_into(self):
197        """
198           Dans le cas ou plusieurs validateurs sont reliés par un OU
199           il faut que tous les validateurs proposent un choix pour 
200           qu'on considère que leur union propose un choix.
201           Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
202           En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un choix (1,2,3,4,5,6)
203        """
204        for validator in self.validators:
205            v=validator.has_into()
206            if not v :
207               return 0
208        return 1
209
210    def get_into(self,liste_courante=None,into_courant=None):
211        """
212           Dans le cas ou plusieurs validateurs sont reliés par un OU
213           tous les validateurs doivent proposer un choix pour 
214           qu'on considère que leur union propose un choix.
215           Tous les choix proposés par les validateurs sont réunis (opérateur d'union)
216           Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
217           En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un choix (1,2,3,4,5,6)
218        """
219        validator_into=[]
220        for validator in self.validators:
221            v_into=validator.get_into(liste_courante,into_courant)
222            if v_into is None:
223               return v_into
224            validator_into.extend(v_into)
225        return validator_into
226     
227
228 class AndVal(Valid):
229    def info(self):
230        return "\n et ".join([v.info() for v in self.validators])
231
232    def info_erreur_item(self):
233        chaine=""
234        a=1
235        for v in self.validators:
236            if v.info_erreur_item() != " " :
237               if a==1:
238                  chaine=v.info_erreur_item()
239                  a=0
240               else:
241                  chaine=chaine+" \n et "+v.info_erreur_item()
242        return chaine
243
244    def info_erreur_liste(self):
245        a=1
246        for v in self.validators:
247            if v.info_erreur_liste() != " " :
248               if a==1:
249                  chaine=v.info_erreur_liste()
250                  a=0
251               else:
252                  chaine=chaine+" \n et "+v.info_erreur_liste()
253        return chaine
254
255    def verif_item(self,valeur):
256        for validator in self.validators:
257            v=validator.verif_item(valeur)
258            if not v :
259               # L'info n'est probablement pas la meme que pour verif ???
260               self.local_info=validator.info()
261               return 0
262        return 1
263
264    def is_list(self):
265        """
266           Si plusieurs validateurs sont reliés par un ET
267           il faut que tous les validateurs attendent une liste
268           pour qu'on considère que leur intersection attende une liste.
269           Exemple Range(2,5) ET Card(1) n'attend pas une liste
270           Range(2,5) ET Pair attend une liste
271        """
272        for validator in self.validators:
273            v=validator.is_list()
274            if v == 0 :
275               return 0
276        return 1
277
278    def has_into(self):
279        """
280           Dans le cas ou plusieurs validateurs sont reliés par un ET
281           il suffit qu'un seul validateur propose un choix pour 
282           qu'on considère que leur intersection propose un choix.
283           Exemple : Enum(1,2,3) ET entier pair, propose un choix
284           En revanche, entier pair ET superieur à 10 ne propose pas de choix 
285        """
286        for validator in self.validators:
287            v=validator.has_into()
288            if v :
289               return 1
290        return 0
291
292
293    def get_into(self,liste_courante=None,into_courant=None):
294        """
295           Dans le cas ou plusieurs validateurs sont reliés par un ET
296           il suffit qu'un seul validateur propose un choix pour 
297           qu'on considère que leur intersection propose un choix.
298
299           Tous les choix proposés par les validateurs sont croisés (opérateur d'intersection)
300           Exemple : Enum(1,2,3) ET entier pair, propose un choix (2,)
301           En revanche, Enum(1,2,3) ET Enum(4,5,6) ne propose pas de choix
302        """
303        for validator in self.validators:
304            into_courant=validator.get_into(liste_courante,into_courant)
305            if into_courant in ([],None):
306               return into_courant
307        return into_courant
308
309 class CardVal(Valid):
310    def info(self):
311        return "longueur de liste comprise entre  %s et %s" % (self.min,self.max)
312
313    def is_list(self):
314        if self.max == '**' or self.max > 1:
315              return 1
316        else:
317              return 0
318
319    def verif_item(self,valeur):
320        return 1
321
322    def valide_liste_partielle(self,liste_courante=None):
323         validite=1
324         print liste_courante
325         if liste_courante != None :
326            if len(liste_courante) > self.max :
327               validite=0
328         return validite
329
330    def get_into(self,liste_courante=None,into_courant=None):
331        if into_courant is None:
332           return None
333        elif liste_courante is None:
334           return into_courant
335        elif self.max == '**':
336           return into_courant
337        elif len(liste_courante) < self.max:
338           return into_courant
339        else:
340           return []
341
342    def info_erreur_liste(self):
343        return "La cardinalité de la liste doit être comprise entre %s et %s" % (self.min,self.max)
344
345 class ListVal(Valid):
346    def is_list(self):
347        return 1
348
349    def get_into(self,liste_courante=None,into_courant=None):
350        """
351           Cette méthode get_into effectue un traitement général qui consiste
352           a filtrer la liste de choix into_courant, si elle existe, en ne conservant
353           que les valeurs valides (appel de la méthode valid)
354        """
355        if into_courant is None:
356           return None
357        else:
358           liste_choix=[]
359           for e in into_courant:
360               if self.verif(e):
361                  liste_choix.append(e)
362           return liste_choix
363
364 class EnumVal(ListVal):
365    def verif_item(self,valeur):
366        if valeur not in self.into:return 0
367        return 1
368
369    def has_into(self):
370        return 1
371  
372    def get_into(self,liste_courante=None,into_courant=None):
373        if into_courant is None:
374           liste_choix= list(self.into)
375        else:
376           liste_choix=[]
377           for e in into_courant:
378               if e in self.into:
379                  liste_choix.append(e)
380        return liste_choix
381
382    def info_erreur_item(self):
383        return "La valeur n'est pas dans la liste des choix possibles"
384           
385 class LongStr(ListVal):
386    def info_erreur_item(self):
387        return "Longueur de la chaine incorrecte"
388
389    def verif_item(self,valeur):
390        low=self.low
391        high=self.high
392        if valeur[0]=="'" and valeur[-1]=="'" :
393           low=low+2
394           high=high+2
395        if len(valeur) < low :return 0
396        if len(valeur) > high:return 0
397        return 1
398  
399 class RangeVal(ListVal):
400    def verif_item(self,valeur):
401        if valeur < self.low :return 0
402        if valeur > self.high:return 0
403        return 1
404
405    def info_erreur_item(self) :
406        return "La valeur doit être comprise entre %s et %s" % (self.low,self.high)
407
408 class TypeVal(ListVal):
409    def verif_item(self,valeur):
410        try:
411           self.coerce(valeur)
412        except:
413           return 0
414        return 1
415
416 class PairVal(ListVal):
417
418    def info_erreur_item(self):
419        return "La valeur saisie doit être paire"
420
421    #ATTENTION METHODE SURCHARGEE: a resorber dans une future version
422    def verif_item(self,valeur):
423        if self.is_eval(valeur):
424           return 1
425        elif self.is_param(valeur):
426           valeur=valeur.valeur
427        elif self.is_unknown(valeur):
428           return 0
429        return valeur % 2 == 0
430
431    def verif(self,valeur):
432           if self.is_param(valeur):
433              valeur=valeur.valeur
434           if type(valeur) in (types.ListType,types.TupleType):
435              for val in valeur:
436                 if not self.verif_item(val):
437                    return 0
438              return 1
439           else:
440              return self.verif_item(valeur)
441
442    def verif_old(self,valeur):
443        print "Ihm.I_MCSIMP.PairVal.verif: ",valeur
444        return self.surcharge_verif(Noyau.N_VALIDATOR.PairVal.verif,valeur)
445
446 class InstanceVal(ListVal):
447    def verif_item(self,valeur):
448        if not isinstance(valeur,self.aClass): return 0
449        return 1
450
451 class NoRepeat(ListVal):
452    def info(self):
453        return "pas de presence de doublon dans la liste"
454
455    def info_erreur_liste(self):
456        return "Les doublons ne sont pas permis"
457
458    def verif_item(self,valeur):
459        return 1
460
461    def get_into(self,liste_courante=None,into_courant=None):
462        """
463           Methode get_into spécifique pour validateur NoRepeat
464           on retourne une liste de choix qui ne contient aucune valeur de into_courant
465           déjà contenue dans liste_courante
466        """
467        if into_courant is None:
468           return None
469        else:
470           liste_choix=[]
471           for e in into_courant:
472               if e in liste_choix: continue
473               if liste_courante is not None and e in liste_courante: continue
474               liste_choix.append(e)
475           return liste_choix
476  
477 class OrdList(ListVal):
478    def verif_item(self,valeur):
479        return 1
480
481    def get_into(self,liste_courante=None,into_courant=None):
482        """
483           Methode get_into spécifique pour validateur OrdList 
484           on retourne une liste de choix qui ne contient aucune valeur de into_courant
485           dont la valeur est inférieure à la dernière valeur de liste_courante, si
486           elle est différente de None.
487        """
488        if into_courant is None:
489           return None
490        elif not liste_courante :
491           return into_courant
492        else:
493           liste_choix=[]
494           last_val=liste_choix[-1]
495           for e in into_courant:
496               if self.ord=='croissant' and e <= last_val:continue
497               if self.ord=='decroissant' and e >= last_val:continue
498               liste_choix.append(e)
499           return liste_choix
500
501    def info_erreur_liste(self) :
502        return "La liste doit être en ordre "+self.ord
503