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