Salome HOME
legere difference ds VARIABLES_TO_BE...
[tools/eficas.git] / Noyau / N_VALIDATOR.py
1 # coding=utf-8
2 # Copyright (C) 2007-2015   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
23 """
24    Ce module contient toutes les classes necessaires pour
25    implanter le concept de validateur dans Accas
26 """
27 from __future__ import absolute_import
28 from __future__ import print_function
29 try :
30    from builtins import str
31    from builtins import range
32    from builtins import object
33 except : pass
34    
35 import types
36 import traceback
37 import re
38 from .N_ASSD import ASSD
39 from .N_types import is_int, is_float_or_int, is_complex, is_number, is_str, is_sequence
40 from Extensions.i18n import tr
41 import six
42 from six.moves import range
43
44
45
46 class ValError(Exception):
47     pass
48
49
50 def cls_mro(cls):
51     if hasattr(cls, "__mro__"):
52         return cls.__mro__
53     mro = [cls]
54     for base in cls.__bases__:
55         mro.extend(cls_mro(base))
56     return mro
57
58
59 class Protocol(object):
60
61     def __init__(self, name):
62         self.registry = {}
63         self.name = name
64         self.args = {}
65
66     def register(self, T, A):
67         self.registry[T] = A
68
69     def adapt(self, obj):
70         # (a) verifier si l'objet peut s'adapter au protocole
71         adapt = getattr(obj, '__adapt__', None)
72         if adapt is not None:
73             # on demande à l'objet obj de réaliser lui-meme l'adaptation
74             return adapt(self)
75
76         # (b) verifier si un adapteur est enregistré (si oui l'utiliser)
77         if self.registry:
78             for T in cls_mro(obj.__class__):
79                 if T in self.registry:
80                     return self.registry[T](obj, self, **self.args)
81
82         # (c) utiliser l'adapteur par defaut
83         return self.default(obj, **self.args)
84
85     def default(self, obj, **args):
86         raise TypeError("Can't adapt %s to %s" %
87                         (obj.__class__.__name__, self.name))
88
89
90 class PProtocol(Protocol):
91
92     """Verificateur de protocole paramétré (classe de base)"""
93     # Protocole paramétré. Le registre est unique pour toutes les instances.
94     # La methode register est une methode de classe
95     registry = {}
96
97     def __init__(self, name, **args):
98         self.name = name
99         self.args = args
100
101     def register(cls, T, A):
102         cls.registry[T] = A
103     register = classmethod(register)
104
105
106 class ListProtocol(Protocol):
107
108     """Verificateur de protocole liste : convertit un objet quelconque en liste pour validation ultérieure"""
109
110     def default(self, obj):
111         if type(obj) is tuple:
112             if len(obj) > 0 and obj[0] in ('RI', 'MP'):
113                 # il s'agit d'un complexe ancienne mode. La cardinalite vaut 1
114                 return (obj,)
115             else:
116                 return obj
117         elif type(obj) is list:
118             return obj
119         elif obj == None:
120             # pas de valeur affecte. La cardinalite vaut 0
121             return obj
122         elif is_str(obj):
123             # il s'agit d'une chaine. La cardinalite vaut 1
124             return (obj,)
125         else:
126             try:
127                 # si l'objet supporte len, on a la cardinalite
128                 length = len(obj)
129                 return obj
130             except:
131                 # sinon elle vaut 1
132                 return (obj,)
133
134 listProto = ListProtocol("list")
135
136
137 class TypeProtocol(PProtocol):
138
139     """Verificateur de type parmi une liste de types possibles"""
140     # pas de registre par instance. Registre unique pour toutes les instances
141     # de TypeProtocol
142     registry = {}
143
144     def __init__(self, name, typ=None):
145         PProtocol.__init__(self, name, typ=typ)
146         self.typ = typ
147
148     def default(self, obj, typ):
149
150         err = ""
151         for type_permis in typ:
152             if type_permis == 'R':
153                 if is_float_or_int(obj):
154                     return obj
155             elif type_permis == 'I':
156                 if is_int(obj):
157                     return obj
158             elif type_permis == 'C':
159                 if self.is_complexe(obj):
160                     return obj
161             elif type_permis == 'TXM':
162                 if is_str(obj): 
163                    return obj
164             elif type_permis == 'shell':
165                 if is_str(obj):
166                     return obj
167             elif type_permis == 'Fichier':
168                 import os
169                 try :
170                    if (len(typ) > 2 and typ[2] == "Sauvegarde") or os.path.isfile(obj):
171                       return obj
172                    else:
173                     raise ValError( "%s n'est pas un fichier valide" % repr(obj))
174                 except : 
175                     raise ValError( "%s n'est pas un fichier valide" % repr(obj))
176
177             elif type_permis == 'FichierNoAbs':
178                 import os
179                 if (len(typ) > 2 and typ[2] == "Sauvegarde") or isinstance(obj, type("")):
180                     return obj
181                 else:
182                     raise ValError( "%s n'est pas un fichier valide" % repr(obj))
183
184             elif type_permis == 'Repertoire':
185                 import os
186                 try : 
187                   if os.path.isdir(obj): return obj
188                   else: raise ValError( "%s n'est pas un repertoire valide" % repr(obj))
189                 except :
190                   raise ValError( "%s n'est pas un repertoire valide" % repr(obj))
191             elif type_permis == 'FichierOuRepertoire':
192                 import os
193                 try : 
194                   if os.path.isdir(obj) or os.path.isfile(obj): return obj
195                   else: raise ValError( "%s n'est pas un fichier ou un repertoire valide" % repr(obj))
196                 except :
197                   raise ValError( "%s n'est pas un fichier ou un repertoire valide" % repr(obj))
198             elif type(type_permis) == type or isinstance(type_permis, type):
199                 try:
200                     if self.is_object_from(obj, type_permis):
201                         return obj
202                 except Exception as err:
203                     pass
204             elif type(type_permis) == types.InstanceType or isinstance(type_permis, object):
205                 try:
206                     if type_permis.__convert__(obj):
207                         return obj
208                 except Exception as err:
209                     pass
210             else:
211                 print(("Type non encore gere %s" %type_permis))
212         raise ValError(
213             tr("%s (de type %s) n'est pas d'un type autorise: %s %s") % (repr(obj), type(obj), typ, err))
214
215     def is_complexe(self, valeur):
216         """ Retourne 1 si valeur est un complexe, 0 sinon """
217         if is_number(valeur):
218             # Pour permettre l'utilisation de complexes Python (accepte les
219             # entiers et réels)
220             return 1
221         elif type(valeur) != tuple:
222             # On n'autorise pas les listes pour les complexes
223             return 0
224         elif len(valeur) != 3:
225             return 0
226         else:
227             # Un complexe doit etre un tuple de longueur 3 avec 'RI' ou 'MP' comme premiere
228             # valeur suivie de 2 reels.
229             if valeur[0].strip() in ('RI', 'MP'):
230                 try:
231                     v1 = reelProto.adapt(valeur[1]), reelProto.adapt(valeur[2])
232                     return 1
233                 except:
234                     return 0
235             else:
236                 return 0
237
238     def is_object_from(self, objet, classe):
239         """
240            Retourne 1 si objet est une instance de la classe classe, 0 sinon
241         """
242         convert = getattr(classe, '__convert__', None)
243         if convert is not None:
244             # classe verifie les valeurs
245             try:
246                 v = convert(objet)
247                 return v is not None
248             except ValueError as err:
249                 raise
250             except:
251                 return 0
252         # On accepte les instances de la classe et des classes derivees
253         return isinstance(objet, classe)
254
255 reelProto = TypeProtocol("reel", typ=('R',))
256
257
258 class CardProtocol(PProtocol):
259
260     """Verificateur de cardinalité """
261     # pas de registre par instance. Registre unique pour toutes les instances
262     registry = {}
263
264     def __init__(self, name, min=1, max=1):
265         PProtocol.__init__(self, name, min=min, max=max)
266
267     def default(self, obj, min, max):
268         length = len(obj)
269         if (length < min) or( length > max):
270             raise ValError(
271                 "Nombre d'arguments de %s incorrect (min = %s, max = %s)" % (repr(obj), min, max))
272         return obj
273
274
275 class IntoProtocol(PProtocol):
276
277     """Verificateur de choix possibles : liste discrète ou intervalle"""
278     # pas de registre par instance. Registre unique pour toutes les instances
279     registry = {}
280
281     def __init__(self, name, into=None, val_min=float('-inf'), val_max=float('inf')):
282      
283         PProtocol.__init__(
284             self, name, into=into, val_min=val_min, val_max=val_max)
285         self.val_min = val_min
286         self.val_max = val_max
287
288     def default(self, obj, into, val_min, val_max):
289         if type(into)  ==types.FunctionType : 
290                maListeDeValeur=into()
291                into=maListeDeValeur
292         if into:
293             if obj not in into:
294                 raise ValError(
295                         tr("La valeur : %s  ne fait pas partie des choix possibles %s") % (repr(obj), into))
296         else:
297             # on est dans le cas d'un ensemble continu de valeurs possibles
298             # (intervalle)
299             if is_float_or_int(obj):
300                 if val_min == '**':
301                     val_min = obj - 1
302                 if val_max == '**':
303                     val_max = obj + 1
304                 if obj < val_min or obj > val_max:
305                     raise ValError(
306                      tr("La valeur : %s est en dehors du domaine de validite [ %s , %s ]") %(repr(obj), self.val_min, self.val_max))
307         return obj
308
309
310 class MinStr(object):
311     # exemple de classe pour verificateur de type
312     # on utilise des instances de classe comme type (typ=MinStr(3,6), par
313     # exemple)
314
315     def __init__(self, min, max):
316         self.min = min
317         self.max = max
318
319     def __convert__(self, valeur):
320         if is_str(valeur) and self.min <= len(valeur) <= self.max: return valeur
321         raise ValError(
322             "%s n'est pas une chaine de longueur comprise entre %s et %s" % (valeur, self.min, self.max))
323
324     def __repr__(self):
325         return tr("TXM de longueur entre %s et %s" % (self.min, self.max))
326
327
328 class Valid(PProtocol):
329
330     """
331          Cette classe est la classe mere des validateurs Accas
332          Elle doit etre derivee
333          Elle presente la signature des methodes indispensables pour son bon
334          fonctionnement et dans certains cas leur comportement par défaut.
335
336          @ivar cata_info: raison de la validite ou de l'invalidite du validateur meme
337          @type cata_info: C{}
338     """
339     registry = {}
340
341     def __init__(self, **args):
342         PProtocol.__init__(self, "valid", **args)
343
344     def info(self):
345         """
346            Cette methode retourne une chaine de caractères informative sur
347            la validation demandée par le validateur. Elle est utilisée
348            pour produire le compte-rendu de validité du mot clé associé.
349         """
350         return "valeur valide"
351
352     def aide(self):
353         """
354            Cette methode retourne une chaine de caractère qui permet
355            de construire un message d'aide en ligne.
356            En général, le message retourné est le meme que celui retourné par la
357            méthode info.
358         """
359         return self.info()
360
361     def info_erreur_item(self):
362         """
363            Cette méthode permet d'avoir un message d'erreur pour un item
364            dans une liste dans le cas ou le validateur fait des vérifications
365            sur les items d'une liste. Si le validateur fait seulement des
366            vérifications sur la liste elle meme et non sur ses items, la méthode
367            doit retourner une chaine vide.
368         """
369         return " "
370
371     def info_erreur_liste(self):
372         """
373            Cette méthode a un comportement complémentaire de celui de
374            info_erreur_item. Elle retourne un message d'erreur lié uniquement
375            aux vérifications sur la liste elle meme et pas sur ses items.
376            Dans le cas où le validateur ne fait pas de vérification sur des
377            listes, elle retourne une chaine vide
378         """
379         return " "
380
381     def verif(self, valeur):
382         """
383             Cette methode sert a verifier si la valeur passee en argument est consideree
384             comme valide ou non par le validateur. Dans le premier cas le validateur retourne 1
385             (valide) sinon 0 (invalide).
386
387             @type valeur: tout type python
388             @param valeur: valeur du mot cle a valider
389             @rtype: C{boolean}
390             @return: indicateur de validite 1 (valide) ou 0 (invalide)
391         """
392         raise NotImplementedError("Must be implemented")
393
394     def verif_item(self, valeur):
395         """
396            La methode verif du validateur effectue une validation complete de
397            la valeur. valeur peut etre un scalaire ou une liste. Le validateur
398            doit traiter les 2 aspects s'il accepte des listes (dans ce cas la
399            methode is_list doit retourner 1).
400            La methode valid_item sert pour effectuer des validations partielles
401            de liste. Elle doit uniquement verifier la validite d'un item de
402            liste mais pas les caracteristiques de la liste.
403         """
404         return 0
405
406     def valide_liste_partielle(self, liste_courante):
407         """
408            Cette methode retourne un entier qui indique si liste_courante est partiellement valide (valeur 1)
409            ou invalide (valeur 0). La validation partielle concerne les listes en cours de construction : on
410            veut savoir si la liste en construction peut etre complétée ou si elle peut déjà etre considérée
411            comme invalide.
412            En général un validateur effectue la meme validation pour les listes partielles et les
413            listes complètes.
414         """
415         return self.verif(liste_courante)
416
417     def verif_cata(self):
418         """
419             Cette methode sert a realiser des verifications du validateur lui meme.
420             Elle est facultative et retourne 1 (valide) par defaut.
421             Elle retourne 0 si le validateur est lui meme invalide si par exemple ses
422             parametres de definition ne sont pas corrects.
423             La raison de l'invalidite est stockee dans l'attribut cata_info.
424
425             @rtype: C{boolean}
426             @return: indicateur de validite 1 (valide) ou 0 (invalide)
427         """
428         return 1
429
430     def is_list(self):
431         """
432            Cette méthode retourne un entier qui indique si le validateur
433            permet les listes (valeur 1) ou ne les permet pas (valeur 0).
434            Par défaut, un validateur n'autorise que des scalaires.
435         """
436         return 0
437
438     def has_into(self):
439         """
440            Cette méthode retourne un entier qui indique si le validateur
441            propose une liste de choix (valeur 1) ou n'en propose pas.
442            Par défaut, un validateur n'en propose pas.
443         """
444         return 0
445
446     def get_into(self, liste_courante=None, into_courant=None):
447         """
448            Cette méthode retourne la liste de choix proposée par le validateur.
449            Si le validateur ne propose pas de liste de choix, la méthode
450            retourne None.
451            L'argument d'entrée liste_courante, s'il est différent de None, donne
452            la liste des choix déjà effectués par l'utilisateur. Dans ce cas, la
453            méthode get_into doit calculer la liste des choix en en tenant
454            compte. Par exemple, si le validateur n'autorise pas les répétitions,
455            la liste des choix retournée ne doit pas contenir les choix déjà
456            contenus dans liste_courante.
457            L'argument d'entrée into_courant, s'il est différent de None, donne
458            la liste des choix proposés par d'autres validateurs. Dans ce cas,
459            la méthode get_into doit calculer la liste des choix à retourner
460            en se limitant à cette liste initiale. Par exemple, si into_courant
461            vaut (1,2,3) et que le validateur propose la liste de choix (3,4,5),
462            la méthode ne doit retourner que (3,).
463
464            La méthode get_into peut retourner une liste vide [], ce qui veut
465            dire qu'il n'y a pas (ou plus) de choix possible. Cette situation
466            peut etre normale : l''utilisateur a utilisé tous les choix, ou
467            résulter d'une incohérence des validateurs :
468            choix parmi (1,2,3) ET choix parmi (4,5,6). Il est impossible de
469            faire la différence entre ces deux situations.
470         """
471         return into_courant
472
473
474 class ListVal(Valid):
475
476     """
477         Cette classe sert de classe mère pour tous les validateurs qui acceptent
478         des listes.
479     """
480
481     def is_list(self):
482         return 1
483
484     def get_into(self, liste_courante=None, into_courant=None):
485         """
486            Cette méthode get_into effectue un traitement général qui consiste
487            a filtrer la liste de choix into_courant, si elle existe, en ne
488            conservant que les valeurs valides (appel de la méthode valid).
489         """
490         if into_courant is None:
491             return None
492         else:
493             liste_choix = []
494             for e in into_courant:
495                 if self.verif(e):
496                     liste_choix.append(e)
497             return liste_choix
498
499     def convert(self, valeur):
500         """
501            Méthode convert pour les validateurs de listes. Cette méthode
502            fait appel à la méthode convert_item sur chaque élément de la
503            liste.
504         """
505         if is_sequence(valeur):
506             for val in valeur:
507                 self.convert_item(val)
508             return valeur
509         else:
510             return self.convert_item(valeur)
511
512     def verif(self, valeur):
513         """
514            Méthode verif pour les validateurs de listes. Cette méthode
515            fait appel à la méthode verif_item sur chaque élément de la
516            liste. Si valeur est un paramètre, on utilise sa valeur effective
517            valeur.valeur.
518         """
519         if is_sequence(valeur):
520             for val in valeur:
521                 if not self.verif_item(val):
522                     return 0
523             return 1
524         else:
525             return self.verif_item(valeur)
526
527
528 class Compulsory(ListVal):
529     """
530         Validateur operationnel
531         Verification de la présence obligatoire d'un élément dans une liste
532     """
533     registry = {}
534
535     def __init__(self, elem=()):
536         if not is_sequence(elem):
537             elem = (elem,)
538         Valid.__init__(self, elem=elem)
539         self.elem = elem
540         self.cata_info = ""
541
542     def info(self):
543         return (tr(u"valeur %s obligatoire") % self.elem)
544
545     def default(self, valeur, elem):
546         return valeur
547
548     def verif_item(self, valeur):
549         return 1
550
551     def convert(self, valeur):
552         elem = list(self.elem)
553         for val in valeur:
554             v = self.adapt(val)
555             if v in elem:
556                 elem.remove(v)
557         if elem:
558             raise ValError(
559                 tr("%s ne contient pas les elements obligatoires : %s ") % (valeur, elem))
560         return valeur
561
562     def has_into(self):
563         return 1
564
565     def verif(self, valeur):
566         if not is_sequence(valeur):
567             liste = list(valeur)
568         else:
569             liste = valeur
570         for val in self.elem:
571             if val not in liste:
572                 return 0
573         return 1
574
575     def info_erreur_item(self):
576         return tr("La valeur n'est pas dans la liste des choix possibles")
577
578
579 class Together(ListVal):
580     """
581         Validateur operationnel
582         si un des éléments est présent les autres doivent aussi l'être
583     """
584     registry = {}
585
586     def __init__(self, elem=()):
587         if not is_sequence(elem):
588             elem = (elem,)
589         Valid.__init__(self, elem=elem)
590         self.elem = elem
591         self.cata_info = ""
592
593     def info(self):
594         return (tr("%s present ensemble") % self.elem)
595
596     def default(self, valeur, elem):
597         return valeur
598
599     def verif_item(self, valeur):
600         return 1
601
602     def convert(self, valeur):
603         elem = list(self.elem)
604         for val in valeur:
605             v = self.adapt(val)
606             if v in elem: elem.remove(v)
607         if ( len(elem) == 0 ): return valeur
608         if len(elem) != len(list(self.elem)) :
609             raise ValError(tr("%s ne contient pas les elements devant etre presents ensemble: %s ") %( valeur, elem))
610         return valeur
611
612     def has_into(self):
613         return 1
614
615     def verif(self, valeur):
616         if not is_sequence(valeur):
617             liste = list(valeur)
618         else:
619             liste = valeur
620         compte = 0
621         for val in self.elem:
622             if val in liste: compte += 1
623         if ( compte == 0 ): return 1
624         if ( compte != len( list(self.elem) ) ): return 0
625         return 1
626
627     def info_erreur_item(self):
628         return tr("La valeur n'est pas dans la liste des choix possibles")
629
630
631 class Absent(ListVal):
632     """
633         Validateur operationnel
634         si un des éléments est présent non valide
635     """
636     registry = {}
637
638     def __init__(self, elem=()):
639         if not is_sequence(elem):
640             elem = (elem,)
641         Valid.__init__(self, elem=elem)
642         self.elem = elem
643         self.cata_info = ""
644
645     def info(self):
646         return (tr("%s absent") % self.elem)
647
648     def default(self, valeur, elem):
649         return valeur
650
651     def verif_item(self, valeur):
652         return 1
653
654     def convert(self, valeur):
655         elem = list(self.elem)
656         for val in valeur:
657             v = self.adapt(val)
658             if v in elem:
659                 raise ValError(tr("%s n'est pas autorise : %s ")% (v, elem))
660         return valeur
661
662     def has_into(self):
663         return 1
664
665     def verif(self, valeur):
666         if not is_sequence(valeur):
667             liste = list(valeur)
668         else:
669             liste = valeur
670         for val in self.elem:
671             if val in liste: return 0
672         return 1
673
674     def info_erreur_item(self):
675         return tr("La valeur n'est pas dans la liste des choix possibles")
676
677
678 class NoRepeat(ListVal):
679     """
680         Validateur operationnel
681         Verification d'absence de doublons dans la liste.
682     """
683     def __init__(self):
684         Valid.__init__(self)
685         self.cata_info = ""
686
687     def info(self):
688         return tr("Pas de doublon dans la liste")
689
690     def info_erreur_liste(self):
691         return tr("Les doublons ne sont pas permis")
692
693     def default(self, valeur):
694         if valeur in self.liste:
695             raise ValError( tr("%s est un doublon") % valeur)
696         return valeur
697
698     def convert(self, valeur):
699         self.liste = []
700         for val in valeur:
701             v = self.adapt(val)
702             self.liste.append(v)
703         return valeur
704
705     def verif_item(self, valeur):
706         return 1
707
708     def verif(self, valeur):
709         if is_sequence(valeur):
710             liste = list(valeur)
711             for val in liste:
712                 if liste.count(val) != 1:
713                     return 0
714             return 1
715         else:
716             return 1
717
718     def get_into(self, liste_courante=None, into_courant=None):
719         """
720         Methode get_into spécifique pour validateur NoRepeat, on retourne
721         une liste de choix qui ne contient aucune valeur de into_courant
722         déjà contenue dans liste_courante
723         """
724         if into_courant is None:
725             liste_choix = None
726         else:
727             liste_choix = []
728             for e in into_courant:
729                 if e in liste_choix:
730                     continue
731                 if liste_courante is not None and e in liste_courante:
732                     continue
733                 liste_choix.append(e)
734         return liste_choix
735
736
737 class LongStr(ListVal):
738
739     """
740         Validateur operationnel
741         Verification de la longueur d une chaine
742     """
743
744     def __init__(self, low, high):
745         ListVal.__init__(self, low=low, high=high)
746         self.low = low
747         self.high = high
748         self.cata_info = ""
749
750     def info(self):
751         return (tr("longueur de la chaine entre %s et %s") %( self.low, self.high))
752
753     def info_erreur_item(self):
754         return tr("Longueur de la chaine incorrecte")
755
756     def convert(self, valeur):
757         for val in valeur:
758             v = self.adapt(val)
759         return valeur
760
761     def verif_item(self, valeur):
762         try:
763             self.adapt(valeur)
764             return 1
765         except:
766             return 0
767
768     def default(self, valeur, low, high):
769         if not is_str(valeur):
770             raise ValError ("%s n'est pas une chaine" % repr(valeur))
771         if valeur[0] == "'" and valeur[-1] == "'":
772             low = low + 2
773             high = high + 2
774         if len(valeur) < low or len(valeur) > high:
775             raise ValError(
776                 "%s n'est pas de la bonne longueur" % repr(valeur))
777         return valeur
778
779
780 class OnlyStr(ListVal):
781
782     """
783         Validateur operationnel
784         Valide que c'est une chaine
785     """
786
787     def __init__(self):
788         ListVal.__init__(self)
789         self.cata_info = ""
790
791     def info(self):
792         return tr("regarde si c'est une chaine")
793
794     def info_erreur_item(self):
795         return tr("Ce n'est pas une chaine")
796
797     def convert(self, valeur):
798         for val in valeur:
799             v = self.adapt(val)
800         return valeur
801
802     def verif_item(self, valeur):
803         try:
804             self.adapt(valeur)
805             return 1
806         except:
807             return 0
808
809     def default(self, valeur):
810         if not is_str(valeur):
811             raise ValError (tr("%s n'est pas une chaine") % repr(valeur))
812         return valeur
813
814
815 class OrdList(ListVal):
816
817     """
818         Validateur operationnel
819         Verification qu'une liste est croissante ou decroissante
820     """
821
822     def __init__(self, ord):
823         ListVal.__init__(self, ord=ord)
824         self.ord = ord
825         self.cata_info = ""
826
827     def info(self):
828         return ("liste %s" % self.ord)
829
830     def info_erreur_liste(self):
831         return (tr("La liste doit etre en ordre %s") % self.ord)
832
833     def convert(self, valeur):
834         self.val = None
835         self.liste = valeur
836         for v in valeur:
837             self.adapt(v)
838         return valeur
839
840     def default(self, valeur, ord):
841         if self.ord == 'croissant':
842             if self.val is not None and valeur < self.val:
843                 raise ValError(
844                     (tr("%s n'est pas par valeurs croissantes") % repr(self.liste)))
845         elif self.ord == 'decroissant':
846             if self.val is not None and valeur > self.val:
847                 raise ValError(
848                     (tr("%s n'est pas par valeurs decroissantes") % repr(self.liste)))
849         self.val = valeur
850         return valeur
851
852     def verif_item(self, valeur):
853         return 1
854
855     def get_into(self, liste_courante=None, into_courant=None):
856         """
857         Methode get_into spécifique pour validateur OrdList, on retourne
858         une liste de choix qui ne contient aucune valeur de into_courant
859         dont la valeur est inférieure à la dernière valeur de
860         liste_courante, si elle est différente de None.
861         """
862         if into_courant is None:
863             return None
864         elif not liste_courante:
865             return into_courant
866         else:
867             liste_choix = []
868             last_val = liste_choix[-1]
869             for e in into_courant:
870                 if self.ord == 'croissant' and e <= last_val:
871                     continue
872                 if self.ord == 'decroissant' and e >= last_val:
873                     continue
874                 liste_choix.append(e)
875             return liste_choix
876
877
878 class OrVal(Valid):
879
880     """
881         Validateur operationnel
882         Cette classe est un validateur qui controle une liste de validateurs
883         Elle verifie qu'au moins un des validateurs de la liste valide la valeur
884     """
885
886     def __init__(self, validators=()):
887         if not is_sequence(validators):
888             validators = (validators,)
889         self.validators = []
890         for validator in validators:
891             if type(validator) == types.FunctionType:
892                 self.validators.append(FunctionVal(validator))
893             else:
894                 self.validators.append(validator)
895         self.cata_info = ""
896
897     def info(self):
898         return "\n ou ".join([v.info() for v in self.validators])
899
900     def convert(self, valeur):
901         for validator in self.validators:
902             try:
903                 return validator.convert(valeur)
904             except:
905                 pass
906         raise ValError(tr("%s n'est pas du bon type")% repr(valeur))
907
908     def info_erreur_item(self):
909         l = []
910         for v in self.validators:
911             err = v.info_erreur_item()
912             if err != " ":
913                 l.append(err)
914         chaine = " \n ou ".join(l)
915         return chaine
916
917     def info_erreur_liste(self):
918         l = []
919         for v in self.validators:
920             err = v.info_erreur_liste()
921             if err != " ":
922                 l.append(err)
923         chaine = " \n ou ".join(l)
924         return chaine
925
926     def is_list(self):
927         """
928            Si plusieurs validateurs sont reliés par un OU
929            il suffit qu'un seul des validateurs attende une liste
930            pour qu'on considère que leur union attend une liste.
931         """
932         for validator in self.validators:
933             v = validator.is_list()
934             if v:
935                 return 1
936         return 0
937
938     def verif(self, valeur):
939         for validator in self.validators:
940             v = validator.verif(valeur)
941             if v:
942                 return 1
943         return 0
944
945     def verif_item(self, valeur):
946         for validator in self.validators:
947             v = validator.verif_item(valeur)
948             if v:
949                 return 1
950         return 0
951
952     def verif_cata(self):
953         infos = []
954         for validator in self.validators:
955             v = validator.verif_cata()
956             if not v:
957                 infos.append(validator.cata_info)
958         if infos:
959             self.cata_info = "\n".join(infos)
960             return 0
961         self.cata_info = ""
962         return 1
963
964     def has_into(self):
965         """
966         Dans le cas ou plusieurs validateurs sont reliés par un OU
967         il faut que tous les validateurs proposent un choix pour
968         qu'on considère que leur union propose un choix.
969         Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
970         En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un choix (1,2,3,4,5,6)
971         """
972         for validator in self.validators:
973             v = validator.has_into()
974             if not v:
975                 return 0
976         return 1
977
978     def get_into(self, liste_courante=None, into_courant=None):
979         """
980         Dans le cas ou plusieurs validateurs sont reliés par un OU
981         tous les validateurs doivent proposer un choix pour
982         qu'on considère que leur union propose un choix. Tous les choix
983         proposés par les validateurs sont réunis (opérateur d'union).
984         Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
985         En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un
986         choix (1,2,3,4,5,6)
987         """
988         validator_into = []
989         for validator in self.validators:
990             v_into = validator.get_into(liste_courante, into_courant)
991             if v_into is None:
992                 return v_into
993             validator_into.extend(v_into)
994         return validator_into
995
996     def valide_liste_partielle(self, liste_courante=None):
997         """
998          Méthode de validation de liste partielle pour le validateur Or.
999          Si un des validateurs gérés par le validateur Or considère la
1000          liste comme valide, le validateur Or la considère comme valide.
1001         """
1002         for validator in self.validators:
1003             v = validator.valide_liste_partielle(liste_courante)
1004             if v:
1005                 return 1
1006         return 0
1007
1008
1009 class AndVal(Valid):
1010
1011     """
1012         Validateur operationnel
1013         Cette classe est un validateur qui controle une liste de validateurs
1014         Elle verifie que tous les validateurs de la liste valident la valeur
1015     """
1016
1017     def __init__(self, validators=()):
1018         if not is_sequence(validators):
1019             validators = (validators,)
1020         self.validators = []
1021         for validator in validators:
1022             if type(validator) == types.FunctionType:
1023                 self.validators.append(FunctionVal(validator))
1024             else:
1025                 self.validators.append(validator)
1026             if hasattr(validator, 'fonctions'):
1027                 for fonction in validator.fonctions:
1028                     f = getattr(validator, fonction)
1029                     setattr(self, fonction, f)
1030         self.cata_info = ""
1031
1032     def info(self):
1033         return "\n et ".join([v.info() for v in self.validators])
1034
1035     def convert(self, valeur):
1036         for validator in self.validators:
1037             valeur = validator.convert(valeur)
1038         return valeur
1039
1040     def info_erreur_item(self):
1041         chaine = ""
1042         a = 1
1043         for v in self.validators:
1044             if v.info_erreur_item() != " ":
1045                 if a == 1:
1046                     chaine = v.info_erreur_item()
1047                     a = 0
1048                 else:
1049                     chaine = chaine + " \n et " + v.info_erreur_item()
1050         return chaine
1051
1052     def info_erreur_liste(self):
1053         chaine=""
1054         a = 1
1055         for v in self.validators:
1056             if v.info_erreur_liste() != " ":
1057                 if a == 1:
1058                     chaine = v.info_erreur_liste()
1059                     a = 0
1060                 else:
1061                     chaine = chaine + " \n et " + v.info_erreur_liste()
1062         return chaine
1063
1064     def verif(self, valeur):
1065         for validator in self.validators:
1066             v = validator.verif(valeur)
1067             if not v:
1068                 self.local_info = validator.info()
1069                 return 0
1070         return 1
1071
1072     def verif_item(self, valeur):
1073         for validator in self.validators:
1074             v = validator.verif_item(valeur)
1075             if not v:
1076                 # L'info n'est probablement pas la meme que pour verif ???
1077                 self.local_info = validator.info()
1078                 return 0
1079         return 1
1080
1081     def verif_cata(self):
1082         infos = []
1083         for validator in self.validators:
1084             v = validator.verif_cata()
1085             if not v:
1086                 infos.append(validator.cata_info)
1087         if infos:
1088             self.cata_info = "\n".join(infos)
1089             return 0
1090         self.cata_info = ""
1091         return 1
1092
1093     def valide_liste_partielle(self, liste_courante=None):
1094         """
1095          Méthode de validation de liste partielle pour le validateur And.
1096          Tous les validateurs gérés par le validateur And doivent considérer
1097          la liste comme valide, pour que le validateur And la considère
1098          comme valide.
1099         """
1100         for validator in self.validators:
1101             v = validator.valide_liste_partielle(liste_courante)
1102             if not v:
1103                 return 0
1104         return 1
1105
1106     def is_list(self):
1107         """
1108         Si plusieurs validateurs sont reliés par un ET
1109         il faut que tous les validateurs attendent une liste
1110         pour qu'on considère que leur intersection attende une liste.
1111         Exemple Range(2,5) ET Card(1) n'attend pas une liste
1112         Range(2,5) ET Pair attend une liste
1113         """
1114         for validator in self.validators:
1115             v = validator.is_list()
1116             if v == 0:
1117                 return 0
1118         return 1
1119
1120     def has_into(self):
1121         """
1122         Dans le cas ou plusieurs validateurs sont reliés par un ET
1123         il suffit qu'un seul validateur propose un choix pour
1124         qu'on considère que leur intersection propose un choix.
1125         Exemple : Enum(1,2,3) ET entier pair, propose un choix
1126         En revanche, entier pair ET superieur à 10 ne propose pas de choix
1127         """
1128         for validator in self.validators:
1129             v = validator.has_into()
1130             if v:
1131                 return 1
1132         return 0
1133
1134     def get_into(self, liste_courante=None, into_courant=None):
1135         """
1136         Dans le cas ou plusieurs validateurs sont reliés par un ET
1137         il suffit qu'un seul validateur propose un choix pour
1138         qu'on considère que leur intersection propose un choix. Tous les
1139         choix proposés par les validateurs sont croisés (opérateur
1140         d'intersection)
1141         Exemple : Enum(1,2,3) ET entier pair, propose un choix (2,)
1142         En revanche, Enum(1,2,3) ET Enum(4,5,6) ne propose pas de choix.
1143         """
1144         for validator in self.validators:
1145             into_courant = validator.get_into(liste_courante, into_courant)
1146             if into_courant in ([], None):
1147                 break
1148         return into_courant
1149
1150
1151 def do_liste(validators):
1152     """
1153        Convertit une arborescence de validateurs en OrVal ou AndVal
1154        validators est une liste de validateurs ou de listes ou de tuples
1155     """
1156     valids = []
1157     for validator in validators:
1158         if type(validator) == types.FunctionType:
1159             valids.append(FunctionVal(validator))
1160         elif type(validator) is tuple:
1161             valids.append(OrVal(do_liste(validator)))
1162         elif type(validator) is list:
1163             valids.append(AndVal(do_liste(validator)))
1164         else:
1165             valids.append(validator)
1166     return valids
1167
1168
1169 def validatorFactory(validator):
1170     if type(validator) == types.FunctionType:
1171         return FunctionVal(validator)
1172     elif type(validator) is tuple:
1173         return OrVal(do_liste(validator))
1174     elif type(validator) is list:
1175         return AndVal(do_liste(validator))
1176     else:
1177         return validator
1178
1179 # Ci-dessous : exemples de validateur (peu testés)
1180
1181
1182 class RangeVal(ListVal):
1183
1184     """
1185         Exemple de classe validateur : verification qu'une valeur
1186         est dans un intervalle.
1187         Pour une liste on verifie que tous les elements sont
1188         dans l'intervalle
1189         Susceptible de remplacer les attributs "vale_min" "vale_max"
1190         dans les catalogues
1191     """
1192
1193     def __init__(self, low, high):
1194         self.low = low
1195         self.high = high
1196         self.cata_info = (tr("%s doit etre inferieur a %s") % (low, high))
1197
1198     def info(self):
1199         return (tr("valeur dans l'intervalle %s , %s") %( self.low, self.high))
1200
1201     def convert_item(self, valeur):
1202         if valeur > self.low and valeur < self.high:
1203             return valeur
1204         raise ValError(tr("%s devrait etre comprise entre %s et %s") % (valeur, self.low, self.high))
1205
1206     def verif_item(self, valeur):
1207         return valeur > self.low and valeur < self.high
1208
1209     def info_erreur_item(self):
1210         return (tr("la valeur %s doit etre comprise entre %s et %s") % (valeur, self.low, self.high))
1211
1212
1213     def verif_cata(self):
1214         if self.low > self.high:
1215             return 0
1216         return 1
1217
1218
1219 class CardVal(Valid):
1220
1221     """
1222         Exemple de classe validateur : verification qu'une liste est
1223         d'une longueur superieur a un minimum (min) et inferieure
1224         a un maximum (max).
1225         Susceptible de remplacer les attributs "min" "max" dans les
1226         catalogues
1227     """
1228
1229     def __init__(self, min=float('-inf'), max=float('inf')):
1230         self.min = min
1231         self.max = max
1232         self.cata_info = (tr("%s doit etre inferieur a %s") %(min, max))
1233
1234     def info(self):
1235         return (tr("longueur de liste comprise entre  %s et %s") %(self.min, self.max))
1236
1237     def info_erreur_liste(self):
1238         return (tr("Le cardinal de la liste doit etre compris entre %s et %s") % (self.min, self.max))
1239
1240     def is_list(self):
1241         return self.max == '**' or self.max > 1
1242
1243     def get_into(self, liste_courante=None, into_courant=None):
1244         if into_courant is None:
1245             return None
1246         elif liste_courante is None:
1247             return into_courant
1248         elif self.max == '**':
1249             return into_courant
1250         elif len(liste_courante) < self.max:
1251             return into_courant
1252         else:
1253             return []
1254
1255     def convert(self, valeur):
1256         if is_sequence(valeur):
1257             l = len(valeur)
1258         elif valeur is None:
1259             l = 0
1260         else:
1261             l = 1
1262         if self.max != '**' and l > self.max:
1263             raise ValError(
1264                 tr("%s devrait etre de longueur inferieure a %s") % (valeur, self.max))
1265         if self.min != '**' and l < self.min:
1266             raise ValError(
1267                 tr("%s devrait etre de longueur superieure a %s") % (valeur, self.min))
1268         return valeur
1269
1270     def verif_item(self, valeur):
1271         return 1
1272
1273     def verif(self, valeur):
1274         if is_sequence(valeur):
1275             if self.max != '**' and len(valeur) > self.max:
1276                 return 0
1277             if self.min != '**' and len(valeur) < self.min:
1278                 return 0
1279             return 1
1280         else:
1281             if self.max != '**' and 1 > self.max:
1282                 return 0
1283             if self.min != '**' and 1 < self.min:
1284                 return 0
1285             return 1
1286
1287     def verif_cata(self):
1288         if self.min != '**' and self.max != '**' and self.min > self.max:
1289             return 0
1290         return 1
1291
1292     def valide_liste_partielle(self, liste_courante=None):
1293         validite = 1
1294         if liste_courante != None:
1295             if len(liste_courante) > self.max:
1296                 validite = 0
1297         return validite
1298
1299
1300 class PairVal(ListVal):
1301
1302     """
1303         Exemple de classe validateur : verification qu'une valeur
1304         est paire.
1305         Pour une liste on verifie que tous les elements sont
1306         pairs
1307     """
1308
1309     def __init__(self):
1310         ListVal.__init__(self)
1311         self.cata_info = ""
1312
1313     def info(self):
1314         return _(u"valeur paire")
1315
1316     def info_erreur_item(self):
1317         return tr("La valeur saisie doit etre paire")
1318
1319     def convert(self, valeur):
1320         for val in valeur:
1321             v = self.adapt(val)
1322             if v % 2 != 0:
1323                 raise ValError(
1324                     tr("%s contient des valeurs non paires") % repr(valeur))
1325         return valeur
1326
1327     def default(self, valeur):
1328         return valeur
1329
1330     def verif_item(self, valeur):
1331         if type(valeur) not in six.integer_types:
1332             return 0
1333         return valeur % 2 == 0
1334
1335     def verif(self, valeur):
1336         if is_sequence(valeur):
1337             for val in valeur:
1338                 if val % 2 != 0:
1339                     return 0
1340             return 1
1341         else:
1342             if valeur % 2 != 0:
1343                 return 0
1344             return 1
1345
1346
1347 class EnumVal(ListVal):
1348
1349     """
1350         Exemple de classe validateur : verification qu'une valeur
1351         est prise dans une liste de valeurs.
1352         Susceptible de remplacer l attribut "into" dans les catalogues
1353     """
1354
1355     def __init__(self, into=()):
1356         if not is_sequence(into):
1357             into = (into,)
1358         self.into = into
1359         self.cata_info = ""
1360
1361     def info(self):
1362         return ("valeur dans %s" % self.into)
1363
1364     def convert_item(self, valeur):
1365         if valeur in self.into:
1366             return valeur
1367         raise ValError(
1368             tr("%s contient des valeurs hors des choix possibles: %s ") % (valeur, self.into))
1369
1370     def verif_item(self, valeur):
1371         if valeur not in self.into:
1372             return 0
1373         return 1
1374
1375     def has_into(self):
1376         return 1
1377
1378     def get_into(self, liste_courante=None, into_courant=None):
1379         if into_courant is None:
1380             liste_choix = list(self.into)
1381         else:
1382             liste_choix = []
1383             for e in into_courant:
1384                 if e in self.into:
1385                     liste_choix.append(e)
1386         return liste_choix
1387
1388     def info_erreur_item(self):
1389         return tr("La valeur n'est pas dans la liste des choix possibles")
1390
1391
1392 def ImpairVal(valeur):
1393     """
1394           Exemple de validateur
1395         Cette fonction est un validateur. Elle verifie que la valeur passee
1396         est bien un nombre impair.
1397     """
1398     if is_sequence(valeur):
1399         for val in valeur:
1400             if val % 2 != 1:
1401                 return 0
1402         return 1
1403     else:
1404         if valeur % 2 != 1:
1405             return 0
1406         return 1
1407
1408 ImpairVal.info = "valeur impaire"
1409
1410
1411 class F1Val(Valid):
1412
1413     """
1414         Exemple de validateur
1415         Cette classe est un validateur de dictionnaire (mot cle facteur ?). Elle verifie
1416         que la somme des cles A et B vaut une valeur donnee
1417         en parametre du validateur
1418     """
1419
1420     def __init__(self, somme=10):
1421         self.somme = somme
1422         self.cata_info = ""
1423
1424     def info(self):
1425         return (tr("valeur %s pour la somme des cles A et B ") % self.somme)
1426
1427     def verif(self, valeur):
1428         if is_sequence(valeur):
1429             for val in valeur:
1430                 if not "A" in val:
1431                     return 0
1432                 if not "B" in val:
1433                     return 0
1434                 if val["A"] + val["B"] != self.somme:
1435                     return 0
1436             return 1
1437         else:
1438             if not "A" in valeur:
1439                 return 0
1440             if not "B" in valeur:
1441                 return 0
1442             if valeur["A"] + valeur["B"] != self.somme:
1443                 return 0
1444             return 1
1445
1446
1447 class FunctionVal(Valid):
1448
1449     """
1450         Exemple de validateur
1451         Cette classe est un validateur qui est initialise avec une fonction
1452     """
1453
1454     def __init__(self, function):
1455         self.function = function
1456
1457     def info(self):
1458         return self.function.info
1459
1460     def info_erreur_item(self):
1461         return self.function.info
1462
1463     def verif(self, valeur):
1464         return self.function(valeur)
1465
1466     def verif_item(self, valeur):
1467         return self.function(valeur)
1468
1469     def convert(self, valeur):
1470         return valeur
1471
1472 # MC ca ne devrait plus servir !
1473 CoercableFuncs = {int:     int,
1474                   int:    int,
1475                   float:   float,
1476                   complex: complex,
1477                   str: six.text_type}
1478
1479
1480 #class FunctionValObjet(FunctionVal):
1481 #OOOOOOOOOOOOOOo
1482
1483 class TypeVal(ListVal):
1484
1485     """
1486         Exemple de validateur
1487         Cette classe est un validateur qui controle qu'une valeur
1488         est bien du type Python attendu.
1489         Pour une liste on verifie que tous les elements sont du bon type.
1490         Semblable a InstanceVal mais ici on fait le test par tentative de conversion
1491         alors qu'avec InstanceVal on ne teste que si isinstance est vrai.
1492     """
1493
1494     def __init__(self, aType):
1495         # Si aType n'est pas un type, on le retrouve a l'aide de la fonction type
1496         # type(1) == int;type(0.2)==float;etc.
1497         if type(aType) != type:
1498             aType = type(aType)
1499         self.aType = aType
1500         try:
1501             self.coerce = CoercableFuncs[aType]
1502         except:
1503             self.coerce = self.identity
1504
1505     def info(self):
1506         return (tr("valeur de %s") % self.aType)
1507
1508     def identity(self, value):
1509         if type(value) == self.aType:
1510             return value
1511         raise ValError
1512
1513     def convert_item(self, valeur):
1514         return self.coerce(valeur)
1515
1516     def verif_item(self, valeur):
1517         try:
1518             self.coerce(valeur)
1519         except:
1520             return 0
1521         return 1
1522
1523
1524 class InstanceVal(ListVal):
1525
1526     """
1527         Exemple de validateur
1528         Cette classe est un validateur qui controle qu'une valeur est
1529         bien une instance (au sens Python) d'une classe
1530         Pour une liste on verifie chaque element de la liste
1531     """
1532
1533     def __init__(self, aClass):
1534         # Si aClass est une classe on la memorise dans self.aClass
1535         # sinon c'est une instance dont on memorise la classe
1536         if type(aClass) == types.InstanceType:
1537             # instance ancienne mode
1538             aClass = aClass.__class__
1539         elif type(aClass) == type:
1540             # classe ancienne mode
1541             aClass = aClass
1542         elif type(aClass) == type:
1543             # classe nouvelle mode
1544             aClass = aClass
1545         elif isinstance(aClass, object):
1546             # instance nouvelle mode
1547             aClass = type(aClass)
1548         else:
1549             raise ValError(tr("type non supporté"))
1550
1551         self.aClass = aClass
1552
1553     def info(self):
1554         return (tr("valeur d'instance de %s") % self.aClass.__name__)
1555
1556     def verif_item(self, valeur):
1557         if not isinstance(valeur, self.aClass):
1558             return 0
1559         return 1
1560
1561
1562 class VerifTypeTuple(ListVal):
1563
1564     def __init__(self, typeDesTuples):
1565         self.typeDesTuples = typeDesTuples
1566         Valid.__init__(self)
1567         self.cata_info = ""
1568
1569     def info(self):
1570         return tr(": verifie les types dans un tuple")
1571
1572     def info_erreur_liste(self):
1573         return tr("Les types entres ne sont pas permis")
1574
1575     def default(self, valeur):
1576         return valeur
1577
1578     def is_list(self):
1579         return 1
1580
1581     def convert_item(self, valeur):
1582         if len(valeur) != len(self.typeDesTuples):
1583             raise ValError(
1584                 tr("%s devrait etre de type  %s ") %( valeur, self.typeDesTuples))
1585         for i in range(len(valeur)):
1586             ok = self.verifType(valeur[i], self.typeDesTuples[i])
1587             if ok != 1:
1588                 raise ValError(
1589                     tr("%s devrait etre de type  %s ") % (valeur, self.typeDesTuples))
1590         return valeur
1591
1592     def verif_item(self, valeur):
1593         try:
1594             if len(valeur) != len(self.typeDesTuples):
1595                 return 0
1596             for i in range(len(valeur)):
1597                 ok = self.verifType(valeur[i], self.typeDesTuples[i])
1598                 if ok != 1:
1599                     return 0
1600         except:
1601             return 0
1602         return 1
1603
1604     def verifType(self, valeur, type_permis):
1605         if type_permis == 'R':
1606             if type(valeur) in (int, float, int):
1607                 return 1
1608         elif type_permis == 'I':
1609             if type(valeur) in (int, int):
1610                 return 1
1611         elif type_permis == 'C':
1612             if self.is_complexe(valeur):
1613                 return 1
1614         elif type_permis == 'TXM':
1615             if type(valeur) == bytes:
1616                 return 1
1617         elif isinstance(valeur, type_permis):
1618                 return 1
1619         return 0
1620
1621     def verif(self, valeur):
1622         if type(valeur) in (list, tuple):
1623             liste = list(valeur)
1624             for val in liste:
1625                 if self.verif_item(val) != 1:
1626                     return 0
1627             return 1
1628
1629
1630 class VerifExiste(ListVal):
1631
1632     """
1633        fonctionne avec into
1634        Met une liste à jour selon les mot clefs existant
1635        exemple si into = ("A","B","C")
1636        si au niveau N du JDC les objets "A" et "C" existe
1637        alors la liste des into deviendra ( "A","C")
1638
1639        niveauVerif est le niveau du JDC dans lequel va s effectuer la verification
1640        niveauVerif est defini par rapport au Noeud :
1641        exemple niveauVerif = 1 : on verifie les freres
1642                niveauVerif = 2 : on verifie les oncles..
1643     """
1644
1645     def __init__(self, niveauVerif):
1646         ListVal.__init__(self)
1647         self.niveauVerif = niveauVerif
1648         self.MCSimp = None
1649         self.listeDesFreres = ()
1650         self.fonctions = ('verifie_liste', 'set_MCSimp')
1651
1652     def is_list(self):
1653         return 1
1654
1655     def verifie_liste(self, liste):
1656         self.set_MCSimp(self.MCSimp)
1657         for item in liste:
1658             if not(item in self.listeDesFreres):
1659                 return 0
1660         return 1
1661
1662     def verif_item(self, valeur):
1663         self.set_MCSimp(self.MCSimp)
1664         if valeur in self.listeDesFreres:
1665             return 1
1666         return 0
1667
1668     def set_MCSimp(self, MCSimp):
1669         self.MCSimp = MCSimp
1670         k = self.niveauVerif
1671         mc = MCSimp
1672         while (k != 0):
1673             parent = mc.parent
1674             mc = parent
1675             k = k - 1
1676         # on met la liste à jour
1677         parent.forceRecalcul = self.niveauVerif
1678         self.listeDesFreres = parent.liste_mc_presents()
1679
1680     def convert_item(self, valeur):
1681         if valeur in self.listeDesFreres:
1682             return valeur
1683         raise ValError(
1684             tr("%s n'est pas dans %s") % (valeur, self.listeDesFreres))
1685
1686
1687 class RegExpVal(ListVal):
1688
1689     """
1690     Vérifie qu'une chaîne de caractère corresponde à l'expression régulière 'pattern'
1691     """
1692
1693     errormsg = 'La chaîne "%(value)s" ne correspond pas au motif "%(pattern)s"'
1694
1695     def __init__(self, pattern):
1696         self.pattern = pattern
1697         self.compiled_regexp = re.compile(pattern)
1698
1699     def info(self):
1700         return tr('Une chaîne correspondant au motif ') + str(self.pattern) + tr(" est attendue")
1701
1702     def info_erreur_item(self):
1703         return tr('Une chaîne correspondant au motif ') + str(self.pattern) + tr(" est attendue")
1704
1705     def verif_item(self, valeur):
1706         if self.compiled_regexp.match(valeur):
1707             return 1
1708         else:
1709             return (0, self.errormsg % {"value": valeur, "pattern": self.pattern})
1710
1711     def convert_item(self, valeur):
1712         if self.compiled_regexp.match(valeur):
1713             return valeur
1714         else:
1715             raise ValError(self.errormsg %
1716                            {"value": valeur, "pattern": self.pattern})
1717
1718
1719 class FileExtVal(RegExpVal):
1720
1721     """
1722     Vérifie qu'une chaîne de caractère soit un nom de fichier valide avec l'extension 'ext'
1723     """
1724
1725     def __init__(self, ext):
1726         self.ext = ext
1727         self.errormsg = '"%%(value)s" n\'est pas un nom de fichier %(ext)s valide' % {
1728             "ext": ext}
1729         #PNPN Modif pour Adao
1730         RegExpVal.__init__(self, "^\S+\.%s$" % self.ext)
1731
1732
1733     def info(self):
1734         return ('Un nom de fichier se terminant par ".%s" est attendu.' % self.ext)
1735
1736     def info_erreur_item(self):
1737         return ('Un nom de fichier se terminant par ".%s" est attendu.' % self.ext)
1738
1739 class CreeMotClef(object):
1740     def __init__(self,MotClef ):
1741         self.MotClef=MotClef
1742         self.MCSimp=None
1743          
1744     def convert(self, lval):
1745         try : valeur=lval[0]
1746         except  : return lval
1747
1748         parent= self.MCSimp.parent
1749         if hasattr(parent, 'inhibeValidator') and parent.inhibeValidator: return lval
1750
1751
1752         if parent.get_child(self.MotClef) == None : longueur=0
1753         else : longueur=len(parent.get_child(self.MotClef))
1754
1755         pos=parent.get_index_child(self.MCSimp.nom)+1
1756         while longueur < valeur : 
1757            parent.inhibeValidator=1
1758            parent.addentite(self.MotClef,pos)
1759            pos=pos+1
1760            parent.inhibeValidator=0
1761            longueur=len(parent.get_child(self.MotClef))
1762
1763         if longueur > valeur : 
1764            parent.inhibeValide=1
1765            parentObj=parent.get_child(self.MotClef)
1766            obj=parent.get_child(self.MotClef)[-1]
1767            parentObj.suppentite(obj)
1768            longueur=len(parent.get_child(self.MotClef))
1769            parent.inhibeValide=0
1770         return lval
1771
1772     def info(self):
1773         return "Cree le bon nombre de Mot %s"  % self.MotClef
1774
1775     def verif_item(self, valeur):
1776         return 1
1777
1778     def set_MCSimp(self, MCSimp):
1779         #print "dans set_MCSimp"
1780         self.MCSimp=MCSimp