2 * Copyright (C) 2003 Marco Pesenti Gritti
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include "egg-toolbar-editor.h"
22 #include "egg-editable-toolbar.h"
25 #include <glib/gi18n.h>
26 #include <libxml/tree.h>
27 #include <gtk/gtkimage.h>
28 #include <gtk/gtkeventbox.h>
29 #include <gtk/gtkdnd.h>
30 #include <gtk/gtkscrolledwindow.h>
31 #include <gtk/gtklabel.h>
32 #include <gtk/gtktable.h>
33 #include <gtk/gtkstock.h>
34 #include <gtk/gtkhbox.h>
36 static GtkTargetEntry dest_drag_types[] = {
37 {EGG_TOOLBAR_ITEM_TYPE, GTK_TARGET_SAME_APP, 0},
39 static int n_dest_drag_types = G_N_ELEMENTS (dest_drag_types);
41 static GtkTargetEntry source_drag_types[] = {
42 {EGG_TOOLBAR_ITEM_TYPE, GTK_TARGET_SAME_APP, 0},
44 static int n_source_drag_types = G_N_ELEMENTS (source_drag_types);
46 static void egg_toolbar_editor_class_init (EggToolbarEditorClass *klass);
47 static void egg_toolbar_editor_init (EggToolbarEditor *t);
48 static void egg_toolbar_editor_finalize (GObject *object);
49 static void update_actions_list (EggToolbarEditor *editor);
50 static void update_editor_sheet (EggToolbarEditor *editor);
59 static GObjectClass *parent_class = NULL;
61 #define EGG_TOOLBAR_EDITOR_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EGG_TYPE_TOOLBAR_EDITOR, EggToolbarEditorPrivate))
63 struct EggToolbarEditorPrivate
65 GtkUIManager *manager;
66 EggToolbarsModel *model;
69 GtkWidget *scrolled_window;
71 GList *default_actions_list;
76 egg_toolbar_editor_get_type (void)
78 static GType egg_toolbar_editor_type = 0;
80 if (egg_toolbar_editor_type == 0)
82 static const GTypeInfo our_info = {
83 sizeof (EggToolbarEditorClass),
85 NULL, /* base_finalize */
86 (GClassInitFunc) egg_toolbar_editor_class_init,
88 NULL, /* class_data */
89 sizeof (EggToolbarEditor),
91 (GInstanceInitFunc) egg_toolbar_editor_init
94 egg_toolbar_editor_type = g_type_register_static (GTK_TYPE_VBOX,
99 return egg_toolbar_editor_type;
103 compare_actions (gconstpointer a,
106 GValue value_a = { 0, }, value_b = { 0, };
107 const char *short_label_a, *short_label_b;
110 g_value_init (&value_a, G_TYPE_STRING);
111 g_object_get_property (G_OBJECT (a), "short_label", &value_a);
112 short_label_a = g_value_get_string (&value_a);
114 g_value_init (&value_b, G_TYPE_STRING);
115 g_object_get_property (G_OBJECT (b), "short_label", &value_b);
116 short_label_b = g_value_get_string (&value_b);
118 ret = g_utf8_collate (short_label_a, short_label_b);
120 g_value_unset (&value_a);
121 g_value_unset (&value_b);
127 find_action (EggToolbarEditor *t,
131 GtkAction *action = NULL;
133 l = gtk_ui_manager_get_action_groups (t->priv->manager);
135 g_return_val_if_fail (EGG_IS_TOOLBAR_EDITOR (t), NULL);
136 g_return_val_if_fail (name != NULL, NULL);
138 for (; l != NULL; l = l->next)
142 tmp = gtk_action_group_get_action (GTK_ACTION_GROUP (l->data), name);
151 egg_toolbar_editor_set_ui_manager (EggToolbarEditor *t,
152 GtkUIManager *manager)
154 g_return_if_fail (GTK_IS_UI_MANAGER (manager));
156 t->priv->manager = g_object_ref (manager);
160 toolbar_removed_cb (EggToolbarsModel *model,
162 EggToolbarEditor *editor)
164 update_actions_list (editor);
165 update_editor_sheet (editor);
169 egg_toolbar_editor_set_model (EggToolbarEditor *t,
170 EggToolbarsModel *model)
172 g_return_if_fail (EGG_IS_TOOLBAR_EDITOR (t));
174 t->priv->model = g_object_ref (model);
176 g_signal_connect_object (model, "toolbar_removed",
177 G_CALLBACK (toolbar_removed_cb), t, 0);
181 egg_toolbar_editor_set_property (GObject *object,
186 EggToolbarEditor *t = EGG_TOOLBAR_EDITOR (object);
190 case PROP_UI_MANAGER:
191 egg_toolbar_editor_set_ui_manager (t, g_value_get_object (value));
193 case PROP_TOOLBARS_MODEL:
194 egg_toolbar_editor_set_model (t, g_value_get_object (value));
200 egg_toolbar_editor_get_property (GObject *object,
205 EggToolbarEditor *t = EGG_TOOLBAR_EDITOR (object);
209 case PROP_UI_MANAGER:
210 g_value_set_object (value, t->priv->manager);
212 case PROP_TOOLBARS_MODEL:
213 g_value_set_object (value, t->priv->model);
219 egg_toolbar_editor_class_init (EggToolbarEditorClass *klass)
221 GObjectClass *object_class = G_OBJECT_CLASS (klass);
223 parent_class = g_type_class_peek_parent (klass);
225 object_class->finalize = egg_toolbar_editor_finalize;
226 object_class->set_property = egg_toolbar_editor_set_property;
227 object_class->get_property = egg_toolbar_editor_get_property;
229 g_object_class_install_property (object_class,
231 g_param_spec_object ("ui-manager",
236 G_PARAM_CONSTRUCT_ONLY));
237 g_object_class_install_property (object_class,
239 g_param_spec_object ("model",
242 EGG_TYPE_TOOLBARS_MODEL,
244 G_PARAM_CONSTRUCT_ONLY));
246 g_type_class_add_private (object_class, sizeof (EggToolbarEditorPrivate));
250 egg_toolbar_editor_finalize (GObject *object)
252 EggToolbarEditor *editor = EGG_TOOLBAR_EDITOR (object);
254 if (editor->priv->manager)
256 g_object_unref (editor->priv->manager);
259 if (editor->priv->model)
261 g_object_unref (editor->priv->model);
264 g_list_free (editor->priv->default_actions_list);
265 g_list_free (editor->priv->actions_list);
267 G_OBJECT_CLASS (parent_class)->finalize (object);
271 egg_toolbar_editor_new (GtkUIManager *manager,
272 EggToolbarsModel *model)
274 return GTK_WIDGET (g_object_new (EGG_TYPE_TOOLBAR_EDITOR,
275 "ui-manager", manager,
281 drag_begin_cb (GtkWidget *widget,
282 GdkDragContext *context)
284 gtk_widget_hide (widget);
288 drag_end_cb (GtkWidget *widget,
289 GdkDragContext *context)
291 gtk_widget_show (widget);
295 editor_drag_data_received_cb (GtkWidget *widget,
296 GdkDragContext *context,
299 GtkSelectionData *selection_data,
302 EggToolbarEditor *editor)
307 g_return_if_fail (EGG_IS_TOOLBAR_EDITOR (editor));
308 g_return_if_fail (selection_data != NULL);
310 if (selection_data->length <= 0 || selection_data->data == NULL) return;
312 data = (const char *) selection_data->data;
314 if (strcmp (data, "separator") == 0) return;
316 action = find_action (editor, data);
317 g_return_if_fail (action != NULL);
319 if (g_list_find (editor->priv->default_actions_list, action))
321 editor->priv->actions_list = g_list_insert_sorted
322 (editor->priv->actions_list, action, compare_actions);
325 update_editor_sheet (editor);
329 editor_drag_data_delete_cb (GtkWidget *widget,
330 GdkDragContext *context,
331 EggToolbarEditor *editor)
334 g_return_if_fail (EGG_IS_TOOLBAR_EDITOR (editor));
336 action = GTK_ACTION (g_object_get_data (G_OBJECT (widget), "egg-action"));
339 editor->priv->actions_list = g_list_remove
340 (editor->priv->actions_list, action);
343 update_editor_sheet (editor);
347 drag_data_get_cb (GtkWidget *widget,
348 GdkDragContext *context,
349 GtkSelectionData *selection_data,
352 EggToolbarEditor *editor)
357 action = GTK_ACTION (g_object_get_data (G_OBJECT (widget), "egg-action"));
361 target = gtk_action_get_name (action);
365 target = "separator";
368 gtk_selection_data_set (selection_data,
369 selection_data->target, 8, target, strlen (target));
373 elide_underscores (const gchar *original)
377 gboolean last_underscore;
379 q = result = g_malloc (strlen (original) + 1);
380 last_underscore = FALSE;
382 for (p = original; *p; p++)
384 if (!last_underscore && *p == '_')
385 last_underscore = TRUE;
388 last_underscore = FALSE;
399 set_drag_cursor (GtkWidget *widget)
404 pixbuf = gdk_pixbuf_new_from_file (CURSOR_DIR "/hand-open.png", NULL);
405 cursor = gdk_cursor_new_from_pixbuf (gdk_display_get_default (), pixbuf, 12, 12);
407 gdk_window_set_cursor (widget->window, cursor);
408 gdk_cursor_unref (cursor);
409 g_object_unref (pixbuf);
413 event_box_realize_cb (GtkWidget *widget, GtkImage *icon)
417 set_drag_cursor (widget);
419 type = gtk_image_get_storage_type (icon);
420 if (type == GTK_IMAGE_STOCK)
424 gtk_image_get_stock (icon, &stock_id, NULL);
425 pixbuf = gtk_widget_render_icon (widget, stock_id,
426 GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
427 gtk_drag_source_set_icon_pixbuf (widget, pixbuf);
428 g_object_unref (pixbuf);
430 else if (type == GTK_IMAGE_PIXBUF)
432 GdkPixbuf *pixbuf = gtk_image_get_pixbuf (icon);
433 gtk_drag_source_set_icon_pixbuf (widget, pixbuf);
438 editor_create_item (EggToolbarEditor *editor,
440 const char *label_text,
441 GdkDragAction action)
443 GtkWidget *event_box;
446 gchar *label_no_mnemonic = NULL;
448 event_box = gtk_event_box_new ();
449 gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE);
450 gtk_widget_show (event_box);
451 gtk_drag_source_set (event_box,
453 source_drag_types, n_source_drag_types, action);
454 g_signal_connect (event_box, "drag_data_get",
455 G_CALLBACK (drag_data_get_cb), editor);
456 g_signal_connect (event_box, "drag_data_delete",
457 G_CALLBACK (editor_drag_data_delete_cb), editor);
458 g_signal_connect_after (event_box, "realize",
459 G_CALLBACK (event_box_realize_cb), icon);
461 if (action == GDK_ACTION_MOVE)
463 g_signal_connect (event_box, "drag_begin",
464 G_CALLBACK (drag_begin_cb), NULL);
465 g_signal_connect (event_box, "drag_end",
466 G_CALLBACK (drag_end_cb), NULL);
469 vbox = gtk_vbox_new (0, FALSE);
470 gtk_widget_show (vbox);
471 gtk_container_add (GTK_CONTAINER (event_box), vbox);
473 gtk_widget_show (GTK_WIDGET (icon));
474 gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (icon), FALSE, TRUE, 0);
475 label_no_mnemonic = elide_underscores (label_text);
476 label = gtk_label_new (label_no_mnemonic);
477 g_free (label_no_mnemonic);
478 gtk_widget_show (label);
479 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
485 update_editor_sheet (EggToolbarEditor *editor)
489 int x, y, height, width;
495 g_return_if_fail (EGG_IS_TOOLBAR_EDITOR (editor));
497 viewport = GTK_BIN (editor->priv->scrolled_window)->child;
500 table = GTK_BIN (viewport)->child;
501 gtk_container_remove (GTK_CONTAINER (viewport), table);
503 table = gtk_table_new (0, 0, TRUE);
504 editor->priv->table = table;
505 gtk_container_set_border_width (GTK_CONTAINER (table), 12);
506 gtk_widget_show (table);
507 gtk_scrolled_window_add_with_viewport
508 (GTK_SCROLLED_WINDOW (editor->priv->scrolled_window), table);
509 gtk_drag_dest_set (table, GTK_DEST_DEFAULT_ALL,
510 dest_drag_types, n_dest_drag_types, GDK_ACTION_MOVE);
511 g_signal_connect (table, "drag_data_received",
512 G_CALLBACK (editor_drag_data_received_cb), editor);
514 to_drag = editor->priv->actions_list;
518 height = (g_list_length (to_drag)) / width + 1;
519 gtk_table_resize (GTK_TABLE (editor->priv->table), height, width);
521 for (l = to_drag; l != NULL; l = l->next)
523 GtkAction *action = (l->data);
524 const char *stock_id, *short_label;
525 GValue value = { 0, };
527 g_value_init (&value, G_TYPE_STRING);
528 g_object_get_property (G_OBJECT (action), "stock_id", &value);
529 stock_id = g_value_get_string (&value);
530 icon = gtk_image_new_from_stock
531 (stock_id ? stock_id : GTK_STOCK_DND,
532 GTK_ICON_SIZE_LARGE_TOOLBAR);
533 g_value_unset (&value);
535 g_value_init (&value, G_TYPE_STRING);
536 g_object_get_property (G_OBJECT (action), "short_label", &value);
537 short_label = g_value_get_string (&value);
538 item = editor_create_item (editor, GTK_IMAGE (icon),
539 short_label, GDK_ACTION_MOVE);
540 g_value_unset (&value);
541 g_object_set_data (G_OBJECT (item), "egg-action", action);
542 gtk_table_attach_defaults (GTK_TABLE (editor->priv->table),
543 item, x, x + 1, y, y + 1);
553 icon = _egg_editable_toolbar_new_separator_image ();
554 item = editor_create_item (editor, GTK_IMAGE (icon), _("Separator"),
556 gtk_table_attach_defaults (GTK_TABLE (editor->priv->table),
557 item, x, x + 1, y, y + 1);
561 setup_editor (EggToolbarEditor *editor)
563 GtkWidget *scrolled_window;
564 GtkWidget *label_hbox;
568 g_return_if_fail (EGG_IS_TOOLBAR_EDITOR (editor));
570 gtk_container_set_border_width (GTK_CONTAINER (editor), 12);
571 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
572 editor->priv->scrolled_window = scrolled_window;
573 gtk_widget_show (scrolled_window);
574 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
575 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
576 gtk_box_pack_start (GTK_BOX (editor), scrolled_window, TRUE, TRUE, 0);
577 label_hbox = gtk_hbox_new (FALSE, 6);
578 gtk_widget_show (label_hbox);
579 gtk_box_pack_start (GTK_BOX (editor), label_hbox, FALSE, FALSE, 0);
581 gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
582 gtk_widget_show (image);
583 gtk_box_pack_start (GTK_BOX (label_hbox), image, FALSE, FALSE, 0);
584 label = gtk_label_new (_("Drag an item onto the toolbars above to add it, "
585 "from the toolbars in the items table to remove it."));
586 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
587 gtk_widget_show (label);
588 gtk_box_pack_start (GTK_BOX (label_hbox), label, FALSE, TRUE, 0);
592 egg_toolbar_editor_init (EggToolbarEditor *t)
594 t->priv = EGG_TOOLBAR_EDITOR_GET_PRIVATE (t);
596 t->priv->manager = NULL;
597 t->priv->default_actions_list = NULL;
598 t->priv->actions_list = NULL;
604 egg_toolbar_editor_add_action (EggToolbarEditor *editor,
605 const char *action_name)
609 action = find_action (editor, action_name);
610 g_return_if_fail (action != NULL);
612 editor->priv->default_actions_list = g_list_insert_sorted
613 (editor->priv->default_actions_list, action, compare_actions);
617 parse_item_list (EggToolbarEditor *t,
622 if (xmlStrEqual (child->name, "toolitem"))
626 name = xmlGetProp (child, "name");
627 egg_toolbar_editor_add_action (t, name);
635 model_has_action (EggToolbarsModel *model, GtkAction *action)
637 int i, l, n_items, n_toolbars;
639 n_toolbars = egg_toolbars_model_n_toolbars (model);
640 for (i = 0; i < n_toolbars; i++)
642 n_items = egg_toolbars_model_n_items (model, i);
643 for (l = 0; l < n_items; l++)
646 const char *action_name;
649 egg_toolbars_model_item_nth (model, i, l, &sep, &name, NULL);
650 action_name = gtk_action_get_name (action);
651 if (!sep && strcmp (name, action_name) == 0) return TRUE;
659 update_actions_list (EggToolbarEditor *editor)
663 if (editor->priv->actions_list)
664 g_list_free (editor->priv->actions_list);
666 /* Remove the already used items */
667 editor->priv->actions_list = NULL;
669 for (l = editor->priv->default_actions_list; l != NULL; l = l->next)
671 GtkAction *action = GTK_ACTION (l->data);
673 if (!model_has_action (editor->priv->model, action))
675 editor->priv->actions_list = g_list_insert_sorted
676 (editor->priv->actions_list, action, compare_actions);
682 egg_toolbar_editor_load_actions (EggToolbarEditor *editor,
683 const char *xml_file)
689 doc = xmlParseFile (xml_file);
690 root = xmlDocGetRootElement (doc);
691 child = root->children;
695 if (xmlStrEqual (child->name, "available"))
697 parse_item_list (editor, child->children);
704 update_actions_list (editor);
705 update_editor_sheet (editor);