Salome HOME
*** empty log message ***
[tools/eficas.git] / Editeur / treewidget.py
index e328c1842f95f5a09d750f7291ce2e10aec32bf3..78b3a16c247745cb718a787fb069fc696a8bd61d 100644 (file)
@@ -1,9 +1,22 @@
-#@ MODIF treewidget Editeur  DATE 02/07/2001   AUTEUR D6BHHJP J.P.LEFEBVRE 
+# -*- coding: utf-8 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
-# COPYRIGHT (C) 1991 - 2001  EDF R&D                  WWW.CODE-ASTER.ORG
-#              SEE THE FILE "LICENSE.TERMS" FOR INFORMATION ON USAGE AND
-#              REDISTRIBUTION OF THIS FILE.
+# COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
+# THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
+# IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
+# THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
+# (AT YOUR OPTION) ANY LATER VERSION.
+#
+# THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
+# WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
+# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
+# GENERAL PUBLIC LICENSE FOR MORE DETAILS.
+#
+# YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
+# ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
+#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
+#
+#
 # ======================================================================
 import os,sys,string,re,types,traceback
 from Tkinter import *
@@ -11,16 +24,17 @@ from Tkinter import *
 
 import fontes
 import images
+from Ihm import CONNECTOR
 
 #
 __version__="$Name:  $"
-__Id__="$Id: treewidget.py,v 1.3 2002/04/03 11:35:12 eficas Exp $"
+__Id__="$Id: treewidget.py,v 1.24 2005/06/10 14:59:37 eficas Exp $"
 #
 
 Fonte_Standard = fontes.standard
 
 class Tree :
-    def __init__(self,appli,jdc_item,scrolledcanvas,command = None):
+    def __init__(self,appli,jdc_item,scrolledcanvas,command = None,rmenu=None):
         self.item = jdc_item
         self.scrolledcanvas = scrolledcanvas
         self.canvas = self.scrolledcanvas.component('canvas')
@@ -28,14 +42,21 @@ class Tree :
         self.canvas.bind("<Key-Next>", self.page_down)
         self.canvas.bind("<Key-Up>", self.unit_up)
         self.canvas.bind("<Key-Down>", self.unit_down)             
+        self.canvas.bind("<Key-Left>", self.mot_up)
+        self.canvas.bind("<Key-Right>", self.mot_down)
+        self.canvas.bind("<1>", self.canvas_select)             
         self.tree = self
         self.command = command
+        self.rmenu=rmenu
         self.appli = appli
         self.parent = None
         self.racine = self
         self.node_selected = None
         self.build_children()
 
+    def canvas_select(self,event):
+        self.canvas.focus_set()
+
     def page_up(self,event):
         event.widget.yview_scroll(-1, "page")
     def page_down(self,event):
@@ -45,10 +66,18 @@ class Tree :
     def unit_down(self,event):
         event.widget.yview_scroll(1, "unit")              
 
+    def mot_down(self,event):
+        self.select_next(None)
+        self.canvas.focus_set()
+
+    def mot_up(self,event):
+        self.node_selected.select_mot_previous()
+        self.canvas.focus_set()
+
     def build_children(self):
         """ Construit la liste des enfants de self """
         self.children = []
-        child = Node(self,self.item,self.command)
+        child = self.item.itemNode(self,self.item,self.command,self.rmenu)
         self.children.append(child)
         child.state='expanded'
 
@@ -59,16 +88,9 @@ class Tree :
         for child in self.children:
             child.draw(x,lasty)
             lasty = child.lasty + 15
-            child.trace_ligne()
-        #self.update()
         self.children[0].select()
         self.resizescrollregion()
 
-    def deselectall_old(self):
-        """ déselectionne tous les éléments de l'arbre """
-        for child in self.children:
-            child.deselect()
-
     def deselectall(self):
         """ déselectionne tous les éléments de l'arbre """
         if self.node_selected :
@@ -79,33 +101,79 @@ class Tree :
         for child in self.children:
             child.update()
 
+    def supprime(self):
+        """ supprime tous les éléments de l'arbre """
+        for child in self.children:
+            child.supprime()
+
+    def update_valid(self) :
+        """Cette methode a pour but de mettre a jour la validite du noeud
+           et de propager la demande de mise à jour à son parent
+        """
+        pass
+
     def resizescrollregion(self):
-        self.scrolledcanvas.resizescrollregion()
+        x0,y0,x1,y1=self.canvas.bbox(ALL)
+        # On ajoute une marge approximativement de la moitié du canvas
+        y1=y1+self.canvas.winfo_height()/2
+        self.canvas.configure(scrollregion = (x0,y0,x1,y1))
 
     def select_next(self,event):
         self.node_selected.select_next()
+        self.canvas.focus_set()
 
     def select_previous(self,event):
         self.node_selected.select_previous()
 
     def full_creation(self,name,index):
+        raise "OBSOLETE"
         # A changer lorsqu'il y aura plusieurs jdc ouverts en même temps
         self.children[0].full_creation(name,index)
 
     def verif_all(self):
+        raise "OBSOLETE"
+        traceback.print_stack()
         for child in self.children :
             self.verif_all_children()
