[gtkmm/wip/dboles/builder-nicer-4] Builder: Add get_object<Derived>(name) overloads



commit b43773fefaa7ed589301f026a2e70e876e7850c2
Author: Daniel Boles <dboles src gnome org>
Date:   Mon Dec 17 18:19:39 2018 +0000

    Builder: Add get_object<Derived>(name) overloads
    
    Allow getting and casting to a subclass of Glib::Object in one line,
    thus making it nicer to deal with non-widget objects in Builder files.
    
    The non-template and template member functions act as distinct
    overloads, meaning the new ones can be named get_object() also.
    
    Add a Gtk::Adjustment to tests/builder, and check its refcounts are OK.
    Also add a g_assert that (A) ensures that the test compiles, i.e. we got
    the right type in the RefPtr and (B) checks we get the right :value out.
    In case (B) seems frivolous, I did see it not working due to prop order!
    Adjustment:value needs set after :lower|:upper as it is clamped by them.
    
    While here, g_assert() the mm pointers/RefPtrs just to be fully paranoid
    
    https://gitlab.gnome.org/GNOME/gtkmm/issues/43

 gtk/src/builder.hg    | 32 ++++++++++++++++++++++++++++++++
 tests/builder/main.cc | 34 ++++++++++++++++++++++++++++++----
 2 files changed, 62 insertions(+), 4 deletions(-)
---
diff --git a/gtk/src/builder.hg b/gtk/src/builder.hg
index 09c4707c..def5df1a 100644
--- a/gtk/src/builder.hg
+++ b/gtk/src/builder.hg
@@ -57,6 +57,7 @@ _WRAP_GERROR(BuilderError,GtkBuilderError,GTK_BUILDER_ERROR)
  * not have to worry about their lifecycle), or without a parent, in which
  * case they have to be added to some container before the builder is deleted
  * to make use of them.
+ *
  * Non-widget objects need to be fetched with get_object() or get_objects()
  * to keep them beyond the lifespan of the builder.
  *
@@ -424,6 +425,7 @@ public:
   //TODO: Custom-implement this and prevent it from being used with GTK_WIDGET-derived types?
   // A Builder can contain objects that don't derive from Buildable,
   // for instance if objects have been added with expose_object().
+
   /** Gets the object named @a name.
    *
    * @newin{2,12}
@@ -432,6 +434,7 @@ public:
    * @return The object named @a name or <tt>nullptr</tt> if it could not be found in the object tree.
    */
   _WRAP_METHOD(Glib::RefPtr<Glib::Object> get_object(const Glib::ustring& name), gtk_builder_get_object, 
refreturn)
+
   /** Gets the object named @a name.
    *
    * @newin{3,8}
@@ -441,6 +444,35 @@ public:
    */
   _WRAP_METHOD(Glib::RefPtr<const Glib::Object> get_object(const Glib::ustring& name) const, 
gtk_builder_get_object, refreturn, constversion)
 
+  /** Gets the object named @a name, cast to a specific derived type.
+   *
+   * For instance:
+   * @code
+   * auto adjustment = refBuilder->get_object<Gtk::Adjustment>("adjustment_id");
+   * adjustment->set_value(42);
+   * @endcode
+   *
+   * @newin{3,94}
+   *
+   * @param name Name of object to get.
+   * @return The object named @a name or <tt>nullptr</tt> if it could not be
+   *   found in the object tree or could not be cast to the specified type.
+   */
+  template <class T_Object> inline
+  Glib::RefPtr<T_Object> get_object(const Glib::ustring& name)
+  {
+    return std::dynamic_pointer_cast<T_Object>(get_object(name));
+  }
+
+  /** See the non-const version.
+   * @newin{3,94}
+   */
+  template <class T_Object> inline
+  Glib::RefPtr<const T_Object> get_object(const Glib::ustring& name) const
+  {
+    return const_cast<Builder*>(this)->get_object<const T_Object>(name);
+  }
+
   /** Gets a widget from the Builder file.
    * For instance:
    * @code
diff --git a/tests/builder/main.cc b/tests/builder/main.cc
index 39bde307..3bfda1de 100644
--- a/tests/builder/main.cc
+++ b/tests/builder/main.cc
@@ -66,6 +66,13 @@ const char gladefile[] =
     "<property name='can_focus'>True</property>"
     "<property name='receives_default'>True</property>"
   "</object>"
+  "<object class='GtkAdjustment' id='adjustment'>"
+    "<property name='lower'>0</property>"
+    "<property name='upper'>100</property>"
+    "<property name='value'>50</property>"
+    "<property name='step-increment'>1</property>"
+    "<property name='page-increment'>10</property>"
+  "</object>"
 "</interface>";
 
 void on_managed_button_deleted(sigc::notifiable* /* data */)
