// -*- c++ -*- /* $Id: treemodel.ccg,v 1.13 2006/05/11 11:40:24 murrayc Exp $ */ /* Copyright 1998-2002 The gtkmm Development Team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include namespace { static gboolean proxy_foreach_iter_callback(GtkTreeModel* model, GtkTreePath*, GtkTreeIter* iter, void* data) { typedef Gtk::TreeModel::SlotForeachIter SlotType; SlotType& slot = *static_cast(data); #ifdef GLIBMM_EXCEPTIONS_ENABLED try { #endif //GLIBMM_EXCEPTIONS_ENABLED return slot(Gtk::TreeModel::iterator(model, iter)); #ifdef GLIBMM_EXCEPTIONS_ENABLED } catch(...) { Glib::exception_handlers_invoke(); } #endif //GLIBMM_EXCEPTIONS_ENABLED return 1; } static gboolean proxy_foreach_path_callback(GtkTreeModel*, GtkTreePath* path, GtkTreeIter*, void* data) { typedef Gtk::TreeModel::SlotForeachPath SlotType; SlotType& slot = *static_cast(data); #ifdef GLIBMM_EXCEPTIONS_ENABLED try { #endif //GLIBMM_EXCEPTIONS_ENABLED return slot(Gtk::TreeModel::Path(path, true)); #ifdef GLIBMM_EXCEPTIONS_ENABLED } catch(...) { Glib::exception_handlers_invoke(); } #endif //GLIBMM_EXCEPTIONS_ENABLED return 1; } static gboolean proxy_foreach_path_and_iter_callback(GtkTreeModel* model, GtkTreePath* path, GtkTreeIter* iter, void* data) { typedef Gtk::TreeModel::SlotForeachPathAndIter SlotType; SlotType& slot = *static_cast(data); #ifdef GLIBMM_EXCEPTIONS_ENABLED try { #endif //GLIBMM_EXCEPTIONS_ENABLED return slot(Gtk::TreeModel::Path(path, true), Gtk::TreeModel::iterator(model, iter)); #ifdef GLIBMM_EXCEPTIONS_ENABLED } catch(...) { Glib::exception_handlers_invoke(); } #endif //GLIBMM_EXCEPTIONS_ENABLED return 1; } } //anonymous namespace //Help the code generator, so that it doesn't have to fully qualify this type: typedef Gtk::TreeModel::iterator iterator; namespace Gtk { TreeModel::iterator TreeModel::get_iter(const Path& path) { Gtk::TreeModel::iterator iter(this); gtk_tree_model_get_iter(gobj(), iter.gobj(), const_cast(path.gobj())); return iter; } TreeModel::iterator TreeModel::get_iter(const Glib::ustring& path_string) { Gtk::TreeModel::iterator iter (this); gtk_tree_model_get_iter_from_string(gobj(), iter.gobj(), path_string.c_str()); return iter; } TreeModel::Children TreeModel::children() { return TreeNodeChildren(this); } TreeModel::Children TreeModel::children() const { //TODO: Remove the const when we have a real const TreeNodeChildren, when we have a real const_iterator. return TreeNodeChildren(const_cast(this)); } void TreeModel::set_value_impl(const iterator&, int, const Glib::ValueBase&) { g_assert_not_reached(); } void TreeModel::get_value_impl(const iterator& row, int column, Glib::ValueBase& value) const { gtk_tree_model_get_value( const_cast(gobj()), const_cast(row.gobj()), column, value.gobj()); } void TreeModel::foreach_iter(const SlotForeachIter& slot) { SlotForeachIter slot_copy (slot); gtk_tree_model_foreach(gobj(), &proxy_foreach_iter_callback, &slot_copy); } void TreeModel::foreach_path(const SlotForeachPath& slot) { SlotForeachPath slot_copy (slot); gtk_tree_model_foreach(gobj(), &proxy_foreach_path_callback, &slot_copy); } void TreeModel::foreach(const SlotForeachPathAndIter& slot) { SlotForeachPathAndIter slot_copy (slot); gtk_tree_model_foreach(gobj(), &proxy_foreach_path_and_iter_callback, &slot_copy); } bool TreeModel::iter_is_valid(const iterator& iter) const { //This method is overriden in TreeStore and ListStore. //This implementation will only be used as a default for custom derived TreeModels, //and when we wrap a C GtkTreeModel with a Gtk::TreeModel instance, without knowing what derived C type it is. // This check is almost the same as the private VALID_ITER() macro in gtkliststore.c and // gtktreestore.c. return (!iter.is_end_ && iter.gobj()->stamp != 0); } #ifdef GLIBMM_VFUNCS_ENABLED // Custom vfunc callbacks, because the C++ vfuncs have different parameters and return types // that can not be generated automatically: gboolean TreeModel_Class::iter_next_vfunc_callback(GtkTreeModel* self, GtkTreeIter* iter) { CppObjectType *const obj = dynamic_cast( Glib::ObjectBase::_get_current_wrapper((GObject*)self)); // Non-gtkmmproc-generated custom classes implicitly call the default // Glib::ObjectBase constructor, which sets is_derived_. But gtkmmproc- // generated classes can use this optimisation, which avoids the unnecessary // parameter conversions if there is no possibility of the virtual function // being overridden: if(obj && obj->is_derived_()) { #ifdef GLIBMM_EXCEPTIONS_ENABLED try // Trap C++ exceptions which would normally be lost because this is a C callback. { #endif //GLIBMM_EXCEPTIONS_ENABLED // Call the virtual member method, which derived classes might override. TreeModel::iterator iter_input = TreeModel::iterator(self, iter); TreeModel::iterator iter_next( self, iter ); //Copies iter by value. gboolean test = obj->iter_next_vfunc(iter_input, iter_next); //Copy the new iter value to the C output parameter: if(test) *iter = *(iter_next.gobj()); return test; #ifdef GLIBMM_EXCEPTIONS_ENABLED } catch(...) { Glib::exception_handlers_invoke(); } #endif //GLIBMM_EXCEPTIONS_ENABLED } else { BaseClassType *const base = static_cast( g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface). g_type_interface_peek(G_OBJECT_GET_CLASS(self), CppObjectType::get_type()) // Get the interface. ) ); // Call the original underlying C function: if(base && base->iter_next) return (*base->iter_next)(self, iter); } typedef gboolean RType; return RType(); } bool TreeModel::iter_next_vfunc(const iterator& iter, iterator& iter_next) const { //Call the default C implementation: BaseClassType *const base = static_cast( g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface). g_type_interface_peek(G_OBJECT_GET_CLASS(gobject_), CppObjectType::get_type()) // Get the interface. ) ); if(base && base->iter_next) { TreeModel::iterator iter_copy = iter; gboolean test = (*base->iter_next)(const_cast(gobj()), iter_copy.gobj()); if(test) iter_next = iter_copy; return test; } return bool(); } gboolean TreeModel_Class::get_iter_vfunc_callback(GtkTreeModel* self, GtkTreeIter* iter, GtkTreePath* path) { CppObjectType *const obj = dynamic_cast( Glib::ObjectBase::_get_current_wrapper((GObject*)self)); // Non-gtkmmproc-generated custom classes implicitly call the default // Glib::ObjectBase constructor, which sets is_derived_. But gtkmmproc- // generated classes can use this optimisation, which avoids the unnecessary // parameter conversions if there is no possibility of the virtual function // being overridden: if(obj && obj->is_derived_()) { #ifdef GLIBMM_EXCEPTIONS_ENABLED try // Trap C++ exceptions which would normally be lost because this is a C callback. { #endif //GLIBMM_EXCEPTIONS_ENABLED // Call the virtual member method, which derived classes might override. Gtk::TreeModel::iterator iter_out(self, iter); //copies the iter by value. gboolean test = obj->get_iter_vfunc(Gtk::TreePath(path, true), iter_out); //Copy the new iter value to the C output parameter: if(test) *iter = *(iter_out.gobj()); return test; #ifdef GLIBMM_EXCEPTIONS_ENABLED } catch(...) { Glib::exception_handlers_invoke(); } #endif //GLIBMM_EXCEPTIONS_ENABLED } else { BaseClassType *const base = static_cast( g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface). g_type_interface_peek(G_OBJECT_GET_CLASS(self), CppObjectType::get_type()) // Get the interface. ) ); // Call the original underlying C function: if(base && base->get_iter) return (*base->get_iter)(self, iter, const_cast(path)); } typedef gboolean RType; return RType(); } bool TreeModel::get_iter_vfunc(const Path& path, iterator& iter) const { //Call the default C implementation: BaseClassType *const base = static_cast( g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface). g_type_interface_peek(G_OBJECT_GET_CLASS(gobject_), CppObjectType::get_type()) // Get the interface. ) ); if(base && base->get_iter) { return (*base->get_iter)( const_cast(gobj()), iter.gobj(), const_cast(path.gobj()) ); } return bool(); } gboolean TreeModel_Class::iter_children_vfunc_callback(GtkTreeModel* self, GtkTreeIter* iter, GtkTreeIter* parent) { CppObjectType *const obj = dynamic_cast( Glib::ObjectBase::_get_current_wrapper((GObject*)self)); // Non-gtkmmproc-generated custom classes implicitly call the default // Glib::ObjectBase constructor, which sets is_derived_. But gtkmmproc- // generated classes can use this optimisation, which avoids the unnecessary // parameter conversions if there is no possibility of the virtual function // being overridden: if(obj && obj->is_derived_()) { #ifdef GLIBMM_EXCEPTIONS_ENABLED try // Trap C++ exceptions which would normally be lost because this is a C callback. { #endif //GLIBMM_EXCEPTIONS_ENABLED // Call the virtual member method, which derived classes might override. Gtk::TreeModel::iterator iter_out(self, iter); //copies the iter by value. gboolean test = false; if(!parent) { //Deal with this case, which is documented in the C docs as: //" If @parent is %NULL returns the first node, equivalent to // gtk_tree_model_get_iter_first (tree_model, iter); " test = obj->iter_nth_root_child_vfunc(0, iter_out); } else { //Normal case: Gtk::TreeModel::iterator parent_cpp(self, parent); test = obj->iter_children_vfunc(parent_cpp, iter_out); } //Copy the new iter value to the C output parameter: if(test) *iter = *(iter_out.gobj()); return test; #ifdef GLIBMM_EXCEPTIONS_ENABLED } catch(...) { Glib::exception_handlers_invoke(); } #endif //GLIBMM_EXCEPTIONS_ENABLED } else { BaseClassType *const base = static_cast( g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface). g_type_interface_peek(G_OBJECT_GET_CLASS(self), CppObjectType::get_type()) // Get the interface. ) ); // Call the original underlying C function: if(base && base->iter_children) return (*base->iter_children)(self, iter, parent); } typedef gboolean RType; return RType(); } bool TreeModel::iter_children_vfunc(const iterator& parent, iterator& iter) const { //Call the default C implementation: BaseClassType *const base = static_cast( g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface). g_type_interface_peek(G_OBJECT_GET_CLASS(gobject_), CppObjectType::get_type()) // Get the interface. ) ); if(base && base->iter_children) { return (*base->iter_children)( const_cast(gobj()), iter.gobj(), const_cast(parent.gobj()) ); } return bool(); } gboolean TreeModel_Class::iter_parent_vfunc_callback(GtkTreeModel* self, GtkTreeIter* iter, GtkTreeIter* child) { CppObjectType *const obj = dynamic_cast( Glib::ObjectBase::_get_current_wrapper((GObject*)self)); // Non-gtkmmproc-generated custom classes implicitly call the default // Glib::ObjectBase constructor, which sets is_derived_. But gtkmmproc- // generated classes can use this optimisation, which avoids the unnecessary // parameter conversions if there is no possibility of the virtual function // being overridden: if(obj && obj->is_derived_()) { #ifdef GLIBMM_EXCEPTIONS_ENABLED try // Trap C++ exceptions which would normally be lost because this is a C callback. { #endif //GLIBMM_EXCEPTIONS_ENABLED // Call the virtual member method, which derived classes might override. Gtk::TreeModel::iterator iter_out(self, iter); Gtk::TreeModel::iterator child_cpp(self, child); gboolean test = obj->iter_parent_vfunc(child_cpp, iter_out); //Copy the new iter value to the C output parameter: if(test) *iter = *(iter_out.gobj()); return test; #ifdef GLIBMM_EXCEPTIONS_ENABLED } catch(...) { Glib::exception_handlers_invoke(); } #endif //GLIBMM_EXCEPTIONS_ENABLED } else { BaseClassType *const base = static_cast( g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface). g_type_interface_peek(G_OBJECT_GET_CLASS(self), CppObjectType::get_type()) // Get the interface. ) ); // Call the original underlying C function: if(base && base->iter_parent) return (*base->iter_parent)(self, iter, child); } typedef gboolean RType; return RType(); } bool TreeModel::iter_parent_vfunc(const iterator& child, iterator& iter) const { //Call the default C implementation: BaseClassType *const base = static_cast( g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface). g_type_interface_peek(G_OBJECT_GET_CLASS(gobject_), CppObjectType::get_type()) // Get the interface. ) ); if(base && base->iter_parent) { return (*base->iter_parent)( const_cast(gobj()), iter.gobj(), const_cast(child.gobj()) ); } return bool(); } gboolean TreeModel_Class::iter_nth_child_vfunc_callback(GtkTreeModel* self, GtkTreeIter* iter, GtkTreeIter* parent, int n) { CppObjectType *const obj = dynamic_cast( Glib::ObjectBase::_get_current_wrapper((GObject*)self)); // Non-gtkmmproc-generated custom classes implicitly call the default // Glib::ObjectBase constructor, which sets is_derived_. But gtkmmproc- // generated classes can use this optimisation, which avoids the unnecessary // parameter conversions if there is no possibility of the virtual function // being overridden: if(obj && obj->is_derived_()) { #ifdef GLIBMM_EXCEPTIONS_ENABLED try // Trap C++ exceptions which would normally be lost because this is a C callback. { #endif //GLIBMM_EXCEPTIONS_ENABLED // Call the virtual member method, which derived classes might override. Gtk::TreeModel::iterator iter_out(self, iter); gboolean test = false; if(!parent) { // Deal with this special case, docuemnted in the C docs as: // "As a special case, if @parent is %NULL, then the nth root node is set.": test = obj->iter_nth_root_child_vfunc(n, iter_out); } else { //The normal case: Gtk::TreeModel::iterator parent_cpp(self, parent); test = obj->iter_nth_child_vfunc(parent_cpp, n, iter_out); } //Copy the new iter value to the C output parameter: if(test) *iter = *(iter_out.gobj()); return test; #ifdef GLIBMM_EXCEPTIONS_ENABLED } catch(...) { Glib::exception_handlers_invoke(); } #endif //GLIBMM_EXCEPTIONS_ENABLED } else { BaseClassType *const base = static_cast( g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface). g_type_interface_peek(G_OBJECT_GET_CLASS(self), CppObjectType::get_type()) // Get the interface. ) ); // Call the original underlying C function: if(base && base->iter_nth_child) return (*base->iter_nth_child)(self, iter, parent, n); } typedef gboolean RType; return RType(); } bool TreeModel::iter_nth_child_vfunc(const iterator& parent, int n, iterator& iter) const { //Call the default C implementation: BaseClassType *const base = static_cast( g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface). g_type_interface_peek(G_OBJECT_GET_CLASS(gobject_), CppObjectType::get_type()) // Get the interface. ) ); if(base && base->iter_nth_child) { return (*base->iter_nth_child)( const_cast(gobj()), iter.gobj(), const_cast(parent.gobj()), n ); } return bool(); } //See the implementation of iter_children_vfunc_callback() and iter_nth_child_vfunc_callback() //to find out why this virtual function exists: bool TreeModel::iter_nth_root_child_vfunc(int n, iterator& iter) const { //Call the default C implementation: BaseClassType *const base = static_cast( g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface). g_type_interface_peek(G_OBJECT_GET_CLASS(gobject_), CppObjectType::get_type()) // Get the interface. ) ); if(base && base->iter_nth_child) { //This means that iter_nth_child(0) might be called by iter_children_vfunc_callback(), //but hopefully that's exactly the same thing. TODO: Ask why both vfuncs exist. murrayc. return (*base->iter_nth_child)( const_cast(gobj()), iter.gobj(), 0 /* the null parent */, n ); } return bool(); } gboolean TreeModel_Class::iter_n_children_vfunc_callback(GtkTreeModel* self, GtkTreeIter* iter) { CppObjectType *const obj = dynamic_cast( Glib::ObjectBase::_get_current_wrapper((GObject*)self)); // Non-gtkmmproc-generated custom classes implicitly call the default // Glib::ObjectBase constructor, which sets is_derived_. But gtkmmproc- // generated classes can use this optimisation, which avoids the unnecessary // parameter conversions if there is no possibility of the virtual function // being overridden: if(obj && obj->is_derived_()) { #ifdef GLIBMM_EXCEPTIONS_ENABLED try // Trap C++ exceptions which would normally be lost because this is a C callback. { #endif //GLIBMM_EXCEPTIONS_ENABLED // Call the virtual member method, which derived classes might override. //Deal with the case that iter is null, as described in the C docs: if(iter) return obj->iter_n_children_vfunc( Gtk::TreeModel::iterator(self, iter) ); else return obj->iter_n_root_children_vfunc(); #ifdef GLIBMM_EXCEPTIONS_ENABLED } catch(...) { Glib::exception_handlers_invoke(); } #endif //GLIBMM_EXCEPTIONS_ENABLED } else { BaseClassType *const base = static_cast( g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface). g_type_interface_peek(G_OBJECT_GET_CLASS(self), CppObjectType::get_type()) // Get the interface. ) ); // Call the original underlying C function: if(base && base->iter_n_children) return (*base->iter_n_children)(self, iter); } typedef gboolean RType; return RType(); } int TreeModel::iter_n_children_vfunc(const iterator& iter) const { BaseClassType *const base = static_cast( g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface). g_type_interface_peek(G_OBJECT_GET_CLASS(gobject_), CppObjectType::get_type()) // Get the interface. ) ); if(base && base->iter_n_children) return (*base->iter_n_children)(const_cast(gobj()), const_cast((iter).gobj())); typedef int RType; return RType(); } int TreeModel::iter_n_root_children_vfunc() const { BaseClassType *const base = static_cast( g_type_interface_peek_parent( // Get the parent interface of the interface (The original underlying C interface). g_type_interface_peek(G_OBJECT_GET_CLASS(gobject_), CppObjectType::get_type()) // Get the interface. ) ); if(base && base->iter_n_children) return (*base->iter_n_children)(const_cast(gobj()), 0 /* null iter to mean root node, as described in C docs */); typedef int RType; return RType(); } #endif //GLIBMM_VFUNCS_ENABLED void TreeModel::rows_reordered(const Path& path, const iterator& iter, const Glib::ArrayHandle& new_order) { //The size of the array seems to be based on the known number of children. murrayc. gtk_tree_model_rows_reordered(gobj(), const_cast((path).gobj()), const_cast((iter).gobj()), const_cast(new_order.data())); } void TreeModel::rows_reordered(const Path& path, const Glib::ArrayHandle& new_order) { //The size of the array seems to be based on the known number of children. murrayc. gtk_tree_model_rows_reordered(gobj(), const_cast((path).gobj()), 0, const_cast(new_order.data())); } } // namespace Gtk