[glade] Move GladeWidgetAdaptor code for GtkNotebook into it's own C file



commit aacacff97129aef802635aaee0b76997b3462996
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Fri May 3 22:20:44 2013 +0900

    Move GladeWidgetAdaptor code for GtkNotebook into it's own C file

 plugins/gtk+/Makefile.am          |    2 +
 plugins/gtk+/glade-gtk-box.c      |    2 +-
 plugins/gtk+/glade-gtk-notebook.c |  959 +++++++++++++++++++++++++++++++++++++
 plugins/gtk+/glade-gtk-notebook.h |   40 ++
 plugins/gtk+/glade-gtk.c          |  933 ------------------------------------
 plugins/gtk+/glade-gtk.h          |   13 -
 po/POTFILES.in                    |    1 +
 7 files changed, 1003 insertions(+), 947 deletions(-)
---
diff --git a/plugins/gtk+/Makefile.am b/plugins/gtk+/Makefile.am
index 73b8652..7e017f8 100644
--- a/plugins/gtk+/Makefile.am
+++ b/plugins/gtk+/Makefile.am
@@ -39,6 +39,7 @@ libgladegtk_la_SOURCES =              \
        glade-gtk-frame.c               \
        glade-gtk-grid.c                \
        glade-gtk-info-bar.c            \
+       glade-gtk-notebook.c            \
        glade-gtk-switch.c              \
        glade-gtk-table.c               \
        glade-gtk-widget.c              \
@@ -72,6 +73,7 @@ noinst_HEADERS =                      \
        glade-gtk.h                     \
        glade-gtk-action-widgets.h      \
        glade-gtk-frame.h               \
+       glade-gtk-notebook.h            \
        glade-icon-factory-editor.h     \
        glade-icon-sources.h            \
        glade-image-editor.h            \
diff --git a/plugins/gtk+/glade-gtk-box.c b/plugins/gtk+/glade-gtk-box.c
index 1eac6a3..1f13282 100644
--- a/plugins/gtk+/glade-gtk-box.c
+++ b/plugins/gtk+/glade-gtk-box.c
@@ -27,9 +27,9 @@
 #include <string.h>
 
 #include "glade-fixed.h"
+#include "glade-gtk-notebook.h"
 #include "glade-gtk.h"
 
