glade/plugins/gtk+/glade-gtk-notebook.c
Tristan Van Berkom a190f19ed7 glade-gtk-notebook.c: Fixed warning about imbalanced children
Now that there is a new special child type, only remove "tab"
widgets when extracting the children. This ugly loop is there
to ensure that the right tab is matched with it's page when
changing the notebook children during undo/redo, and also to
handle the case where positions of notebook tabs are not
specified in the datamodel (yet) because the notebook is
being loaded from a file and the appearance of tabs in
the loaded file should be used.

In any case, this small commit fixes the undo/redo console
warnings when undoing/redoing the addition/removal of children
from the new start action / end action positions.
2015-12-14 15:20:34 +09:00

1076 lines
36 KiB
C

/*
* 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"
#include "glade-notebook-editor.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;
GladeEditable *
glade_gtk_notebook_create_editable (GladeWidgetAdaptor * adaptor,
GladeEditorPageType type)
{
if (type == GLADE_PAGE_GENERAL)
return (GladeEditable *) glade_notebook_editor_new ();
return GWA_GET_CLASS (GTK_TYPE_CONTAINER)->create_editable (adaptor, type);
}
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 (!strcmp (special_child_type, "tab"))
{
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);
}
static void
glade_gtk_notebook_parse_finished (GladeProject * project, GObject * object)
{
GtkWidget *action;
action = gtk_notebook_get_action_widget (GTK_NOTEBOOK (object), GTK_PACK_START);
glade_widget_property_set (glade_widget_get_from_gobject (object),
"has-action-start", action != NULL);
action = gtk_notebook_get_action_widget (GTK_NOTEBOOK (object), GTK_PACK_END);
glade_widget_property_set (glade_widget_get_from_gobject (object),
"has-action-end", action != NULL);
}
void
glade_gtk_notebook_post_create (GladeWidgetAdaptor * adaptor,
GObject * notebook, GladeCreateReason reason)
{
GladeWidget *gwidget = glade_widget_get_from_gobject (notebook);
GladeProject *project = glade_widget_get_project (gwidget);
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);
if (reason == GLADE_CREATE_LOAD)
g_signal_connect (project, "parse-finished",
G_CALLBACK (glade_gtk_notebook_parse_finished),
notebook);
}
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 if (!strcmp (id, "has-action-start"))
{
if (g_value_get_boolean (value))
{
GtkWidget *action = gtk_notebook_get_action_widget (GTK_NOTEBOOK (object), GTK_PACK_START);
if (!action)
action = glade_placeholder_new ();
g_object_set_data (G_OBJECT (action), "special-child-type", "action-start");
gtk_notebook_set_action_widget (GTK_NOTEBOOK (object), action, GTK_PACK_START);
}
else
gtk_notebook_set_action_widget (GTK_NOTEBOOK (object), NULL, GTK_PACK_START);
}
else if (!strcmp (id, "has-action-end"))
{
if (g_value_get_boolean (value))
{
GtkWidget *action = gtk_notebook_get_action_widget (GTK_NOTEBOOK (object), GTK_PACK_END);
if (!action)
action = glade_placeholder_new ();
g_object_set_data (G_OBJECT (action), "special-child-type", "action-end");
gtk_notebook_set_action_widget (GTK_NOTEBOOK (object), action, GTK_PACK_END);
}
else
gtk_notebook_set_action_widget (GTK_NOTEBOOK (object), NULL, GTK_PACK_END);
}
else
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object,
id, value);
}
void
glade_gtk_notebook_get_property (GladeWidgetAdaptor * adaptor,
GObject * object, const gchar * id, GValue * value)
{
if (!strcmp (id, "has-action-start"))
{
g_value_reset (value);
g_value_set_boolean (value, gtk_notebook_get_action_widget (GTK_NOTEBOOK (object), GTK_PACK_START) != NULL);
}
else if (!strcmp (id, "has-action-end"))
{
g_value_reset (value);
g_value_set_boolean (value, gtk_notebook_get_action_widget (GTK_NOTEBOOK (object), GTK_PACK_END) != NULL);
}
else
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->get_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);
special_child_type = g_object_get_data (child, "special-child-type");
if (special_child_type && !strcmp (special_child_type, "action-start"))
{
gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_START);
}
else if (special_child_type && !strcmp (special_child_type, "action-end"))
{
gtk_notebook_set_action_widget (notebook, GTK_WIDGET (child), GTK_PACK_END);
}
else if (glade_widget_superuser ())
{
/* Just append pages blindly when loading/dupping */
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;
gchar *special_child_type;
special_child_type = g_object_get_data (child, "special-child-type");
if (special_child_type && !strcmp (special_child_type, "action-start"))
{
GtkWidget *placeholder = glade_placeholder_new ();
g_object_set_data (G_OBJECT (placeholder), "special-child-type", "action-start");
gtk_notebook_set_action_widget (GTK_NOTEBOOK (object), placeholder, GTK_PACK_START);
return;
}
else if (special_child_type && !strcmp (special_child_type, "action-end"))
{
GtkWidget *placeholder = glade_placeholder_new ();
g_object_set_data (G_OBJECT (placeholder), "special-child-type", "action-end");
gtk_notebook_set_action_widget (GTK_NOTEBOOK (object), placeholder, GTK_PACK_END);
return;
}
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;
gchar *special_child_type;
notebook = GTK_NOTEBOOK (container);
special_child_type = g_object_get_data (G_OBJECT (current), "special-child-type");
g_object_set_data (G_OBJECT (new_widget), "special-child-type", special_child_type);
if (!g_strcmp0 (special_child_type, "action-start"))
{
gtk_notebook_set_action_widget (notebook, GTK_WIDGET (new_widget), GTK_PACK_START);
return;
}
else if (!g_strcmp0 (special_child_type, "action-end"))
{
gtk_notebook_set_action_widget (notebook, GTK_WIDGET (new_widget), GTK_PACK_END);
return;
}
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);
}
}
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_strcmp0 (g_object_get_data (child, "special-child-type"), "tab") == 0)
{
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 if (g_object_get_data (child, "special-child-type") != NULL)
{
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 ();
}