Salome HOME
CCAR: corrections diverses dans le cas d'insertion d'un include avec concepts de
[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.21 2005/05/19 12:18:48 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.canvas.bind("<Key-Prior>", self.page_up)
42         self.canvas.bind("<Key-Next>", self.page_down)
43         self.canvas.bind("<Key-Up>", self.unit_up)
44         self.canvas.bind("<Key-Down>", self.unit_down)             
45         self.canvas.bind("<Key-Left>", self.mot_up)
46         self.canvas.bind("<Key-Right>", self.mot_down)
47         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 update_valid(self) :
105         """Cette methode a pour but de mettre a jour la validite du noeud
106            et de propager la demande de mise à jour à son parent
107         """
108         pass
109
110     def resizescrollregion(self):
111         x0,y0,x1,y1=self.canvas.bbox(ALL)
112         # On ajoute une marge approximativement de la moitié du canvas
113         y1=y1+self.canvas.winfo_height()/2
114         self.canvas.configure(scrollregion = (x0,y0,x1,y1))
115
116     def select_next(self,event):
117         self.node_selected.select_next()
118         self.canvas.focus_set()
119
120     def select_previous(self,event):
121         self.node_selected.select_previous()
122
123     def full_creation(self,name,index):
124         raise "OBSOLETE"
125         # A changer lorsqu'il y aura plusieurs jdc ouverts en même temps
126         self.children[0].full_creation(name,index)
127
128     def verif_all(self):
129         raise "OBSOLETE"
130         traceback.print_stack()
131         for child in self.children :
132             self.verif_all_children()
133
134     def see(self,items):
135         x1, y1, x2, y2=apply(self.canvas.bbox, items)
136         while x2 > self.canvas.canvasx(0)+self.canvas.winfo_width():
137             old=self.canvas.canvasx(0)
138             self.canvas.xview_scroll( 1, 'units')
139             # avoid endless loop if we can't scroll
140             if old == self.canvas.canvasx(0):
141                 break
142         while y2 > self.canvas.canvasy(0)+self.canvas.winfo_height():
143             old=self.canvas.canvasy(0)
144             self.canvas.yview_scroll( 1, 'units')
145             if old == self.canvas.canvasy(0):
146                 break
147         # done in this order to ensure upper-left of object is visible
148         while x1 < self.canvas.canvasx(0):
149             old=self.canvas.canvasx(0)
150             self.canvas.xview_scroll( -1, 'units')
151             if old == self.canvas.canvasx(0):
152                 break
153         while y1 < self.canvas.canvasy(0):
154             old=self.canvas.canvasy(0)
155             self.canvas.yview_scroll( -1, 'units')
156             if old == self.canvas.canvasy(0):
157                 break
158             
159 class Node :
160     def __init__(self,parent,item,command=None,rmenu=None):
161         self.parent = parent
162         self.item = item
163         self.connections=[]
164         self.connect()
165
166         self.command = command
167         self.rmenu=rmenu
168         self.tree = self.parent.tree
169         self.appli = self.parent.appli
170         self.canvas = self.parent.canvas
171         self.init()
172
173     def init(self):
174         self.state='collapsed'
175         self.displayed = 0
176         self.selected = 0
177         self.x = self.y  =None
178         self.lasty = 0
179         self.children = None
180         self.id = []
181         if self.parent is self.tree:
182            self.racine=self
183         else:
184            self.racine = self.parent.racine
185            
186         # etape = noeud d'étape auquel appartient self
187         # = self si c'est lui-même
188         #if isinstance(self.parent,Tree) :
189             # on est  sur un noeud de JDC
190             #self.etape=None
191         #elif isinstance(self.parent.parent,Tree) :
192             # on est sur un noeud d'étape
193             #self.etape=self
194         #else :
195             # on est sur un noeud de mot-clé
196             #self.etape=self.parent.etape
197
198     def reconnect(self):
199         self.disconnect()
200         self.connect()
201
202     def connect(self):
203         self.connections.append(self.item._object)
204         CONNECTOR.Connect(self.item._object,"add",self.onAdd,())
205         CONNECTOR.Connect(self.item._object,"supp",self.onSupp,())
206         CONNECTOR.Connect(self.item._object,"valid",self.onValid,())
207         if self.item.object is not self.item._object:
208            CONNECTOR.Connect(self.item.object,"add",self.onAdd,())
209            CONNECTOR.Connect(self.item.object,"supp",self.onSupp,())
210            CONNECTOR.Connect(self.item.object,"valid",self.onValid,())
211            self.connections.append(self.item.object)
212
213     def disconnect(self):
214         for c in self.connections:
215            CONNECTOR.Disconnect(c,"add",self.onAdd,())
216            CONNECTOR.Disconnect(c,"supp",self.onSupp,())
217            CONNECTOR.Disconnect(c,"valid",self.onValid,())
218         self.connections=[]
219
220     def __del__(self):
221         """ appele a la destruction du noeud """
222         #print "NOEUD DETRUIT",self,self.item.GetLabelText()[0]
223
224     def force_select(self):
225         if self.selected:
226            # le noeud est selectionné. On force la reconstruction du panel associé
227            if self.command:apply(self.command,(None,))
228            self.select()
229
230     def onValid(self):
231         #print "onValid : l'item a changé de validité ",self.item,self.item.object,self.item.object.isvalid()
232         self.update_node_valid()
233         self.update_label_texte()
234         self.update_texte()
235
236     def onAdd(self,objet):
237         #print "onAdd : un objet a été ajouté aux fils de l'item ",self.item.object,objet
238         self.expand_node()
239         old_nodes=self.children
240         self.update_nodes()
241         #print "onAdd:nodes",self.children
242         self.redraw_children(old_nodes)
243         self.force_select()
244
245     def onSupp(self,objet):
246         #print "onSupp : un objet a été supprimé des fils de l'item ",self.item.object,objet
247         self.expand_node()
248         old_nodes=self.children
249         self.update_nodes()
250         #print "onSupp:nodes",self.children
251         self.redraw_children(old_nodes)
252         self.force_select()
253
254     def update_nodes(self):
255         #print "update_nodes",self
256         newnodes=[]
257         inodes=iter(self.children)
258         sublist=self.item._GetSubList()
259         iliste=iter(sublist)
260         #print "update_nodes",self.children
261         #print "update_nodes",sublist
262
263         while(1):
264            old_item=item=None
265            for node in inodes:
266               old_item=node.item
267               if old_item in sublist:break
268               #print "item supprime",old_item
269            for item in iliste:
270               if item is old_item:break
271               #print "item ajoute",item
272               child = item.itemNode(self,item,self.command,self.rmenu)
273               newnodes.append(child)
274
275            if old_item is None and item is None:break
276            if old_item is item:
277               #print "item conserve",item
278               newnodes.append(node)
279
280         self.children=newnodes
281         self.reconnect()
282
283     def supprime(self):
284         self.disconnect()
285         self.efface_node()
286
287         #self.label_id=None
288         #self.text_id=None
289         #self.label=None
290         #self.text=None
291         #self.image_id=None
292         #self.icone_id=None
293         #self.etape=None
294         ####self.parent=None
295         #self.command = None
296         #self.rmenu=None
297         #self.tree = None
298         #self.appli=None
299         #self.canvas = None
300
301         if not self.children : return
302         for child in self.children:
303             child.supprime()
304         self.children=None
305
306     def redraw_children(self,old_nodes):
307         #print "redraw_children",old_nodes
308         #print self.children
309         y = self.y + 20
310         x = self.x + 15
311         supp_nodes=[]
312
313         inodes=iter(old_nodes)
314         iliste=iter(self.children)
315         # on parcourt la liste des anciens noeuds (node)
316         # et la liste des nouveaux noeuds (new_node) en parallele (iterateurs)
317
318         while(1):
319            new_node=node=None
320            for node in inodes:
321               #print "ancien noeud",node
322               if node in self.children:break # ancien noeud toujours present
323               #print "noeud supprime",node,node.item.GetLabelText()[0]
324               dy=node.y-node.lasty -20
325               #print "deplacer noeuds",y,dy
326               node.move_nodes(y,dy)
327               node.supprime()
328               #supp_nodes.append(node)
329
330            for new_node in iliste:
331               #print "nouveau noeud",new_node
332               if new_node in old_nodes: break # nouveau noeud deja present
333               #print "noeud ajoute",new_node,new_node.item.GetLabelText()[0]
334               y=self.draw_node(new_node,x,y)
335
336            if node is None and new_node is None : break
337
338            if node is new_node: # ancien noeud
339               #print "noeud conserve",node
340               node.update_label_texte()
341               y=y+node.lasty-node.y +20
342
343         self.racine.update_coords()
344         self.canvas.delete('line')
345         self.racine.trace_ligne()
346         self.tree.resizescrollregion()
347         # Mettre à 1 pour verifier les cycles entre objets node
348         #withCyclops=0
349         #if withCyclops:
350            #from Misc import Cyclops
351            #z = Cyclops.CycleFinder()
352            #print supp_nodes
353            #for o in supp_nodes:
354              #z.register(o)
355            #del supp_nodes
356            #del o
357            #z.find_cycles()
358            #z.show_stats()
359            #z.show_cycles()
360
361     def tag_move_nodes(self,y):
362         """ Marque pour deplacement tous les noeuds au dela de l'ordonnée y """
363         self.canvas.dtag(ALL,'move')
364         # on marque tous les ids au dela de y
365         x0, y0, x1, y1 = self.canvas.bbox(ALL)
366         self.canvas.addtag_overlapping('move',x0,y,x1,y1)
367
368     def move_nodes(self,y,dy):
369         """ Déplace de l'incrément dy les noeuds au dela de l'ordonnée y """
370         self.tag_move_nodes(y)
371         # on déplace tous les items de dy
372         self.canvas.move('move',0,dy)
373
374     def draw_node(self,new_node,x,y):
375         """ Dessine le noeud new_node en x,y en deplacant les noeuds existants
376             en y et au dela
377             Retourne la position du premier des noeuds deplaces
378         """
379         self.tag_move_nodes(y)
380         #if new_node.item.isactif():
381            #new_node.state = 'expanded'
382         new_node.state = 'expanded'
383         new_node.draw(x,y)
384         dy=(new_node.get_nb_children()+1)*20
385         #print "deplacer noeuds",y,dy
386         self.canvas.move('move',0,dy)
387         return new_node.lasty+20
388
389     def build_children(self):
390         """ Construit la liste des enfants de self """
391         self.children = []
392         sublist = self.item._GetSubList()
393         if not sublist : return
394         for item in sublist :
395             child = item.itemNode(self,item,self.command,self.rmenu)
396             self.children.append(child)
397             
398     #-----------------------------------------------
399     # Méthodes de sélection/déselection d'un noeud
400     #-----------------------------------------------
401     
402     def select(self, event=None):
403         """
404         Rend le noeud courant (self) sélectionné et déselectionne
405         tous les autres
406         """
407         #print "SELECT",self
408         #traceback.print_stack()
409         if not self.children : self.build_children()
410         #if self.selected and self.tree.node_selected is self: return
411         self.tree.deselectall()
412         self.selected = 1
413         self.tree.node_selected = self
414         if self.command:apply(self.command,(self,))
415         self.highlight()
416         self.make_visible()
417
418     def deselect(self, event=None):
419         """ Déselectionne self """
420         self.selected = 0
421         if self.displayed == 1 : self.dehighlight()
422             
423     def make_visible(self):
424         """ Rend l'objet self visible cad déplace le scroll pour que self soit dans
425             la fenêtre de visu
426         """
427         lchild=self.last_child()
428         self.tree.see((self.image_id,lchild.image_id))
429         
430     def select_next(self,ind=0):
431         """ on doit chercher à sélectionner dans l'ordre:
432                 - son premier fils s'il est affiché
433                 - son frère cadet s'il existe
434                 - son oncle (benjamin de son père)
435                 - ... appel récursif ...
436         """
437         if self.state=='expanded' and len(self.children) > ind:
438             self.children[ind].select()
439         else :
440             index = self.parent.children.index(self) + 1
441             try :
442               if isinstance(self.parent,TREE) :
443                 try:
444                     self.children[ind].select()
445                 except:
446                     self.children[0].select()
447               else :                
448                 self.parent.select_next(index)
449             except :
450                 self.parent.select_next(index)
451
452     def select_mot_previous(self):
453         index = self.parent.children.index(self) - 1
454         try :
455             if index > 0  :
456                self.parent.children[index].select()
457             else :
458                self.parent.select()
459         except:
460             self.parent.select()
461
462     def select_previous(self):
463         """ on doit d'abord sélectionner(dans l'ordre) :
464              - son frère aîné
465              - son père
466         """
467         index = self.parent.children.index(self) + 1
468         try :
469             self.parent.children[index].select()
470         except:
471             self.parent.select()
472
473     def popup(self,event=None):
474         """
475             Declenche le traitement associé au clic droit de la souris
476             sur l'icone du Node
477         """
478         if not self.rmenu:return
479         apply(self.rmenu,(self,event))
480
481     #-----------------------------------------------
482     # Méthodes de recherche d'informations
483     #-----------------------------------------------
484     def geticonimage(self,name=None):
485         """
486         Retourne l'image qui doit être associée à self
487         """
488         if not name :
489             name = self.item.GetIconName()
490         if not name or name == 'aucune' :
491             return None
492         return images.get_image(name)
493
494     def get_nb_children(self):
495         """ Retourne le nombre d'enfants affichés de self """
496         nb = 0
497         if self.state =='collapsed' :  return nb
498         for child in self.children :
499             nb = nb + 1 + child.get_nb_children()
500         return nb
501
502     def get_liste_id(self):
503         """ Retourne la liste de tous les id (filiation comprise) de self """
504         liste = self.id
505         for child in self.children:
506             liste.extend(child.get_liste_id())
507         return liste
508
509     def get_node_fils(self,name) :
510         """ Retourne le fils de self de nom name s'il existe"""
511         for child in self.children:
512             if child.item.get_nom() == name: return child
513         return None
514
515     #-----------------------------------------------
516     # Méthodes d'affichage d'un noeud
517     #-----------------------------------------------
518     def draw(self,x,y):
519         """ Permet de tracer le noeud self """
520         # le début du noeud est en x,y
521         self.x = x
522         self.y = y
523         self.lasty = y
524         self.displayed = 1
525         self.id=[]
526         # choix de l'icone à afficher : + ou -
527         if self.item.IsExpandable():
528             if self.state == 'expanded':
529                 iconname = "minusnode"
530                 callback = self.collapse
531             else:
532                 iconname = "plusnode"
533                 callback = self.expand
534             image = self.geticonimage(name=iconname)
535             self.icone_id = self.canvas.create_image(self.x, self.y, image=image)
536             self.callback_id=self.canvas.tag_bind(self.icone_id, "<1>", callback)
537             self.id.append(self.icone_id)
538         # création de la ligne horizontale
539         self.ligne_id = self.canvas.create_line(self.x,self.y,self.x+10,self.y)
540         self.id.append(self.ligne_id)
541         self.canvas.tag_lower(self.ligne_id)
542         # affichage de l'icone (carre ,rond, ovale ...) de couleur
543         image = self.geticonimage()
544         if image != None :
545             self.image_id = self.canvas.create_image(self.x+15,self.y,image = image)
546             self.select_id2=self.canvas.tag_bind(self.image_id,"<1>",self.select)
547             self.popup_id2=self.canvas.tag_bind(self.image_id,"<3>",self.popup)
548             self.id.append(self.image_id)
549         else:
550             self.image_id = None
551         # affichage du texte : nom de l'objet (ETAPE ou MOT-CLE) et sa valeur
552         self.drawtext()
553         if self.state == 'expanded' :
554             if not self.children : self.build_children()
555             if len(self.children) > 0:
556                 self.drawchildren()
557                 self.lasty = self.children[-1].lasty
558    
559     def drawchildren(self):
560         """ Dessine les enfants de self """
561         y = self.y + 20
562         x = self.x + 15
563         for child in self.children:
564             child.draw(x,y)
565             nb = child.get_nb_children()
566             y = y + 20*(nb+1)
567         self.trace_ligne()
568
569     def drawtext(self):
570         """ Affiche les deux zones de texte après l'icône de couleur de l'objet """
571         if self.image_id != None :
572             textx = self.x + 30
573         else:
574             textx = self.x + 15
575         texty = self.y
576         # nom,fonte et couleur de l'objet du noeud à afficher
577         labeltext,fonte,couleur = self.item.GetLabelText()
578         if labeltext    == ''   : labeltext = '   '
579         if fonte        == None : fonte = Fonte_Standard
580         if couleur      == None : couleur = 'black'
581         # création du widget label
582         self.label = Label(self.canvas,
583                            text = labeltext,
584                            fg = couleur,
585                            bg = 'gray95',
586                            font=fonte)
587         self.label_id = self.canvas.create_window(textx,texty,window=self.label,anchor='w')
588         self.id.append(self.label_id)
589         # bindings sur le widget label
590         self.select_id=self.label.bind("<1>", self.select)
591         self.popup_id=self.label.bind("<3>", self.popup)
592         self.enter_id=self.label.bind("<Enter>",self.enter)
593         self.leave_id=self.label.bind("<Leave>",self.leave)
594         # valeur de cet objet à afficher
595         x0, y0, x1, y1 = self.canvas.bbox(self.label_id)
596         textx = max(x1, 200) + 10
597         text = self.item.GetText() or " "
598         self.text = Label(self.canvas, text=text,
599                             bd=0, padx=2, pady=2,background='gray95',
600                             font=fonte)
601         if self.selected:
602             self.highlight()
603         else:
604             self.dehighlight()
605         self.text_id = self.canvas.create_window(textx, texty,anchor="w", window=self.text)
606         self.id.append(self.text_id)
607         
608     def highlight(self,event=None):
609         """ Met en surbrillance self"""
610         if hasattr(self,'label'):
611             self.label.configure(fg='white',bg='#00008b')
612             
613     def dehighlight(self,event=None):
614         """ Rétablit l'affichage normal de self"""
615         if hasattr(self,'label'):
616             self.label.configure(fg='black',bg='gray95')
617
618     def enter(self,event=None):
619         """ Met en surbrillance self et affiche le fr de l'objet """
620         self.highlight()
621         fr = self.item.get_fr()
622         self.appli.affiche_infos(fr)
623         
624     def leave(self,event=None):
625         """ Rétablit l'affichage normal de self et efface le fr de l'objet """
626         if not self.selected :
627             self.dehighlight()
628         self.appli.affiche_infos('')
629
630     def collapse_children(self):
631         """ Collapse récursivement tous les descendants de self """
632         if not self.children : return
633         for child in self.children:
634             child.state='collapsed'
635             child.collapse_children()
636             
637     def collapse(self,event = None):
638         """ Collapse self et descendants et retrace self """
639         nb = self.get_nb_children()
640         self.state = 'collapsed'
641         self.collapse_children()
642         self.redraw(-nb)
643         self.select()
644    
645     def expand_node(self,event = None):
646         """ Expanse self et le retrace """
647         if self.state == 'expanded':return
648         #if not self.item.isactif() : return
649         if not self.children : self.build_children()
650         self.state = 'expanded'
651         nb = self.get_nb_children()
652         self.redraw(nb)
653
654     def expand(self,event = None):
655         """ Expanse self et le retrace """
656         self.expand_node()
657         self.select()
658
659     def redraw(self,nb):
660         """ Redessine self :  nb est le décalage à introduire
661             en dessous de self pour le redessiner """
662         # nb = nombre d'items de décalage
663         self.move(20*nb)
664         # on efface self et on le redessine
665         self.efface()
666         self.draw(self.x,self.y)
667         # Il n'est pas nécessaire d'appeler update
668         # il suffit d'updater les coordonnees et de retracer les lignes
669         self.racine.update_coords()
670         self.racine.trace_ligne()
671         self.update_valid()
672         self.tree.resizescrollregion()
673         
674     def update_coords(self):
675         """ Permet d'updater les coordonnes de self et de tous ses enfants"""
676         if self.displayed == 0 : return
677         if self.image_id != None :
678             coords = self.canvas.coords(self.image_id)
679             self.x = coords[0]-15
680         else:
681             coords = self.canvas.coords(self.label_id)
682             self.x = coords[0]-15
683         self.y = coords[1]
684         self.lasty = self.y
685         if self.state == 'expanded' :
686             for child in self.children:
687                 if child.displayed != 0:
688                     child.update_coords()
689                     self.lasty = child.lasty
690
691     def update_icone(self):
692         """ Met à jour les icônes de tous les noeuds : teste la validité de l'objet
693         Cette méthode est très lente, trop !!"""
694         if self.image_id != None :
695             image = self.geticonimage()
696             self.canvas.itemconfig(self.image_id,image=image)
697         if self.state == 'expanded':
698             for child in self.children:
699                 if child.displayed != 0:
700                     child.update_icone()
701
702     def update_label_texte(self):
703         # nom,fonte et couleur de l'objet du noeud à afficher
704         labeltext,fonte,couleur = self.item.GetLabelText()
705         if labeltext    == ''   : labeltext = '   '
706         if fonte        == None : fonte = Fonte_Standard
707         if couleur      == None : couleur = 'black'
708         self.label.configure(text=labeltext,font=fonte)
709         if self.state == 'expanded' :
710             for child in self.children:
711                 if child.displayed != 0 : child.update_label_texte()
712
713     def update_texte(self):
714         """ Met à jour les noms des SD et valeurs des mots-clés """
715         text = self.item.GetText()
716         if text == None : text = ''
717         self.text.configure(text=text)
718         if self.state == 'expanded' :
719             for child in self.children:
720                 if child.displayed != 0 : child.update_texte()
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.image_id != None :
727             image = self.geticonimage()
728             self.canvas.itemconfig(self.image_id,image=image)
729
730     def update_valid(self) :
731         """Cette methode a pour but de mettre a jour la validite du noeud
732            et de propager la demande de mise à jour à son parent
733         """
734         self.update_node_valid()
735         self.parent.update_valid()
736
737     def update(self,event=None) :
738         """ Classe Node :
739             Cette méthode est appelée pour demander l update d un noeud 
740             d'un jeu de commandes
741             Cette demande est transmise au noeud racine (le JDC) qui update
742             tout l arbre représentant le jeu de commandes
743             Pendant cette mise à jour, on appelle la méthode isvalid qui
744             fera l update de tous les objets déclarés modifiés lors des
745             actions précédentes
746             La métode isvalid est en général appelée par l intermédiaire de
747             update_icone -> geticonimage -> GetIconName
748         """
749         #print "update",self
750         #traceback.print_stack()
751         self.racine.update_coords()
752         self.racine.trace_ligne()
753         self.racine.update_icone()
754         self.racine.update_texte()
755         self.tree.resizescrollregion()
756
757     def efface_node(self):
758         if self.displayed != 0:
759            self.label.unbind("<1>", self.select_id)
760            self.label.unbind("<3>", self.popup_id)
761            self.label.unbind("<Enter>",self.enter_id)
762            self.label.unbind("<Leave>",self.leave_id)
763            self.canvas.tag_unbind(self.image_id,"<1>",self.select_id2)
764            self.canvas.tag_unbind(self.image_id,"<3>",self.popup_id2)
765            if self.item.IsExpandable():
766               self.canvas.tag_unbind(self.icone_id, "<1>", self.callback_id)
767            self.label.destroy()
768            self.text.destroy()
769
770         for id in self.id :
771             self.canvas.delete(id)
772         self.id=[]
773         self.label_id=None
774         self.text_id=None
775         self.image_id=None
776         self.icone_id=None
777         self.label=None
778         self.text=None
779         self.displayed=0
780
781     def efface(self):
782         """ Efface du canvas les id associés à self : cad les siens et ceux
783             de ses enfants """
784         self.efface_node()
785         if not self.children : return
786         for child in self.children:
787             child.efface()
788
789     def move(self,dy):
790         """ Déplace de l'incrément dy tous les id en dessous de self """
791         # il faut marquer tous les suivants de self
792         bbox1 = self.canvas.bbox(ALL)
793         self.canvas.dtag(ALL,'move')
794         self.canvas.delete('line')
795         try:
796             self.canvas.addtag_overlapping('move',bbox1[0],self.y +10,bbox1[2],bbox1[3])
797         except:
798             print "Erreur dans move :"
799             print self
800             print self.item
801             print self.item.getObject()
802             print self.item.getObject().definition.label
803             print 'y=',self.y
804             print 'dy=',dy
805         # on déplace tous les items de dy
806         self.canvas.move('move',0,dy)
807
808     def trace_ligne(self):
809         """ Dessine les lignes verticales entre frères et entre père et premier fils"""
810         if self.state=='collapsed' : return
811         if len(self.children)==0 : return
812         # on est bien dans le cas d'un noeud expansé avec enfants ...
813         # il faut rechercher l'ordonnée du dernier fils de self
814         y_end = self.children[-1].y
815         ligne = self.canvas.create_line(self.x+15,self.y,self.x+15,y_end,tags='line')
816         self.canvas.tag_lower(ligne)
817         for child in self.children :
818             try:
819                 child.trace_ligne()
820             except:
821                 print "Erreur dans trace_ligne :"
822                 print child
823                 print child.item.getObject()
824
825     def last_child(self):
826         lchild=self
827         if self.state == 'expanded' and self.children:
828            lchild= self.children[-1].last_child()
829         return lchild
830
831     #------------------------------------------------------------------
832     # Méthodes de création et destruction de noeuds
833     # Certaines de ces méthodes peuvent être appelées depuis l'externe
834     #------------------------------------------------------------------
835     def replace_node(self,node1,node2):
836         """ Remplace le noeud 1 par le noeud 2 dans la liste des enfants de self"""
837         raise "OBSOLETE"
838         index= self.children.index(node1)
839         self.delete_node_child(node1)
840         self.children.insert(index,node2)
841         
842     def replace_enfant(self,item):
843         """ Retourne le noeud fils à éventuellement remplacer """
844         raise "OBSOLETE"
845         return self.get_node_fils(item.get_nom())
846
847     def full_creation(self,name,pos=None):
848         """
849             Interface avec ACCAS : création de l'objet de nom name et
850             du noeud associé. Retourne le noeud fils ainsi créé
851         """
852         raise "OBSOLETE"
853         #print "full_creation",name,pos,self.item
854         item = self.item.additem(name,pos)
855         if item == None or item == 0:
856             # impossible d'ajouter le noeud de nom : name
857             return 0
858
859         enfant = self.replace_enfant(item)
860         if enfant :
861             # un fils de même nom existe déjà : on le remplace
862             child = item.itemNode(self,item,self.command,self.rmenu)
863             self.replace_node(enfant,child)
864         else :            
865             child = item.itemNode(self, item,self.command,self.rmenu)
866             if pos is None:
867                 self.children.append(child)
868             else :
869                 self.children.insert(pos,child)
870         return child
871
872     def append_brother_BAK(self,name,pos='after',retour='non'):
873         """
874         Permet d'ajouter un frère à self
875         par défaut on l'ajoute après self
876         Méthode externe
877         """
878         raise "OBSOLETE"
879         # on veut ajouter le frère de nom name directement avant ou après self
880         index = self.parent.children.index(self)
881         if pos == 'before':
882             index = index
883         elif pos == 'after':
884             index = index +1
885         else:
886             print str(pos)," n'est pas un index valide pour append_brother"
887             return
888         return self.parent.append_child(name,pos=index,retour=retour)
889     
890     def append_node_child(self,fils,pos=None,verif='oui'):
891         """
892         Fait appel à la création complète de fils et à la vérification
893         des conditions en fonction du contexte
894         Attention : fils peut être un nom ou déjà un object (cas d'une copie)
895         """
896         raise "OBSOLETE"
897         if not self.children : self.build_children()
898         if pos == None :
899             if type(fils) == types.InstanceType:
900                 pos = self.item.get_index_child(fils.nom)
901             else:
902                 pos = self.item.get_index_child(fils)
903         child = self.full_creation(fils,pos)
904         if child == 0 :
905             # on n'a pas pu créer le noeud fils
906             return 0
907         self.state = 'expanded'
908         child.displayed = 1
909         if child.item.isactif():
910            child.state = 'expanded'
911         if not child.children : child.build_children()
912         if verif == 'oui':
913            child.verif_condition()
914            self.verif_condition()
915         return child
916             
917     def append_brother(self,name,pos='after',retour='non'):
918         """
919         Permet d'ajouter un objet frère à l'objet associé au noeud self
920         par défaut on l'ajoute immédiatement après 
921         Méthode externe
922         """
923         # on veut ajouter le frère de nom name directement avant ou après self
924         index = self.parent.children.index(self)
925         if pos == 'before':
926             index = index
927         elif pos == 'after':
928             index = index +1
929         else:
930             print str(pos)," n'est pas un index valide pour append_brother"
931             return 0
932         return self.parent.append_child(name,pos=index)
933
934     def append_child(self,name,pos=None,verif='oui',retour='non'):
935         """
936            Methode pour ajouter un objet fils à l'objet associé au noeud self.
937            On peut l'ajouter en début de liste (pos='first'), en fin (pos='last')
938            ou en position intermédiaire.
939            Si pos vaut None, on le place à la position du catalogue.
940         """
941         #print "append_child",self,self.children
942         if pos == 'first':
943             index = 0
944         elif pos == 'last':
945             index = len(self.children)
946         elif type(pos) == types.IntType :
947             # position fixee
948             index = pos
949         elif type(pos) == types.InstanceType:
950             # pos est un item. Il faut inserer name apres pos
951             index = self.item.get_index(pos) +1
952         elif type(name) == types.InstanceType:
953             index = self.item.get_index_child(name.nom)
954         else:
955             index = self.item.get_index_child(name)
956         obj=self.item.additem(name,index)
957         #print obj
958         if obj is None:obj=0
959         if obj == 0:return 0
960         #print "append_child",index,self.children
961         child=self.children[index]
962         child.select()
963         return child
964
965     def append_child_BAK(self,name,pos=None,verif='oui',retour='non'):
966         """
967         Permet d'ajouter un fils à self
968         on peut l'ajouter en fin de liste (défaut) ou en début
969         Méthode externe
970         """
971         raise "OBSOLETE"
972         if pos == 'first':
973             index = 0
974         elif pos == 'last':
975             index = len(self.children)
976         elif pos != None and type(pos) == types.IntType :
977             # on donne la position depuis l'extérieur
978             # (appel de append_child par append_brother par exemple)
979             index = pos
980         elif type(pos) == types.InstanceType:
981             # pos est un item. Il faut inserer name apres pos
982             index = self.item.get_index(pos) +1
983         else :
984             if type(name) == types.InstanceType:
985                 index = self.item.get_index_child(name.nom)
986             else:
987                 index = self.item.get_index_child(name)
988         nbold = self.get_nb_children()
989         self.state='expanded'
990         child = self.append_node_child(name,pos=index)
991         if child == 0 :
992             # on n'a pas pu créer le fils
993             return 0
994         nbnew = self.get_nb_children()
995         self.redraw(nbnew-nbold)
996         child.select()
997         if retour == 'oui': return child
998
999     def delete_node_child_BAK(self,child):
1000         """ Supprime child des enfants de self et les id associés """
1001         raise "OBSOLETE"
1002         child.efface()
1003         self.children.remove(child)
1004         self.canvas.update()
1005         
1006     def delete_child_BAK(self,child):
1007         """ 
1008             Supprime child des enfants de self, tous les id associés
1009             ET l'objet associé 
1010         """
1011         raise "OBSOLETE"
1012         if self.item.suppitem(child.item):
1013             self.delete_node_child(child)
1014             return 1
1015         else :
1016             return 0
1017                     
1018     def delete(self):
1019         """ 
1020             Méthode externe pour la destruction de l'objet associé au noeud
1021             La mise à jour des noeuds est faite par onSupp sur notification
1022         """
1023         index = self.parent.children.index(self) - 1 
1024         if index < 0 : index =0
1025         #print index
1026
1027         ret=self.parent.item.suppitem(self.item)
1028         if ret == 0:return
1029
1030         brothers=self.parent.children
1031         if brothers:
1032            toselect=brothers[index]
1033         else:
1034            toselect=self.parent
1035         toselect.select()
1036
1037     def delete_BAK(self):
1038         """ Méthode externe pour la destruction du noeud ET de l'objet
1039             Gère l'update du canvas"""
1040         raise "OBSOLETE"
1041         pere = self.parent
1042         nbold = pere.get_nb_children()
1043
1044         if self.parent.children.index(self) > 0 :
1045             index = self.parent.children.index(self) - 1 
1046         else:
1047             index=0
1048         if self.parent.delete_child(self):
1049             if self.item.get_position() == 'global':
1050                 self.etape.verif_all()
1051             elif self.item.get_position() == 'global_jdc':
1052                 self.racine.verif_all()
1053             else:
1054                 self.parent.verif_condition()
1055         else:
1056             print 'Erreur dans la destruction de ',self.item.get_nom(),' dans delete'
1057
1058         nbnew = pere.get_nb_children()
1059         pere.redraw(nbnew-nbold)
1060
1061         # Le noeud n'est pas au 1er niveau
1062         if  pere.parent.parent != None:
1063             pere.select()
1064         else:
1065             enfants = self.parent.children
1066             try:
1067               enfants[index].select()
1068             except :
1069               try :
1070                 enfants[index+1].select()
1071               except :
1072                 # on est avant debut
1073                 pass
1074
1075     def doPaste(self,node_selected):
1076         self.appli.message="Vous ne pouvez copier que des commandes ou des mots-clés facteurs !"
1077         return 0
1078
1079     def doPaste_Commande(self,objet_a_copier):
1080         """
1081         Réalise la copie de l'objet passé en argument qui est nécessairement
1082         une commande
1083         """
1084         raise "OBSOLETE"
1085         child = self.append_brother(objet_a_copier,retour='oui')
1086         return child
1087
1088     #--------------------------------------------------------------
1089     # Méthodes de vérification du contexte et de validité du noeud
1090     #--------------------------------------------------------------
1091     def verif_all(self):
1092         raise "OBSOLETE"
1093         traceback.print_stack()
1094         self.verif_all_children()
1095             
1096     def verif_all_children(self):
1097         raise "OBSOLETE"
1098         traceback.print_stack()
1099         if not self.children : self.build_children()
1100         self.verif()
1101         for child in self.children :
1102             child.verif_all_children()
1103
1104     def verif(self) :
1105         """ 
1106             Lance la vérification des conditions des blocs de self et le cas
1107             échéant redessine self 
1108         """
1109         raise "OBSOLETE"
1110         traceback.print_stack()
1111         nbold = self.get_nb_children()
1112         test = self.verif_condition()
1113         nbnew = self.get_nb_children()
1114         if test != 0 :
1115             self.redraw(nbnew-nbold)
1116
1117     def verif_condition(self):
1118         """
1119         on lance la vérification des conditions de chaque bloc de self
1120         on crée ou supprime les noeuds concernés
1121         (self est d'un niveau inférieur ou égal à l'ETAPE)
1122         """
1123         raise "OBSOLETE"
1124         traceback.print_stack()
1125         test = 0
1126         l_bloc_arajouter,l_bloc_aenlever = self.verif_condition_bloc()
1127         if len(l_bloc_arajouter) > 0:
1128             test = 1
1129             for mc in l_bloc_arajouter:
1130                 self.append_node_child(mc,verif='non')
1131         if len(l_bloc_aenlever) > 0:
1132             test = 1
1133             for mc in l_bloc_aenlever:
1134                 mocle = self.get_node_fils(mc)
1135                 self.delete_child(mocle)
1136         l_mc_presents = self.item.get_liste_mc_presents()
1137         l_mc_arajouter= self.verif_condition_regles(l_mc_presents)
1138         if len(l_mc_arajouter) > 0:
1139             test = 1
1140             for mc in l_mc_arajouter:
1141                 self.append_node_child(mc,verif='non')
1142         if len(l_mc_arajouter)+len(l_bloc_arajouter)+len(l_bloc_aenlever) != 0 :
1143             self.verif_condition()
1144         return test
1145         
1146     def verif_condition_bloc(self):
1147         raise "OBSOLETE"
1148         traceback.print_stack()
1149         return self.item.verif_condition_bloc()
1150
1151     def verif_condition_regles(self,l_mc_presents):
1152         raise "OBSOLETE"
1153         traceback.print_stack()
1154         return self.item.verif_condition_regles(l_mc_presents)
1155     
1156