@@ -78,6 +85,11 @@ void on_orphaned_button_deleted(sigc::notifiable* /* data */)
   std::cout << "Orphaned Gtk::Button deleted" << std::endl;
 }
 
+void on_adjustment_deleted(sigc::notifiable* /* data */)
+{
+  std::cout << "Gtk::Adjustment deleted" << std::endl;
+}
+
 class DerivedButton : public Gtk::Button
 {
 public:
@@ -143,24 +155,35 @@ int main(int argc, char* argv[])
   }
 
   auto app = Gtk::Application::create();
+  g_assert_nonnull(app);
 
   auto builder = Gtk::Builder::create_from_string(gladefile);
+  g_assert_nonnull(builder);
 
   auto main_win = Gtk::Builder::get_widget_derived<MainWindow>(builder, "main_window");
+  g_assert_nonnull(main_win);
 
   auto orph_button = builder->get_widget<Gtk::Button>("orphaned_button");
+  g_assert_nonnull(orph_button);
   orph_button->add_destroy_notify_callback(nullptr, on_orphaned_button_deleted);
 
+  auto adjustment = builder->get_object<Gtk::Adjustment>("adjustment");
+  g_assert_nonnull(adjustment);
+  g_assert_cmpfloat(adjustment->get_value(), ==, 50);
+  adjustment->add_destroy_notify_callback(nullptr, on_adjustment_deleted);
+
   const GObject* const window = (GObject*)main_win->gobj();
   const GObject* const orphaned_button = (GObject*)orph_button->gobj();
   const GObject* const derived_button = (GObject*)main_win->get_derived_button()->gobj();
   const GObject* const standard_button = (GObject*)main_win->get_standard_button()->gobj();
+  const GObject* const adjustment_gobj = (GObject*)adjustment->gobj();
 
   std::cout << "Before app->run(*main_win, argc1, argv)" << std::endl
     << "  ref_count(MainWindow)=" << window->ref_count << std::endl
     << "  ref_count(DerivedButton)=" << derived_button->ref_count << std::endl
     << "  ref_count(Gtk::Button)=" << standard_button->ref_count << std::endl
-    << "  ref_count(orphaned_button)=" << orphaned_button->ref_count << std::endl;
+    << "  ref_count(orphaned_button)=" << orphaned_button->ref_count << std::endl
+    << "  ref_count(adjustment)=" << adjustment_gobj->ref_count << std::endl;
 
   const int result = app->run(*main_win, argc1, argv);
 
@@ -168,7 +191,8 @@ int main(int argc, char* argv[])
     << "  ref_count(MainWindow)=" << window->ref_count << std::endl
     << "  ref_count(DerivedButton)=" << derived_button->ref_count << std::endl
     << "  ref_count(Gtk::Button)=" << standard_button->ref_count << std::endl
-    << "  ref_count(orphaned_button)=" << orphaned_button->ref_count << std::endl;
+    << "  ref_count(orphaned_button)=" << orphaned_button->ref_count << std::endl
+    << "  ref_count(adjustment)=" << adjustment_gobj->ref_count << std::endl;
 
   delete main_win;
 
@@ -176,7 +200,8 @@ int main(int argc, char* argv[])
     << "  ref_count(MainWindow)=" << window->ref_count << std::endl
     << "  ref_count(DerivedButton)=" << derived_button->ref_count << std::endl
     << "  ref_count(Gtk::Button)=" << standard_button->ref_count << std::endl
-    << "  ref_count(orphaned_button)=" << orphaned_button->ref_count << std::endl;
+    << "  ref_count(orphaned_button)=" << orphaned_button->ref_count << std::endl
+    << "  ref_count(adjustment)=" << adjustment_gobj->ref_count << std::endl;
 
   builder.reset();
 
@@ -187,7 +212,8 @@ int main(int argc, char* argv[])
       << "  ref_count(MainWindow)=" << window->ref_count << std::endl
       << "  ref_count(DerivedButton)=" << derived_button->ref_count << std::endl
       << "  ref_count(Gtk::Button)=" << standard_button->ref_count << std::endl
-      << "  ref_count(orphaned_button)=" << orphaned_button->ref_count << std::endl;
+      << "  ref_count(orphaned_button)=" << orphaned_button->ref_count << std::endl
+      << "  ref_count(adjustment)=" << adjustment_gobj->ref_count << std::endl;
   }
 
   return result;


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