+
+    def see(self,items):
+        x1, y1, x2, y2=apply(self.canvas.bbox, items)
+        while x2 > self.canvas.canvasx(0)+self.canvas.winfo_width():
+            old=self.canvas.canvasx(0)
+            self.canvas.xview_scroll( 1, 'units')
+            # avoid endless loop if we can't scroll
+            if old == self.canvas.canvasx(0):
+                break
+        while y2 > self.canvas.canvasy(0)+self.canvas.winfo_height():
+            old=self.canvas.canvasy(0)
+            self.canvas.yview_scroll( 1, 'units')
+            if old == self.canvas.canvasy(0):
+                break
+        # done in this order to ensure upper-left of object is visible
+        while x1 < self.canvas.canvasx(0):
+            old=self.canvas.canvasx(0)
+            self.canvas.xview_scroll( -1, 'units')
+            if old == self.canvas.canvasx(0):
+                break
+        while y1 < self.canvas.canvasy(0):
+            old=self.canvas.canvasy(0)
+            self.canvas.yview_scroll( -1, 'units')
+            if old == self.canvas.canvasy(0):
+                break
             
 class Node :
-    def __init__(self,parent,item,command=None):
+    def __init__(self,parent,item,command=None,rmenu=None):
         self.parent = parent
         self.item = item
+        self.connections=[]
+        self.connect()
+
         self.command = command
+        self.rmenu=rmenu
         self.tree = self.parent.tree
         self.appli = self.parent.appli
         self.canvas = self.parent.canvas
         self.init()
-        #self.build_children()
 
     def init(self):
         self.state='collapsed'
@@ -115,23 +183,199 @@ class Node :
         self.lasty = 0
         self.children = None
         self.id = []
