[gtkmm] Gtk::TreeRow and TreeNodeChildren: Make real const versions



commit acd6dcfb65c61e8517ed84a51721cdd2bcdeeeb5
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date:   Sun Jan 8 15:46:53 2017 +0100

    Gtk::TreeRow and TreeNodeChildren: Make real const versions
    
    Split TreeRow and TreeNodeChildren into TreeRow+TreeConstRow and
    TreeNodeChildren+TreeNodeConstChildren. Since TreeRow and TreeNodeChildren
    are just disguised iterators, they too shall have const versions that can't
    be implicitly copied to non-const versions that can be used for changing the
    underlying TreeModel.
    Add const versions of TreeModel::get_iter(). Bug #134520

 demos/gtk-demo/example_iconbrowser.cc |    7 +-
 demos/gtk-demo/example_iconview.cc    |    4 +-
 gtk/src/treeiter.ccg                  |   72 +++------
 gtk/src/treeiter.hg                   |  292 ++++++++++++++++++++-------------
 gtk/src/treemodel.ccg                 |   15 ++-
 gtk/src/treemodel.hg                  |   35 +++--
 6 files changed, 241 insertions(+), 184 deletions(-)
---
diff --git a/demos/gtk-demo/example_iconbrowser.cc b/demos/gtk-demo/example_iconbrowser.cc
index 47b660f..fa14ba9 100644
--- a/demos/gtk-demo/example_iconbrowser.cc
+++ b/demos/gtk-demo/example_iconbrowser.cc
@@ -865,7 +865,7 @@ void Example_IconBrowser::add_icon(const Glib::ustring& name,
 
 bool Example_IconBrowser::is_icon_visible(const Gtk::TreeModel::const_iterator& iter) const
 {
-  const Gtk::TreeModel::Row row = *iter;
+  const auto row = *iter;
   const Glib::ustring name = row[m_store->get_text_column()];
   if (name.empty())
     return false;
@@ -1005,12 +1005,11 @@ Glib::RefPtr<IconInfoStore> IconInfoStore::create()
 bool IconInfoStore::drag_data_get_vfunc(const Gtk::TreeModel::Path& path,
   Gtk::SelectionData& selection_data) const
 {
-  // There is no const version of Gtk::TreeModel::get_iter().
-  Gtk::TreeModel::const_iterator iter = const_cast<IconInfoStore*>(this)->get_iter(path);
+  const auto iter = get_iter(path);
   if (!iter)
     return false;
 
-  const Gtk::TreeModel::Row row = *iter;
+  const auto row = *iter;
   const Glib::ustring name = row[m_text_column];
   selection_data.set_text(name);
   return true;
diff --git a/demos/gtk-demo/example_iconview.cc b/demos/gtk-demo/example_iconview.cc
index 4a9b009..6a14bce 100644
--- a/demos/gtk-demo/example_iconview.cc
+++ b/demos/gtk-demo/example_iconview.cc
@@ -134,8 +134,8 @@ int Example_IconView::on_model_sort(const Gtk::TreeModel::const_iterator& a, con
    * folders before files.
    */
 
-  const Gtk::TreeModel::Row row_a = *a;
-  const Gtk::TreeModel::Row row_b = *b;
+  const auto row_a = *a;
+  const auto row_b = *b;
 
   const bool a_is_dir = row_a[m_columns.is_directory];
   const bool b_is_dir = row_b[m_columns.is_directory];
diff --git a/gtk/src/treeiter.ccg b/gtk/src/treeiter.ccg
index db3dac4..8335770 100644
--- a/gtk/src/treeiter.ccg
+++ b/gtk/src/treeiter.ccg
@@ -154,7 +154,7 @@ void TreeIterBase3::set_stamp(int stamp)
 }
 
 
-/**** Gtk::TreeRow *********************************************************/
+/**** Gtk::TreeConstRow and Gtk::TreeRow **************************************/
 
 TreeNodeChildren& TreeRow::children()
 {
@@ -163,9 +163,11 @@ TreeNodeChildren& TreeRow::children()
   return static_cast<TreeNodeChildren&>(static_cast<TreeIterBase2&>(*this));
 }
 
-const TreeNodeChildren& TreeRow::children() const
+const TreeNodeConstChildren& TreeConstRow::children() const
 {
-  return const_cast<TreeRow*>(this)->children();
+  g_assert(!is_end_);
+
+  return static_cast<const TreeNodeConstChildren&>(static_cast<const TreeIterBase2&>(*this));
 }
 
 TreeIter<TreeRow> TreeRow::parent()
@@ -180,9 +182,9 @@ TreeIter<TreeRow> TreeRow::parent()
   return iter;
 }
 
-TreeIter<const TreeRow> TreeRow::parent() const
+TreeIter<TreeConstRow> TreeConstRow::parent() const
 {
-  TreeIter<const TreeRow> iter(model_);
+  TreeIter<TreeConstRow> iter(model_);
 
   if(is_end_)
     iter.gobject_ = gobject_;
@@ -197,9 +199,9 @@ TreeIter<TreeRow> TreeRow::get_iter()
   return static_cast<TreeIter<TreeRow>&>(static_cast<TreeIterBase2&>(*this));
 }
 
-TreeIter<const TreeRow> TreeRow::get_iter() const
+TreeIter<TreeConstRow> TreeConstRow::get_iter() const
 {
-  return static_cast<const TreeIter<const TreeRow>&>(static_cast<const TreeIterBase2&>(*this));
+  return static_cast<const TreeIter<TreeConstRow>&>(static_cast<const TreeIterBase2&>(*this));
 }
 
 void TreeRow::set_value_impl(int column, const Glib::ValueBase& value)
@@ -209,10 +211,15 @@ void TreeRow::set_value_impl(int column, const Glib::ValueBase& value)
 
 void TreeRow::get_value_impl(int column, Glib::ValueBase& value) const
 {
-  model_->get_value_impl(static_cast<const TreeIter<const TreeRow>&>(static_cast<const 
TreeIterBase2&>(*this)), column, value);
+  model_->get_value_impl(static_cast<const TreeIter<TreeConstRow>&>(static_cast<const 
TreeIterBase2&>(*this)), column, value);
+}
+
+void TreeConstRow::get_value_impl(int column, Glib::ValueBase& value) const
+{
+  model_->get_value_impl(static_cast<const TreeIter<TreeConstRow>&>(static_cast<const 
TreeIterBase2&>(*this)), column, value);
 }
 
-TreeRow::operator bool() const
+TreeConstRow::operator bool() const
 {
   // Test whether the GtkTreeIter is valid and not an end iterator. This check
   // is almost the same as the private VALID_ITER() macro in gtkliststore.c and
@@ -220,7 +227,7 @@ TreeRow::operator bool() const
   return !is_end_ && gobject_.stamp;
 }
 
-/**** Gtk::TreeNodeChildren ************************************************/
+/**** Gtk::TreeNodeConstChildren and Gtk::TreeNodeChildren ********************/
 
 TreeNodeChildren::iterator TreeNodeChildren::begin()
 {
@@ -231,7 +238,7 @@ TreeNodeChildren::iterator TreeNodeChildren::begin()
 
   if(gobject_.stamp != 0)
   {
-    if(!gtk_tree_model_iter_children(model_->gobj(), iter.gobj(), const_cast<GtkTreeIter*>(&gobject_)))
+    if(!gtk_tree_model_iter_children(model_->gobj(), iter.gobj(), &gobject_))
     {
       // Assign the already known parent, in order to create an end iterator.
       iter.gobject_ = gobject_;
@@ -250,34 +257,9 @@ TreeNodeChildren::iterator TreeNodeChildren::begin()
   return iter;
 }
 
-TreeNodeChildren::const_iterator TreeNodeChildren::begin() const
+TreeNodeConstChildren::const_iterator TreeNodeConstChildren::begin() const
 {
-  //TODO: Reduce the copy/paste from the non-const begin()?
-
-  const_iterator iter(model_);
-
-  // If the iterator is invalid (stamp == 0), assume a 'virtual' toplevel
-  // node.  This behaviour is needed to implement Gtk::TreeModel::children().
-
-  if(gobject_.stamp != 0)
-  {
-    if(!gtk_tree_model_iter_children(model_->gobj(), iter.gobj(), const_cast<GtkTreeIter*>(&gobject_)))
-    {
-      // Assign the already known parent, in order to create an end iterator.
-      iter.gobject_ = gobject_;
-      iter.is_end_ = true;
-    }
-  }
-  else
-  {
-    if(!gtk_tree_model_get_iter_first(model_->gobj(), iter.gobj()))
-    {
-      // No need to copy the GtkTreeIter, since iter.gobject_ is already empty.
-      iter.is_end_ = true;
-    }
-  }
-
-  return iter;
+  return const_cast<TreeNodeChildren*>(static_cast<const TreeNodeChildren*>(this))->begin();
 }
 
 TreeNodeChildren::iterator TreeNodeChildren::end()
@@ -289,13 +271,9 @@ TreeNodeChildren::iterator TreeNodeChildren::end()
   return iter;
 }
 
-TreeNodeChildren::const_iterator TreeNodeChildren::end() const
+TreeNodeConstChildren::const_iterator TreeNodeConstChildren::end() const
 {
-  // Just copy the parent, and turn it into an end iterator.
-  const_iterator iter(model_);
-  iter.gobject_ = gobject_;
-  iter.is_end_ = true;
-  return iter;
+  return const_cast<TreeNodeChildren*>(static_cast<const TreeNodeChildren*>(this))->end();
 }
 
 TreeNodeChildren::value_type TreeNodeChildren::operator[](TreeNodeChildren::size_type index)
@@ -314,7 +292,7 @@ TreeNodeChildren::value_type TreeNodeChildren::operator[](TreeNodeChildren::size
   return *iter;
 }
 
-const TreeNodeChildren::value_type TreeNodeChildren::operator[](TreeNodeChildren::size_type index) const
+const TreeNodeConstChildren::value_type TreeNodeConstChildren::operator[](TreeNodeChildren::size_type index) 
const
 {
   const_iterator iter(model_);
 
@@ -330,14 +308,14 @@ const TreeNodeChildren::value_type TreeNodeChildren::operator[](TreeNodeChildren
   return *iter;
 }
 
-TreeNodeChildren::size_type TreeNodeChildren::size() const
+TreeNodeConstChildren::size_type TreeNodeConstChildren::size() const
 {
   const auto parent = const_cast<GtkTreeIter*>(get_parent_gobject());
 
   return gtk_tree_model_iter_n_children(model_->gobj(), parent);
 }
 
-bool TreeNodeChildren::empty() const
+bool TreeNodeConstChildren::empty() const
 {
   // If the iterator is invalid (stamp == 0), assume a 'virtual' toplevel
   // node.  This behaviour is needed to implement Gtk::TreeModel::children().
diff --git a/gtk/src/treeiter.hg b/gtk/src/treeiter.hg
index 71065b2..bd38b79 100644
--- a/gtk/src/treeiter.hg
+++ b/gtk/src/treeiter.hg
@@ -22,9 +22,6 @@ _DEFS(gtkmm,gtk)
 #include <iterator>
 #include <type_traits>
 #include <gtk/gtk.h> /* for GtkTreeIter */
-#ifdef GLIBMM_HAVE_SUN_REVERSE_ITERATOR
-#include <cstddef> /* for std::ptrdiff_t */
-#endif
 
 namespace Gtk
 {
@@ -32,7 +29,9 @@ namespace Gtk
 class TreeModel;
 template <typename T>
 class TreeIter;
+class TreeConstRow;
 class TreeRow;
+class TreeNodeConstChildren;
 class TreeNodeChildren;
 
 // Why all the base classes?
@@ -85,8 +84,11 @@ protected:
   bool       is_end_;
 
   // For the conversion and assignment from iterator to const_iterator
-  friend class Gtk::TreeIter<const Gtk::TreeRow>;
+  friend class Gtk::TreeIter<Gtk::TreeConstRow>;
+
+  friend class Gtk::TreeConstRow;
   friend class Gtk::TreeRow;
+  friend class Gtk::TreeNodeConstChildren;
   friend class Gtk::TreeNodeChildren;
 #endif // DOXYGEN_SHOULD_SKIP_THIS
 
@@ -94,7 +96,7 @@ protected:
 
 /** Base of TreeIter.
  *
- * Contains the common parts of TreeIter<TreeRow> and TreeIter<const&nbsp;TreeRow>.
+ * Contains the common parts of TreeIter<TreeRow> and TreeIter<TreeConstRow>.
  *
  * @ingroup TreeView
  */
@@ -165,9 +167,9 @@ protected:
 // carefully implemented by hand.
 //TODO: document implementation details.
 
-/** A Gtk::TreeModel::iterator is a reference to a specific node on a specific
- * model.
+/** Typedefed as TreeModel::iterator and TreeModel::const_iterator.
  *
+ * A Gtk::TreeModel::iterator is a reference to a specific node on a specific model.
  * It is a generic structure with an integer and three generic pointers.
  * These are filled in by the model in a model-specific way.
  *
@@ -190,21 +192,19 @@ protected:
  * the Gtk::TREE_MODEL_ITERS_PERSIST flag was added to indicate this behaviour -
  * see Gtk::TreeModel::get_flags().
  *
- * Typedefed as Gtk::TreeModel::iterator and Gtk::TreeModel::const_iterator.
- *
- * @tparam T <TreeRow> for an iterator, or <const&nbsp;TreeRow> for a const_iterator.
+ * @tparam T TreeRow for an iterator, TreeConstRow for a const_iterator.
  *
  * @ingroup TreeView
  */
 template <typename T>
 class TreeIter : public TreeIterBase3
 {
-  static_assert(std::is_same<T, TreeRow>::value || std::is_same<T, const TreeRow>::value,
-                "TreeIter can only iterate over TreeRow or const TreeRow");
+  static_assert(std::is_same<T, TreeRow>::value || std::is_same<T, TreeConstRow>::value,
+                "TreeIter can only iterate over TreeRow or TreeConstRow");
 
 public:
   using iterator_category = std::bidirectional_iterator_tag;
-  using value_type        = TreeRow;
+  using value_type        = T;
   using difference_type   = int;
   using reference         = T&;
   using pointer           = T*;
@@ -212,13 +212,13 @@ public:
   TreeIter();
 
   /// iterator to const_iterator conversion.
-  template <typename T2, typename = typename std::enable_if<!std::is_same<T, T2>::value &&
-    std::is_same<T, const T2>::value, T2>::type>
+  template <typename T2, typename = typename std::enable_if<
+    std::is_same<T, TreeConstRow>::value && std::is_same<T2, TreeRow>::value, T2>::type>
   TreeIter(const TreeIter<T2>& src);
 
   /// iterator to const_iterator assignment.
-  template <typename T2, typename = typename std::enable_if<!std::is_same<T, T2>::value &&
-    std::is_same<T, const T2>::value, T2>::type>
+  template <typename T2, typename = typename std::enable_if<
+    std::is_same<T, TreeConstRow>::value && std::is_same<T2, TreeRow>::value, T2>::type>
   TreeIter& operator=(const TreeIter<T2>& src);
 
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
@@ -263,26 +263,100 @@ template <typename T>
 inline bool operator!=(const TreeIter<T>& lhs, const TreeIter<T>& rhs)
 { return !lhs.equal(rhs); }
 
-template <class ColumnType>
+template <typename RowType, typename ColumnType>
 class TreeValueProxy
 {
 public:
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
-  inline TreeValueProxy(const TreeRow& row, const TreeModelColumn<ColumnType>& column);
+  inline TreeValueProxy(const RowType& row, const TreeModelColumn<ColumnType>& column);
 #endif
 
-  inline TreeValueProxy<ColumnType>& operator=(const ColumnType& data);
+  inline TreeValueProxy& operator=(const ColumnType& data);
   inline operator ColumnType() const;
 
 private:
-  TreeRow& row_;
+  RowType& row_;
   const TreeModelColumn<ColumnType>& column_;
 
   // no copy assignment
-  TreeValueProxy<ColumnType>& operator=(const TreeValueProxy<ColumnType>&) = delete;
+  TreeValueProxy& operator=(const TreeValueProxy&) = delete;
 };
 
 
+/** Typedefed as TreeModel::ConstRow.
+ *
+ * %TreeConstRow is a const version of %TreeRow. %TreeConstRow does not contain
+ * methods for modifying the underlying TreeModel.
+ *
+ * @see TreeRow
+ * @ingroup TreeView
+ */
+class TreeConstRow : public TreeIterBase2
+{
+public:
+
+  /** Use this to get the value of this @a column of this row.
+   * This is a templated method, so the compiler will not allow you to provide an inappropriate type
+   * of data for the model column.
+   *
+   * This is just a more convenient syntax that does the same thing as get_value().
+   *
+   * @param column The model column.
+   */
+  template <typename ColumnType> inline
+  const TreeValueProxy<TreeConstRow, ColumnType> operator[](const TreeModelColumn<ColumnType>& column) const;
+
+  /** Gets the value of this @a column of this row.
+   *
+   * See also operator[]().
+   *
+   * @param column The model column.
+   * @result The value of this column of this row.
+   */
+  template <typename ColumnType>
+  ColumnType get_value(const TreeModelColumn<ColumnType>& column) const;
+
+  /** Use get_value(const TreeModelColumn<>& column) unless
+   * you do not know the column type at compile-time.
+   * If the @a data output argument is of an inappropriate C++ type then this might fail at runtime.
+   * @param column The number of the column whose value you want to query.
+   * @param[out] data An output argument which will contain the value of this column of this row.
+   */
+  template <typename ColumnType>
+  void get_value(int column, ColumnType& data) const;
+
+  /** This returns an STL-like container API, for iterating over the rows.
+   * See also Gtk::TreeModel::children() for the top-level children.
+   */
+  const TreeNodeConstChildren& children() const;
+
+  /** Gets a const_iterator to the parent row of this row.
+   * @result A const_iterator to the parent row.
+   */
+  TreeIter<TreeConstRow> parent() const;
+
+  /** Gets a const_iterator to this row.
+   * @result A const_iterator to this row.
+   */
+  TreeIter<TreeConstRow> get_iter() const;
+
+  /** Discover whether this is a valid row.
+   * For instance,
+   * @code
+   * if (treerow)
+   *   do_something();
+   * @endcode
+   *
+   * @newin{3,22}
+   */
+  explicit operator bool() const;
+
+private:
+  // Forwarders to Gtk::TreeModel virtual methods.
+  void get_value_impl(int column, Glib::ValueBase& value) const;
+
+}; // class TreeConstRow
+
 /** Typedefed as TreeModel::Row.
  *
  * Dereference a TreeModel::iterator to get the Row. Use operator[] or set_value()
@@ -297,10 +371,16 @@ private:
  *
  * @ingroup TreeView
  */
-class TreeRow : public TreeIterBase2
+class TreeRow : public TreeConstRow
 {
 public:
 
+  // Inherit the const versions
+  using TreeConstRow::operator[];
+  using TreeConstRow::children;
+  using TreeConstRow::parent;
+  using TreeConstRow::get_iter;
+
   /** Use this to set and get the value of this @a column of this row.
    * This is a templated method, so the compiler will not allow you to provide an inappropriate type
    * of data for the model column.
@@ -309,22 +389,19 @@ public:
    *
    * @param column The model column.
    */
-  template <class ColumnType> inline
-  TreeValueProxy<ColumnType> operator[](const TreeModelColumn<ColumnType>& column);
-
-  template <class ColumnType> inline
-  const TreeValueProxy<ColumnType> operator[](const TreeModelColumn<ColumnType>& column) const;
+  template <typename ColumnType> inline
+  TreeValueProxy<TreeRow, ColumnType> operator[](const TreeModelColumn<ColumnType>& column);
 
   /** Sets the value of this @a column of this row.
    * This is a templated method, so the compiler will not allow you to provide an inappropriate type
    * of @a data for the model column.
    *
-   * See also operator[].
+   * See also operator[]().
    *
    * @param column The model column.
    * @param data The new value to use for this column of this row.
    */
-  template <class ColumnType>
+  template <typename ColumnType>
   void set_value(const TreeModelColumn<ColumnType>& column, const ColumnType& data);
 
   /** Use set_value(const TreeModelColumn<>& column, const ColumnType& data) unless
@@ -333,77 +410,24 @@ public:
    * @param column The number of the column whose value you want to change.
    * @param data The new value to use for this column of this row.
    */
-  template <class ColumnType>
+  template <typename ColumnType>
   void set_value(int column, const ColumnType& data);
 
-  /** Gets the value of this @a column of this row.
-   * This is a templated method, so the compiler will not allow you to provide an inappropriate type
-   * of data for the model column.
-   *
-   * See also operator[].
-   *
-   * @param column The model column.
-   * @result The value of this column of this row
-   */
-  template <class ColumnType>
-  ColumnType get_value(const TreeModelColumn<ColumnType>& column) const;
-
-  /** Use get_value(const TreeModelColumn<>& column) unless
-   * you do not know the column type at compile-time.
-   * If the @a data output argument is of an inappropriate C++ type then this might fail at runtime.
-   * @param column The number of the column whose value you want to query.
-   * @param[out] data An output argument which will contain the value of this column of this row.
-   */
-  template <class ColumnType>
-  void get_value(int column, ColumnType& data) const;
-
   /** This returns an STL-like container API, for iterating over the rows.
    * See also Gtk::TreeModel::children() for the top-level children.
    */
   TreeNodeChildren& children();
 
-  /** This returns an STL-like container API, for iterating over the rows.
-   * See also Gtk::TreeModel::children() for the top-level children.
-   */
-  const TreeNodeChildren& children() const;
-
   /** Gets an iterator to the parent row of this row.
    * @result An iterator to the parent row.
    */
   TreeIter<TreeRow> parent();
 
-  /** Gets a const_iterator to the parent row of this row.
-   * @result A const_iterator to the parent row.
-   */
-  TreeIter<const TreeRow> parent() const;
-
   /** Gets an iterator to this row.
    * @result An iterator to this row.
    */
   TreeIter<TreeRow> get_iter();
 
-  /** Gets a const_iterator to this row.
-   * @result A const_iterator to this row.
-   */
-  TreeIter<const TreeRow> get_iter() const;
-
-  /** Discover whether this is a valid row.
-   * For instance,
-   * @code
-   * if (treerow)
-   *   do_something();
-   * @endcode
-   *
-   * @newin{3,22}
-   */
-  explicit operator bool() const;
-
-  /// Provides access to the underlying C GObject.
-  GtkTreeIter*       gobj()       { return TreeIterBase::gobj(); }
-
-  /// Provides access to the underlying C GObject.
-  const GtkTreeIter* gobj() const { return TreeIterBase::gobj(); }
-
 private:
   // Forwarders to Gtk::TreeModel virtual methods.
   void set_value_impl(int column, const Glib::ValueBase& value);
@@ -414,33 +438,33 @@ private:
 
 //TODO: Document begin(), end(), size(), etc, in an STL-style way. murrayc.
 
-/** Virtual container of TreeModel::Row items.
+/** Typedefed as TreeModel::ConstChildren.
+ *
+ * Virtual container of TreeModel::ConstRow items.
  *
- * typedefed as TreeModel::Children.
+ * %TreeNodeConstChildren is a const version of %TreeNodeChildren.
+ * %TreeNodeConstChildren does not contain methods for modifying the underlying TreeModel.
  *
+ * @see TreeNodeChildren
  * @ingroup TreeView
  */
-class TreeNodeChildren : public TreeIterBase2
+class TreeNodeConstChildren : public TreeIterBase2
 {
 public:
-  using value_type      = Gtk::TreeRow;
+  using value_type      = Gtk::TreeConstRow;
   using size_type       = unsigned int;
   using difference_type = int;
-  using iterator        = Gtk::TreeIter<Gtk::TreeRow>;
-  using const_iterator  = Gtk::TreeIter<const Gtk::TreeRow>;
+  using const_iterator  = Gtk::TreeIter<Gtk::TreeConstRow>;
 
-  iterator begin();
   const_iterator begin() const;
-  iterator end();
   const_iterator end()   const;
 
-  value_type operator[](size_type index);
   const value_type operator[](size_type index) const;
 
   size_type size() const;
   bool empty() const;
 
-  /** Discover whether this is a valid TreeNodeChildren.
+  /** Discover whether this is a valid container.
    * For instance,
    * @code
    * if (children)
@@ -456,11 +480,42 @@ public:
 
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 
-  explicit TreeNodeChildren(TreeModel* model)
-    : TreeIterBase2(model) {}
+  explicit TreeNodeConstChildren(const TreeModel* model)
+    : TreeIterBase2(const_cast<TreeModel*>(model)) {}
 
   const GtkTreeIter* get_parent_gobject() const
-    { return (gobject_.stamp != 0) ? &gobject_ : nullptr; }
+  { return (gobject_.stamp != 0) ? &gobject_ : nullptr; }
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+}; // class TreeNodeConstChildren
+
+/** Typedefed as TreeModel::Children.
+ *
+ * Virtual container of TreeModel::Row items.
+ *
+ * @ingroup TreeView
+ */
+class TreeNodeChildren : public TreeNodeConstChildren
+{
+public:
+  using value_type      = Gtk::TreeRow;
+  using iterator        = Gtk::TreeIter<Gtk::TreeRow>;
+
+  // Inherit the const versions
+  using TreeNodeConstChildren::begin;
+  using TreeNodeConstChildren::end;
+  using TreeNodeConstChildren::operator[];
+
+  iterator begin();
+  iterator end();
+
+  value_type operator[](size_type index);
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+  explicit TreeNodeChildren(TreeModel* model)
+    : TreeNodeConstChildren(model) {}
 
 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
 
@@ -562,42 +617,45 @@ TreeIter<T>::operator bool() const
 
 /**** Gtk::TreeValueProxy<> ************************************************/
 
-template <class ColumnType> inline
-TreeValueProxy<ColumnType>::TreeValueProxy(const TreeRow& row, const TreeModelColumn<ColumnType>& column)
+template <typename RowType, typename ColumnType> inline
+TreeValueProxy<RowType, ColumnType>::TreeValueProxy(const RowType& row, const TreeModelColumn<ColumnType>& 
column)
 :
-  row_    (const_cast<TreeRow&>(row)),
+  row_    (const_cast<RowType&>(row)),
   column_ (column)
 {}
 
-template <class ColumnType> inline
-TreeValueProxy<ColumnType>& TreeValueProxy<ColumnType>::operator=(const ColumnType& data)
+template <typename RowType, typename ColumnType> inline
+TreeValueProxy<RowType, ColumnType>& TreeValueProxy<RowType, ColumnType>::operator=(const ColumnType& data)
 {
+  // If row_ is a TreeConstRow and TreeValueProxy::operator=() is actually used,
+  // this will fail at compile time. TreeConstRow has no set_value() method.
+  // This failure is deliberate.
   row_.set_value(column_, data);
   return *this;
 }
 
-template <class ColumnType> inline
-TreeValueProxy<ColumnType>::operator ColumnType() const
+template <typename RowType, typename ColumnType> inline
+TreeValueProxy<RowType, ColumnType>::operator ColumnType() const
 {
   return row_.get_value(column_);
 }
 
 
-/**** Gtk::TreeRow *********************************************************/
+/**** Gtk::TreeConstRow and Gtk::TreeRow **************************************/
 
-template <class ColumnType> inline
-const TreeValueProxy<ColumnType> TreeRow::operator[](const TreeModelColumn<ColumnType>& column) const
+template <typename ColumnType> inline
+const TreeValueProxy<TreeConstRow, ColumnType> TreeConstRow::operator[](const TreeModelColumn<ColumnType>& 
column) const
 {
-  return TreeValueProxy<ColumnType>(*this, column);
+  return TreeValueProxy<TreeConstRow, ColumnType>(*this, column);
 }
 
-template <class ColumnType> inline
-TreeValueProxy<ColumnType> TreeRow::operator[](const TreeModelColumn<ColumnType>& column)
+template <typename ColumnType> inline
+TreeValueProxy<TreeRow, ColumnType> TreeRow::operator[](const TreeModelColumn<ColumnType>& column)
 {
-  return TreeValueProxy<ColumnType>(*this, column);
+  return TreeValueProxy<TreeRow, ColumnType>(*this, column);
 }
 
-template <class ColumnType>
+template <typename ColumnType>
 void TreeRow::set_value(const TreeModelColumn<ColumnType>& column, const ColumnType& data)
 {
   using ValueType = typename Gtk::TreeModelColumn<ColumnType>::ValueType;
@@ -609,7 +667,7 @@ void TreeRow::set_value(const TreeModelColumn<ColumnType>& column, const ColumnT
   this->set_value_impl(column.index(), value);
 }
 
-template <class ColumnType>
+template <typename ColumnType>
 void TreeRow::set_value(int column, const ColumnType& data)
 {
   // This could fail at run-time, because the wrong ColumnType might be used.
@@ -624,8 +682,8 @@ void TreeRow::set_value(int column, const ColumnType& data)
   this->set_value_impl(column, value);
 }
 
-template <class ColumnType>
-ColumnType TreeRow::get_value(const TreeModelColumn<ColumnType>& column) const
+template <typename ColumnType>
+ColumnType TreeConstRow::get_value(const TreeModelColumn<ColumnType>& column) const
 {
   using ValueType = typename Gtk::TreeModelColumn<ColumnType>::ValueType;
 
@@ -635,8 +693,8 @@ ColumnType TreeRow::get_value(const TreeModelColumn<ColumnType>& column) const
   return value.get();
 }
 
-template <class ColumnType>
-void TreeRow::get_value(int column, ColumnType& data) const
+template <typename ColumnType>
+void TreeConstRow::get_value(int column, ColumnType& data) const
 {
   // This could fail at run-time, because the wrong ColumnType might be used.
   // It's only for dynamically generated model columns.
diff --git a/gtk/src/treemodel.ccg b/gtk/src/treemodel.ccg
index 5766464..a2835c4 100644
--- a/gtk/src/treemodel.ccg
+++ b/gtk/src/treemodel.ccg
@@ -93,6 +93,11 @@ TreeModel::iterator TreeModel::get_iter(const Path& path)
   return iter;
 }
 
+TreeModel::const_iterator TreeModel::get_iter(const Path& path) const
+{
+  return const_cast<TreeModel*>(this)->get_iter(path);
+}
+
 TreeModel::iterator TreeModel::get_iter(const Glib::ustring& path_string)
 {
   Gtk::TreeModel::iterator iter (this);
@@ -100,15 +105,19 @@ TreeModel::iterator TreeModel::get_iter(const Glib::ustring& path_string)
   return iter;
 }
 
+TreeModel::const_iterator TreeModel::get_iter(const Glib::ustring& path_string) const
+{
+  return const_cast<TreeModel*>(this)->get_iter(path_string);
+}
+
 TreeModel::Children TreeModel::children()
 {
   return TreeNodeChildren(this);
 }
 
-TreeModel::Children TreeModel::children() const
+const TreeModel::ConstChildren 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<TreeModel*>(this));
+  return TreeNodeConstChildren(this);
 }
 
 void TreeModel::set_value_impl(const iterator&, int, const Glib::ValueBase&)
diff --git a/gtk/src/treemodel.hg b/gtk/src/treemodel.hg
index f63b849..3023e7b 100644
--- a/gtk/src/treemodel.hg
+++ b/gtk/src/treemodel.hg
@@ -97,9 +97,11 @@ public:
   typedef TreeModelColumnRecord ColumnRecord;
 
   typedef TreeNodeChildren Children;
+  typedef TreeNodeConstChildren ConstChildren;
   typedef Children::iterator iterator;
-  typedef Children::const_iterator const_iterator;
+  typedef ConstChildren::const_iterator const_iterator;
 
+  typedef TreeConstRow ConstRow;
   typedef TreeRow Row;
   typedef TreePath Path;
   typedef TreeRowReference RowReference;
@@ -113,8 +115,13 @@ public:
    * @result A valid iterator pointing to the path, or an invalid iterator if that is not possible.
    */
   iterator get_iter(const Path& path);
-  //TODO: Add const_iterator get_iter(const Path& path) const;
-  //Implement a const_iterator?
+
+  /** Returns a valid iterator pointing to @a path.
+   *
+   * @param path The @link Gtk::TreePath Gtk::TreeModel::Path@endlink.
+   * @result A valid iterator pointing to the path, or an invalid iterator if that is not possible.
+   */
+  const_iterator get_iter(const Path& path) const;
 
   /** Returns a valid iterator pointing to @a path_string.
    *
@@ -122,26 +129,31 @@ public:
    * @result A valid iterator pointing to the path, or an invalid iterator if that is not possible.
    */
   iterator get_iter(const Glib::ustring& path_string);
-  //TODO: Implement a const_iterator? const_iterator get_iter(const Glib::ustring& path_string) const;
+
+  /** Returns a valid iterator pointing to @a path_string.
+   *
+   * @param path_string The path, as a string representation.
+   * @result A valid iterator pointing to the path, or an invalid iterator if that is not possible.
+   */
+  const_iterator get_iter(const Glib::ustring& path_string) const;
 
   ///This returns an STL-like container API, for iterating over the rows.
   Children children();
 
-  //TODO: Return a real TreeNodeChildren (a container of const_iterators), when we have a real 
const_iterator.
   ///This returns an STL-like container API, for iterating over the rows.
-  Children children() const;
+  const ConstChildren children() const;
 
   _IGNORE(gtk_tree_model_foreach)
 
   /** For example,
    * void on_foreach(const Gtk::TreeModel::iterator& iter);
    *
-   * If the callback function returns true, then the tree ceases to be walked, and foreach() returns.
+   * If the callback function returns true, then the tree ceases to be walked, and foreach_iter() returns.
    */
   typedef sigc::slot<bool(const TreeModel::iterator&)> SlotForeachIter;
 
   /** Calls a callback slot on each node in the model in a depth-first fashion.
-   * If the callback function returns true, then the tree ceases to be walked, and foreach() returns.
+   * If the callback function returns true, then the tree ceases to be walked, and foreach_iter() returns.
    *
    * @param slot The function to call for each selected node.
    */
@@ -150,12 +162,12 @@ public:
   /** For example,
    * void on_foreach(const Gtk::TreeModel::Path& path);
    *
-   * If the callback function returns true, then the tree ceases to be walked, and foreach() returns.
+   * If the callback function returns true, then the tree ceases to be walked, and foreach_path() returns.
    */
   typedef sigc::slot<bool(const TreeModel::Path&)> SlotForeachPath;
 
   /** Calls a callback slot on each node in the model in a depth-first fashion.
-   * If the callback function returns true, then the tree ceases to be walked, and foreach() returns.
+   * If the callback function returns true, then the tree ceases to be walked, and foreach_path() returns.
    *
    * @param slot The function to call for each selected node.
    */
@@ -180,7 +192,7 @@ public:
   _WRAP_METHOD(GType get_column_type(int index) const, gtk_tree_model_get_column_type)
   //TODO: A C++-type version of get_column_type()?
 
-  _WRAP_METHOD(TreeModel::Path get_path(const iterator& iter) const, gtk_tree_model_get_path)
+  _WRAP_METHOD(TreeModel::Path get_path(const const_iterator& iter) const, gtk_tree_model_get_path)
 
   _WRAP_METHOD(void row_changed(const Path& path, const iterator& iter), gtk_tree_model_row_changed)
   _WRAP_METHOD(void row_inserted(const Path& path, const iterator& iter), gtk_tree_model_row_inserted)
@@ -403,6 +415,7 @@ dnl
 
   friend class Gtk::TreeModelFilter;
   friend class Gtk::TreeModelSort;
+  friend class Gtk::TreeConstRow;
   friend class Gtk::TreeRow;
 };
 


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