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