-        # etape = noeud d'étape auquel appartient self
-        # = self si c'est lui-même
-        if isinstance(self.parent,Tree) :
-            # on est  sur un noeud de JDC
-            self.racine=self
-            self.etape=None
-            self.nature='JDC'
-        elif isinstance(self.parent.parent,Tree) :
-            # on est sur un noeud d'étape
-            self.racine = self.parent
-            self.etape=self
-            self.nature = 'ETAPE'
-        else :
-            # on est sur un noeud de mot-clé
-            self.racine = self.parent.racine
-            self.etape=self.parent.etape
-            self.nature = 'MOTCLE'
+        if self.parent is self.tree:
+           self.racine=self
+        else:
+           self.racine = self.parent.racine
+           
+    def reconnect(self):
+        self.disconnect()
+        self.connect()
+
+    def connect(self):
+        self.connections.append(self.item._object)
+        CONNECTOR.Connect(self.item._object,"add",self.onAdd,())
+        CONNECTOR.Connect(self.item._object,"supp",self.onSupp,())
+        CONNECTOR.Connect(self.item._object,"valid",self.onValid,())
+        if self.item.object is not self.item._object:
+           CONNECTOR.Connect(self.item.object,"add",self.onAdd,())
+           CONNECTOR.Connect(self.item.object,"supp",self.onSupp,())
+           CONNECTOR.Connect(self.item.object,"valid",self.onValid,())
+           self.connections.append(self.item.object)
+
+    def disconnect(self):
+        for c in self.connections:
+           CONNECTOR.Disconnect(c,"add",self.onAdd,())
+           CONNECTOR.Disconnect(c,"supp",self.onSupp,())
+           CONNECTOR.Disconnect(c,"valid",self.onValid,())
+        self.connections=[]
+
+    def __del__(self):
+        """ appele a la destruction du noeud """
+        #print "NOEUD DETRUIT",self,self.item.GetLabelText()[0]
+
+    def force_select(self):
+        if self.selected:
+           # le noeud est selectionné. On force la reconstruction du panel associé
+           if self.command:apply(self.command,(None,))
+           self.select()
+
+    def onValid(self):
+        #print "onValid : l'item a changé de validité ",self.item,self.item.object,self.item.object.isvalid()
+        self.update_node_valid()
+        self.update_node_label()
+        self.update_node_texte()
+        if self.selected and self.command:
+           self.command(self)
+
+    def onAdd(self,objet):
+        #print "onAdd : un objet a été ajouté aux fils de l'item ",self.item.object,objet
+        self.expand_node()
+        old_nodes=self.children
+        self.update_nodes()
+        self.redraw_children(old_nodes)
+        self.force_select()
+
+    def onSupp(self,objet):
+        #print "onSupp : un objet a été supprimé des fils de l'item ",self.item.object,objet
+        self.expand_node()
+        old_nodes=self.children
+        self.update_nodes()
+        self.redraw_children(old_nodes)
+        self.force_select()
+
+    def update_nodes(self):
+        #print "update_nodes",self
+        newnodes=[]
+        inodes=iter(self.children)
+        sublist=self.item._GetSubList()
+        iliste=iter(sublist)
+
+        while(1):
+           old_item=item=None
+           for node in inodes:
+              old_item=node.item
+              if old_item in sublist:break
+              #print "item supprime",old_item
+           for item in iliste:
+              if item is old_item:break
+              #print "item ajoute",item
+              child = item.itemNode(self,item,self.command,self.rmenu)
+              newnodes.append(child)
+
+           if old_item is None and item is None:break
+           if old_item is item:
+              #print "item conserve",item
+              newnodes.append(node)
+
+        self.children=newnodes
+        self.reconnect()
+
+    def supprime(self):
+        self.disconnect()
+        self.efface_node()
+
+        #self.label_id=None
+        #self.text_id=None
+        #self.label=None
+        #self.text=None
+        #self.image_id=None
+        #self.icone_id=None
+        #self.etape=None
+        ####self.parent=None
+        #self.command = None
+        #self.rmenu=None
+        #self.tree = None
+        #self.appli=None
+        #self.canvas = None
+
+        if not self.children : return
+        for child in self.children:
+            child.supprime()
+        self.children=None
+
+    def redraw_children(self,old_nodes):
+        #print "redraw_children",old_nodes
+        #print self.children
+        y = self.y + 20
+        x = self.x + 15
+        supp_nodes=[]
+
+        inodes=iter(old_nodes)
+        iliste=iter(self.children)
+        # on parcourt la liste des anciens noeuds (node)
+        # et la liste des nouveaux noeuds (new_node) en parallele (iterateurs)
+
+        while(1):
+           new_node=node=None
+           for node in inodes:
+              #print "ancien noeud",node
+              if node in self.children:break # ancien noeud toujours present
+              #print "noeud supprime",node,node.item.GetLabelText()[0]
+              dy=node.y-node.lasty -20
+              #print "deplacer noeuds",y,dy
+              node.move_nodes(y,dy)
+              node.supprime()
+              #supp_nodes.append(node)
+
+           for new_node in iliste:
+              #print "nouveau noeud",new_node
+              if new_node in old_nodes: break # nouveau noeud deja present
+              #print "noeud ajoute",new_node,new_node.item.GetLabelText()[0]
+              y=self.draw_node(new_node,x,y)
+
+           if node is None and new_node is None : break
+
+           if node is new_node: # ancien noeud
+              #print "noeud conserve",node
+              node.update_node_label()
+              y=y+node.lasty-node.y +20
+
+        self.racine.update_coords()
+        self.canvas.delete('line')
+        self.racine.trace_ligne()
+        self.tree.resizescrollregion()
+        # Mettre à 1 pour verifier les cycles entre objets node
+        #withCyclops=0
+        #if withCyclops:
+           #from Misc import Cyclops
+           #z = Cyclops.CycleFinder()
+           #print supp_nodes
+           #for o in supp_nodes:
+             #z.register(o)
+           #del supp_nodes
+           #del o
+           #z.find_cycles()
+           #z.show_stats()
+           #z.show_cycles()
+
+    def tag_move_nodes(self,y):
+        """ Marque pour deplacement tous les noeuds au dela de l'ordonnée y """
+        self.canvas.dtag(ALL,'move')
+        # on marque tous les ids au dela de y
+        x0, y0, x1, y1 = self.canvas.bbox(ALL)
+        self.canvas.addtag_overlapping('move',x0,y,x1,y1)
+
+    def move_nodes(self,y,dy):
+        """ Déplace de l'incrément dy les noeuds au dela de l'ordonnée y """
+       self.tag_move_nodes(y)
+        # on déplace tous les items de dy
+        self.canvas.move('move',0,dy)
+
+    def draw_node(self,new_node,x,y):
+        """ Dessine le noeud new_node en x,y en deplacant les noeuds existants
+            en y et au dela
+            Retourne la position du premier des noeuds deplaces
+        """
+        self.tag_move_nodes(y)
+        #if new_node.item.isactif():
+           #new_node.state = 'expanded'
+        new_node.state = 'expanded'
+        new_node.draw(x,y)
+        dy=(new_node.get_nb_children()+1)*20
+        #print "deplacer noeuds",y,dy
+        self.canvas.move('move',0,dy)
+        return new_node.lasty+20
 
     def build_children(self):
         """ Construit la liste des enfants de self """
@@ -139,7 +383,7 @@ class Node :
         sublist = self.item._GetSubList()
         if not sublist : return
         for item in sublist :
-            child = Node(self,item,self.command)
+            child = item.itemNode(self,item,self.command,self.rmenu)
             self.children.append(child)
             
     #-----------------------------------------------
@@ -151,22 +395,14 @@ class Node :
         Rend le noeud courant (self) sélectionné et déselectionne
         tous les autres
         """
+        #print "SELECT",self
         if not self.children : self.build_children()
         self.tree.deselectall()
         self.selected = 1
         self.tree.node_selected = self
         if self.command:apply(self.command,(self,))
         self.highlight()
-        self.canvas.focus_force()
-        #self.make_visible()
-
-    def deselect_old(self, event=None):
-        """ Déselectionne self """
-        self.selected = 0
-        if self.displayed == 1:
-            self.dehighlight()
-        for child in self.children:
-            child.deselect()
+        self.make_visible()
 
     def deselect(self, event=None):
         """ Déselectionne self """
@@ -175,9 +411,10 @@ class Node :
             
     def make_visible(self):
         """ Rend l'objet self visible cad déplace le scroll pour que self soit dans
