[gtkmm] Add GtkContainer's child properties handling



commit 4442cbf5879f826d32261e486a7fc8468bc302b1
Author: Juan R. GarcĂ­a Blanco <juanrgar gmail com>
Date:   Mon Jun 30 22:08:01 2014 +0200

    Add GtkContainer's child properties handling
    
        * gtk/gtkmm/childpropertyproxy_base.[h|cc]: New files.
        * gtk/gtkmm/childpropertyproxy.[h|cc]: New files.
        * gtk/gtkmm/filelist.am: Add childpropertyproxy_base.[h|cc] and
        childpropertyproxy.[h|cc].
        * gtk/src/container.hg: Include gtkmm/childpropertyproxy.h.
        * tools/extra_defs_gen/generate_defs_gtk.cc: Add
        get_child_properties(), and use it to gather information about
        child properties in GtkContainer subclasses.
        * tools/m4/child_property.m4: New file that expands
        _CHILD_PROPERTY_PROXY macro.
        * tools/m4/convert_gtkmm.m4: Include child_property.m4.
        * tools/m4/filelist.am: Add child_property.m4.

 gtk/gtkmm/childpropertyproxy.cc           |   26 ++++
 gtk/gtkmm/childpropertyproxy.h            |  181 +++++++++++++++++++++++++++++
 gtk/gtkmm/childpropertyproxy_base.cc      |   92 +++++++++++++++
 gtk/gtkmm/childpropertyproxy_base.h       |   71 +++++++++++
 gtk/gtkmm/filelist.am                     |    4 +
 gtk/src/container.hg                      |    1 +
 tools/extra_defs_gen/generate_defs_gtk.cc |   61 ++++++++++
 tools/m4/child_property.m4                |   37 ++++++
 tools/m4/convert_gtkmm.m4                 |    1 +
 tools/m4/filelist.am                      |    1 +
 10 files changed, 475 insertions(+), 0 deletions(-)
