X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=Editeur%2Ftreewidget.py;h=47918d2bfcb4effb4d78f0fb88da233f4a4658fd;hb=fd27c38037ee9c07a594b6727c99965322d9f9bc;hp=a0d6554eacc6172e053c382649c465fd5ada1c63;hpb=fcd054a825fbe171652108194c0204f8e3fd955a;p=tools%2Feficas.git diff --git a/Editeur/treewidget.py b/Editeur/treewidget.py index a0d6554e..47918d2b 100644 --- a/Editeur/treewidget.py +++ b/Editeur/treewidget.py @@ -1,11 +1,24 @@ -#@ 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 +import os,sys,string,re,types,traceback from Tkinter import * @@ -13,14 +26,14 @@ import fontes import images # -__version__="$Name: V1_1p1 $" -__Id__="$Id: treewidget.py,v 1.1.1.1 2001/12/04 15:38:23 eficas Exp $" +__version__="$Name: $" +__Id__="$Id: treewidget.py,v 1.13 2003/09/25 15:25:10 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 +41,19 @@ class Tree : self.canvas.bind("", self.page_down) self.canvas.bind("", self.unit_up) self.canvas.bind("", self.unit_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): @@ -48,7 +66,7 @@ class Tree : def build_children(self): """ Construit la liste des enfants de self """ self.children = [] - child = Node(self,self.item,self.command) + child = Node(self,self.item,self.command,self.rmenu) self.children.append(child) child.state='expanded' @@ -59,16 +77,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,8 +90,17 @@ class Tree : for child in self.children: child.update() + 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() @@ -95,17 +115,42 @@ class Tree : def verif_all(self): 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.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' @@ -139,7 +184,7 @@ class Node : sublist = self.item._GetSubList() if not sublist : return for item in sublist : - child = Node(self,item,self.command) + child = Node(self,item,self.command,self.rmenu) self.children.append(child) #----------------------------------------------- @@ -157,16 +202,7 @@ class Node : 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 +211,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: @@ -208,6 +245,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 #----------------------------------------------- @@ -273,6 +319,7 @@ class Node : 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.canvas.tag_bind(self.image_id,"<3>",self.popup) self.id.append(self.image_id) else: self.image_id = None @@ -292,6 +339,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 """ @@ -315,6 +363,7 @@ class Node : self.id.append(self.label_id) # bindings sur le widget label self.label.bind("<1>", self.select) + self.label.bind("<3>", self.popup) self.label.bind("",self.enter) self.label.bind("",self.leave) # valeur de cet objet à afficher @@ -366,26 +415,17 @@ 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): """ Expanse self et le retrace """ 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) self.select() - self.update() def redraw(self,nb): """ Redessine self : nb est le décalage à introduire @@ -395,7 +435,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""" @@ -432,17 +477,26 @@ class Node : for child in self.children: if child.displayed != 0 : child.update_texte() + 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 + """ + if self.image_id != None : + image = self.geticonimage() + self.canvas.itemconfig(self.image_id,image=image) + 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 """ self.racine.update_coords() self.racine.trace_ligne() @@ -468,6 +522,7 @@ class Node : try: self.canvas.addtag_overlapping('move',bbox1[0],self.y +10,bbox1[2],bbox1[3]) except: + print "Erreur dans move :" print self print self.item print self.item.object @@ -476,8 +531,6 @@ class Node : 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""" @@ -493,22 +546,16 @@ class Node : try: child.trace_ligne() 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 - + 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 @@ -521,30 +568,32 @@ class Node : 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éé + Interface avec ACCAS : création de l'objet de nom name et + du noeud associé. Retourne le noeud fils ainsi créé """ 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 =="COMMANDE" or nature == "OPERATEUR" or nature == "PROCEDURE": 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()) 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) + child = Node(self,item,self.command,self.rmenu) self.replace_node(enfant,child) else : - child = Node(self, item,self.command) + child = Node(self, item,self.command,self.rmenu) if pos is None: self.children.append(child) else : @@ -576,7 +625,6 @@ class Node : """ 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: @@ -585,10 +633,12 @@ 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() @@ -611,6 +661,9 @@ class Node : # on donne la position depuis l'extérieur # (appel de append_child par append_brother par exemple) index = pos + elif type(pos) == types.InstanceType: + # pos est un item. Il faut inserer name apres pos + index = self.item.get_index(pos) +1 else : if type(name) == types.InstanceType: index = self.item.get_index_child(name.nom) @@ -625,8 +678,6 @@ 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): @@ -676,6 +727,7 @@ class Node : 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) """ @@ -690,15 +742,17 @@ class Node : try : child.item.object.mc_liste = objet_copie.mc_liste except: - pass + traceback.print_exc() + #-------------------------------------------------------------- # Méthodes de vérification du contexte et de validité du noeud #-------------------------------------------------------------- - def traite_mclist(self): + 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() @@ -709,6 +763,8 @@ class Node : 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 : @@ -716,6 +772,26 @@ class Node : 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): self.verif_all_children()