Salome HOME
pb de check box
[tools/eficas.git] / Ihm / I_MCSIMP.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2013   EDF R&D
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20 from __future__ import absolute_import
21 import types
22 import traceback
23 from copy import copy
24 from six.moves.reprlib import Repr
25 from Extensions.i18n import tr
26 from Extensions.eficas_exception import EficasException
27 from six.moves import range
28 myrepr = Repr()
29 myrepr.maxstring = 100
30 myrepr.maxother = 100
31
32 from Noyau.N_utils import repr_float
33 import Validation
34 from . import CONNECTOR
35
36 # Attention : les classes ASSD,.... peuvent etre surchargees
37 # dans le package Accas. Il faut donc prendre des precautions si
38 # on utilise les classes du Noyau pour faire des tests (isxxxx, ...)
39 # Si on veut creer des objets comme des CO avec les classes du noyau
40 # ils n'auront pas les conportements des autres packages (pb!!!)
41 # Il vaut mieux les importer d'Accas mais probleme d'import circulaire,
42 # on ne peut pas les importer au debut.
43 # On fait donc un import local quand c'est necessaire (peut occasionner
44 # des pbs de prformance).
45 from Noyau.N_ASSD import ASSD,assd
46 from Noyau.N_GEOM import GEOM,geom
47 from Noyau.N_CO import CO
48 import Accas
49 # fin attention
50
51 from Extensions import parametre
52 from Extensions import param2
53 from . import I_OBJECT
54 from . import CONNECTOR
55 from .I_VALIDATOR import ValError,listProto
56
57 class MCSIMP(I_OBJECT.OBJECT):
58
59
60   def isvalid(self,cr='non'):
61       if self.state == 'unchanged':
62         return self.valid
63       for type_permis in self.definition.type:
64           if hasattr(type_permis, "__class__") and type_permis.__class__.__name__ == 'Matrice':
65              self.monType=type_permis
66              return self.valideMatrice(cr=cr)
67       return Validation.V_MCSIMP.MCSIMP.isvalid(self,cr=cr)
68
69   def GetNomConcept(self):
70       p=self
71       while p.parent :
72          try :
73             nomconcept=p.get_sdname()
74             return nomconcept
75          except:
76             try :
77                nomconcept= p.object.get_sdname()
78                return nomconcept
79             except :
80                pass
81          p=p.parent
82       return ""
83
84   def GetText(self):
85     """
86         Retourne le texte a afficher dans l'arbre representant la valeur de l'objet
87         pointe par self
88     """
89
90     if self.valeur == None : 
91       return None
92     elif type(self.valeur) == float : 
93       # Traitement d'un flottant isole
94       txt = str(self.valeur)
95       clefobj=self.GetNomConcept()
96       if clefobj in self.jdc.appli.appliEficas.dict_reels :
97         if self.valeur in self.jdc.appli.appliEficas.dict_reels[clefobj]:
98            txt=self.jdc.appli.appliEficas.dict_reels[clefobj][self.valeur]
99     elif type(self.valeur) in (list,tuple) :
100       if self.valeur==[] or self.valeur == (): return str(self.valeur)
101       # Traitement des listes
102       txt='('
103       sep=''
104       for val in self.valeur:
105         if type(val) == float : 
106            clefobj=self.GetNomConcept()
107            if clefobj in self.jdc.appli.appliEficas.dict_reels:
108               if val in self.jdc.appli.appliEficas.dict_reels[clefobj]:
109                  txt=txt + sep +self.jdc.appli.appliEficas.dict_reels[clefobj][val]
110               else :
111                  txt=txt + sep + str(val)
112            else :
113               txt=txt + sep + str(val)
114         else: 
115            if isinstance(val,tuple):
116               texteVal='('
117               for i in val :
118                   if isinstance(i, bytes) : texteVal = texteVal +"'"+str(i)+"'," 
119                   else : texteVal = texteVal + str(i)+','
120               texteVal=texteVal[:-1]+')'
121            else : 
122               if isinstance(val,bytes): texteVal="'"+str(val)+"'"
123               else :texteVal=str(val)
124            txt = txt + sep+ texteVal 
125
126 ##        if len(txt) > 200:
127 ##            #ligne trop longue, on tronque
128 ##            txt=txt+" ..."
129 ##            break
130         sep=','
131       # cas des listes de tuples de longueur 1
132       if isinstance(val,tuple) and len(self.valeur) == 1 : txt=txt+','
133       txt=txt+')'
134     else:
135       # Traitement des autres cas
136       txt = str(self.valeur)
137
138     # txt peut etre une longue chaine sur plusieurs lignes.
139     # Il est possible de tronquer cette chaine au premier \n et 
140     # de limiter la longueur de la chaine a 30 caracteres. Cependant
141     # ceci provoque une perte d'information pour l'utilisateur
142     # Pour le moment on retourne la chaine telle que
143     return txt
144
145   def getval(self):
146     """ 
147        Retourne une chaine de caractere representant la valeur de self 
148     """
149     val=self.valeur
150     if type(val) == float : 
151       clefobj=self.GetNomConcept()
152       if clefobj in self.jdc.appli.appliEficas.dict_reels :
153         if val in self.jdc.appli.appliEficas.appliEficas.dict_reels[clefobj] :
154            return self.jdc.appli.appliEficas.dict_reels[clefobj][val]
155     if type(val) != tuple :
156       try:
157         return val.get_name()
158       except:
159         return val
160     else :
161       if val ==() or val == [] : return val
162       s='( '
163       for item in val :
164         try :
165           s=s+item.get_name()+','
166         except:
167           s=s+repr(item)+','
168       s=s+' )'
169       return s
170
171   def wait_bool(self):
172       for typ in self.definition.type:
173           try :
174             if typ == bool: return True
175           except :
176             pass
177       return False
178
179   def wait_co(self):
180     """
181         Methode booleenne qui retourne 1 si l'objet attend un objet ASSD 
182         qui n'existe pas encore (type CO()), 0 sinon
183     """
184     for typ in self.definition.type:
185       if type(typ) == type or isinstance(typ,type):
186         if issubclass(typ,CO) :
187            return 1
188     return 0
189
190   def wait_assd(self):
191     """ 
192         Methode booleenne qui retourne 1 si le MCS attend un objet de type ASSD 
193         ou derive, 0 sinon
194     """
195     for typ in self.definition.type:
196       if type(typ) == type or isinstance(typ,type):
197         if issubclass(typ,ASSD) and not issubclass(typ,GEOM):
198           return 1
199     return 0
200
201   def wait_assd_or_geom(self):
202     """ 
203          Retourne 1 si le mot-cle simple attend un objet de type
204          assd, ASSD, geom ou GEOM
205          Retourne 0 dans le cas contraire
206     """
207     for typ in self.definition.type:
208       if type(typ) == type or isinstance(typ,type):
209         if typ.__name__ in ("GEOM","ASSD","geom","assd") or issubclass(typ,GEOM) :
210           return 1
211     return 0
212
213   def wait_geom(self):
214     """ 
215          Retourne 1 si le mot-cle simple attend un objet de type GEOM
216          Retourne 0 dans le cas contraire
217     """
218     for typ in self.definition.type:
219       if type(typ) == type or isinstance(typ,type):
220         if issubclass(typ,GEOM) : return 1
221     return 0
222
223
224   def wait_TXM(self):
225     """ 
226          Retourne 1 si le mot-cle simple attend un objet de type TXM
227          Retourne 0 dans le cas contraire
228     """
229     for typ in self.definition.type:
230       if typ == 'TXM' :return 1
231     return 0
232
233   def get_liste_valeurs(self):
234     """
235     """
236     if self.valeur == None:
237       return []
238     elif type(self.valeur) == tuple:
239       return list(self.valeur)
240     elif type(self.valeur) == list:
241       return self.valeur
242     else:
243       return [self.valeur]
244
245   def isoblig(self):
246     return self.definition.statut=='o'
247
248   def isImmuable(self):
249     return self.definition.homo=='constant'
250
251   def isInformation(self):
252     return self.definition.homo=='information'
253
254
255
256   def valid_val(self,valeur):
257       """
258         Verifie que la valeur passee en argument (valeur) est valide
259         sans modifier la valeur courante 
260       """
261       lval=listProto.adapt(valeur)
262       if lval is None:
263          valid=0
264          mess=tr("None n'est pas une valeur autorisee")
265       else:
266          try:
267             for val in lval:
268                 self.typeProto.adapt(val)
269                 self.intoProto.adapt(val)
270             self.cardProto.adapt(lval)
271             if self.definition.validators:
272                 self.definition.validators.convert(lval)
273             valid,mess=1,""
274          except ValError as e:
275             mess=str(e)
276             valid=0
277       return valid,mess
278
279   def valid_valeur(self,new_valeur):
280       """
281         Verifie que la valeur passee en argument (new_valeur) est valide
282         sans modifier la valeur courante (evite d'utiliser set_valeur et est plus performant)
283       """
284       validite,mess=self.valid_val(new_valeur)
285       return validite
286
287   def valid_valeur_partielle(self,new_valeur):
288       """
289         Verifie que la valeur passee en argument (new_valeur) est une liste partiellement valide
290         sans modifier la valeur courante du mot cle
291       """
292       validite=1
293       try:
294           for val in new_valeur:
295               self.typeProto.adapt(val)
296               self.intoProto.adapt(val)
297               #on ne verifie pas la cardinalite
298               if self.definition.validators:
299                   validite=self.definition.validators.valide_liste_partielle(new_valeur)
300       except ValError as e:
301           validite=0
302
303       return validite
304
305   def update_condition_bloc(self):
306       """ Met a jour les blocs conditionnels dependant du mot cle simple self
307       """
308       if self.definition.position == 'global' : 
309          self.etape.deep_update_condition_bloc()
310       elif self.definition.position == 'global_jdc' :
311          self.jdc.deep_update_condition_bloc()
312       else:
313          self.parent.update_condition_bloc()
314
315   def set_valeur(self,new_valeur,evaluation='oui'):
316         #print "set_valeur",new_valeur
317         self.init_modif()
318         self.valeur = new_valeur
319         self.val = new_valeur
320         self.update_condition_bloc()
321         self.etape.modified()
322         self.fin_modif()
323         return 1
324
325   def eval_valeur(self,new_valeur):
326     """
327         Essaie d'evaluer new_valeur comme une SD, une declaration Python 
328         ou un EVAL: Retourne la valeur evaluee (ou None) et le test de reussite (1 ou 0)
329     """
330     sd = self.jdc.get_sd_avant_etape(new_valeur,self.etape)
331     #sd = self.jdc.get_contexte_avant(self.etape).get(new_valeur,None)
332     #print sd
333     if sd is not None:
334       return sd,1
335     lsd = self.jdc.cherche_list_avant(self.etape,new_valeur) 
336     if lsd :
337       return lsd,1
338     else:
339       d={}
340       # On veut EVAL avec tous ses comportements. On utilise Accas. Perfs ??
341       d['EVAL']=Accas.EVAL
342       try :
343         objet = eval(new_valeur,d)
344         return objet,1
345       except Exception:
346         itparam=self.cherche_item_parametre(new_valeur)
347         if itparam:
348              return itparam,1
349         try :
350              object=eval(new_valeur.valeur,d)
351         except :
352              pass
353         if CONTEXT.debug : traceback.print_exc()
354         return None,0
355
356   def eval_val(self,new_valeur):
357     """
358        Tente d'evaluer new_valeur comme un objet du jdc (par appel a eval_val_item)
359        ou comme une liste de ces memes objets
360        Si new_valeur contient au moins un separateur (,), tente l'evaluation sur
361        la chaine splittee
362     """
363     if new_valeur in ('True','False') and 'TXM' in self.definition.type  :
364        valeur=self.eval_val_item(str(new_valeur))
365        return new_valeur
366     if type(new_valeur) in (list,tuple):
367        valeurretour=[]
368        for item in new_valeur :
369           valeurretour.append(self.eval_val_item(item))
370        return valeurretour
371     else:
372        valeur=self.eval_val_item(new_valeur)
373        return valeur
374
375   def eval_val_item(self,new_valeur):
376     """
377        Tente d'evaluer new_valeur comme un concept, un parametre, un objet Python
378        Si c'est impossible retourne new_valeur inchange
379        argument new_valeur : string (nom de concept, de parametre, expression ou simple chaine)
380     """
381     if self.etape and self.etape.parent:
382        valeur=self.etape.parent.eval_in_context(new_valeur,self.etape)
383        return valeur
384     else:
385        try :
386            valeur = eval(val)
387            return valeur
388        except:
389            #traceback.print_exc()
390            return new_valeur
391            pass
392
393   def cherche_item_parametre (self,new_valeur):
394         try:
395           nomparam=new_valeur[0:new_valeur.find("[")]
396           indice=new_valeur[new_valeur.find(u"[")+1:new_valeur.find(u"]")]
397           for p in self.jdc.params:
398              if p.nom == nomparam :
399                 if int(indice) < len(p.get_valeurs()):
400                    itparam=parametre.ITEM_PARAMETRE(p,int(indice))
401                    return itparam
402           return None
403         except:
404           return None
405
406   def update_concept(self,sd):
407     if type(self.valeur) in (list,tuple) :
408        if sd in self.valeur:
409          self.init_modif()
410          self.fin_modif()
411     else:
412        if sd == self.valeur:
413          self.init_modif()
414          self.fin_modif()
415
416   def delete_concept(self,sd):
417     """ 
418         Inputs :
419            - sd=concept detruit
420         Fonction :
421         Met a jour la valeur du mot cle simple suite a la disparition 
422         du concept sd
423         Attention aux matrices
424     """
425     if type(self.valeur) == tuple :
426       if sd in self.valeur:
427         self.init_modif()
428         self.valeur=list(self.valeur)
429         self.valeur.remove(sd)
430         self.fin_modif()
431     elif type(self.valeur) == list:
432       if sd in self.valeur:
433         self.init_modif()
434         self.valeur.remove(sd)
435         self.fin_modif()
436     else:
437       if self.valeur == sd:
438         self.init_modif()
439         self.valeur=None
440         self.val=None
441         self.fin_modif()
442     # Glut Horrible pour les matrices ???
443     if sd.__class__.__name__== "variable":
444        for type_permis in self.definition.type:
445             if type(type_permis) == types.InstanceType:
446                if type_permis.__class__.__name__ == 'Matrice' :
447                    self.state="changed"
448                    self.isvalid()
449                   
450
451   def replace_concept(self,old_sd,sd):
452     """
453         Inputs :
454            - old_sd=concept remplace
455            - sd=nouveau concept
456         Fonction :
457         Met a jour la valeur du mot cle simple suite au remplacement 
458         du concept old_sd
459     """
460     #print "replace_concept",old_sd,sd
461     if type(self.valeur) == tuple :
462       if old_sd in self.valeur:
463         self.init_modif()
464         self.valeur=list(self.valeur)
465         i=self.valeur.index(old_sd)
466         self.valeur[i]=sd
467         self.fin_modif()
468     elif type(self.valeur) == list:
469       if old_sd in self.valeur:
470         self.init_modif()
471         i=self.valeur.index(old_sd)
472         self.valeur[i]=sd
473         self.fin_modif()
474     else:
475       if self.valeur == old_sd:
476         self.init_modif()
477         self.valeur=sd
478         self.val=sd
479         self.fin_modif()
480
481   def set_valeur_co(self,nom_co):
482       """
483           Affecte a self l'objet de type CO et de nom nom_co
484       """
485       #print "set_valeur_co",nom_co
486       step=self.etape.parent
487       if nom_co == None or nom_co == '':
488          new_objet=None
489       else:
490          # Avant de creer un concept il faut s'assurer du contexte : step 
491          # courant
492          sd= step.get_sd_autour_etape(nom_co,self.etape,avec='oui')
493          if sd:
494             # Si un concept du meme nom existe deja dans la portee de l'etape
495             # on ne cree pas le concept
496             return 0,tr("un concept de meme nom existe deja")
497          # Il n'existe pas de concept de meme nom. On peut donc le creer 
498          # Il faut neanmoins que la methode NommerSdProd de step gere les 
499          # contextes en mode editeur
500          # Normalement la methode  du Noyau doit etre surchargee
501          # On declare l'etape du mot cle comme etape courante pour NommerSdprod
502          cs= CONTEXT.get_current_step()
503          CONTEXT.unset_current_step()
504          CONTEXT.set_current_step(step)
505          step.set_etape_context(self.etape)
506          new_objet = Accas.CO(nom_co)
507          CONTEXT.unset_current_step()
508          CONTEXT.set_current_step(cs)
509       self.init_modif()
510       self.valeur = new_objet
511       self.val = new_objet
512       # On force l'enregistrement de new_objet en tant que concept produit 
513       # de la macro en appelant get_type_produit avec force=1
514       self.etape.get_type_produit(force=1)
515       self.fin_modif()
516       step.reset_context()
517       #print "set_valeur_co",new_objet
518       return 1,tr("Concept cree")
519         
520   def verif_existence_sd(self):
521      """
522         Verifie que les structures de donnees utilisees dans self existent bien dans le contexte
523         avant etape, sinon enleve la referea ces concepts
524      """
525      #print "verif_existence_sd"
526      # Attention : possible probleme avec include
527      # A priori il n'y a pas de raison de retirer les concepts non existants
528      # avant etape. En fait il s'agit uniquement eventuellement de ceux crees par une macro
529      l_sd_avant_etape = list(self.jdc.get_contexte_avant(self.etape).values())  
530      if type(self.valeur) in (tuple,list) :
531        l=[]
532        for sd in self.valeur:
533          if isinstance(sd,ASSD) :
534             if sd in l_sd_avant_etape or self.etape.get_sdprods(sd.nom) is sd:
535                l.append(sd)
536          else:
537             l.append(sd)
538        if len(l) < len(self.valeur):
539           self.init_modif()
540           self.valeur=tuple(l)
541           self.fin_modif()
542      else:
543        if isinstance(self.valeur,ASSD) :
544           if self.valeur not in l_sd_avant_etape and self.etape.get_sdprods(self.valeur.nom) is None:
545              self.init_modif()
546              self.valeur = None
547              self.fin_modif()
548  
549   def get_min_max(self):
550      """
551      Retourne les valeurs min et max admissibles pour la valeur de self
552      """
553      return self.definition.min,self.definition.max
554
555
556   def get_type(self):
557      """
558      Retourne le type attendu par le mot-cle simple
559      """
560      return self.definition.type
561
562   def delete_mc_global(self):
563       """ Retire self des declarations globales
564       """
565       if self.definition.position == 'global' : 
566          etape = self.get_etape()
567          if etape :
568             del etape.mc_globaux[self.nom]
569       elif self.definition.position == 'global_jdc' :
570          del self.jdc.mc_globaux[self.nom]
571
572   def update_mc_global(self):
573      """
574         Met a jour les mots cles globaux enregistres dans l'etape parente
575         et dans le jdc parent.
576         Un mot cle simple peut etre global. 
577      """
578      if self.definition.position == 'global' :
579         etape = self.get_etape()
580         if etape :
581            etape.mc_globaux[self.nom]=self
582      elif self.definition.position == 'global_jdc' :
583         if self.jdc:
584            self.jdc.mc_globaux[self.nom]=self
585
586   def nbrColonnes(self):
587      genea = self.get_genealogie()
588      if "VALE_C" in genea and "DEFI_FONCTION" in genea : return 3
589      if "VALE" in genea and "DEFI_FONCTION" in genea : return 2
590      return 0
591
592   def valide_item(self,item):
593       """Valide un item isole. Cet item est candidata l'ajout a la liste existante"""
594       valid=1
595       try:
596           #on verifie le type
597           self.typeProto.adapt(item)
598           #on verifie les choix possibles
599           self.intoProto.adapt(item)
600           #on ne verifie pas la cardinalite
601           if self.definition.validators:
602               valid=self.definition.validators.verif_item(item)
603       except ValError as e:
604           #traceback.print_exc()
605           valid=0
606       return valid
607
608   def verif_type(self,item):
609       """Verifie le type d'un item de liste"""
610       try:
611           #on verifie le type
612           self.typeProto.adapt(item)
613           #on verifie les choix possibles
614           self.intoProto.adapt(item)
615           #on ne verifie pas la cardinalite mais on verifie les validateurs
616           if self.definition.validators:
617               valid=self.definition.validators.verif_item(item)
618           comment=""
619           valid=1
620       except ValError as e:
621           #traceback.print_exc()
622           comment=tr(e.__str__())
623           valid=0
624       return valid,comment
625
626   def valideMatrice(self,cr):
627        #Attention, la matrice contient comme dernier tuple l ordre des variables
628        if self.valideEnteteMatrice()==False :
629            self.set_valid(0)
630            if cr == "oui" : self.cr.fatal(tr("La matrice n'a pas le bon entete"))
631            return 0
632        if self.monType.methodeCalculTaille != None :
633            MCSIMP.__dict__[self.monType.methodeCalculTaille](*(self,))
634        try :
635        #if 1 :
636            ok=0
637            if len(self.valeur) == self.monType.nbLigs +1:
638               ok=1
639               for i in range(len(self.valeur) -1):
640                   if len(self.valeur[i])!= self.monType.nbCols:
641                      ok=0
642            if ok: 
643               self.set_valid(1)
644               return 1 
645        except :
646        #else :
647             pass
648        if cr == 'oui' :
649              self.cr.fatal(tr("La matrice n'est pas une matrice %(n_lign)d sur %(n_col)d", \
650              {'n_lign': self.monType.nbLigs, 'n_col': self.monType.nbCols}))
651        self.set_valid(0)
652        return 0
653
654
655   def NbDeVariables(self):
656        listeVariables=self.jdc.get_variables(self.etape)
657        self.monType.nbLigs=len(listeVariables)
658        self.monType.nbCols=len(listeVariables)
659       
660   def valideEnteteMatrice(self):
661       if self.jdc.get_distributions(self.etape) == () or self.valeur == None : return 0
662       if self.jdc.get_distributions(self.etape) != self.valeur[0] : return 0
663       return 1
664      
665   def changeEnteteMatrice(self):
666       a=[self.jdc.get_distributions(self.etape),]
667       for t in self.valeur[1:]:
668          a.append(t)
669       self.valeur=a
670
671
672   def NbDeDistributions(self):
673        listeVariables=self.jdc.get_distributions(self.etape)
674        self.monType.nbLigs=len(listeVariables)
675        self.monType.nbCols=len(listeVariables)
676       
677 #--------------------------------------------------------------------------------
678  
679 #ATTENTION SURCHARGE : toutes les methodes ci apres sont des surcharges du Noyau et de Validation
680 # Elles doivent etre reintegrees des que possible
681
682
683   def verif_typeihm(self,val,cr='non'):
684       try :
685          val.eval()
686          return 1
687       except :
688          traceback.print_exc()
689          pass
690       return self.verif_type(val,cr)
691
692   def verif_typeliste(self,val,cr='non') :
693       verif=0
694       for v in val :
695         verif=verif+self.verif_typeihm(v,cr)
696       return verif
697
698   def init_modif_up(self):
699     Validation.V_MCSIMP.MCSIMP.init_modif_up(self)
700     CONNECTOR.Emit(self,"valid")