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