Re: Enable drag and drop for treeview?



Jef Driesen wrote:
Paul Davis wrote:
On 5/2/07, Jef Driesen <jefdriesen hotmail com> wrote:
For my application, I want to be able to re-order rows in a treeview
(treestore model) using drag and drop. According to the gtkmm book, I
can use set_reorderable(). But how can I detect when a drag and drop
operation is finished (to update the underlying database)? I can't find
any signals to connect to. Am I missing something?
I think to do this, you have to subclass Gtk::TreeModel and override
Gtk::TreeDragDest::drag_data_received_vfunc()

I did something similar here:
http://trac.lsdcas.engineering.uiowa.edu/browser/trunk/cas2/plugins/viewer/event_analysis/treemodel.hh
http://trac.lsdcas.engineering.uiowa.edu/browser/trunk/cas2/plugins/viewer/event_analysis/treemodel.cc

There's also an example in the book about doing this stuff which is
what I based my implementation on:

http://www.gtkmm.org/docs/gtkmm-2.4/examples/book/treeview/drag_and_drop/

Does this method also work well with a sorted treemodel? Because the simple set_reorderable() does not seem to work in that case. Once the model is sorted (by clicking on a treeview column header), drag and drop is not possible anymore.

I tried that approach and the row_drop_possible_vfunc is not very difficult. I ported the default gtk function to gtkmm, disabled the check for the sorting and added some extra constraints (see code below). But I'm having problems with implementing drag_data_received_vfunc, because there is no gtk_tree_store_copy function. And I can't easily re-use the existing code from gtk+ because it depends on the treestore (private) internals. Any suggestions?

The changes that are required to make my custom dnd work with a sorted treestore is not very complicated (I think). Instead of adding the row to a specific location (using gtk_tree_store_prepend or gtk_tree_store_insert_after) I would have to add it to a parent. Because if you do that, the row is automatically sorted, and that is exactly what I need.

While testing, I also found some very strange behavior for the row_drop_possible_vfunc. If you have this very simple treestore:

Item 0
Item 1
Item 2

and try to drop item 0 between item 1 and 2, the path passed to the function is 2, as I expected. But if you drop after item 2, the path is also 2. But once you drop the item there, drag_data_received_vfunc receives the path 3. Shouldn't row_drop_possible_vfunc also receive the path 3?

bool
DndTreeStore::row_drop_possible_vfunc (const Gtk::TreeModel::Path& dest_path, const Gtk::SelectionData& selection_data) const
{
   // don't accept drops if the tree has been sorted
   /*if (GTK_TREE_STORE_IS_SORTED (this))
      return false;*/

   Glib::RefPtr<Gtk::TreeModel> src_model;
   Gtk::TreePath src_path;
   if (!Gtk::TreePath::get_from_selection_data (selection_data,
         src_model,
         src_path))
      return false;

   // can only drag to ourselves
   /*if (src_model != GTK_TREE_MODEL (this))
      return false;*/

    // Can't drop into ourself.
   if (src_path.is_ancestor (dest_path))
      return false;

   // Can't drop if dest_path's parent doesn't exist
   if (dest_path.get_depth() > 1) {
      Gtk::TreePath tmp = dest_path; tmp.up();

      if (!((Gtk::TreeStore*)this)->get_iter (tmp))
           return false;
   }

   // Can't drop into to the same parent.
   if (dnd_equal_parent(src_path, dest_path))
      return false;

   // Allow new parent only
   if (dest_path.back() != 0)
      return false;

   // Can otherwise drop anywhere.
   return true;
}

static bool
dnd_equal_parent (const Gtk::TreeModel::Path& src, const Gtk::TreeModel::Path& dst)
{
   // Paths with a different depth never have the same parent.
   if (src.size() != dst.size())
      return false;

   // Top-level paths always have the same parent.
   // Note: There is no need to check both depths,
   // because they are always equal at this point.
   if (src.size() == 1)
      return true;

   // Compare parent paths for all other cases.
   Gtk::TreeModel::Path src_parent = src; src_parent.up();
   Gtk::TreeModel::Path dst_parent = dst; dst_parent.up();
   return (src_parent == dst_parent);
}




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]