-        la fenêtre de visu"""
-        x0,y0,x1,y1 = self.canvas.bbox(ALL)
-        self.canvas.yview("moveto",self.y/y1)
+            la fenêtre de visu
+        """
+        lchild=self.last_child()
+        self.tree.see((self.image_id,lchild.image_id))
         
     def select_next(self,ind=0):
         """ on doit chercher à sélectionner dans l'ordre:
@@ -190,13 +427,26 @@ class Node :
             self.children[ind].select()
         else :
             index = self.parent.children.index(self) + 1
-            if isinstance(self.parent,TREE) :
+            try :
+              if isinstance(self.parent,TREE) :
                 try:
                     self.children[ind].select()
                 except:
                     self.children[0].select()
-            else :                
+              else :                
                 self.parent.select_next(index)
+            except :
+                self.parent.select_next(index)
+
+    def select_mot_previous(self):
+        index = self.parent.children.index(self) - 1
+        try :
+            if index > 0  :
+               self.parent.children[index].select()
+            else :
+               self.parent.select()
+        except:
+            self.parent.select()
 
     def select_previous(self):
         """ on doit d'abord sélectionner(dans l'ordre) :
@@ -208,6 +458,15 @@ class Node :
             self.parent.children[index].select()
         except:
             self.parent.select()
+
+    def popup(self,event=None):
+        """
+            Declenche le traitement associé au clic droit de la souris
+            sur l'icone du Node
+        """
+        if not self.rmenu:return
+        apply(self.rmenu,(self,event))
+
     #-----------------------------------------------
     # Méthodes de recherche d'informations
     #-----------------------------------------------
@@ -241,6 +500,7 @@ class Node :
         for child in self.children:
             if child.item.get_nom() == name: return child
         return None
+
     #-----------------------------------------------
     # Méthodes d'affichage d'un noeud
     #-----------------------------------------------
@@ -262,7 +522,7 @@ class Node :
                 callback = self.expand
             image = self.geticonimage(name=iconname)
             self.icone_id = self.canvas.create_image(self.x, self.y, image=image)
-            self.canvas.tag_bind(self.icone_id, "<1>", callback)
+            self.callback_id=self.canvas.tag_bind(self.icone_id, "<1>", callback)
             self.id.append(self.icone_id)
         # création de la ligne horizontale
         self.ligne_id = self.canvas.create_line(self.x,self.y,self.x+10,self.y)
@@ -272,7 +532,8 @@ class Node :
         image = self.geticonimage()
         if image != None :
             self.image_id = self.canvas.create_image(self.x+15,self.y,image = image)
-            self.canvas.tag_bind(self.image_id,"<1>",self.select)
+            self.select_id2=self.canvas.tag_bind(self.image_id,"<1>",self.select)
+            self.popup_id2=self.canvas.tag_bind(self.image_id,"<3>",self.popup)
             self.id.append(self.image_id)
         else:
             self.image_id = None
@@ -292,6 +553,7 @@ class Node :
             child.draw(x,y)
             nb = child.get_nb_children()
             y = y + 20*(nb+1)
+        self.trace_ligne()
 
     def drawtext(self):
         """ Affiche les deux zones de texte après l'icône de couleur de l'objet """
@@ -314,9 +576,10 @@ class Node :
         self.label_id = self.canvas.create_window(textx,texty,window=self.label,anchor='w')
         self.id.append(self.label_id)
         # bindings sur le widget label
-        self.label.bind("<1>", self.select)
-        self.label.bind("<Enter>",self.enter)
-        self.label.bind("<Leave>",self.leave)
+        self.select_id=self.label.bind("<1>", self.select)
+        self.popup_id=self.label.bind("<3>", self.popup)
+        self.enter_id=self.label.bind("<Enter>",self.enter)
+        self.leave_id=self.label.bind("<Leave>",self.leave)
         # valeur de cet objet à afficher
         x0, y0, x1, y1 = self.canvas.bbox(self.label_id)
         textx = max(x1, 200) + 10
@@ -358,7 +621,6 @@ class Node :
         if not self.children : return
         for child in self.children:
             child.state='collapsed'
-            child.displayed = 0
             child.collapse_children()
             
     def collapse(self,event = None):
@@ -366,26 +628,22 @@ class Node :
         nb = self.get_nb_children()
         self.state = 'collapsed'
         self.collapse_children()
-        self.efface()
-        try:
-            self.move(-20*nb)
-        except:
-            pass
-        self.draw(self.x,self.y)
+        self.redraw(-nb)
         self.select()
-        self.update()
-
-    def expand(self,event = None):
+   
+    def expand_node(self,event = None):
         """ Expanse self et le retrace """
-        if not self.item.isactif() : return
+        if self.state == 'expanded':return
+        #if not self.item.isactif() : return
         if not self.children : self.build_children()
         self.state = 'expanded'
         nb = self.get_nb_children()
-        self.move(20*nb)
-        self.efface()
-        self.draw(self.x,self.y)
+        self.redraw(nb)
+
+    def expand(self,event = None):
+        """ Expanse self et le retrace """
+        self.expand_node()
         self.select()