---
diff --git a/gtk/gtkmm/childpropertyproxy.cc b/gtk/gtkmm/childpropertyproxy.cc
new file mode 100644
index 0000000..a9f5f4a
--- /dev/null
+++ b/gtk/gtkmm/childpropertyproxy.cc
@@ -0,0 +1,26 @@
+// -*- c++ -*-
+
+/* childpropertyproxy.cc
+ *
+ * Copyright 2014 The gtkmm Development Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gtkmm/childpropertyproxy.h>
+
+namespace Gtk
+{
+} // namespace Gtk
diff --git a/gtk/gtkmm/childpropertyproxy.h b/gtk/gtkmm/childpropertyproxy.h
new file mode 100644
index 0000000..f374efd
--- /dev/null
+++ b/gtk/gtkmm/childpropertyproxy.h
@@ -0,0 +1,181 @@
+// -*- c++ -*-
+#ifndef _GTKMM_CHILDPROPERTYPROXY_H
+#define _GTKMM_CHILDPROPERTYPROXY_H
+
+/* childpropertyproxy.h
+ *
+ * Copyright 2014 The gtkmm Development Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gtkmm/childpropertyproxy_base.h>
+
+
+namespace Gtk
+{
+
+/** A ChildPropertyProxy can be used to get and set the value of a GtkContainer's child property.
+ * Child properties are not specific to either the container or the contained widget, but rather
+ * to their relation.
+ * With the ChildPropertyProxy, you may use either get_value() and set_value(), or operator=()
+ * and operator PropertyType(), like in this example:
+ * @code
+ * bool first_tab_tab_expand = notebook.property_tab_expand(first_tab_widget);
+ * notebook.property_tab_expand(first_tab_widget) = true;
+ * @endcode
+ *
+ * You may also receive notification when a property's value changes on a child, by connecting
+ * to signal_changed().
+ */
+template <class T>
+class ChildPropertyProxy : public ChildPropertyProxy_Base
+{
+public:
+  typedef T PropertyType;
+
+  ChildPropertyProxy(Gtk::Container* parent, Gtk::Widget& child, const char* property_name)
+    : ChildPropertyProxy_Base(parent, child, property_name) {}
+
+  /** Set the value of this property in child.
+   * @param data The new value for the property.
+   */
+  void set_value(const PropertyType& data);
+
+  /** Get the value of this property in child.
+   * @result The current value of the property.
+   */
+  PropertyType get_value() const;
+
+  /** Set the value of this property in child back to its default value.
+   */
+  void reset_value()
+    { reset_property_(); }
+
+  ChildPropertyProxy<T>& operator=(const PropertyType& data)
+    { set_value(data); return *this; }
+
+  operator PropertyType() const
+    { return get_value(); }
+
+  SignalProxyChildProperty signal_changed();
+};
+
+
+/** See ChildPropertyProxy().
+ * This property can be written, but not read, so there is no get_value() method.
+ */
+template <class T>
+class ChildPropertyProxy_WriteOnly : public ChildPropertyProxy_Base
+{
+public:
+  typedef T PropertyType;
+
+  ChildPropertyProxy_WriteOnly(Gtk::Container* parent, Gtk::Widget& child, const char* property_name)
+    : ChildPropertyProxy_Base(parent, child, property_name) {}
+
+  /** Set the value of this property in child.
+   * @param data The new value for the property.
+   */
+  void set_value(const PropertyType& data);
+
+  /** Set the value of this property in child back to its default value.
+   */
+  void reset_value()
+    { reset_property_(); }
+
+  ChildPropertyProxy_WriteOnly<T>& operator=(const PropertyType& data)
+    { set_value(data); return *this; }
+};
+
+/** See ChildPropertyProxy().
+ * This property can be read, but not written, so there is no set_value() method.
+ */
+template <class T>
+class ChildPropertyProxy_ReadOnly : public ChildPropertyProxy_Base
+{
+public:
+  typedef T PropertyType;
+
+  //obj is const, because this should be returned by const accessors.
+  ChildPropertyProxy_ReadOnly(const Gtk::Container* parent, const Gtk::Widget& child, const char* 
property_name)
+    : ChildPropertyProxy_Base(const_cast<Gtk::Container*>(parent), const_cast<Gtk::Widget&>(child), 
property_name) {}
+
+  /** Get the value of this property in child.
+   * @result The current value of the property.
+   */
+  PropertyType get_value() const;
+
+  operator PropertyType() const
+    { return get_value(); }
+};
+
+
+/**** Template Implementation **********************************************/
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+template <class T>
+void ChildPropertyProxy<T>::set_value(const T& data)
+{
+  Glib::Value<T> value;
+  value.init(Glib::Value<T>::value_type());
+
+  value.set(data);
+  set_property_(value);
+}
+
+template <class T>
+T ChildPropertyProxy<T>::get_value() const
+{
+  Glib::Value<T> value;
+  value.init(Glib::Value<T>::value_type());
+
+  get_property_(value);
+  return value.get();
+}
+
+template <class T>
+SignalProxyChildProperty ChildPropertyProxy<T>::signal_changed()
+{
+  return SignalProxyChildProperty(&child_, property_name_);
+}
+
+template <class T>
+void ChildPropertyProxy_WriteOnly<T>::set_value(const T& data)
+{
+  Glib::Value<T> value;
+  value.init(Glib::Value<T>::value_type());
+
+  value.set(data);
+  set_property_(value);
+}
+
+template <class T>
+T ChildPropertyProxy_ReadOnly<T>::get_value() const
+{
+  Glib::Value<T> value;
+  value.init(Glib::Value<T>::value_type());
+
+  get_property_(value);
+  return value.get();
+}
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+} // namespace Gtk
+
+
+#endif /* _GTKMM_CHILDPROPERTYPROXY_H */
diff --git a/gtk/gtkmm/childpropertyproxy_base.cc b/gtk/gtkmm/childpropertyproxy_base.cc
new file mode 100644
index 0000000..1bd5125
--- /dev/null
+++ b/gtk/gtkmm/childpropertyproxy_base.cc
@@ -0,0 +1,92 @@
+// -*- c++ -*-
+
+/* childpropertyproxy_base.cc
+ *
+ * Copyright 2014 The gtkmm Development Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gtkmm/childpropertyproxy_base.h>
+#include <gtkmm/container.h>
+
+#include <gtk/gtk.h>
+
+namespace Gtk
+{
+
+sigc::connection SignalProxyChildProperty::connect(const SlotType& sl)
+{
+  // Create a proxy to hold our connection info
+  // This will be deleted by destroy_notify_handler.
+  Glib::PropertyProxyConnectionNode* pConnectionNode = new Glib::PropertyProxyConnectionNode(sl, 
obj_->gobj());
+
+  // connect it to gtk+
+  // pConnectionNode will be passed as the data argument to the callback.
+  // The callback will then call the virtual Object::property_change_notify() method,
+  // which will contain a switch/case statement which will examine the property name.
+  const Glib::ustring notify_signal_name = "child-notify::" + Glib::ustring(property_name_);
+  pConnectionNode->connection_id_ = g_signal_connect_data(obj_->gobj(),
+         notify_signal_name.c_str(), (GCallback)(&Glib::PropertyProxyConnectionNode::callback), 
pConnectionNode,
+         &Glib::PropertyProxyConnectionNode::destroy_notify_handler,
+         G_CONNECT_AFTER);
+
+  return sigc::connection(pConnectionNode->slot_);
+}
+
+ChildPropertyProxy_Base::ChildPropertyProxy_Base(Gtk::Container* parent, Gtk::Widget& child, const char* 
property_name)
+  : parent_(parent),
+    child_(child),
+    property_name_(property_name) {}
+
+ChildPropertyProxy_Base::ChildPropertyProxy_Base(const ChildPropertyProxy_Base& other)
+  : parent_(other.parent_),
+    child_(other.child_),
+    property_name_(other.property_name_) {}
+
+SignalProxyChildProperty ChildPropertyProxy_Base::signal_changed()
+{
+  return SignalProxyChildProperty(&child_, property_name_);
+}
+
+void ChildPropertyProxy_Base::set_property_(const Glib::ValueBase& value)
+{
+  gtk_container_child_set_property(parent_->gobj(), child_.gobj(), property_name_, value.gobj());
+}
+
+void ChildPropertyProxy_Base::get_property_(Glib::ValueBase& value) const
+{
+  gtk_container_child_get_property(parent_->gobj(), child_.gobj(), property_name_, value.gobj());
+}
+
+void ChildPropertyProxy_Base::reset_property_()
+{
+  // Get information about the parameter:
+  const GParamSpec *const pParamSpec =
+      gtk_container_class_find_child_property(G_OBJECT_GET_CLASS(parent_->gobj()), property_name_);
+
+  g_return_if_fail(pParamSpec != 0);
+
+  Glib::ValueBase value;
+  value.init(G_PARAM_SPEC_VALUE_TYPE(pParamSpec));
+
+  // An explicit reset is not needed, because ValueBase:init()
+  // has already initialized it to the default value for this type.
+  // value.reset();
+
+  set_property_(value);
+}
+
+} // namespace Gtk
diff --git a/gtk/gtkmm/childpropertyproxy_base.h b/gtk/gtkmm/childpropertyproxy_base.h
new file mode 100644
index 0000000..6ae0428
--- /dev/null
+++ b/gtk/gtkmm/childpropertyproxy_base.h
@@ -0,0 +1,71 @@
+// -*- c++ -*-
+#ifndef _GTKMM_CHILDPROPERTYPROXY_BASE_H
+#define _GTKMM_CHILDPROPERTYPROXY_BASE_H
+
+/* childpropertyproxy_base.h
+ *
+ * Copyright 2014 The gtkmm Development Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <glibmm/value.h>
+#include <glibmm/propertyproxy_base.h>
+#include <gtkmm/widget.h>
+
+#include <sigc++/sigc++.h>
+
+
+namespace Gtk
+{
+
+// We need to reimplement the connect() method so that it uses
+// "child-notify" as prefix for notify signal.
+class SignalProxyChildProperty : public Glib::SignalProxyProperty
+{
+public:
+  SignalProxyChildProperty(Widget* child, const char* property_name)
+    : Glib::SignalProxyProperty(child, property_name) {}
+
+  sigc::connection connect(const SlotType& sl);
+};
+
+class Container;
+
+class ChildPropertyProxy_Base
+{
+public:
+  ChildPropertyProxy_Base(Container* parent, Widget& child, const char* property_name);
+  ChildPropertyProxy_Base(const ChildPropertyProxy_Base& other);
+
+  SignalProxyChildProperty signal_changed();
+
+  Container* get_parent() const { return parent_; }
+  Widget& get_child() const { return child_; }
+  const char* get_name() const { return property_name_; }
+
+protected:
+  void set_property_(const Glib::ValueBase& value);
+  void get_property_(Glib::ValueBase& value) const;
+  void reset_property_();
+
+  Container* parent_;
+  Widget& child_;
+  const char* property_name_;
+};
+
+} // namespace Gtk
+
+#endif /* _GTKMM_CHILDPROPERTYPROXY_BASE_H */
diff --git a/gtk/gtkmm/filelist.am b/gtk/gtkmm/filelist.am
index cfe106d..337d6b2 100644
--- a/gtk/gtkmm/filelist.am
+++ b/gtk/gtkmm/filelist.am
@@ -8,6 +8,8 @@ gtkmm_files_extra_any_cc =              \
        accelkey.cc                     \
        accelmap.cc                     \
        cellrenderer_generation.cc      \
