Salome HOME
bug
[tools/eficas.git] / Ihm / I_MCSIMP.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2017   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       validite=Validation.V_MCSIMP.MCSIMP.isValid(self,cr=cr)
68       if self.definition.siValide != None and validite:
69             self.definition.siValide(self)
70       return validite 
71
72   def getNomConcept(self):
73       p=self
74       while p.parent :
75          try :
76             nomconcept=p.getSdname()
77             return nomconcept
78          except:
79             try :
80                nomconcept= p.object.getSdname()
81                return nomconcept
82             except :
83                pass
84          p=p.parent
85       return ""
86
87   def getText(self):
88     """
89         Retourne le texte a afficher dans l'arbre representant la valeur de l'objet
90         pointe par self
91     """
92
93     if self.valeur == None : 
94       return None
95     elif type(self.valeur) == float : 
96       # traitement d'un flottant isole
97       txt = str(self.valeur)
98       clefobj=self.getNomConcept()
99       if clefobj in self.jdc.appli.appliEficas.dict_reels :
100         if self.valeur in self.jdc.appli.appliEficas.dict_reels[clefobj]:
101            txt=self.jdc.appli.appliEficas.dict_reels[clefobj][self.valeur]
102     elif type(self.valeur) in (list,tuple) :
103       if self.valeur==[] or self.valeur == (): return str(self.valeur)
104       # traitement des listes
105       txt='('
106       sep=''
107       for val in self.valeur:
108         if type(val) == float : 
109            clefobj=self.getNomConcept()
110            if clefobj in self.jdc.appli.appliEficas.dict_reels:
111               if val in self.jdc.appli.appliEficas.dict_reels[clefobj]:
112                  txt=txt + sep +self.jdc.appli.appliEficas.dict_reels[clefobj][val]
113               else :
114                  txt=txt + sep + str(val)
115            else :
116               txt=txt + sep + str(val)
117         else: 
118            if isinstance(val,tuple):
119               texteVal='('
120               for i in val :
121                   if isinstance(i, bytes) or isinstance(i,str) : texteVal = texteVal +"'"+str(i)+"'," 
122                   else : texteVal = texteVal + str(i)+','
123               texteVal=texteVal[:-1]+')'
124            else : 
125               if isinstance(val,bytes) or isinstance(val, str): texteVal="'"+str(val)+"'"
126               else :texteVal=str(val)
127            txt = txt + sep+ texteVal 
128
129 ##        if len(txt) > 200:
130 ##            #ligne trop longue, on tronque
131 ##            txt=txt+" ..."
132 ##            break
133         sep=','
134       # cas des listes de tuples de longueur 1
135       if isinstance(val,tuple) and len(self.valeur) == 1 : txt=txt+','
136       txt=txt+')'
137     else:
138       # traitement des autres cas
139       txt = str(self.valeur)
140
141     # txt peut etre une longue chaine sur plusieurs lignes.
142     # Il est possible de tronquer cette chaine au premier \n et 
143     # de limiter la longueur de la chaine a 30 caracteres. Cependant
144     # ceci provoque une perte d'information pour l'utilisateur
145     # Pour le moment on retourne la chaine telle que
146     return txt
147
148   def getVal(self):
149     """ 
150        Retourne une chaine de caractere representant la valeur de self 
151     """
152     val=self.valeur
153     if type(val) == float : 
154       clefobj=self.getNomConcept()
155       if clefobj in self.jdc.appli.appliEficas.dict_reels :
156         if val in self.jdc.appli.appliEficas.appliEficas.dict_reels[clefobj] :
157            return self.jdc.appli.appliEficas.dict_reels[clefobj][val]
158     if type(val) != tuple :
159       try:
160         return val.getName()
161       except:
162         return val
163     else :
164       if val ==() or val == [] : return val
165       s='( '
166       for item in val :
167         try :
168           s=s+item.getName()+','
169         except:
170           s=s+repr(item)+','
171       s=s+' )'
172       return s
173
174   def waitBool(self):
175       for typ in self.definition.type:
176           try :
177             if typ == bool: return True
178           except :
179             pass
180       return False
181
182   def waitCo(self):
183     """
184         Methode booleenne qui retourne 1 si l'objet attend un objet ASSD 
185         qui n'existe pas encore (type CO()), 0 sinon
186     """
187     for typ in self.definition.type:
188       if type(typ) == type or isinstance(typ,type):
189         if issubclass(typ,CO) :
190            return 1
191     return 0
192
193   def waitAssd(self):
194     """ 
195         Methode booleenne qui retourne 1 si le MCS attend un objet de type ASSD 
196         ou derive, 0 sinon
197     """
198     for typ in self.definition.type:
199       if type(typ) == type or isinstance(typ,type):
200         if issubclass(typ,ASSD) and not issubclass(typ,GEOM):
201           return 1
202     return 0
203
204   def waitAssdOrGeom(self):
205     """ 
206          Retourne 1 si le mot-cle simple attend un objet de type
207          assd, ASSD, geom ou GEOM
208          Retourne 0 dans le cas contraire
209     """
210     for typ in self.definition.type:
211       if type(typ) == type or isinstance(typ,type):
212         if typ.__name__ in ("GEOM","ASSD","geom","assd") or issubclass(typ,GEOM) :
213           return 1
214     return 0
215
216   def waitGeom(self):
217     """ 
218          Retourne 1 si le mot-cle simple attend un objet de type GEOM
219          Retourne 0 dans le cas contraire
220     """
221     for typ in self.definition.type:
222       if type(typ) == type or isinstance(typ,type):
223         if issubclass(typ,GEOM) : return 1
224     return 0
225
226
227   def waitTxm(self):
228     """ 
229          Retourne 1 si le mot-cle simple attend un objet de type TXM
230          Retourne 0 dans le cas contraire
231     """
232     for typ in self.definition.type:
233       if typ == 'TXM' :return 1
234     return 0
235
236   def waitTuple(self):
237     for ss_type in self.definition.type:
238         if repr(ss_type).find('Tuple') != -1 :
239           return 1
240     return 0
241
242
243   def getListeValeurs(self):
244     """
245     """
246     if self.valeur == None:
247       return []
248     elif type(self.valeur) == tuple:
249       return list(self.valeur)
250     elif type(self.valeur) == list:
251       return self.valeur
252     else:
253       return [self.valeur]
254
255   def isOblig(self):
256     return self.definition.statut=='o'
257
258   def isImmuable(self):
259     return self.definition.homo=='constant'
260
261   def isInformation(self):
262     return self.definition.homo=='information'
263
264
265
266   def validVal(self,valeur):
267       """
268         Verifie que la valeur passee en argument (valeur) est valide
269         sans modifier la valeur courante 
270       """
271       lval=listProto.adapt(valeur)
272       if lval is None:
273          valid=0
274          mess=tr("None n'est pas une valeur autorisee")
275       else:
276          try:
277             for val in lval:
278                 self.typeProto.adapt(val)
279                 self.intoProto.adapt(val)
280             self.cardProto.adapt(lval)
281             if self.definition.validators:
282                 self.definition.validators.convert(lval)
283             valid,mess=1,""
284          except ValError as e:
285             mess=str(e)
286             valid=0
287       return valid,mess
288
289   def validValeur(self,new_valeur):
290       """
291         Verifie que la valeur passee en argument (new_valeur) est valide
292         sans modifier la valeur courante (evite d'utiliser setValeur et est plus performant)
293       """
294       validite,mess=self.validVal(new_valeur)
295       return validite
296
297   def validValeurPartielle(self,new_valeur):
298       """
299         Verifie que la valeur passee en argument (new_valeur) est une liste partiellement valide
300         sans modifier la valeur courante du mot cle
301       """
302       validite=1
303       try:
304           for val in new_valeur:
305               self.typeProto.adapt(val)
306               self.intoProto.adapt(val)
307               #on ne verifie pas la cardinalite
308               if self.definition.validators:
309                   validite=self.definition.validators.valideListePartielle(new_valeur)
310       except ValError as e:
311           validite=0
312
313       return validite
314
315   def updateConditionBloc(self):
316       """ Met a jour les blocs conditionnels dependant du mot cle simple self
317       """
318       if self.definition.position == 'global' : 
319          self.etape.deepUpdateConditionBloc()
320       elif self.definition.position == 'global_jdc' :
321          self.jdc.deepUpdateConditionBloc()
322       else:
323          self.parent.updateConditionBloc()
324
325   def setValeur(self,new_valeur,evaluation='oui'):
326         #print ("setValeur Ihm/IMCSIMP ",new_valeur)
327         self.initModif()
328         self.valeur = new_valeur
329         self.val = new_valeur
330         #self.setValeurObjPyxb(new_valeur)
331         self.updateConditionBloc()
332         self.etape.modified()
333         self.finModif()
334         return 1
335
336   def evalValeur(self,new_valeur):
337     """
338         Essaie d'evaluer new_valeur comme une SD, une declaration Python 
339         ou un EVAL: Retourne la valeur evaluee (ou None) et le test de reussite (1 ou 0)
340     """
341     sd = self.jdc.getSdAvantEtape(new_valeur,self.etape)
342     #sd = self.jdc.getContexteAvant(self.etape).get(new_valeur,None)
343     #print sd
344     if sd is not None:
345       return sd,1
346     lsd = self.jdc.chercheListAvant(self.etape,new_valeur) 
347     if lsd :
348       return lsd,1
349     else:
350       d={}
351       # On veut EVAL avec tous ses comportements. On utilise Accas. Perfs ??
352       d['EVAL']=Accas.EVAL
353       try :
354         objet = eval(new_valeur,d)
355         return objet,1
356       except Exception:
357         itparam=self.chercheItemParametre(new_valeur)
358         if itparam:
359              return itparam,1
360         try :
361              object=eval(new_valeur.valeur,d)
362         except :
363              pass
364         if CONTEXT.debug : traceback.print_exc()
365         return None,0
366
367   def evalVal(self,new_valeur):
368     """
369        Tente d'evaluer new_valeur comme un objet du jdc (par appel a evalValItem)
370        ou comme une liste de ces memes objets
371        Si new_valeur contient au moins un separateur (,), tente l'evaluation sur
372        la chaine splittee
373     """
374     if new_valeur in ('True','False') and 'TXM' in self.definition.type  :
375        valeur=self.evalValItem(str(new_valeur))
376        return new_valeur
377     if type(new_valeur) in (list,tuple):
378        valeurretour=[]
379        for item in new_valeur :
380           valeurretour.append(self.evalValItem(item))
381        return valeurretour
382     else:
383        valeur=self.evalValItem(new_valeur)
384        return valeur
385
386   def evalValItem(self,new_valeur):
387     """
388        Tente d'evaluer new_valeur comme un concept, un parametre, un objet Python
389        Si c'est impossible retourne new_valeur inchange
390        argument new_valeur : string (nom de concept, de parametre, expression ou simple chaine)
391     """
392     if self.etape and self.etape.parent:
393        valeur=self.etape.parent.evalInContext(new_valeur,self.etape)
394        return valeur
395     else:
396        try :
397            valeur = eval(val)
398            return valeur
399        except:
400            #traceback.print_exc()
401            return new_valeur
402            pass
403
404   def chercheItemParametre (self,new_valeur):
405         try:
406           nomparam=new_valeur[0:new_valeur.find("[")]
407           indice=new_valeur[new_valeur.find(u"[")+1:new_valeur.find(u"]")]
408           for p in self.jdc.params:
409              if p.nom == nomparam :
410                 if int(indice) < len(p.getValeurs()):
411                    itparam=parametre.ITEM_PARAMETRE(p,int(indice))
412                    return itparam
413           return None
414         except:
415           return None
416
417   def updateConcept(self,sd):
418     if type(self.valeur) in (list,tuple) :
419        if sd in self.valeur:
420          self.initModif()
421          self.finModif()
422     else:
423        if sd == self.valeur:
424          self.initModif()
425          self.finModif()
426
427   def deleteConcept(self,sd):
428     """ 
429         Inputs :
430            - sd=concept detruit
431         Fonction :
432         Met a jour la valeur du mot cle simple suite a la disparition 
433         du concept sd
434         Attention aux matrices
435     """
436     if type(self.valeur) == tuple :
437       if sd in self.valeur:
438         self.initModif()
439         self.valeur=list(self.valeur)
440         self.valeur.remove(sd)
441         self.finModif()
442     elif type(self.valeur) == list:
443       if sd in self.valeur:
444         self.initModif()
445         self.valeur.remove(sd)
446         self.finModif()
447     else:
448       if self.valeur == sd:
449         self.initModif()
450         self.valeur=None
451         self.val=None
452         self.finModif()
453     # Glut Horrible pour les matrices ???
454     if sd.__class__.__name__== "variable":
455        for type_permis in self.definition.type:
456             #if type(type_permis) == types.InstanceType:
457             # a voir en python 3
458                if type_permis.__class__.__name__ == 'Matrice' :
459                    self.state="changed"
460                    self.isValid()
461                   
462
463   def replaceConcept(self,old_sd,sd):
464     """
465         Inputs :
466            - old_sd=concept remplace
467            - sd=nouveau concept
468         Fonction :
469         Met a jour la valeur du mot cle simple suite au remplacement 
470         du concept old_sd
471     """
472     #print "replaceConcept",old_sd,sd
473     if type(self.valeur) == tuple :
474       if old_sd in self.valeur:
475         self.initModif()
476         self.valeur=list(self.valeur)
477         i=self.valeur.index(old_sd)
478         self.valeur[i]=sd
479         self.finModif()
480     elif type(self.valeur) == list:
481       if old_sd in self.valeur:
482         self.initModif()
483         i=self.valeur.index(old_sd)
484         self.valeur[i]=sd
485         self.finModif()
486     else:
487       if self.valeur == old_sd:
488         self.initModif()
489         self.valeur=sd
490         self.val=sd
491         self.finModif()
492
493   def setValeurCo(self,nom_co):
494       """
495           Affecte a self l'objet de type CO et de nom nom_co
496       """
497       #print "setValeurCo",nom_co
498       step=self.etape.parent
499       if nom_co == None or nom_co == '':
500          new_objet=None
501       else:
502          # Avant de creer un concept il faut s'assurer du contexte : step 
503          # courant
504          sd= step.getSdAutourEtape(nom_co,self.etape,avec='oui')
505          if sd:
506             # Si un concept du meme nom existe deja dans la portee de l'etape
507             # on ne cree pas le concept
508             return 0,tr("un concept de meme nom existe deja")
509          # Il n'existe pas de concept de meme nom. On peut donc le creer 
510          # Il faut neanmoins que la methode NommerSdProd de step gere les 
511          # contextes en mode editeur
512          # Normalement la methode  du Noyau doit etre surchargee
513          # On declare l'etape du mot cle comme etape courante pour NommerSdprod
514          cs= CONTEXT.getCurrentStep()
515          CONTEXT.unsetCurrentStep()
516          CONTEXT.setCurrentStep(step)
517          step.setEtapeContext(self.etape)
518          new_objet = Accas.CO(nom_co)
519          CONTEXT.unsetCurrentStep()
520          CONTEXT.setCurrentStep(cs)
521       self.initModif()
522       self.valeur = new_objet
523       self.val = new_objet
524       # On force l'enregistrement de new_objet en tant que concept produit 
525       # de la macro en appelant getType_produit avec force=1
526       self.etape.getType_produit(force=1)
527       self.finModif()
528       step.resetContext()
529       #print "setValeurCo",new_objet
530       return 1,tr("Concept cree")
531         
532   def verifExistenceSd(self):
533      """
534         Verifie que les structures de donnees utilisees dans self existent bien dans le contexte
535         avant etape, sinon enleve la referea ces concepts
536      """
537      #print "verifExistenceSd"
538      # Attention : possible probleme avec include
539      # A priori il n'y a pas de raison de retirer les concepts non existants
540      # avant etape. En fait il s'agit uniquement eventuellement de ceux crees par une macro
541      l_sd_avant_etape = list(self.jdc.getContexteAvant(self.etape).values())  
542      if type(self.valeur) in (tuple,list) :
543        l=[]
544        for sd in self.valeur:
545          if isinstance(sd,ASSD) :
546             if sd in l_sd_avant_etape or self.etape.getSdprods(sd.nom) is sd:
547                l.append(sd)
548          else:
549             l.append(sd)
550        if len(l) < len(self.valeur):
551           self.initModif()
552           self.valeur=tuple(l)
553           self.finModif()
554      else:
555        if isinstance(self.valeur,ASSD) :
556           if self.valeur not in l_sd_avant_etape and self.etape.getSdprods(self.valeur.nom) is None:
557              self.initModif()
558              self.valeur = None
559              self.finModif()
560  
561   def getMinMax(self):
562      """
563      Retourne les valeurs min et max admissibles pour la valeur de self
564      """
565      return self.definition.min,self.definition.max
566
567
568   def getType(self):
569      """
570      Retourne le type attendu par le mot-cle simple
571      """
572      return self.definition.type
573
574   def deleteMcGlobal(self):
575       """ Retire self des declarations globales
576       """
577       if self.definition.position == 'global' : 
578          etape = self.getEtape()
579          if etape :
580             del etape.mc_globaux[self.nom]
581       elif self.definition.position == 'global_jdc' :
582          del self.jdc.mc_globaux[self.nom]
583
584   def updateMcGlobal(self):
585      """
586         Met a jour les mots cles globaux enregistres dans l'etape parente
587         et dans le jdc parent.
588         Un mot cle simple peut etre global. 
589      """
590      if self.definition.position == 'global' :
591         etape = self.getEtape()
592         if etape :
593            etape.mc_globaux[self.nom]=self
594      elif self.definition.position == 'global_jdc' :
595         if self.jdc:
596            self.jdc.mc_globaux[self.nom]=self
597
598   def nbrColonnes(self):
599      genea = self.getGenealogie()
600      if "VALE_C" in genea and "DEFI_FONCTION" in genea : return 3
601      if "VALE" in genea and "DEFI_FONCTION" in genea : return 2
602      return 0
603
604   def valideItem(self,item):
605       """Valide un item isole. Cet item est candidata l'ajout a la liste existante"""
606       valid=1
607       try:
608           #on verifie le type
609           self.typeProto.adapt(item)
610           #on verifie les choix possibles
611           self.intoProto.adapt(item)
612           #on ne verifie pas la cardinalite
613           if self.definition.validators:
614               valid=self.definition.validators.verifItem(item)
615       except ValError as e:
616           #traceback.print_exc()
617           valid=0
618       return valid
619
620   def verifType(self,item):
621       """Verifie le type d'un item de liste"""
622       try:
623           #on verifie le type
624           self.typeProto.adapt(item)
625           #on verifie les choix possibles
626           self.intoProto.adapt(item)
627           #on ne verifie pas la cardinalite mais on verifie les validateurs
628           if self.definition.validators:
629               valid=self.definition.validators.verifItem(item)
630           comment=""
631           valid=1
632       except ValError as e:
633           #traceback.print_exc()
634           comment=tr(e.__str__())
635           valid=0
636       return valid,comment
637
638   def valideMatrice(self,cr):
639        #Attention, la matrice contient comme dernier tuple l ordre des variables
640        if self.valideEnteteMatrice()==False :
641            self.setValid(0)
642            if cr == "oui" : self.cr.fatal(tr("La matrice n'a pas le bon entete"))
643            return 0
644        if self.monType.methodeCalculTaille != None :
645            MCSIMP.__dict__[self.monType.methodeCalculTaille](*(self,))
646        try :
647        #if 1 :
648            ok=0
649            if len(self.valeur) == self.monType.nbLigs +1:
650               ok=1
651               for i in range(len(self.valeur) -1):
652                   if len(self.valeur[i])!= self.monType.nbCols:
653                      ok=0
654            if ok: 
655               self.setValid(1)
656               return 1 
657        except :
658        #else :
659             pass
660        if cr == 'oui' :
661              self.cr.fatal(tr("La matrice n'est pas une matrice %(n_lign)d sur %(n_col)d", \
662              {'n_lign': self.monType.nbLigs, 'n_col': self.monType.nbCols}))
663        self.setValid(0)
664        return 0
665
666
667   def nbDeVariables(self):
668        listeVariables=self.jdc.getVariables(self.etape)
669        self.monType.nbLigs=len(listeVariables)
670        self.monType.nbCols=len(listeVariables)
671       
672   def valideEnteteMatrice(self):
673       if self.jdc.getDistributions(self.etape) == () or self.valeur == None : return 0
674       if self.jdc.getDistributions(self.etape) != self.valeur[0] : return 0
675       return 1
676      
677   def changeEnteteMatrice(self):
678       a=[self.jdc.getDistributions(self.etape),]
679       for t in self.valeur[1:]:
680          a.append(t)
681       self.valeur=a
682
683
684   def nNbDeDistributions(self):
685        listeVariables=self.jdc.getDistributions(self.etape)
686        self.monType.nbLigs=len(listeVariables)
687        self.monType.nbCols=len(listeVariables)
688       
689 #--------------------------------------------------------------------------------
690  
691 #ATTENTION SURCHARGE : toutes les methodes ci apres sont des surcharges du Noyau et de Validation
692 # Elles doivent etre reintegrees des que possible
693
694
695   def verifTypeIhm(self,val,cr='non'):
696       try :
697          val.eval()
698          return 1
699       except :
700          traceback.print_exc()
701          pass
702       return self.verifType(val,cr)
703
704   def verifTypeliste(self,val,cr='non') :
705       verif=0
706       for v in val :
707         verif=verif+self.verifTypeIhm(v,cr)
708       return verif
709
710   def initModifUp(self):
711     Validation.V_MCSIMP.MCSIMP.initModifUp(self)
712     CONNECTOR.Emit(self,"valid")