mirror of
https://gitlab.gnome.org/GNOME/glade.git
synced 2025-11-17 00:03:25 -05:00
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.
1076 lines
36 KiB
C
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 ();
|
|
}
|