summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlex Valavanis <valavanisalex@gmail.com>2011-07-09 14:26:35 +0000
committerAlex Valavanis <valavanisalex@gmail.com>2011-07-09 14:26:35 +0000
commit351ad21da89e374b88b2214977f6e67ce4795ff0 (patch)
tree71f70a4a72b52aac691b50d9d104387bdba84083 /src
parentNext step in refactoring color management. More to come. (diff)
downloadinkscape-351ad21da89e374b88b2214977f6e67ce4795ff0.tar.gz
inkscape-351ad21da89e374b88b2214977f6e67ce4795ff0.zip
Merge upstream GDL 0.7.8 changes
(bzr r10430)
Diffstat (limited to 'src')
-rw-r--r--src/libgdl/Makefile_insert2
-rw-r--r--src/libgdl/gdl-combo-button.c383
-rw-r--r--src/libgdl/gdl-combo-button.h65
-rw-r--r--src/libgdl/gdl-data-frame.c297
-rw-r--r--src/libgdl/gdl-data-frame.h72
-rw-r--r--src/libgdl/gdl-data-model-test.c240
-rw-r--r--src/libgdl/gdl-data-model-test.h32
-rw-r--r--src/libgdl/gdl-data-model.c160
-rw-r--r--src/libgdl/gdl-data-model.h105
-rw-r--r--src/libgdl/gdl-data-row.c604
-rw-r--r--src/libgdl/gdl-data-row.h90
-rw-r--r--src/libgdl/gdl-data-view.c526
-rw-r--r--src/libgdl/gdl-data-view.h71
-rw-r--r--src/libgdl/gdl-dock-item-grip.c4
-rw-r--r--src/libgdl/gdl-dock-item.c47
-rw-r--r--src/libgdl/gdl-dock-layout.c1411
-rw-r--r--src/libgdl/gdl-dock-layout.h98
-rw-r--r--src/libgdl/gdl-dock-object.c37
-rw-r--r--src/libgdl/gdl-dock-placeholder.c4
-rw-r--r--src/libgdl/gdl-icons.c267
-rw-r--r--src/libgdl/gdl-icons.h61
-rw-r--r--src/libgdl/gdl-switcher.c12
-rw-r--r--src/libgdl/gdl.h (renamed from src/libgdl/libgdl.h)2
-rw-r--r--src/libgdl/libgdltypebuiltins.h2
-rw-r--r--src/libgdl/test-combo-button.c111
-rw-r--r--src/libgdl/test-dataview.c43
-rw-r--r--src/libgdl/test-dock.c311
-rw-r--r--src/ui/dialog/dock-behavior.h2
-rw-r--r--src/ui/widget/dock-item.h2
-rw-r--r--src/ui/widget/dock.h2
30 files changed, 5031 insertions, 32 deletions
diff --git a/src/libgdl/Makefile_insert b/src/libgdl/Makefile_insert
index 5869633ea..2276aa801 100644
--- a/src/libgdl/Makefile_insert
+++ b/src/libgdl/Makefile_insert
@@ -40,4 +40,4 @@ libgdl_libgdl_a_SOURCES = \
libgdl/libgdltypebuiltins.c \
libgdl/libgdlmarshal.h \
libgdl/libgdlmarshal.c \
- libgdl/libgdl.h
+ libgdl/gdl.h
diff --git a/src/libgdl/gdl-combo-button.c b/src/libgdl/gdl-combo-button.c
new file mode 100644
index 000000000..6414a8110
--- /dev/null
+++ b/src/libgdl/gdl-combo-button.c
@@ -0,0 +1,383 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ * gdl-combo-button.c
+ *
+ * Copyright (C) 2003 Jeroen Zwartepoorte
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include "gdl-tools.h"
+#include "gdl-combo-button.h"
+
+struct _GdlComboButtonPrivate {
+ GtkWidget *default_button;
+ GtkWidget *image;
+ GtkWidget *label;
+ GtkWidget *menu_button;
+ GtkWidget *menu;
+ gboolean menu_popped_up;
+};
+
+GDL_CLASS_BOILERPLATE (GdlComboButton, gdl_combo_button, GtkHBox, GTK_TYPE_HBOX);
+
+static void
+default_button_clicked_cb (GtkButton *button,
+ gpointer user_data)
+{
+ GdlComboButton *combo;
+ GdlComboButtonPrivate *priv;
+
+ combo = GDL_COMBO_BUTTON (user_data);
+ priv = combo->priv;
+
+ if (!priv->menu_popped_up)
+ g_signal_emit_by_name (G_OBJECT (combo),
+ "activate-default", NULL);
+}
+
+static gboolean
+default_button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ GdlComboButton *combo_button;
+ GdlComboButtonPrivate *priv;
+
+ combo_button = GDL_COMBO_BUTTON (user_data);
+ priv = combo_button->priv;
+
+ if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
+ GTK_BUTTON (priv->menu_button)->button_down = TRUE;
+ gtk_button_pressed (GTK_BUTTON (priv->menu_button));
+ }
+
+ return FALSE;
+}
+
+static gboolean
+default_button_release_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ GdlComboButton *combo_button;
+ GdlComboButtonPrivate *priv;
+
+ combo_button = GDL_COMBO_BUTTON (user_data);
+ priv = combo_button->priv;
+
+ if (event->button == 1) {
+ gtk_button_released (GTK_BUTTON (priv->menu_button));
+ }
+
+ return FALSE;
+}
+
+static gboolean
+button_enter_notify_cb (GtkWidget *widget,
+ GdkEventCrossing *event,
+ gpointer user_data)
+{
+ GdlComboButton *combo_button;
+ GdlComboButtonPrivate *priv;
+
+ combo_button = GDL_COMBO_BUTTON (user_data);
+ priv = combo_button->priv;
+
+ if (event->detail != GDK_NOTIFY_INFERIOR) {
+ GTK_BUTTON (priv->default_button)->in_button = TRUE;
+ GTK_BUTTON (priv->menu_button)->in_button = TRUE;
+ gtk_button_enter (GTK_BUTTON (priv->default_button));
+ gtk_button_enter (GTK_BUTTON (priv->menu_button));
+ }
+
+ return TRUE;
+}
+
+static gboolean
+button_leave_notify_cb (GtkWidget *widget,
+ GdkEventCrossing *event,
+ gpointer user_data)
+{
+ GdlComboButton *combo_button;
+ GdlComboButtonPrivate *priv;
+
+ combo_button = GDL_COMBO_BUTTON (user_data);
+ priv = combo_button->priv;
+
+ if (priv->menu_popped_up)
+ return TRUE;
+
+ if (event->detail != GDK_NOTIFY_INFERIOR) {
+ GTK_BUTTON (priv->default_button)->in_button = FALSE;
+ GTK_BUTTON (priv->menu_button)->in_button = FALSE;
+ gtk_button_leave (GTK_BUTTON (priv->default_button));
+ gtk_button_leave (GTK_BUTTON (priv->menu_button));
+ }
+
+ return TRUE;
+}
+
+static void
+menu_position_func (GtkMenu *menu,
+ gint *x_return,
+ gint *y_return,
+ gboolean *push_in,
+ gpointer user_data)
+{
+ GdlComboButton *combo_button;
+ GdlComboButtonPrivate *priv;
+ GtkAllocation *allocation;
+
+ combo_button = GDL_COMBO_BUTTON (user_data);
+ priv = combo_button->priv;
+ allocation = &(priv->default_button->allocation);
+
+ gdk_window_get_origin (priv->default_button->window, x_return, y_return);
+
+ *x_return += allocation->x;
+ *y_return += allocation->height;
+}
+
+static gboolean
+menu_button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ GdlComboButton *combo_button;
+ GdlComboButtonPrivate *priv;
+
+ combo_button = GDL_COMBO_BUTTON (user_data);
+ priv = combo_button->priv;
+
+ if (event->type == GDK_BUTTON_PRESS &&
+ (event->button == 1 || event->button == 3)) {
+ GTK_BUTTON (priv->menu_button)->button_down = TRUE;
+
+ gtk_button_pressed (GTK_BUTTON (priv->menu_button));
+
+ priv->menu_popped_up = TRUE;
+ gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
+ menu_position_func, combo_button,
+ event->button, event->time);
+ }
+
+ return TRUE;
+}
+
+static void
+menu_deactivate_cb (GtkMenuShell *menu_shell,
+ gpointer user_data)
+{
+ GdlComboButton *combo_button;
+ GdlComboButtonPrivate *priv;
+
+ combo_button = GDL_COMBO_BUTTON (user_data);
+ priv = combo_button->priv;
+
+ priv->menu_popped_up = FALSE;
+
+ GTK_BUTTON (priv->menu_button)->button_down = FALSE;
+ GTK_BUTTON (priv->menu_button)->in_button = FALSE;
+ GTK_BUTTON (priv->default_button)->in_button = FALSE;
+ gtk_button_leave (GTK_BUTTON (priv->menu_button));
+ gtk_button_leave (GTK_BUTTON (priv->default_button));
+ gtk_button_clicked (GTK_BUTTON (priv->menu_button));
+}
+
+static void
+menu_detacher (GtkWidget *widget,
+ GtkMenu *menu)
+{
+ GdlComboButton *combo_button;
+
+ combo_button = GDL_COMBO_BUTTON (widget);
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (menu),
+ menu_deactivate_cb,
+ combo_button);
+ combo_button->priv->menu = NULL;
+}
+
+static void
+gdl_combo_button_destroy (GtkObject *object)
+{
+ GdlComboButton *combo_button;
+ GdlComboButtonPrivate *priv;
+
+ combo_button = GDL_COMBO_BUTTON (object);
+ priv = combo_button->priv;
+
+ if (priv) {
+ g_free (priv);
+ combo_button->priv = NULL;
+ }
+
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+static void
+gdl_combo_button_class_init (GdlComboButtonClass *klass)
+{
+ GtkObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class = GTK_OBJECT_CLASS (klass);
+ widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->destroy = gdl_combo_button_destroy;
+
+ g_signal_new ("activate-default",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdlComboButtonClass, activate_default),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+gdl_combo_button_instance_init (GdlComboButton *combo_button)
+{
+ GdlComboButtonPrivate *priv;
+ GtkWidget *hbox, *align, *arrow;
+
+ priv = g_new (GdlComboButtonPrivate, 1);
+ combo_button->priv = priv;
+
+ priv->menu = NULL;
+ priv->menu_popped_up = FALSE;
+
+ priv->default_button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (priv->default_button), GTK_RELIEF_NONE);
+
+ /* Following code copied from gtk_button_construct_child. */
+ priv->label = gtk_label_new ("");
+ gtk_label_set_use_underline (GTK_LABEL (priv->label), TRUE);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (priv->label),
+ priv->default_button);
+
+ priv->image = gtk_image_new ();
+ hbox = gtk_hbox_new (FALSE, 2);
+
+ align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
+
+ gtk_box_pack_start (GTK_BOX (hbox), priv->image, FALSE, FALSE, 0);
+ gtk_box_pack_end (GTK_BOX (hbox), priv->label, FALSE, FALSE, 0);
+
+ gtk_container_add (GTK_CONTAINER (priv->default_button), align);
+ gtk_container_add (GTK_CONTAINER (align), hbox);
+ /* End copied block. */
+
+ gtk_box_pack_start (GTK_BOX (combo_button), priv->default_button,
+ FALSE, FALSE, 0);
+ gtk_widget_show_all (priv->default_button);
+
+ priv->menu_button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (priv->menu_button), GTK_RELIEF_NONE);
+ arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
+ gtk_container_add (GTK_CONTAINER (priv->menu_button), arrow);
+ gtk_box_pack_start (GTK_BOX (combo_button), priv->menu_button, FALSE,
+ FALSE, 0);
+ gtk_widget_show_all (priv->menu_button);
+
+ /* Default button. */
+ g_signal_connect (G_OBJECT (priv->default_button), "clicked",
+ G_CALLBACK (default_button_clicked_cb), combo_button);
+ g_signal_connect (G_OBJECT (priv->default_button), "button_press_event",
+ G_CALLBACK (default_button_press_event_cb), combo_button);
+ g_signal_connect (G_OBJECT (priv->default_button), "button_release_event",
+ G_CALLBACK (default_button_release_event_cb), combo_button);
+ g_signal_connect (G_OBJECT (priv->default_button), "enter_notify_event",
+ G_CALLBACK (button_enter_notify_cb), combo_button);
+ g_signal_connect (G_OBJECT (priv->default_button), "leave_notify_event",
+ G_CALLBACK (button_leave_notify_cb), combo_button);
+
+ /* Menu button. */
+ g_signal_connect (G_OBJECT (priv->menu_button), "button_press_event",
+ G_CALLBACK (menu_button_press_event_cb), combo_button);
+ g_signal_connect (G_OBJECT (priv->menu_button), "enter_notify_event",
+ G_CALLBACK (button_enter_notify_cb), combo_button);
+ g_signal_connect (G_OBJECT (priv->menu_button), "leave_notify_event",
+ G_CALLBACK (button_leave_notify_cb), combo_button);
+}
+
+GtkWidget *
+gdl_combo_button_new (void)
+{
+ GtkWidget *combo_button;
+
+ combo_button = GTK_WIDGET (g_object_new (GDL_TYPE_COMBO_BUTTON, NULL));
+
+ return combo_button;
+}
+
+void
+gdl_combo_button_set_icon (GdlComboButton *combo_button,
+ GdkPixbuf *pixbuf)
+{
+ GdlComboButtonPrivate *priv;
+
+ g_return_if_fail (GDL_IS_COMBO_BUTTON (combo_button));
+ g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
+
+ priv = combo_button->priv;
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), pixbuf);
+}
+
+void
+gdl_combo_button_set_label (GdlComboButton *combo_button,
+ const gchar *label)
+{
+ GdlComboButtonPrivate *priv;
+
+ g_return_if_fail (GDL_IS_COMBO_BUTTON (combo_button));
+ g_return_if_fail (label != NULL);
+
+ priv = combo_button->priv;
+
+ gtk_label_set_text (GTK_LABEL (priv->label), label);
+}
+
+void
+gdl_combo_button_set_menu (GdlComboButton *combo_button,
+ GtkMenu *menu)
+{
+ GdlComboButtonPrivate *priv;
+
+ g_return_if_fail (GDL_IS_COMBO_BUTTON (combo_button));
+ g_return_if_fail (GTK_IS_MENU (menu));
+
+ priv = combo_button->priv;
+
+ if (priv->menu != NULL)
+ gtk_menu_detach (GTK_MENU (priv->menu));
+
+ priv->menu = GTK_WIDGET (menu);
+ if (menu == NULL)
+ return;
+
+ gtk_menu_attach_to_widget (menu, GTK_WIDGET (combo_button), menu_detacher);
+
+ g_signal_connect (G_OBJECT (menu), "deactivate",
+ G_CALLBACK (menu_deactivate_cb), combo_button);
+}
diff --git a/src/libgdl/gdl-combo-button.h b/src/libgdl/gdl-combo-button.h
new file mode 100644
index 000000000..6e80af0b6
--- /dev/null
+++ b/src/libgdl/gdl-combo-button.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ * gdl-combo-button.h
+ *
+ * Copyright (C) 2003 Jeroen Zwartepoorte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _GDL_COMBO_BUTTON_H_
+#define _GDL_COMBO_BUTTON_H_
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkmenu.h>
+
+G_BEGIN_DECLS
+
+#define GDL_TYPE_COMBO_BUTTON (gdl_combo_button_get_type ())
+#define GDL_COMBO_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDL_TYPE_COMBO_BUTTON, GdlComboButton))
+#define GDL_COMBO_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDL_TYPE_COMBO_BUTTON, GdlComboButtonClass))
+#define GDL_IS_COMBO_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDL_TYPE_COMBO_BUTTON))
+#define GDL_IS_COMBO_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), GDL_TYPE_COMBO_BUTTON))
+
+typedef struct _GdlComboButton GdlComboButton;
+typedef struct _GdlComboButtonPrivate GdlComboButtonPrivate;
+typedef struct _GdlComboButtonClass GdlComboButtonClass;
+
+struct _GdlComboButton {
+ GtkHBox parent;
+
+ GdlComboButtonPrivate *priv;
+};
+
+struct _GdlComboButtonClass {
+ GtkHBoxClass parent_class;
+
+ /* Signals. */
+ void (* activate_default) (GdlComboButton *combo_button);
+};
+
+GType gdl_combo_button_get_type (void);
+GtkWidget *gdl_combo_button_new (void);
+
+void gdl_combo_button_set_icon (GdlComboButton *combo_button,
+ GdkPixbuf *pixbuf);
+void gdl_combo_button_set_label (GdlComboButton *combo_button,
+ const gchar *label);
+void gdl_combo_button_set_menu (GdlComboButton *combo_button,
+ GtkMenu *menu);
+
+G_END_DECLS
+
+#endif /* _GDL_COMBO_BUTTON_H_ */
diff --git a/src/libgdl/gdl-data-frame.c b/src/libgdl/gdl-data-frame.c
new file mode 100644
index 000000000..d6fb19533
--- /dev/null
+++ b/src/libgdl/gdl-data-frame.c
@@ -0,0 +1,297 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * This file is part of the GNOME Devtools Libraries.
+ *
+ * Copyright (C) 2001 Dave Camp <dave@ximian.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gdl-i18n.h"
+#include "gdl-tools.h"
+#include <string.h>
+
+#include "gdl-data-view.h"
+#include "gdl-data-frame.h"
+#include "gdl-data-model.h"
+#include "gdl-data-row.h"
+
+struct _GdlDataFramePrivate {
+ GdkRectangle shadow_r;
+ GdkRectangle frame_r;
+ GdkRectangle titlebar_r;
+ GdkRectangle title_r;
+ GdkRectangle close_r;
+ GdkRectangle row_r;
+
+ int shadow_offset;
+ int titlebar_height;
+ char *title;
+
+ GdlDataRow *row;
+
+ PangoLayout *layout;
+
+ gboolean selected;
+};
+
+static void gdl_data_frame_class_init (GdlDataFrameClass *klass);
+static void gdl_data_frame_instance_init (GdlDataFrame *obj);
+static void gdl_data_frame_finalize (GObject *object);
+
+GDL_CLASS_BOILERPLATE (GdlDataFrame, gdl_data_frame, GObject, G_TYPE_OBJECT);
+
+#define PAD 2
+#define BORDER 1
+
+#define CENTERY(r1, r2) { r1.y = ((r2.y + (r2.height / 2)) - (r1.height / 2)); }
+
+void
+gdl_data_frame_layout (GdlDataFrame *frame)
+{
+ GdkPixbuf *close_pixbuf;
+ /* Sizes */
+ if (frame->priv->row) {
+ gdl_data_row_get_size (frame->priv->row,
+ NULL, NULL,
+ &frame->priv->row_r.width,
+ &frame->priv->row_r.height);
+ } else {
+ frame->priv->row_r.height = frame->priv->row_r.width = 0;
+ }
+
+ if (frame->priv->layout) {
+ pango_layout_get_pixel_size (frame->priv->layout,
+ &frame->priv->title_r.width,
+ &frame->priv->title_r.height);
+ } else {
+ frame->priv->title_r.width = frame->priv->title_r.height = 0;
+ }
+
+ close_pixbuf = gdl_data_view_get_close_pixbuf (frame->view);
+ if (close_pixbuf) {
+ frame->priv->close_r.width =
+ gdk_pixbuf_get_width (close_pixbuf);
+ frame->priv->close_r.height =
+ gdk_pixbuf_get_width (close_pixbuf);
+ } else {
+ frame->priv->close_r.width = frame->priv->close_r.height = 0;
+ }
+
+ frame->priv->titlebar_r.height = MAX (frame->priv->titlebar_height,
+ frame->priv->title_r.height);
+ frame->priv->titlebar_r.height = MAX (frame->priv->titlebar_r.height,
+ frame->priv->close_r.height);
+
+ frame->priv->frame_r.width = 2 * BORDER + 3 * PAD + frame->priv->title_r.width + frame->priv->close_r.width;
+ frame->priv->frame_r.width = MAX (frame->priv->frame_r.width,
+ frame->priv->row_r.width + 2 * BORDER + 2 * PAD);
+ frame->priv->frame_r.height = frame->priv->row_r.height + frame->priv->titlebar_r.height + 2 * PAD + 2 * BORDER;
+ frame->priv->titlebar_r.width = frame->priv->frame_r.width - BORDER;
+ frame->priv->shadow_r.width = frame->priv->frame_r.width;
+ frame->priv->shadow_r.height = frame->priv->frame_r.height;
+
+ /* Locations */
+ frame->priv->frame_r.x = frame->area.x;
+ frame->priv->frame_r.y = frame->area.y;
+
+ frame->priv->shadow_r.x = frame->priv->frame_r.x + frame->priv->shadow_offset;
+ frame->priv->shadow_r.y = frame->priv->frame_r.y + frame->priv->shadow_offset;
+ frame->priv->titlebar_r.x = frame->priv->frame_r.x + BORDER;
+ frame->priv->titlebar_r.y = frame->priv->frame_r.y + BORDER;
+ frame->priv->title_r.x = frame->priv->frame_r.x + BORDER + PAD;
+ CENTERY (frame->priv->title_r, frame->priv->titlebar_r);
+ frame->priv->close_r.x = (frame->priv->frame_r.x + frame->priv->frame_r.width) - (frame->priv->close_r.width + BORDER + PAD);
+ CENTERY (frame->priv->close_r, frame->priv->titlebar_r);
+
+ if (frame->priv->row) {
+ frame->priv->row_r.x = frame->priv->frame_r.x + BORDER + PAD;
+ frame->priv->row_r.y = frame->priv->titlebar_r.y + frame->priv->titlebar_r.height + PAD;
+ gdl_data_row_layout (frame->priv->row, &frame->priv->row_r);
+ } else {
+ frame->priv->row_r.x = frame->priv->row_r.y = 0;
+ }
+
+ frame->area.width = frame->priv->frame_r.width + frame->priv->shadow_offset;
+ frame->area.height = frame->priv->frame_r.height + frame->priv->shadow_offset;
+}
+
+#if 0 /* not used */
+static void
+change_layout (GdlDataFrame *frame)
+{
+ char *text = frame->priv->title ? frame->priv->title : "?";
+ pango_layout_set_text (frame->priv->layout, text, strlen (text));
+}
+#endif
+
+#define EXPLODE(r) (r).x, (r).y, (r).width, (r).height
+
+void
+gdl_data_frame_draw (GdlDataFrame *frame, GdkDrawable *drawable,
+ GdkRectangle *expose_area)
+{
+ GdkRectangle inter;
+ guint8 state =
+ frame->priv->selected ? GTK_STATE_SELECTED : GTK_STATE_NORMAL;
+
+ gdk_draw_rectangle (drawable,
+ GTK_WIDGET (frame->view)->style->dark_gc[state],
+ TRUE,
+ EXPLODE (frame->priv->shadow_r));
+ gdk_draw_rectangle (drawable,
+ GTK_WIDGET (frame->view)->style->base_gc[GTK_STATE_NORMAL],
+ TRUE,
+ EXPLODE (frame->priv->frame_r));
+ gdk_draw_rectangle (drawable,
+ GTK_WIDGET (frame->view)->style->black_gc,
+ FALSE,
+ EXPLODE (frame->priv->frame_r));
+ gdk_draw_rectangle (drawable,
+ GTK_WIDGET (frame->view)->style->bg_gc[state],
+ TRUE,
+ EXPLODE (frame->priv->titlebar_r));
+ gdk_draw_layout (drawable,
+ GTK_WIDGET (frame->view)->style->fg_gc[state],
+ frame->priv->title_r.x, frame->priv->title_r.y,
+ frame->priv->layout);
+
+ if (gdk_rectangle_intersect (expose_area, &frame->priv->close_r, &inter)) {
+ GdkPixbuf *pixbuf = gdl_data_view_get_close_pixbuf (frame->view);
+ gdk_draw_pixbuf (drawable, NULL, pixbuf,
+ 0, 0,
+ inter.x - frame->priv->close_r.x,
+ inter.y - frame->priv->close_r.y,
+ gdk_pixbuf_get_width (pixbuf),
+ gdk_pixbuf_get_height (pixbuf),
+ GDK_RGB_DITHER_NORMAL, 0, 0);
+ }
+
+ if (frame->priv->row) {
+ if (gdk_rectangle_intersect (expose_area, &frame->priv->row_r,
+ &inter)) {
+ gdl_data_row_render (frame->priv->row, drawable,
+ &inter,
+ frame->priv->selected ? GTK_CELL_RENDERER_SELECTED : 0);
+ }
+ }
+}
+
+void
+gdl_data_frame_class_init (GdlDataFrameClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *)klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->finalize = gdl_data_frame_finalize;
+}
+
+void
+gdl_data_frame_instance_init (GdlDataFrame *frame)
+{
+ frame->priv = g_new0 (GdlDataFramePrivate, 1);
+ frame->area.x = frame->area.y = 0;
+ frame->priv->shadow_offset = 3;
+ frame->priv->titlebar_height = 20;
+
+ frame->area.height = frame->area.width = 100;
+}
+
+void
+gdl_data_frame_finalize (GObject *object)
+{
+ GdlDataFrame *frame = GDL_DATA_FRAME (object);
+
+ if (frame->priv) {
+ g_free (frame->priv->title);
+ g_object_unref (frame->priv->layout);
+ g_object_unref (frame->priv->row);
+
+ g_free (frame->priv);
+ frame->priv = NULL;
+ }
+ GDL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+void
+gdl_data_frame_set_selected (GdlDataFrame *frame,
+ gboolean val)
+{
+ frame->priv->selected = val;
+
+ gdk_window_invalidate_rect (GTK_LAYOUT (frame->view)->bin_window,
+ &frame->priv->frame_r,
+ TRUE);
+}
+
+gboolean
+gdl_data_frame_button_press (GdlDataFrame *frame,
+ GdkEventButton *event)
+{
+ return FALSE;
+}
+
+void
+gdl_data_frame_set_position (GdlDataFrame *frame,
+ int x,
+ int y)
+{
+ frame->area.x = x;
+ frame->area.y = y;
+
+ gdl_data_frame_layout (frame);
+}
+
+static void
+setup_layout (GdlDataFrame *frame)
+{
+ PangoFontDescription *font_desc =
+ pango_font_description_copy (GTK_WIDGET (frame->view)->style->font_desc);
+
+ pango_font_description_set_weight (font_desc,
+ PANGO_WEIGHT_BOLD);
+
+ frame->priv->layout = gtk_widget_create_pango_layout (GTK_WIDGET (frame->view),
+ frame->priv->title ? frame->priv->title : "?");
+ pango_layout_set_font_description (frame->priv->layout,
+ font_desc);
+ pango_font_description_free (font_desc);
+}
+
+
+GdlDataFrame *
+gdl_data_frame_new (GdlDataView *view,
+ GdlDataRow *row)
+{
+ GdlDataFrame *frame;
+ frame = GDL_DATA_FRAME (g_object_new (GDL_TYPE_DATA_FRAME, NULL));
+
+ frame->view = view;
+
+ frame->priv->row = row;
+ frame->priv->title = g_strdup (gdl_data_row_get_title (row));
+
+ setup_layout (frame);
+
+ gdl_data_frame_layout (frame);
+
+ return frame;
+}
diff --git a/src/libgdl/gdl-data-frame.h b/src/libgdl/gdl-data-frame.h
new file mode 100644
index 000000000..740c38293
--- /dev/null
+++ b/src/libgdl/gdl-data-frame.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * This file is part of the GNOME Devtools Libraries.
+ *
+ * Copyright (C) 2001 Dave Camp <dave@ximian.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GDL_DATA_FRAME_H
+#define GDL_DATA_FRAME_H
+
+#include <glib-object.h>
+#include <gdl/gdl-data-row.h>
+
+G_BEGIN_DECLS
+
+#define GDL_TYPE_DATA_FRAME (gdl_data_frame_get_type ())
+#define GDL_DATA_FRAME(obj) (GTK_CHECK_CAST ((obj), GDL_TYPE_DATA_FRAME, GdlDataFrame))
+#define GDL_DATA_FRAME_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GDL_DATA_VIEW_FRAM, GdlDataFrame))
+#define GDL_IS_DATA_FRAME(obj) (GTK_CHECK_TYPE ((obj), GDL_TYPE_DATA_FRAME))
+#define GDL_IS_DATA_FRAME_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GDL_TYPE_DATA_FRAME))
+#define GDL_DATA_FRAME_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GDL_TYPE_DATA_FRAME, GdlDataFrameClass))
+
+typedef struct _GdlDataFrame GdlDataFrame;
+typedef struct _GdlDataFramePrivate GdlDataFramePrivate;
+typedef struct _GdlDataFrameClass GdlDataFrameClass;
+
+struct _GdlDataFrame {
+ GObject parent;
+
+ GdlDataView *view;
+ GdkRectangle area;
+
+ GdlDataFramePrivate *priv;
+};
+
+struct _GdlDataFrameClass {
+ GObjectClass parent_class;
+};
+
+GType gdl_data_frame_get_type (void);
+GdlDataFrame *gdl_data_frame_new (GdlDataView *view,
+ GdlDataRow *row);
+void gdl_data_frame_layout (GdlDataFrame *frame);
+void gdl_data_frame_draw (GdlDataFrame *item,
+ GdkDrawable *drawable,
+ GdkRectangle *expose_area);
+void gdl_data_frame_set_selected (GdlDataFrame *frame,
+ gboolean val);
+gboolean gdl_data_frame_button_press (GdlDataFrame *frame,
+ GdkEventButton *event);
+void gdl_data_frame_set_position (GdlDataFrame *frame,
+ int x,
+ int y);
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgdl/gdl-data-model-test.c b/src/libgdl/gdl-data-model-test.c
new file mode 100644
index 000000000..ec6ed4d50
--- /dev/null
+++ b/src/libgdl/gdl-data-model-test.c
@@ -0,0 +1,240 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gdl-i18n.h"
+
+#include "gdl-data-model-test.h"
+#include "gdl-data-model.h"
+
+#include <string.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkcellrenderertoggle.h>
+
+GObjectClass *parent_class;
+
+typedef struct _DataItem {
+ char *name;
+ char *value;
+ char *path;
+ struct _DataItem *children;
+} DataItem;
+
+DataItem data1[] = {
+ { "foo1", "foo1", "0:0", NULL},
+ { "bar1", "bar1", "0:1", NULL },
+ { "baz1", "baz1", "0:2", NULL },
+ { NULL, NULL, NULL, NULL }
+
+};
+DataItem data2[] = {
+ { "foo2", "foo2", "1:0", NULL },
+ { "bar2", "bar2", "1:1", NULL },
+ { "baz2", "baz2", "1:2", NULL },
+ { NULL, NULL, NULL, NULL }
+
+};
+
+DataItem data5[] = {
+ { "1", "1", "2:2:1:0", NULL },
+ { "2", "2", "2:2:1:1", NULL },
+ { "3", "3", "2:2:1:2", NULL },
+ { "4", "4", "2:2:1:3", NULL },
+ { "5", "5", "2:2:1:4", NULL },
+ { "6", "6", "2:2:1:5", NULL },
+ { NULL, NULL, NULL, NULL }
+
+};
+DataItem data4[] = {
+ { "foo4", "foo4", "2:2:0", NULL },
+ { "bar4", "[...]", "2:2:1", data5 },
+ { "baz4", "baz4", "2:2:2", NULL },
+ { NULL, NULL, NULL, NULL }
+
+};
+DataItem data3[] = {
+ { "foo foo", "foo3", "2:0", NULL },
+ { "bar3", "1", "2:1", NULL },
+ { "baz3", "{...}", "2:2", data4 },
+ { NULL, NULL, NULL, NULL }
+
+};
+
+DataItem root[] = {
+ { "test-data", "value1", "0", NULL } ,
+ { "test-data2", "value2", "1", NULL } ,
+ { "test-data3", "{...}", "2", data3 } ,
+ { NULL, NULL, NULL }
+};
+
+static gboolean
+get_iter (GdlDataModel *dm, GdlDataIter *iter, GtkTreePath *path)
+{
+ int *i = gtk_tree_path_get_indices (path);
+ int n = gtk_tree_path_get_depth (path);
+ DataItem *item;
+
+ g_assert (i);
+ item = &root[*i++];
+
+ while (--n) {
+ item = &item->children[*i++];
+ }
+
+ iter->data1 = item;
+
+ return TRUE;
+}
+
+static GtkTreePath *
+get_path (GdlDataModel *dm, GdlDataIter *iter)
+{
+ DataItem *item = iter->data1;
+ return gtk_tree_path_new_from_string (item->path);
+}
+
+static void
+get_name (GdlDataModel *dm, GdlDataIter *iter, char **name)
+{
+ DataItem *item = iter->data1;
+ *name = item->name;
+}
+
+static void
+get_value (GdlDataModel *dm, GdlDataIter *iter, GValue *value)
+{
+ DataItem *item = iter->data1;
+ if (strcmp (item->name, "bar3")) {
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, item->value);
+ } else {
+ g_value_init (value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (value, !strcmp (item->value, "1"));
+ }
+}
+
+static void
+get_renderer (GdlDataModel *dm, GdlDataIter *iter,
+ GtkCellRenderer **renderer, char **field,
+ gboolean *is_editable)
+{
+ DataItem *item = iter->data1;
+ if (!strcmp (item->name, "bar3")) {
+ *renderer = g_object_new (gtk_cell_renderer_toggle_get_type (),
+ "activatable", TRUE, NULL);
+ *field = "active";
+ } else {
+ *renderer = g_object_new (gtk_cell_renderer_text_get_type (),
+ "editable", TRUE, NULL);
+ *field = "text";
+ }
+ *is_editable = (item->children == NULL);
+}
+
+static gboolean
+iter_next (GdlDataModel *dm, GdlDataIter *iter)
+{
+ DataItem *item = iter->data1;
+ item++;
+ if (item->name) {
+ iter->data1 = item;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static gboolean
+iter_children (GdlDataModel *dm, GdlDataIter *iter, GdlDataIter *parent)
+{
+ DataItem *item = parent->data1;
+
+ item = &item->children[0];
+ if (item) {
+ iter->data1 = item;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static gboolean
+iter_has_child (GdlDataModel *dm, GdlDataIter *iter)
+{
+ DataItem *item = iter->data1;
+ if (item->children) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+static void
+gdl_data_model_test_instance_init (GdlDataModelTest *model)
+{
+}
+
+static void
+gdl_data_model_test_finalize (GObject *object)
+{
+ (*parent_class->finalize) (object);
+}
+
+static void
+gdl_data_model_test_class_init (GdlDataModelTestClass *klass)
+{
+ GObjectClass *object_class;
+ parent_class = g_type_class_peek_parent (klass);
+ object_class = (GObjectClass *)klass;
+ object_class->finalize = gdl_data_model_test_finalize;
+}
+
+static void
+gdl_data_model_test_data_model_init (GdlDataModelIface *iface)
+{
+ iface->get_iter = get_iter;
+ iface->get_path = get_path;
+ iface->get_name = get_name;
+ iface->get_value = get_value;
+ iface->get_renderer = get_renderer;
+ iface->iter_next = iter_next;
+ iface->iter_children = iter_children;
+ iface->iter_has_child = iter_has_child;
+}
+
+GType
+gdl_data_model_test_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo data_model_test_info = {
+ sizeof (GdlDataModelTestClass),
+ NULL, NULL,
+ (GClassInitFunc) gdl_data_model_test_class_init,
+ NULL, NULL,
+ sizeof (GdlDataModelTest), 0,
+ (GInstanceInitFunc) gdl_data_model_test_instance_init
+ };
+
+ static const GInterfaceInfo data_model_info = {
+ (GInterfaceInitFunc) gdl_data_model_test_data_model_init,
+ NULL, NULL
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "GdlDataModelTest",
+ &data_model_test_info, 0);
+ g_type_add_interface_static (type,
+ GDL_TYPE_DATA_MODEL,
+ &data_model_info);
+ }
+ return type;
+}
+
+GdlDataModelTest *
+gdl_data_model_test_new (void)
+{
+ return GDL_DATA_MODEL_TEST (g_object_new (gdl_data_model_test_get_type (), NULL));
+}
diff --git a/src/libgdl/gdl-data-model-test.h b/src/libgdl/gdl-data-model-test.h
new file mode 100644
index 000000000..c8add8daf
--- /dev/null
+++ b/src/libgdl/gdl-data-model-test.h
@@ -0,0 +1,32 @@
+#ifndef GDL_DATA_MODEL_TEST_H
+#define GDL_DATA_MODEL_TEST_H
+
+#include <glib.h>
+#include "gdl-data-model.h"
+
+G_BEGIN_DECLS
+
+#define GDL_TYPE_DATA_MODEL_TEST (gdl_data_model_test_get_type ())
+#define GDL_DATA_MODEL_TEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDL_TYPE_DATA_MODEL_TEST, GdlDataModelTest))
+#define GDL_IS_DATA_MODEL_TEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDL_TYPE_DATA_MODEL_TEST))
+
+
+typedef struct _GdlDataModelTest GdlDataModelTest;
+typedef struct _GdlDataModelTestClass GdlDataModelTestClass;
+
+struct _GdlDataModelTest {
+ GObject parent;
+
+ int stamp;
+};
+
+struct _GdlDataModelTestClass {
+ GObjectClass parent_class;
+};
+
+GType gdl_data_model_test_get_type (void);
+GdlDataModelTest *gdl_data_model_test_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgdl/gdl-data-model.c b/src/libgdl/gdl-data-model.c
new file mode 100644
index 000000000..69fbb93d5
--- /dev/null
+++ b/src/libgdl/gdl-data-model.c
@@ -0,0 +1,160 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * This file is part of the GNOME Devtools Libraries.
+ *
+ * Copyright (C) 2001 Dave Camp <dave@ximian.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gdl-data-model.h"
+
+gboolean
+gdl_data_model_get_iter (GdlDataModel *dm,
+ GdlDataIter *iter,
+ GtkTreePath *path)
+{
+ g_return_val_if_fail (dm != NULL, FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (path != NULL, FALSE);
+ g_return_val_if_fail (GDL_DATA_MODEL_GET_IFACE (dm)->get_iter != NULL,
+ FALSE);
+
+ return (*GDL_DATA_MODEL_GET_IFACE (dm)->get_iter) (dm, iter, path);
+}
+
+GtkTreePath *
+gdl_data_model_get_path (GdlDataModel *dm,
+ GdlDataIter *iter)
+{
+ g_return_val_if_fail (dm != NULL, NULL);
+ g_return_val_if_fail (iter != NULL, NULL);
+ g_return_val_if_fail (GDL_DATA_MODEL_GET_IFACE (dm)->get_path != NULL,
+ NULL);
+
+ return (*GDL_DATA_MODEL_GET_IFACE (dm)->get_path) (dm, iter);
+}
+
+void
+gdl_data_model_get_name (GdlDataModel *dm,
+ GdlDataIter *iter,
+ char **name)
+{
+ g_return_if_fail (dm != NULL);
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (GDL_DATA_MODEL_GET_IFACE (dm)->get_name != NULL);
+
+ (*GDL_DATA_MODEL_GET_IFACE (dm)->get_name) (dm, iter, name);
+}
+
+void
+gdl_data_model_get_value (GdlDataModel *dm,
+ GdlDataIter *iter,
+ GValue *value)
+{
+ g_return_if_fail (dm != NULL);
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (value != NULL);
+ g_return_if_fail (GDL_DATA_MODEL_GET_IFACE (dm)->get_value != NULL);
+
+ (*GDL_DATA_MODEL_GET_IFACE (dm)->get_value) (dm, iter, value);
+}
+
+void
+gdl_data_model_get_renderer (GdlDataModel *dm,
+ GdlDataIter *iter,
+ GtkCellRenderer **renderer,
+ char **field,
+ gboolean *is_editable)
+{
+ g_return_if_fail (dm != NULL);
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (renderer != NULL);
+ g_return_if_fail (GDL_DATA_MODEL_GET_IFACE (dm)->get_renderer != NULL);
+
+ (*GDL_DATA_MODEL_GET_IFACE (dm)->get_renderer) (dm, iter,
+ renderer, field,
+ is_editable);
+}
+
+gboolean
+gdl_data_model_iter_next (GdlDataModel *dm,
+ GdlDataIter *iter)
+{
+ g_return_val_if_fail (dm != NULL, FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (GDL_DATA_MODEL_GET_IFACE (dm)->iter_next != NULL, FALSE);
+
+ return (*GDL_DATA_MODEL_GET_IFACE (dm)->iter_next) (dm, iter);
+}
+
+gboolean
+gdl_data_model_iter_children (GdlDataModel *dm,
+ GdlDataIter *iter,
+ GdlDataIter *parent)
+{
+ g_return_val_if_fail (dm != NULL, FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (GDL_DATA_MODEL_GET_IFACE (dm)->iter_children != NULL, FALSE);
+
+ return (*GDL_DATA_MODEL_GET_IFACE (dm)->iter_children) (dm, iter, parent);
+}
+
+gboolean
+gdl_data_model_iter_has_child (GdlDataModel *dm,
+ GdlDataIter *iter)
+{
+ g_return_val_if_fail (dm != NULL, FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (GDL_DATA_MODEL_GET_IFACE (dm)->iter_has_child != NULL, FALSE);
+
+ return (*GDL_DATA_MODEL_GET_IFACE (dm)->iter_has_child) (dm, iter);
+}
+
+static void
+gdl_data_model_base_init (gpointer g_class)
+{
+ static gboolean initialized = FALSE;
+
+ if (!initialized) {
+ }
+}
+
+GType
+gdl_data_model_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo info = {
+ sizeof (GdlDataModelIface),
+ gdl_data_model_base_init,
+ NULL, NULL, NULL, NULL, 0, 0, NULL
+ };
+
+ type = g_type_register_static (G_TYPE_INTERFACE,
+ "GdlDataModel",
+ &info, 0);
+ g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+ }
+
+ return type;
+}
diff --git a/src/libgdl/gdl-data-model.h b/src/libgdl/gdl-data-model.h
new file mode 100644
index 000000000..521a65d0c
--- /dev/null
+++ b/src/libgdl/gdl-data-model.h
@@ -0,0 +1,105 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * This file is part of the GNOME Devtools Libraries.
+ *
+ * Copyright (C) 2001 Dave Camp <dave@ximian.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GDL_DATA_MODEL_H
+#define GDL_DATA_MODEL_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+/* Using GtkTreePath to save time */
+#include <gtk/gtktreemodel.h>
+#include <gtk/gtkcellrenderer.h>
+
+G_BEGIN_DECLS
+
+#define GDL_TYPE_DATA_MODEL (gdl_data_model_get_type ())
+#define GDL_DATA_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDL_TYPE_DATA_MODEL, GdlDataModel))
+#define GDL_IS_DATA_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDL_TYPE_DATA_MODEL))
+#define GDL_DATA_MODEL_GET_IFACE(obj) ((GdlDataModelIface *)g_type_interface_peek (((GTypeInstance *)GDL_DATA_MODEL (obj))->g_class, GDL_TYPE_DATA_MODEL))
+
+typedef struct _GdlDataModel GdlDataModel;
+typedef struct _GdlDataIter GdlDataIter;
+typedef struct _GdlDataModelIface GdlDataModelIface;
+
+struct _GdlDataIter {
+ int stamp;
+
+ gpointer data1;
+ gpointer data2;
+ gpointer data3;
+};
+
+struct _GdlDataModelIface {
+ GTypeInterface g_iface;
+
+ /* Signals */
+ void (*path_changed) (GdlDataModel *dm, GtkTreePath *path);
+ void (*path_inserted) (GdlDataModel *dm, GtkTreePath *path);
+ void (*path_deleted) (GdlDataModel *dm, GtkTreePath *path);
+
+ /* Virtual Table */
+ gboolean (*get_iter) (GdlDataModel *dm, GdlDataIter *iter,
+ GtkTreePath *path);
+ GtkTreePath* (*get_path) (GdlDataModel *dm, GdlDataIter *iter);
+
+ void (*get_name) (GdlDataModel *dm, GdlDataIter *iter,
+ char **name);
+ void (*get_value) (GdlDataModel *dm, GdlDataIter *iter,
+ GValue *value);
+ void (*get_renderer) (GdlDataModel *dm, GdlDataIter *iter,
+ GtkCellRenderer **renderer, char **field,
+ gboolean *is_editable);
+ gboolean (*iter_next) (GdlDataModel *dm, GdlDataIter *iter);
+ gboolean (*iter_children) (GdlDataModel *dm, GdlDataIter *iter,
+ GdlDataIter *parent);
+ gboolean (*iter_has_child) (GdlDataModel *dm, GdlDataIter *iter);
+};
+
+GType gdl_data_model_get_type (void);
+gboolean gdl_data_model_get_iter (GdlDataModel *dm,
+ GdlDataIter *iter,
+ GtkTreePath *path);
+GtkTreePath *gdl_data_model_get_path (GdlDataModel *dm,
+ GdlDataIter *iter);
+void gdl_data_model_get_name (GdlDataModel *dm,
+ GdlDataIter *iter,
+ char **name);
+void gdl_data_model_get_value (GdlDataModel *dm,
+ GdlDataIter *iter,
+ GValue *value);
+void gdl_data_model_get_renderer (GdlDataModel *dm,
+ GdlDataIter *iter,
+ GtkCellRenderer **renderer,
+ char **field,
+ gboolean *is_editable);
+gboolean gdl_data_model_iter_next (GdlDataModel *dm,
+ GdlDataIter *iter);
+gboolean gdl_data_model_iter_children (GdlDataModel *dm,
+ GdlDataIter *iter,
+ GdlDataIter *children);
+gboolean gdl_data_model_iter_has_child (GdlDataModel *dm,
+ GdlDataIter *iter);
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgdl/gdl-data-row.c b/src/libgdl/gdl-data-row.c
new file mode 100644
index 000000000..666c658fe
--- /dev/null
+++ b/src/libgdl/gdl-data-row.c
@@ -0,0 +1,604 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * This file is part of the GNOME Devtools Libraries.
+ *
+ * Copyright (C) 2001 Dave Camp <dave@ximian.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gdl-i18n.h"
+#include "gdl-tools.h"
+#include "gdl-data-row.h"
+#include "gdl-data-model.h"
+
+#include <gtk/gtktreemodel.h>
+#include <gtk/gtkcellrenderer.h>
+
+struct _GdlDataRowPrivate {
+ GdlDataModel *model;
+ GtkTreePath *path;
+ GdlDataView *view;
+
+ char *name;
+
+ /* area_r
+ * +- title_r
+ * | +- name_r
+ * | +- sep_r
+ * +- data_r
+ * +- expand_r
+ * +- cell_r
+ */
+
+ GdkRectangle area_r;
+
+ GdkRectangle title_r;
+ GdkRectangle name_r;
+ GdkRectangle sep_r;
+
+ GdkRectangle data_r;
+ GdkRectangle expand_r;
+ GdkRectangle cell_r;
+
+ gboolean multi;
+ GtkCellRenderer *cell;
+ GList *subrows;
+
+ char *renderer_field;
+
+ gboolean expanded;
+ gboolean focused;
+ gboolean editable;
+
+ int split;
+ int child_split;
+ gboolean selected;
+};
+
+GDL_CLASS_BOILERPLATE (GdlDataRow, gdl_data_row, GObject, G_TYPE_OBJECT);
+
+
+static void
+expand (GdlDataRow *row)
+{
+ GdlDataIter iter;
+ gboolean valid;
+
+ if (gdl_data_model_get_iter (row->priv->model, &iter, row->priv->path)) {
+ valid = gdl_data_model_iter_children (row->priv->model,
+ &iter, &iter);
+ while (valid) {
+ GdlDataRow *new_row;
+ GtkTreePath *path;
+
+ path = gdl_data_model_get_path (row->priv->model,
+ &iter);
+ new_row = gdl_data_row_new (row->priv->view,
+ path);
+ row->priv->subrows =
+ g_list_prepend (row->priv->subrows, new_row);
+ gtk_tree_path_free (path);
+
+ valid = gdl_data_model_iter_next (row->priv->model,
+ &iter);
+ }
+ row->priv->subrows = g_list_reverse (row->priv->subrows);
+
+ row->priv->expanded = TRUE;
+ gdl_data_view_layout (GDL_DATA_VIEW (row->priv->view));
+ gtk_widget_queue_draw (GTK_WIDGET (row->priv->view));
+ }
+}
+
+static void
+contract (GdlDataRow *row)
+{
+ GList *l;
+ for (l = row->priv->subrows; l != NULL; l = l->next) {
+ g_object_unref (G_OBJECT (l->data));
+ }
+ g_list_free (row->priv->subrows);
+ row->priv->subrows = NULL;
+
+ row->priv->expanded = FALSE;
+ gdl_data_view_layout (GDL_DATA_VIEW (row->priv->view));
+ gtk_widget_queue_draw (GTK_WIDGET (row->priv->view));
+}
+
+static void
+load_path (GdlDataRow *row)
+{
+ GdlDataIter iter;
+
+ /* Make sure the path has been unloaded */
+ g_return_if_fail (row->priv->name == NULL);
+ g_return_if_fail (row->priv->cell == NULL);
+
+ if (gdl_data_model_get_iter (row->priv->model,
+ &iter, row->priv->path)) {
+ GValue val = { 0, };
+ char *str;
+
+ gdl_data_model_get_name (row->priv->model, &iter,
+ &str);
+ row->priv->name = g_strdup (str);
+
+ if (gdl_data_model_iter_has_child (row->priv->model, &iter)) {
+ row->priv->multi = TRUE;
+ }
+
+ gdl_data_model_get_renderer (row->priv->model, &iter,
+ &row->priv->cell,
+ &str,
+ &row->priv->editable);
+ g_object_ref (GTK_OBJECT (row->priv->cell));
+ gtk_object_sink (GTK_OBJECT (row->priv->cell));
+
+ row->priv->renderer_field = g_strdup (str);
+ gdl_data_model_get_value (row->priv->model, &iter, &val);
+
+ g_object_set_property (G_OBJECT (row->priv->cell),
+ row->priv->renderer_field,
+ &val);
+ g_value_unset (&val);
+ }
+}
+
+static void
+unload_path (GdlDataRow *row)
+{
+ if (row->priv->renderer_field) {
+ g_free (row->priv->renderer_field);
+ row->priv->renderer_field = NULL;
+ }
+
+ if (row->priv->name) {
+ g_free (row->priv->name);
+ row->priv->name = NULL;
+ }
+
+ if (row->priv->cell) {
+ g_object_unref (row->priv->cell);
+ row->priv->cell = NULL;
+ }
+
+ if (row->priv->subrows) {
+ GList *l;
+ for (l = row->priv->subrows; l != NULL; l = l->next) {
+ g_object_unref (G_OBJECT (l->data));
+ }
+ g_list_free (row->priv->subrows);
+ row->priv->subrows = NULL;
+ }
+}
+
+static void
+gdl_data_row_instance_init (GdlDataRow *row)
+{
+ row->priv = g_new0 (GdlDataRowPrivate, 1);
+}
+
+static void
+gdl_data_row_finalize (GObject *object)
+{
+ GdlDataRow *row = GDL_DATA_ROW (object);
+ if (row->priv) {
+ unload_path (row);
+
+ if (row->priv->path) {
+ gtk_tree_path_free (row->priv->path);
+ row->priv->path = NULL;
+ }
+
+
+ g_object_unref (row->priv->model);
+
+ g_free (row->priv);
+ row->priv = NULL;
+ }
+}
+
+static void
+gdl_data_row_class_init (GdlDataRowClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass*) klass;
+ gobject_class->finalize = gdl_data_row_finalize;
+
+ parent_class = g_type_class_peek_parent (klass);
+}
+
+GdlDataRow *
+gdl_data_row_new (GdlDataView *view,
+ GtkTreePath *path)
+{
+ GdlDataRow *row;
+
+ row = GDL_DATA_ROW (g_object_new (gdl_data_row_get_type (),
+ NULL));
+
+ row->priv->view = view;
+ row->priv->model = g_object_ref (view->model);
+ row->priv->path = gtk_tree_path_copy (path);
+ load_path (row);
+
+ return row;
+}
+
+
+#define PAD 3
+
+static void
+layout_row (GdlDataRow *row,
+ int x, int y, int width, int height)
+{
+ PangoLayout *layout;
+
+ /* sizes */
+
+ layout = gtk_widget_create_pango_layout (GTK_WIDGET (row->priv->view),
+ row->priv->name);
+ pango_layout_get_pixel_size (layout,
+ &row->priv->name_r.width,
+ &row->priv->name_r.height);
+ g_object_unref (layout);
+
+ layout = gtk_widget_create_pango_layout (GTK_WIDGET (row->priv->view), "=");
+ pango_layout_get_pixel_size (layout,
+ &row->priv->sep_r.width,
+ &row->priv->sep_r.height);
+ g_object_unref (layout);
+
+ row->priv->title_r.width =
+ MAX (row->priv->name_r.width + row->priv->sep_r.width + PAD,
+ row->priv->split);
+ row->priv->title_r.height =
+ MAX (row->priv->name_r.height, row->priv->sep_r.width);
+
+ if (row->priv->cell) {
+ gtk_cell_renderer_get_size (row->priv->cell,
+ GTK_WIDGET (row->priv->view),
+ NULL, NULL, NULL,
+ &row->priv->cell_r.width,
+ &row->priv->cell_r.height);
+ } else {
+ row->priv->cell_r.width = row->priv->cell_r.height = 0;
+ }
+
+ row->priv->data_r.width = row->priv->cell_r.width;
+ row->priv->data_r.height = row->priv->cell_r.height;
+
+ if (row->priv->multi) {
+ row->priv->expand_r.width = 10;
+ row->priv->expand_r.height = 10;
+
+ row->priv->data_r.width += row->priv->expand_r.width;
+ row->priv->data_r.height = MAX (row->priv->expand_r.height,
+ row->priv->data_r.height);
+
+ if (row->priv->expanded) {
+ GList *l;
+ int name_w = 0, data_w = 0;
+ for (l = row->priv->subrows; l != NULL; l = l->next) {
+ int w1, w2, h;
+ gdl_data_row_get_size (GDL_DATA_ROW (l->data),
+ &w1, &w2, NULL, &h);
+ name_w = MAX (name_w, w1);
+ data_w = MAX (data_w, w2);
+ row->priv->data_r.height += h;
+ }
+ row->priv->child_split = name_w;
+ row->priv->data_r.width =
+ MAX (name_w + data_w + 3 * PAD,
+ row->priv->data_r.width);
+ row->priv->data_r.height += 2 * PAD;
+ }
+ }
+
+ row->priv->area_r.width = MAX (width,
+ row->priv->data_r.width + row->priv->title_r.width + PAD);
+
+ row->priv->area_r.height = MAX (height,
+ (MAX (row->priv->data_r.height,
+ row->priv->title_r.height)));
+
+ /* Positions */
+
+ row->priv->area_r.x = x;
+ row->priv->area_r.y = y;
+
+ row->priv->title_r.x = x;
+ row->priv->title_r.y = y + ((row->priv->area_r.height) / 2) - (row->priv->title_r.height / 2);
+
+ row->priv->name_r.x = x;
+ row->priv->name_r.y = y + ((row->priv->area_r.height) / 2) - (row->priv->name_r.height / 2);
+
+ row->priv->sep_r.x = row->priv->title_r.x + row->priv->title_r.width - row->priv->sep_r.width;
+ row->priv->sep_r.y = y + ((row->priv->area_r.height) / 2) - (row->priv->sep_r.height / 2);
+
+ row->priv->data_r.x = row->priv->title_r.x + row->priv->title_r.width + PAD;
+ row->priv->data_r.y = y;
+
+ /* Readjust the data area size to fit */
+ row->priv->data_r.width = row->priv->area_r.width - (row->priv->title_r.width + PAD);
+ row->priv->data_r.height = row->priv->area_r.height;
+
+ if (row->priv->multi) {
+ row->priv->expand_r.x = row->priv->data_r.x;
+ row->priv->expand_r.y = row->priv->data_r.y + ((row->priv->cell_r.height) / 2) - (row->priv->expand_r.height / 2);
+
+ row->priv->cell_r.y = row->priv->data_r.y;
+ row->priv->cell_r.height = MAX (row->priv->expand_r.height, row->priv->cell_r.height);
+ row->priv->cell_r.width = (row->priv->data_r.width - row->priv->expand_r.width);
+
+ row->priv->cell_r.x = row->priv->expand_r.x + row->priv->expand_r.width;
+ } else {
+ row->priv->cell_r = row->priv->data_r;
+ }
+}
+
+void
+gdl_data_row_get_size (GdlDataRow *row, int *sep_width,
+ int *cell_width, int *total_width, int *height)
+{
+ layout_row (row, 0, 0, 0, 0);
+
+ if (sep_width) {
+ *sep_width = row->priv->name_r.width + row->priv->sep_r.width + PAD;
+ }
+
+ if (cell_width) *cell_width = row->priv->data_r.width;
+ if (total_width) *total_width = row->priv->area_r.width;
+ if (height) *height = row->priv->area_r.height;
+}
+
+void
+gdl_data_row_set_show_name (GdlDataRow *row, gboolean show_name)
+{
+}
+
+void
+gdl_data_row_layout (GdlDataRow *row, GdkRectangle *alloc)
+{
+ layout_row (row, alloc->x, alloc->y, alloc->width, alloc->height);
+
+ if (row->priv->multi && row->priv->expanded) {
+ GList *l;
+ GdkRectangle sub;
+ sub.y = row->priv->expand_r.y + row->priv->expand_r.width + PAD;
+ sub.x = row->priv->data_r.x + PAD;
+ sub.width = row->priv->data_r.width - 2 * PAD;
+ sub.height = row->priv->data_r.height - 2 * PAD;
+
+ for (l = row->priv->subrows; l != NULL; l = l->next) {
+ gdl_data_row_get_size (GDL_DATA_ROW (l->data),
+ NULL, NULL, NULL, &sub.height);
+ gdl_data_row_set_split (GDL_DATA_ROW (l->data),
+ row->priv->child_split);
+ gdl_data_row_layout (GDL_DATA_ROW (l->data),
+ &sub);
+ sub.y += sub.height;
+ }
+ }
+}
+
+#if 0
+#define DRAWR(r) { gdk_draw_rectangle (drawable, GTK_WIDGET (row->priv->view)->style->text_gc[GTK_STATE_NORMAL],FALSE,row->priv->r.x,row->priv->r.y,row->priv->r.width, row->priv->r.height); }
+#else
+#define DRAWR(r)
+#endif
+
+
+void
+gdl_data_row_render (GdlDataRow *row, GdkDrawable *drawable,
+ GdkRectangle *expose_area,
+ GtkCellRendererState flags)
+{
+ PangoLayout *layout;
+
+ guint state = GTK_STATE_NORMAL;
+
+ if (row->priv->selected) {
+ if (flags & GTK_CELL_RENDERER_SELECTED)
+ state = GTK_STATE_SELECTED;
+ else
+ state = GTK_STATE_ACTIVE;
+ gtk_paint_flat_box (GTK_WIDGET (row->priv->view)->style,
+ drawable, state,
+ GTK_SHADOW_NONE, expose_area,
+ GTK_WIDGET (row->priv->view), "cell_even",
+ row->priv->area_r.x, row->priv->area_r.y,
+ row->priv->area_r.width + 1,
+ row->priv->area_r.height + 1);
+
+ }
+
+ layout = gtk_widget_create_pango_layout (GTK_WIDGET (row->priv->view),
+ row->priv->name);
+ gdk_draw_layout (drawable,
+ GTK_WIDGET (row->priv->view)->style->text_gc[state],
+ row->priv->name_r.x, row->priv->name_r.y, layout);
+ g_object_unref (layout);
+ DRAWR(name_r);
+
+ layout = gtk_widget_create_pango_layout (GTK_WIDGET (row->priv->view), "=");
+ gdk_draw_layout (drawable,
+ GTK_WIDGET (row->priv->view)->style->text_gc[state],
+ row->priv->sep_r.x, row->priv->sep_r.y, layout);
+ g_object_unref (layout);
+ DRAWR(sep_r);
+ DRAWR(title_r);
+
+ if (row->priv->cell) {
+ if (row->priv->focused) {
+ gtk_paint_focus (GTK_WIDGET (row->priv->view)->style,
+ drawable,
+ GTK_WIDGET_STATE (GTK_WIDGET (row->priv->view)),
+ NULL, GTK_WIDGET (row->priv->view),
+ "treeview",
+ row->priv->cell_r.x - 1,
+ row->priv->cell_r.y - 1,
+ row->priv->cell_r.width + 2,
+ row->priv->cell_r.height + 2);
+ }
+
+ gtk_cell_renderer_render (row->priv->cell,
+ drawable, GTK_WIDGET (row->priv->view),
+ &row->priv->area_r,
+ &row->priv->cell_r,
+ expose_area,
+ row->priv->selected ? GTK_CELL_RENDERER_SELECTED : 0);
+ DRAWR(cell_r);
+ }
+ if (row->priv->multi) {
+ gtk_paint_expander (GTK_WIDGET (row->priv->view)->style,
+ drawable,
+ GTK_WIDGET_STATE (GTK_WIDGET (row->priv->view)),
+ expose_area,
+ GTK_WIDGET (row->priv->view),
+ "gdldataview",
+ row->priv->expand_r.x + row->priv->expand_r.width / 2,
+ row->priv->expand_r.y + row->priv->expand_r.height / 2,
+ row->priv->expanded ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED);
+ DRAWR(expand_r);
+
+ if (row->priv->expanded) {
+ GList *l;
+
+ for (l = row->priv->subrows; l != NULL; l = l->next) {
+ gdl_data_row_render (GDL_DATA_ROW (l->data),
+ drawable,
+ expose_area, flags);
+ }
+ }
+ gdk_draw_rectangle (drawable,
+ GTK_WIDGET (row->priv->view)->style->text_gc[GTK_STATE_NORMAL],
+ FALSE,
+ row->priv->data_r.x,
+ row->priv->data_r.y,
+ row->priv->data_r.width,
+ row->priv->data_r.height);
+ }
+ DRAWR(data_r);
+}
+
+
+GdlDataRow *
+gdl_data_row_at (GdlDataRow *row, int x, int y)
+{
+ if (!GDL_POINT_IN (x, y, &row->priv->area_r)) {
+ return NULL;
+ }
+
+ if (row->priv->multi && row->priv->expanded) {
+ GList *l;
+ for (l = row->priv->subrows; l != NULL; l = l->next) {
+ GdlDataRow *ret = gdl_data_row_at (GDL_DATA_ROW (l->data), x, y);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return row;
+}
+
+static gboolean
+button_press_event (GdlDataRow *row, GdkEventButton *event,
+ GtkCellEditable **editable_widget)
+{
+ if (editable_widget)
+ *editable_widget = NULL;
+
+ if (GDL_POINT_IN (event->x, event->y, &row->priv->expand_r)) {
+ if (row->priv->expanded)
+ contract (row);
+ else
+ expand (row);
+ }
+
+ if (GDL_POINT_IN (event->x, event->y, &row->priv->cell_r)
+ && row->priv->editable) {
+ g_return_val_if_fail (editable_widget, FALSE);
+ *editable_widget = gtk_cell_renderer_start_editing
+ (row->priv->cell,
+ (GdkEvent*)event,
+ GTK_WIDGET (row->priv->view),
+ "1:2:3",
+ &row->priv->area_r,
+ &row->priv->cell_r,
+ GTK_CELL_RENDERER_SELECTED);
+ }
+
+ return FALSE;
+
+}
+
+
+gboolean
+gdl_data_row_event (GdlDataRow *row, GdkEvent *event,
+ GtkCellEditable **editable_widget)
+{
+ switch (((GdkEventAny *)event)->type) {
+ case GDK_BUTTON_PRESS:
+ return button_press_event (row,
+ (GdkEventButton *)event,
+ editable_widget);
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+void
+gdl_data_row_get_cell_area (GdlDataRow *row,
+ GdkRectangle *rect)
+{
+ *rect = row->priv->cell_r;
+}
+
+void
+gdl_data_row_set_split (GdlDataRow *row, int split)
+{
+ row->priv->split = split;
+}
+
+void
+gdl_data_row_set_selected (GdlDataRow *row, gboolean selected)
+{
+ row->priv->selected = selected;
+
+ /* FIXME: invalidate here */
+ gtk_widget_queue_draw (GTK_WIDGET (row->priv->view));
+}
+
+void
+gdl_data_row_set_focused (GdlDataRow *row, gboolean focused)
+{
+ row->priv->focused = focused;
+
+ /* FIXME: invalidate here */
+ gtk_widget_queue_draw (GTK_WIDGET (row->priv->view));
+}
+
+const char *
+gdl_data_row_get_title (GdlDataRow *row)
+{
+ return row->priv->name;
+}
diff --git a/src/libgdl/gdl-data-row.h b/src/libgdl/gdl-data-row.h
new file mode 100644
index 000000000..d4928958d
--- /dev/null
+++ b/src/libgdl/gdl-data-row.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * This file is part of the GNOME Devtools Libraries.
+ *
+ * Copyright (C) 2001 Dave Camp <dave@ximian.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GDL_DATA_ROW_H
+#define GDL_DATA_ROW_H
+
+#include <glib.h>
+
+#include <glib-object.h>
+#include <gtk/gtktreemodel.h>
+#include <gtk/gtkcellrenderer.h>
+#include <gdl/gdl-data-view.h>
+
+G_BEGIN_DECLS
+
+#define GDL_TYPE_DATA_ROW (gdl_data_row_get_type ())
+#define GDL_DATA_ROW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDL_TYPE_DATA_ROW, GdlDataRow))
+#define GDL_DATA_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDL_TYPE_DATA_ROW, GdlDataRowClass))
+#define GDL_IS_DATA_ROW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDL_TYPE_DATA_ROW))
+#define GDL_IS_DATA_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDL_TYPE_DATA_ROW))
+
+typedef struct _GdlDataRow GdlDataRow;
+typedef struct _GdlDataRowClass GdlDataRowClass;
+typedef struct _GdlDataRowPrivate GdlDataRowPrivate;
+
+struct _GdlDataRow {
+ GObject parent;
+
+ GdlDataRowPrivate *priv;
+};
+
+struct _GdlDataRowClass {
+ GObjectClass parent_class;
+};
+
+GType gdl_data_row_get_type (void);
+GdlDataRow *gdl_data_row_new (GdlDataView *view,
+ GtkTreePath *path);
+void gdl_data_row_get_size (GdlDataRow *row,
+ int *text_w,
+ int *cell_w,
+ int *total_width,
+ int *height);
+void gdl_data_row_set_show_name (GdlDataRow *row,
+ gboolean show_name);
+void gdl_data_row_layout (GdlDataRow *row,
+ GdkRectangle *alloc);
+void gdl_data_row_render (GdlDataRow *row,
+ GdkDrawable *drawable,
+ GdkRectangle *expose_area,
+ GtkCellRendererState flags);
+GdlDataRow *gdl_data_row_at (GdlDataRow *row,
+ int x,
+ int y);
+gboolean gdl_data_row_event (GdlDataRow *row,
+ GdkEvent *event,
+ GtkCellEditable **editable_widget);
+void gdl_data_row_get_cell_area (GdlDataRow *row,
+ GdkRectangle *rect);
+void gdl_data_row_set_split (GdlDataRow *row,
+ int split);
+void gdl_data_row_set_selected (GdlDataRow *row,
+ gboolean selected);
+void gdl_data_row_set_focused (GdlDataRow *row,
+ gboolean focused);
+const char *gdl_data_row_get_title (GdlDataRow *row);
+
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgdl/gdl-data-view.c b/src/libgdl/gdl-data-view.c
new file mode 100644
index 000000000..81e1795f7
--- /dev/null
+++ b/src/libgdl/gdl-data-view.c
@@ -0,0 +1,526 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * This file is part of the GNOME Devtools Libraries.
+ *
+ * Copyright (C) 2001 Dave Camp <dave@ximian.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gdl-i18n.h"
+#include "gdl-tools.h"
+#include "gdl-data-view.h"
+#include "gdl-data-frame.h"
+
+#include "tree-expand.xpm"
+#include "tree-contract.xpm"
+
+struct _GdlDataViewPrivate {
+ GList *frames;
+ GList *rows;
+ GList *widgets;
+
+ GdlDataFrame *selected_frame;
+ GdlDataRow *selected_row;
+
+ GtkCellEditable *editable;
+
+ GdkPixbuf *close_pixbuf;
+ GdkPixbuf *expand_pixbuf;
+ GdkPixbuf *contract_pixbuf;
+};
+
+typedef struct {
+ GtkWidget *widget;
+ int x, y, height, width;
+} ChildWidget;
+
+static void gdl_data_view_instance_init (GdlDataView *dv);
+static void gdl_data_view_class_init (GdlDataViewClass *klass);
+
+GDL_CLASS_BOILERPLATE (GdlDataView, gdl_data_view, GtkLayout, GTK_TYPE_LAYOUT);
+
+
+#define GRID_SPACING 15
+
+static void
+paint_grid (GtkWidget *widget, GdkDrawable *drawable,
+ int offset_x, int offset_y, int width, int height)
+{
+ GdlDataView *dv;
+ int x;
+ int y;
+
+ g_return_if_fail (GDL_IS_DATA_VIEW (widget));
+ dv = GDL_DATA_VIEW (widget);
+
+ x = offset_x + ((GRID_SPACING - (offset_x % GRID_SPACING)) % GRID_SPACING);
+
+ /* Draw grid points */
+ for (; x < width; x += GRID_SPACING) {
+ y = offset_y + ((GRID_SPACING - (offset_y % GRID_SPACING)) % GRID_SPACING);
+
+ for (; y < height; y += GRID_SPACING) {
+ gdk_draw_point (drawable,
+ widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+ x, y);
+ }
+ }
+}
+
+static void
+expose_frames (GdlDataView *view, GdkEventExpose *event)
+{
+ GList *l;
+
+ for (l = view->priv->frames; l != NULL; l = l->next) {
+ GdkRectangle intersect;
+ GdlDataFrame *frame = GDL_DATA_FRAME (l->data);
+ if (gdk_rectangle_intersect (&frame->area,
+ &event->area,
+ &intersect)) {
+ gdl_data_frame_draw (GDL_DATA_FRAME (l->data),
+ GTK_LAYOUT(view)->bin_window,
+ &intersect);
+ }
+ }
+}
+
+static void
+expose_widgets (GdlDataView *view, GdkEventExpose *event)
+{
+ GList *l;
+
+ for (l = view->priv->widgets; l != NULL; l = l->next) {
+ ChildWidget *child = l->data;
+ gtk_container_propagate_expose (GTK_CONTAINER (view),
+ child->widget, event);
+ }
+}
+
+static gboolean
+gdl_data_view_expose (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ if (GTK_WIDGET_DRAWABLE (widget)) {
+ if (event->window == GTK_LAYOUT (widget)->bin_window) {
+ paint_grid (widget, GTK_LAYOUT (widget)->bin_window,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ expose_frames (GDL_DATA_VIEW (widget), event);
+ expose_widgets (GDL_DATA_VIEW (widget), event);
+ return TRUE;
+ } else {
+ GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
+ }
+ }
+
+ return FALSE;
+}
+
+static GdlDataFrame *
+frame_at (GdlDataView *dv, int x, int y)
+{
+ GList *l;
+ for (l = dv->priv->frames; l != NULL; l = l->next) {
+ GdlDataFrame *frame = l->data;
+ if (x >= frame->area.x && x <= frame->area.x + frame->area.width
+ && y >= frame->area.y && y <= frame->area.y + frame->area.height) {
+ return frame;
+ }
+ }
+ return NULL;
+}
+
+static GdlDataRow *
+row_at (GdlDataView *view, int x, int y)
+{
+ GList *l;
+ GdlDataRow *ret = NULL;
+ for (l = view->priv->rows; l != NULL; l = l->next) {
+ GdlDataRow *row = l->data;
+ ret = gdl_data_row_at (row, x, y);
+ if (ret) break;
+ }
+ return ret;
+}
+
+static void
+gdl_data_view_put (GdlDataView *view, GtkWidget *widget,
+ int x, int y, int width, int height)
+{
+ ChildWidget *child = g_new0 (ChildWidget, 1);
+
+ child->widget = widget;
+ child->x = x;
+ child->y = y;
+ child->width = width;
+ child->height = height;
+
+ view->priv->widgets = g_list_append (view->priv->widgets, child);
+
+ if (GTK_WIDGET_REALIZED (view)) {
+ gtk_widget_set_parent_window (child->widget,
+ GTK_LAYOUT (view)->bin_window);
+ }
+
+ gtk_widget_set_parent (child->widget, GTK_WIDGET (view));
+}
+
+static void
+stop_editing (GdlDataView *dv)
+{
+ if (dv->priv->editable) {
+ gtk_cell_editable_editing_done (dv->priv->editable);
+ gtk_cell_editable_remove_widget (dv->priv->editable);
+ }
+}
+
+static void
+remove_widget_cb (GtkCellEditable *cell_editable, GdlDataView *view)
+{
+ if (view->priv->editable) {
+ view->priv->editable = NULL;
+ gdl_data_row_set_focused (view->priv->selected_row, FALSE);
+ gtk_widget_grab_focus (GTK_WIDGET (view));
+ gtk_container_remove (GTK_CONTAINER (view),
+ GTK_WIDGET (cell_editable));
+ }
+}
+
+static gboolean
+button_press_event_cb (GdlDataView *dv, GdkEventButton *event, gpointer data)
+{
+ GdlDataFrame *frame;
+ GdlDataRow *row;
+ gboolean ret = FALSE;
+
+ stop_editing (dv);
+
+ if (event->type == GDK_BUTTON_PRESS) {
+ frame = frame_at (dv, event->x, event->y);
+ if (frame) {
+ if (dv->priv->selected_frame) {
+ gdl_data_frame_set_selected (dv->priv->selected_frame, FALSE);
+ }
+ gdl_data_frame_set_selected (frame, TRUE);
+ dv->priv->selected_frame = frame;
+ }
+
+ row = row_at (dv, event->x, event->y);
+ if (row) {
+ GtkCellEditable *editable;
+
+ if (dv->priv->selected_row) {
+ gdl_data_row_set_selected (dv->priv->selected_row,
+ FALSE);
+ }
+ dv->priv->selected_row = row;
+ gdl_data_row_set_selected (row, TRUE);
+ ret = gdl_data_row_event (row, (GdkEvent*)event,
+ &editable);
+ if (editable) {
+ GdkRectangle area;
+ dv->priv->editable = editable;
+ gtk_cell_editable_start_editing (editable,
+ (GdkEvent*)event);
+
+ gdl_data_row_get_cell_area (row, &area);
+ gdl_data_view_put (dv,
+ GTK_WIDGET (editable),
+ area.x,
+ area.y,
+ area.width,
+ area.height);
+
+ gtk_widget_grab_focus (GTK_WIDGET (editable));
+ dv->priv->editable = editable;
+ gdl_data_row_set_focused (row, TRUE);
+
+ g_signal_connect
+ (G_OBJECT (editable),
+ "remove_widget",
+ G_CALLBACK (remove_widget_cb), dv);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static void
+gdl_data_view_instance_init (GdlDataView *dv)
+{
+ GTK_WIDGET_SET_FLAGS (dv, GTK_CAN_FOCUS);
+ dv->priv = g_new0 (GdlDataViewPrivate, 1);
+
+ g_signal_connect (G_OBJECT (dv), "button_press_event",
+ G_CALLBACK (button_press_event_cb),
+ NULL);
+
+ dv->priv->close_pixbuf = gtk_widget_render_icon (GTK_WIDGET (dv),
+ "gtk-close",
+ GTK_ICON_SIZE_MENU,
+ "gdl-data-view-close");
+
+ dv->priv->expand_pixbuf =
+ gdk_pixbuf_new_from_xpm_data ((const char **)tree_expand_xpm);
+
+ dv->priv->contract_pixbuf =
+ gdk_pixbuf_new_from_xpm_data ((const char **)tree_contract_xpm);
+}
+
+static void
+gdl_data_view_realize (GtkWidget *widget)
+{
+ GList *l;
+ GdlDataView *view = GDL_DATA_VIEW (widget);
+
+ GDL_CALL_PARENT (GTK_WIDGET_CLASS, realize, (widget));
+
+ for (l = view->priv->widgets; l != NULL; l = l->next) {
+ ChildWidget *child = l->data;
+ gtk_widget_set_parent_window (child->widget,
+ GTK_LAYOUT (view)->bin_window);
+ }
+}
+
+static void
+gdl_data_view_size_request (GtkWidget *widget, GtkRequisition *req)
+{
+ GList *l;
+
+ req->width = req->height = 0;
+
+ for (l = GDL_DATA_VIEW (widget)->priv->widgets; l != NULL; l = l->next) {
+ GtkRequisition child_req;
+ ChildWidget *child = l->data;
+
+ gtk_widget_size_request (child->widget, &child_req);
+ }
+}
+
+
+static void
+gdl_data_view_size_allocate (GtkWidget *widget, GtkAllocation *alloc)
+{
+ GdlDataView *view = GDL_DATA_VIEW (widget);
+ GList *l;
+;
+ for (l = view->priv->widgets; l != NULL; l = l->next) {
+ ChildWidget *child = l->data;
+ GtkAllocation child_alloc;
+
+ child_alloc.x = child->x;
+ child_alloc.y = child->y;
+ child_alloc.width = child->width;
+ child_alloc.height = child->height;
+
+ gtk_widget_size_allocate (child->widget, &child_alloc);
+ }
+ GDL_CALL_PARENT (GTK_WIDGET_CLASS, size_allocate, (widget, alloc));
+}
+
+static void
+gdl_data_view_forall (GtkContainer *container, gboolean include_internals,
+ GtkCallback callback, gpointer callback_data)
+{
+ GdlDataView *view = GDL_DATA_VIEW (container);
+ GList *l;
+
+ for (l = view->priv->widgets; l != NULL; l = l->next) {
+ ChildWidget *child = l->data;
+ (*callback) (child->widget, callback_data);
+ }
+}
+
+static void
+gdl_data_view_remove (GtkContainer *container, GtkWidget *widget)
+{
+ GList *l;
+ GdlDataView *view = GDL_DATA_VIEW (container);
+
+ for (l = view->priv->widgets; l != NULL; l = l->next) {
+ ChildWidget *child = l->data;
+ if (child->widget == widget) {
+ gtk_widget_unparent (widget);
+ view->priv->widgets =
+ g_list_remove_link (view->priv->widgets, l);
+ g_list_free_1 (l);
+ g_free (child);
+ return;
+ }
+ }
+}
+
+static void
+gdl_data_view_destroy (GtkObject *obj)
+{
+ GdlDataView *dv = GDL_DATA_VIEW (obj);
+
+ stop_editing (dv);
+
+ if (dv->priv) {
+ GList *l;
+ for (l = dv->priv->frames; l != NULL; l = l->next) {
+ g_object_unref (G_OBJECT (l->data));
+ }
+ g_list_free (dv->priv->frames);
+
+ g_object_unref (dv->priv->close_pixbuf);
+ g_object_unref (dv->priv->expand_pixbuf);
+ g_object_unref (dv->priv->contract_pixbuf);
+
+ g_free (dv->priv);
+ dv->priv = NULL;
+ }
+ GDL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (obj));
+}
+
+static void
+gdl_data_view_class_init (GdlDataViewClass *klass)
+{
+ GtkObjectClass *object_class = (GtkObjectClass *)klass;
+ GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
+ GtkContainerClass *container_class = (GtkContainerClass *)klass;
+
+ parent_class = gtk_type_class (GTK_TYPE_LAYOUT);
+
+ container_class->forall = gdl_data_view_forall;
+ container_class->remove = gdl_data_view_remove;
+
+ widget_class->expose_event = gdl_data_view_expose;
+ widget_class->realize = gdl_data_view_realize;
+ /* FIXME: unrealize */
+ widget_class->size_request = gdl_data_view_size_request;
+ widget_class->size_allocate = gdl_data_view_size_allocate;
+ object_class->destroy = gdl_data_view_destroy;
+
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_int ("expander-size",
+ _("Expander Size"),
+ _("Size of the expander arrow."),
+ 0,
+ G_MAXINT,
+ 10,
+ G_PARAM_READABLE));
+}
+
+GtkWidget *
+gdl_data_view_new (void)
+{
+ GdlDataView *dv;
+ dv = g_object_new (gdl_data_view_get_type (), NULL);
+ return GTK_WIDGET (dv);
+}
+
+void
+gdl_data_view_set_model (GdlDataView *dv, GdlDataModel *model)
+{
+ GtkTreePath *path;
+ GdlDataIter iter;
+ gboolean iter_valid;
+ int x = 5;
+
+ dv->model = model;
+
+ path = gtk_tree_path_new_from_string ("0");
+
+ iter_valid = gdl_data_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+
+ while (iter_valid) {
+ GdlDataFrame *frame;
+ GdlDataRow *row;
+
+ path = gdl_data_model_get_path (model, &iter);
+
+ row = gdl_data_row_new (dv, path);
+ frame = gdl_data_frame_new (dv, row);
+ gdl_data_frame_set_position (frame, x, 5);
+
+ dv->priv->frames = g_list_append (dv->priv->frames,
+ frame);
+ dv->priv->rows = g_list_append (dv->priv->rows, row);
+
+ gtk_tree_path_free (path);
+
+ x += 150;
+
+ iter_valid = gdl_data_model_iter_next (model, &iter);
+ }
+}
+
+void
+gdl_data_view_layout (GdlDataView *view)
+{
+ GList *l;
+ for (l = view->priv->frames; l != NULL; l = l->next) {
+ gdl_data_frame_layout (GDL_DATA_FRAME (l->data));
+ }
+}
+
+GdkPixbuf *
+gdl_data_view_get_close_pixbuf (GdlDataView *view)
+{
+ return view->priv->close_pixbuf;
+}
+
+void
+gdl_data_view_set_close_pixbuf (GdlDataView *view, GdkPixbuf *pixbuf)
+{
+ if (view->priv->close_pixbuf) {
+ g_object_unref (view->priv->close_pixbuf);
+ }
+
+ view->priv->close_pixbuf = g_object_ref (pixbuf);
+}
+
+GdkPixbuf *
+gdl_data_view_get_expand_pixbuf (GdlDataView *view)
+{
+ return view->priv->expand_pixbuf;
+}
+
+void
+gdl_data_view_set_expand_pixbuf (GdlDataView *view, GdkPixbuf *pixbuf)
+{
+ if (view->priv->expand_pixbuf) {
+ g_object_unref (view->priv->expand_pixbuf);
+ }
+
+ view->priv->expand_pixbuf = g_object_ref (pixbuf);
+}
+
+GdkPixbuf *
+gdl_data_view_get_contract_pixbuf (GdlDataView *view)
+{
+ return view->priv->contract_pixbuf;
+}
+
+void
+gdl_data_view_set_contract_pixbuf (GdlDataView *view, GdkPixbuf *pixbuf)
+{
+ if (view->priv->contract_pixbuf) {
+ g_object_unref (view->priv->contract_pixbuf);
+ }
+
+ view->priv->contract_pixbuf = g_object_ref (pixbuf);
+}
diff --git a/src/libgdl/gdl-data-view.h b/src/libgdl/gdl-data-view.h
new file mode 100644
index 000000000..a29132074
--- /dev/null
+++ b/src/libgdl/gdl-data-view.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * This file is part of the GNOME Devtools Libraries.
+ *
+ * Copyright (C) 2001 Dave Camp <dave@ximian.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GDL_DATA_VIEW_H
+#define GDL_DATA_VIEW_H
+
+#include <gdl/gdl-data-model.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GDL_TYPE_DATA_VIEW (gdl_data_view_get_type ())
+#define GDL_DATA_VIEW(obj) (GTK_CHECK_CAST ((obj), GDL_TYPE_DATA_VIEW, GdlDataView))
+#define GDL_DATA_VIEW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GDL_TYPE_DATA_VIEW, GdlDataViewClass))
+#define GDL_IS_DATA_VIEW(obj) (GTK_CHECK_TYPE ((obj), GDL_TYPE_DATA_VIEW))
+#define GDL_IS_DATA_VIEW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GDL_TYPE_DATA_VIEW))
+#define GDL_DATA_VIEW_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GDL_TYPE_DATA_VIEW, GdlDataViewClass))
+
+typedef struct _GdlDataView GdlDataView;
+typedef struct _GdlDataViewClass GdlDataViewClass;
+typedef struct _GdlDataViewPrivate GdlDataViewPrivate;
+
+#define GDL_POINT_IN(x1,y1,r) ((x1) >= (r)->x && x1 < (r)->x + (r)->width && (y1) >= (r)->y && y1 < (r)->y + (r)->height)
+
+struct _GdlDataView {
+ GtkLayout layout;
+
+ GdlDataModel *model;
+
+ GdlDataViewPrivate *priv;
+};
+
+struct _GdlDataViewClass {
+ GtkLayoutClass parent_class;
+};
+
+GtkType gdl_data_view_get_type (void);
+GtkWidget *gdl_data_view_new (void);
+void gdl_data_view_set_model (GdlDataView *view,
+ GdlDataModel *model);
+void gdl_data_view_layout (GdlDataView *view);
+GdkPixbuf *gdl_data_view_get_close_pixbuf (GdlDataView *view);
+void gdl_data_view_set_close_pixbuf (GdlDataView *view,
+ GdkPixbuf *pixbuf);
+GdkPixbuf *gdl_data_view_get_expand_pixbuf (GdlDataView *view);
+void gdl_data_view_set_expand_pixbuf (GdlDataView *view,
+ GdkPixbuf *pixbuf);
+GdkPixbuf *gdl_data_view_get_contract_pixbuf (GdlDataView *view);
+void gdl_data_view_set_contract_pixbuf (GdlDataView *view,
+ GdkPixbuf *pixbuf);
+
+#endif
diff --git a/src/libgdl/gdl-dock-item-grip.c b/src/libgdl/gdl-dock-item-grip.c
index 2513313ef..2101d9621 100644
--- a/src/libgdl/gdl-dock-item-grip.c
+++ b/src/libgdl/gdl-dock-item-grip.c
@@ -293,10 +293,10 @@ gdl_dock_item_grip_set_property (GObject *object,
case PROP_ITEM:
grip->item = g_value_get_object (value);
if (grip->item) {
- g_signal_connect (grip->item, "notify::long_name",
+ g_signal_connect (grip->item, "notify::long-name",
G_CALLBACK (gdl_dock_item_grip_item_notify),
grip);
- g_signal_connect (grip->item, "notify::stock_id",
+ g_signal_connect (grip->item, "notify::stock-id",
G_CALLBACK (gdl_dock_item_grip_item_notify),
grip);
g_signal_connect (grip->item, "notify::behavior",
diff --git a/src/libgdl/gdl-dock-item.c b/src/libgdl/gdl-dock-item.c
index c01737636..db31ade30 100644
--- a/src/libgdl/gdl-dock-item.c
+++ b/src/libgdl/gdl-dock-item.c
@@ -1257,8 +1257,9 @@ gdl_dock_item_dock (GdlDockObject *object,
GdlDockPlacement position,
GValue *other_data)
{
- GdlDockObject *new_parent, *parent;
- gboolean add_ourselves_first;
+ GdlDockObject *new_parent = NULL;
+ GdlDockObject *parent, *requestor_parent;
+ gboolean add_ourselves_first = FALSE;
guint available_space=0;
gint pref_size=-1;
@@ -1372,11 +1373,16 @@ gdl_dock_item_dock (GdlDockObject *object,
pref_size = req.width;
break;
case GDL_DOCK_CENTER:
- new_parent = g_object_new (gdl_dock_object_type_from_nick ("notebook"),
- "preferred-width", object_req.width,
- "preferred-height", object_req.height,
- NULL);
- add_ourselves_first = TRUE;
+ /* If the parent is already a DockNotebook, we don't need
+ to create a new one. */
+ if (!GDL_IS_DOCK_NOTEBOOK (parent))
+ {
+ new_parent = g_object_new (gdl_dock_object_type_from_nick ("notebook"),
+ "preferred-width", object_req.width,
+ "preferred-height", object_req.height,
+ NULL);
+ add_ourselves_first = TRUE;
+ }
break;
default:
{
@@ -1396,9 +1402,12 @@ gdl_dock_item_dock (GdlDockObject *object,
gdl_dock_object_freeze (parent);
/* ref ourselves since we could be destroyed when detached */
- g_object_ref (object);
- GDL_DOCK_OBJECT_SET_FLAGS (object, GDL_DOCK_IN_REFLOW);
- gdl_dock_object_detach (object, FALSE);
+ if (new_parent)
+ {
+ g_object_ref (object);
+ GDL_DOCK_OBJECT_SET_FLAGS (object, GDL_DOCK_IN_REFLOW);
+ gdl_dock_object_detach (object, FALSE);
+ }
/* freeze the new parent, so reduce won't get called before it's
actually added to our parent */
@@ -1424,7 +1433,14 @@ gdl_dock_item_dock (GdlDockObject *object,
/* show automatic object */
if (gtk_widget_get_visible (GTK_WIDGET (object)))
+ {
gtk_widget_show (GTK_WIDGET (new_parent));
+ GDL_DOCK_OBJECT_UNSET_FLAGS (object, GDL_DOCK_IN_REFLOW);
+ gdl_dock_object_thaw (new_parent);
+ }
+ else // If the parent is already a DockNotebook, we don't need
+ // to create a new one.
+ gtk_container_add (GTK_CONTAINER (parent), GTK_WIDGET (requestor));
/* use extra docking parameter */
if (position != GDL_DOCK_CENTER && other_data &&
@@ -1437,10 +1453,17 @@ gdl_dock_item_dock (GdlDockObject *object,
g_object_set (G_OBJECT (new_parent), "position", splitpos, NULL);
}
- GDL_DOCK_OBJECT_UNSET_FLAGS (object, GDL_DOCK_IN_REFLOW);
g_object_unref (object);
- gdl_dock_object_thaw (new_parent);
+ requestor_parent = gdl_dock_object_get_parent_object (requestor);
+ if (GDL_IS_DOCK_NOTEBOOK (requestor_parent))
+ {
+ /* Activate the page we just added */
+ GdlDockItem* notebook = GDL_DOCK_ITEM (gdl_dock_object_get_parent_object (requestor));
+ gtk_notebook_set_page (GTK_NOTEBOOK (notebook->child),
+ gtk_notebook_page_num (GTK_NOTEBOOK (notebook->child), GTK_WIDGET (requestor)));
+ }
+
if (parent)
gdl_dock_object_thaw (parent);
diff --git a/src/libgdl/gdl-dock-layout.c b/src/libgdl/gdl-dock-layout.c
new file mode 100644
index 000000000..c3b0a4dac
--- /dev/null
+++ b/src/libgdl/gdl-dock-layout.c
@@ -0,0 +1,1411 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This file is part of the GNOME Devtools Libraries.
+ *
+ * Copyright (C) 2002 Gustavo Giráldez <gustavo.giraldez@gmx.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gdl-i18n.h"
+#include <string.h>
+#include <stdlib.h>
+#include <libxml/parser.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include "gdl-dock-layout.h"
+#include "gdl-tools.h"
+#include "gdl-dock-placeholder.h"
+
+
+/* ----- Private variables ----- */
+
+enum {
+ PROP_0,
+ PROP_MASTER,
+ PROP_DIRTY
+};
+
+#define ROOT_ELEMENT "dock-layout"
+#define DEFAULT_LAYOUT "__default__"
+#define LAYOUT_ELEMENT_NAME "layout"
+#define NAME_ATTRIBUTE_NAME "name"
+
+#define LAYOUT_GLADE_FILE "layout.glade"
+
+enum {
+ COLUMN_NAME,
+ COLUMN_SHOW,
+ COLUMN_LOCKED,
+ COLUMN_ITEM
+};
+
+#define COLUMN_EDITABLE COLUMN_SHOW
+
+struct _GdlDockLayoutPrivate {
+ xmlDocPtr doc;
+
+ /* layout list models */
+ GtkListStore *items_model;
+ GtkListStore *layouts_model;
+
+ /* idle control */
+ gboolean idle_save_pending;
+};
+
+typedef struct _GdlDockLayoutUIData GdlDockLayoutUIData;
+
+struct _GdlDockLayoutUIData {
+ GdlDockLayout *layout;
+ GtkWidget *locked_check;
+ GtkTreeSelection *selection;
+};
+
+
+/* ----- Private prototypes ----- */
+
+static void gdl_dock_layout_class_init (GdlDockLayoutClass *klass);
+
+static void gdl_dock_layout_instance_init (GdlDockLayout *layout);
+
+static void gdl_dock_layout_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void gdl_dock_layout_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gdl_dock_layout_dispose (GObject *object);
+
+static void gdl_dock_layout_build_doc (GdlDockLayout *layout);
+
+static xmlNodePtr gdl_dock_layout_find_layout (GdlDockLayout *layout,
+ const gchar *name);
+
+static void gdl_dock_layout_build_models (GdlDockLayout *layout);
+
+
+/* ----- Private implementation ----- */
+
+GDL_CLASS_BOILERPLATE (GdlDockLayout, gdl_dock_layout, GObject, G_TYPE_OBJECT);
+
+static void
+gdl_dock_layout_class_init (GdlDockLayoutClass *klass)
+{
+ GObjectClass *g_object_class = (GObjectClass *) klass;
+
+ g_object_class->set_property = gdl_dock_layout_set_property;
+ g_object_class->get_property = gdl_dock_layout_get_property;
+ g_object_class->dispose = gdl_dock_layout_dispose;
+
+ g_object_class_install_property (
+ g_object_class, PROP_MASTER,
+ g_param_spec_object ("master", _("Master"),
+ _("GdlDockMaster object which the layout object "
+ "is attached to"),
+ GDL_TYPE_DOCK_MASTER,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ g_object_class, PROP_DIRTY,
+ g_param_spec_boolean ("dirty", _("Dirty"),
+ _("True if the layouts have changed and need to be "
+ "saved to a file"),
+ FALSE,
+ G_PARAM_READABLE));
+}
+
+static void
+gdl_dock_layout_instance_init (GdlDockLayout *layout)
+{
+ layout->master = NULL;
+ layout->dirty = FALSE;
+ layout->_priv = g_new0 (GdlDockLayoutPrivate, 1);
+ layout->_priv->idle_save_pending = FALSE;
+
+ gdl_dock_layout_build_models (layout);
+}
+
+static void
+gdl_dock_layout_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdlDockLayout *layout = GDL_DOCK_LAYOUT (object);
+
+ switch (prop_id) {
+ case PROP_MASTER:
+ gdl_dock_layout_attach (layout, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ };
+}
+
+static void
+gdl_dock_layout_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdlDockLayout *layout = GDL_DOCK_LAYOUT (object);
+
+ switch (prop_id) {
+ case PROP_MASTER:
+ g_value_set_object (value, layout->master);
+ break;
+ case PROP_DIRTY:
+ g_value_set_boolean (value, layout->dirty);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ };
+}
+
+static void
+gdl_dock_layout_dispose (GObject *object)
+{
+ GdlDockLayout *layout;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDL_IS_DOCK_LAYOUT (object));
+
+ layout = GDL_DOCK_LAYOUT (object);
+
+ if (layout->master)
+ gdl_dock_layout_attach (layout, NULL);
+
+ if (layout->_priv) {
+ if (layout->_priv->idle_save_pending) {
+ layout->_priv->idle_save_pending = FALSE;
+ g_idle_remove_by_data (layout);
+ }
+
+ if (layout->_priv->doc) {
+ xmlFreeDoc (layout->_priv->doc);
+ layout->_priv->doc = NULL;
+ }
+
+ if (layout->_priv->items_model) {
+ g_object_unref (layout->_priv->items_model);
+ g_object_unref (layout->_priv->layouts_model);
+ layout->_priv->items_model = NULL;
+ layout->_priv->layouts_model = NULL;
+ }
+
+ xmlFreeDoc(layout->_priv->doc);
+ g_free (layout->_priv);
+ layout->_priv = NULL;
+ }
+}
+
+static void
+gdl_dock_layout_build_doc (GdlDockLayout *layout)
+{
+ g_return_if_fail (layout->_priv->doc == NULL);
+
+ layout->_priv->doc = xmlNewDoc (BAD_CAST "1.0");
+ layout->_priv->doc->children = xmlNewDocNode (layout->_priv->doc, NULL,
+ BAD_CAST ROOT_ELEMENT, NULL);
+}
+
+static xmlNodePtr
+gdl_dock_layout_find_layout (GdlDockLayout *layout,
+ const gchar *name)
+{
+ xmlNodePtr node;
+ gboolean found = FALSE;
+
+ g_return_val_if_fail (layout != NULL, NULL);
+
+ if (!layout->_priv->doc)
+ return NULL;
+
+ /* get document root */
+ node = layout->_priv->doc->children;
+ for (node = node->children; node; node = node->next) {
+ xmlChar *layout_name;
+
+ if (strcmp ((char*)node->name, LAYOUT_ELEMENT_NAME))
+ /* skip non-layout element */
+ continue;
+
+ /* we want the first layout */
+ if (!name)
+ break;
+
+ layout_name = xmlGetProp (node, BAD_CAST NAME_ATTRIBUTE_NAME);
+ if (!strcmp (name, (char*)layout_name))
+ found = TRUE;
+ xmlFree (layout_name);
+
+ if (found)
+ break;
+ };
+ return node;
+}
+
+static void
+gdl_dock_layout_build_models (GdlDockLayout *layout)
+{
+ if (!layout->_priv->items_model) {
+ layout->_priv->items_model = gtk_list_store_new (4,
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN,
+ G_TYPE_POINTER);
+ gtk_tree_sortable_set_sort_column_id (
+ GTK_TREE_SORTABLE (layout->_priv->items_model),
+ COLUMN_NAME, GTK_SORT_ASCENDING);
+ }
+
+ if (!layout->_priv->layouts_model) {
+ layout->_priv->layouts_model = gtk_list_store_new (2, G_TYPE_STRING,
+ G_TYPE_BOOLEAN);
+ gtk_tree_sortable_set_sort_column_id (
+ GTK_TREE_SORTABLE (layout->_priv->layouts_model),
+ COLUMN_NAME, GTK_SORT_ASCENDING);
+ }
+}
+
+static void
+build_list (GdlDockObject *object, GList **list)
+{
+ /* add only items, not toplevels */
+ if (GDL_IS_DOCK_ITEM (object))
+ *list = g_list_prepend (*list, object);
+}
+
+static void
+update_items_model (GdlDockLayout *layout)
+{
+ GList *items, *l;
+ GtkTreeIter iter;
+ GtkListStore *store;
+ gchar *long_name;
+ gboolean locked;
+
+ g_return_if_fail (layout != NULL);
+ g_return_if_fail (layout->_priv->items_model != NULL);
+
+ if (!layout->master)
+ return;
+
+ /* build items list */
+ items = NULL;
+ gdl_dock_master_foreach (layout->master, (GFunc) build_list, &items);
+
+ /* walk the current model */
+ store = layout->_priv->items_model;
+
+ /* update items model data after a layout load */
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
+ gboolean valid = TRUE;
+
+ while (valid) {
+ GdlDockItem *item;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+ COLUMN_ITEM, &item,
+ -1);
+ if (item) {
+ /* look for the object in the items list */
+ for (l = items; l && l->data != item; l = l->next);
+
+ if (l) {
+ /* found, update data */
+ g_object_get (item,
+ "long-name", &long_name,
+ "locked", &locked,
+ NULL);
+ gtk_list_store_set (store, &iter,
+ COLUMN_NAME, long_name,
+ COLUMN_SHOW, GDL_DOCK_OBJECT_ATTACHED (item),
+ COLUMN_LOCKED, locked,
+ -1);
+ g_free (long_name);
+
+ /* remove the item from the linked list and keep on walking the model */
+ items = g_list_delete_link (items, l);
+ valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
+
+ } else {
+ /* not found, which means the item has been removed */
+ valid = gtk_list_store_remove (store, &iter);
+
+ }
+
+ } else {
+ /* not a valid row */
+ valid = gtk_list_store_remove (store, &iter);
+ }
+ }
+ }
+
+ /* add any remaining objects */
+ for (l = items; l; l = l->next) {
+ GdlDockObject *object = l->data;
+
+ g_object_get (object,
+ "long-name", &long_name,
+ "locked", &locked,
+ NULL);
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COLUMN_ITEM, object,
+ COLUMN_NAME, long_name,
+ COLUMN_SHOW, GDL_DOCK_OBJECT_ATTACHED (object),
+ COLUMN_LOCKED, locked,
+ -1);
+ g_free (long_name);
+ }
+
+ g_list_free (items);
+}
+
+static void
+update_layouts_model (GdlDockLayout *layout)
+{
+ GList *items, *l;
+ GtkTreeIter iter;
+
+ g_return_if_fail (layout != NULL);
+ g_return_if_fail (layout->_priv->layouts_model != NULL);
+
+ /* build layouts list */
+ gtk_list_store_clear (layout->_priv->layouts_model);
+ items = gdl_dock_layout_get_layouts (layout, FALSE);
+ for (l = items; l; l = l->next) {
+ gtk_list_store_append (layout->_priv->layouts_model, &iter);
+ gtk_list_store_set (layout->_priv->layouts_model, &iter,
+ COLUMN_NAME, l->data, COLUMN_EDITABLE, TRUE,
+ -1);
+ g_free (l->data);
+ };
+ g_list_free (items);
+}
+
+
+/* ------- UI functions & callbacks ------ */
+
+static void
+load_layout_cb (GtkWidget *w,
+ gpointer data)
+{
+ GdlDockLayoutUIData *ui_data = (GdlDockLayoutUIData *) data;
+
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GdlDockLayout *layout = ui_data->layout;
+ gchar *name;
+
+ g_return_if_fail (layout != NULL);
+
+ if (gtk_tree_selection_get_selected (ui_data->selection, &model, &iter)) {
+ gtk_tree_model_get (model, &iter,
+ COLUMN_NAME, &name,
+ -1);
+ gdl_dock_layout_load_layout (layout, name);
+ g_free (name);
+ }
+}
+
+static void
+delete_layout_cb (GtkWidget *w, gpointer data)
+{
+ GdlDockLayoutUIData *ui_data = (GdlDockLayoutUIData *) data;
+
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GdlDockLayout *layout = ui_data->layout;
+ gchar *name;
+
+ g_return_if_fail (layout != NULL);
+
+ if (gtk_tree_selection_get_selected (ui_data->selection, &model, &iter)) {
+ gtk_tree_model_get (model, &iter,
+ COLUMN_NAME, &name,
+ -1);
+ gdl_dock_layout_delete_layout (layout, name);
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+ g_free (name);
+ };
+}
+
+static void
+show_toggled_cb (GtkCellRendererToggle *renderer,
+ gchar *path_str,
+ gpointer data)
+{
+ GdlDockLayoutUIData *ui_data = (GdlDockLayoutUIData *) data;
+
+ GdlDockLayout *layout = ui_data->layout;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
+ gboolean value;
+ GdlDockItem *item;
+
+ g_return_if_fail (layout != NULL);
+
+ model = GTK_TREE_MODEL (layout->_priv->items_model);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ COLUMN_SHOW, &value,
+ COLUMN_ITEM, &item,
+ -1);
+
+ value = !value;
+ if (value)
+ gdl_dock_item_show_item (item);
+ else
+ gdl_dock_item_hide_item (item);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+all_locked_toggled_cb (GtkWidget *widget,
+ gpointer data)
+{
+ GdlDockLayoutUIData *ui_data = (GdlDockLayoutUIData *) data;
+ GdlDockMaster *master;
+ gboolean locked;
+
+ g_return_if_fail (ui_data->layout != NULL);
+ master = ui_data->layout->master;
+ g_return_if_fail (master != NULL);
+
+ locked = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+ g_object_set (master, "locked", locked ? 1 : 0, NULL);
+}
+
+static void
+layout_ui_destroyed (GtkWidget *widget,
+ gpointer user_data)
+{
+ GdlDockLayoutUIData *ui_data;
+
+ /* widget is the GtkContainer */
+ ui_data = g_object_get_data (G_OBJECT (widget), "ui_data");
+ if (ui_data) {
+ if (ui_data->layout) {
+ if (ui_data->layout->master)
+ /* disconnet the notify handler */
+ g_signal_handlers_disconnect_matched (ui_data->layout->master,
+ G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL,
+ ui_data);
+
+ g_object_remove_weak_pointer (G_OBJECT (ui_data->layout),
+ (gpointer *) &ui_data->layout);
+ ui_data->layout = NULL;
+ }
+ g_object_set_data (G_OBJECT (widget), "ui_data", NULL);
+ g_free (ui_data);
+ }
+}
+
+static void
+master_locked_notify_cb (GdlDockMaster *master,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GdlDockLayoutUIData *ui_data = (GdlDockLayoutUIData *) user_data;
+ gint locked;
+
+ g_object_get (master, "locked", &locked, NULL);
+ if (locked == -1) {
+ gtk_toggle_button_set_inconsistent (
+ GTK_TOGGLE_BUTTON (ui_data->locked_check), TRUE);
+ }
+ else {
+ gtk_toggle_button_set_inconsistent (
+ GTK_TOGGLE_BUTTON (ui_data->locked_check), FALSE);
+ gtk_toggle_button_set_active (
+ GTK_TOGGLE_BUTTON (ui_data->locked_check), (locked == 1));
+ }
+}
+
+static GladeXML *
+load_interface (const gchar *top_widget)
+{
+ GladeXML *gui;
+ gchar *gui_file;
+
+ /* load ui */
+ gui_file = g_build_filename (GDL_GLADEDIR, LAYOUT_GLADE_FILE, NULL);
+ gui = glade_xml_new (gui_file, top_widget, GETTEXT_PACKAGE);
+ g_free (gui_file);
+ if (!gui) {
+ /* FIXME: pop up an error dialog */
+ g_warning (_("Could not load layout user interface file '%s'"),
+ LAYOUT_GLADE_FILE);
+ return NULL;
+ };
+ return gui;
+}
+
+static GtkWidget *
+gdl_dock_layout_construct_items_ui (GdlDockLayout *layout)
+{
+ GladeXML *gui;
+ GtkWidget *container;
+ GtkWidget *items_list;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+ GdlDockLayoutUIData *ui_data;
+
+ /* load the interface if it wasn't provided */
+ gui = load_interface ("items_vbox");
+
+ if (!gui)
+ return NULL;
+
+ /* get the container */
+ container = glade_xml_get_widget (gui, "items_vbox");
+
+ ui_data = g_new0 (GdlDockLayoutUIData, 1);
+ ui_data->layout = layout;
+ g_object_add_weak_pointer (G_OBJECT (layout),
+ (gpointer *) &ui_data->layout);
+ g_object_set_data (G_OBJECT (container), "ui_data", ui_data);
+
+ /* get ui widget references */
+ ui_data->locked_check = glade_xml_get_widget (gui, "locked_check");
+ items_list = glade_xml_get_widget (gui, "items_list");
+
+ /* locked check connections */
+ g_signal_connect (ui_data->locked_check, "toggled",
+ (GCallback) all_locked_toggled_cb, ui_data);
+ if (layout->master) {
+ g_signal_connect (layout->master, "notify::locked",
+ (GCallback) master_locked_notify_cb, ui_data);
+ /* force update now */
+ master_locked_notify_cb (layout->master, NULL, ui_data);
+ }
+
+ /* set models */
+ gtk_tree_view_set_model (GTK_TREE_VIEW (items_list),
+ GTK_TREE_MODEL (layout->_priv->items_model));
+
+ /* construct list views */
+ renderer = gtk_cell_renderer_toggle_new ();
+ g_signal_connect (renderer, "toggled",
+ G_CALLBACK (show_toggled_cb), ui_data);
+ column = gtk_tree_view_column_new_with_attributes (_("Visible"),
+ renderer,
+ "active", COLUMN_SHOW,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (items_list), column);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("Item"),
+ renderer,
+ "text", COLUMN_NAME,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (items_list), column);
+
+ /* connect signals */
+ g_signal_connect (container, "destroy", (GCallback) layout_ui_destroyed, NULL);
+
+ g_object_unref (gui);
+
+ return container;
+}
+
+static void
+cell_edited_cb (GtkCellRendererText *cell,
+ const gchar *path_string,
+ const gchar *new_text,
+ gpointer data)
+{
+ GdlDockLayoutUIData *ui_data = data;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gchar *name;
+ xmlNodePtr node;
+
+ model = GTK_TREE_MODEL (ui_data->layout->_priv->layouts_model);
+ path = gtk_tree_path_new_from_string (path_string);
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, COLUMN_NAME, &name, -1);
+
+ node = gdl_dock_layout_find_layout (ui_data->layout, name);
+ g_free (name);
+ g_return_if_fail (node != NULL);
+
+ xmlSetProp (node, BAD_CAST NAME_ATTRIBUTE_NAME, BAD_CAST new_text);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_NAME, new_text,
+ COLUMN_EDITABLE, TRUE, -1);
+
+ gdl_dock_layout_save_layout (ui_data->layout, new_text);
+
+ gtk_tree_path_free (path);
+}
+
+static GtkWidget *
+gdl_dock_layout_construct_layouts_ui (GdlDockLayout *layout)
+{
+ GladeXML *gui;
+ GtkWidget *container;
+ GtkWidget *layouts_list;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+ GdlDockLayoutUIData *ui_data;
+
+ /* load the interface if it wasn't provided */
+ gui = load_interface ("layouts_vbox");
+
+ if (!gui)
+ return NULL;
+
+ /* get the container */
+ container = glade_xml_get_widget (gui, "layouts_vbox");
+
+ ui_data = g_new0 (GdlDockLayoutUIData, 1);
+ ui_data->layout = layout;
+ g_object_add_weak_pointer (G_OBJECT (layout),
+ (gpointer *) &ui_data->layout);
+ g_object_set_data (G_OBJECT (container), "ui-data", ui_data);
+
+ /* get ui widget references */
+ layouts_list = glade_xml_get_widget (gui, "layouts_list");
+
+ /* set models */
+ gtk_tree_view_set_model (GTK_TREE_VIEW (layouts_list),
+ GTK_TREE_MODEL (layout->_priv->layouts_model));
+
+ /* construct list views */
+ renderer = gtk_cell_renderer_text_new ();
+ g_signal_connect (G_OBJECT (renderer), "edited",
+ G_CALLBACK (cell_edited_cb), ui_data);
+ column = gtk_tree_view_column_new_with_attributes (_("Name"), renderer,
+ "text", COLUMN_NAME,
+ "editable", COLUMN_EDITABLE,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (layouts_list), column);
+
+ ui_data->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (layouts_list));
+
+ /* connect signals */
+ glade_xml_signal_connect_data (gui, "on_load_button_clicked",
+ GTK_SIGNAL_FUNC (load_layout_cb), ui_data);
+ glade_xml_signal_connect_data (gui, "on_delete_button_clicked",
+ GTK_SIGNAL_FUNC (delete_layout_cb), ui_data);
+
+ g_signal_connect (container, "destroy", (GCallback) layout_ui_destroyed, NULL);
+
+ g_object_unref (gui);
+
+ return container;
+}
+
+static GtkWidget *
+gdl_dock_layout_construct_ui (GdlDockLayout *layout)
+{
+ GtkWidget *container, *child;
+
+ container = gtk_notebook_new ();
+ gtk_widget_show (container);
+
+ child = gdl_dock_layout_construct_items_ui (layout);
+ if (child)
+ gtk_notebook_append_page (GTK_NOTEBOOK (container),
+ child,
+ gtk_label_new (_("Dock items")));
+
+ child = gdl_dock_layout_construct_layouts_ui (layout);
+ if (child)
+ gtk_notebook_append_page (GTK_NOTEBOOK (container),
+ child,
+ gtk_label_new (_("Saved layouts")));
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (container), 0);
+
+ return container;
+}
+
+/* ----- Save & Load layout functions --------- */
+
+#define GDL_DOCK_PARAM_CONSTRUCTION(p) \
+ (((p)->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) != 0)
+
+static GdlDockObject *
+gdl_dock_layout_setup_object (GdlDockMaster *master,
+ xmlNodePtr node,
+ gint *n_after_params,
+ GParameter **after_params)
+{
+ GdlDockObject *object = NULL;
+ GType object_type;
+ xmlChar *object_name;
+ GObjectClass *object_class = NULL;
+
+ GParamSpec **props;
+ guint n_props, i;
+ GParameter *params = NULL;
+ gint n_params = 0;
+ GValue serialized = { 0, };
+
+ object_name = xmlGetProp (node, BAD_CAST GDL_DOCK_NAME_PROPERTY);
+ if (object_name && strlen ((char*)object_name) > 0) {
+ /* the object must already be bound to the master */
+ object = gdl_dock_master_get_object (master, (char*)object_name);
+
+ xmlFree (object_name);
+ object_type = object ? G_TYPE_FROM_INSTANCE (object) : G_TYPE_NONE;
+ }
+ else {
+ /* the object should be automatic, so create it by
+ retrieving the object type from the dock registry */
+ object_type = gdl_dock_object_type_from_nick ((char*)node->name);
+ if (object_type == G_TYPE_NONE) {
+ g_warning (_("While loading layout: don't know how to create "
+ "a dock object whose nick is '%s'"), node->name);
+ }
+ }
+
+ if (object_type == G_TYPE_NONE || !G_TYPE_IS_CLASSED (object_type))
+ return NULL;
+
+ object_class = g_type_class_ref (object_type);
+ props = g_object_class_list_properties (object_class, &n_props);
+
+ /* create parameter slots */
+ /* extra parameter is the master */
+ params = g_new0 (GParameter, n_props + 1);
+ *after_params = g_new0 (GParameter, n_props);
+ *n_after_params = 0;
+
+ /* initialize value used for transformations */
+ g_value_init (&serialized, GDL_TYPE_DOCK_PARAM);
+
+ for (i = 0; i < n_props; i++) {
+ xmlChar *xml_prop;
+
+ /* process all exported properties, skip
+ GDL_DOCK_NAME_PROPERTY, since named items should
+ already by in the master */
+ if (!(props [i]->flags & GDL_DOCK_PARAM_EXPORT) ||
+ !strcmp (props [i]->name, GDL_DOCK_NAME_PROPERTY))
+ continue;
+
+ /* get the property from xml if there is one */
+ xml_prop = xmlGetProp (node, BAD_CAST props [i]->name);
+ if (xml_prop) {
+ g_value_set_static_string (&serialized, (char*)xml_prop);
+
+ if (!GDL_DOCK_PARAM_CONSTRUCTION (props [i]) &&
+ (props [i]->flags & GDL_DOCK_PARAM_AFTER)) {
+ (*after_params) [*n_after_params].name = props [i]->name;
+ g_value_init (&((* after_params) [*n_after_params].value),
+ props [i]->value_type);
+ g_value_transform (&serialized,
+ &((* after_params) [*n_after_params].value));
+ (*n_after_params)++;
+ }
+ else if (!object || (!GDL_DOCK_PARAM_CONSTRUCTION (props [i]) && object)) {
+ params [n_params].name = props [i]->name;
+ g_value_init (&(params [n_params].value), props [i]->value_type);
+ g_value_transform (&serialized, &(params [n_params].value));
+ n_params++;
+ }
+ xmlFree (xml_prop);
+ }
+ }
+ g_value_unset (&serialized);
+ g_free (props);
+
+ if (!object) {
+ params [n_params].name = GDL_DOCK_MASTER_PROPERTY;
+ g_value_init (&params [n_params].value, GDL_TYPE_DOCK_MASTER);
+ g_value_set_object (&params [n_params].value, master);
+ n_params++;
+
+ /* construct the object if we have to */
+ /* set the master, so toplevels are created correctly and
+ other objects are bound */
+ object = g_object_newv (object_type, n_params, params);
+ }
+ else {
+ /* set the parameters to the existing object */
+ for (i = 0; i < n_params; i++)
+ g_object_set_property (G_OBJECT (object),
+ params [i].name,
+ &params [i].value);
+ }
+
+ /* free the parameters (names are static/const strings) */
+ for (i = 0; i < n_params; i++)
+ g_value_unset (&params [i].value);
+ g_free (params);
+
+ /* finally unref object class */
+ g_type_class_unref (object_class);
+
+ return object;
+}
+
+static void
+gdl_dock_layout_recursive_build (GdlDockMaster *master,
+ xmlNodePtr parent_node,
+ GdlDockObject *parent)
+{
+ GdlDockObject *object;
+ xmlNodePtr node;
+
+ g_return_if_fail (master != NULL && parent_node != NULL);
+
+ /* if parent is NULL we should build toplevels */
+ for (node = parent_node->children; node; node = node->next) {
+ GParameter *after_params = NULL;
+ gint n_after_params = 0, i;
+
+ object = gdl_dock_layout_setup_object (master, node,
+ &n_after_params,
+ &after_params);
+
+ if (object) {
+ gdl_dock_object_freeze (object);
+
+ /* recurse here to catch placeholders */
+ gdl_dock_layout_recursive_build (master, node, object);
+
+ if (GDL_IS_DOCK_PLACEHOLDER (object))
+ /* placeholders are later attached to the parent */
+ gdl_dock_object_detach (object, FALSE);
+
+ /* apply "after" parameters */
+ for (i = 0; i < n_after_params; i++) {
+ g_object_set_property (G_OBJECT (object),
+ after_params [i].name,
+ &after_params [i].value);
+ /* unset and free the value */
+ g_value_unset (&after_params [i].value);
+ }
+ g_free (after_params);
+
+ /* add the object to the parent */
+ if (parent) {
+ if (GDL_IS_DOCK_PLACEHOLDER (object))
+ gdl_dock_placeholder_attach (GDL_DOCK_PLACEHOLDER (object),
+ parent);
+ else if (gdl_dock_object_is_compound (parent)) {
+ gtk_container_add (GTK_CONTAINER (parent), GTK_WIDGET (object));
+ if (GTK_WIDGET_VISIBLE (parent))
+ gtk_widget_show (GTK_WIDGET (object));
+ }
+ }
+ else {
+ GdlDockObject *controller = gdl_dock_master_get_controller (master);
+ if (controller != object && GTK_WIDGET_VISIBLE (controller))
+ gtk_widget_show (GTK_WIDGET (object));
+ }
+
+ /* call reduce just in case any child is missing */
+ if (gdl_dock_object_is_compound (object))
+ gdl_dock_object_reduce (object);
+
+ gdl_dock_object_thaw (object);
+ }
+ }
+}
+
+static void
+_gdl_dock_layout_foreach_detach (GdlDockObject *object)
+{
+ gdl_dock_object_detach (object, TRUE);
+}
+
+static void
+gdl_dock_layout_foreach_toplevel_detach (GdlDockObject *object)
+{
+ gtk_container_foreach (GTK_CONTAINER (object),
+ (GtkCallback) _gdl_dock_layout_foreach_detach,
+ NULL);
+}
+
+static void
+gdl_dock_layout_load (GdlDockMaster *master, xmlNodePtr node)
+{
+ g_return_if_fail (master != NULL && node != NULL);
+
+ /* start by detaching all items from the toplevels */
+ gdl_dock_master_foreach_toplevel (master, TRUE,
+ (GFunc) gdl_dock_layout_foreach_toplevel_detach,
+ NULL);
+
+ gdl_dock_layout_recursive_build (master, node, NULL);
+}
+
+static void
+gdl_dock_layout_foreach_object_save (GdlDockObject *object,
+ gpointer user_data)
+{
+ struct {
+ xmlNodePtr where;
+ GHashTable *placeholders;
+ } *info = user_data, info_child;
+
+ xmlNodePtr node;
+ guint n_props, i;
+ GParamSpec **props;
+ GValue attr = { 0, };
+
+ g_return_if_fail (object != NULL && GDL_IS_DOCK_OBJECT (object));
+ g_return_if_fail (info->where != NULL);
+
+ node = xmlNewChild (info->where,
+ NULL, /* ns */
+ BAD_CAST gdl_dock_object_nick_from_type (G_TYPE_FROM_INSTANCE (object)),
+ BAD_CAST NULL); /* contents */
+
+ /* get object exported attributes */
+ props = g_object_class_list_properties (G_OBJECT_GET_CLASS (object),
+ &n_props);
+ g_value_init (&attr, GDL_TYPE_DOCK_PARAM);
+ for (i = 0; i < n_props; i++) {
+ GParamSpec *p = props [i];
+
+ if (p->flags & GDL_DOCK_PARAM_EXPORT) {
+ GValue v = { 0, };
+
+ /* export this parameter */
+ /* get the parameter value */
+ g_value_init (&v, p->value_type);
+ g_object_get_property (G_OBJECT (object),
+ p->name,
+ &v);
+
+ /* only save the object "name" if it is set
+ (i.e. don't save the empty string) */
+ if (strcmp (p->name, GDL_DOCK_NAME_PROPERTY) ||
+ g_value_get_string (&v)) {
+ if (g_value_transform (&v, &attr))
+ xmlSetProp (node, BAD_CAST p->name, BAD_CAST g_value_get_string (&attr));
+ }
+
+ /* free the parameter value */
+ g_value_unset (&v);
+ }
+ }
+ g_value_unset (&attr);
+ g_free (props);
+
+ info_child = *info;
+ info_child.where = node;
+
+ /* save placeholders for the object */
+ if (info->placeholders && !GDL_IS_DOCK_PLACEHOLDER (object)) {
+ GList *lph = g_hash_table_lookup (info->placeholders, object);
+ for (; lph; lph = lph->next)
+ gdl_dock_layout_foreach_object_save (GDL_DOCK_OBJECT (lph->data),
+ (gpointer) &info_child);
+ }
+
+ /* recurse the object if appropiate */
+ if (gdl_dock_object_is_compound (object)) {
+ gtk_container_foreach (GTK_CONTAINER (object),
+ (GtkCallback) gdl_dock_layout_foreach_object_save,
+ (gpointer) &info_child);
+ }
+}
+
+static void
+add_placeholder (GdlDockObject *object,
+ GHashTable *placeholders)
+{
+ if (GDL_IS_DOCK_PLACEHOLDER (object)) {
+ GdlDockObject *host;
+ GList *l;
+
+ g_object_get (object, "host", &host, NULL);
+ if (host) {
+ l = g_hash_table_lookup (placeholders, host);
+ /* add the current placeholder to the list of placeholders
+ for that host */
+ if (l)
+ g_hash_table_steal (placeholders, host);
+
+ l = g_list_prepend (l, object);
+ g_hash_table_insert (placeholders, host, l);
+ g_object_unref (host);
+ }
+ }
+}
+
+static void
+gdl_dock_layout_save (GdlDockMaster *master,
+ xmlNodePtr where)
+{
+ struct {
+ xmlNodePtr where;
+ GHashTable *placeholders;
+ } info;
+
+ GHashTable *placeholders;
+
+ g_return_if_fail (master != NULL && where != NULL);
+
+ /* build the placeholder's hash: the hash keeps lists of
+ * placeholders associated to each object, so that we can save the
+ * placeholders when we are saving the object (since placeholders
+ * don't show up in the normal widget hierarchy) */
+ placeholders = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) g_list_free);
+ gdl_dock_master_foreach (master, (GFunc) add_placeholder, placeholders);
+
+ /* save the layout recursively */
+ info.where = where;
+ info.placeholders = placeholders;
+
+ gdl_dock_master_foreach_toplevel (master, TRUE,
+ (GFunc) gdl_dock_layout_foreach_object_save,
+ (gpointer) &info);
+
+ g_hash_table_destroy (placeholders);
+}
+
+
+/* ----- Public interface ----- */
+
+GdlDockLayout *
+gdl_dock_layout_new (GdlDock *dock)
+{
+ GdlDockMaster *master = NULL;
+
+ /* get the master of the given dock */
+ if (dock)
+ master = GDL_DOCK_OBJECT_GET_MASTER (dock);
+
+ return g_object_new (GDL_TYPE_DOCK_LAYOUT,
+ "master", master,
+ NULL);
+}
+
+static gboolean
+gdl_dock_layout_idle_save (GdlDockLayout *layout)
+{
+ /* save default layout */
+ gdl_dock_layout_save_layout (layout, NULL);
+
+ layout->_priv->idle_save_pending = FALSE;
+
+ return FALSE;
+}
+
+static void
+gdl_dock_layout_layout_changed_cb (GdlDockMaster *master,
+ GdlDockLayout *layout)
+{
+ /* update model */
+ update_items_model (layout);
+
+ if (!layout->_priv->idle_save_pending) {
+ g_idle_add ((GSourceFunc) gdl_dock_layout_idle_save, layout);
+ layout->_priv->idle_save_pending = TRUE;
+ }
+}
+
+void
+gdl_dock_layout_attach (GdlDockLayout *layout,
+ GdlDockMaster *master)
+{
+ g_return_if_fail (layout != NULL);
+ g_return_if_fail (master == NULL || GDL_IS_DOCK_MASTER (master));
+
+ if (layout->master) {
+ g_signal_handlers_disconnect_matched (layout->master, G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, layout);
+ g_object_unref (layout->master);
+ }
+
+ gtk_list_store_clear (layout->_priv->items_model);
+
+ layout->master = master;
+ if (layout->master) {
+ g_object_ref (layout->master);
+ g_signal_connect (layout->master, "layout-changed",
+ (GCallback) gdl_dock_layout_layout_changed_cb,
+ layout);
+ }
+
+ update_items_model (layout);
+}
+
+gboolean
+gdl_dock_layout_load_layout (GdlDockLayout *layout,
+ const gchar *name)
+{
+ xmlNodePtr node;
+ gchar *layout_name;
+
+ g_return_val_if_fail (layout != NULL, FALSE);
+
+ if (!layout->_priv->doc || !layout->master)
+ return FALSE;
+
+ if (!name)
+ layout_name = DEFAULT_LAYOUT;
+ else
+ layout_name = (gchar *) name;
+
+ node = gdl_dock_layout_find_layout (layout, layout_name);
+ if (!node && !name)
+ /* return the first layout if the default name failed to load */
+ node = gdl_dock_layout_find_layout (layout, NULL);
+
+ if (node) {
+ gdl_dock_layout_load (layout->master, node);
+ return TRUE;
+ } else
+ return FALSE;
+}
+
+void
+gdl_dock_layout_save_layout (GdlDockLayout *layout,
+ const gchar *name)
+{
+ xmlNodePtr node;
+ gchar *layout_name;
+
+ g_return_if_fail (layout != NULL);
+ g_return_if_fail (layout->master != NULL);
+
+ if (!layout->_priv->doc)
+ gdl_dock_layout_build_doc (layout);
+
+ if (!name)
+ layout_name = DEFAULT_LAYOUT;
+ else
+ layout_name = (gchar *) name;
+
+ /* delete any previously node with the same name */
+ node = gdl_dock_layout_find_layout (layout, layout_name);
+ if (node) {
+ xmlUnlinkNode (node);
+ xmlFreeNode (node);
+ };
+
+ /* create the new node */
+ node = xmlNewChild (layout->_priv->doc->children, NULL,
+ BAD_CAST LAYOUT_ELEMENT_NAME, NULL);
+ xmlSetProp (node, BAD_CAST NAME_ATTRIBUTE_NAME, BAD_CAST layout_name);
+
+ /* save the layout */
+ gdl_dock_layout_save (layout->master, node);
+ layout->dirty = TRUE;
+ g_object_notify (G_OBJECT (layout), "dirty");
+}
+
+void
+gdl_dock_layout_delete_layout (GdlDockLayout *layout,
+ const gchar *name)
+{
+ xmlNodePtr node;
+
+ g_return_if_fail (layout != NULL);
+
+ /* don't allow the deletion of the default layout */
+ if (!name || !strcmp (DEFAULT_LAYOUT, name))
+ return;
+
+ node = gdl_dock_layout_find_layout (layout, name);
+ if (node) {
+ xmlUnlinkNode (node);
+ xmlFreeNode (node);
+ layout->dirty = TRUE;
+ g_object_notify (G_OBJECT (layout), "dirty");
+ }
+}
+
+void
+gdl_dock_layout_run_manager (GdlDockLayout *layout)
+{
+ GtkWidget *dialog, *container;
+ GtkWidget *parent = NULL;
+
+ g_return_if_fail (layout != NULL);
+
+ if (!layout->master)
+ /* not attached to a dock yet */
+ return;
+
+ container = gdl_dock_layout_construct_ui (layout);
+ if (!container)
+ return;
+
+ parent = GTK_WIDGET (gdl_dock_master_get_controller (layout->master));
+ if (parent)
+ parent = gtk_widget_get_toplevel (parent);
+
+ dialog = gtk_dialog_new_with_buttons (_("Layout managment"),
+ parent ? GTK_WINDOW (parent) : NULL,
+ GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR,
+ GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+ NULL);
+
+ gtk_window_set_default_size (GTK_WINDOW (dialog), -1, 300);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), container);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+
+ gtk_widget_destroy (dialog);
+}
+
+gboolean
+gdl_dock_layout_load_from_file (GdlDockLayout *layout,
+ const gchar *filename)
+{
+ gboolean retval = FALSE;
+
+ if (layout->_priv->doc) {
+ xmlFreeDoc (layout->_priv->doc);
+ layout->_priv->doc = NULL;
+ layout->dirty = FALSE;
+ g_object_notify (G_OBJECT (layout), "dirty");
+ }
+
+ /* FIXME: cannot open symlinks */
+ if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
+ layout->_priv->doc = xmlParseFile (filename);
+ if (layout->_priv->doc) {
+ xmlNodePtr root = layout->_priv->doc->children;
+ /* minimum validation: test the root element */
+ if (root && !strcmp ((char*)root->name, ROOT_ELEMENT)) {
+ update_layouts_model (layout);
+ retval = TRUE;
+ } else {
+ xmlFreeDoc (layout->_priv->doc);
+ layout->_priv->doc = NULL;
+ }
+ }
+ }
+
+ return retval;
+}
+
+gboolean
+gdl_dock_layout_save_to_file (GdlDockLayout *layout,
+ const gchar *filename)
+{
+ FILE *file_handle;
+ int bytes;
+ gboolean retval = FALSE;
+
+ g_return_val_if_fail (layout != NULL, FALSE);
+ g_return_val_if_fail (filename != NULL, FALSE);
+
+ /* if there is still no xml doc, create an empty one */
+ if (!layout->_priv->doc)
+ gdl_dock_layout_build_doc (layout);
+
+ file_handle = fopen (filename, "w");
+ if (file_handle) {
+ bytes = xmlDocDump (file_handle, layout->_priv->doc);
+ if (bytes >= 0) {
+ layout->dirty = FALSE;
+ g_object_notify (G_OBJECT (layout), "dirty");
+ retval = TRUE;
+ };
+ fclose (file_handle);
+ };
+
+ return retval;
+}
+
+gboolean
+gdl_dock_layout_is_dirty (GdlDockLayout *layout)
+{
+ g_return_val_if_fail (layout != NULL, FALSE);
+
+ return layout->dirty;
+};
+
+GList *
+gdl_dock_layout_get_layouts (GdlDockLayout *layout,
+ gboolean include_default)
+{
+ GList *retval = NULL;
+ xmlNodePtr node;
+
+ g_return_val_if_fail (layout != NULL, NULL);
+
+ if (!layout->_priv->doc)
+ return NULL;
+
+ node = layout->_priv->doc->children;
+ for (node = node->children; node; node = node->next) {
+ xmlChar *name;
+
+ if (strcmp ((char*)node->name, LAYOUT_ELEMENT_NAME))
+ continue;
+
+ name = xmlGetProp (node, BAD_CAST NAME_ATTRIBUTE_NAME);
+ if (include_default || strcmp ((char*)name, DEFAULT_LAYOUT))
+ retval = g_list_prepend (retval, g_strdup ((char*)name));
+ xmlFree (name);
+ };
+ retval = g_list_reverse (retval);
+
+ return retval;
+}
+
+GtkWidget *
+gdl_dock_layout_get_ui (GdlDockLayout *layout)
+{
+ GtkWidget *ui;
+
+ g_return_val_if_fail (layout != NULL, NULL);
+ ui = gdl_dock_layout_construct_ui (layout);
+
+ return ui;
+}
+
+GtkWidget *
+gdl_dock_layout_get_items_ui (GdlDockLayout *layout)
+{
+ GtkWidget *ui;
+
+ g_return_val_if_fail (layout != NULL, NULL);
+ ui = gdl_dock_layout_construct_items_ui (layout);
+
+ return ui;
+}
+
+GtkWidget *
+gdl_dock_layout_get_layouts_ui (GdlDockLayout *layout)
+{
+ GtkWidget *ui;
+
+ g_return_val_if_fail (layout != NULL, NULL);
+ ui = gdl_dock_layout_construct_layouts_ui (layout);
+
+ return ui;
+}
diff --git a/src/libgdl/gdl-dock-layout.h b/src/libgdl/gdl-dock-layout.h
new file mode 100644
index 000000000..2ce5d13b3
--- /dev/null
+++ b/src/libgdl/gdl-dock-layout.h
@@ -0,0 +1,98 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This file is part of the GNOME Devtools Libraries.
+ *
+ * Copyright (C) 2002 Gustavo Giráldez <gustavo.giraldez@gmx.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#ifndef __GDL_DOCK_LAYOUT_H__
+#define __GDL_DOCK_LAYOUT_H__
+
+#include <glib-object.h>
+#include "libgdl/gdl-dock-master.h"
+#include "libgdl/gdl-dock.h"
+
+G_BEGIN_DECLS
+
+/* standard macros */
+#define GDL_TYPE_DOCK_LAYOUT (gdl_dock_layout_get_type ())
+#define GDL_DOCK_LAYOUT(object) (GTK_CHECK_CAST ((object), GDL_TYPE_DOCK_LAYOUT, GdlDockLayout))
+#define GDL_DOCK_LAYOUT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GDL_TYPE_DOCK_LAYOUT, GdlDockLayoutClass))
+#define GDL_IS_DOCK_LAYOUT(object) (GTK_CHECK_TYPE ((object), GDL_TYPE_DOCK_LAYOUT))
+#define GDL_IS_DOCK_LAYOUT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GDL_TYPE_DOCK_LAYOUT))
+#define GDL_DOCK_LAYOUT_GET_CLASS(object) (GTK_CHECK_GET_CLASS ((object), GDL_TYPE_DOCK_LAYOUT, GdlDockLayoutClass))
+
+/* data types & structures */
+typedef struct _GdlDockLayout GdlDockLayout;
+typedef struct _GdlDockLayoutClass GdlDockLayoutClass;
+typedef struct _GdlDockLayoutPrivate GdlDockLayoutPrivate;
+
+struct _GdlDockLayout {
+ GObject g_object;
+
+ gboolean dirty;
+ GdlDockMaster *master;
+
+ GdlDockLayoutPrivate *_priv;
+};
+
+struct _GdlDockLayoutClass {
+ GObjectClass g_object_class;
+};
+
+
+/* public interface */
+
+GType gdl_dock_layout_get_type (void);
+
+GdlDockLayout *gdl_dock_layout_new (GdlDock *dock);
+
+void gdl_dock_layout_attach (GdlDockLayout *layout,
+ GdlDockMaster *master);
+
+gboolean gdl_dock_layout_load_layout (GdlDockLayout *layout,
+ const gchar *name);
+
+void gdl_dock_layout_save_layout (GdlDockLayout *layout,
+ const gchar *name);
+
+void gdl_dock_layout_delete_layout (GdlDockLayout *layout,
+ const gchar *name);
+
+GList *gdl_dock_layout_get_layouts (GdlDockLayout *layout,
+ gboolean include_default);
+
+void gdl_dock_layout_run_manager (GdlDockLayout *layout);
+
+gboolean gdl_dock_layout_load_from_file (GdlDockLayout *layout,
+ const gchar *filename);
+
+gboolean gdl_dock_layout_save_to_file (GdlDockLayout *layout,
+ const gchar *filename);
+
+gboolean gdl_dock_layout_is_dirty (GdlDockLayout *layout);
+
+GtkWidget *gdl_dock_layout_get_ui (GdlDockLayout *layout);
+GtkWidget *gdl_dock_layout_get_items_ui (GdlDockLayout *layout);
+GtkWidget *gdl_dock_layout_get_layouts_ui (GdlDockLayout *layout);
+
+G_END_DECLS
+
+#endif
+
+
diff --git a/src/libgdl/gdl-dock-object.c b/src/libgdl/gdl-dock-object.c
index 9bdcd18ed..129cc28d9 100644
--- a/src/libgdl/gdl-dock-object.c
+++ b/src/libgdl/gdl-dock-object.c
@@ -396,6 +396,7 @@ gdl_dock_object_real_reduce (GdlDockObject *object)
children = gtk_container_get_children (GTK_CONTAINER (object));
if (g_list_length (children) <= 1) {
GList *l;
+ GList *dchildren = NULL;
/* detach ourselves and then re-attach our children to our
current parent. if we are not currently attached, the
@@ -403,18 +404,41 @@ gdl_dock_object_real_reduce (GdlDockObject *object)
if (parent)
gdl_dock_object_freeze (parent);
gdl_dock_object_freeze (object);
- gdl_dock_object_detach (object, FALSE);
+ /* Detach the children before detaching this object, since in this
+ * way the children can have access to the whole object hierarchy.
+ * Set the InDetach flag now, so the children know that this object
+ * is going to be detached. */
+
+
+ GDL_DOCK_OBJECT_SET_FLAGS (object, GDL_DOCK_IN_DETACH);
+
for (l = children; l; l = l->next) {
- GdlDockObject *child = GDL_DOCK_OBJECT (l->data);
+ GdlDockObject *child;
+
+ if (!GDL_IS_DOCK_OBJECT (l->data))
+ continue;
+
+ child = GDL_DOCK_OBJECT (l->data);
g_object_ref (child);
- GDL_DOCK_OBJECT_SET_FLAGS (child, GDL_DOCK_IN_REFLOW);
gdl_dock_object_detach (child, FALSE);
+ GDL_DOCK_OBJECT_SET_FLAGS (child, GDL_DOCK_IN_REFLOW);
if (parent)
- gtk_container_add (GTK_CONTAINER (parent), GTK_WIDGET (child));
+ dchildren = g_list_append (dchildren, child);
GDL_DOCK_OBJECT_UNSET_FLAGS (child, GDL_DOCK_IN_REFLOW);
- g_object_unref (child);
}
+ /* Now it can be detached */
+ gdl_dock_object_detach (object, FALSE);
+
+ /* After detaching the reduced object, we can add the
+ children (the only child in fact) to the new parent */
+ for (l = dchildren; l; l = l->next) {
+ gtk_container_add (GTK_CONTAINER (parent), l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free (dchildren);
+
+
/* sink the widget, so any automatic floating widget is destroyed */
g_object_ref_sink (object);
/* don't reenter */
@@ -469,6 +493,9 @@ gdl_dock_object_detach (GdlDockObject *object,
{
g_return_if_fail (object != NULL);
+ if (!GDL_IS_DOCK_OBJECT (object))
+ return;
+
if (!GDL_DOCK_OBJECT_ATTACHED (object))
return;
diff --git a/src/libgdl/gdl-dock-placeholder.c b/src/libgdl/gdl-dock-placeholder.c
index ca7763a55..33934e2e0 100644
--- a/src/libgdl/gdl-dock-placeholder.c
+++ b/src/libgdl/gdl-dock-placeholder.c
@@ -189,14 +189,14 @@ gdl_dock_placeholder_class_init (GdlDockPlaceholderClass *klass)
g_object_class_install_property (
g_object_class, PROP_FLOAT_X,
g_param_spec_int ("floatx", _("X-Coordinate"),
- _("X coordinate for dock when floating"),
+ _("X-Coordinate for dock when floating"),
-1, G_MAXINT, -1,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
GDL_DOCK_PARAM_EXPORT));
g_object_class_install_property (
g_object_class, PROP_FLOAT_Y,
g_param_spec_int ("floaty", _("Y-Coordinate"),
- _("Y coordinate for dock when floating"),
+ _("Y-Coordinate for dock when floating"),
-1, G_MAXINT, -1,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
GDL_DOCK_PARAM_EXPORT));
diff --git a/src/libgdl/gdl-icons.c b/src/libgdl/gdl-icons.c
new file mode 100644
index 000000000..2af2a8a9a
--- /dev/null
+++ b/src/libgdl/gdl-icons.c
@@ -0,0 +1,267 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gdl-icons.c
+ *
+ * Copyright (C) 2000-2001 Dave Camp
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Dave Camp, Jeroen Zwartepoorte
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gdl-i18n.h"
+#include "gdl-tools.h"
+#include <string.h>
+#include <libgnomeui/gnome-icon-lookup.h>
+#include <libgnomevfs/gnome-vfs-ops.h>
+#include "gdl-icons.h"
+
+enum {
+ PROP_BOGUS,
+ PROP_ICON_SIZE,
+};
+
+#define GDL_ICONS_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GDL_TYPE_ICONS, GdlIconsPrivate))
+
+typedef struct _GdlIconsPrivate GdlIconsPrivate;
+
+struct _GdlIconsPrivate {
+ int icon_size;
+
+ GtkIconTheme *icon_theme;
+ GHashTable *icons;
+};
+
+GDL_CLASS_BOILERPLATE (GdlIcons, gdl_icons, GObject, G_TYPE_OBJECT);
+
+static void
+gdl_icons_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdlIconsPrivate *priv = GDL_ICONS_GET_PRIVATE (object);
+
+ switch (prop_id) {
+ case PROP_ICON_SIZE:
+ g_value_set_int (value, priv->icon_size);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdl_icons_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdlIconsPrivate *priv = GDL_ICONS_GET_PRIVATE (object);
+
+ switch (prop_id) {
+ case PROP_ICON_SIZE:
+ priv->icon_size = g_value_get_int (value);
+ g_hash_table_destroy (priv->icons);
+ priv->icons = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) gdk_pixbuf_unref);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+theme_changed_cb (GtkIconTheme *theme,
+ gpointer user_data)
+{
+ GdlIconsPrivate *priv = GDL_ICONS_GET_PRIVATE (user_data);
+
+ g_hash_table_destroy (priv->icons);
+ priv->icons = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) gdk_pixbuf_unref);
+}
+
+static void
+gdl_icons_dispose (GObject *object)
+{
+ GdlIconsPrivate *priv = GDL_ICONS_GET_PRIVATE (object);
+
+ if (priv->icon_theme) {
+ /* Don't do that - look a GTK+ docs */
+ /* g_object_unref (priv->icon_theme); */
+ priv->icon_theme = NULL;
+ }
+
+ if (priv->icons) {
+ g_hash_table_destroy (priv->icons);
+ priv->icons = NULL;
+ }
+}
+
+static void
+gdl_icons_class_init (GdlIconsClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->dispose = gdl_icons_dispose;
+ object_class->get_property = gdl_icons_get_property;
+ object_class->set_property = gdl_icons_set_property;
+
+ g_object_class_install_property (object_class, PROP_ICON_SIZE,
+ g_param_spec_int ("icon-size",
+ _("Icon size"),
+ _("Icon size"),
+ 12, 256, 24,
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private (object_class, sizeof (GdlIconsPrivate));
+}
+
+static void
+gdl_icons_instance_init (GdlIcons *icons)
+{
+ GdlIconsPrivate *priv = GDL_ICONS_GET_PRIVATE (icons);
+
+ priv->icon_theme = gtk_icon_theme_get_default ();
+ /* gtk_icon_theme_get_default() does not ref the returned object */
+ /* but API docs state the you should NOT ref it */
+ /* g_object_ref (priv->icon_theme);*/
+ g_signal_connect_object (G_OBJECT (priv->icon_theme), "changed",
+ G_CALLBACK (theme_changed_cb), icons, 0);
+ priv->icons = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) gdk_pixbuf_unref);
+}
+
+GdlIcons *
+gdl_icons_new (int icon_size)
+{
+ return GDL_ICONS (g_object_new (GDL_TYPE_ICONS,
+ "icon-size", icon_size,
+ NULL));
+}
+
+GdkPixbuf *
+gdl_icons_get_folder_icon (GdlIcons *icons)
+{
+ g_return_val_if_fail (icons != NULL, NULL);
+ g_return_val_if_fail (GDL_IS_ICONS (icons), NULL);
+
+ return gdl_icons_get_mime_icon (icons, "application/directory-normal");
+}
+
+GdkPixbuf *
+gdl_icons_get_uri_icon (GdlIcons *icons,
+ const char *uri)
+{
+ GnomeVFSFileInfo *info;
+ GdkPixbuf *pixbuf;
+
+ g_return_val_if_fail (icons != NULL, NULL);
+ g_return_val_if_fail (GDL_IS_ICONS (icons), NULL);
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ info = gnome_vfs_file_info_new ();
+ gnome_vfs_get_file_info (uri, info,
+ GNOME_VFS_FILE_INFO_FOLLOW_LINKS |
+ GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
+ GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE);
+ if (info->mime_type)
+ pixbuf = gdl_icons_get_mime_icon (icons, info->mime_type);
+ else
+ pixbuf = gdl_icons_get_mime_icon (icons, "gnome-fs-regular");
+ gnome_vfs_file_info_unref (info);
+
+ return pixbuf;
+}
+
+GdkPixbuf *
+gdl_icons_get_mime_icon (GdlIcons *icons,
+ const char *mime_type)
+{
+ GdkPixbuf *pixbuf;
+ char *icon_name;
+
+ g_return_val_if_fail (icons != NULL, NULL);
+ g_return_val_if_fail (GDL_IS_ICONS (icons), NULL);
+ g_return_val_if_fail (mime_type != NULL, NULL);
+
+ GdlIconsPrivate *priv = GDL_ICONS_GET_PRIVATE (icons);
+
+ pixbuf = g_hash_table_lookup (priv->icons, mime_type);
+ if (pixbuf != NULL) {
+ g_object_ref (G_OBJECT (pixbuf));
+ return pixbuf;
+ }
+
+ if (!strcmp (mime_type, "application/directory-normal")) {
+ icon_name = g_strdup ("gnome-fs-directory");
+ } else {
+ icon_name = gnome_icon_lookup (priv->icon_theme,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ mime_type,
+ GNOME_ICON_LOOKUP_FLAGS_NONE,
+ NULL);
+ }
+
+ if (!icon_name) {
+ /* Return regular icon if one doesn't exist for mime type. */
+ if (!strcmp (mime_type, "gnome-fs-regular"))
+ return NULL;
+ else
+ return gdl_icons_get_mime_icon (icons, "gnome-fs-regular");
+ } else {
+ if (!gtk_icon_theme_has_icon (priv->icon_theme, icon_name)) {
+ g_free (icon_name);
+ if (!strcmp (mime_type, "gnome-fs-regular"))
+ return NULL;
+ else
+ return gdl_icons_get_mime_icon (icons, "gnome-fs-regular");
+ } else {
+ pixbuf = gtk_icon_theme_load_icon (priv->icon_theme,
+ icon_name,
+ priv->icon_size,
+ 0, /* lookup flags */
+ NULL);
+ g_free (icon_name);
+
+ if (pixbuf == NULL) {
+ if (!strcmp (mime_type, "gnome-fs-regular"))
+ return NULL;
+ else
+ return gdl_icons_get_mime_icon (icons,
+ "gnome-fs-regular");
+ }
+ }
+ }
+
+ g_hash_table_insert (priv->icons, g_strdup (mime_type), pixbuf);
+ g_object_ref (pixbuf);
+
+ return pixbuf;
+}
diff --git a/src/libgdl/gdl-icons.h b/src/libgdl/gdl-icons.h
new file mode 100644
index 000000000..79f3bba85
--- /dev/null
+++ b/src/libgdl/gdl-icons.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gdl-icons.h
+ *
+ * Copyright (C) 2000-2001 JP Rosevear
+ * 2000 Dave Camp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: JP Rosevear, Dave Camp, Jeroen Zwartepoorte
+ */
+
+#ifndef _GDL_ICONS_H_
+#define _GDL_ICONS_H_
+
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+G_BEGIN_DECLS
+
+#define GDL_TYPE_ICONS (gdl_icons_get_type ())
+#define GDL_ICONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDL_TYPE_ICONS, GdlIcons))
+#define GDL_ICONS_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((klass), GDL_TYPE_ICONS, GdlIconsClass))
+#define GDL_IS_ICONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDL_TYPE_ICONS))
+#define GDL_IS_ICONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), GDL_TYPE_ICONS))
+
+typedef struct _GdlIcons GdlIcons;
+typedef struct _GdlIconsClass GdlIconsClass;
+
+struct _GdlIcons {
+ GObject parent;
+};
+
+struct _GdlIconsClass {
+ GObjectClass parent_class;
+};
+
+GType gdl_icons_get_type (void);
+GdlIcons *gdl_icons_new (int icon_size);
+
+GdkPixbuf *gdl_icons_get_folder_icon (GdlIcons *icons);
+GdkPixbuf *gdl_icons_get_uri_icon (GdlIcons *icons,
+ const char *uri);
+GdkPixbuf *gdl_icons_get_mime_icon (GdlIcons *icons,
+ const char *mime_type);
+
+G_END_DECLS
+
+#endif /* _GDL_ICONS_H_ */
diff --git a/src/libgdl/gdl-switcher.c b/src/libgdl/gdl-switcher.c
index eccd66ce2..24ec72126 100644
--- a/src/libgdl/gdl-switcher.c
+++ b/src/libgdl/gdl-switcher.c
@@ -55,7 +55,7 @@ static void gdl_switcher_add_button (GdlSwitcher *switcher,
const gchar *stock_id,
const GdkPixbuf *pixbuf_icon,
gint switcher_id);
-static void gdl_switcher_remove_button (GdlSwitcher *switcher, gint switcher_id);
+/* static void gdl_switcher_remove_button (GdlSwitcher *switcher, gint switcher_id); */
static void gdl_switcher_select_page (GdlSwitcher *switcher, gint switcher_id);
static void gdl_switcher_select_button (GdlSwitcher *switcher, gint switcher_id);
static void gdl_switcher_set_show_buttons (GdlSwitcher *switcher, gboolean show);
@@ -514,7 +514,7 @@ gdl_switcher_expose (GtkWidget *widget, GdkEventExpose *event)
}
}
return GDL_CALL_PARENT_WITH_DEFAULT (GTK_WIDGET_CLASS, expose_event,
- (widget, event), FALSE);
+ (widget, event), FALSE);
}
static void
@@ -678,11 +678,9 @@ gdl_switcher_select_page (GdlSwitcher *switcher, gint id)
static void
gdl_switcher_class_init (GdlSwitcherClass *klass)
{
- GtkNotebookClass *notebook_class = GTK_NOTEBOOK_CLASS (klass);
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- (void)notebook_class;
container_class->forall = gdl_switcher_forall;
container_class->remove = gdl_switcher_remove;
@@ -763,11 +761,11 @@ gdl_switcher_add_button (GdlSwitcher *switcher, const gchar *label,
gtk_widget_show (hbox);
if (stock_id) {
- icon_widget = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
+ icon_widget = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
} else if (pixbuf_icon) {
icon_widget = gtk_image_new_from_pixbuf (pixbuf_icon);
} else {
- icon_widget = gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_BUTTON);
+ icon_widget = gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU);
}
gtk_widget_show (icon_widget);
@@ -810,6 +808,7 @@ gdl_switcher_add_button (GdlSwitcher *switcher, const gchar *label,
gtk_widget_queue_resize (GTK_WIDGET (switcher));
}
+#if 0
static void
gdl_switcher_remove_button (GdlSwitcher *switcher, gint switcher_id)
{
@@ -827,6 +826,7 @@ gdl_switcher_remove_button (GdlSwitcher *switcher, gint switcher_id)
}
gtk_widget_queue_resize (GTK_WIDGET (switcher));
}
+#endif
static void
gdl_switcher_select_button (GdlSwitcher *switcher, gint switcher_id)
diff --git a/src/libgdl/libgdl.h b/src/libgdl/gdl.h
index 5ee84e1ae..e47dc310d 100644
--- a/src/libgdl/libgdl.h
+++ b/src/libgdl/gdl.h
@@ -28,10 +28,12 @@
#include "libgdl/gdl-dock-master.h"
#include "libgdl/gdl-dock.h"
#include "libgdl/gdl-dock-item.h"
+#include "libgdl/gdl-dock-layout.h"
#include "libgdl/gdl-dock-paned.h"
#include "libgdl/gdl-dock-notebook.h"
#include "libgdl/gdl-dock-tablabel.h"
#include "libgdl/gdl-dock-bar.h"
+#include "libgdl/gdl-combo-button.h"
#include "libgdl/gdl-switcher.h"
#endif
diff --git a/src/libgdl/libgdltypebuiltins.h b/src/libgdl/libgdltypebuiltins.h
index 8be5decb1..f5e6ea17b 100644
--- a/src/libgdl/libgdltypebuiltins.h
+++ b/src/libgdl/libgdltypebuiltins.h
@@ -4,7 +4,7 @@
#ifndef __LIBGDLTYPEBUILTINS_H__
#define __LIBGDLTYPEBUILTINS_H__ 1
-#include "libgdl/libgdl.h"
+#include "libgdl/gdl.h"
G_BEGIN_DECLS
diff --git a/src/libgdl/test-combo-button.c b/src/libgdl/test-combo-button.c
new file mode 100644
index 000000000..35ce3fff3
--- /dev/null
+++ b/src/libgdl/test-combo-button.c
@@ -0,0 +1,111 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* test-combo-button.c
+ *
+ * Copyright (C) 2003 Jeroen Zwartepoorte
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include "gdl-combo-button.h"
+
+static void
+combo_button_activate_default_cb (GdlComboButton *combo,
+ gpointer data)
+{
+ g_message ("combo_button_activate_default_cb");
+}
+
+int
+main (int argc, char **argv)
+{
+ GtkWidget *window, *hbox, *combo, *menu, *menuitem;
+ GdkPixbuf *icon;
+
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ g_signal_connect (G_OBJECT (window), "delete_event",
+ G_CALLBACK (gtk_main_quit), NULL);
+ gtk_window_set_title (GTK_WINDOW (window), "Combo button test");
+ gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), hbox);
+
+ combo = gtk_button_new_from_stock (GTK_STOCK_OPEN);
+ gtk_button_set_relief (GTK_BUTTON (combo), GTK_RELIEF_NONE);
+ gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
+
+ menu = gtk_menu_new ();
+ menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_OPEN, NULL);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+ menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SAVE, NULL);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+ gtk_widget_show_all (menu);
+
+ combo = gdl_combo_button_new ();
+ gdl_combo_button_set_label (GDL_COMBO_BUTTON (combo), "Run");
+ gdl_combo_button_set_menu (GDL_COMBO_BUTTON (combo), GTK_MENU (menu));
+ icon = gtk_widget_render_icon (combo, GTK_STOCK_EXECUTE,
+ GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
+ gdl_combo_button_set_icon (GDL_COMBO_BUTTON (combo), icon);
+ gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
+
+ g_signal_connect (combo, "activate_default",
+ G_CALLBACK (combo_button_activate_default_cb), NULL);
+
+ combo = gtk_button_new_from_stock (GTK_STOCK_SAVE);
+ gtk_button_set_relief (GTK_BUTTON (combo), GTK_RELIEF_NONE);
+ gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
+
+ menu = gtk_menu_new ();
+ menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_OPEN, NULL);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+ menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SAVE, NULL);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+ gtk_widget_show_all (menu);
+
+ combo = gdl_combo_button_new ();
+ gdl_combo_button_set_label (GDL_COMBO_BUTTON (combo), "Open");
+ gdl_combo_button_set_menu (GDL_COMBO_BUTTON (combo), GTK_MENU (menu));
+ icon = gtk_widget_render_icon (combo, GTK_STOCK_OPEN,
+ GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
+ gdl_combo_button_set_icon (GDL_COMBO_BUTTON (combo), icon);
+ gtk_widget_set_sensitive (combo, FALSE);
+ gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
+
+ g_signal_connect (combo, "activate_default",
+ G_CALLBACK (combo_button_activate_default_cb), NULL);
+
+ menu = gtk_menu_new ();
+ combo = gdl_combo_button_new ();
+ gdl_combo_button_set_label (GDL_COMBO_BUTTON (combo), "Open");
+ gdl_combo_button_set_menu (GDL_COMBO_BUTTON (combo), GTK_MENU (menu));
+ icon = gtk_widget_render_icon (combo, GTK_STOCK_OPEN,
+ GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
+ gdl_combo_button_set_icon (GDL_COMBO_BUTTON (combo), icon);
+ gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
+
+ gtk_widget_show_all (window);
+
+ gtk_main ();
+
+ return 0;
+}
diff --git a/src/libgdl/test-dataview.c b/src/libgdl/test-dataview.c
new file mode 100644
index 000000000..bc89cbd4f
--- /dev/null
+++ b/src/libgdl/test-dataview.c
@@ -0,0 +1,43 @@
+#include <config.h>
+#include <gtk/gtk.h>
+#include <libgnome/libgnome.h>
+
+#include "gdl-data-view.h"
+#include "gdl-data-model-test.h"
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *win;
+ GtkWidget *view;
+ GdlDataModel *model;
+ GtkWidget *vbox;
+
+ gtk_init (&argc, &argv);
+
+ win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size (GTK_WINDOW (win), 500, 200);
+
+ vbox = gtk_vbox_new (FALSE, 5);
+
+ view = gdl_data_view_new ();
+
+ gtk_layout_set_hadjustment (GTK_LAYOUT (view), NULL);
+ gtk_layout_set_vadjustment (GTK_LAYOUT (view), NULL);
+
+
+ model = GDL_DATA_MODEL (gdl_data_model_test_new ());
+ gdl_data_view_set_model (GDL_DATA_VIEW (view),
+ model);
+
+ gtk_box_pack_start (GTK_BOX (vbox), view, TRUE, TRUE, 0);
+
+ gtk_container_add (GTK_CONTAINER (win), vbox);
+
+ gtk_widget_show_all (win);
+ gtk_widget_grab_focus (GTK_WIDGET (view));
+
+ gtk_main ();
+
+ return 0;
+}
diff --git a/src/libgdl/test-dock.c b/src/libgdl/test-dock.c
new file mode 100644
index 000000000..1e9c80111
--- /dev/null
+++ b/src/libgdl/test-dock.c
@@ -0,0 +1,311 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <gtk/gtk.h>
+
+#include "gdl-tools.h"
+
+#include "gdl-dock.h"
+#include "gdl-dock-item.h"
+#include "gdl-dock-notebook.h"
+#include "gdl-dock-layout.h"
+#include "gdl-dock-placeholder.h"
+#include "gdl-dock-bar.h"
+#include "gdl-switcher.h"
+
+#include <glib.h>
+
+/* ---- end of debugging code */
+
+static void
+on_style_button_toggled (GtkRadioButton *button, GdlDock *dock)
+{
+ gboolean active;
+ GdlDockMaster *master = GDL_DOCK_OBJECT_GET_MASTER (dock);
+ GdlSwitcherStyle style =
+ GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button),
+ "__style_id"));
+ active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+ if (active) {
+ g_object_set (master, "switcher-style", style, NULL);
+ }
+}
+
+static GtkWidget *
+create_style_button (GtkWidget *dock, GtkWidget *box, GtkWidget *group,
+ GdlSwitcherStyle style, const gchar *style_text)
+{
+ GdlSwitcherStyle current_style;
+ GtkWidget *button1;
+ GdlDockMaster *master = GDL_DOCK_OBJECT_GET_MASTER (dock);
+
+ g_object_get (master, "switcher-style", &current_style, NULL);
+ button1 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (group),
+ style_text);
+ gtk_widget_show (button1);
+ g_object_set_data (G_OBJECT (button1), "__style_id",
+ GINT_TO_POINTER (style));
+ if (current_style == style) {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
+ }
+ g_signal_connect (button1, "toggled",
+ G_CALLBACK (on_style_button_toggled),
+ dock);
+ gtk_box_pack_start (GTK_BOX (box), button1, FALSE, FALSE, 0);
+ return button1;
+}
+
+static GtkWidget *
+create_styles_item (GtkWidget *dock)
+{
+ GtkWidget *vbox1;
+ GtkWidget *group;
+
+ vbox1 = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (vbox1);
+
+ group = create_style_button (dock, vbox1, NULL,
+ GDL_SWITCHER_STYLE_ICON, "Only icon");
+ group = create_style_button (dock, vbox1, group,
+ GDL_SWITCHER_STYLE_TEXT, "Only text");
+ group = create_style_button (dock, vbox1, group,
+ GDL_SWITCHER_STYLE_BOTH,
+ "Both icons and texts");
+ group = create_style_button (dock, vbox1, group,
+ GDL_SWITCHER_STYLE_TOOLBAR,
+ "Desktop toolbar style");
+ group = create_style_button (dock, vbox1, group,
+ GDL_SWITCHER_STYLE_TABS,
+ "Notebook tabs");
+ return vbox1;
+}
+
+static GtkWidget *
+create_item (const gchar *button_title)
+{
+ GtkWidget *vbox1;
+ GtkWidget *button1;
+
+ vbox1 = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (vbox1);
+
+ button1 = gtk_button_new_with_label (button_title);
+ gtk_widget_show (button1);
+ gtk_box_pack_start (GTK_BOX (vbox1), button1, TRUE, TRUE, 0);
+
+ return vbox1;
+}
+
+/* creates a simple widget with a textbox inside */
+static GtkWidget *
+create_text_item ()
+{
+ GtkWidget *vbox1;
+ GtkWidget *scrolledwindow1;
+ GtkWidget *text;
+
+ vbox1 = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (vbox1);
+
+ scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_show (scrolledwindow1);
+ gtk_box_pack_start (GTK_BOX (vbox1), scrolledwindow1, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow1),
+ GTK_SHADOW_ETCHED_IN);
+ text = gtk_text_view_new ();
+ g_object_set (text, "wrap-mode", GTK_WRAP_WORD, NULL);
+ gtk_widget_show (text);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow1), text);
+
+ return vbox1;
+}
+
+static void
+button_dump_cb (GtkWidget *button, gpointer data)
+{
+ /* Dump XML tree. */
+ gdl_dock_layout_save_to_file (GDL_DOCK_LAYOUT (data), "layout.xml");
+ g_spawn_command_line_async ("cat layout.xml", NULL);
+}
+
+static void
+run_layout_manager_cb (GtkWidget *w, gpointer data)
+{
+ GdlDockLayout *layout = GDL_DOCK_LAYOUT (data);
+ gdl_dock_layout_run_manager (layout);
+}
+
+static void
+save_layout_cb (GtkWidget *w, gpointer data)
+{
+ GdlDockLayout *layout = GDL_DOCK_LAYOUT (data);
+ GtkWidget *dialog, *hbox, *label, *entry;
+ gint response;
+
+ dialog = gtk_dialog_new_with_buttons ("New Layout",
+ NULL,
+ GTK_DIALOG_MODAL |
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_OK,
+ GTK_RESPONSE_OK,
+ NULL);
+
+ hbox = gtk_hbox_new (FALSE, 8);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new ("Name:");
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ entry = gtk_entry_new ();
+ gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
+
+ gtk_widget_show_all (hbox);
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ if (response == GTK_RESPONSE_OK) {
+ const gchar *name = gtk_entry_get_text (GTK_ENTRY (entry));
+ gdl_dock_layout_save_layout (layout, name);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+int
+main (int argc, char **argv)
+{
+ GtkWidget *item1, *item2, *item3;
+ GtkWidget *items [4];
+ GtkWidget *win, *table, *button, *box;
+ int i;
+ GdlDockLayout *layout;
+ GtkWidget *dock, *dockbar;
+
+ gtk_init (&argc, &argv);
+
+ /*gtk_widget_set_default_direction (GTK_TEXT_DIR_RTL);*/
+
+ /* window creation */
+ win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ g_signal_connect (win, "delete_event",
+ G_CALLBACK (gtk_main_quit), NULL);
+ gtk_window_set_title (GTK_WINDOW (win), "Docking widget test");
+ gtk_window_set_default_size (GTK_WINDOW (win), 400, 400);
+
+ /* table */
+ table = gtk_vbox_new (FALSE, 5);
+ gtk_container_add (GTK_CONTAINER (win), table);
+ gtk_container_set_border_width (GTK_CONTAINER (table), 10);
+
+ /* create the dock */
+ dock = gdl_dock_new ();
+
+ /* ... and the layout manager */
+ layout = gdl_dock_layout_new (GDL_DOCK (dock));
+
+ /* create the dockbar */
+ dockbar = gdl_dock_bar_new (GDL_DOCK (dock));
+ gdl_dock_bar_set_style(GDL_DOCK_BAR(dockbar), GDL_DOCK_BAR_TEXT);
+
+ box = gtk_hbox_new (FALSE, 5);
+ gtk_box_pack_start (GTK_BOX (table), box, TRUE, TRUE, 0);
+
+ gtk_box_pack_start (GTK_BOX (box), dockbar, FALSE, FALSE, 0);
+ gtk_box_pack_end (GTK_BOX (box), dock, TRUE, TRUE, 0);
+
+ /* create the dock items */
+ item1 = gdl_dock_item_new ("item1", "Item #1", GDL_DOCK_ITEM_BEH_LOCKED);
+ gtk_container_add (GTK_CONTAINER (item1), create_text_item ());
+ gdl_dock_add_item (GDL_DOCK (dock), GDL_DOCK_ITEM (item1),
+ GDL_DOCK_TOP);
+ gtk_widget_show (item1);
+
+ item2 = gdl_dock_item_new_with_stock ("item2", "Item #2: Select the switcher style for notebooks",
+ GTK_STOCK_EXECUTE,
+ GDL_DOCK_ITEM_BEH_NORMAL);
+ g_object_set (item2, "resize", FALSE, NULL);
+ gtk_container_add (GTK_CONTAINER (item2), create_styles_item (dock));
+ gdl_dock_add_item (GDL_DOCK (dock), GDL_DOCK_ITEM (item2),
+ GDL_DOCK_RIGHT);
+ gtk_widget_show (item2);
+
+ item3 = gdl_dock_item_new_with_stock ("item3", "Item #3 has accented characters (áéíóúñ)",
+ GTK_STOCK_CONVERT,
+ GDL_DOCK_ITEM_BEH_NORMAL |
+ GDL_DOCK_ITEM_BEH_CANT_CLOSE);
+ gtk_container_add (GTK_CONTAINER (item3), create_item ("Button 3"));
+ gdl_dock_add_item (GDL_DOCK (dock), GDL_DOCK_ITEM (item3),
+ GDL_DOCK_BOTTOM);
+ gtk_widget_show (item3);
+
+ items [0] = gdl_dock_item_new_with_stock ("Item #4", "Item #4",
+ GTK_STOCK_JUSTIFY_FILL,
+ GDL_DOCK_ITEM_BEH_NORMAL |
+ GDL_DOCK_ITEM_BEH_CANT_ICONIFY);
+ gtk_container_add (GTK_CONTAINER (items [0]), create_text_item ());
+ gtk_widget_show (items [0]);
+ gdl_dock_add_item (GDL_DOCK (dock), GDL_DOCK_ITEM (items [0]), GDL_DOCK_BOTTOM);
+ for (i = 1; i < 3; i++) {
+ gchar name[10];
+
+ snprintf (name, sizeof (name), "Item #%d", i + 4);
+ items [i] = gdl_dock_item_new_with_stock (name, name, GTK_STOCK_NEW,
+ GDL_DOCK_ITEM_BEH_NORMAL);
+ gtk_container_add (GTK_CONTAINER (items [i]), create_text_item ());
+ gtk_widget_show (items [i]);
+
+ gdl_dock_object_dock (GDL_DOCK_OBJECT (items [0]),
+ GDL_DOCK_OBJECT (items [i]),
+ GDL_DOCK_CENTER, NULL);
+ };
+
+ /* tests: manually dock and move around some of the items */
+ gdl_dock_item_dock_to (GDL_DOCK_ITEM (item3), GDL_DOCK_ITEM (item1),
+ GDL_DOCK_TOP, -1);
+
+ gdl_dock_item_dock_to (GDL_DOCK_ITEM (item2), GDL_DOCK_ITEM (item3),
+ GDL_DOCK_RIGHT, -1);
+
+ gdl_dock_item_dock_to (GDL_DOCK_ITEM (item2), GDL_DOCK_ITEM (item3),
+ GDL_DOCK_LEFT, -1);
+
+ gdl_dock_item_dock_to (GDL_DOCK_ITEM (item2), NULL,
+ GDL_DOCK_FLOATING, -1);
+
+ box = gtk_hbox_new (TRUE, 5);
+ gtk_box_pack_end (GTK_BOX (table), box, FALSE, FALSE, 0);
+
+ button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (save_layout_cb), layout);
+ gtk_box_pack_end (GTK_BOX (box), button, FALSE, TRUE, 0);
+
+ button = gtk_button_new_with_label ("Layout Manager");
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (run_layout_manager_cb), layout);
+ gtk_box_pack_end (GTK_BOX (box), button, FALSE, TRUE, 0);
+
+ button = gtk_button_new_with_label ("Dump XML");
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (button_dump_cb), layout);
+ gtk_box_pack_end (GTK_BOX (box), button, FALSE, TRUE, 0);
+
+ gtk_widget_show_all (win);
+
+ gdl_dock_placeholder_new ("ph1", GDL_DOCK_OBJECT (dock), GDL_DOCK_TOP, FALSE);
+ gdl_dock_placeholder_new ("ph2", GDL_DOCK_OBJECT (dock), GDL_DOCK_BOTTOM, FALSE);
+ gdl_dock_placeholder_new ("ph3", GDL_DOCK_OBJECT (dock), GDL_DOCK_LEFT, FALSE);
+ gdl_dock_placeholder_new ("ph4", GDL_DOCK_OBJECT (dock), GDL_DOCK_RIGHT, FALSE);
+
+ gtk_main ();
+
+ g_object_unref (layout);
+
+ return 0;
+}
diff --git a/src/ui/dialog/dock-behavior.h b/src/ui/dialog/dock-behavior.h
index b865af545..98c111719 100644
--- a/src/ui/dialog/dock-behavior.h
+++ b/src/ui/dialog/dock-behavior.h
@@ -21,7 +21,7 @@
#include "ui/widget/dock-item.h"
-#include "libgdl/libgdl.h"
+#include "libgdl/gdl.h"
#include "behavior.h"
diff --git a/src/ui/widget/dock-item.h b/src/ui/widget/dock-item.h
index 79d69d862..1780b7525 100644
--- a/src/ui/widget/dock-item.h
+++ b/src/ui/widget/dock-item.h
@@ -19,7 +19,7 @@
#include <gtkmm/paned.h>
#include <gtkmm/window.h>
-#include "libgdl/libgdl.h"
+#include "libgdl/gdl.h"
namespace Inkscape {
namespace UI {
diff --git a/src/ui/widget/dock.h b/src/ui/widget/dock.h
index 5836cf83f..bd5685348 100644
--- a/src/ui/widget/dock.h
+++ b/src/ui/widget/dock.h
@@ -20,7 +20,7 @@
#include "ui/widget/dock-item.h"
-#include "libgdl/libgdl.h"
+#include "libgdl/gdl.h"
namespace Inkscape {
namespace UI {