-
 static gboolean glade_gtk_box_configure_child (GladeFixed * fixed,
                                               GladeWidget * child,
                                               GdkRectangle * rect,
diff --git a/plugins/gtk+/glade-gtk-notebook.c b/plugins/gtk+/glade-gtk-notebook.c
new file mode 100644
index 0000000..e069d9d
--- /dev/null
+++ b/plugins/gtk+/glade-gtk-notebook.c
@@ -0,0 +1,959 @@
+/*
+ * glade-gtk-notebook.c - GladeWidgetAdaptor for GtkNotebook
+ *
+ * Copyright (C) 2013 Tristan Van Berkom
+ *
+ * Authors:
+ *      Tristan Van Berkom <tristan van berkom gmail com>
+ *
+ * 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 program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <config.h>
+#include <glib/gi18n-lib.h>
+#include <gladeui/glade.h>
+
+#include "glade-gtk-notebook.h"
+
+typedef struct
+{
+  gint pages;
+  gint page;
+
+  GList *children;
+  GList *tabs;
+
+  GList *extra_children;
+  GList *extra_tabs;
+} NotebookChildren;
+
+static gboolean glade_gtk_notebook_setting_position = FALSE;
+
+static gint
+notebook_child_compare_func (GtkWidget * widget_a, GtkWidget * widget_b)
+{
+  GladeWidget *gwidget_a, *gwidget_b;
+  gint pos_a = 0, pos_b = 0;
+
+  gwidget_a = glade_widget_get_from_gobject (widget_a);
+  gwidget_b = glade_widget_get_from_gobject (widget_b);
+
+  g_assert (gwidget_a && gwidget_b);
+
+  glade_widget_pack_property_get (gwidget_a, "position", &pos_a);
+  glade_widget_pack_property_get (gwidget_b, "position", &pos_b);
+
+  return pos_a - pos_b;
+}
+
+static gint
+notebook_find_child (GtkWidget * check, gpointer cmp_pos_p)
+{
+  GladeWidget *gcheck;
+  gint position = 0, cmp_pos = GPOINTER_TO_INT (cmp_pos_p);
+
+  gcheck = glade_widget_get_from_gobject (check);
+  g_assert (gcheck);
+
+  glade_widget_pack_property_get (gcheck, "position", &position);
+
+  return position - cmp_pos;
+}
+
+static gint
+notebook_search_tab (GtkNotebook * notebook, GtkWidget * tab)
+{
+  GtkWidget *page;
+  gint i;
+
+  for (i = 0; i < gtk_notebook_get_n_pages (notebook); i++)
+    {
+      page = gtk_notebook_get_nth_page (notebook, i);
+
+      if (tab == gtk_notebook_get_tab_label (notebook, page))
+        return i;
+    }
+  g_critical ("Unable to find tab position in a notebook");
+  return -1;
+}
+
+static GtkWidget *
+notebook_get_filler (NotebookChildren * nchildren, gboolean page)
+{
+  GtkWidget *widget = NULL;
+
+  if (page && nchildren->extra_children)
+    {
+      widget = nchildren->extra_children->data;
+      nchildren->extra_children =
+          g_list_remove (nchildren->extra_children, widget);
+      g_assert (widget);
+    }
+  else if (!page && nchildren->extra_tabs)
+    {
+      widget = nchildren->extra_tabs->data;
+      nchildren->extra_tabs = g_list_remove (nchildren->extra_tabs, widget);
+      g_assert (widget);
+    }
+
+  if (widget == NULL)
+    {
+      /* Need explicit reference here */
+      widget = glade_placeholder_new ();
+
+      g_object_ref (G_OBJECT (widget));
+
+      if (!page)
+        g_object_set_data (G_OBJECT (widget), "special-child-type", "tab");
+
+    }
+  return widget;
+}
+
+static GtkWidget *
+notebook_get_page (NotebookChildren * nchildren, gint position)
+{
+  GList *node;
+  GtkWidget *widget = NULL;
+
+  if ((node = g_list_find_custom
+       (nchildren->children,
+        GINT_TO_POINTER (position),
+        (GCompareFunc) notebook_find_child)) != NULL)
+    {
+      widget = node->data;
+      nchildren->children = g_list_remove (nchildren->children, widget);
+    }
+  else
+    widget = notebook_get_filler (nchildren, TRUE);
+
+  return widget;
+}
+
+static GtkWidget *
+notebook_get_tab (NotebookChildren * nchildren, gint position)
+{
+  GList *node;
+  GtkWidget *widget = NULL;
+
+  if ((node = g_list_find_custom
+       (nchildren->tabs,
+        GINT_TO_POINTER (position),
+        (GCompareFunc) notebook_find_child)) != NULL)
+    {
+      widget = node->data;
+      nchildren->tabs = g_list_remove (nchildren->tabs, widget);
+    }
+  else
+    widget = notebook_get_filler (nchildren, FALSE);
+
+  return widget;
+}
+
+static NotebookChildren *
+glade_gtk_notebook_extract_children (GtkWidget * notebook)
+{
+  NotebookChildren *nchildren;
+  gchar *special_child_type;
+  GList *list, *children =
+      glade_util_container_get_all_children (GTK_CONTAINER (notebook));
+  GladeWidget *gchild;
+  gint position = 0;
+  GtkNotebook *nb;
+
+  nb = GTK_NOTEBOOK (notebook);
+  nchildren = g_new0 (NotebookChildren, 1);
+  nchildren->pages = gtk_notebook_get_n_pages (nb);
+  nchildren->page = gtk_notebook_get_current_page (nb);
+
+  /* Ref all the project widgets and build returned list first */
+  for (list = children; list; list = list->next)
+    {
+      if ((gchild = glade_widget_get_from_gobject (list->data)) != NULL)
+        {
+          special_child_type =
+              g_object_get_data (G_OBJECT (list->data), "special-child-type");
+
+          glade_widget_pack_property_get (gchild, "position", &position);
+
+          g_object_ref (G_OBJECT (list->data));
+
+          /* Sort it into the proper struct member
+           */
+          if (special_child_type == NULL)
+            {
+              if (g_list_find_custom (nchildren->children,
+                                      GINT_TO_POINTER (position),
+                                      (GCompareFunc) notebook_find_child))
+                nchildren->extra_children =
+                    g_list_insert_sorted
+                    (nchildren->extra_children, list->data,
+                     (GCompareFunc) notebook_child_compare_func);
+              else
+                nchildren->children =
+                    g_list_insert_sorted
+                    (nchildren->children, list->data,
+                     (GCompareFunc) notebook_child_compare_func);
+            }
+          else
+            {
+              if (g_list_find_custom (nchildren->tabs,
+                                      GINT_TO_POINTER (position),
+                                      (GCompareFunc) notebook_find_child))
+                nchildren->extra_tabs =
+                    g_list_insert_sorted
+                    (nchildren->extra_tabs, list->data,
+                     (GCompareFunc) notebook_child_compare_func);
+              else
+                nchildren->tabs =
+                    g_list_insert_sorted
+                    (nchildren->tabs, list->data,
+                     (GCompareFunc) notebook_child_compare_func);
+            }
+        }
+    }
+
+  /* Remove all pages, resulting in the unparenting of all widgets including tab-labels.
+   */
+  while (gtk_notebook_get_n_pages (nb) > 0)
+    {
+      GtkWidget *page = gtk_notebook_get_nth_page (nb, 0);
+      GtkWidget *tab = gtk_notebook_get_tab_label (nb, page);
+
+      if (tab)
+       g_object_ref (tab);
+
+      /* Explicitly remove the tab label first */
+      gtk_notebook_set_tab_label (nb, page, NULL);
+
+      /* FIXE: we need to unparent here to avoid anoying warning when reparenting */
+      if (tab)
+       {
+         gtk_widget_unparent (tab);
+         g_object_unref (tab);
+       }
+
+      gtk_notebook_remove_page (nb, 0);
+    }
+
+  if (children)
+    g_list_free (children);
+
+  return nchildren;
+}
+
+static void
+glade_gtk_notebook_insert_children (GtkWidget * notebook,
+                                    NotebookChildren * nchildren)
+{
+  gint i;
+
+  /*********************************************************
+   *                     INSERT PAGES                      *
+   *********************************************************/
+  for (i = 0; i < nchildren->pages; i++)
+    {
+      GtkWidget *page = notebook_get_page (nchildren, i);
+      GtkWidget *tab = notebook_get_tab (nchildren, i);
+
+      gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), page, tab, i);
+
+      g_object_unref (G_OBJECT (page));
+      g_object_unref (G_OBJECT (tab));
+    }
+
+  /* Stay on the same page */
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), nchildren->page);
+
+  /* Free the original lists now */
+  if (nchildren->children)
+    g_list_free (nchildren->children);
+
+  if (nchildren->tabs)
+    g_list_free (nchildren->tabs);
+
+  if (nchildren->children ||
+      nchildren->tabs || nchildren->extra_children || nchildren->extra_tabs)
+    g_critical ("Unbalanced children when inserting notebook children"
+                " (pages: %d tabs: %d extra pages: %d extra tabs %d)",
+                g_list_length (nchildren->children),
+                g_list_length (nchildren->tabs),
+                g_list_length (nchildren->extra_children),
+                g_list_length (nchildren->extra_tabs));
+
+  g_free (nchildren);
+}
+
+static void
+glade_gtk_notebook_switch_page (GtkNotebook * notebook,
+                                GtkWidget * page,
+                                guint page_num, gpointer user_data)
+{
+  GladeWidget *gnotebook = glade_widget_get_from_gobject (notebook);
+
+  glade_widget_property_set (gnotebook, "page", page_num);
+
+}
+
+/* Track project selection to set the notebook pages to display
+ * the selected widget.
+ */
+static void
+glade_gtk_notebook_selection_changed (GladeProject * project,
+                                      GladeWidget * gwidget)
+{
+  GList *list;
+  gint i;
+  GtkWidget *page, *sel_widget;
+  GtkNotebook *notebook = GTK_NOTEBOOK (glade_widget_get_object (gwidget));
+
+  if ((list = glade_project_selection_get (project)) != NULL &&
+      g_list_length (list) == 1)
+    {
+      sel_widget = list->data;
+
+      /* Check if selected widget is inside the notebook */
+      if (GTK_IS_WIDGET (sel_widget) &&
+          gtk_widget_is_ancestor (sel_widget, GTK_WIDGET (notebook)))
+        {
+          /* Find and activate the page */
+          for (i = 0;
+               i < gtk_notebook_get_n_pages (notebook);
+               i++)
+            {
+              page = gtk_notebook_get_nth_page (notebook, i);
+
+              if (sel_widget == page ||
+                  gtk_widget_is_ancestor (sel_widget, GTK_WIDGET (page)))
+                {
+                  glade_widget_property_set (gwidget, "page", i);
+                  return;
+                }
+            }
+        }
+    }
+}
+
+static void
+glade_gtk_notebook_project_changed (GladeWidget * gwidget,
+                                    GParamSpec * pspec, gpointer userdata)
+{
+  GladeProject
+      * project = glade_widget_get_project (gwidget),
+      *old_project =
+      g_object_get_data (G_OBJECT (gwidget), "notebook-project-ptr");
+
+  if (old_project)
+    g_signal_handlers_disconnect_by_func (G_OBJECT (old_project),
+                                          G_CALLBACK
+                                          (glade_gtk_notebook_selection_changed),
+                                          gwidget);
+
+  if (project)
+    g_signal_connect (G_OBJECT (project), "selection-changed",
+                      G_CALLBACK (glade_gtk_notebook_selection_changed),
+                      gwidget);
+
+  g_object_set_data (G_OBJECT (gwidget), "notebook-project-ptr", project);
+}
+
+void
+glade_gtk_notebook_post_create (GladeWidgetAdaptor * adaptor,
+                                GObject * notebook, GladeCreateReason reason)
+{
+  GladeWidget *gwidget = glade_widget_get_from_gobject (notebook);
+
+  gtk_notebook_popup_disable (GTK_NOTEBOOK (notebook));
+
+  g_signal_connect (G_OBJECT (gwidget), "notify::project",
+                    G_CALLBACK (glade_gtk_notebook_project_changed), NULL);
+
+  glade_gtk_notebook_project_changed (gwidget, NULL, NULL);
+
+  g_signal_connect (G_OBJECT (notebook), "switch-page",
+                    G_CALLBACK (glade_gtk_notebook_switch_page), NULL);
+}
+
+static gint
+glade_gtk_notebook_get_first_blank_page (GtkNotebook * notebook)
+{
+  GladeWidget *gwidget;
+  GtkWidget *widget;
+  gint position;
+
+  for (position = 0; position < gtk_notebook_get_n_pages (notebook); position++)
+    {
+      widget = gtk_notebook_get_nth_page (notebook, position);
+      if ((gwidget = glade_widget_get_from_gobject (widget)) != NULL)
+        {
+          GladeProperty *property =
+              glade_widget_get_property (gwidget, "position");
+          gint gwidget_position = g_value_get_int (glade_property_inline_value (property));
+
+          if ((gwidget_position - position) > 0)
+            return position;
+        }
+    }
+  return position;
+}
+
+static GladeWidget *
+glade_gtk_notebook_generate_tab (GladeWidget * notebook, gint page_id)
+{
+  static GladeWidgetAdaptor *wadaptor = NULL;
+  gchar *str;
+  GladeWidget *glabel;
+
+  if (wadaptor == NULL)
+    wadaptor = glade_widget_adaptor_get_by_type (GTK_TYPE_LABEL);
+
+  glabel = glade_widget_adaptor_create_widget (wadaptor, FALSE,
+                                               "parent", notebook,
+                                               "project",
+                                               glade_widget_get_project
+                                               (notebook), NULL);
+
+  str = g_strdup_printf ("page %d", page_id);
+  glade_widget_property_set (glabel, "label", str);
+  g_free (str);
+
+  g_object_set_data (glade_widget_get_object (glabel), "special-child-type", "tab");
+  gtk_widget_show (GTK_WIDGET (glade_widget_get_object (glabel)));
+
+  return glabel;
+}
+
+static void
+glade_gtk_notebook_set_n_pages (GObject * object, const GValue * value)
+{
+  GladeWidget *widget;
+  GtkNotebook *notebook;
+  GtkWidget *child_widget;
+  gint new_size, i;
+  gint old_size;
+
+  notebook = GTK_NOTEBOOK (object);
+  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
+
+  widget = glade_widget_get_from_gobject (GTK_WIDGET (notebook));
+  g_return_if_fail (widget != NULL);
+
+  new_size = g_value_get_int (value);
+  old_size = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));
+
+  /* Ensure base size of notebook */
+  if (glade_widget_superuser () == FALSE)
+    {
+      for (i = gtk_notebook_get_n_pages (notebook); i < new_size; i++)
+        {
+          gint position = glade_gtk_notebook_get_first_blank_page (notebook);
+          GtkWidget *placeholder = glade_placeholder_new ();
+          GladeWidget *gtab;
+
+          gtk_notebook_insert_page (notebook, placeholder, NULL, position);
+
+          /* XXX Ugly hack amongst many, this one only creates project widgets
+           * when the 'n-pages' of a notebook is initially set, otherwise it puts
+           * placeholders. (this makes the job easier when doing "insert before/after")
+           */
+          if (old_size == 0 && new_size > 1)
+            {
+              gtab = glade_gtk_notebook_generate_tab (widget, position + 1);
+
+              /* Must pass through GladeWidget api so that packing props
+               * are correctly assigned.
+               */
+              glade_widget_add_child (widget, gtab, FALSE);
+            }
+          else
+            {
+              GtkWidget *tab_placeholder = glade_placeholder_new ();
+
+              g_object_set_data (G_OBJECT (tab_placeholder),
+                                 "special-child-type", "tab");
+
+              gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), placeholder,
+                                          tab_placeholder);
+            }
+        }
+    }
+
+  /*
+   * Thing to remember is that GtkNotebook starts the
+   * page numbers from 0, not 1 (C-style). So we need to do
+   * old_size-1, where we're referring to "nth" widget.
+   */
+  while (old_size > new_size)
+    {
+      /* Get the last page and remove it (project objects have been cleared by
+       * the action code already). */
+      child_widget = gtk_notebook_get_nth_page (notebook, old_size - 1);
+
+      /* Ok there shouldnt be widget in the content area, that's
+       * the placeholder, we should clean up the project widget that
+       * we put in the tab here though (this happens in the case where
+       * we undo increasing the "pages" property).
+       */
+      if (glade_widget_get_from_gobject (child_widget))
+        g_critical ("Bug in notebook_set_n_pages()");
+
+      gtk_notebook_remove_page (notebook, old_size - 1);
+
+      old_size--;
+    }
+}
+
+void
+glade_gtk_notebook_set_property (GladeWidgetAdaptor * adaptor,
+                                 GObject * object,
+                                 const gchar * id, const GValue * value)
+{
+  if (!strcmp (id, "pages"))
+    glade_gtk_notebook_set_n_pages (object, value);
+  else
+    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object,
+                                                      id, value);
+}
+
+static gboolean
+glade_gtk_notebook_verify_n_pages (GObject * object, const GValue * value)
+{
+  GtkNotebook *notebook = GTK_NOTEBOOK (object);
+  GtkWidget *child_widget, *tab_widget;
+  gint old_size, new_size = g_value_get_int (value);
+
+  for (old_size = gtk_notebook_get_n_pages (notebook);
+       old_size > new_size; old_size--)
+    {
+      /* Get the last widget. */
+      child_widget = gtk_notebook_get_nth_page (notebook, old_size - 1);
+      tab_widget = gtk_notebook_get_tab_label (notebook, child_widget);
+
+      /* 
+       * If we got it, and its not a placeholder, remove it
+       * from project.
+       */
+      if (glade_widget_get_from_gobject (child_widget) ||
+          glade_widget_get_from_gobject (tab_widget))
+        return FALSE;
+    }
+  return TRUE;
+}
+
+gboolean
+glade_gtk_notebook_verify_property (GladeWidgetAdaptor * adaptor,
+                                    GObject * object,
+                                    const gchar * id, const GValue * value)
+{
+  if (!strcmp (id, "pages"))
+    return glade_gtk_notebook_verify_n_pages (object, value);
+  else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property)
+    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property (adaptor, object,
+                                                         id, value);
+
+  return TRUE;
+}
+
+void
+glade_gtk_notebook_add_child (GladeWidgetAdaptor * adaptor,
+                              GObject * object, GObject * child)
+{
+  GtkNotebook *notebook;
+  gint num_page, position = 0;
+  GtkWidget *last_page;
+  GladeWidget *gwidget;
+  gchar *special_child_type;
+
+  notebook = GTK_NOTEBOOK (object);
+
+  num_page = gtk_notebook_get_n_pages (notebook);
+  gwidget = glade_widget_get_from_gobject (object);
+
+  /* Just append pages blindly when loading/dupping
+   */
+  if (glade_widget_superuser ())
+    {
+      special_child_type = g_object_get_data (child, "special-child-type");
+      if (special_child_type && !strcmp (special_child_type, "tab"))
+        {
+          last_page = gtk_notebook_get_nth_page (notebook, num_page - 1);
+          gtk_notebook_set_tab_label (notebook, last_page, GTK_WIDGET (child));
+        }
+      else
+        {
+          gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (child));
+
+          glade_widget_property_set (gwidget, "pages", num_page + 1);
+
+          gwidget = glade_widget_get_from_gobject (child);
+          if (gwidget && glade_widget_get_packing_properties (gwidget))
+            glade_widget_pack_property_set (gwidget, "position", num_page);
+        }
+    }
+  else
+    {
+      NotebookChildren *nchildren;
+
+      /* Just destroy placeholders */
+      if (GLADE_IS_PLACEHOLDER (child))
+        gtk_widget_destroy (GTK_WIDGET (child));
+      else
+        {
+          gwidget = glade_widget_get_from_gobject (child);
+          g_assert (gwidget);
+
+          glade_widget_pack_property_get (gwidget, "position", &position);
+
+          nchildren =
+              glade_gtk_notebook_extract_children (GTK_WIDGET (notebook));
+
+          if (g_object_get_data (child, "special-child-type") != NULL)
+            {
+              if (g_list_find_custom (nchildren->tabs,
+                                      GINT_TO_POINTER (position),
+                                      (GCompareFunc) notebook_find_child))
+                nchildren->extra_tabs =
+                    g_list_insert_sorted
+                    (nchildren->extra_tabs, child,
+                     (GCompareFunc) notebook_child_compare_func);
+              else
+                nchildren->tabs =
+                    g_list_insert_sorted
+                    (nchildren->tabs, child,
+                     (GCompareFunc) notebook_child_compare_func);
+            }
+          else
+            {
+              if (g_list_find_custom (nchildren->children,
+                                      GINT_TO_POINTER (position),
+                                      (GCompareFunc) notebook_find_child))
+                nchildren->extra_children =
+                    g_list_insert_sorted
+                    (nchildren->extra_children, child,
+                     (GCompareFunc) notebook_child_compare_func);
+              else
+                nchildren->children =
+                    g_list_insert_sorted
+                    (nchildren->children, child,
+                     (GCompareFunc) notebook_child_compare_func);
+            }
+
+          /* Takes an explicit reference when sitting on the list */
+          g_object_ref (child);
+
+          glade_gtk_notebook_insert_children (GTK_WIDGET (notebook), nchildren);
+        }
+    }
+}
+
+void
+glade_gtk_notebook_remove_child (GladeWidgetAdaptor * adaptor,
+                                 GObject * object, GObject * child)
+{
+  NotebookChildren *nchildren;
+
+  nchildren = glade_gtk_notebook_extract_children (GTK_WIDGET (object));
+
+  if (g_list_find (nchildren->children, child))
+    {
+      nchildren->children = g_list_remove (nchildren->children, child);
+      g_object_unref (child);
+    }
+  else if (g_list_find (nchildren->extra_children, child))
+    {
+      nchildren->extra_children =
+          g_list_remove (nchildren->extra_children, child);
+      g_object_unref (child);
+    }
+  else if (g_list_find (nchildren->tabs, child))
+    {
+      nchildren->tabs = g_list_remove (nchildren->tabs, child);
+      g_object_unref (child);
+    }
+  else if (g_list_find (nchildren->extra_tabs, child))
+    {
+      nchildren->extra_tabs = g_list_remove (nchildren->extra_tabs, child);
+      g_object_unref (child);
+    }
+
+  glade_gtk_notebook_insert_children (GTK_WIDGET (object), nchildren);
+
+}
+
+void
+glade_gtk_notebook_replace_child (GladeWidgetAdaptor * adaptor,
+                                  GtkWidget * container,
+                                  GtkWidget * current, GtkWidget * new_widget)
+{
+  GtkNotebook *notebook;
+  GladeWidget *gcurrent, *gnew;
+  gint position = 0;
+
+  notebook = GTK_NOTEBOOK (container);
+
+  if ((gcurrent = glade_widget_get_from_gobject (current)) != NULL)
+    glade_widget_pack_property_get (gcurrent, "position", &position);
+  else
+    {
+      if ((position = gtk_notebook_page_num (notebook, current)) < 0)
+        {
+          position = notebook_search_tab (notebook, current);
+          g_assert (position >= 0);
+        }
+    }
+
+  if (g_object_get_data (G_OBJECT (current), "special-child-type"))
+    g_object_set_data (G_OBJECT (new_widget), "special-child-type", "tab");
+
+  glade_gtk_notebook_remove_child (adaptor,
+                                   G_OBJECT (container), G_OBJECT (current));
+
+  if (GLADE_IS_PLACEHOLDER (new_widget) == FALSE)
+    {
+      gnew = glade_widget_get_from_gobject (new_widget);
+
+      glade_gtk_notebook_add_child (adaptor,
+                                    G_OBJECT (container),
+                                    G_OBJECT (new_widget));
+
+      if (glade_widget_pack_property_set (gnew, "position", position) == FALSE)
+        g_critical ("No position property found on new widget");
+    }
+  else
+    gtk_widget_destroy (GTK_WIDGET (new_widget));
+}
+
+gboolean
+glade_gtk_notebook_child_verify_property (GladeWidgetAdaptor * adaptor,
+                                          GObject * container,
+                                          GObject * child,
+                                          const gchar * id, GValue * value)
+{
+  if (!strcmp (id, "position"))
+    return g_value_get_int (value) >= 0 &&
+        g_value_get_int (value) <
+        gtk_notebook_get_n_pages (GTK_NOTEBOOK (container));
+  else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_verify_property)
+    GWA_GET_CLASS
+        (GTK_TYPE_CONTAINER)->child_verify_property (adaptor,
+                                                     container, child,
+                                                     id, value);
+
+  return TRUE;
+}
+
+void
+glade_gtk_notebook_set_child_property (GladeWidgetAdaptor * adaptor,
+                                       GObject * container,
+                                       GObject * child,
+                                       const gchar * property_name,
+                                       const GValue * value)
+{
+  NotebookChildren *nchildren;
+
+  if (strcmp (property_name, "position") == 0)
+    {
+      /* If we are setting this internally, avoid feedback. */
+      if (glade_gtk_notebook_setting_position || glade_widget_superuser ())
+        return;
+
+      /* Just rebuild the notebook, property values are already set at this point */
+      nchildren = glade_gtk_notebook_extract_children (GTK_WIDGET (container));
+      glade_gtk_notebook_insert_children (GTK_WIDGET (container), nchildren);
+    }
+  /* packing properties are unsupported on tabs ... except "position" */
+  else if (g_object_get_data (child, "special-child-type") == NULL)
+    GWA_GET_CLASS
+        (GTK_TYPE_CONTAINER)->child_set_property (adaptor,
+                                                  container, child,
+                                                  property_name, value);
+}
+
+void
+glade_gtk_notebook_get_child_property (GladeWidgetAdaptor * adaptor,
+                                       GObject * container,
+                                       GObject * child,
+                                       const gchar * property_name,
+                                       GValue * value)
+{
+  gint position;
+
+  if (strcmp (property_name, "position") == 0)
+    {
+      if (g_object_get_data (child, "special-child-type") != NULL)
+        {
+          if ((position = notebook_search_tab (GTK_NOTEBOOK (container),
+                                               GTK_WIDGET (child))) >= 0)
+            g_value_set_int (value, position);
+          else
+            g_value_set_int (value, 0);
+        }
+      else
+        gtk_container_child_get_property (GTK_CONTAINER (container),
+                                          GTK_WIDGET (child),
+                                          property_name, value);
+    }
+  /* packing properties are unsupported on tabs ... except "position" */
+  else if (g_object_get_data (child, "special-child-type") == NULL)
+    gtk_container_child_get_property (GTK_CONTAINER (container),
+                                      GTK_WIDGET (child), property_name, value);
+}
+
+void
+glade_gtk_notebook_child_action_activate (GladeWidgetAdaptor * adaptor,
+                                          GObject * container,
+                                          GObject * object,
+                                          const gchar * action_path)
+{
+  if (strcmp (action_path, "insert_page_after") == 0)
+    {
+      glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
+                                                         object, "pages",
+                                                         _("Insert page on %s"),
+                                                         FALSE, TRUE);
+    }
+  else if (strcmp (action_path, "insert_page_before") == 0)
+    {
+      glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
+                                                         object, "pages",
+                                                         _("Insert page on %s"),
+                                                         FALSE, FALSE);
+    }
+  else if (strcmp (action_path, "remove_page") == 0)
+    {
+      glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
+                                                         object, "pages",
+                                                         _
+                                                         ("Remove page from %s"),
+                                                         TRUE, TRUE);
+    }
+  else
+    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_action_activate (adaptor,
+                                                               container,
+                                                               object,
+                                                               action_path);
+}
+
+/* Shared with glade-gtk-box.c */
+void
+glade_gtk_box_notebook_child_insert_remove_action (GladeWidgetAdaptor * adaptor,
+                                                   GObject * container,
+                                                   GObject * object,
+                                                   const gchar * size_prop,
+                                                   const gchar * group_format,
+                                                   gboolean remove,
+                                                   gboolean after)
+{
+  GladeWidget *parent;
+  GList *children, *l;
+  gint child_pos, size, offset;
+
+  if (GTK_IS_NOTEBOOK (container) &&
+      g_object_get_data (object, "special-child-type"))
+    /* Its a Tab! */
+    child_pos = notebook_search_tab (GTK_NOTEBOOK (container),
+                                     GTK_WIDGET (object));
+  else
+    gtk_container_child_get (GTK_CONTAINER (container),
+                             GTK_WIDGET (object), "position", &child_pos, NULL);
+
+  parent = glade_widget_get_from_gobject (container);
+  glade_command_push_group (group_format, glade_widget_get_name (parent));
+
+  /* Make sure widgets does not get destroyed */
+  children = glade_widget_adaptor_get_children (adaptor, container);
+  g_list_foreach (children, (GFunc) g_object_ref, NULL);
+
+  glade_widget_property_get (parent, size_prop, &size);
+
+  if (remove)
+    {
+      GList *del = NULL;
+      offset = -1;
+      /* Remove children first */
+      for (l = children; l; l = g_list_next (l))
+        {
+          GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
+          gint pos;
+
+          /* Skip placeholders */
+          if (gchild == NULL)
+            continue;
+
+          glade_widget_pack_property_get (gchild, "position", &pos);
+          if (pos == child_pos)
+            del = g_list_prepend (del, gchild);
+        }
+      if (del)
+        {
+          glade_command_delete (del);
+          g_list_free (del);
+        }
+    }
+  else
+    {
+      /* Expand container */
+      glade_command_set_property (glade_widget_get_property (parent, size_prop),
+                                  size + 1);
+      offset = 1;
+    }
+
+  /* Reoder children (fix the position property tracking widget positions) */
+  for (l = g_list_last (children); l; l = g_list_previous (l))
+    {
+      GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
+      gint pos;
+
+      /* Skip placeholders */
+      if (gchild == NULL)
+        continue;
+
+      glade_widget_pack_property_get (gchild, "position", &pos);
+      if ((after) ? pos > child_pos : pos >= child_pos)
+        glade_command_set_property (glade_widget_get_pack_property
+                                    (gchild, "position"), pos + offset);
+    }
+
+  if (remove)
+    {
+      /* Shrink container */
+      glade_command_set_property (glade_widget_get_property (parent, size_prop),
+                                  size - 1);
+    }
+  /* If it's a notebook we need to create an undoable tab now */
+  else if (GTK_IS_NOTEBOOK (container))
+    {
+      gint new_pos = after ? child_pos + 1 : child_pos;
+      GtkWidget *new_page;
+      GtkWidget *tab_placeholder;
+      GladeWidget *gtab;
+      GList list = { 0, };
+
+      new_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (container), new_pos);
+
+      /* Deleting the project widget gives us a real placeholder now */
+      new_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (container), new_pos);
+      tab_placeholder =
+          gtk_notebook_get_tab_label (GTK_NOTEBOOK (container), new_page);
+      gtab = glade_gtk_notebook_generate_tab (parent, new_pos + 1);
+      list.data = gtab;
+
+      glade_command_paste (&list, parent, GLADE_PLACEHOLDER (tab_placeholder),
+                          glade_widget_get_project (parent));
+    }
+
+  g_list_foreach (children, (GFunc) g_object_unref, NULL);
+  g_list_free (children);
+  glade_command_pop_group ();
+}
diff --git a/plugins/gtk+/glade-gtk-notebook.h b/plugins/gtk+/glade-gtk-notebook.h
new file mode 100644
index 0000000..bb5e835
--- /dev/null
+++ b/plugins/gtk+/glade-gtk-notebook.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 Tristan Van Berkom.
+ *
+ * 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 program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Authors:
+ *   Tristan Van Berkom <tvb gnome org>
+ */
+#ifndef _GLADE_GTK_NOTEBOOK_H_
+#define _GLADE_GTK_NOTEBOOK_H_
+
+#include <gtk/gtk.h>
+#include <gladeui/glade.h>
+
+G_BEGIN_DECLS
+
+void glade_gtk_box_notebook_child_insert_remove_action (GladeWidgetAdaptor * adaptor,
+                                                       GObject * container,
+                                                       GObject * object,
+                                                       const gchar * size_prop,
+                                                       const gchar * group_format,
+                                                       gboolean remove,
+                                                       gboolean after);
+
+
+G_END_DECLS
+
+#endif  /* _GLADE_GTK_NOTEBOOK_H_ */
diff --git a/plugins/gtk+/glade-gtk.c b/plugins/gtk+/glade-gtk.c
index fbca6a8..f9b0bd0 100644
--- a/plugins/gtk+/glade-gtk.c
+++ b/plugins/gtk+/glade-gtk.c
@@ -85,939 +85,6 @@ glade_gtk_init (const gchar * name)
 {
 }
 
