#include "listmodel_wrapper.h"
#include "gtk_helpers.h"
#include <gtkmm/cellrenderercombo.h>
#include <gtkmm/icontheme.h>


#ifndef NO_MENU_MANAGER
#include "menu_manager.h"
#endif

//#define DEBUG
#undef DEBUG

#ifdef DEBUG
#define dprint(...) fprintf(stderr, __VA_ARGS__)
#else
#define dprint(...)
#endif


//------------------------------------------------------------------------------
Gtk::TreeModel::Path node2path(const ::bec::NodeId& node)
{
  const int depth = node.depth();
  Gtk::TreeModel::Path path;

  for ( int i = 0; i < depth; i++ )
    path.append_index(node[i]);

  return path;
}

//------------------------------------------------------------------------------
ColumnsModel::~ColumnsModel()
{
  std::list<Gtk::TreeModelColumnBase*>::iterator         it = _columns.begin();
  std::list<Gtk::TreeModelColumnBase*>::const_iterator last = _columns.end();

  for ( ; last != it; ++it )
    delete *it;

  _columns.clear();
}

//------------------------------------------------------------------------------
void ColumnsModel::add_bec_index_mapping(const int bec_tm_index)
{
  _ui2bec.push_back(bec_tm_index);
}

//------------------------------------------------------------------------------
int ColumnsModel::ui2bec(const int index_of_ui_column) const
{
  g_assert((size_t)index_of_ui_column < _ui2bec.size());

  return _ui2bec[index_of_ui_column];
}

//------------------------------------------------------------------------------
const StringColumn&
ColumnsModel::set_markup_column(const int          bec_tm_idx
                                ,const bool         editable
                                ,Gtk::IconView     *iv
                                )
{
  // Create columns
  // add mapping from ui to bec
  // add them with add() to the model
  // add columns to the IconView
  // check if editable and bind signals

  Gtk::TreeModelColumn<Glib::ustring> *markup = new Gtk::TreeModelColumn<Glib::ustring>;
  Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > *icon = new Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> >;

  _columns.push_back(markup);
  _columns.push_back(icon);

  add_bec_index_mapping(bec_tm_idx);
  add_bec_index_mapping(bec_tm_idx);

  add(*markup);
  add(*icon);

  iv->set_markup_column(*markup);
  iv->set_pixbuf_column(*icon);

  return *markup;
}


//------------------------------------------------------------------------------
void ColumnsModel::add_tooltip_column(int bec_tm_idx)
{
  Gtk::TreeModelColumn<Glib::ustring> *col = new Gtk::TreeModelColumn<Glib::ustring>;
  add(*col);
  add_bec_index_mapping(-bec_tm_idx); // negative means pick description

  _columns.push_back(col);
}

//------------------------------------------------------------------------------
const IntColumn&
ColumnsModel::append_int_column(const int bec_tm_idx, const std::string& name, const Editable editable)
{
  Gtk::TreeModelColumn<int> *col = new Gtk::TreeModelColumn<int>;

  add(*col);
  add_bec_index_mapping(bec_tm_idx);

  int nr_of_cols;
  if ( editable == EDITABLE )
  {
    nr_of_cols= _treeview->append_column_editable(name, *col);

    Gtk::CellRendererText *cell = (Gtk::CellRendererText*)(_treeview->get_column_cell_renderer(nr_of_cols - 1));
    cell->signal_edited().connect(sigc::bind
                                  (sigc::mem_fun(*_tmw
                                                ,&ListModelWrapper::after_cell_edit<int>
                                                )
                                                , sigc::ref(*col)
                                  )
                                 );
  }
  else
    nr_of_cols= _treeview->append_column(name, *col);

  _treeview->get_column(nr_of_cols-1)->set_resizable(true);

  _columns.push_back(col);

  return *col;
}

//------------------------------------------------------------------------------
const DoubleColumn&
ColumnsModel::append_double_column(const int bec_tm_idx, const std::string& name, const Editable editable)
{
  Gtk::TreeModelColumn<double> *col = new Gtk::TreeModelColumn<double>;
  add_bec_index_mapping(bec_tm_idx);
  add(*col);

  _columns.push_back(col);

  return *col;
}

