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