-        self.update()
 
     def redraw(self,nb):
         """ Redessine self :  nb est le décalage à introduire
@@ -395,7 +653,12 @@ class Node :
         # on efface self et on le redessine
         self.efface()
         self.draw(self.x,self.y)
-        self.update()
+        # Il n'est pas nécessaire d'appeler update
+        # il suffit d'updater les coordonnees et de retracer les lignes
+        self.racine.update_coords()
+        self.racine.trace_ligne()
+        self.update_valid()
+        self.tree.resizescrollregion()
         
     def update_coords(self):
         """ Permet d'updater les coordonnes de self et de tous ses enfants"""
@@ -407,10 +670,12 @@ class Node :
             coords = self.canvas.coords(self.label_id)
             self.x = coords[0]-15
         self.y = coords[1]
+        self.lasty = self.y
         if self.state == 'expanded' :
             for child in self.children:
                 if child.displayed != 0:
                     child.update_coords()
+                    self.lasty = child.lasty
 
     def update_icone(self):
         """ Met à jour les icônes de tous les noeuds : teste la validité de l'objet
@@ -423,38 +688,102 @@ class Node :
                 if child.displayed != 0:
                     child.update_icone()
 
+    def update_label_texte(self):
+        """ Met a jour le label du noeud et celui de tous ses fils ouverts """
+        self.update_node_label()
+        if self.state == 'expanded' :
+            for child in self.children:
+                if child.displayed != 0 : child.update_label_texte()
+
     def update_texte(self):
         """ Met à jour les noms des SD et valeurs des mots-clés """
-        text = self.item.GetText()
-        if text == None : text = ''
-        self.text.configure(text=text)
+        self.update_node_texte()
         if self.state == 'expanded' :
             for child in self.children:
                 if child.displayed != 0 : child.update_texte()
         
+    def update_node_label(self):
+        """ Met a jour le label du noeud """
+        if self.displayed == 0 : return
+        # nom,fonte et couleur de l'objet du noeud à afficher
+        labeltext,fonte,couleur = self.item.GetLabelText()
+        if labeltext    == ''   : labeltext = '   '
+        if fonte        == None : fonte = Fonte_Standard
+        if couleur      == None : couleur = 'black'
+        self.label.configure(text=labeltext,font=fonte)
+
+    def update_node_texte(self):
+        """ Met à jour les noms des SD et valeurs des mots-clés """
+        if self.displayed == 0 : return
+        text = self.item.GetText()
+        if text == None : text = ''
+        self.text.configure(text=text)
+
+    def update_node_valid(self) :
+        """Cette methode remet a jour la validite du noeud (icone)
+           Elle appelle isvalid
+        """
+        if self.displayed == 0 : return
+        if self.image_id != None :
+            image = self.geticonimage()
+            self.canvas.itemconfig(self.image_id,image=image)
+
+    def update_valid(self) :
+        """Cette methode a pour but de mettre a jour la validite du noeud
+           et de propager la demande de mise à jour à son parent
+        """
+        self.update_node_valid()
+        self.parent.update_valid()
+
     def update(self,event=None) :
         """ Classe Node :
             Cette méthode est appelée pour demander l update d un noeud 
