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