1 #@ MODIF treewidget Editeur DATE 02/07/2001 AUTEUR D6BHHJP J.P.LEFEBVRE
2 # CONFIGURATION MANAGEMENT OF EDF VERSION
3 # ======================================================================
4 # COPYRIGHT (C) 1991 - 2001 EDF R&D WWW.CODE-ASTER.ORG
5 # SEE THE FILE "LICENSE.TERMS" FOR INFORMATION ON USAGE AND
6 # REDISTRIBUTION OF THIS FILE.
7 # ======================================================================
8 import os,sys,string,re,types
16 __version__="$Name: $"
17 __Id__="$Id: treewidget.py,v 1.2 2002/03/27 16:20:02 eficas Exp $"
20 Fonte_Standard = fontes.standard
23 def __init__(self,appli,jdc_item,scrolledcanvas,command = None):
25 self.scrolledcanvas = scrolledcanvas
26 self.canvas = self.scrolledcanvas.component('canvas')
27 self.canvas.bind("<Key-Prior>", self.page_up)
28 self.canvas.bind("<Key-Next>", self.page_down)
29 self.canvas.bind("<Key-Up>", self.unit_up)
30 self.canvas.bind("<Key-Down>", self.unit_down)
32 self.command = command
36 self.node_selected = None
39 def page_up(self,event):
40 event.widget.yview_scroll(-1, "page")
41 def page_down(self,event):
42 event.widget.yview_scroll(1, "page")
43 def unit_up(self,event):
44 event.widget.yview_scroll(-1, "unit")
45 def unit_down(self,event):
46 event.widget.yview_scroll(1, "unit")
48 def build_children(self):
49 """ Construit la liste des enfants de self """
51 child = Node(self,self.item,self.command)
52 self.children.append(child)
53 child.state='expanded'
56 """ Dessine l'arbre """
59 for child in self.children:
61 lasty = child.lasty + 15
64 self.children[0].select()
65 self.resizescrollregion()
67 def deselectall_old(self):
68 """ déselectionne tous les éléments de l'arbre """
69 for child in self.children:
72 def deselectall(self):
73 """ déselectionne tous les éléments de l'arbre """
74 if self.node_selected :
75 self.node_selected.deselect()
78 """ Update tous les éléments de l'arbre """
79 for child in self.children:
82 def resizescrollregion(self):
83 self.scrolledcanvas.resizescrollregion()
85 def select_next(self,event):
86 self.node_selected.select_next()
88 def select_previous(self,event):
89 self.node_selected.select_previous()
91 def full_creation(self,name,index):
92 # A changer lorsqu'il y aura plusieurs jdc ouverts en même temps
93 self.children[0].full_creation(name,index)
96 for child in self.children :
97 self.verif_all_children()
100 def __init__(self,parent,item,command=None):
103 self.command = command
104 self.tree = self.parent.tree
105 self.appli = self.parent.appli
106 self.canvas = self.parent.canvas
108 #self.build_children()
111 self.state='collapsed'
114 self.x = self.y =None
118 # etape = noeud d'étape auquel appartient self
119 # = self si c'est lui-même
120 if isinstance(self.parent,Tree) :
121 # on est sur un noeud de JDC
125 elif isinstance(self.parent.parent,Tree) :
126 # on est sur un noeud d'étape
127 self.racine = self.parent
129 self.nature = 'ETAPE'
131 # on est sur un noeud de mot-clé
132 self.racine = self.parent.racine
133 self.etape=self.parent.etape
134 self.nature = 'MOTCLE'
136 def build_children(self):
137 """ Construit la liste des enfants de self """
139 sublist = self.item._GetSubList()
140 if not sublist : return
141 for item in sublist :
142 child = Node(self,item,self.command)
143 self.children.append(child)
145 #-----------------------------------------------
146 # Méthodes de sélection/déselection d'un noeud
147 #-----------------------------------------------
149 def select(self, event=None):
151 Rend le noeud courant (self) sélectionné et déselectionne
154 if not self.children : self.build_children()
155 self.tree.deselectall()
157 self.tree.node_selected = self
158 if self.command:apply(self.command,(self,))
160 self.canvas.focus_force()
163 def deselect_old(self, event=None):
164 """ Déselectionne self """
166 if self.displayed == 1:
168 for child in self.children:
171 def deselect(self, event=None):
172 """ Déselectionne self """
174 if self.displayed == 1 : self.dehighlight()
176 def make_visible(self):
177 """ Rend l'objet self visible cad déplace le scroll pour que self soit dans
178 la fenêtre de visu"""
179 x0,y0,x1,y1 = self.canvas.bbox(ALL)
180 self.canvas.yview("moveto",self.y/y1)
182 def select_next(self,ind=0):
183 """ on doit chercher à sélectionner dans l'ordre:
184 - son premier fils s'il est affiché
185 - son frère cadet s'il existe
186 - son oncle (benjamin de son père)
187 - ... appel récursif ...
189 if self.state=='expanded' and len(self.children) > ind:
190 self.children[ind].select()
192 index = self.parent.children.index(self) + 1
193 if isinstance(self.parent,TREE) :
195 self.children[ind].select()
197 self.children[0].select()
199 self.parent.select_next(index)
201 def select_previous(self):
202 """ on doit d'abord sélectionner(dans l'ordre) :
206 index = self.parent.children.index(self) + 1
208 self.parent.children[index].select()
211 #-----------------------------------------------
212 # Méthodes de recherche d'informations
213 #-----------------------------------------------
214 def geticonimage(self,name=None):
216 Retourne l'image qui doit être associée à self
219 name = self.item.GetIconName()
220 if not name or name == 'aucune' :
222 return images.get_image(name)
224 def get_nb_children(self):
225 """ Retourne le nombre d'enfants affichés de self """
227 if self.state =='collapsed' : return nb
228 for child in self.children :
229 nb = nb + 1 + child.get_nb_children()
232 def get_liste_id(self):
233 """ Retourne la liste de tous les id (filiation comprise) de self """
235 for child in self.children:
236 liste.extend(child.get_liste_id())
239 def get_node_fils(self,name) :
240 """ Retourne le fils de self de nom name s'il existe"""
241 for child in self.children:
242 if child.item.get_nom() == name: return child
244 #-----------------------------------------------
245 # Méthodes d'affichage d'un noeud
246 #-----------------------------------------------
248 """ Permet de tracer le noeud self """
249 # le début du noeud est en x,y
255 # choix de l'icone à afficher : + ou -
256 if self.item.IsExpandable():
257 if self.state == 'expanded':
258 iconname = "minusnode"
259 callback = self.collapse
261 iconname = "plusnode"
262 callback = self.expand
263 image = self.geticonimage(name=iconname)
264 self.icone_id = self.canvas.create_image(self.x, self.y, image=image)
265 self.canvas.tag_bind(self.icone_id, "<1>", callback)
266 self.id.append(self.icone_id)
267 # création de la ligne horizontale
268 self.ligne_id = self.canvas.create_line(self.x,self.y,self.x+10,self.y)
269 self.id.append(self.ligne_id)
270 self.canvas.tag_lower(self.ligne_id)
271 # affichage de l'icone (carre ,rond, ovale ...) de couleur
272 image = self.geticonimage()
274 self.image_id = self.canvas.create_image(self.x+15,self.y,image = image)
275 self.canvas.tag_bind(self.image_id,"<1>",self.select)
276 self.id.append(self.image_id)
279 # affichage du texte : nom de l'objet (ETAPE ou MOT-CLE) et sa valeur
281 if self.state == 'expanded' :
282 if not self.children : self.build_children()
283 if len(self.children) > 0:
285 self.lasty = self.children[-1].lasty
287 def drawchildren(self):
288 """ Dessine les enfants de self """
291 for child in self.children:
293 nb = child.get_nb_children()
297 """ Affiche les deux zones de texte après l'icône de couleur de l'objet """
298 if self.image_id != None :
303 # nom,fonte et couleur de l'objet du noeud à afficher
304 labeltext,fonte,couleur = self.item.GetLabelText()
305 if labeltext == '' : labeltext = ' '
306 if fonte == None : fonte = Fonte_Standard
307 if couleur == None : couleur = 'black'
308 # création du widget label
309 self.label = Label(self.canvas,
314 self.label_id = self.canvas.create_window(textx,texty,window=self.label,anchor='w')
315 self.id.append(self.label_id)
316 # bindings sur le widget label
317 self.label.bind("<1>", self.select)
318 self.label.bind("<Enter>",self.enter)
319 self.label.bind("<Leave>",self.leave)
320 # valeur de cet objet à afficher
321 x0, y0, x1, y1 = self.canvas.bbox(self.label_id)
322 textx = max(x1, 200) + 10
323 text = self.item.GetText() or " "
324 self.text = Label(self.canvas, text=text,
325 bd=0, padx=2, pady=2,background='gray95',
331 self.text_id = self.canvas.create_window(textx, texty,anchor="w", window=self.text)
332 self.id.append(self.text_id)
334 def highlight(self,event=None):
335 """ Met en surbrillance self"""
336 if hasattr(self,'label'):
337 self.label.configure(fg='white',bg='#00008b')
339 def dehighlight(self,event=None):
340 """ Rétablit l'affichage normal de self"""
341 if hasattr(self,'label'):
342 self.label.configure(fg='black',bg='gray95')
344 def enter(self,event=None):
345 """ Met en surbrillance self et affiche le fr de l'objet """
347 fr = self.item.get_fr()
348 self.appli.affiche_infos(fr)
350 def leave(self,event=None):
351 """ Rétablit l'affichage normal de self et efface le fr de l'objet """
352 if not self.selected :
354 self.appli.affiche_infos('')
356 def collapse_children(self):
357 """ Collapse récursivement tous les descendants de self """
358 if not self.children : return
359 for child in self.children:
360 child.state='collapsed'
362 child.collapse_children()
364 def collapse(self,event = None):
365 """ Collapse self et descendants et retrace self """
366 nb = self.get_nb_children()
367 self.state = 'collapsed'
368 self.collapse_children()
374 self.draw(self.x,self.y)
378 def expand(self,event = None):
379 """ Expanse self et le retrace """
380 if not self.item.isactif() : return
381 if not self.children : self.build_children()
382 self.state = 'expanded'
383 nb = self.get_nb_children()
386 self.draw(self.x,self.y)
391 """ Redessine self : nb est le décalage à introduire
392 en dessous de self pour le redessiner """
393 # nb = nombre d'items de décalage
395 # on efface self et on le redessine
397 self.draw(self.x,self.y)
400 def update_coords(self):
401 """ Permet d'updater les coordonnes de self et de tous ses enfants"""
402 if self.displayed == 0 : return
403 if self.image_id != None :
404 coords = self.canvas.coords(self.image_id)
405 self.x = coords[0]-15
407 coords = self.canvas.coords(self.label_id)
408 self.x = coords[0]-15
410 if self.state == 'expanded' :
411 for child in self.children:
412 if child.displayed != 0:
413 child.update_coords()
415 def update_icone(self):
416 """ Met à jour les icônes de tous les noeuds : teste la validité de l'objet
417 Cette méthode est très lente, trop !!"""
418 if self.image_id != None :
419 image = self.geticonimage()
420 self.canvas.itemconfig(self.image_id,image=image)
421 if self.state == 'expanded':
422 for child in self.children:
423 if child.displayed != 0:
426 def update_texte(self):
427 """ Met à jour les noms des SD et valeurs des mots-clés """
428 text = self.item.GetText()
429 if text == None : text = ''
430 self.text.configure(text=text)
431 if self.state == 'expanded' :
432 for child in self.children:
433 if child.displayed != 0 : child.update_texte()
435 def update(self,event=None) :
437 Cette méthode est appelée pour demander l update d un noeud
438 d'un jeu de commandes
439 Cette demande est transmise au noeud racine (le JDC) qui update
440 tout l arbre représentant le jeu de commandes
441 Pendant cette mise à jour, on appelle la méthode isvalid qui
442 fera l update de tous les objets déclarés modifiés lors des
444 La métode isvalid est en général appelée par l intermédiaire de
445 update_icone -> geticonimage -> GetIconName
447 self.racine.update_coords()
448 self.racine.trace_ligne()
449 self.racine.update_icone()
450 self.racine.update_texte()
451 self.tree.resizescrollregion()
454 """ Efface du canvas les id associés à self : cad les siens et ceux
457 self.canvas.delete(id)
458 if not self.children : return
459 for child in self.children:
463 """ Déplace de l'incrément dy tous les id en dessous de self """
464 # il faut marquer tous les suivants de self
465 bbox1 = self.canvas.bbox(ALL)
466 self.canvas.dtag(ALL,'move')
467 self.canvas.delete('line')
469 self.canvas.addtag_overlapping('move',bbox1[0],self.y +10,bbox1[2],bbox1[3])
471 print "Erreur dans move :"
474 print self.item.object
475 print self.item.object.definition.label
478 # on déplace tous les items de dy
479 self.canvas.move('move',0,dy)
480 # il faut réactualiser la zone de scroll
481 self.tree.resizescrollregion()
483 def trace_ligne(self):
484 """ Dessine les lignes verticales entre frères et entre père et premier fils"""
485 if self.state=='collapsed' : return
486 #if self.displayed == 0 : return
487 if len(self.children)==0 : return
488 # on est bien dans le cas d'un noeud expansé avec enfants ...
489 # il faut rechercher l'ordonnée du dernier fils de self
490 y_end = self.children[-1].y
491 ligne = self.canvas.create_line(self.x+15,self.y,self.x+15,y_end,tags='line')
492 self.canvas.tag_lower(ligne)
493 for child in self.children :
497 print "Erreur dans trace_ligne :"
499 print child.item.object
501 def make_visible_OBSOLETE(self,nb):
502 """ Cette méthode a pour but de rendre le noeud self (avec tous ses descendants
503 affichés) visible dans le canvas """
504 x = self.canvas.canvasx(self.canvas.cget('width'))
505 y = self.canvas.canvasy(self.canvas.cget('height'))
507 x0,y0,x1,y1 = self.canvas.bbox(ALL)
508 #print 'x0,y1=',x0,y1
510 nb = self.get_nb_children()
511 y_fin = y_deb + 20*nb
512 #print 'y_deb,y_fin=',y_deb,y_fin
514 #------------------------------------------------------------------
515 # Méthodes de création et destruction de noeuds
516 # Certaines de ces méthodes peuvent être appelées depuis l'externe
517 #------------------------------------------------------------------
518 def replace_node(self,node1,node2):
519 """ Remplace le noeud 1 par le noeud 2 dans la liste des enfants de self"""
520 index= self.children.index(node1)
521 self.delete_node_child(node1)
522 self.children.insert(index,node2)
524 def full_creation(self,name,pos=None):
526 Interface avec ACCAS : création de l'objet de nom name et
527 du noeud associé. Retourne le noeud fils ainsi créé
529 item = self.item.additem(name,pos)
530 if item == None or item == 0:
531 # impossible d'ajouter le noeud de nom : name
533 nature = item.get_nature()
534 if nature in ("COMMANDE","OPERATEUR","PROCEDURE","COMMENTAIRE",
535 "PARAMETRE","COMMANDE_COMMENTARISEE","PARAMETRE_EVAL"):
536 # on veut ajouter une commande ou un commentaire ou un paramètre
537 # il ne faut pas rechercher un même objet déjà existant
538 # à modifier : il faut tester l'attribut 'repetable'
540 elif self.item.object.isMCList():
541 # Dans ce cas on ne fait pas de remplacement. On ne cherche pas un objet de meme nom
544 enfant = self.get_node_fils(item.get_nom())
546 # un fils de même nom existe déjà : on remplace
547 # un MCFACT (ou une MCList) par une (autre) MCList
548 child = Node(self,item,self.command)
549 self.replace_node(enfant,child)
551 child = Node(self, item,self.command)
553 self.children.append(child)
555 self.children.insert(pos,child)
558 def append_brother(self,name,pos='after',retour='non'):
560 Permet d'ajouter un frère à self
561 par défaut on l'ajoute après self
564 # on veut ajouter le frère de nom name directement avant ou après self
565 index = self.parent.children.index(self)
571 print str(pos)," n'est pas un index valide pour append_brother"
573 return self.parent.append_child(name,pos=index,retour=retour)
575 def append_node_child(self,fils,pos=None,verif='oui'):
577 Fait appel à la création complète de fils et à la vérification
578 des conditions en fonction du contexte
579 Attention : fils peut être un nom ou déjà un object (cas d'une copie)
581 if not self.children : self.build_children()
583 #pos = len(self.children)
584 if type(fils) == types.InstanceType:
585 pos = self.item.get_index_child(fils.nom)
587 pos = self.item.get_index_child(fils)
588 child = self.full_creation(fils,pos)
590 # on n'a pas pu créer le noeud fils
593 self.state = 'expanded'
595 if not child.children : child.build_children()
596 test = child.item.isMCList()
598 child.children[-1].verif_condition()
600 child.verif_condition()
601 self.verif_condition()
604 def append_child(self,name,pos=None,verif='oui',retour='non'):
606 Permet d'ajouter un fils à self
607 on peut l'ajouter en fin de liste (défaut) ou en début
613 index = len(self.children)
614 elif pos != None and type(pos) == types.IntType :
615 # on donne la position depuis l'extérieur
616 # (appel de append_child par append_brother par exemple)
618 elif type(pos) == types.InstanceType:
619 # pos est un item. Il faut inserer name apres pos
620 index = self.item.get_index(pos) +1
622 if type(name) == types.InstanceType:
623 index = self.item.get_index_child(name.nom)
625 index = self.item.get_index_child(name)
626 nbold = self.get_nb_children()
627 self.state='expanded'
628 child = self.append_node_child(name,pos=index)
630 # on n'a pas pu créer le fils
632 nbnew = self.get_nb_children()
633 self.redraw(nbnew-nbold)
636 #child.make_visible()
637 if retour == 'oui': return child
639 def delete_node_child(self,child):
640 """ Supprime child des enfants de self et les id associés """
643 self.children.remove(child)
646 def delete_child(self,child):
648 Supprime child des enfants de self, tous les id associés
651 if self.item.suppitem(child.item):
652 self.delete_node_child(child)
658 """ Méthode externe pour la destruction du noeud ET de l'objet
659 Gère l'update du canvas"""
660 if self.parent.item.isMCList():
661 pere = self.parent.parent
662 nbold = pere.get_nb_children()
663 if self.parent.delete_child(self):
664 self.parent.traite_mclist()
665 if self.item.get_position() == 'global':
666 self.etape.verif_all()
667 elif self.item.get_position() == 'global_jdc':
668 self.racine.verif_all()
670 self.parent.verif_condition()
671 nbnew = pere.get_nb_children()
674 nbold = pere.get_nb_children()
675 if self.parent.delete_child(self):
676 if self.item.get_position() == 'global':
677 self.etape.verif_all()
678 elif self.item.get_position() == 'global_jdc':
679 self.racine.verif_all()
681 self.parent.verif_condition()
683 print 'Erreur dans la destruction de ',self.item.get_nom(),' dans delete'
684 nbnew = pere.get_nb_children()
685 pere.redraw(nbnew-nbold)
687 def copynode(self,node,pos) :
688 """ node est le noeud à copier à la position pos de self ( = parent de node) """
689 objet_copie = node.item.get_copie_objet()
690 child = self.full_creation(node.item,pos)
691 child.displayed = node.displayed
692 #child.image_id = node.image_id
693 #child.label_id = node.label_id
694 if child.item.get_nature() == "MCList":
695 child.item.object[-1].mc_liste = objet_copie.mc_liste
698 child.item.object.mc_liste = objet_copie.mc_liste
701 #--------------------------------------------------------------
702 # Méthodes de vérification du contexte et de validité du noeud
703 #--------------------------------------------------------------
704 def traite_mclist(self):
705 """ Dans le cas d'une MCList il faut vérifier qu'elle n'est pas vide
706 ou réduite à un seul élément suite à une destruction
708 # self représente une MCList
709 if len(self.item) == 0 :
710 # la liste est vide : il faut la supprimer
712 elif len(self.item) == 1:
713 # il ne reste plus qu'un élément dans la liste
714 # il faut supprimer la liste et créer directement l'objet
715 index = self.parent.children.index(self)
716 noeud = self.children[0]
717 if self.parent.delete_child(self):
718 self.parent.append_node_child(noeud.item,pos=index,verif='non')
719 #if self.parent.delete_child(self):
720 # self.parent.copynode(self.children[0],index)
722 # print 'erreur dans la destruction de :',self.item.get_nom(),' dans traite_mclist'
727 self.verif_all_children()
729 def verif_all_children(self):
730 if not self.children : self.build_children()
731 if self.nature != 'JDC' :
733 for child in self.children :
734 child.verif_all_children()
738 Lance la vérification des conditions des blocs de self et le cas
739 échéant redessine self
741 nbold = self.get_nb_children()
742 test = self.verif_condition()
743 nbnew = self.get_nb_children()
745 self.redraw(nbnew-nbold)
747 def verif_condition(self):
749 on lance la vérification des conditions de chaque bloc de self
750 on crée ou supprime les noeuds concernés
751 (self est d'un niveau inférieur ou égal à l'ETAPE)
753 if self.item.object.__class__.__name__ == 'ETAPE_NIVEAU': return 0
755 l_bloc_arajouter,l_bloc_aenlever = self.verif_condition_bloc()
756 if len(l_bloc_arajouter) > 0:
758 for mc in l_bloc_arajouter:
759 self.append_node_child(mc,verif='non')
760 if len(l_bloc_aenlever) > 0:
762 for mc in l_bloc_aenlever:
763 mocle = self.get_node_fils(mc)
764 self.delete_child(mocle)
765 l_mc_presents = self.item.get_liste_mc_presents()
766 l_mc_arajouter= self.verif_condition_regles(l_mc_presents)
767 if len(l_mc_arajouter) > 0:
769 for mc in l_mc_arajouter:
770 self.append_node_child(mc,verif='non')
771 if len(l_mc_arajouter)+len(l_bloc_arajouter)+len(l_bloc_aenlever) != 0 :
772 self.verif_condition()
775 def verif_condition_bloc(self):
776 return self.item.verif_condition_bloc()
778 def verif_condition_regles(self,l_mc_presents):
779 return self.item.verif_condition_regles(l_mc_presents)