-             d'un jeu de commandes
-             Cette demande est transmise au noeud racine (le JDC) qui update
-             tout l arbre représentant le jeu de commandes
-             Pendant cette mise à jour, on appelle la méthode isvalid qui
-             fera l update de tous les objets déclarés modifiés lors des
-             actions précédentes
-             La métode isvalid est en général appelée par l intermédiaire de
-             update_icone -> geticonimage -> GetIconName
+            d'un jeu de commandes
+            Cette demande est transmise au noeud racine (le JDC) qui update
+            tout l arbre représentant le jeu de commandes
+            Pendant cette mise à jour, on appelle la méthode isvalid qui
+            fera l update de tous les objets déclarés modifiés lors des
+            actions précédentes
+            La métode isvalid est en général appelée par l intermédiaire de
+            update_icone -> geticonimage -> GetIconName
         """
+        #print "update",self
+        #traceback.print_stack()
         self.racine.update_coords()
         self.racine.trace_ligne()
         self.racine.update_icone()
         self.racine.update_texte()
+        self.racine.update_label_texte()
         self.tree.resizescrollregion()
 
+    def efface_node(self):
+        if self.displayed != 0:
+           self.label.unbind("<1>", self.select_id)
+           self.label.unbind("<3>", self.popup_id)
+           self.label.unbind("<Enter>",self.enter_id)
+           self.label.unbind("<Leave>",self.leave_id)
+           self.canvas.tag_unbind(self.image_id,"<1>",self.select_id2)
+           self.canvas.tag_unbind(self.image_id,"<3>",self.popup_id2)
+           if self.item.IsExpandable():
+              self.canvas.tag_unbind(self.icone_id, "<1>", self.callback_id)
+           self.label.destroy()
+           self.text.destroy()
+
+        for id in self.id :
+            self.canvas.delete(id)
+        self.id=[]
+        self.label_id=None
+        self.text_id=None
+        self.image_id=None
+        self.icone_id=None
+        self.label=None
+        self.text=None
+       self.displayed=0
+
     def efface(self):
         """ Efface du canvas les id associés à self : cad les siens et ceux
             de ses enfants """
-        for id in self.id :
-            self.canvas.delete(id)
+        self.efface_node()
         if not self.children : return
         for child in self.children:
             child.efface()
@@ -471,19 +800,16 @@ class Node :
            print "Erreur dans move :"
             print self
             print self.item
-            print self.item.object
-            print self.item.object.definition.label
+            print self.item.getObject()
+            print self.item.getObject().definition.label
             print 'y=',self.y
             print 'dy=',dy
         # on déplace tous les items de dy
         self.canvas.move('move',0,dy)
-        # il faut réactualiser la zone de scroll
-        self.tree.resizescrollregion()
 
     def trace_ligne(self):
         """ Dessine les lignes verticales entre frères et entre père et premier fils"""
         if self.state=='collapsed' : return
-        #if self.displayed == 0 : return
         if len(self.children)==0 : return
         # on est bien dans le cas d'un noeud expansé avec enfants ...
         # il faut rechercher l'ordonnée du dernier fils de self
@@ -496,71 +822,62 @@ class Node :
             except:
                print "Erreur dans trace_ligne :"
                 print child
-                print child.item.object
-
-    def make_visible_OBSOLETE(self,nb):
-        """ Cette méthode a pour but de rendre le noeud self (avec tous ses descendants
-        affichés) visible dans le canvas """
-        x = self.canvas.canvasx(self.canvas.cget('width'))
-        y = self.canvas.canvasy(self.canvas.cget('height'))
-        #print 'x,y =',x,y
-        x0,y0,x1,y1 = self.canvas.bbox(ALL)
-        #print 'x0,y1=',x0,y1
-        y_deb = self.y
-        nb = self.get_nb_children()
-        y_fin = y_deb + 20*nb
-        #print 'y_deb,y_fin=',y_deb,y_fin
-        
+                print child.item.getObject()
+
+    def last_child(self):
+        lchild=self
+        if self.state == 'expanded' and self.children:
+           lchild= self.children[-1].last_child()
+        return lchild
+
     #------------------------------------------------------------------
     # Méthodes de création et destruction de noeuds
     # Certaines de ces méthodes peuvent être appelées depuis l'externe
     #------------------------------------------------------------------
     def replace_node(self,node1,node2):
         """ Remplace le noeud 1 par le noeud 2 dans la liste des enfants de self"""
+        raise "OBSOLETE"
         index= self.children.index(node1)
         self.delete_node_child(node1)
         self.children.insert(index,node2)
         
+    def replace_enfant(self,item):
+        """ Retourne le noeud fils à éventuellement remplacer """
+        raise "OBSOLETE"
+        return self.get_node_fils(item.get_nom())
+
     def full_creation(self,name,pos=None):
         """
             Interface avec ACCAS : création de l'objet de nom name et
             du noeud associé. Retourne le noeud fils ainsi créé
         """
+        raise "OBSOLETE"
+        #print "full_creation",name,pos,self.item
         item = self.item.additem(name,pos)
         if item == None or item == 0:
             # impossible d'ajouter le noeud de nom : name
             return 0
-        nature = item.get_nature()
-        if nature in ("COMMANDE","OPERATEUR","PROCEDURE","COMMENTAIRE",
-                      "PARAMETRE","COMMANDE_COMMENTARISEE","PARAMETRE_EVAL"):
-            # on veut ajouter une commande ou un commentaire ou un paramètre
-            # il ne faut pas rechercher un même objet déjà existant
-            # à modifier : il faut tester l'attribut 'repetable' 
-            enfant = None
-        elif self.item.object.isMCList():
-            # Dans ce cas on ne fait pas de remplacement. On ne cherche pas un objet de meme nom
-            enfant=None
-        else :
-            enfant = self.get_node_fils(item.get_nom())
+
+        enfant = self.replace_enfant(item)
         if enfant :
-            # un fils de même nom existe déjà : on remplace
-            # un MCFACT (ou une MCList) par une (autre) MCList
-            child = Node(self,item,self.command)
+            # un fils de même nom existe déjà : on le remplace
+            child = item.itemNode(self,item,self.command,self.rmenu)
             self.replace_node(enfant,child)
         else :            
-            child = Node(self, item,self.command)
+            child = item.itemNode(self, item,self.command,self.rmenu)
             if pos is None:
                 self.children.append(child)
             else :
                 self.children.insert(pos,child)
         return child
 
-    def append_brother(self,name,pos='after',retour='non'):
+    def append_brother_BAK(self,name,pos='after',retour='non'):
         """
         Permet d'ajouter un frère à self
         par défaut on l'ajoute après self
         Méthode externe
         """
+        raise "OBSOLETE"
         # on veut ajouter le frère de nom name directement avant ou après self
         index = self.parent.children.index(self)
         if pos == 'before':
@@ -578,9 +895,9 @@ class Node :
         des conditions en fonction du contexte
         Attention : fils peut être un nom ou déjà un object (cas d'une copie)
         """
+        raise "OBSOLETE"
         if not self.children : self.build_children()
         if pos == None :
-            #pos = len(self.children)
             if type(fils) == types.InstanceType:
                 pos = self.item.get_index_child(fils.nom)
             else:
@@ -589,24 +906,71 @@ class Node :
         if child == 0 :
             # on n'a pas pu créer le noeud fils
             return 0
-        child.displayed = 1
         self.state = 'expanded'
+        child.displayed = 1
+        if child.item.isactif():
+           child.state = 'expanded'
+        if not child.children : child.build_children()
         if verif == 'oui':
-            if not child.children : child.build_children()
-            test = child.item.isMCList()
-            if test :
-                child.children[-1].verif_condition()
-            else :
-                child.verif_condition()
-            self.verif_condition()
+           child.verif_condition()
+           self.verif_condition()
         return child
             
+    def append_brother(self,name,pos='after',retour='non'):
+        """
+        Permet d'ajouter un objet frère à l'objet associé au noeud self
+        par défaut on l'ajoute immédiatement après 
+        Méthode externe
+        """
+        # on veut ajouter le frère de nom name directement avant ou après self
+        index = self.parent.children.index(self)
+        if pos == 'before':
+            index = index
+        elif pos == 'after':
+            index = index +1
+        else:
+            print str(pos)," n'est pas un index valide pour append_brother"
+            return 0
+        return self.parent.append_child(name,pos=index)
+
     def append_child(self,name,pos=None,verif='oui',retour='non'):
+        """
+           Methode pour ajouter un objet fils à l'objet associé au noeud self.
+           On peut l'ajouter en début de liste (pos='first'), en fin (pos='last')
+           ou en position intermédiaire.
+           Si pos vaut None, on le place à la position du catalogue.
+        """
+        #print "append_child",self,self.children
+        if pos == 'first':
+            index = 0
+        elif pos == 'last':
+            index = len(self.children)
+        elif type(pos) == types.IntType :
+            # position fixee
+            index = pos
+        elif type(pos) == types.InstanceType:
+            # pos est un item. Il faut inserer name apres pos
+            index = self.item.get_index(pos) +1
+        elif type(name) == types.InstanceType:
+            index = self.item.get_index_child(name.nom)
+        else:
+            index = self.item.get_index_child(name)
+        obj=self.item.additem(name,index)
+        #print obj
+        if obj is None:obj=0
+        if obj == 0:return 0
+        #print "append_child",index,self.children
+        child=self.children[index]
+        child.select()
+        return child
+
+    def append_child_BAK(self,name,pos=None,verif='oui',retour='non'):
         """
         Permet d'ajouter un fils à self
         on peut l'ajouter en fin de liste (défaut) ou en début
         Méthode externe
         """
+        raise "OBSOLETE"
         if pos == 'first':
             index = 0
         elif pos == 'last':
@@ -632,22 +996,21 @@ class Node :
         nbnew = self.get_nb_children()
         self.redraw(nbnew-nbold)
         child.select()
-        child.expand()
-        #child.make_visible()
         if retour == 'oui': return child
 
-    def delete_node_child(self,child):
+    def delete_node_child_BAK(self,child):
         """ Supprime child des enfants de self et les id associés """
+        raise "OBSOLETE"
         child.efface()
-        child.displayed = 0
         self.children.remove(child)
         self.canvas.update()
         
-    def delete_child(self,child):
+    def delete_child_BAK(self,child):
         """ 
             Supprime child des enfants de self, tous les id associés
             ET l'objet associé 
         """
+        raise "OBSOLETE"
         if self.item.suppitem(child.item):
             self.delete_node_child(child)
             return 1
@@ -655,105 +1018,86 @@ class Node :
             return 0
                     
     def delete(self):
+        """ 
+            Méthode externe pour la destruction de l'objet associé au noeud
+            La mise à jour des noeuds est faite par onSupp sur notification
+        """
+        index = self.parent.children.index(self) - 1 
+        if index < 0 : index =0
+
+        ret=self.parent.item.suppitem(self.item)
+        if ret == 0:return
+
+        brothers=self.parent.children
+        if brothers:
+           toselect=brothers[index]
+        else:
+           toselect=self.parent
+        toselect.select()
+
+    def delete_BAK(self):
         """ Méthode externe pour la destruction du noeud ET de l'objet
             Gère l'update du canvas"""
-        if self.parent.item.isMCList():
-            pere = self.parent.parent
-            nbold = pere.get_nb_children()
-            if self.parent.delete_child(self):
-                self.parent.traite_mclist()
+        raise "OBSOLETE"
+        pere = self.parent
+        nbold = pere.get_nb_children()
+
+       if self.parent.children.index(self) > 0 :
+            index = self.parent.children.index(self) - 1 
+       else:
+           index=0
+        if self.parent.delete_child(self):
             if self.item.get_position() == 'global':
                 self.etape.verif_all()
             elif self.item.get_position() == 'global_jdc':
                 self.racine.verif_all()
             else:
                 self.parent.verif_condition()
-            nbnew = pere.get_nb_children()
         else:
-            pere = self.parent
-            nbold = pere.get_nb_children()
-            if self.parent.delete_child(self):
-                if self.item.get_position() == 'global':
-                    self.etape.verif_all()
-                elif self.item.get_position() == 'global_jdc':
-                    self.racine.verif_all()
-                else:
-                    self.parent.verif_condition()
-            else :
-                print 'Erreur dans la destruction de ',self.item.get_nom(),' dans delete'
-            nbnew = pere.get_nb_children()
+            print 'Erreur dans la destruction de ',self.item.get_nom(),' dans delete'
+
+        nbnew = pere.get_nb_children()
         pere.redraw(nbnew-nbold)
-       pere.select()
-
-    def copynode(self,node,pos) :
-        """ node est le noeud à copier à la position pos de self ( = parent de node) """
-        objet_copie = node.item.get_copie_objet()
-        child = self.full_creation(node.item,pos)
-        child.displayed = node.displayed
-        #child.image_id = node.image_id
-        #child.label_id = node.label_id
-        if child.item.get_nature() == "MCList":
-            child.item.object[-1].mc_liste = objet_copie.mc_liste
-        else :
-            try :
-                child.item.object.mc_liste = objet_copie.mc_liste
-            except:
-                traceback.print_exc()
+
+        # Le noeud n'est pas au 1er niveau
+        if  pere.parent.parent != None:
+            pere.select()
+        else:
+            enfants = self.parent.children
+            try:
+              enfants[index].select()
+            except :
+             try :
+               enfants[index+1].select()
+             except :
+               # on est avant debut
+               pass
+
+    def doPaste(self,node_selected):
+        self.appli.message="Vous ne pouvez copier que des commandes ou des mots-clés facteurs !"
+        return 0
+
+    def doPaste_Commande(self,objet_a_copier):
+        """
+       Réalise la copie de l'objet passé en argument qui est nécessairement
+       une commande
+       """
+       child = self.append_brother(objet_a_copier,retour='oui')
+       return child
+
     #--------------------------------------------------------------
     # Méthodes de vérification du contexte et de validité du noeud
     #--------------------------------------------------------------
-    def traite_mclist_OLD(self):
-        """ Dans le cas d'une MCList il faut vérifier qu'elle n'est pas vide
-            ou réduite à un seul élément suite à une destruction
-        """
-        # self représente une MCList
-       print "on passe par traite_mclist ",len(self.item)
-        if len(self.item) == 0 :
-            # la liste est vide : il faut la supprimer
-            self.delete()
-        elif len(self.item) == 1:
-            # il ne reste plus qu'un élément dans la liste
-            # il faut supprimer la liste et créer directement l'objet
-            index = self.parent.children.index(self)
-            noeud = self.children[0]
-            if self.parent.delete_child(self):
-                self.parent.append_node_child(noeud.item,pos=index,verif='non')
-            else:
-               print "destruction de self impossible !"
-            #if self.parent.delete_child(self):
-            #    self.parent.copynode(self.children[0],index)
-            #else :
-            #    print 'erreur dans la destruction de :',self.item.get_nom(),' dans traite_mclist'
-        else :
-            return
-
-    def traite_mclist(self):
-        """ Dans le cas d'une MCList il faut vérifier qu'elle n'est pas vide
-            ou réduite à un seul élément suite à une destruction
-        """
-        # self représente une MCList
-        if len(self.item) == 0 :
-            # la liste est vide : il faut la supprimer
-            self.delete()
-        elif len(self.item) == 1:
-            # il ne reste plus qu'un élément dans la liste
-            # il faut supprimer la liste et créer directement l'objet
-            index = self.parent.children.index(self)
-            noeud = self.children[0]
-           noeud.parent = self.parent
-           self.parent.delete_node_child(self)
-            self.parent.item.replace_child(self.item,noeud.item)
-           self.parent.children.insert(index,noeud)
-        else :
-            return
-           
     def verif_all(self):
+        raise "OBSOLETE"
+        traceback.print_stack()
         self.verif_all_children()
             
     def verif_all_children(self):
+        raise "OBSOLETE"
+        traceback.print_stack()
         if not self.children : self.build_children()
-        if self.nature != 'JDC' :
-            self.verif()
+        self.verif()
         for child in self.children :
             child.verif_all_children()
 
@@ -762,6 +1106,8 @@ class Node :
             Lance la vérification des conditions des blocs de self et le cas
             échéant redessine self 
         """
+        raise "OBSOLETE"
+        traceback.print_stack()
         nbold = self.get_nb_children()
         test = self.verif_condition()
         nbnew = self.get_nb_children()
@@ -774,7 +1120,8 @@ class Node :
         on crée ou supprime les noeuds concernés
         (self est d'un niveau inférieur ou égal à l'ETAPE)
         """
-        if self.item.object.__class__.__name__ == 'ETAPE_NIVEAU': return 0
+        raise "OBSOLETE"
+        traceback.print_stack()
         test = 0
         l_bloc_arajouter,l_bloc_aenlever = self.verif_condition_bloc()
         if len(l_bloc_arajouter) > 0:
@@ -797,9 +1144,13 @@ class Node :
         return test
         
     def verif_condition_bloc(self):
+        raise "OBSOLETE"
+        traceback.print_stack()
         return self.item.verif_condition_bloc()
 
     def verif_condition_regles(self,l_mc_presents):
+        raise "OBSOLETE"
+        traceback.print_stack()
         return self.item.verif_condition_regles(l_mc_presents)