3

I have a custom GenericTreeModel, that works just fine. Now I want the user to be able to rearrange the nodes using drag and drop, so I move a node to its new parent in the data model. However then, the TreeModel wants to be notified using methods like row_has_child_toggled, row_deleted and row_inserted.

So apparently there is no row_moved and calling row_deleted (for the original path) and row_inserted (for the new path) seems not to be enough. So I thought I may have to recursively issue these changes.

Consider the following example:

* A (0,)
* B (1,)
  * C (1,0)
    * D (1,0,0)

Now, if I move C to A, the following things have happened:

row_delete( (1,0) ) # C
row_delete( (1,0,0) ) # D
row_inserted( (0,0) ) # C'
row_inserted( (0,0,0) ) # D'
child_toggle( (0,) ) # A
child_toggle( (1,) ) # B
child_toggle( (0,1) ) # C'

However, gtk still complains about inconsistent state of the model. Two things come to my mind:

  • maybe the order of calling these functions is relevant (if so any idea how?)
  • technically child_toggle( (1,0) ) also happens, however the row is a) already deleted and b) row_has_child_toggled needs a tree_iter reference, which I can't get as it doesn't exist any more.

Maybe I am following a totally wrong approach here, so what’s the best way to go about this?

gpoo
  • 8,408
  • 3
  • 38
  • 53
rumpel
  • 7,870
  • 2
  • 38
  • 39

2 Answers2

2

Figured it out: Removing a subtree works fine by removing the subtree’s root node row (notify the model that the path is gone and conditionally toggling parent.has_child). Same goes for insertion of a new subtree, so I don't need to tell the model stuff recursively.

However the combination is critical, so

  1. first remove, notify model
  2. then insert and notify model again.
rumpel
  • 7,870
  • 2
  • 38
  • 39
1

IMHO, this update should happen automatically for the treeview, if you connect the treeview correctly with its "drag_data_get" and "drag_data_received" methods AND allows it to be a source and a destination with its "enable_model_drag_dest" and "enable_model_drag_source" methods. There should be nothing more to do for the treeview.

The model must be updated in the calls to its "drag_data_received_data", but there is no "delete" to do, just the specific "insert_before" or "insert_after" as shown here :

   def drag_data_received_data(self, treeview, context, x, y, selection,
                               info, etime):
       model = treeview.get_model()
       data = selection.data
       drop_info = treeview.get_dest_row_at_pos(x, y)
       if drop_info:
           path, position = drop_info
           iter = model.get_iter(path)
           if (position == gtk.TREE_VIEW_DROP_BEFORE
               or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE):
               model.insert_before(iter, [data])
           else:
               model.insert_after(iter, [data])
       else:
           model.append([data])
       if context.action == gtk.gdk.ACTION_MOVE:
           context.finish(True, True, etime)
       return

This snippet comes from :

http://www.pygtk.org/pygtk2tutorial/sec-TreeViewDragAndDrop.html#DragDropReordering

where the program " treeviewdnd.py" works perfectly to show you what you need.

Hope this solves your quest !

Louis
  • 2,854
  • 2
  • 19
  • 24
  • This is true for a gtk.TreeStore, however a gtk.GenericTreeModel does not support the insert_after/before functions. So I’d have to implement them and will be back to my issue unfortunately. – rumpel Sep 06 '11 at 10:04