+       childpropertyproxy.cc \
+       childpropertyproxy_base.cc \
        listviewtext.cc                 \
        object.cc \
        radiobuttongroup.cc             \
@@ -26,6 +28,8 @@ gtkmm_files_extra_any_h =                     \
        base.h                          \
        border.h                        \
        cellrenderer_generation.h       \
+       childpropertyproxy.h \
+       childpropertyproxy_base.h \
        listviewtext.h                  \
        object.h \
        radiobuttongroup.h              \
diff --git a/gtk/src/container.hg b/gtk/src/container.hg
index 99f551f..75d0989 100644
--- a/gtk/src/container.hg
+++ b/gtk/src/container.hg
@@ -18,6 +18,7 @@
 #include <vector>
 
 #include <gtkmm/widget.h>
+#include <gtkmm/childpropertyproxy.h>
 
 _DEFS(gtkmm,gtk)
 _PINCLUDE(gtkmm/private/widget_p.h)
diff --git a/tools/extra_defs_gen/generate_defs_gtk.cc b/tools/extra_defs_gen/generate_defs_gtk.cc
index 210a6f3..30fa543 100644
--- a/tools/extra_defs_gen/generate_defs_gtk.cc
+++ b/tools/extra_defs_gen/generate_defs_gtk.cc
@@ -40,6 +40,8 @@
 # include <gtk/gtkunixprint.h>
 #endif
 