//------------------------------------------------------------------------------
const StringColumn&
ColumnsModel::append_string_column(const int bec_tm_idx, const std::string& name, const Editable editable, const Iconic have_icon)
{
  Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > *icon= 0;

  Gtk::TreeViewColumn *column= Gtk::manage(new Gtk::TreeViewColumn(name));

  if ( have_icon == WITH_ICON )
  {
    icon = new Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> >;
    add(*icon);
    add_bec_index_mapping(bec_tm_idx);
    column->pack_start(*icon, false);

    _columns.push_back(icon);
  }

  Gtk::TreeModelColumn<Glib::ustring> *col = new Gtk::TreeModelColumn<Glib::ustring>;
  add(*col);
  add_bec_index_mapping(bec_tm_idx);
  column->pack_start(*col);

  _columns.push_back(col);

  int nr_of_cols= _treeview->append_column(*column);
  _treeview->get_column(nr_of_cols-1)->set_resizable(true);

  if (editable == EDITABLE)
  {
    std::vector<Gtk::CellRenderer*> rends= column->get_cell_renderers();

    Gtk::CellRendererText *cell = (Gtk::CellRendererText*)rends[icon ? 1 : 0];
    cell->property_editable()= true;
    cell->signal_edited().connect(sigc::bind
                                  (sigc::mem_fun(*_tmw
                                                ,&ListModelWrapper::after_cell_edit<Glib::ustring>
                                                )
                                                , sigc::ref(*col)
                                  )
                                 );
  }

  return *col;
}

//------------------------------------------------------------------------------
const StringColumn&
ColumnsModel::append_combo_column(const int bec_tm_idx
                                     ,const std::string            &name
                                     ,Glib::RefPtr<Gtk::ListStore>  list_w
                                     ,const Editable                editable
                                     )
{
  Gtk::TreeModelColumn<Glib::ustring> *choosen = new Gtk::TreeModelColumn<Glib::ustring>;
  _columns.push_back(choosen);
  add(*choosen);
  add_bec_index_mapping(bec_tm_idx);

  Gtk::TreeView::Column   *col = Gtk::manage(new Gtk::TreeViewColumn(name));
  Gtk::CellRendererCombo *cell = Gtk::manage(new Gtk::CellRendererCombo);
  col->pack_start(*cell);

  col->add_attribute(cell->property_text(), *choosen);
  cell->property_model() = list_w;
  cell->property_text_column() = 0;
  cell->property_editable() = editable;

  Gtk::TreeModelColumn<Glib::RefPtr<Gtk::TreeModel> > *model_col = new Gtk::TreeModelColumn<Glib::RefPtr<Gtk::TreeModel> >();
  add_bec_index_mapping(bec_tm_idx);
  add(*model_col);
  const int nr_of_cols = _treeview->append_column(*col);

  _columns.push_back(model_col);

  _treeview->get_column(nr_of_cols-1)->set_resizable(true);

  if ( editable == EDITABLE )
  {
    Gtk::CellRendererText *cell = (Gtk::CellRendererText*)(_treeview->get_column_cell_renderer(nr_of_cols - 1));
    cell->signal_edited().connect(sigc::bind
                                    (sigc::mem_fun(*_tmw
                                                  ,&ListModelWrapper::after_cell_edit<Glib::ustring>
                                                  )
                                                  , sigc::ref(*choosen)
                                   )
                                 );
  }

  return *choosen;
}

//------------------------------------------------------------------------------
int
ColumnsModel::append_check_column(const int bec_tm_idx
                                 ,const std::string         &name
                                 ,const Editable             editable
                                 ,const ToggleAction         action
                                 )
{
  Gtk::TreeModelColumn<bool> *col = new Gtk::TreeModelColumn<bool>;
  _columns.push_back(col);
  add(*col);
  add_bec_index_mapping(bec_tm_idx);

  int nr_of_cols;
  // If we have bec_tm_idx set to negative value it means that column added is not
  // directly mapped to a model. Handling of values set/get are done through
  // ListModelWrapper::_fake_column_value_getter/setter slot
  if ( editable == EDITABLE  )
  {
    nr_of_cols= _treeview->append_column_editable(name, *col);

    Gtk::CellRendererToggle *cell = (Gtk::CellRendererToggle*)(_treeview->get_column_cell_renderer(nr_of_cols - 1));
    cell->property_activatable() = true;
    if ( action == TOGGLE_BY_WRAPPER /* && bec_tm_idx >= 0 */)
    {
      cell->signal_toggled().connect(sigc::bind
                                    (sigc::mem_fun(*_tmw
                                                  ,&ListModelWrapper::after_cell_toggle/*<bool>*/
                                                  )
                                                  , sigc::ref(*col)
                                    )
                                    );
    }
  }
  else
    nr_of_cols= _treeview->append_column(name, *col);

  _treeview->get_column(nr_of_cols-1)->set_resizable(true);

  return nr_of_cols;
}

