]> SALOME platform Git repositories - tools/eficas.git/blob - Editeur/treewidget.py
Salome HOME
PN : pour déplacement dans l arbre
[tools/eficas.git] / Editeur / treewidget.py
1 # -*- coding: utf-8 -*-
2 #            CONFIGURATION MANAGEMENT OF EDF VERSION
3 # ======================================================================
4 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
5 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
6 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
7 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
8 # (AT YOUR OPTION) ANY LATER VERSION.
9 #
10 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
11 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
12 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
13 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
14 #
15 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
16 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
17 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
18 #
19 #
20 # ======================================================================
21 import os,sys,string,re,types,traceback
22 from Tkinter import *
23
24
25 import fontes
26 import images
27 from Ihm import CONNECTOR
28
29 #
30 __version__="$Name:  $"
31 __Id__="$Id: treewidget.py,v 1.26 2005/11/03 09:03:49 eficas Exp $"
32 #
33
34 Fonte_Standard = fontes.standard
35
36 class Tree :
37     def __init__(self,appli,jdc_item,scrolledcanvas,command = None,rmenu=None):
38         self.item = jdc_item
39         self.scrolledcanvas = scrolledcanvas
40         self.canvas = self.scrolledcanvas.component('canvas')
41         self.id_up=self.canvas.bind("<Key-Prior>", self.page_up)
42         self.id_down=self.canvas.bind("<Key-Next>", self.page_down)
43         #self.id_uup=self.canvas.bind("<Key-Up>", self.unit_up)
44         #self.id_udown=self.canvas.bind("<Key-Down>", self.unit_down)             
45         self.id_um=self.canvas.bind("<Key-Left>", self.mot_up)
46         self.id_dm=self.canvas.bind("<Key-Right>", self.mot_down)
47         self.id_s=self.canvas.bind("<1>", self.canvas_select)             
48         self.tree = self
49         self.command = command
50         self.rmenu=rmenu
51         self.appli = appli
52         self.parent = None
53         self.racine = self
54         self.node_selected = None
55         self.build_children()
56
57     def canvas_select(self,event):
58         self.canvas.focus_set()
59
60     def page_up(self,event):
61         event.widget.yview_scroll(-1, "page")
62
63     def page_down(self,event):
64         event.widget.yview_scroll(1, "page")
65         
66     def unit_up(self,event):
67         event.widget.yview_scroll(-1, "unit")
68
69     def unit_down(self,event):
70         event.widget.yview_scroll(1, "unit")              
71
72     def mot_down(self,event):
73         self.select_next(None)
74         self.canvas.focus_set()
75
76     def mot_down_force(self):
77         self.select_next(None)
78         self.canvas.focus_set()
79
80     def mot_up(self,event):
81         self.node_selected.select_mot_previous()
82         self.canvas.focus_set()
83
84     def mot_up_force(self):
85         self.node_selected.select_mot_previous()
86         self.canvas.focus_set()
87
88     def build_children(self):
89         """ Construit la liste des enfants de self """
90         self.children = []
91         child = self.item.itemNode(self,self.item,self.command,self.rmenu)
92         self.children.append(child)
93         child.state='expanded'
94
95     def draw(self):
96         """ Dessine l'arbre """
97         lasty = 8
98         x = 5
99         for child in self.children:
100             child.draw(x,lasty)
101             lasty = child.lasty + 15
102         self.children[0].select()
103         self.resizescrollregion()
104
105     def deselectall(self):
106         """ déselectionne tous les éléments de l'arbre """
107         if self.node_selected :
108             self.node_selected.deselect()
109             
110     def update(self):
111         """ Update tous les éléments de l'arbre """
112         for child in self.children:
113             child.update()
114
115     def supprime(self):
116         """ supprime tous les éléments de l'arbre """
117         #print "supprime",self
118         self.canvas.unbind("<Key-Prior>",self.id_up)
119         self.canvas.unbind("<Key-Next>",self.id_down)
120         self.canvas.unbind("<Key-Up>",self.id_uup)
121         self.canvas.unbind("<Key-Down>",self.id_udown)             
122         self.canvas.unbind("<Key-Left>",self.id_um)
123         self.canvas.unbind("<Key-Right>",self.id_dm)
124         self.canvas.unbind("<1>",self.id_s)             
125         self.tree = None
126         self.racine = None
127         self.node_selected = None
128         self.item = None
129         self.scrolledcanvas = None
130         self.canvas = None
131         self.command = None
132         self.rmenu=None
133         for child in self.children:
134             child.supprime()
135         self.children=[]
136
137     def update_valid(self) :
138         """Cette methode a pour but de mettre a jour la validite du noeud
139            et de propager la demande de mise à jour à son parent
140         """
141         pass
142
143     def resizescrollregion(self):
144         x0,y0,x1,y1=self.canvas.bbox(ALL)
145         # On ajoute une marge approximativement de la moitié du canvas
146         y1=y1+self.canvas.winfo_height()/2
147         self.canvas.configure(scrollregion = (x0,y0,x1,y1))
148
149     def select_next(self,event):
150         self.node_selected.select_next()
151         self.canvas.focus_set()
152
153     def select_previous(self,event):
154         self.node_selected.select_previous()
155
156     def see(self,items):
157         x1, y1, x2, y2=apply(self.canvas.bbox, items)
158         while x2 > self.canvas.canvasx(0)+self.canvas.winfo_width():
159             old=self.canvas.canvasx(0)
160             self.canvas.xview_scroll( 1, 'units')
161             # avoid endless loop if we can't scroll
162             if old == self.canvas.canvasx(0):
163                 break
164         while y2 > self.canvas.canvasy(0)+self.canvas.winfo_height():
165             old=self.canvas.canvasy(0)
166             self.canvas.yview_scroll( 1, 'units')
167             if old == self.canvas.canvasy(0):
168                 break
169         # done in this order to ensure upper-left of object is visible
170         while x1 < self.canvas.canvasx(0):
171             old=self.canvas.canvasx(0)
172             self.canvas.xview_scroll( -1, 'units')
173             if old == self.canvas.canvasx(0):
174                 break
175         while y1 < self.canvas.canvasy(0):
176             old=self.canvas.canvasy(0)
177             self.canvas.yview_scroll( -1, 'units')
178             if old == self.canvas.canvasy(0):
179                 break
180
181     #def __del__(self):
182     #   print "__del__",self
183
184             
185 class Node :
186     def __init__(self,parent,item,command=None,rmenu=None):
187         self.parent = parent
188         self.item = item
189         self.connect()
190
191         self.command = command
192         self.rmenu=rmenu
193         self.tree = self.parent.tree
194         self.appli = self.parent.appli
195         self.canvas = self.parent.canvas
196         self.init()
197
198     def init(self):
199         self.state='collapsed'
200         self.displayed = 0
201         self.selected = 0
202         self.x = self.y  =None
203         self.lasty = 0
204         self.children = None
205         self.id = []
206         if self.parent is self.tree:
207            self.racine=self
208         else:
209            self.racine = self.parent.racine
210            
211     def connect(self):
212         self.item.connect("add",self.onAdd,())
213         self.item.connect("supp",self.onSupp,())
214         self.item.connect("valid",self.onValid,())
215
216     #def __del__(self):
217     #    print "__del__",self
218
219     def force_select(self):
220         if self.selected:
221            # le noeud est selectionné. On force la reconstruction du panel associé
222            if self.command:apply(self.command,(None,))
223            self.select()
224
225     def onValid(self):
226         #print "onValid : l'item a changé de validité ",self.item,self.item.object,self.item.object.isvalid()
227         self.update_node_valid()
228         self.update_node_label()
229         self.update_node_texte()
230         if self.selected and self.command:
231            self.command(self)
232
233     def onAdd(self,objet):
234         #print "onAdd : un objet a été ajouté aux fils de l'item ",self.item.object,objet
235         self.expand_node()
236         old_nodes=self.children
237         self.update_nodes()
238         self.redraw_children(old_nodes)
239         self.force_select()
240
241     def onSupp(self,objet):
242         #print "onSupp : un objet a été supprimé des fils de l'item ",self.item.object,objet
243         self.expand_node()
244         old_nodes=self.children
245         self.update_nodes()
246         self.redraw_children(old_nodes)
247         self.force_select()
248
249     def update_nodes(self):
250         #print "update_nodes",self
251         newnodes=[]
252         inodes=iter(self.children)
253         sublist=self.item._GetSubList()
254         iliste=iter(sublist)
255
256         while(1):
257            old_item=item=None
258            for node in inodes:
259               old_item=node.item
260               if old_item in sublist:break
261               #print "item supprime",old_item
262            for item in iliste:
263               if item is old_item:break
264               #print "item ajoute",item
265               child = item.itemNode(self,item,self.command,self.rmenu)
266               newnodes.append(child)
267
268            if old_item is None and item is None:break
269            if old_item is item:
270               #print "item conserve",item
271               newnodes.append(node)
272
273         self.children=newnodes
274         self.connect()
275
276     def supprime(self):
277         #print "supprime",self
278         self.efface_node()
279         self.racine = None
280         self.command = None
281         self.rmenu=None
282         if not self.children : return
283         for child in self.children:
284             child.supprime()
285         self.children=None
286
287     def redraw_children(self,old_nodes):
288         #print "redraw_children",old_nodes
289         #print self.children
290         y = self.y + 20
291         x = self.x + 15
292         supp_nodes=[]
293
294         inodes=iter(old_nodes)
295         iliste=iter(self.children)
296         # on parcourt la liste des anciens noeuds (node)
297         # et la liste des nouveaux noeuds (new_node) en parallele (iterateurs)
298
299         while(1):
300            new_node=node=None
301            for node in inodes:
302               #print "ancien noeud",node
303               if node in self.children:break # ancien noeud toujours present
304               #print "noeud supprime",node,node.item.GetLabelText()[0]
305               dy=node.y-node.lasty -20
306               #print "deplacer noeuds",y,dy
307               node.move_nodes(y,dy)
308               node.supprime()
309               #supp_nodes.append(node)
310
311            for new_node in iliste:
312               #print "nouveau noeud",new_node
313               if new_node in old_nodes: break # nouveau noeud deja present
314               #print "noeud ajoute",new_node,new_node.item.GetLabelText()[0]
315               y=self.draw_node(new_node,x,y)
316
317            if node is None and new_node is None : break
318
319            if node is new_node: # ancien noeud
320               #print "noeud conserve",node
321               node.update_node_label()
322               y=y+node.lasty-node.y +20
323
324         self.racine.update_coords()
325         self.canvas.delete('line')
326         self.racine.trace_ligne()
327         self.tree.resizescrollregion()
328         # Mettre à 1 pour verifier les cycles entre objets node
329         #withCyclops=0
330         #if withCyclops:
331            #from Misc import Cyclops
332            #z = Cyclops.CycleFinder()
333            #print supp_nodes
334            #for o in supp_nodes:
335              #z.register(o)
336            #del supp_nodes
337            #del o
338            #z.find_cycles()
339            #z.show_stats()
340            #z.show_cycles()
341
342     def tag_move_nodes(self,y):
343         """ Marque pour deplacement tous les noeuds au dela de l'ordonnée y """
344         self.canvas.dtag(ALL,'move')
345         # on marque tous les ids au dela de y
346         x0, y0, x1, y1 = self.canvas.bbox(ALL)
347         self.canvas.addtag_overlapping('move',x0,y,x1,y1)
348
349     def move_nodes(self,y,dy):
350         """ Déplace de l'incrément dy les noeuds au dela de l'ordonnée y """
351         self.tag_move_nodes(y)
352         # on déplace tous les items de dy
353         self.canvas.move('move',0,dy)
354
355     def draw_node(self,new_node,x,y):
356         """ Dessine le noeud new_node en x,y en deplacant les noeuds existants
357             en y et au dela
358             Retourne la position du premier des noeuds deplaces
359         """
360         self.tag_move_nodes(y)
361         #if new_node.item.isactif():
362            #new_node.state = 'expanded'
363         new_node.state = 'expanded'
364         new_node.draw(x,y)
365         dy=(new_node.get_nb_children()+1)*20
366         #print "deplacer noeuds",y,dy
367         self.canvas.move('move',0,dy)
368         return new_node.lasty+20
369
370     def build_children(self):
371         """ Construit la liste des enfants de self """
372         self.children = []
373         sublist = self.item._GetSubList()
374         if not sublist : return
375         for item in sublist :
376             child = item.itemNode(self,item,self.command,self.rmenu)
377             self.children.append(child)
378             
379     #-----------------------------------------------
380     # Méthodes de sélection/déselection d'un noeud
381     #-----------------------------------------------
382     
383     def select(self, event=None):
384         """
385         Rend le noeud courant (self) sélectionné et déselectionne
386         tous les autres
387         """
388         #print "SELECT",self
389         if not self.children : self.build_children()
390         self.tree.deselectall()
391         self.selected = 1
392         self.tree.node_selected = self
393         if self.command:apply(self.command,(self,))
394         self.highlight()
395         self.make_visible()
396
397     def deselect(self, event=None):
398         """ Déselectionne self """
399         self.selected = 0
400         if self.displayed == 1 : self.dehighlight()
401             
402     def make_visible(self):
403         """ Rend l'objet self visible cad déplace le scroll pour que self soit dans
404             la fenêtre de visu
405         """
406         lchild=self.last_child()
407         self.tree.see((self.image_id,lchild.image_id))
408         
409     def select_next(self,ind=0):
410         """ on doit chercher à sélectionner dans l'ordre:
411                 - son premier fils s'il est affiché
412                 - son frère cadet s'il existe
413                 - son oncle (benjamin de son père)
414                 - ... appel récursif ...
415         """
416         if self.state=='expanded' and len(self.children) > ind:
417             self.children[ind].select()
418         else :
419             index = self.parent.children.index(self) + 1
420             try :
421               if isinstance(self.parent,TREE) :
422                 try:
423                     self.children[ind].select()
424                 except:
425                     self.children[0].select()
426             except :
427                 if self.parent is self.tree:
428                    pass
429                 else :
430                    self.parent.select_next(index)
431
432     def select_mot_previous(self):
433         index = self.parent.children.index(self) - 1
434         try :
435             if index > -1  :
436                self.parent.children[index].select()
437             elif self.parent is self.tree:
438                pass
439             else :
440                self.parent.select()
441         except:
442             if self.parent is self.tree:
443                    pass
444             else :
445                self.parent.select_previous()
446
447     def select_previous(self):
448         """ on doit d'abord sélectionner(dans l'ordre) :
449              - son frère aîné
450              - son père
451         """
452         index = self.parent.children.index(self) - 1
453         try :
454             self.parent.children[index].select()
455         except:
456             #self.parent.select()
457             if self.parent is self.tree:
458                    pass
459             else :
460                self.parent.select_previous()
461
462     def popup(self,event=None):
463         """
464             Declenche le traitement associé au clic droit de la souris
465             sur l'icone du Node
466         """
467         if not self.rmenu:return
468         apply(self.rmenu,(self,event))
469
470     #-----------------------------------------------
471     # Méthodes de recherche d'informations
472     #-----------------------------------------------
473     def geticonimage(self,name=None):
474         """
475         Retourne l'image qui doit être associée à self
476         """
477         if not name :
478             name = self.item.GetIconName()
479         if not name or name == 'aucune' :
480             return None
481         return images.get_image(name)
482
483     def get_nb_children(self):
484         """ Retourne le nombre d'enfants affichés de self """
485         nb = 0
486         if self.state =='collapsed' :  return nb
487         for child in self.children :
488             nb = nb + 1 + child.get_nb_children()
489         return nb
490
491     def get_liste_id(self):
492         """ Retourne la liste de tous les id (filiation comprise) de self """
493         liste = self.id
494         for child in self.children:
495             liste.extend(child.get_liste_id())
496         return liste
497
498     def get_node_fils(self,name) :
499         """ Retourne le fils de self de nom name s'il existe"""
500         for child in self.children:
501             if child.item.get_nom() == name: return child
502         return None
503
504     #-----------------------------------------------
505     # Méthodes d'affichage d'un noeud
506     #-----------------------------------------------
507     def draw(self,x,y):
508         """ Permet de tracer le noeud self """
509         # le début du noeud est en x,y
510         self.x = x
511         self.y = y
512         self.lasty = y
513         self.displayed = 1
514         self.id=[]
515         # choix de l'icone à afficher : + ou -
516         if self.item.IsExpandable():
517             if self.state == 'expanded':
518                 iconname = "minusnode"
519                 callback = self.collapse
520             else:
521                 iconname = "plusnode"
522                 callback = self.expand
523             image = self.geticonimage(name=iconname)
524             self.icone_id = self.canvas.create_image(self.x, self.y, image=image)
525             self.callback_id=self.canvas.tag_bind(self.icone_id, "<1>", callback)
526             self.id.append(self.icone_id)
527         # création de la ligne horizontale
528         self.ligne_id = self.canvas.create_line(self.x,self.y,self.x+10,self.y)
529         self.id.append(self.ligne_id)
530         self.canvas.tag_lower(self.ligne_id)
531         # affichage de l'icone (carre ,rond, ovale ...) de couleur
532         image = self.geticonimage()
533         if image != None :
534             self.image_id = self.canvas.create_image(self.x+15,self.y,image = image)
535             self.select_id2=self.canvas.tag_bind(self.image_id,"<1>",self.select)
536             self.popup_id2=self.canvas.tag_bind(self.image_id,"<3>",self.popup)
537             self.id.append(self.image_id)
538         else:
539             self.image_id = None
540         # affichage du texte : nom de l'objet (ETAPE ou MOT-CLE) et sa valeur
541         self.drawtext()
542         if self.state == 'expanded' :
543             if not self.children : self.build_children()
544             if len(self.children) > 0:
545                 self.drawchildren()
546                 self.lasty = self.children[-1].lasty
547    
548     def drawchildren(self):
549         """ Dessine les enfants de self """
550         y = self.y + 20
551         x = self.x + 15
552         for child in self.children:
553             child.draw(x,y)
554             nb = child.get_nb_children()
555             y = y + 20*(nb+1)
556         self.trace_ligne()
557
558     def drawtext(self):
559         """ Affiche les deux zones de texte après l'icône de couleur de l'objet """
560         if self.image_id != None :
561             textx = self.x + 30
562         else:
563             textx = self.x + 15
564         texty = self.y
565         # nom,fonte et couleur de l'objet du noeud à afficher
566         labeltext,fonte,couleur = self.item.GetLabelText()
567         if labeltext    == ''   : labeltext = '   '
568         if fonte        == None : fonte = Fonte_Standard
569         if couleur      == None : couleur = 'black'
570         # création du widget label
571         self.label = Label(self.canvas,
572                            text = labeltext,
573                            fg = couleur,
574                            bg = 'gray95',
575                            font=fonte)
576         self.label_id = self.canvas.create_window(textx,texty,window=self.label,anchor='w')
577         self.id.append(self.label_id)
578         # bindings sur le widget label
579         self.select_id=self.label.bind("<1>", self.select)
580         self.popup_id=self.label.bind("<3>", self.popup)
581         self.enter_id=self.label.bind("<Enter>",self.enter)
582         self.leave_id=self.label.bind("<Leave>",self.leave)
583         # valeur de cet objet à afficher
584         x0, y0, x1, y1 = self.canvas.bbox(self.label_id)
585         textx = max(x1, 200) + 10
586         text = self.item.GetText() or " "
587         self.text = Label(self.canvas, text=text,
588                             bd=0, padx=2, pady=2,background='gray95',
589                             font=fonte)
590         if self.selected:
591             self.highlight()
592         else:
593             self.dehighlight()
594         self.text_id = self.canvas.create_window(textx, texty,anchor="w", window=self.text)
595         self.id.append(self.text_id)
596         
597     def highlight(self,event=None):
598         """ Met en surbrillance self"""
599         if hasattr(self,'label'):
600             self.label.configure(fg='white',bg='#00008b')
601             
602     def dehighlight(self,event=None):
603         """ Rétablit l'affichage normal de self"""
604         if hasattr(self,'label'):
605             self.label.configure(fg='black',bg='gray95')
606
607     def enter(self,event=None):
608         """ Met en surbrillance self et affiche le fr de l'objet """
609         self.highlight()
610         fr = self.item.get_fr()
611         self.appli.affiche_infos(fr)
612         
613     def leave(self,event=None):
614         """ Rétablit l'affichage normal de self et efface le fr de l'objet """
615         if not self.selected :
616             self.dehighlight()
617         self.appli.affiche_infos('')
618
619     def collapse_children(self):
620         """ Collapse récursivement tous les descendants de self """
621         if not self.children : return
622         for child in self.children:
623             child.state='collapsed'
624             child.collapse_children()
625             
626     def collapse(self,event = None):
627         """ Collapse self et descendants et retrace self """
628         nb = self.get_nb_children()
629         self.state = 'collapsed'
630         self.collapse_children()
631         self.redraw(-nb)
632         self.select()
633    
634     def expand_node(self,event = None):
635         """ Expanse self et le retrace """
636         if self.state == 'expanded':return
637         #if not self.item.isactif() : return
638         if not self.children : self.build_children()
639         self.state = 'expanded'
640         nb = self.get_nb_children()
641         self.redraw(nb)
642
643     def expand(self,event = None):
644         """ Expanse self et le retrace """
645         self.expand_node()
646         self.select()
647
648     def redraw(self,nb):
649         """ Redessine self :  nb est le décalage à introduire
650             en dessous de self pour le redessiner """
651         # nb = nombre d'items de décalage
652         self.move(20*nb)
653         # on efface self et on le redessine
654         self.efface()
655         self.draw(self.x,self.y)
656         # Il n'est pas nécessaire d'appeler update
657         # il suffit d'updater les coordonnees et de retracer les lignes
658         self.racine.update_coords()
659         self.racine.trace_ligne()
660         self.update_valid()
661         self.tree.resizescrollregion()
662         
663     def update_coords(self):
664         """ Permet d'updater les coordonnes de self et de tous ses enfants"""
665         if self.displayed == 0 : return
666         if self.image_id != None :
667             coords = self.canvas.coords(self.image_id)
668             self.x = coords[0]-15
669         else:
670             coords = self.canvas.coords(self.label_id)
671             self.x = coords[0]-15
672         self.y = coords[1]
673         self.lasty = self.y
674         if self.state == 'expanded' :
675             for child in self.children:
676                 if child.displayed != 0:
677                     child.update_coords()
678                     self.lasty = child.lasty
679
680     def update_icone(self):
681         """ Met à jour les icônes de tous les noeuds : teste la validité de l'objet
682         Cette méthode est très lente, trop !!"""
683         if self.image_id != None :
684             image = self.geticonimage()
685             self.canvas.itemconfig(self.image_id,image=image)
686         if self.state == 'expanded':
687             for child in self.children:
688                 if child.displayed != 0:
689                     child.update_icone()
690
691     def update_label_texte(self):
692         """ Met a jour le label du noeud et celui de tous ses fils ouverts """
693         self.update_node_label()
694         if self.state == 'expanded' :
695             for child in self.children:
696                 if child.displayed != 0 : child.update_label_texte()
697
698     def update_texte(self):
699         """ Met à jour les noms des SD et valeurs des mots-clés """
700         self.update_node_texte()
701         if self.state == 'expanded' :
702             for child in self.children:
703                 if child.displayed != 0 : child.update_texte()
704         
705     def update_node_label(self):
706         """ Met a jour le label du noeud """
707         if self.displayed == 0 : return
708         # nom,fonte et couleur de l'objet du noeud à afficher
709         labeltext,fonte,couleur = self.item.GetLabelText()
710         if labeltext    == ''   : labeltext = '   '
711         if fonte        == None : fonte = Fonte_Standard
712         if couleur      == None : couleur = 'black'
713         self.label.configure(text=labeltext,font=fonte)
714
715     def update_node_texte(self):
716         """ Met à jour les noms des SD et valeurs des mots-clés """
717         if self.displayed == 0 : return
718         text = self.item.GetText()
719         if text == None : text = ''
720         self.text.configure(text=text)
721
722     def update_node_valid(self) :
723         """Cette methode remet a jour la validite du noeud (icone)
724            Elle appelle isvalid
725         """
726         if self.displayed == 0 : return
727         if self.image_id != None :
728             image = self.geticonimage()
729             self.canvas.itemconfig(self.image_id,image=image)
730
731     def update_valid(self) :
732         """Cette methode a pour but de mettre a jour la validite du noeud
733            et de propager la demande de mise à jour à son parent
734         """
735         self.update_node_valid()
736         self.parent.update_valid()
737
738     def update(self,event=None) :
739         """ Classe Node :
740             Cette méthode est appelée pour demander l update d un noeud 
741             d'un jeu de commandes
742             Cette demande est transmise au noeud racine (le JDC) qui update
743             tout l arbre représentant le jeu de commandes
744             Pendant cette mise à jour, on appelle la méthode isvalid qui
745             fera l update de tous les objets déclarés modifiés lors des
746             actions précédentes
747             La métode isvalid est en général appelée par l intermédiaire de
748             update_icone -> geticonimage -> GetIconName
749         """
750         #print "update",self
751         #traceback.print_stack()
752         self.racine.update_coords()
753         self.racine.trace_ligne()
754         self.racine.update_icone()
755         self.racine.update_texte()
756         self.racine.update_label_texte()
757         self.tree.resizescrollregion()
758
759     def efface_node(self):
760         if self.displayed != 0:
761            self.label.unbind("<1>", self.select_id)
762            self.label.unbind("<3>", self.popup_id)
763            self.label.unbind("<Enter>",self.enter_id)
764            self.label.unbind("<Leave>",self.leave_id)
765            self.canvas.tag_unbind(self.image_id,"<1>",self.select_id2)
766            self.canvas.tag_unbind(self.image_id,"<3>",self.popup_id2)
767            if self.item.IsExpandable():
768               self.canvas.tag_unbind(self.icone_id, "<1>", self.callback_id)
769            self.label.destroy()
770            self.text.destroy()
771
772         for id in self.id :
773             self.canvas.delete(id)
774         self.id=[]
775         self.label_id=None
776         self.text_id=None
777         self.image_id=None
778         self.icone_id=None
779         self.label=None
780         self.text=None
781         self.displayed=0
782
783     def efface(self):
784         """ Efface du canvas les id associés à self : cad les siens et ceux
785             de ses enfants """
786         self.efface_node()
787         if not self.children : return
788         for child in self.children:
789             child.efface()
790
791     def move(self,dy):
792         """ Déplace de l'incrément dy tous les id en dessous de self """
793         # il faut marquer tous les suivants de self
794         bbox1 = self.canvas.bbox(ALL)
795         self.canvas.dtag(ALL,'move')
796         self.canvas.delete('line')
797         try:
798             self.canvas.addtag_overlapping('move',bbox1[0],self.y +10,bbox1[2],bbox1[3])
799         except:
800             print "Erreur dans move :"
801             print self
802             print self.item
803             print self.item.getObject()
804             print self.item.getObject().definition.label
805             print 'y=',self.y
806             print 'dy=',dy
807         # on déplace tous les items de dy
808         self.canvas.move('move',0,dy)
809
810     def trace_ligne(self):
811         """ Dessine les lignes verticales entre frères et entre père et premier fils"""
812         if self.state=='collapsed' : return
813         if len(self.children)==0 : return
814         # on est bien dans le cas d'un noeud expansé avec enfants ...
815         # il faut rechercher l'ordonnée du dernier fils de self
816         y_end = self.children[-1].y
817         ligne = self.canvas.create_line(self.x+15,self.y,self.x+15,y_end,tags='line')
818         self.canvas.tag_lower(ligne)
819         for child in self.children :
820             try:
821                 child.trace_ligne()
822             except:
823                 print "Erreur dans trace_ligne :"
824                 print child
825                 print child.item.getObject()
826
827     def last_child(self):
828         lchild=self
829         if self.state == 'expanded' and self.children:
830            lchild= self.children[-1].last_child()
831         return lchild
832
833     #------------------------------------------------------------------
834     # Méthodes de création et destruction de noeuds
835     # Certaines de ces méthodes peuvent être appelées depuis l'externe
836     #------------------------------------------------------------------
837     def append_brother(self,name,pos='after',retour='non'):
838         """
839         Permet d'ajouter un objet frère à l'objet associé au noeud self
840         par défaut on l'ajoute immédiatement après 
841         Méthode externe
842         """
843         # on veut ajouter le frère de nom name directement avant ou après self
844         index = self.parent.children.index(self)
845         if pos == 'before':
846             index = index
847         elif pos == 'after':
848             index = index +1
849         else:
850             print str(pos)," n'est pas un index valide pour append_brother"
851             return 0
852         return self.parent.append_child(name,pos=index)
853
854     def append_child(self,name,pos=None,verif='oui',retour='non'):
855         """
856            Methode pour ajouter un objet fils à l'objet associé au noeud self.
857            On peut l'ajouter en début de liste (pos='first'), en fin (pos='last')
858            ou en position intermédiaire.
859            Si pos vaut None, on le place à la position du catalogue.
860         """
861         #print "append_child",self,self.children
862         if pos == 'first':
863             index = 0
864         elif pos == 'last':
865             index = len(self.children)
866         elif type(pos) == types.IntType :
867             # position fixee
868             index = pos
869         elif type(pos) == types.InstanceType:
870             # pos est un item. Il faut inserer name apres pos
871             index = self.item.get_index(pos) +1
872         elif type(name) == types.InstanceType:
873             index = self.item.get_index_child(name.nom)
874         else:
875             index = self.item.get_index_child(name)
876         obj=self.item.additem(name,index)
877         #print obj
878         if obj is None:obj=0
879         if obj == 0:return 0
880         #print "append_child",index,self.children
881         child=self.children[index]
882         child.select()
883         return child
884
885     def delete(self):
886         """ 
887             Méthode externe pour la destruction de l'objet associé au noeud
888             La mise à jour des noeuds est faite par onSupp sur notification
889         """
890         index = self.parent.children.index(self) - 1 
891         if index < 0 : index =0
892
893         parent=self.parent
894         ret=parent.item.suppitem(self.item)
895         if ret == 0:return
896
897         brothers=parent.children
898         if brothers:
899            toselect=brothers[index]
900         else:
901            toselect=parent
902         toselect.select()
903