-/* ----------------------------- GtkNotebook ------------------------------ */
-typedef struct
-{
-  gint pages;
-  gint page;
-
-  GList *children;
-  GList *tabs;
-
-  GList *extra_children;
-  GList *extra_tabs;
-} NotebookChildren;
-
-static gboolean glade_gtk_notebook_setting_position = FALSE;
-
-static gint
-notebook_child_compare_func (GtkWidget * widget_a, GtkWidget * widget_b)
-{
-  GladeWidget *gwidget_a, *gwidget_b;
-  gint pos_a = 0, pos_b = 0;
-
-  gwidget_a = glade_widget_get_from_gobject (widget_a);
-  gwidget_b = glade_widget_get_from_gobject (widget_b);
-
-  g_assert (gwidget_a && gwidget_b);
-
-  glade_widget_pack_property_get (gwidget_a, "position", &pos_a);
-  glade_widget_pack_property_get (gwidget_b, "position", &pos_b);
-
-  return pos_a - pos_b;
-}
-
-static gint
-notebook_find_child (GtkWidget * check, gpointer cmp_pos_p)
-{
-  GladeWidget *gcheck;
-  gint position = 0, cmp_pos = GPOINTER_TO_INT (cmp_pos_p);
-
-  gcheck = glade_widget_get_from_gobject (check);
-  g_assert (gcheck);
-
-  glade_widget_pack_property_get (gcheck, "position", &position);
-
-  return position - cmp_pos;
-}
-
-static gint
-notebook_search_tab (GtkNotebook * notebook, GtkWidget * tab)
-{
-  GtkWidget *page;
-  gint i;
-
-  for (i = 0; i < gtk_notebook_get_n_pages (notebook); i++)
-    {
-      page = gtk_notebook_get_nth_page (notebook, i);
-
-      if (tab == gtk_notebook_get_tab_label (notebook, page))
-        return i;
-    }
-  g_critical ("Unable to find tab position in a notebook");
-  return -1;
-}
-
-static GtkWidget *
-notebook_get_filler (NotebookChildren * nchildren, gboolean page)
-{
-  GtkWidget *widget = NULL;
-
-  if (page && nchildren->extra_children)
-    {
-      widget = nchildren->extra_children->data;
-      nchildren->extra_children =
-          g_list_remove (nchildren->extra_children, widget);
-      g_assert (widget);
-    }
-  else if (!page && nchildren->extra_tabs)
-    {
-      widget = nchildren->extra_tabs->data;
-      nchildren->extra_tabs = g_list_remove (nchildren->extra_tabs, widget);
-      g_assert (widget);
-    }
-
-  if (widget == NULL)
-    {
-      /* Need explicit reference here */
-      widget = glade_placeholder_new ();
-
-      g_object_ref (G_OBJECT (widget));
-
-      if (!page)
-        g_object_set_data (G_OBJECT (widget), "special-child-type", "tab");
-
-    }
-  return widget;
-}
-
-static GtkWidget *
-notebook_get_page (NotebookChildren * nchildren, gint position)
-{
-  GList *node;
-  GtkWidget *widget = NULL;
-
-  if ((node = g_list_find_custom
-       (nchildren->children,
-        GINT_TO_POINTER (position),
-        (GCompareFunc) notebook_find_child)) != NULL)
-    {
-      widget = node->data;
-      nchildren->children = g_list_remove (nchildren->children, widget);
-    }
-  else
-    widget = notebook_get_filler (nchildren, TRUE);
-
-  return widget;
-}
-
-static GtkWidget *
-notebook_get_tab (NotebookChildren * nchildren, gint position)
-{
-  GList *node;
-  GtkWidget *widget = NULL;
-
-  if ((node = g_list_find_custom
-       (nchildren->tabs,
-        GINT_TO_POINTER (position),
-        (GCompareFunc) notebook_find_child)) != NULL)
-    {
-      widget = node->data;
-      nchildren->tabs = g_list_remove (nchildren->tabs, widget);
-    }
-  else
-    widget = notebook_get_filler (nchildren, FALSE);
-
-  return widget;
-}
-
-static NotebookChildren *
-glade_gtk_notebook_extract_children (GtkWidget * notebook)
-{
-  NotebookChildren *nchildren;
-  gchar *special_child_type;
-  GList *list, *children =
-      glade_util_container_get_all_children (GTK_CONTAINER (notebook));
-  GladeWidget *gchild;
-  gint position = 0;
-  GtkNotebook *nb;
-
-  nb = GTK_NOTEBOOK (notebook);
-  nchildren = g_new0 (NotebookChildren, 1);
-  nchildren->pages = gtk_notebook_get_n_pages (nb);
-  nchildren->page = gtk_notebook_get_current_page (nb);
-
-  /* Ref all the project widgets and build returned list first */
-  for (list = children; list; list = list->next)
-    {
-      if ((gchild = glade_widget_get_from_gobject (list->data)) != NULL)
-        {
-          special_child_type =
-              g_object_get_data (G_OBJECT (list->data), "special-child-type");
-
-          glade_widget_pack_property_get (gchild, "position", &position);
-
-          g_object_ref (G_OBJECT (list->data));
-
-          /* Sort it into the proper struct member
-           */
-          if (special_child_type == NULL)
-            {
-              if (g_list_find_custom (nchildren->children,
-                                      GINT_TO_POINTER (position),
-                                      (GCompareFunc) notebook_find_child))
-                nchildren->extra_children =
-                    g_list_insert_sorted
-                    (nchildren->extra_children, list->data,
-                     (GCompareFunc) notebook_child_compare_func);
-              else
-                nchildren->children =
-                    g_list_insert_sorted
-                    (nchildren->children, list->data,
-                     (GCompareFunc) notebook_child_compare_func);
-            }
-          else
-            {
-              if (g_list_find_custom (nchildren->tabs,
-                                      GINT_TO_POINTER (position),
-                                      (GCompareFunc) notebook_find_child))
-                nchildren->extra_tabs =
-                    g_list_insert_sorted
-                    (nchildren->extra_tabs, list->data,
-                     (GCompareFunc) notebook_child_compare_func);
-              else
-                nchildren->tabs =
-                    g_list_insert_sorted
-                    (nchildren->tabs, list->data,
-                     (GCompareFunc) notebook_child_compare_func);
-            }
-        }
-    }
-
-  /* Remove all pages, resulting in the unparenting of all widgets including tab-labels.
-   */
-  while (gtk_notebook_get_n_pages (nb) > 0)
-    {
-      GtkWidget *page = gtk_notebook_get_nth_page (nb, 0);
-      GtkWidget *tab = gtk_notebook_get_tab_label (nb, page);
-
-      if (tab)
-       g_object_ref (tab);
-
-      /* Explicitly remove the tab label first */
-      gtk_notebook_set_tab_label (nb, page, NULL);
-
-      /* FIXE: we need to unparent here to avoid anoying warning when reparenting */
-      if (tab)
-       {
-         gtk_widget_unparent (tab);
-         g_object_unref (tab);
-       }
-
-      gtk_notebook_remove_page (nb, 0);
-    }
-
-  if (children)
-    g_list_free (children);
-
-  return nchildren;
-}
-
-static void
-glade_gtk_notebook_insert_children (GtkWidget * notebook,
-                                    NotebookChildren * nchildren)
-{
-  gint i;
-
-  /*********************************************************
-   *                     INSERT PAGES                      *
-   *********************************************************/
-  for (i = 0; i < nchildren->pages; i++)
-    {
-      GtkWidget *page = notebook_get_page (nchildren, i);
-      GtkWidget *tab = notebook_get_tab (nchildren, i);
-
-      gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), page, tab, i);
-
-      g_object_unref (G_OBJECT (page));
-      g_object_unref (G_OBJECT (tab));
-    }
-
-  /* Stay on the same page */
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), nchildren->page);
-
-  /* Free the original lists now */
-  if (nchildren->children)
-    g_list_free (nchildren->children);
-
-  if (nchildren->tabs)
-    g_list_free (nchildren->tabs);
-
-  if (nchildren->children ||
-      nchildren->tabs || nchildren->extra_children || nchildren->extra_tabs)
-    g_critical ("Unbalanced children when inserting notebook children"
-                " (pages: %d tabs: %d extra pages: %d extra tabs %d)",
-                g_list_length (nchildren->children),
-                g_list_length (nchildren->tabs),
-                g_list_length (nchildren->extra_children),
-                g_list_length (nchildren->extra_tabs));
-
-  g_free (nchildren);
-}
-
-static void
-glade_gtk_notebook_switch_page (GtkNotebook * notebook,
-                                GtkWidget * page,
-                                guint page_num, gpointer user_data)
-{
-  GladeWidget *gnotebook = glade_widget_get_from_gobject (notebook);
-
-  glade_widget_property_set (gnotebook, "page", page_num);
-
-}
-
-/* Track project selection to set the notebook pages to display
- * the selected widget.
- */
-static void
-glade_gtk_notebook_selection_changed (GladeProject * project,
-                                      GladeWidget * gwidget)
-{
-  GList *list;
-  gint i;
-  GtkWidget *page, *sel_widget;
-  GtkNotebook *notebook = GTK_NOTEBOOK (glade_widget_get_object (gwidget));
-
-  if ((list = glade_project_selection_get (project)) != NULL &&
-      g_list_length (list) == 1)
-    {
-      sel_widget = list->data;
-
-      /* Check if selected widget is inside the notebook */
-      if (GTK_IS_WIDGET (sel_widget) &&
-          gtk_widget_is_ancestor (sel_widget, GTK_WIDGET (notebook)))
-        {
-          /* Find and activate the page */
-          for (i = 0;
-               i < gtk_notebook_get_n_pages (notebook);
-               i++)
-            {
-              page = gtk_notebook_get_nth_page (notebook, i);
-
-              if (sel_widget == page ||
-                  gtk_widget_is_ancestor (sel_widget, GTK_WIDGET (page)))
-                {
-                  glade_widget_property_set (gwidget, "page", i);
-                  return;
-                }
-            }
-        }
-    }
-}
-
-static void
-glade_gtk_notebook_project_changed (GladeWidget * gwidget,
-                                    GParamSpec * pspec, gpointer userdata)
-{
-  GladeProject
-      * project = glade_widget_get_project (gwidget),
-      *old_project =
-      g_object_get_data (G_OBJECT (gwidget), "notebook-project-ptr");
-
-  if (old_project)
-    g_signal_handlers_disconnect_by_func (G_OBJECT (old_project),
-                                          G_CALLBACK
-                                          (glade_gtk_notebook_selection_changed),
-                                          gwidget);
-
-  if (project)
-    g_signal_connect (G_OBJECT (project), "selection-changed",
-                      G_CALLBACK (glade_gtk_notebook_selection_changed),
-                      gwidget);
-
-  g_object_set_data (G_OBJECT (gwidget), "notebook-project-ptr", project);
-}
-
-void
-glade_gtk_notebook_post_create (GladeWidgetAdaptor * adaptor,
-                                GObject * notebook, GladeCreateReason reason)
-{
-  GladeWidget *gwidget = glade_widget_get_from_gobject (notebook);
-
-  gtk_notebook_popup_disable (GTK_NOTEBOOK (notebook));
-
-  g_signal_connect (G_OBJECT (gwidget), "notify::project",
-                    G_CALLBACK (glade_gtk_notebook_project_changed), NULL);
-
-  glade_gtk_notebook_project_changed (gwidget, NULL, NULL);
-
-  g_signal_connect (G_OBJECT (notebook), "switch-page",
-                    G_CALLBACK (glade_gtk_notebook_switch_page), NULL);
-}
-
-static gint
-glade_gtk_notebook_get_first_blank_page (GtkNotebook * notebook)
-{
-  GladeWidget *gwidget;
-  GtkWidget *widget;
-  gint position;
-
-  for (position = 0; position < gtk_notebook_get_n_pages (notebook); position++)
-    {
-      widget = gtk_notebook_get_nth_page (notebook, position);
-      if ((gwidget = glade_widget_get_from_gobject (widget)) != NULL)
-        {
-          GladeProperty *property =
-              glade_widget_get_property (gwidget, "position");
-          gint gwidget_position = g_value_get_int (glade_property_inline_value (property));
-
-          if ((gwidget_position - position) > 0)
-            return position;
-        }
-    }
-  return position;
-}
-
-static GladeWidget *
-glade_gtk_notebook_generate_tab (GladeWidget * notebook, gint page_id)
-{
-  static GladeWidgetAdaptor *wadaptor = NULL;
-  gchar *str;
-  GladeWidget *glabel;
-
-  if (wadaptor == NULL)
-    wadaptor = glade_widget_adaptor_get_by_type (GTK_TYPE_LABEL);
-
-  glabel = glade_widget_adaptor_create_widget (wadaptor, FALSE,
-                                               "parent", notebook,
-                                               "project",
-                                               glade_widget_get_project
-                                               (notebook), NULL);
-
-  str = g_strdup_printf ("page %d", page_id);
-  glade_widget_property_set (glabel, "label", str);
-  g_free (str);
-
-  g_object_set_data (glade_widget_get_object (glabel), "special-child-type", "tab");
-  gtk_widget_show (GTK_WIDGET (glade_widget_get_object (glabel)));
-
-  return glabel;
-}
-
-static void
-glade_gtk_notebook_set_n_pages (GObject * object, const GValue * value)
-{
-  GladeWidget *widget;
-  GtkNotebook *notebook;
-  GtkWidget *child_widget;
-  gint new_size, i;
-  gint old_size;
-
-  notebook = GTK_NOTEBOOK (object);
-  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
-
-  widget = glade_widget_get_from_gobject (GTK_WIDGET (notebook));
-  g_return_if_fail (widget != NULL);
-
-  new_size = g_value_get_int (value);
-  old_size = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));
-
-  /* Ensure base size of notebook */
-  if (glade_widget_superuser () == FALSE)
-    {
-      for (i = gtk_notebook_get_n_pages (notebook); i < new_size; i++)
-        {
-          gint position = glade_gtk_notebook_get_first_blank_page (notebook);
-          GtkWidget *placeholder = glade_placeholder_new ();
-          GladeWidget *gtab;
-
-          gtk_notebook_insert_page (notebook, placeholder, NULL, position);
-
-          /* XXX Ugly hack amongst many, this one only creates project widgets
-           * when the 'n-pages' of a notebook is initially set, otherwise it puts
-           * placeholders. (this makes the job easier when doing "insert before/after")
-           */
-          if (old_size == 0 && new_size > 1)
-            {
-              gtab = glade_gtk_notebook_generate_tab (widget, position + 1);
-
-              /* Must pass through GladeWidget api so that packing props
-               * are correctly assigned.
-               */
-              glade_widget_add_child (widget, gtab, FALSE);
-            }
-          else
-            {
-              GtkWidget *tab_placeholder = glade_placeholder_new ();
-
-              g_object_set_data (G_OBJECT (tab_placeholder),
-                                 "special-child-type", "tab");
-
-              gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), placeholder,
-                                          tab_placeholder);
-            }
-        }
-    }
-
-  /*
-   * Thing to remember is that GtkNotebook starts the
-   * page numbers from 0, not 1 (C-style). So we need to do
-   * old_size-1, where we're referring to "nth" widget.
-   */
-  while (old_size > new_size)
-    {
-      /* Get the last page and remove it (project objects have been cleared by
-       * the action code already). */
-      child_widget = gtk_notebook_get_nth_page (notebook, old_size - 1);
-
-      /* Ok there shouldnt be widget in the content area, that's
-       * the placeholder, we should clean up the project widget that
-       * we put in the tab here though (this happens in the case where
-       * we undo increasing the "pages" property).
-       */
-      if (glade_widget_get_from_gobject (child_widget))
-        g_critical ("Bug in notebook_set_n_pages()");
-
-      gtk_notebook_remove_page (notebook, old_size - 1);
-
-      old_size--;
-    }
-}
-
-void
-glade_gtk_notebook_set_property (GladeWidgetAdaptor * adaptor,
-                                 GObject * object,
-                                 const gchar * id, const GValue * value)
-{
-  if (!strcmp (id, "pages"))
-    glade_gtk_notebook_set_n_pages (object, value);
-  else
-    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object,
-                                                      id, value);
-}
-
-static gboolean
-glade_gtk_notebook_verify_n_pages (GObject * object, const GValue * value)
-{
-  GtkNotebook *notebook = GTK_NOTEBOOK (object);
-  GtkWidget *child_widget, *tab_widget;
-  gint old_size, new_size = g_value_get_int (value);
-
-  for (old_size = gtk_notebook_get_n_pages (notebook);
-       old_size > new_size; old_size--)
-    {
-      /* Get the last widget. */
-      child_widget = gtk_notebook_get_nth_page (notebook, old_size - 1);
-      tab_widget = gtk_notebook_get_tab_label (notebook, child_widget);
-
-      /* 
-       * If we got it, and its not a placeholder, remove it
-       * from project.
-       */
-      if (glade_widget_get_from_gobject (child_widget) ||
-          glade_widget_get_from_gobject (tab_widget))
-        return FALSE;
-    }
-  return TRUE;
-}
-
-gboolean
-glade_gtk_notebook_verify_property (GladeWidgetAdaptor * adaptor,
-                                    GObject * object,
-                                    const gchar * id, const GValue * value)
-{
-  if (!strcmp (id, "pages"))
-    return glade_gtk_notebook_verify_n_pages (object, value);
-  else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property)
-    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property (adaptor, object,
-                                                         id, value);
-
-  return TRUE;
-}
-
-void
-glade_gtk_notebook_add_child (GladeWidgetAdaptor * adaptor,
-                              GObject * object, GObject * child)
-{
-  GtkNotebook *notebook;
-  gint num_page, position = 0;
-  GtkWidget *last_page;
-  GladeWidget *gwidget;
-  gchar *special_child_type;
-
-  notebook = GTK_NOTEBOOK (object);
-
-  num_page = gtk_notebook_get_n_pages (notebook);
-  gwidget = glade_widget_get_from_gobject (object);
-
-  /* Just append pages blindly when loading/dupping
-   */
-  if (glade_widget_superuser ())
-    {
-      special_child_type = g_object_get_data (child, "special-child-type");
-      if (special_child_type && !strcmp (special_child_type, "tab"))
-        {
-          last_page = gtk_notebook_get_nth_page (notebook, num_page - 1);
-          gtk_notebook_set_tab_label (notebook, last_page, GTK_WIDGET (child));
-        }
-      else
-        {
-          gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (child));
-
-          glade_widget_property_set (gwidget, "pages", num_page + 1);
-
-          gwidget = glade_widget_get_from_gobject (child);
-          if (gwidget && glade_widget_get_packing_properties (gwidget))
-            glade_widget_pack_property_set (gwidget, "position", num_page);
-        }
-    }
-  else
-    {
-      NotebookChildren *nchildren;
-
-      /* Just destroy placeholders */
-      if (GLADE_IS_PLACEHOLDER (child))
-        gtk_widget_destroy (GTK_WIDGET (child));
-      else
-        {
-          gwidget = glade_widget_get_from_gobject (child);
-          g_assert (gwidget);
-
-          glade_widget_pack_property_get (gwidget, "position", &position);
-
-          nchildren =
-              glade_gtk_notebook_extract_children (GTK_WIDGET (notebook));
-
-          if (g_object_get_data (child, "special-child-type") != NULL)
-            {
-              if (g_list_find_custom (nchildren->tabs,
-                                      GINT_TO_POINTER (position),
-                                      (GCompareFunc) notebook_find_child))
-                nchildren->extra_tabs =
-                    g_list_insert_sorted
-                    (nchildren->extra_tabs, child,
-                     (GCompareFunc) notebook_child_compare_func);
-              else
-                nchildren->tabs =
-                    g_list_insert_sorted
-                    (nchildren->tabs, child,
-                     (GCompareFunc) notebook_child_compare_func);
-            }
-          else
-            {
-              if (g_list_find_custom (nchildren->children,
-                                      GINT_TO_POINTER (position),
-                                      (GCompareFunc) notebook_find_child))
-                nchildren->extra_children =
-                    g_list_insert_sorted
-                    (nchildren->extra_children, child,
-                     (GCompareFunc) notebook_child_compare_func);
-              else
-                nchildren->children =
-                    g_list_insert_sorted
-                    (nchildren->children, child,
-                     (GCompareFunc) notebook_child_compare_func);
-            }
-
-          /* Takes an explicit reference when sitting on the list */
-          g_object_ref (child);
-
-          glade_gtk_notebook_insert_children (GTK_WIDGET (notebook), nchildren);
-        }
-    }
-}
-
-void
-glade_gtk_notebook_remove_child (GladeWidgetAdaptor * adaptor,
-                                 GObject * object, GObject * child)
-{
-  NotebookChildren *nchildren;
-
-  nchildren = glade_gtk_notebook_extract_children (GTK_WIDGET (object));
-
-  if (g_list_find (nchildren->children, child))
-    {
-      nchildren->children = g_list_remove (nchildren->children, child);
-      g_object_unref (child);
-    }
-  else if (g_list_find (nchildren->extra_children, child))
-    {
-      nchildren->extra_children =
-          g_list_remove (nchildren->extra_children, child);
-      g_object_unref (child);
-    }
-  else if (g_list_find (nchildren->tabs, child))
-    {
-      nchildren->tabs = g_list_remove (nchildren->tabs, child);
-      g_object_unref (child);
-    }
-  else if (g_list_find (nchildren->extra_tabs, child))
-    {
-      nchildren->extra_tabs = g_list_remove (nchildren->extra_tabs, child);
-      g_object_unref (child);
-    }
-
-  glade_gtk_notebook_insert_children (GTK_WIDGET (object), nchildren);
-
-}
-
-void
-glade_gtk_notebook_replace_child (GladeWidgetAdaptor * adaptor,
-                                  GtkWidget * container,
-                                  GtkWidget * current, GtkWidget * new_widget)
-{
-  GtkNotebook *notebook;
-  GladeWidget *gcurrent, *gnew;
-  gint position = 0;
-
-  notebook = GTK_NOTEBOOK (container);
-
-  if ((gcurrent = glade_widget_get_from_gobject (current)) != NULL)
-    glade_widget_pack_property_get (gcurrent, "position", &position);
-  else
-    {
-      if ((position = gtk_notebook_page_num (notebook, current)) < 0)
-        {
-          position = notebook_search_tab (notebook, current);
-          g_assert (position >= 0);
-        }
-    }
-
-  if (g_object_get_data (G_OBJECT (current), "special-child-type"))
-    g_object_set_data (G_OBJECT (new_widget), "special-child-type", "tab");
-
-  glade_gtk_notebook_remove_child (adaptor,
-                                   G_OBJECT (container), G_OBJECT (current));
-
-  if (GLADE_IS_PLACEHOLDER (new_widget) == FALSE)
-    {
-      gnew = glade_widget_get_from_gobject (new_widget);
-
-      glade_gtk_notebook_add_child (adaptor,
-                                    G_OBJECT (container),
-                                    G_OBJECT (new_widget));
-
-      if (glade_widget_pack_property_set (gnew, "position", position) == FALSE)
-        g_critical ("No position property found on new widget");
-    }
-  else
-    gtk_widget_destroy (GTK_WIDGET (new_widget));
-}
-
-gboolean
-glade_gtk_notebook_child_verify_property (GladeWidgetAdaptor * adaptor,
-                                          GObject * container,
-                                          GObject * child,
-                                          const gchar * id, GValue * value)
-{
-  if (!strcmp (id, "position"))
-    return g_value_get_int (value) >= 0 &&
-        g_value_get_int (value) <
-        gtk_notebook_get_n_pages (GTK_NOTEBOOK (container));
-  else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_verify_property)
-    GWA_GET_CLASS
-        (GTK_TYPE_CONTAINER)->child_verify_property (adaptor,
-                                                     container, child,
-                                                     id, value);
-
-  return TRUE;
-}
-
-void
-glade_gtk_notebook_set_child_property (GladeWidgetAdaptor * adaptor,
-                                       GObject * container,
-                                       GObject * child,
-                                       const gchar * property_name,
-                                       const GValue * value)
-{
-  NotebookChildren *nchildren;
-
-  if (strcmp (property_name, "position") == 0)
-    {
-      /* If we are setting this internally, avoid feedback. */
-      if (glade_gtk_notebook_setting_position || glade_widget_superuser ())
-        return;
-
-      /* Just rebuild the notebook, property values are already set at this point */
-      nchildren = glade_gtk_notebook_extract_children (GTK_WIDGET (container));
-      glade_gtk_notebook_insert_children (GTK_WIDGET (container), nchildren);
-    }
-  /* packing properties are unsupported on tabs ... except "position" */
-  else if (g_object_get_data (child, "special-child-type") == NULL)
-    GWA_GET_CLASS
-        (GTK_TYPE_CONTAINER)->child_set_property (adaptor,
-                                                  container, child,
-                                                  property_name, value);
-}
-
-void
-glade_gtk_notebook_get_child_property (GladeWidgetAdaptor * adaptor,
-                                       GObject * container,
-                                       GObject * child,
-                                       const gchar * property_name,
-                                       GValue * value)
-{
-  gint position;
-
-  if (strcmp (property_name, "position") == 0)
-    {
-      if (g_object_get_data (child, "special-child-type") != NULL)
-        {
-          if ((position = notebook_search_tab (GTK_NOTEBOOK (container),
-                                               GTK_WIDGET (child))) >= 0)
-            g_value_set_int (value, position);
-          else
-            g_value_set_int (value, 0);
-        }
-      else
-        gtk_container_child_get_property (GTK_CONTAINER (container),
-                                          GTK_WIDGET (child),
-                                          property_name, value);
-    }
-  /* packing properties are unsupported on tabs ... except "position" */
-  else if (g_object_get_data (child, "special-child-type") == NULL)
-    gtk_container_child_get_property (GTK_CONTAINER (container),
-                                      GTK_WIDGET (child), property_name, value);
-}
-
-/* Shared with glade-gtk-box.c */
-void
-glade_gtk_box_notebook_child_insert_remove_action (GladeWidgetAdaptor * adaptor,
-                                                   GObject * container,
-                                                   GObject * object,
-                                                   const gchar * size_prop,
-                                                   const gchar * group_format,
-                                                   gboolean remove,
-                                                   gboolean after)
-{
-  GladeWidget *parent;
-  GList *children, *l;
-  gint child_pos, size, offset;
-
-  if (GTK_IS_NOTEBOOK (container) &&
-      g_object_get_data (object, "special-child-type"))
-    /* Its a Tab! */
-    child_pos = notebook_search_tab (GTK_NOTEBOOK (container),
-                                     GTK_WIDGET (object));
-  else
-    gtk_container_child_get (GTK_CONTAINER (container),
-                             GTK_WIDGET (object), "position", &child_pos, NULL);
-
-  parent = glade_widget_get_from_gobject (container);
-  glade_command_push_group (group_format, glade_widget_get_name (parent));
-
-  /* Make sure widgets does not get destroyed */
-  children = glade_widget_adaptor_get_children (adaptor, container);
-  g_list_foreach (children, (GFunc) g_object_ref, NULL);
-
-  glade_widget_property_get (parent, size_prop, &size);
-
-  if (remove)
-    {
-      GList *del = NULL;
-      offset = -1;
-      /* Remove children first */
-      for (l = children; l; l = g_list_next (l))
-        {
-          GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
-          gint pos;
-
-          /* Skip placeholders */
-          if (gchild == NULL)
-            continue;
-
-          glade_widget_pack_property_get (gchild, "position", &pos);
-          if (pos == child_pos)
-            del = g_list_prepend (del, gchild);
-        }
-      if (del)
-        {
-          glade_command_delete (del);
-          g_list_free (del);
-        }
-    }
-  else
-    {
-      /* Expand container */
-      glade_command_set_property (glade_widget_get_property (parent, size_prop),
-                                  size + 1);
-      offset = 1;
-    }
-
-  /* Reoder children (fix the position property tracking widget positions) */
-  for (l = g_list_last (children); l; l = g_list_previous (l))
-    {
-      GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
-      gint pos;
-
-      /* Skip placeholders */
-      if (gchild == NULL)
-        continue;
-
-      glade_widget_pack_property_get (gchild, "position", &pos);
-      if ((after) ? pos > child_pos : pos >= child_pos)
-        glade_command_set_property (glade_widget_get_pack_property
-                                    (gchild, "position"), pos + offset);
-    }
-
-  if (remove)
-    {
-      /* Shrink container */
-      glade_command_set_property (glade_widget_get_property (parent, size_prop),
-                                  size - 1);
-    }
-  /* If it's a notebook we need to create an undoable tab now */
-  else if (GTK_IS_NOTEBOOK (container))
-    {
-      gint new_pos = after ? child_pos + 1 : child_pos;
-      GtkWidget *new_page;
-      GtkWidget *tab_placeholder;
-      GladeWidget *gtab;
-      GList list = { 0, };
-
-      new_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (container), new_pos);
-
-      /* Deleting the project widget gives us a real placeholder now */
-      new_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (container), new_pos);
-      tab_placeholder =
-          gtk_notebook_get_tab_label (GTK_NOTEBOOK (container), new_page);
-      gtab = glade_gtk_notebook_generate_tab (parent, new_pos + 1);
-      list.data = gtab;
-
-      glade_command_paste (&list, parent, GLADE_PLACEHOLDER (tab_placeholder),
-                          glade_widget_get_project (parent));
-    }
-
-  g_list_foreach (children, (GFunc) g_object_unref, NULL);
-  g_list_free (children);
-  glade_command_pop_group ();
-}
-
-void
-glade_gtk_notebook_child_action_activate (GladeWidgetAdaptor * adaptor,
-                                          GObject * container,
-                                          GObject * object,
-                                          const gchar * action_path)
-{
-  if (strcmp (action_path, "insert_page_after") == 0)
-    {
-      glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
-                                                         object, "pages",
-                                                         _("Insert page on %s"),
-                                                         FALSE, TRUE);
-    }
-  else if (strcmp (action_path, "insert_page_before") == 0)
-    {
-      glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
-                                                         object, "pages",
-                                                         _("Insert page on %s"),
-                                                         FALSE, FALSE);
-    }
-  else if (strcmp (action_path, "remove_page") == 0)
-    {
-      glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
-                                                         object, "pages",
-                                                         _
-                                                         ("Remove page from %s"),
-                                                         TRUE, TRUE);
-    }
-  else
-    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_action_activate (adaptor,
-                                                               container,
-                                                               object,
-                                                               action_path);
-}
-
 /* ----------------------------- GtkPaned ------------------------------ */
 void
 glade_gtk_paned_post_create (GladeWidgetAdaptor * adaptor,
diff --git a/plugins/gtk+/glade-gtk.h b/plugins/gtk+/glade-gtk.h
index ccd1624..6936ed4 100644
--- a/plugins/gtk+/glade-gtk.h
+++ b/plugins/gtk+/glade-gtk.h
@@ -41,17 +41,4 @@
 
 #define ONLY_THIS_GOES_IN_THAT_MSG _("Only objects of type %s can be added to objects of type %s.")
 
-G_BEGIN_DECLS
-
-/* Shared functions */
-void      glade_gtk_box_notebook_child_insert_remove_action (GladeWidgetAdaptor * adaptor,
-                                                            GObject * container,
-                                                            GObject * object,
-                                                            const gchar * size_prop,
-                                                            const gchar * group_format,
-                                                            gboolean remove,
-                                                            gboolean after);
-
-G_END_DECLS
-
 #endif /* __GLADE_GTK_H__ */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 7ae7e28..f2381b4 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -66,6 +66,7 @@ plugins/gtk+/glade-gtk-box.c
 plugins/gtk+/glade-gtk-container.c
 plugins/gtk+/glade-gtk-frame.c
 plugins/gtk+/glade-gtk-grid.c
+plugins/gtk+/glade-gtk-notebook.c
 plugins/gtk+/glade-gtk-table.c
 plugins/gtk+/glade-gtk-widget.c
 plugins/gtk+/glade-icon-factory-editor.c


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