//------------------------------------------------------------------------------

int ColumnsModel::add_generic_column(const int bec_tm_idx, Gtk::TreeModelColumnBase *column,
                                     Gtk::TreeViewColumn *vcolumn)
{
  add(*column);
  add_bec_index_mapping(bec_tm_idx);

  return _treeview->append_column(*vcolumn);
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
ListModelWrapper::ListModelWrapper(bec::ListModel* tm, Gtk::TreeView *treeview, const std::string& name)
                    : Glib::ObjectBase(typeid(ListModelWrapper))
                    , Glib::Object()
                    , Gtk::TreeModel()
                    , _tm(tm)
                    , _treeview(treeview)
                    , _iconview(0)
                    , _stamp(1)
                    , _columns(this, treeview)
                    , _icon_size(bec::Icon16)
                    , _name(name)
{
  tm->tree_changed_signal().connect(sigc::mem_fun(*this, &::ListModelWrapper::model_changed));
  #ifndef NO_MENU_MANAGER
  if (_treeview)
    _treeview->signal_event().connect(sigc::mem_fun(this, &ListModelWrapper::handle_popup_event));
  #endif
}

ListModelWrapper::~ListModelWrapper()
{
}

void ListModelWrapper::set_iconview(Gtk::IconView* iv)
{
  _iconview = iv;
  #ifndef NO_MENU_MANAGER
  if (_iconview)
    _iconview->signal_event().connect(sigc::mem_fun(this, &ListModelWrapper::handle_popup_event));
  #endif
}

ListModelWrapper::NodeIdArray ListModelWrapper::get_selection() const
{
  NodeIdArray nodes;

  if (_treeview)
  {
    const std::vector<Gtk::TreePath> paths = _treeview->get_selection()->get_selected_rows();
    const int size = paths.size();
    nodes.reserve(size);
    for (int i = 0; i < size; ++i)
      nodes.push_back(get_node_for_path(paths[i]));
  }
  else if (_iconview)
  {
    const std::vector<Gtk::TreePath> paths = _iconview->get_selected_items();
    const int size = paths.size();
    nodes.reserve(size);
    for (int i = 0; i < size; ++i)
      nodes.push_back(get_node_for_path(paths[i]));
  }
  
  return nodes;
}

#ifndef NO_MENU_MANAGER
void ListModelWrapper::handle_popup(const int x, const int y, const int time)
{
  Gtk::TreeModel::Path   path;
  Gtk::TreeView::Column *column(0);
  int                    cell_x(-1);
  int                    cell_y(-1);

  ListModelWrapper::NodeIdArray list = get_selection();

  bool there_is_path_at_pos = false;
  if (_treeview)
    there_is_path_at_pos = _treeview->get_path_at_pos(x, y, path, column, cell_x, cell_y);
  else if (_iconview)
  {
    path = _iconview->get_path_at_pos(x, y);
    there_is_path_at_pos = path.gobj() && !path.empty();
  }
  
  if ( there_is_path_at_pos )
  {
    // Check that popup is requested on selection, otherwise unselect all and select
    // path_at_pos
    bec::NodeId node = get_node_for_path(path);
    // list stores current selection
    bool path_at_pos_is_in_selection = false;
    for (int i = list.size() - 1; i >= 0; --i)
    {
      if (node == list[i])
      {
        path_at_pos_is_in_selection = true;
        break;
      }
    }

    // If path is not in current selection unselect old selection and
    // select path at pos 
    if (!path_at_pos_is_in_selection)
    {
      if (_treeview)
      {
        _treeview->get_selection()->unselect_all();
        _treeview->get_selection()->select(path);
        // update list of selected nodes as well
      }
      else if (_iconview)
      {
        _iconview->unselect_all();
        _iconview->select_path(path);
      }

      list.clear();
      list.push_back(node);
    }

  }

  MenuManager::run_and_forward_action(_tm->get_popup_items_for_nodes(list), x, y, time, _tm, list, _fe_menu_handler);
}

bool ListModelWrapper::handle_popup_event(GdkEvent* event)
{
  bool ret = false;
  if ( event->type == GDK_BUTTON_PRESS && event->button.button == 3 )
  {
    handle_popup((int)event->button.x, (int)event->button.y, event->button.time);
    // Return true to preserve selection. In handle_popup check that popup is requested
    // on selection.
    ret = true;
  }
  return ret;
}
#endif

Gtk::TreeModelFlags ListModelWrapper::get_flags_vfunc() const
{
  return Gtk::TREE_MODEL_ITERS_PERSIST | Gtk::TREE_MODEL_LIST_ONLY;
}

bec::NodeId ListModelWrapper::get_node_for_path(const Gtk::TreeModel::Path &path) const
{
  return bec::NodeId(path.to_string());
}

//------------------------------------------------------------------------------
bool ListModelWrapper::init_gtktreeiter(GtkTreeIter *it, const bec::NodeId &node) const throw()
{
  if ( _tm && it && node.is_valid() )
  {
    it->stamp      = _stamp;
    it->user_data  = _tm;
    it->user_data2 = _tm->nodeid_to_uid(node);
  }
  return it && node.is_valid();
}


bec::NodeId ListModelWrapper::node_for_iter(const iterator &iter) const throw()
{
  const GtkTreeIter* it = iter.gobj();
  bec::ListModel   *tm = reinterpret_cast<bec::ListModel*>(it->user_data);
  bec::NodeId::uid uid = reinterpret_cast<bec::NodeId::uid>(it->user_data2);

  if ( tm && tm == _tm && uid )
  {
    if (it->stamp == _stamp)
      return bec::NodeId(tm->nodeuid_to_path(uid));
    else
      g_warning("reference to invalid iter in grt list/tree model");
  }
  return bec::NodeId();
}

//------------------------------------------------------------------------------
void ListModelWrapper::refresh()
{
  if (_tm) _tm->refresh();
  model_changed();
}

//------------------------------------------------------------------------------
void ListModelWrapper::set_fake_column_value_getter(FakeColumnValueGetter fake_getter)
{
  _fake_column_value_getter = fake_getter;
}

//------------------------------------------------------------------------------
void ListModelWrapper::set_fake_column_value_setter(FakeColumnValueSetter fake_setter)
{
  _fake_column_value_setter = fake_setter;
}

//------------------------------------------------------------------------------
void ListModelWrapper::reset_iter(iterator& iter) const throw()
{
  GtkTreeIter *it = iter.gobj();
  it->stamp = 0;
  it->user_data = it->user_data2 = 0;
}

//------------------------------------------------------------------------------
int ListModelWrapper::get_n_columns_vfunc() const
{
  return _columns.size();
}

//------------------------------------------------------------------------------
GType ListModelWrapper::get_column_type_vfunc(int index) const
{
  return *(_columns.types() + index);
}

//------------------------------------------------------------------------------
bool ListModelWrapper::iter_next_vfunc(const iterator& iter, iterator& iter_next) const
{
  bool ret = false;
  bec::NodeId current_node= node_for_iter(iter);

  //g_message("LMW::iter_next_vfunc: %s", _name.c_str());

  // Invalidate iter_next
  reset_iter(iter_next);

  if (_tm)
  {
    if (current_node.is_valid() && _tm->has_next(current_node))
    {
      try
      {
        // Obtain parent of the current node to get number of children of the parent node
        current_node = _tm->get_next(current_node);
      }
      catch (...)
      {
        current_node= bec::NodeId();
      }
      // Check if the resulted nodeid is valid and setup iter_next with values pointing to the nodeid
      if ( current_node.is_valid() )
        ret = init_gtktreeiter(iter_next.gobj(), current_node);
    }
  }
  return ret;
}

//------------------------------------------------------------------------------
bool ListModelWrapper::get_iter_vfunc(const Path& path, iterator& iter) const
{
  bool ret = false;
  GtkTreeIter* it = iter.gobj();

  // Invalidate iter_next
  reset_iter(iter);

  if (_tm)
  {
    bec::NodeId node(path.to_string());

    if ( node.is_valid() && node.back() < _tm->count() )
      ret = init_gtktreeiter(it, node);
  }
  return ret;
}

//------------------------------------------------------------------------------
bool ListModelWrapper::iter_children_vfunc(const iterator& parent, iterator& iter) const
{
  return false;
}

//------------------------------------------------------------------------------
bool ListModelWrapper::iter_parent_vfunc(const iterator& child, iterator& iter) const
{
  return false;
}

//------------------------------------------------------------------------------
bool ListModelWrapper::iter_nth_child_vfunc(const iterator& parent, int n, iterator& iter) const
{
  return false;
}

//------------------------------------------------------------------------------
bool ListModelWrapper::iter_nth_root_child_vfunc(int n, iterator& iter) const
{
  bool ret = false;
  //Sets @a iter to be the child of at the root level using the given index.  The first
  //index is 0.  If @a n is too big, or if there are no children, @a iter is set
  //to an invalid iterator and false is returned.
  //See also iter_nth_child_vfunc().
  if ( _tm && n >= 0 && n < iter_n_root_children_vfunc() )
  {
    bec::NodeId node = _tm->get_node(n);
    init_gtktreeiter(iter.gobj(), node);
    ret = true;
  }

  return ret;
}

//------------------------------------------------------------------------------
bool ListModelWrapper::iter_has_child_vfunc(const iterator& iter) const
{
  return iter_n_children_vfunc(iter) != 0;
}

//------------------------------------------------------------------------------
int ListModelWrapper::iter_n_children_vfunc(const iterator& iter) const
{
  return 0;
}

//------------------------------------------------------------------------------
int ListModelWrapper::iter_n_root_children_vfunc() const
{
  const int ret = _tm ? _tm->count() : 0;
  return ret;
}

//------------------------------------------------------------------------------
Gtk::TreeModel::Path ListModelWrapper::get_path_vfunc(const iterator& iter) const
{
  const bec::NodeId node = node_for_iter(iter);
  Gtk::TreeModel::Path path;

  if ( node.is_valid() )
  {
    const int node_depth = node.depth();

    for ( int i = 0; i < node_depth; i++ )
      path.push_back(node[i]);
  }

  return path;
}


void ListModelWrapper::get_icon_value(const iterator& iter, int column, const bec::NodeId &node, Glib::ValueBase& value) const
{
  if (!_tm)
    return;

  static ImageCache       *pixbufs      =  ImageCache::get_instance();
  static Glib::RefPtr<Gtk::IconTheme> icon_theme= Gtk::IconTheme::get_default();
  GValue *gval = value.gobj();

  bec::IconId               icon_id = _tm->get_field_icon(node, column, get_icon_size());

  g_value_init(gval, GDK_TYPE_PIXBUF);
  if (icon_id != 0)
  {
    Glib::RefPtr<Gdk::Pixbuf>  pixbuf = pixbufs->image(icon_id);

    if ( pixbuf )
    {
      g_value_set_object(gval, pixbuf->gobj());
    }
  }
}

//------------------------------------------------------------------------------
void ListModelWrapper::get_value_vfunc(const iterator& iter, int column, Glib::ValueBase& value) const
{
  if (!_tm)
    return;

  bec::NodeId node= node_for_iter(iter);

  if ( node.is_valid() )
  {
    const GType type = *(_columns.types() + column);

    column = _columns.ui2bec(column);

    if ( column < 0 )
    {
      if ( !_fake_column_value_getter.empty() )
        _fake_column_value_getter(iter, column, value);
    }
    else if ( type == GDK_TYPE_PIXBUF )
    {
      get_icon_value(iter, column, node, value);
    }
    else
    {
      switch ( type )
      {
      case G_TYPE_BOOLEAN:
        {
          bool bv = false;
          _tm->get_field(node, column, bv);
          set_glib_bool(value, bv);
          dprint("LMW::get_value_vfunc: %s: node %s, col %i: value: %i\n", _name.c_str(), node.repr().c_str(), column, bv);
          break;
        }
      case G_TYPE_INT:
      case G_TYPE_UINT:
        {
          int iv = 0;
          _tm->get_field(node, column, iv);
          set_glib_int(value, iv);
          dprint("LMW::get_value_vfunc: %s: node %s, col %i: value: %i\n", _name.c_str(), node.repr().c_str(), column, iv);
          break;
        }
      case G_TYPE_LONG:
      case G_TYPE_ULONG:
      case G_TYPE_INT64:
      case G_TYPE_UINT64:
        {
          throw std::logic_error("Imlement long ints in get_value_func");
          break;
        }
      case G_TYPE_FLOAT:
      case G_TYPE_DOUBLE:
        {
          double dv = 0.0;
          _tm->get_field(node, column, dv);
          set_glib_double(value, dv);
          dprint("LMW::get_value_vfunc: %s: node %s, col %i: value: %f\n", _name.c_str(), node.repr().c_str(), column, dv);
          break;
        }
      case G_TYPE_STRING:
        {
          std::string sv;
          if (column < 0)
            sv= _tm->get_field_description(node, -column);
          else
            _tm->get_field(node, column, sv);
          set_glib_string(value, sv);
          dprint("LMW::get_value_vfunc: %s: node %s, col %i: value: '%s'\n", _name.c_str(), node.repr().c_str(), column, sv.c_str());
          break;
        }
      default:
        set_glib_string(value, "<unkn>");
        break;
      }
    }
  }
}

//------------------------------------------------------------------------------
bool ListModelWrapper::iter_is_valid(const iterator& iter) const
{
  bec::NodeId node(node_for_iter(iter));

  return node.is_valid();
}

//------------------------------------------------------------------------------
void ListModelWrapper::set_value_impl(const iterator& row, int column, const Glib::ValueBase& value)
{
  if (!_tm)
    return;

  bec::NodeId node(node_for_iter(row));

  if ( node.is_valid() )
  {
    const GType type = *(_columns.types() + column);
    column = _columns.ui2bec(column);

    if ( column < 0 )
    {
      if ( !_fake_column_value_setter.empty() )
        _fake_column_value_setter(row, column, value);
    }
    else
    {
      switch ( type )
      {
      case G_TYPE_BOOLEAN:
        {
          Glib::Value<bool>   v;
          v.init(value.gobj());
          dprint("LMW::set_value_impl:%s node %s, column %i, value %i\n", _name.c_str(), node.repr().c_str(), column, v.get());
          _tm->set_field(node, column, v.get());
          break;
        }
      case G_TYPE_INT:
      case G_TYPE_UINT:
        {
          Glib::Value<int>   v;
          v.init(value.gobj());
          dprint("LMW::set_value_impl: node %s, column %i, value %i\n", node.repr().c_str(), column, v.get());
          _tm->set_field(node, column, v.get());
          break;
        }
      case G_TYPE_FLOAT:
      case G_TYPE_DOUBLE:
        {
          Glib::Value<double>  v;
          v.init(value.gobj());
          _tm->set_field(node, column, v.get());
          break;
        }
      case G_TYPE_STRING:
        {
          Glib::Value<std::string>   v;
          v.init(value.gobj());
          _tm->set_field(node, column, v.get());
          dprint("LMW::set_value: %s '%s'\n", _name.c_str(), v.get().c_str());
          break;
        }
      default:
        break;
      }
    }
  }
}

//------------------------------------------------------------------------------
void ListModelWrapper::get_value_impl(const iterator& row, int column, Glib::ValueBase& value) const
{
  get_value_vfunc(row, column, value);
}


void ListModelWrapper::set_row_draggable_slot(const sigc::slot<bool, Gtk::TreeModel::Path> &slot)
{
  _row_draggable= slot;
}

bool ListModelWrapper::drag_data_get_vfunc(const Gtk::TreeModel::Path& path, Gtk::SelectionData& selection_data) const
{
  selection_data.set("text/path", path.to_string());
  return true;
}

bool ListModelWrapper::drag_data_delete_vfunc (const Gtk::TreeModel::Path& path)
{
  return true;
}

bool ListModelWrapper::row_draggable_vfunc(const TreeModel::Path &path) const
{
  if (_row_draggable)
    return _row_draggable(path);

  return true;
}

bool ListModelWrapper::row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& selection_data) const
{
  return true;
}

bool ListModelWrapper::drag_data_received_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& selection_data)
{
  bool ret = false;
  // Currently this works for linear lists
  try
  {
    _tm->reorder(bec::NodeId((const char*)selection_data.get_data()), dest.front());
    ret = true;
  }
  catch (const std::logic_error& e)
  {}
  return ret;
}
