Tree内でのドラッグアンドドロップ

まずはTreeStore内に汎用的なノードの移動メソッドを作ってみました。

def moveNodeToChild(self, src_item, dest_item):
    print "moveNodeToChild"
    node = self.get_value(src_item,c.COL_OBJECT)
    new_item = self.append(dest_item)
    self.set_value(new_item,c.COL_TEXT,node.title)
    self.set_value(new_item,c.COL_OBJECT,node)
    i = 0
    while i <= self.iter_n_children(src_item) - 1:
        iter = self.iter_nth_child(src_item,i)
        self.moveNodeToChild(iter,new_item)
        i += 1
    self.remove(src_item)
    return new_item

上記は他のノードの子ノードに移動するメソッドですが、ちょっと変えるだけで他のノードの前、他のノードの後に移動するメソッドも作れます。慣れてるのでwhileで書いたんですがちょっと別の言語っぽく見えるのは気のせいでしょうか。python使いの人は普通はforを使うんでしょうか?

で、ドラッグアンドドロップですが思ったように、結構簡単でした。

self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.onTreeBeginDrag)
self.Bind(wx.EVT_TREE_END_DRAG, self.onTreeEndDrag)
def onTreeBeginDrag(self, event):
    print "treeBeginDrag"
    event.Allow()
    self.dragItem = event.GetItem()

def onTreeEndDrag(self, event):
    print "treeEndDrag"
    src_item = self.dragItem
    target_item = event.GetItem()
    if target_item != None:
        self.get_model().moveNodeToChild(src_item, target_item)
        self.Expand(target_item)

こんな感じです。ただしこれだとドロップすると強制的にドロップ先の子供になってしまうので、

def onTreeEndDrag(self, event):
    print "treeEndDrag"
    src_item = self.dragItem
    target_item = event.GetItem()
    if target_item != None:
        item, flag = self.HitTest(event.GetPoint())
        status = self.__dropPointStatus(flag)
        if status==0:
            self.get_model().moveNodeBefore(src_item, target_item)
        elif status==1:
            self.get_model().moveNodeAfter(src_item, target_item)
        elif status==2:
            self.get_model().moveNodeToChild(src_item, target_item)
        self.Expand(target_item)

という感じで、dropPointStatusという関数を作ってドロップ場所に応じて処理をわけることにしました。しかしこのPointの返すフラグの意味がまだよく分かっていないので、今のところdropPointStatusはこんな感じです。

def __dropPointStatus(self, flag):
    return 2

ここで一旦コミット(Rev.38)。