+std::string get_child_properties(GType gtype);
+
 int main(int argc, char** argv)
 {
   gtk_init(&argc, &argv);
@@ -243,5 +245,64 @@ int main(int argc, char** argv)
             << get_defs( GTK_TYPE_WIDGET )
             << get_defs( GTK_TYPE_WINDOW )
             ;
+
+  std::cout << get_child_properties( GTK_TYPE_BIN )
+            << get_child_properties( GTK_TYPE_BOX )
+            << get_child_properties( GTK_TYPE_FIXED )
+            << get_child_properties( GTK_TYPE_FLOW_BOX )
+            << get_child_properties( GTK_TYPE_GRID )
+            << get_child_properties( GTK_TYPE_HEADER_BAR )
+            << get_child_properties( GTK_TYPE_PANED )
+            << get_child_properties( GTK_TYPE_ICON_VIEW )
+            << get_child_properties( GTK_TYPE_LAYOUT )
+            << get_child_properties( GTK_TYPE_LIST_BOX )
+            << get_child_properties( GTK_TYPE_MENU_SHELL )
+            << get_child_properties( GTK_TYPE_NOTEBOOK )
+#ifdef GDK_WINDOWING_X11
+            << get_child_properties( GTK_TYPE_SOCKET )
+#endif
+            << get_child_properties( GTK_TYPE_STACK )
+            << get_child_properties( GTK_TYPE_TEXT_VIEW )
+            << get_child_properties( GTK_TYPE_TOOLBAR )
+            << get_child_properties( GTK_TYPE_TOOL_ITEM_GROUP )
+            << get_child_properties( GTK_TYPE_TOOL_PALETTE )
+            << get_child_properties( GTK_TYPE_TREE_VIEW )
+            ;
+
   return 0;
 }
