/* * Copyright (C) 2000 Marco Pesenti Gritti * (C) 2001, 2002 Jorn Baayen * * 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, 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. */ #include "ephy-editable-toolbar.h" #include "ephy-toolbars-group.h" #include "ephy-debug.h" #include "ephy-dnd.h" #include "ephy-file-helpers.h" #include "eggtoolitem.h" #include "eggtoolbar.h" #include "eggseparatortoolitem.h" #include #include static GtkTargetEntry dest_drag_types [] = { { "EPHY_TOOLBAR_BUTTON", 0, 0 }, /* FIXME generic way to add types */ { EPHY_DND_URL_TYPE, 0, 1 }, { EPHY_DND_TOPIC_TYPE, 0, 2 } }; static GtkTargetEntry source_drag_types [] = { { "EPHY_TOOLBAR_BUTTON", 0, 0 } }; enum { RESPONSE_ADD_TOOLBAR }; static void ephy_editable_toolbar_class_init (EphyEditableToolbarClass *klass); static void ephy_editable_toolbar_init (EphyEditableToolbar *t); static void ephy_editable_toolbar_finalize (GObject *object); static void do_merge (EphyEditableToolbar *t); static void setup_editor (EphyEditableToolbar *etoolbar, GtkWidget *window); static void update_editor_sheet (EphyEditableToolbar *etoolbar); static void ephy_editable_toolbar_remove_cb (EggAction *action, EphyEditableToolbar *etoolbar); static void ephy_editable_toolbar_edit_cb (EggAction *action, EphyEditableToolbar *etoolbar); static EggActionGroupEntry ephy_toolbar_popups [] = { /* Toplevel */ { "FakeToplevel", (""), NULL, NULL, NULL, NULL, NULL }, /* Popups */ { "RemoveToolbarPopup", N_("_Remove Toolbar"), GTK_STOCK_REMOVE, NULL, NULL, G_CALLBACK (ephy_editable_toolbar_remove_cb), NULL }, { "EditToolbarPopup", N_("_Edit Toolbars..."), GTK_STOCK_PREFERENCES, NULL, NULL, G_CALLBACK (ephy_editable_toolbar_edit_cb), NULL }, }; static guint ephy_toolbar_popups_n_entries = G_N_ELEMENTS (ephy_toolbar_popups); enum { PROP_0, PROP_TOOLBARS_GROUP, PROP_MENU_MERGE }; static GObjectClass *parent_class = NULL; struct EphyEditableToolbarPrivate { EggMenuMerge *merge; GtkWidget *editor; GtkWidget *table; GtkWidget *scrolled_window; GtkWidget *last_toolbar; guint ui_id; gboolean toolbars_dirty; gboolean editor_sheet_dirty; gboolean edit_mode; EphyToolbarsGroup *group; EggMenuMerge *popup_merge; EggActionGroup *popup_action_group; GList *actions_list; }; typedef struct { EphyEditableToolbar *etoolbar; EphyToolbarsToolbar *t; } ContextMenuData; GType ephy_editable_toolbar_get_type (void) { static GType ephy_editable_toolbar_type = 0; if (ephy_editable_toolbar_type == 0) { static const GTypeInfo our_info = { sizeof (EphyEditableToolbarClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) ephy_editable_toolbar_class_init, NULL, NULL, /* class_data */ sizeof (EphyEditableToolbar), 0, /* n_preallocs */ (GInstanceInitFunc) ephy_editable_toolbar_init }; ephy_editable_toolbar_type = g_type_register_static (G_TYPE_OBJECT, "EphyEditableToolbar", &our_info, 0); } return ephy_editable_toolbar_type; } static void update_popup_menu (EphyEditableToolbar *t) { EggAction *action; action = egg_action_group_get_action (t->priv->popup_action_group, "EditToolbarPopup"); g_object_set (G_OBJECT (action), "visible", !t->priv->edit_mode, NULL); action = egg_action_group_get_action (t->priv->popup_action_group, "RemoveToolbarPopup"); g_object_set (G_OBJECT (action), "visible", t->priv->edit_mode, NULL); } static EggAction * find_action (EphyEditableToolbar *t, const char *name) { GList *l = t->priv->merge->action_groups; EggAction *action = NULL; g_return_val_if_fail (IS_EPHY_EDITABLE_TOOLBAR (t), NULL); g_return_val_if_fail (name != NULL, NULL); for (; l != NULL; l = l->next) { EggAction *tmp; tmp = egg_action_group_get_action (EGG_ACTION_GROUP (l->data), name); if (tmp) action = tmp; } return action; } static char * impl_get_action_name (EphyEditableToolbar *etoolbar, const char *drag_type, const char *data) { return NULL; } static EggAction * impl_get_action (EphyEditableToolbar *etoolbar, const char *name) { EggAction *action; g_return_val_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar), NULL); action = find_action (etoolbar, name); return action; } static gboolean ui_update (gpointer data) { EphyEditableToolbar *etoolbar = EPHY_EDITABLE_TOOLBAR (data); g_return_val_if_fail (etoolbar != NULL, FALSE); if (etoolbar->priv->toolbars_dirty) { LOG ("Update ui: toolbars") do_merge (etoolbar); etoolbar->priv->toolbars_dirty = FALSE; } if (etoolbar->priv->editor_sheet_dirty) { LOG ("Update ui: editor sheet") update_editor_sheet (etoolbar); etoolbar->priv->editor_sheet_dirty = FALSE; } return FALSE; } static void queue_ui_update (EphyEditableToolbar *etoolbar) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_idle_add (ui_update, etoolbar); } static void drag_data_received_cb (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time_, EphyEditableToolbar *etoolbar) { EphyToolbarsToolbar *toolbar; EphyToolbarsToolbar *parent; EphyToolbarsItem *sibling; const char *type = NULL; GdkAtom target; EggAction *action = NULL; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); LOG ("Drag data received") toolbar = (EphyToolbarsToolbar *)g_object_get_data (G_OBJECT (widget), "toolbar_data"); if (!toolbar) { sibling = (EphyToolbarsItem *)g_object_get_data (G_OBJECT (widget), "item_data"); g_return_if_fail (sibling != NULL); parent = sibling->parent; } else { sibling = NULL; parent = toolbar; } g_return_if_fail (parent != NULL); target = gtk_drag_dest_find_target (widget, context, NULL); if (target == gdk_atom_intern (EPHY_DND_URL_TYPE, FALSE)) { type = EPHY_DND_URL_TYPE; } else if (target == gdk_atom_intern (EPHY_DND_TOPIC_TYPE, FALSE)) { type = EPHY_DND_TOPIC_TYPE; } if (type) { char *name; name = ephy_editable_toolbar_get_action_name (etoolbar, type, selection_data->data); if (name != NULL) { action = ephy_editable_toolbar_get_action (etoolbar, name); g_free (name); } } else { action = ephy_editable_toolbar_get_action (etoolbar, selection_data->data); } if (action) { ephy_toolbars_group_add_item (etoolbar->priv->group, parent, sibling, action->name); etoolbar->priv->toolbars_dirty = TRUE; queue_ui_update (etoolbar); } } static void drag_data_delete_cb (GtkWidget *widget, GdkDragContext *context, EphyEditableToolbar *etoolbar) { EphyToolbarsItem *node; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); node = (EphyToolbarsItem *)g_object_get_data (G_OBJECT (widget), "item_data"); g_return_if_fail (node != NULL); ephy_toolbars_group_remove_item (etoolbar->priv->group, node); etoolbar->priv->toolbars_dirty = TRUE; queue_ui_update (etoolbar); } static void drag_data_get_cb (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint32 time, EphyEditableToolbar *etoolbar) { EggAction *action; const char *target; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); action = EGG_ACTION (g_object_get_data (G_OBJECT (widget), "egg-action")); target = action->name; LOG ("Drag data get %s", action->name); gtk_selection_data_set (selection_data, selection_data->target, 8, target, strlen (target)); } static void toolbar_drag_data_delete_cb (GtkWidget *widget, GdkDragContext *context, EphyEditableToolbar *etoolbar) { EphyToolbarsToolbar *t; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); t = (EphyToolbarsToolbar *)g_object_get_data (G_OBJECT (widget), "toolbar_drag_data"); g_return_if_fail (t != NULL); ephy_toolbars_group_remove_toolbar (etoolbar->priv->group, t); etoolbar->priv->toolbars_dirty = TRUE; queue_ui_update (etoolbar); } static void toolbar_drag_data_get_cb (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint32 time, EphyEditableToolbar *etoolbar) { EphyToolbarsToolbar *t; char *target; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); t = (EphyToolbarsToolbar *)g_object_get_data (G_OBJECT (widget), "toolbar_drag_data"); target = t->id; LOG ("Drag data get %s", t->id); gtk_selection_data_set (selection_data, selection_data->target, 8, target, strlen (target)); } static void ephy_editable_toolbar_remove_cb (EggAction *action, EphyEditableToolbar *etoolbar) { EphyToolbarsToolbar *t; t = g_object_get_data (G_OBJECT (etoolbar), "popup_toolbar"); ephy_toolbars_group_remove_toolbar (etoolbar->priv->group, t); } static void ephy_editable_toolbar_edit_cb (EggAction *action, EphyEditableToolbar *etoolbar) { ephy_editable_toolbar_edit (etoolbar, NULL); } static GtkWidget * get_item_widget (EphyEditableToolbar *t, gpointer data) { GtkWidget *widget; char *path; path = ephy_toolbars_group_get_path (t->priv->group, data); g_return_val_if_fail (path != NULL, NULL); widget = egg_menu_merge_get_widget (t->priv->merge, path); g_free (path); return widget; } static void connect_item_drag_source (EphyToolbarsItem *item, EphyEditableToolbar *etoolbar) { GtkWidget *toolitem; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_return_if_fail (item != NULL); toolitem = get_item_widget (etoolbar, item); if (!g_object_get_data (G_OBJECT (toolitem), "drag_source_set")) { g_object_set_data (G_OBJECT (toolitem), "drag_source_set", GINT_TO_POINTER (TRUE)); g_signal_connect (toolitem, "drag_data_get", G_CALLBACK (drag_data_get_cb), etoolbar); g_signal_connect (toolitem, "drag_data_delete", G_CALLBACK (drag_data_delete_cb), etoolbar); } } static void disconnect_item_drag_source (EphyToolbarsItem *item, EphyEditableToolbar *etoolbar) { GtkWidget *toolitem; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_return_if_fail (item != NULL); toolitem = get_item_widget (etoolbar, item); if (g_object_get_data (G_OBJECT (toolitem), "drag_source_set")) { g_object_set_data (G_OBJECT (toolitem), "drag_source_set", GINT_TO_POINTER (FALSE)); g_signal_handlers_disconnect_by_func (toolitem, G_CALLBACK (drag_data_get_cb), etoolbar); g_signal_handlers_disconnect_by_func (toolitem, G_CALLBACK (drag_data_delete_cb), etoolbar); } } static void connect_toolbar_drag_source (EphyToolbarsToolbar *t, EphyEditableToolbar *etoolbar) { GtkWidget *tb; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_return_if_fail (t != NULL); tb = get_item_widget (etoolbar, t); g_return_if_fail (tb != NULL); if (!g_object_get_data (G_OBJECT (tb), "drag_source_set")) { g_object_set_data (G_OBJECT (tb), "drag_source_set", GINT_TO_POINTER (TRUE)); g_object_set_data (G_OBJECT (tb), "toolbar_drag_data", t); g_signal_connect (tb, "drag_data_get", G_CALLBACK (toolbar_drag_data_get_cb), etoolbar); g_signal_connect (tb, "drag_data_delete", G_CALLBACK (toolbar_drag_data_delete_cb), etoolbar); } } static void disconnect_toolbar_drag_source (EphyToolbarsToolbar *t, EphyEditableToolbar *etoolbar) { GtkWidget *tb; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_return_if_fail (t != NULL); tb = get_item_widget (etoolbar, t); g_return_if_fail (tb != NULL); if (g_object_get_data (G_OBJECT (tb), "drag_source_set")) { g_object_set_data (G_OBJECT (tb), "drag_source_set", GINT_TO_POINTER (FALSE)); g_signal_handlers_disconnect_by_func (tb, G_CALLBACK (toolbar_drag_data_get_cb), etoolbar); g_signal_handlers_disconnect_by_func (tb, G_CALLBACK (toolbar_drag_data_delete_cb), etoolbar); } } static void popup_toolbar_context_menu (EggToolbar *toolbar, ContextMenuData *data) { GtkWidget *widget; widget = egg_menu_merge_get_widget (data->etoolbar->priv->popup_merge, "/popups/EphyToolbarPopup"); g_object_set_data (G_OBJECT (data->etoolbar), "popup_toolbar", data->t); g_return_if_fail (widget != NULL); gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL, 2, gtk_get_current_event_time ()); } static void setup_toolbar (EphyToolbarsToolbar *toolbar, EphyEditableToolbar *etoolbar) { GtkWidget *widget; ContextMenuData *data; int signal_id; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_return_if_fail (toolbar != NULL); widget = get_item_widget (etoolbar, toolbar); g_object_set_data (G_OBJECT (widget), "toolbar_data", toolbar); if (!g_object_get_data (G_OBJECT (widget), "drag_dest_set")) { LOG ("Setup drag dest for toolbar %s", toolbar->id) g_object_set_data (G_OBJECT (widget), "drag_dest_set", GINT_TO_POINTER (TRUE)); gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_ALL, dest_drag_types, 3, GDK_ACTION_MOVE | GDK_ACTION_COPY); g_signal_connect (widget, "drag_data_received", G_CALLBACK (drag_data_received_cb), etoolbar); } if (!g_object_get_data (G_OBJECT (widget), "popup_signal_id")) { data = g_new0 (ContextMenuData, 1); data->etoolbar = etoolbar; data->t = toolbar; signal_id = g_signal_connect_data (widget, "popup_context_menu", G_CALLBACK (popup_toolbar_context_menu), data, (GClosureNotify)g_free, 0); g_object_set_data (G_OBJECT (widget), "popup_signal_id", GINT_TO_POINTER (signal_id)); } etoolbar->priv->last_toolbar = widget; } static void setup_item (EphyToolbarsItem *item, EphyEditableToolbar *etoolbar) { GtkWidget *toolitem; char *path; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_return_if_fail (item != NULL); path = ephy_toolbars_group_get_path (etoolbar->priv->group, item); g_return_if_fail (path != NULL); toolitem = get_item_widget (etoolbar, item); g_object_set_data (G_OBJECT (toolitem), "item_data", item); LOG ("Setup drag dest for toolbar item %s %p", path, toolitem); if (!g_object_get_data (G_OBJECT (toolitem), "drag_dest_set")) { g_object_set_data (G_OBJECT (toolitem), "drag_dest_set", GINT_TO_POINTER (TRUE)); gtk_drag_dest_set (toolitem, GTK_DEST_DEFAULT_ALL, dest_drag_types, 3, GDK_ACTION_COPY | GDK_ACTION_MOVE); g_signal_connect (toolitem, "drag_data_received", G_CALLBACK (drag_data_received_cb), etoolbar); } g_free (path); } static void ensure_toolbar_min_size (EphyToolbarsToolbar *toolbar, EphyEditableToolbar *t) { GtkWidget *widget; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (t)); g_return_if_fail (toolbar != NULL); widget = get_item_widget (t, toolbar); if (EGG_TOOLBAR (widget)->num_children == 0) { gtk_widget_set_size_request (widget, -1, 20); } else { gtk_widget_set_size_request (widget, -1, -1); } } static void do_merge (EphyEditableToolbar *t) { char *str; guint ui_id; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (t)); str = ephy_toolbars_group_to_string (t->priv->group); g_return_if_fail (str != NULL); LOG ("Merge UI\n%s", str) ui_id = egg_menu_merge_add_ui_from_string (t->priv->merge, str, -1, NULL); if (t->priv->ui_id != 0) { LOG ("Remove old toolbar") egg_menu_merge_remove_ui (t->priv->merge, t->priv->ui_id); } t->priv->ui_id = ui_id; egg_menu_merge_ensure_update (t->priv->merge); ephy_toolbars_group_foreach_toolbar (t->priv->group, (EphyToolbarsGroupForeachToolbarFunc) setup_toolbar, t); ephy_toolbars_group_foreach_item (t->priv->group, (EphyToolbarsGroupForeachItemFunc) setup_item, t); if (t->priv->edit_mode) { ephy_toolbars_group_foreach_item (t->priv->group, (EphyToolbarsGroupForeachItemFunc) connect_item_drag_source, t); ephy_toolbars_group_foreach_toolbar (t->priv->group, (EphyToolbarsGroupForeachToolbarFunc) connect_toolbar_drag_source, t); } ephy_toolbars_group_foreach_toolbar (t->priv->group, (EphyToolbarsGroupForeachToolbarFunc) ensure_toolbar_min_size, t); g_free (str); } static void ensure_action (EphyToolbarsItem *item, EphyEditableToolbar *t) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (t)); g_return_if_fail (item != NULL); ephy_editable_toolbar_get_action (t, item->action); } static void group_changed_cb (EphyToolbarsGroup *group, EphyEditableToolbar *t) { g_return_if_fail (IS_EPHY_TOOLBARS_GROUP (group)); g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (t)); t->priv->toolbars_dirty = TRUE; ephy_toolbars_group_foreach_item (t->priv->group, (EphyToolbarsGroupForeachItemFunc) ensure_action, t); queue_ui_update (t); } static void ephy_editable_toolbar_set_group (EphyEditableToolbar *t, EphyToolbarsGroup *group) { g_return_if_fail (IS_EPHY_TOOLBARS_GROUP (group)); g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (t)); t->priv->group = group; g_signal_connect_object (group, "changed", G_CALLBACK (group_changed_cb), t, 0); } static void ephy_editable_toolbar_set_merge (EphyEditableToolbar *t, EggMenuMerge *merge) { g_return_if_fail (EGG_IS_MENU_MERGE (merge)); g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (t)); t->priv->merge = merge; LOG ("Got MenuMerge") ephy_toolbars_group_foreach_item (t->priv->group, (EphyToolbarsGroupForeachItemFunc) ensure_action, t); do_merge (t); } static void ephy_editable_toolbar_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { EphyEditableToolbar *t = EPHY_EDITABLE_TOOLBAR (object); switch (prop_id) { case PROP_MENU_MERGE: ephy_editable_toolbar_set_merge (t, g_value_get_object (value)); break; case PROP_TOOLBARS_GROUP: ephy_editable_toolbar_set_group (t, g_value_get_object (value)); break; } } static void ephy_editable_toolbar_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { EphyEditableToolbar *t = EPHY_EDITABLE_TOOLBAR (object); switch (prop_id) { case PROP_MENU_MERGE: g_value_set_object (value, t->priv->merge); break; case PROP_TOOLBARS_GROUP: g_value_set_object (value, t->priv->group); break; } } static void ephy_editable_toolbar_class_init (EphyEditableToolbarClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); object_class->finalize = ephy_editable_toolbar_finalize; object_class->set_property = ephy_editable_toolbar_set_property; object_class->get_property = ephy_editable_toolbar_get_property; klass->get_action = impl_get_action; klass->get_action_name = impl_get_action_name; g_object_class_install_property (object_class, PROP_MENU_MERGE, g_param_spec_object ("MenuMerge", "MenuMerge", "Menu merge", EGG_TYPE_MENU_MERGE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_TOOLBARS_GROUP, g_param_spec_object ("ToolbarsGroup", "ToolbarsGroup", "Toolbars Group", EPHY_TOOLBARS_GROUP_TYPE, G_PARAM_READWRITE)); } static void ephy_editable_toolbar_init (EphyEditableToolbar *t) { int i; t->priv = g_new0 (EphyEditableToolbarPrivate, 1); t->priv->merge = NULL; t->priv->editor = NULL; t->priv->ui_id = 0; t->priv->toolbars_dirty = FALSE; t->priv->editor_sheet_dirty = FALSE; t->priv->edit_mode = FALSE; t->priv->actions_list = NULL; for (i = 0; i < ephy_toolbar_popups_n_entries; i++) { ephy_toolbar_popups[i].user_data = t; } t->priv->popup_merge = egg_menu_merge_new (); t->priv->popup_action_group = egg_action_group_new ("ToolbarPopupActions"); egg_action_group_add_actions (t->priv->popup_action_group, ephy_toolbar_popups, ephy_toolbar_popups_n_entries); egg_menu_merge_insert_action_group (t->priv->popup_merge, t->priv->popup_action_group, 0); egg_menu_merge_add_ui_from_file (t->priv->popup_merge, ephy_file ("epiphany-toolbar-popup-ui.xml"), NULL); update_popup_menu (t); } static void ephy_editable_toolbar_finalize (GObject *object) { EphyEditableToolbar *t = EPHY_EDITABLE_TOOLBAR (object); g_return_if_fail (object != NULL); g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (object)); if (t->priv->editor) { gtk_widget_destroy (t->priv->editor); } g_object_unref (t->priv->popup_action_group); egg_menu_merge_remove_action_group (t->priv->popup_merge, t->priv->popup_action_group); g_object_unref (t->priv->popup_merge); g_free (t->priv); LOG ("EphyEditableToolbar finalized") G_OBJECT_CLASS (parent_class)->finalize (object); } EphyEditableToolbar * ephy_editable_toolbar_new (EggMenuMerge *merge) { EphyEditableToolbar *t; t = EPHY_EDITABLE_TOOLBAR (g_object_new (EPHY_EDITABLE_TOOLBAR_TYPE, "MenuMerge", merge, NULL)); g_return_val_if_fail (t->priv != NULL, NULL); return t; } static void hide_editor (EphyEditableToolbar *etoolbar) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); gtk_grab_remove (GTK_WIDGET (etoolbar->priv->editor)); gtk_widget_hide (GTK_WIDGET (etoolbar->priv->editor)); } static void editor_drag_data_received_cb (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time_, EphyEditableToolbar *etoolbar) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); etoolbar->priv->editor_sheet_dirty = TRUE; queue_ui_update (etoolbar); } static void editor_drag_data_delete_cb (GtkWidget *widget, GdkDragContext *context, EphyEditableToolbar *etoolbar) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); etoolbar->priv->editor_sheet_dirty = TRUE; queue_ui_update (etoolbar); } static void editor_close (EphyEditableToolbar *etoolbar) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); etoolbar->priv->edit_mode = FALSE; ephy_toolbars_group_foreach_item (etoolbar->priv->group, (EphyToolbarsGroupForeachItemFunc) disconnect_item_drag_source, etoolbar); ephy_toolbars_group_foreach_toolbar (etoolbar->priv->group, (EphyToolbarsGroupForeachToolbarFunc) disconnect_toolbar_drag_source, etoolbar); update_popup_menu (etoolbar); hide_editor (etoolbar); } static void editor_add_toolbar (EphyEditableToolbar *etoolbar) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); ephy_toolbars_group_add_toolbar (etoolbar->priv->group); etoolbar->priv->toolbars_dirty = TRUE; queue_ui_update (etoolbar); } static void dialog_response_cb (GtkDialog *dialog, gint response_id, EphyEditableToolbar *etoolbar) { switch (response_id) { case RESPONSE_ADD_TOOLBAR: editor_add_toolbar (etoolbar); break; case GTK_RESPONSE_CLOSE: editor_close (etoolbar); break; } } static void setup_editor (EphyEditableToolbar *etoolbar, GtkWidget *window) { GtkWidget *editor; GtkWidget *scrolled_window; GtkWidget *vbox; GtkWidget *label_hbox; GtkWidget *image; GtkWidget *label; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); editor = gtk_dialog_new (), gtk_dialog_set_has_separator (GTK_DIALOG (editor), FALSE); gtk_widget_set_size_request (GTK_WIDGET (editor), 500, 330); gtk_window_set_transient_for (GTK_WINDOW (editor), GTK_WINDOW (window)); gtk_window_set_title (GTK_WINDOW (editor), "Toolbar editor"); etoolbar->priv->editor = editor; vbox = gtk_vbox_new (FALSE, 12); gtk_container_set_border_width (GTK_CONTAINER (vbox), 12); gtk_widget_show (vbox); gtk_container_add (GTK_CONTAINER (GTK_DIALOG (editor)->vbox), vbox); scrolled_window = gtk_scrolled_window_new (NULL, NULL); etoolbar->priv->scrolled_window = scrolled_window; gtk_widget_show (scrolled_window); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0); label_hbox = gtk_hbox_new (FALSE, 6); gtk_widget_show (label_hbox); gtk_box_pack_start (GTK_BOX (vbox), label_hbox, FALSE, FALSE, 0); image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG); gtk_widget_show (image); gtk_box_pack_start (GTK_BOX (label_hbox), image, FALSE, FALSE, 0); label = gtk_label_new (_("Drag an item onto the toolbars above to add it, " "from the toolbars in the items table to remove it.")); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (label_hbox), label, FALSE, TRUE, 0); gtk_dialog_add_button (GTK_DIALOG (editor), _("Add Toolbar"), RESPONSE_ADD_TOOLBAR); gtk_dialog_add_button (GTK_DIALOG (editor), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); g_signal_connect (editor, "response", G_CALLBACK (dialog_response_cb), etoolbar); update_editor_sheet (etoolbar); } static void add_to_list (EphyToolbarsItem *item, GList **l) { g_return_if_fail (item != NULL); *l = g_list_append (*l, item); } static void update_editor_sheet (EphyEditableToolbar *etoolbar) { GList *l; GList *to_drag = NULL; int x, y, height, width; GtkWidget *table; GtkWidget *viewport; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); viewport = GTK_BIN (etoolbar->priv->scrolled_window)->child; if (viewport) { table = GTK_BIN (viewport)->child; gtk_container_remove (GTK_CONTAINER (viewport), table); } table = gtk_table_new (0, 0, TRUE); etoolbar->priv->table = table; gtk_container_set_border_width (GTK_CONTAINER (table), 12); gtk_widget_show (table); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (etoolbar->priv->scrolled_window), table); gtk_drag_dest_set (table, GTK_DEST_DEFAULT_ALL, dest_drag_types, 3, GDK_ACTION_MOVE); g_signal_connect (table, "drag_data_received", G_CALLBACK (editor_drag_data_received_cb), etoolbar); ephy_toolbars_group_foreach_available (etoolbar->priv->group, (EphyToolbarsGroupForeachItemFunc) add_to_list, &to_drag); x = y = 0; width = 4; height = (g_list_length (to_drag) - 1) / width + 1; gtk_table_resize (GTK_TABLE (etoolbar->priv->table), height, width); for (l = to_drag; l != NULL; l = l->next) { GtkWidget *event_box; GtkWidget *vbox; GtkWidget *icon; GtkWidget *label; EphyToolbarsItem *node = (EphyToolbarsItem *) (l->data); EggAction *action; action = ephy_editable_toolbar_get_action (etoolbar, node->action); g_return_if_fail (action != NULL); event_box = gtk_event_box_new (); gtk_widget_show (event_box); gtk_drag_source_set (event_box, GDK_BUTTON1_MASK, source_drag_types, 1, GDK_ACTION_MOVE); g_signal_connect (event_box, "drag_data_get", G_CALLBACK (drag_data_get_cb), etoolbar); g_signal_connect (event_box, "drag_data_delete", G_CALLBACK (editor_drag_data_delete_cb), etoolbar); g_object_set_data (G_OBJECT (event_box), "egg-action", action); vbox = gtk_vbox_new (0, FALSE); gtk_widget_show (vbox); gtk_container_add (GTK_CONTAINER (event_box), vbox); icon = gtk_image_new_from_stock (action->stock_id ? action->stock_id : GTK_STOCK_DND, GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_widget_show (icon); gtk_box_pack_start (GTK_BOX (vbox), icon, FALSE, TRUE, 0); label = gtk_label_new_with_mnemonic (action->label); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); gtk_table_attach_defaults (GTK_TABLE (etoolbar->priv->table), event_box, x, x + 1, y, y + 1); x ++; if (x >= width) { x = 0; y++; } } g_list_free (to_drag); } static gboolean button_press_cb (GtkWidget *w, GdkEvent *event, EphyEditableToolbar *etoolbar) { GtkWidget *widget; GtkWidget *toolitem; g_return_val_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar), FALSE); widget = gtk_get_event_widget (event); toolitem = gtk_widget_get_ancestor (widget, EGG_TYPE_TOOL_ITEM); if (toolitem == NULL && event->type == GDK_BUTTON_PRESS && EGG_IS_TOOLBAR (widget)) { if (event->button.button == 3) { gtk_widget_event (widget, event); return FALSE; } else { gtk_drag_begin (widget, gtk_target_list_new (source_drag_types, 1), GDK_ACTION_MOVE, 1, event); return TRUE; } } else if (toolitem == NULL) return FALSE; switch (event->type) { case GDK_BUTTON_PRESS: gtk_drag_begin (toolitem, gtk_target_list_new (source_drag_types, 1), GDK_ACTION_MOVE, 1, event); return TRUE; default: break; } return FALSE; } static void show_editor (EphyEditableToolbar *etoolbar) { GtkWidget *editor = etoolbar->priv->editor; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_return_if_fail (editor != NULL); gtk_widget_show (GTK_WIDGET (editor)); gtk_grab_add (editor); g_signal_connect (editor, "button_press_event", G_CALLBACK (button_press_cb), etoolbar); } static void set_action_sensitive (EphyToolbarsItem *item, EphyEditableToolbar *etoolbar) { EggAction *action; g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); g_return_if_fail (item != NULL); if (!item->separator) { action = find_action (etoolbar, item->action); g_object_set (action, "sensitive", TRUE, NULL); } } void ephy_editable_toolbar_edit (EphyEditableToolbar *etoolbar, GtkWidget *window) { g_return_if_fail (IS_EPHY_EDITABLE_TOOLBAR (etoolbar)); etoolbar->priv->edit_mode = TRUE; ephy_toolbars_group_foreach_item (etoolbar->priv->group, (EphyToolbarsGroupForeachItemFunc) connect_item_drag_source, etoolbar); ephy_toolbars_group_foreach_item (etoolbar->priv->group, (EphyToolbarsGroupForeachItemFunc) set_action_sensitive, etoolbar); ephy_toolbars_group_foreach_toolbar (etoolbar->priv->group, (EphyToolbarsGroupForeachToolbarFunc) connect_toolbar_drag_source, etoolbar); update_popup_menu (etoolbar); setup_editor (etoolbar, window); show_editor (etoolbar); } char * ephy_editable_toolbar_get_action_name (EphyEditableToolbar *etoolbar, const char *drag_type, const char *data) { EphyEditableToolbarClass *klass = EPHY_EDITABLE_TOOLBAR_GET_CLASS (etoolbar); return klass->get_action_name (etoolbar, drag_type, data); } EggAction * ephy_editable_toolbar_get_action (EphyEditableToolbar *etoolbar, const char *name) { EphyEditableToolbarClass *klass = EPHY_EDITABLE_TOOLBAR_GET_CLASS (etoolbar); return klass->get_action (etoolbar, name); }