+
+std::string get_child_properties(GType gtype)
+{
+  std::string strResult; std::string strObjectName = g_type_name(gtype);
+
+  //Get the list of properties:
+  GParamSpec** ppParamSpec = 0;
+  guint iCount = 0;
+  if(g_type_is_a(gtype, GTK_TYPE_CONTAINER))
+  {
+    GObjectClass* pGClass = G_OBJECT_CLASS(g_type_class_ref(gtype));
+    ppParamSpec = gtk_container_class_list_child_properties (pGClass, &iCount);
+    g_type_class_unref(pGClass);
+
+    if(!ppParamSpec)
+    {
+      strResult += ";; Warning: gtk_container_class_list_child_properties() returned NULL for " + 
std::string(g_type_name(gtype)) + "\n";
+      iCount = 0;
+    }
+  }
+
+  for(guint i = 0; i < iCount; i++)
+  {
+    GParamSpec* pParamSpec = ppParamSpec[i];
+
+    if(pParamSpec && pParamSpec->owner_type == gtype)
+    {
+      strResult += get_property_with_node_name(pParamSpec, strObjectName, "define-child-property");
+    }
+  }
+
+  g_free(ppParamSpec);
+
+  return strResult;
+}
diff --git a/tools/m4/child_property.m4 b/tools/m4/child_property.m4
new file mode 100644
index 0000000..6add346
--- /dev/null
+++ b/tools/m4/child_property.m4
@@ -0,0 +1,37 @@
+dnl
+dnl
+dnl  Code generation sections for GtkContainer child properties
+dnl
+dnl
+
+dnl                       $1         $2            $3          $4           $5        $6
+dnl _CHILD_PROPERTY_PROXY(name, name_underscored, cpp_type, proxy_suffix, deprecated, docs)
+dnl proxy_suffix could be "", "_WriteOnly" or "_ReadOnly"
+dnl The method will be const if the propertyproxy is _ReadOnly.
+dnl
+define(`_CHILD_PROPERTY_PROXY',`dnl
+dnl
+dnl Put spaces around the template parameter if necessary.
+pushdef(`__PROXY_TYPE__',`dnl
+Gtk::ChildPropertyProxy$4< _QUOTE($3) >'dnl
+)dnl
+/** $6
+   *
+   * @return A ChildPropertyProxy$4 that allows you to dnl
+ifelse($4,_ReadOnly,get,`ifelse($4,_WriteOnly,set,get or set)') the value of the property,
+   * or receive notification when the value of the property changes.
+   */
+  __PROXY_TYPE__ child_property_$2`'(ifelse($4,_ReadOnly,const ,)Gtk::Widget& child) ifelse($4,_ReadOnly, 
const,);
+_PUSH(SECTION_CC_PROPERTYPROXIES)
+ifelse(`$5',,,`_DEPRECATE_IFDEF_START
+')dnl
+__PROXY_TYPE__ __CPPNAME__::child_property_$2`'(ifelse($4,_ReadOnly,const ,)Gtk::Widget& child) 
ifelse($4,_ReadOnly, const,)
+{
+  return __PROXY_TYPE__`'(this, child, "$1");
+}
+ifelse(`$5',,,`_DEPRECATE_IFDEF_END
+')dnl
+
+_POP()
+popdef(`__PROXY_TYPE__')dnl
+')dnl
diff --git a/tools/m4/convert_gtkmm.m4 b/tools/m4/convert_gtkmm.m4
index 9c5353c..1c9f4e1 100644
--- a/tools/m4/convert_gtkmm.m4
+++ b/tools/m4/convert_gtkmm.m4
@@ -17,6 +17,7 @@
 ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
 include(class_gtkobject.m4)
+include(child_property.m4)
 include(convert_base.m4)
 include(convert_gtk.m4)
 include(convert_gdk.m4)
diff --git a/tools/m4/filelist.am b/tools/m4/filelist.am
index 9e489f2..c6196a1 100644
--- a/tools/m4/filelist.am
+++ b/tools/m4/filelist.am
@@ -18,6 +18,7 @@
 
 files_codegen_m4 =             \
        class_gtkobject.m4              \
+       child_property.m4               \
        convert.m4              \
        convert_gdk.m4          \
        convert_gtk.m4          \


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