From 184fd329e9a52df566130c7526f8612eb0a399ee Mon Sep 17 00:00:00 2001 From: Nickolay V. Shmyrev Date: Fri, 26 May 2006 06:46:29 +0000 Subject: Sync toolbareditor with epiphany and libegg * cut-n-paste/toolbar-editor/Makefile.am: * cut-n-paste/toolbar-editor/egg-editable-toolbar.c: (get_dock_position), (get_toolbar_position), (get_toolbar_nth), (find_action), (drag_data_delete_cb), (drag_begin_cb), (drag_end_cb), (drag_data_get_cb), (move_item_cb), (remove_item_cb), (remove_toolbar_cb), (popup_context_deactivate), (popup_context_menu_cb), (button_press_event_cb), (configure_item_sensitivity), (configure_item_cursor), (configure_item_tooltip), (connect_widget_signals), (action_sensitive_cb), (create_item_from_action), (create_item_from_position), (toolbar_drag_data_received_cb), (toolbar_drag_drop_cb), (toolbar_drag_motion_cb), (toolbar_drag_leave_cb), (configure_drag_dest), (toggled_visibility_cb), (toolbar_visibility_refresh), (create_dock), (toolbar_changed_cb), (unparent_fixed), (update_fixed), (toolbar_added_cb), (toolbar_removed_cb), (item_added_cb), (item_removed_cb), (egg_editable_toolbar_build), (egg_editable_toolbar_set_model), (egg_editable_toolbar_init), (egg_editable_toolbar_dispose), (egg_editable_toolbar_set_ui_manager), (egg_editable_toolbar_get_selected), (egg_editable_toolbar_set_selected), (set_edit_mode), (egg_editable_toolbar_set_property), (egg_editable_toolbar_get_property), (egg_editable_toolbar_class_init), (egg_editable_toolbar_new), (egg_editable_toolbar_new_with_model), (egg_editable_toolbar_get_edit_mode), (egg_editable_toolbar_set_edit_mode), (egg_editable_toolbar_add_visibility), (egg_editable_toolbar_show), (egg_editable_toolbar_hide), (egg_editable_toolbar_set_fixed): * cut-n-paste/toolbar-editor/egg-editable-toolbar.h: * cut-n-paste/toolbar-editor/egg-toolbar-editor.c: (compare_items), (item_added_or_removed_cb), (toolbar_removed_cb), (egg_toolbar_editor_set_model), (egg_toolbar_editor_class_init), (egg_toolbar_editor_finalize), (drag_begin_cb), (drag_end_cb), (drag_data_get_cb), (set_drag_cursor), (editor_create_item), (editor_create_item_from_name), (append_table), (update_editor_sheet), (egg_toolbar_editor_init): * cut-n-paste/toolbar-editor/egg-toolbar-editor.h: * cut-n-paste/toolbar-editor/egg-toolbars-model.c: (egg_toolbars_model_to_xml), (egg_toolbars_model_save_toolbars), (is_unique), (toolbar_node_new), (item_node_new), (item_node_free), (toolbar_node_free), (egg_toolbars_model_get_flags), (egg_toolbars_model_set_flags), (egg_toolbars_model_get_data), (egg_toolbars_model_get_name), (impl_add_item), (egg_toolbars_model_add_item), (egg_toolbars_model_add_toolbar), (parse_data_list), (parse_item_list), (parse_toolbars), (egg_toolbars_model_load_toolbars), (parse_available_list), (parse_names), (egg_toolbars_model_load_names), (egg_toolbars_model_class_init), (egg_toolbars_model_init), (egg_toolbars_model_finalize), (egg_toolbars_model_remove_toolbar), (egg_toolbars_model_remove_item), (egg_toolbars_model_move_item), (egg_toolbars_model_delete_item), (egg_toolbars_model_n_items), (egg_toolbars_model_item_nth), (egg_toolbars_model_n_toolbars), (egg_toolbars_model_toolbar_nth), (egg_toolbars_model_get_types), (egg_toolbars_model_set_types), (fill_avail_array), (egg_toolbars_model_get_name_avail), (egg_toolbars_model_get_name_flags), (egg_toolbars_model_set_name_flags): * cut-n-paste/toolbar-editor/egg-toolbars-model.h: * cut-n-paste/toolbar-editor/eggintl.h: * cut-n-paste/toolbar-editor/eggtreemultidnd.c: (egg_tree_multi_drag_source_get_type), (egg_tree_multi_drag_source_row_draggable), (egg_tree_multi_drag_source_drag_data_delete), (egg_tree_multi_drag_source_drag_data_get), (stop_drag_check), (egg_tree_multi_drag_button_release_event), (selection_foreach), (path_list_free), (set_context_data), (get_context_data), (get_info), (egg_tree_multi_drag_drag_data_get), (egg_tree_multi_drag_motion_event), (egg_tree_multi_drag_button_press_event), (egg_tree_multi_drag_add_drag_support): * cut-n-paste/toolbar-editor/eggtreemultidnd.h: * shell/ev-application.c: (ev_application_init), (ev_application_save_toolbars_model): * shell/ev-window.c: (ev_window_create_fullscreen_popup), (ev_window_cmd_edit_toolbar), (ev_window_init): Sync toolbareditor with epiphany and libegg --- (limited to 'cut-n-paste') diff --git a/cut-n-paste/toolbar-editor/Makefile.am b/cut-n-paste/toolbar-editor/Makefile.am index fe172f8..2d1614c 100644 --- a/cut-n-paste/toolbar-editor/Makefile.am +++ b/cut-n-paste/toolbar-editor/Makefile.am @@ -10,8 +10,7 @@ EGGHEADERS = \ noinst_HEADERS = \ $(EGGHEADERS) \ - eggmarshalers.h \ - eggintl.h + eggmarshalers.h noinst_LTLIBRARIES = libtoolbareditor.la diff --git a/cut-n-paste/toolbar-editor/egg-editable-toolbar.c b/cut-n-paste/toolbar-editor/egg-editable-toolbar.c index 006df26..b7fa095 100644 --- a/cut-n-paste/toolbar-editor/egg-editable-toolbar.c +++ b/cut-n-paste/toolbar-editor/egg-editable-toolbar.c @@ -32,20 +32,27 @@ #include #include #include +#include +#include #include +#include #include #include +#include +#include #include #include +#include #include #include #include static void egg_editable_toolbar_class_init (EggEditableToolbarClass *klass); -static void egg_editable_toolbar_init (EggEditableToolbar *t); -static void egg_editable_toolbar_finalize (GObject *object); +static void egg_editable_toolbar_init (EggEditableToolbar *etoolbar); #define MIN_TOOLBAR_HEIGHT 20 +#define EGG_ITEM_NAME "egg-item-name" +#define STOCK_DRAG_MODE "stock_drag-mode" static const GtkTargetEntry dest_drag_types[] = { {EGG_TOOLBAR_ITEM_TYPE, GTK_TARGET_SAME_APP, 0}, @@ -55,7 +62,10 @@ enum { PROP_0, PROP_TOOLBARS_MODEL, - PROP_UI_MANAGER + PROP_UI_MANAGER, + PROP_POPUP_PATH, + PROP_SELECTED, + PROP_EDIT_MODE }; enum @@ -74,13 +84,22 @@ struct _EggEditableToolbarPrivate { GtkUIManager *manager; EggToolbarsModel *model; - gboolean edit_mode; - GtkWidget *selected_toolbar; + guint edit_mode; + gboolean save_hidden; GtkWidget *fixed_toolbar; + + GtkWidget *selected; + GtkActionGroup *actions; + + guint visibility_id; + GList *visibility_paths; + GPtrArray *visibility_actions; - gboolean pending; - GtkToolbar *target_toolbar; - GtkWidget *dragged_item; + char *popup_path; + + guint dnd_pending; + GtkToolbar *dnd_toolbar; + GtkToolItem *dnd_toolitem; }; GType @@ -111,19 +130,26 @@ egg_editable_toolbar_get_type (void) } static int -get_toolbar_position (EggEditableToolbar *etoolbar, GtkWidget *toolbar) +get_dock_position (EggEditableToolbar *etoolbar, + GtkWidget *dock) { GList *l; int result; l = gtk_container_get_children (GTK_CONTAINER (etoolbar)); - result = g_list_index (l, toolbar->parent); + result = g_list_index (l, dock); g_list_free (l); return result; } static int +get_toolbar_position (EggEditableToolbar *etoolbar, GtkWidget *toolbar) +{ + return get_dock_position (etoolbar, toolbar->parent); +} + +static int get_n_toolbars (EggEditableToolbar *etoolbar) { GList *l; @@ -159,6 +185,7 @@ get_toolbar_nth (EggEditableToolbar *etoolbar, GtkWidget *result; dock = get_dock_nth (etoolbar, position); + g_return_val_if_fail (dock != NULL, NULL); l = gtk_container_get_children (GTK_CONTAINER (dock)); result = GTK_WIDGET (l->data); @@ -168,13 +195,13 @@ get_toolbar_nth (EggEditableToolbar *etoolbar, } static GtkAction * -find_action (EggEditableToolbar *t, +find_action (EggEditableToolbar *etoolbar, const char *name) { GList *l; GtkAction *action = NULL; - l = gtk_ui_manager_get_action_groups (t->priv->manager); + l = gtk_ui_manager_get_action_groups (etoolbar->priv->manager); g_return_val_if_fail (name != NULL, NULL); @@ -197,6 +224,8 @@ drag_data_delete_cb (GtkWidget *widget, { int pos, toolbar_pos; + widget = gtk_widget_get_ancestor (widget, GTK_TYPE_TOOL_ITEM); + g_return_if_fail (widget != NULL); g_return_if_fail (EGG_IS_EDITABLE_TOOLBAR (etoolbar)); pos = gtk_toolbar_get_item_index (GTK_TOOLBAR (widget->parent), @@ -204,7 +233,7 @@ drag_data_delete_cb (GtkWidget *widget, toolbar_pos = get_toolbar_position (etoolbar, widget->parent); egg_toolbars_model_remove_item (etoolbar->priv->model, - toolbar_pos, pos); + toolbar_pos, pos); } static void @@ -212,7 +241,23 @@ drag_begin_cb (GtkWidget *widget, GdkDragContext *context, EggEditableToolbar *etoolbar) { - gtk_widget_hide (widget); + GtkAction *action; + gint flags; + + gtk_widget_hide (widget); + + action = g_object_get_data (G_OBJECT (widget), "gtk-action"); + if (action == NULL) return; + + flags = egg_toolbars_model_get_name_flags (etoolbar->priv->model, + gtk_action_get_name (action)); + if (!(flags & EGG_TB_MODEL_NAME_INFINITE)) + { + flags &= ~EGG_TB_MODEL_NAME_USED; + egg_toolbars_model_set_name_flags (etoolbar->priv->model, + gtk_action_get_name (action), + flags); + } } static void @@ -220,7 +265,26 @@ drag_end_cb (GtkWidget *widget, GdkDragContext *context, EggEditableToolbar *etoolbar) { - gtk_widget_show (widget); + GtkAction *action; + gint flags; + + if (gtk_widget_get_parent (widget) != NULL) + { + gtk_widget_show (widget); + + action = g_object_get_data (G_OBJECT (widget), "gtk-action"); + if (action == NULL) return; + + flags = egg_toolbars_model_get_name_flags (etoolbar->priv->model, + gtk_action_get_name (action)); + if (!(flags & EGG_TB_MODEL_NAME_INFINITE)) + { + flags |= EGG_TB_MODEL_NAME_USED; + egg_toolbars_model_set_name_flags (etoolbar->priv->model, + gtk_action_get_name (action), + flags); + } + } } static void @@ -231,223 +295,310 @@ drag_data_get_cb (GtkWidget *widget, guint32 time, EggEditableToolbar *etoolbar) { - const char *id, *type; - char *target; + EggToolbarsModel *model; + const char *name; + char *data; g_return_if_fail (EGG_IS_EDITABLE_TOOLBAR (etoolbar)); - - type = g_object_get_data (G_OBJECT (widget), "type"); - id = g_object_get_data (G_OBJECT (widget), "id"); - if (strcmp (id, "separator") == 0) + model = egg_editable_toolbar_get_model (etoolbar); + + name = g_object_get_data (G_OBJECT (widget), EGG_ITEM_NAME); + if (name == NULL) { - target = g_strdup (id); + name = g_object_get_data (G_OBJECT (gtk_widget_get_parent (widget)), EGG_ITEM_NAME); + g_return_if_fail (name != NULL); } - else + + data = egg_toolbars_model_get_data (model, selection_data->target, name); + if (data != NULL) { - target = egg_toolbars_model_get_item_data (etoolbar->priv->model, - type, id); + gtk_selection_data_set (selection_data, selection_data->target, 8, (unsigned char *)data, strlen (data)); + g_free (data); } - - gtk_selection_data_set (selection_data, - selection_data->target, 8, - (const guchar *)target, strlen (target)); - - g_free (target); } static void -set_drag_cursor (GtkWidget *widget) +move_item_cb (GtkAction *action, + EggEditableToolbar *etoolbar) { - if (widget->window) - { - GdkCursor *cursor; - GdkPixbuf *pixbuf; - - pixbuf = gdk_pixbuf_new_from_file (CURSOR_DIR "/hand-open.png", NULL); - cursor = gdk_cursor_new_from_pixbuf (gdk_display_get_default (), - pixbuf, 12, 12); - gdk_window_set_cursor (widget->window, cursor); - gdk_cursor_unref (cursor); - g_object_unref (pixbuf); - } + GtkWidget *toolitem = gtk_widget_get_ancestor (egg_editable_toolbar_get_selected (etoolbar), GTK_TYPE_TOOL_ITEM); + GtkTargetList *list = gtk_target_list_new (dest_drag_types, G_N_ELEMENTS (dest_drag_types)); + + GdkEvent *realevent = gtk_get_current_event(); + GdkEventMotion event; + event.type = GDK_MOTION_NOTIFY; + event.window = realevent->any.window; + event.send_event = FALSE; + event.axes = NULL; + event.time = gdk_event_get_time (realevent); + gdk_event_get_state (realevent, &event.state); + gdk_event_get_coords (realevent, &event.x, &event.y); + gdk_event_get_root_coords (realevent, &event.x_root, &event.y_root); + + gtk_drag_begin (toolitem, list, GDK_ACTION_MOVE, 1, (GdkEvent *)&event); + gtk_target_list_unref (list); } static void -unset_drag_cursor (GtkWidget *widget) +remove_item_cb (GtkAction *action, + EggEditableToolbar *etoolbar) { - if (widget->window) + GtkWidget *toolitem = gtk_widget_get_ancestor (egg_editable_toolbar_get_selected (etoolbar), GTK_TYPE_TOOL_ITEM); + int pos, toolbar_pos; + + toolbar_pos = get_toolbar_position (etoolbar, toolitem->parent); + pos = gtk_toolbar_get_item_index (GTK_TOOLBAR (toolitem->parent), + GTK_TOOL_ITEM (toolitem)); + + egg_toolbars_model_remove_item (etoolbar->priv->model, + toolbar_pos, pos); + + if (egg_toolbars_model_n_items (etoolbar->priv->model, toolbar_pos) == 0) { - gdk_window_set_cursor (widget->window, NULL); + egg_toolbars_model_remove_toolbar (etoolbar->priv->model, toolbar_pos); } } static void -set_item_drag_source (EggToolbarsModel *model, - GtkWidget *item, - GtkAction *action, - gboolean is_separator, - const char *type) +remove_toolbar_cb (GtkAction *action, + EggEditableToolbar *etoolbar) { - GtkTargetEntry target_entry; - const char *id; + GtkWidget *selected = egg_editable_toolbar_get_selected (etoolbar); + GtkWidget *toolbar = gtk_widget_get_ancestor (selected, GTK_TYPE_TOOLBAR); + int toolbar_pos; - target_entry.target = (char *)type; - target_entry.flags = GTK_TARGET_SAME_APP; - target_entry.info = 0; + toolbar_pos = get_toolbar_position (etoolbar, toolbar); + egg_toolbars_model_remove_toolbar (etoolbar->priv->model, toolbar_pos); +} - gtk_drag_source_set (item, GDK_BUTTON1_MASK, - &target_entry, 1, - GDK_ACTION_MOVE); +static void +popup_context_deactivate (GtkMenuShell *menu, + EggEditableToolbar *etoolbar) +{ + egg_editable_toolbar_set_selected (etoolbar, NULL); + g_object_notify (G_OBJECT (etoolbar), "selected"); +} - if (is_separator) +static void +popup_context_menu_cb (GtkWidget *toolbar, + gint x, + gint y, + gint button_number, + EggEditableToolbar *etoolbar) +{ + if (etoolbar->priv->popup_path != NULL) { - GtkWidget *icon; - GdkPixbuf *pixbuf; - - id = "separator"; + GtkMenu *menu; + + egg_editable_toolbar_set_selected (etoolbar, toolbar); + g_object_notify (G_OBJECT (etoolbar), "selected"); + + menu = GTK_MENU (gtk_ui_manager_get_widget (etoolbar->priv->manager, + etoolbar->priv->popup_path)); + g_return_if_fail (menu != NULL); + gtk_menu_popup (menu, NULL, NULL, NULL, NULL, button_number, gtk_get_current_event_time ()); + g_signal_connect_object (menu, "selection-done", + G_CALLBACK (popup_context_deactivate), + etoolbar, 0); + } +} - icon = _egg_editable_toolbar_new_separator_image (); - pixbuf = gtk_image_get_pixbuf (GTK_IMAGE (icon)); - gtk_drag_source_set_icon_pixbuf (item, pixbuf); +static gboolean +button_press_event_cb (GtkWidget *widget, + GdkEventButton *event, + EggEditableToolbar *etoolbar) +{ + if (event->button == 3 && etoolbar->priv->popup_path != NULL) + { + GtkMenu *menu; + + egg_editable_toolbar_set_selected (etoolbar, widget); + g_object_notify (G_OBJECT (etoolbar), "selected"); + + menu = GTK_MENU (gtk_ui_manager_get_widget (etoolbar->priv->manager, + etoolbar->priv->popup_path)); + g_return_val_if_fail (menu != NULL, FALSE); + gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button, event->time); + g_signal_connect_object (menu, "selection-done", + G_CALLBACK (popup_context_deactivate), + etoolbar, 0); + + return TRUE; } - else + + return FALSE; +} + +static void +configure_item_sensitivity (GtkToolItem *item, EggEditableToolbar *etoolbar) +{ + GtkAction *action; + char *name; + + name = g_object_get_data (G_OBJECT (item), EGG_ITEM_NAME); + action = name ? find_action (etoolbar, name) : NULL; + + if (action) { - const char *stock_id; - GValue value = { 0, }; - GdkPixbuf *pixbuf; + g_object_notify (G_OBJECT (action), "sensitive"); + } - id = gtk_action_get_name (action); + gtk_tool_item_set_use_drag_window (item, + (etoolbar->priv->edit_mode > 0) || + GTK_IS_SEPARATOR_TOOL_ITEM (item)); + +} - g_value_init (&value, G_TYPE_STRING); - g_object_get_property (G_OBJECT (action), "stock_id", &value); - stock_id = g_value_get_string (&value); +static void +configure_item_cursor (GtkToolItem *item, + EggEditableToolbar *etoolbar) +{ + EggEditableToolbarPrivate *priv = etoolbar->priv; + GtkWidget *widget = GTK_WIDGET (item); - if (stock_id != NULL) + if (widget->window != NULL) + { + if (priv->edit_mode > 0) { - pixbuf = gtk_widget_render_icon (item, stock_id, - GTK_ICON_SIZE_LARGE_TOOLBAR, NULL); + GdkCursor *cursor; + + cursor = gdk_cursor_new (GDK_HAND2); + gdk_window_set_cursor (widget->window, cursor); + gdk_cursor_unref (cursor); + + gtk_drag_source_set (widget, GDK_BUTTON1_MASK, dest_drag_types, + G_N_ELEMENTS (dest_drag_types), GDK_ACTION_MOVE); } else { - pixbuf = gtk_widget_render_icon (item, GTK_STOCK_DND, - GTK_ICON_SIZE_LARGE_TOOLBAR, NULL); + gdk_window_set_cursor (GTK_WIDGET(item)->window, NULL); } + } +} - gtk_drag_source_set_icon_pixbuf (item, pixbuf); - g_object_unref (pixbuf); - g_value_unset (&value); +static void +configure_item_tooltip (GtkToolItem *item) +{ + GtkAction *action = g_object_get_data (G_OBJECT (item), + "gtk-action"); + + if (action != NULL) + { + g_object_notify (G_OBJECT (action), "tooltip"); } - - g_object_set_data_full (G_OBJECT (item), "id", - g_strdup (id), g_free); - g_object_set_data_full (G_OBJECT (item), "type", - g_strdup (type), g_free); } -static GtkWidget * -create_item_from_action (EggEditableToolbar *t, - const char *action_name, - const char *type, - gboolean is_separator, - GtkAction **ret_action) + +static void +connect_widget_signals (GtkWidget *proxy, EggEditableToolbar *etoolbar) { - GtkWidget *item; - GtkAction *action; + if (GTK_IS_CONTAINER (proxy)) + { + gtk_container_forall (GTK_CONTAINER (proxy), + (GtkCallback) connect_widget_signals, + (gpointer) etoolbar); + } - if (is_separator) + if (GTK_IS_TOOL_ITEM (proxy)) { - item = GTK_WIDGET (gtk_separator_tool_item_new ()); - action = NULL; + g_signal_connect_object (proxy, "drag_begin", + G_CALLBACK (drag_begin_cb), + etoolbar, 0); + g_signal_connect_object (proxy, "drag_end", + G_CALLBACK (drag_end_cb), + etoolbar, 0); + g_signal_connect_object (proxy, "drag_data_get", + G_CALLBACK (drag_data_get_cb), + etoolbar, 0); + g_signal_connect_object (proxy, "drag_data_delete", + G_CALLBACK (drag_data_delete_cb), + etoolbar, 0); } - else + + if (GTK_IS_BUTTON (proxy) || GTK_IS_TOOL_ITEM (proxy)) { - g_return_val_if_fail (action_name != NULL, NULL); + g_signal_connect_object (proxy, "button-press-event", + G_CALLBACK (button_press_event_cb), + etoolbar, 0); + } +} - g_signal_emit (G_OBJECT (t), egg_editable_toolbar_signals[ACTION_REQUEST], - 0, action_name); +static void +action_sensitive_cb (GtkAction *action, + GParamSpec *pspec, + GtkToolItem *item) +{ + EggEditableToolbar *etoolbar = EGG_EDITABLE_TOOLBAR + (gtk_widget_get_ancestor (GTK_WIDGET (item), EGG_TYPE_EDITABLE_TOOLBAR)); - action = find_action (t, action_name); - if (action) - { - item = gtk_action_create_tool_item (action); - } - else - { - return NULL; - } + if (etoolbar->priv->edit_mode > 0) + { + gtk_widget_set_sensitive (GTK_WIDGET (item), TRUE); } +} - gtk_widget_show (item); - - g_signal_connect (item, "drag_begin", - G_CALLBACK (drag_begin_cb), t); - g_signal_connect (item, "drag_end", - G_CALLBACK (drag_end_cb), t); - g_signal_connect (item, "drag_data_get", - G_CALLBACK (drag_data_get_cb), t); - g_signal_connect (item, "drag_data_delete", - G_CALLBACK (drag_data_delete_cb), t); +static GtkToolItem * +create_item_from_action (EggEditableToolbar *etoolbar, + const char *name) +{ + GtkToolItem *item; - if (t->priv->edit_mode) + g_return_val_if_fail (name != NULL, NULL); + + if (strcmp (name, "_separator") == 0) { - set_drag_cursor (item); - gtk_widget_set_sensitive (item, TRUE); - set_item_drag_source (t->priv->model, item, action, - is_separator, type); - gtk_tool_item_set_use_drag_window (GTK_TOOL_ITEM (item), TRUE); + item = gtk_separator_tool_item_new (); } - - if (ret_action) + else { - *ret_action = action; + GtkAction *action = find_action (etoolbar, name); + if (action == NULL) return NULL; + + item = GTK_TOOL_ITEM (gtk_action_create_tool_item (action)); + + /* Normally done on-demand by the GtkUIManager, but no + * such demand may have been made yet, so do it ourselves. + */ + gtk_action_set_accel_group + (action, gtk_ui_manager_get_accel_group(etoolbar->priv->manager)); + + g_signal_connect_object (action, "notify::sensitive", + G_CALLBACK (action_sensitive_cb), item, 0); } + gtk_widget_show (GTK_WIDGET (item)); + + g_object_set_data_full (G_OBJECT (item), EGG_ITEM_NAME, + g_strdup (name), g_free); + return item; } -static GtkWidget * -create_item (EggEditableToolbar *t, - EggToolbarsModel *model, - int toolbar_position, - int position, - GtkAction **ret_action) +static GtkToolItem * +create_item_from_position (EggEditableToolbar *etoolbar, + int toolbar_position, + int position) { - const char *action_name, *type; - gboolean is_separator; + GtkToolItem *item; + const char *name; - egg_toolbars_model_item_nth (model, toolbar_position, position, - &is_separator, &action_name, &type); - return create_item_from_action (t, action_name, type, - is_separator, ret_action); -} + name = egg_toolbars_model_item_nth (etoolbar->priv->model, toolbar_position, position); + item = create_item_from_action (etoolbar, name); -static gboolean -data_is_separator (const char *data) -{ - return strcmp (data, "separator") == 0; + return item; } static void -drag_data_received_cb (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection_data, - guint info, - guint time, - EggEditableToolbar *etoolbar) +toolbar_drag_data_received_cb (GtkToolbar *toolbar, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time, + EggEditableToolbar *etoolbar) { - char *type; - char *id; - - GdkAtom target; - - target = gtk_drag_dest_find_target (widget, context, NULL); - type = egg_toolbars_model_get_item_type (etoolbar->priv->model, target); - id = egg_toolbars_model_get_item_id (etoolbar->priv->model, type, - (const char*)selection_data->data); - /* This function can be called for two reasons * * (1) drag_motion() needs an item to pass to @@ -459,113 +610,65 @@ drag_data_received_cb (GtkWidget *widget, * actually add a new item to the toolbar. */ - if (id == NULL) - { - etoolbar->priv->pending = FALSE; - g_free (type); - return; - } - - if (etoolbar->priv->pending) - { - etoolbar->priv->pending = FALSE; - etoolbar->priv->dragged_item = - create_item_from_action (etoolbar, id, type, - data_is_separator (id), NULL); - g_object_ref (etoolbar->priv->dragged_item); - gtk_object_sink (GTK_OBJECT (etoolbar->priv->dragged_item)); - } - else + GdkAtom type = selection_data->type; + const char *data = (char *)selection_data->data; + + int ipos = -1; + char *name = NULL; + gboolean used = FALSE; + + /* Find out where the drop is occuring, and the name of what is being dropped. */ + if (selection_data->length >= 0) { - int pos, toolbar_pos; - - pos = gtk_toolbar_get_drop_index (GTK_TOOLBAR (widget), x, y); - toolbar_pos = get_toolbar_position (etoolbar, widget); - - if (data_is_separator ((const char*)selection_data->data)) - { - egg_toolbars_model_add_separator (etoolbar->priv->model, - toolbar_pos, pos); - } - else + ipos = gtk_toolbar_get_drop_index (toolbar, x, y); + name = egg_toolbars_model_get_name (etoolbar->priv->model, type, data, FALSE); + if (name != NULL) { - egg_toolbars_model_add_item (etoolbar->priv->model, - toolbar_pos, pos, id, type); - } - - gtk_drag_finish (context, TRUE, context->action == GDK_ACTION_MOVE, - time); + used = ((egg_toolbars_model_get_name_flags (etoolbar->priv->model, name) & EGG_TB_MODEL_NAME_USED) != 0); + } } - g_free (type); - g_free (id); -} - -static void -remove_toolbar_cb (GtkWidget *menuitem, - EggEditableToolbar *etoolbar) -{ - int pos; - - pos = get_toolbar_position (etoolbar, etoolbar->priv->selected_toolbar); - egg_toolbars_model_remove_toolbar (etoolbar->priv->model, pos); -} - -static void -popup_toolbar_context_menu_cb (GtkWidget *toolbar, - gint x, - gint y, - gint button_number, - EggEditableToolbar *t) -{ - GtkWidget *menu; - GtkWidget *item; - GtkWidget *image; - - if (t->priv->edit_mode) + /* If we just want a highlight item, then . */ + if (etoolbar->priv->dnd_pending > 0) { - EggTbModelFlags flags; - int position; - - t->priv->selected_toolbar = toolbar; - - menu = gtk_menu_new (); - - item = gtk_image_menu_item_new_with_mnemonic (_("_Remove Toolbar")); - gtk_widget_show (item); - image = gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU); - gtk_widget_show (image); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - g_signal_connect (item, "activate", - G_CALLBACK (remove_toolbar_cb), - t); - - position = get_toolbar_position (t, toolbar); - flags = egg_toolbars_model_get_flags (t->priv->model, position); - if (flags & EGG_TB_MODEL_NOT_REMOVABLE) + etoolbar->priv->dnd_pending--; + + if (name != NULL && etoolbar->priv->dnd_toolbar == toolbar && !used) { - gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE); + etoolbar->priv->dnd_toolitem = create_item_from_action (etoolbar, name); + gtk_toolbar_set_drop_highlight_item (etoolbar->priv->dnd_toolbar, + etoolbar->priv->dnd_toolitem, ipos); } - - gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 2, - gtk_get_current_event_time ()); } -} - -static void -free_dragged_item (EggEditableToolbar *etoolbar) -{ - if (etoolbar->priv->dragged_item) + else { - gtk_widget_destroy (etoolbar->priv->dragged_item); - g_object_unref (etoolbar->priv->dragged_item); - etoolbar->priv->dragged_item = NULL; + gtk_toolbar_set_drop_highlight_item (toolbar, NULL, 0); + etoolbar->priv->dnd_toolbar = NULL; + etoolbar->priv->dnd_toolitem = NULL; + + /* If we don't have a name to use yet, try to create one. */ + if (name == NULL && selection_data->length >= 0) + { + name = egg_toolbars_model_get_name (etoolbar->priv->model, type, data, TRUE); + } + + if (name != NULL && !used) + { + gint tpos = get_toolbar_position (etoolbar, GTK_WIDGET (toolbar)); + egg_toolbars_model_add_item (etoolbar->priv->model, tpos, ipos, name); + gtk_drag_finish (context, TRUE, context->action == GDK_ACTION_MOVE, time); + } + else + { + gtk_drag_finish (context, FALSE, context->action == GDK_ACTION_MOVE, time); + } } + + g_free (name); } static gboolean -toolbar_drag_drop_cb (GtkWidget *widget, +toolbar_drag_drop_cb (GtkToolbar *toolbar, GdkDragContext *context, gint x, gint y, @@ -574,88 +677,46 @@ toolbar_drag_drop_cb (GtkWidget *widget, { GdkAtom target; - target = gtk_drag_dest_find_target (widget, context, NULL); + target = gtk_drag_dest_find_target (GTK_WIDGET (toolbar), context, NULL); if (target != GDK_NONE) { - gtk_drag_get_data (widget, context, - target, - time); + gtk_drag_get_data (GTK_WIDGET (toolbar), context, target, time); return TRUE; } - free_dragged_item (etoolbar); - return FALSE; } static gboolean -toolbar_drag_motion_cb (GtkWidget *widget, +toolbar_drag_motion_cb (GtkToolbar *toolbar, GdkDragContext *context, gint x, gint y, guint time, EggEditableToolbar *etoolbar) { - GdkAtom target; - int index; - GtkToolbar *toolbar = GTK_TOOLBAR (widget); - GtkToolItem *item; - GtkWidget *source; - - source = gtk_drag_get_source_widget (context); - if (source) - { - EggTbModelFlags flags; - int pos; - gboolean is_item; - - pos = get_toolbar_position (etoolbar, widget); - flags = egg_toolbars_model_get_flags (etoolbar->priv->model, pos); - - is_item = etoolbar->priv->edit_mode && - (gtk_widget_get_ancestor (source, EGG_TYPE_EDITABLE_TOOLBAR) || - gtk_widget_get_ancestor (source, EGG_TYPE_TOOLBAR_EDITOR)); - - if ((flags & EGG_TB_MODEL_ACCEPT_ITEMS_ONLY) && !is_item) - { - gdk_drag_status (context, 0, time); - return FALSE; - } - - if (gtk_widget_is_ancestor (source, widget)) - { - context->suggested_action = GDK_ACTION_MOVE; - } - } - - target = gtk_drag_dest_find_target (widget, context, NULL); + GdkAtom target = gtk_drag_dest_find_target (GTK_WIDGET (toolbar), context, NULL); if (target == GDK_NONE) { gdk_drag_status (context, 0, time); return FALSE; } - if (etoolbar->priv->target_toolbar != toolbar) + /* Make ourselves the current dnd toolbar, and request a highlight item. */ + if (etoolbar->priv->dnd_toolbar != toolbar) { - if (etoolbar->priv->target_toolbar) - gtk_toolbar_set_drop_highlight_item - (etoolbar->priv->target_toolbar, NULL, 0); - - free_dragged_item (etoolbar); - etoolbar->priv->pending = TRUE; - - etoolbar->priv->target_toolbar = toolbar; - - gtk_drag_get_data (widget, context, target, time); + etoolbar->priv->dnd_toolbar = toolbar; + etoolbar->priv->dnd_toolitem = NULL; + etoolbar->priv->dnd_pending++; + gtk_drag_get_data (GTK_WIDGET (toolbar), context, target, time); } - - if (etoolbar->priv->dragged_item != NULL && - etoolbar->priv->edit_mode) + + /* If a highlight item is available, use it. */ + else if (etoolbar->priv->dnd_toolitem) { - item = GTK_TOOL_ITEM (etoolbar->priv->dragged_item); - - index = gtk_toolbar_get_drop_index (toolbar, x, y); - gtk_toolbar_set_drop_highlight_item (toolbar, item, index); + gint ipos = gtk_toolbar_get_drop_index (etoolbar->priv->dnd_toolbar, x, y); + gtk_toolbar_set_drop_highlight_item (etoolbar->priv->dnd_toolbar, + etoolbar->priv->dnd_toolitem, ipos); } gdk_drag_status (context, context->suggested_action, time); @@ -669,53 +730,248 @@ toolbar_drag_leave_cb (GtkToolbar *toolbar, guint time, EggEditableToolbar *etoolbar) { - /* This is a workaround for bug 125557. Sometimes - * we seemingly enter another toolbar *before* leaving - * the current one. - * - * In that case etoolbar->priv->target_toolbar will - * have been set to something else and the highlighting - * will already have been turned off - */ + gtk_toolbar_set_drop_highlight_item (toolbar, NULL, 0); + + /* If we were the current dnd toolbar target, remove the item. */ + if (etoolbar->priv->dnd_toolbar == toolbar) + { + etoolbar->priv->dnd_toolbar = NULL; + etoolbar->priv->dnd_toolitem = NULL; + } +} + +static void +configure_drag_dest (EggEditableToolbar *etoolbar, + GtkToolbar *toolbar) +{ + EggToolbarsItemType *type; + GtkTargetList *targets; + GList *list; + + /* Make every toolbar able to receive drag-drops. */ + gtk_drag_dest_set (GTK_WIDGET (toolbar), 0, + dest_drag_types, G_N_ELEMENTS (dest_drag_types), + GDK_ACTION_MOVE | GDK_ACTION_COPY); + + /* Add any specialist drag-drop abilities. */ + targets = gtk_drag_dest_get_target_list (GTK_WIDGET (toolbar)); + list = egg_toolbars_model_get_types (etoolbar->priv->model); + while (list) + { + type = list->data; + if (type->new_name != NULL || type->get_name != NULL) + gtk_target_list_add (targets, type->type, 0, 0); + list = list->next; + } +} + +static void +toggled_visibility_cb (GtkToggleAction *action, + EggEditableToolbar *etoolbar) +{ + EggEditableToolbarPrivate *priv = etoolbar->priv; + GtkWidget *dock; + EggTbModelFlags flags; + gboolean visible; + gint i; + + visible = gtk_toggle_action_get_active (action); + for (i = 0; i < priv->visibility_actions->len; i++) + if (g_ptr_array_index (priv->visibility_actions, i) == action) + break; + + g_return_if_fail (i < priv->visibility_actions->len); - if (etoolbar->priv->target_toolbar == toolbar) + dock = get_dock_nth (etoolbar, i); + if (visible) { - gtk_toolbar_set_drop_highlight_item (toolbar, NULL, 0); + gtk_widget_show (dock); + } + else + { + gtk_widget_hide (dock); + } + + if (priv->save_hidden) + { + flags = egg_toolbars_model_get_flags (priv->model, i); + + if (visible) + { + flags &= ~(EGG_TB_MODEL_HIDDEN); + } + else + { + flags |= (EGG_TB_MODEL_HIDDEN); + } + + egg_toolbars_model_set_flags (priv->model, i, flags); + } +} - etoolbar->priv->target_toolbar = NULL; - free_dragged_item (etoolbar); +static void +toolbar_visibility_refresh (EggEditableToolbar *etoolbar) +{ + EggEditableToolbarPrivate *priv = etoolbar->priv; + gint n_toolbars, n_items, i, j, k; + GtkToggleAction *action; + GList *list; + GString *string; + gboolean showing; + char action_name[40]; + char *action_label; + char *tmp; + + if (priv == NULL || priv->model == NULL || priv->manager == NULL || + priv->visibility_paths == NULL || priv->actions == NULL) + { + return; + } + + if (priv->visibility_actions == NULL) + { + priv->visibility_actions = g_ptr_array_new (); + } + + if (priv->visibility_id != 0) + { + gtk_ui_manager_remove_ui (priv->manager, priv->visibility_id); + } + + priv->visibility_id = gtk_ui_manager_new_merge_id (priv->manager); + + showing = GTK_WIDGET_VISIBLE (etoolbar); + + n_toolbars = egg_toolbars_model_n_toolbars (priv->model); + for (i = 0; i < n_toolbars; i++) + { + string = g_string_sized_new (0); + n_items = egg_toolbars_model_n_items (priv->model, i); + for (k = 0, j = 0; j < n_items; j++) + { + GValue value = { 0, }; + GtkAction *action; + const char *name; + + name = egg_toolbars_model_item_nth (priv->model, i, j); + if (name == NULL) continue; + action = find_action (etoolbar, name); + if (action == NULL) continue; + + g_value_init (&value, G_TYPE_STRING); + g_object_get_property (G_OBJECT (action), "label", &value); + name = g_value_get_string (&value); + if (name == NULL) + { + g_value_unset (&value); + continue; + } + k += g_utf8_strlen (name, -1) + 2; + if (j > 0) + { + g_string_append (string, ", "); + if (j > 1 && k > 25) + { + g_value_unset (&value); + break; + } + } + g_string_append (string, name); + g_value_unset (&value); + } + if (j < n_items) + { + g_string_append (string, " ..."); + } + + tmp = g_string_free (string, FALSE); + for (j = 0, k = 0; tmp[j]; j++) + { + if (tmp[j] == '_') continue; + tmp[k] = tmp[j]; + k++; + } + tmp[k] = 0; + /* Translaters: This string is for a toggle to display a toolbar. + * The name of the toolbar is automatically computed from the widgets + * on the toolbar, and is placed at the %s. Note the _ before the %s + * which is used to add mnemonics. We know that this is likely to + * produce duplicates, but don't worry about it. If your language + * normally has a mnemonic at the start, please use the _. If not, + * please remove. */ + action_label = g_strdup_printf (_("Show ā€œ_%sā€"), tmp); + g_free (tmp); + + sprintf(action_name, "ToolbarToggle%d", i); + + if (i >= priv->visibility_actions->len) + { + action = gtk_toggle_action_new (action_name, action_label, NULL, NULL); + g_ptr_array_add (priv->visibility_actions, action); + g_signal_connect_object (action, "toggled", + G_CALLBACK (toggled_visibility_cb), + etoolbar, 0); + gtk_action_group_add_action (priv->actions, GTK_ACTION (action)); + } + else + { + action = g_ptr_array_index (priv->visibility_actions, i); + g_object_set (action, "label", action_label, NULL); + } + + gtk_action_set_visible (GTK_ACTION (action), (egg_toolbars_model_get_flags (priv->model, i) + & EGG_TB_MODEL_NOT_REMOVABLE) == 0); + gtk_action_set_sensitive (GTK_ACTION (action), showing); + gtk_toggle_action_set_active (action, GTK_WIDGET_VISIBLE + (get_dock_nth (etoolbar, i))); + + for (list = priv->visibility_paths; list != NULL; list = g_list_next (list)) + { + gtk_ui_manager_add_ui (priv->manager, priv->visibility_id, + (const char *)list->data, action_name, action_name, + GTK_UI_MANAGER_MENUITEM, FALSE); + } + + g_free (action_label); + } + + gtk_ui_manager_ensure_update (priv->manager); + + while (i < priv->visibility_actions->len) + { + action = g_ptr_array_index (priv->visibility_actions, i); + g_ptr_array_remove_index_fast (priv->visibility_actions, i); + gtk_action_group_remove_action (priv->actions, GTK_ACTION (action)); + i++; } } static GtkWidget * -create_dock (EggEditableToolbar *t) +create_dock (EggEditableToolbar *etoolbar) { GtkWidget *toolbar, *hbox; hbox = gtk_hbox_new (0, FALSE); - gtk_widget_show (hbox); toolbar = gtk_toolbar_new (); gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), TRUE); gtk_widget_show (toolbar); gtk_box_pack_start (GTK_BOX (hbox), toolbar, TRUE, TRUE, 0); - gtk_drag_dest_set (toolbar, 0, - dest_drag_types, G_N_ELEMENTS (dest_drag_types), - GDK_ACTION_MOVE | GDK_ACTION_COPY); - g_signal_connect (toolbar, "drag_drop", - G_CALLBACK (toolbar_drag_drop_cb), t); + G_CALLBACK (toolbar_drag_drop_cb), etoolbar); g_signal_connect (toolbar, "drag_motion", - G_CALLBACK (toolbar_drag_motion_cb), t); + G_CALLBACK (toolbar_drag_motion_cb), etoolbar); g_signal_connect (toolbar, "drag_leave", - G_CALLBACK (toolbar_drag_leave_cb), t); + G_CALLBACK (toolbar_drag_leave_cb), etoolbar); g_signal_connect (toolbar, "drag_data_received", - G_CALLBACK (drag_data_received_cb), t); + G_CALLBACK (toolbar_drag_data_received_cb), etoolbar); g_signal_connect (toolbar, "popup_context_menu", - G_CALLBACK (popup_toolbar_context_menu_cb), t); + G_CALLBACK (popup_context_menu_cb), etoolbar); + configure_drag_dest (etoolbar, GTK_TOOLBAR (toolbar)); + return hbox; } @@ -737,14 +993,14 @@ unset_fixed_style (EggEditableToolbar *t) static void toolbar_changed_cb (EggToolbarsModel *model, int position, - EggEditableToolbar *t) + EggEditableToolbar *etoolbar) { GtkWidget *toolbar; EggTbModelFlags flags; GtkToolbarStyle style; flags = egg_toolbars_model_get_flags (model, position); - toolbar = get_toolbar_nth (t, position); + toolbar = get_toolbar_nth (etoolbar, position); if (flags & EGG_TB_MODEL_ICONS) { @@ -765,28 +1021,30 @@ toolbar_changed_cb (EggToolbarsModel *model, else { gtk_toolbar_unset_style (GTK_TOOLBAR (toolbar)); - if (position == 0 && t->priv->fixed_toolbar) + if (position == 0 && etoolbar->priv->fixed_toolbar) { - unset_fixed_style (t); + unset_fixed_style (etoolbar); } return; } gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), style); - if (position == 0 && t->priv->fixed_toolbar) + if (position == 0 && etoolbar->priv->fixed_toolbar) { - set_fixed_style (t, style); + set_fixed_style (etoolbar, style); } + + toolbar_visibility_refresh (etoolbar); } static void -unparent_fixed (EggEditableToolbar *t) +unparent_fixed (EggEditableToolbar *etoolbar) { GtkWidget *toolbar, *dock; - g_return_if_fail (GTK_IS_TOOLBAR (t->priv->fixed_toolbar)); + g_return_if_fail (GTK_IS_TOOLBAR (etoolbar->priv->fixed_toolbar)); - toolbar = t->priv->fixed_toolbar; - dock = get_dock_nth (t, 0); + toolbar = etoolbar->priv->fixed_toolbar; + dock = get_dock_nth (etoolbar, 0); if (dock && toolbar->parent != NULL) { @@ -795,13 +1053,13 @@ unparent_fixed (EggEditableToolbar *t) } static void -update_fixed (EggEditableToolbar *t) +update_fixed (EggEditableToolbar *etoolbar) { GtkWidget *toolbar, *dock; - if (!t->priv->fixed_toolbar) return; + if (!etoolbar->priv->fixed_toolbar) return; - toolbar = t->priv->fixed_toolbar; - dock = get_dock_nth (t, 0); + toolbar = etoolbar->priv->fixed_toolbar; + dock = get_dock_nth (etoolbar, 0); if (dock && toolbar && toolbar->parent == NULL) { @@ -817,97 +1075,109 @@ update_fixed (EggEditableToolbar *t) static void toolbar_added_cb (EggToolbarsModel *model, int position, - EggEditableToolbar *t) + EggEditableToolbar *etoolbar) { GtkWidget *dock; - dock = create_dock (t); + dock = create_dock (etoolbar); + if ((egg_toolbars_model_get_flags (model, position) & EGG_TB_MODEL_HIDDEN) == 0) + gtk_widget_show (dock); gtk_widget_set_size_request (dock, -1, MIN_TOOLBAR_HEIGHT); - gtk_box_pack_start (GTK_BOX (t), dock, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (etoolbar), dock, TRUE, TRUE, 0); - gtk_box_reorder_child (GTK_BOX (t), dock, position); + gtk_box_reorder_child (GTK_BOX (etoolbar), dock, position); gtk_widget_show_all (dock); - update_fixed (t); + update_fixed (etoolbar); + + toolbar_visibility_refresh (etoolbar); } static void toolbar_removed_cb (EggToolbarsModel *model, int position, - EggEditableToolbar *t) + EggEditableToolbar *etoolbar) { - GtkWidget *toolbar; + GtkWidget *dock; - if (position == 0 && t->priv->fixed_toolbar != NULL) + if (position == 0 && etoolbar->priv->fixed_toolbar != NULL) { - unparent_fixed (t); + unparent_fixed (etoolbar); } - toolbar = get_dock_nth (t, position); - gtk_widget_destroy (toolbar); + dock = get_dock_nth (etoolbar, position); + gtk_widget_destroy (dock); - update_fixed (t); + update_fixed (etoolbar); + + toolbar_visibility_refresh (etoolbar); } static void item_added_cb (EggToolbarsModel *model, - int toolbar_position, - int position, - EggEditableToolbar *t) + int tpos, + int ipos, + EggEditableToolbar *etoolbar) { GtkWidget *dock; GtkWidget *toolbar; - GtkWidget *item; - GtkAction *action; - - toolbar = get_toolbar_nth (t, toolbar_position); - item = create_item (t, model, toolbar_position, position, &action); - gtk_toolbar_insert (GTK_TOOLBAR (toolbar), - GTK_TOOL_ITEM (item), position); + GtkToolItem *item; - dock = get_dock_nth (t, toolbar_position); + toolbar = get_toolbar_nth (etoolbar, tpos); + item = create_item_from_position (etoolbar, tpos, ipos); + if (item == NULL) return; + + gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, ipos); + + connect_widget_signals (GTK_WIDGET (item), etoolbar); + configure_item_tooltip (item); + configure_item_cursor (item, etoolbar); + configure_item_sensitivity (item, etoolbar); + + dock = get_dock_nth (etoolbar, tpos); gtk_widget_set_size_request (dock, -1, -1); gtk_widget_queue_resize_no_redraw (dock); - /* FIXME Hack to make tooltip work from gtk */ - if (action) - { - g_object_notify (G_OBJECT (action), "tooltip"); - } + toolbar_visibility_refresh (etoolbar); } static void item_removed_cb (EggToolbarsModel *model, int toolbar_position, int position, - EggEditableToolbar *t) + EggEditableToolbar *etoolbar) { + EggEditableToolbarPrivate *priv = etoolbar->priv; + GtkWidget *toolbar; GtkWidget *item; - toolbar = get_toolbar_nth (t, toolbar_position); + toolbar = get_toolbar_nth (etoolbar, toolbar_position); item = GTK_WIDGET (gtk_toolbar_get_nth_item (GTK_TOOLBAR (toolbar), position)); g_return_if_fail (item != NULL); - gtk_container_remove (GTK_CONTAINER (toolbar), item); - if (egg_toolbars_model_n_items (model, toolbar_position) == 0) + if (item == priv->selected) { - egg_toolbars_model_remove_toolbar (model, toolbar_position); + /* FIXME */ } + + gtk_container_remove (GTK_CONTAINER (toolbar), item); + + toolbar_visibility_refresh (etoolbar); } static void -egg_editable_toolbar_construct (EggEditableToolbar *t) +egg_editable_toolbar_build (EggEditableToolbar *etoolbar) { int i, l, n_items, n_toolbars; - EggToolbarsModel *model = t->priv->model; + EggToolbarsModel *model = etoolbar->priv->model; g_return_if_fail (model != NULL); - g_return_if_fail (t->priv->manager != NULL); + g_return_if_fail (etoolbar->priv->manager != NULL); n_toolbars = egg_toolbars_model_n_toolbars (model); @@ -915,26 +1185,25 @@ egg_editable_toolbar_construct (EggEditableToolbar *t) { GtkWidget *toolbar, *dock; - dock = create_dock (t); - gtk_box_pack_start (GTK_BOX (t), dock, TRUE, TRUE, 0); - toolbar = get_toolbar_nth (t, i); + dock = create_dock (etoolbar); + if ((egg_toolbars_model_get_flags (model, i) & EGG_TB_MODEL_HIDDEN) == 0) + gtk_widget_show (dock); + gtk_box_pack_start (GTK_BOX (etoolbar), dock, TRUE, TRUE, 0); + toolbar = get_toolbar_nth (etoolbar, i); n_items = egg_toolbars_model_n_items (model, i); for (l = 0; l < n_items; l++) { - GtkWidget *item; - GtkAction *action; + GtkToolItem *item; - item = create_item (t, model, i, l, &action); + item = create_item_from_position (etoolbar, i, l); if (item) { - gtk_toolbar_insert (GTK_TOOLBAR (toolbar), - GTK_TOOL_ITEM (item), l); - /* FIXME Hack to make tooltip work from gtk */ - if (action) - { - g_object_notify (G_OBJECT (action), "tooltip"); - } + gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, l); + + connect_widget_signals (GTK_WIDGET (item), etoolbar); + configure_item_tooltip (item); + configure_item_sensitivity (item, etoolbar); } else { @@ -950,12 +1219,12 @@ egg_editable_toolbar_construct (EggEditableToolbar *t) } } - update_fixed (t); + update_fixed (etoolbar); /* apply styles */ for (i = 0; i < n_toolbars; i ++) { - toolbar_changed_cb (model, i, t); + toolbar_changed_cb (model, i, etoolbar); } } @@ -996,46 +1265,198 @@ egg_editable_toolbar_deconstruct (EggEditableToolbar *toolbar) } void -egg_editable_toolbar_set_model (EggEditableToolbar *toolbar, +egg_editable_toolbar_set_model (EggEditableToolbar *etoolbar, EggToolbarsModel *model) { - g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model)); - g_return_if_fail (EGG_IS_EDITABLE_TOOLBAR (toolbar)); - g_return_if_fail (toolbar->priv->manager); + EggEditableToolbarPrivate *priv = etoolbar->priv; - if (toolbar->priv->model == model) return; + if (priv->model == model) return; - if (toolbar->priv->model) + if (priv->model) { - egg_editable_toolbar_disconnect_model (toolbar); - egg_editable_toolbar_deconstruct (toolbar); + egg_editable_toolbar_disconnect_model (etoolbar); + egg_editable_toolbar_deconstruct (etoolbar); - g_object_unref (toolbar->priv->model); + g_object_unref (priv->model); } - toolbar->priv->model = g_object_ref (model); + priv->model = g_object_ref (model); + + egg_editable_toolbar_build (etoolbar); - egg_editable_toolbar_construct (toolbar); + toolbar_visibility_refresh (etoolbar); g_signal_connect (model, "item_added", - G_CALLBACK (item_added_cb), toolbar); + G_CALLBACK (item_added_cb), etoolbar); g_signal_connect (model, "item_removed", - G_CALLBACK (item_removed_cb), toolbar); + G_CALLBACK (item_removed_cb), etoolbar); g_signal_connect (model, "toolbar_added", - G_CALLBACK (toolbar_added_cb), toolbar); + G_CALLBACK (toolbar_added_cb), etoolbar); g_signal_connect (model, "toolbar_removed", - G_CALLBACK (toolbar_removed_cb), toolbar); + G_CALLBACK (toolbar_removed_cb), etoolbar); g_signal_connect (model, "toolbar_changed", - G_CALLBACK (toolbar_changed_cb), toolbar); + G_CALLBACK (toolbar_changed_cb), etoolbar); +} + +static void +egg_editable_toolbar_init (EggEditableToolbar *etoolbar) +{ + EggEditableToolbarPrivate *priv; + + priv = etoolbar->priv = EGG_EDITABLE_TOOLBAR_GET_PRIVATE (etoolbar); + + priv->save_hidden = TRUE; + + g_signal_connect (etoolbar, "notify::visible", + G_CALLBACK (toolbar_visibility_refresh), NULL); } static void -egg_editable_toolbar_set_ui_manager (EggEditableToolbar *t, +egg_editable_toolbar_dispose (GObject *object) +{ + EggEditableToolbar *etoolbar = EGG_EDITABLE_TOOLBAR (object); + EggEditableToolbarPrivate *priv = etoolbar->priv; + GList *children; + + if (priv->fixed_toolbar != NULL) + { + g_object_unref (priv->fixed_toolbar); + priv->fixed_toolbar = NULL; + } + + if (priv->visibility_paths) + { + children = priv->visibility_paths; + g_list_foreach (children, (GFunc) g_free, NULL); + g_list_free (children); + priv->visibility_paths = NULL; + } + + if (priv->manager != NULL) + { + if (priv->visibility_id) + { + gtk_ui_manager_remove_ui (priv->manager, priv->visibility_id); + priv->visibility_id = 0; + } + + g_object_unref (priv->manager); + priv->manager = NULL; + } + + if (priv->model) + { + egg_editable_toolbar_disconnect_model (etoolbar); + g_object_unref (priv->model); + priv->model = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +egg_editable_toolbar_set_ui_manager (EggEditableToolbar *etoolbar, GtkUIManager *manager) { - g_return_if_fail (GTK_IS_UI_MANAGER (manager)); + static const GtkActionEntry actions[] = { + { "MoveToolItem", STOCK_DRAG_MODE, N_("_Move on Toolbar"), NULL, + N_("Move the selected item on the toolbar"), G_CALLBACK (move_item_cb) }, + { "RemoveToolItem", GTK_STOCK_REMOVE, N_("_Remove from Toolbar"), NULL, + N_("Remove the selected item from the toolbar"), G_CALLBACK (remove_item_cb) }, + { "RemoveToolbar", GTK_STOCK_DELETE, N_("_Delete Toolbar"), NULL, + N_("Remove the selected toolbar"), G_CALLBACK (remove_toolbar_cb) }, + }; + + etoolbar->priv->manager = g_object_ref (manager); + + etoolbar->priv->actions = gtk_action_group_new ("ToolbarActions"); + gtk_action_group_set_translation_domain (etoolbar->priv->actions, GETTEXT_PACKAGE); + gtk_action_group_add_actions (etoolbar->priv->actions, actions, + G_N_ELEMENTS (actions), etoolbar); + gtk_ui_manager_insert_action_group (manager, etoolbar->priv->actions, -1); + g_object_unref (etoolbar->priv->actions); + + toolbar_visibility_refresh (etoolbar); +} + +GtkWidget * egg_editable_toolbar_get_selected (EggEditableToolbar *etoolbar) +{ + return etoolbar->priv->selected; +} + +void +egg_editable_toolbar_set_selected (EggEditableToolbar *etoolbar, + GtkWidget *widget) +{ + GtkWidget *toolbar, *toolitem; + gboolean editable; - t->priv->manager = g_object_ref (manager); + etoolbar->priv->selected = widget; + + toolbar = (widget != NULL) ? gtk_widget_get_ancestor (widget, GTK_TYPE_TOOLBAR) : NULL; + toolitem = (widget != NULL) ? gtk_widget_get_ancestor (widget, GTK_TYPE_TOOL_ITEM) : NULL; + + if(toolbar != NULL) + { + gint tpos = get_toolbar_position (etoolbar, toolbar); + editable = ((egg_toolbars_model_get_flags (etoolbar->priv->model, tpos) & EGG_TB_MODEL_NOT_EDITABLE) == 0); + } + else + { + editable = FALSE; + } + + gtk_action_set_visible (find_action (etoolbar, "RemoveToolbar"), (toolbar != NULL) && (etoolbar->priv->edit_mode > 0)); + gtk_action_set_visible (find_action (etoolbar, "RemoveToolItem"), (toolitem != NULL) && editable); + gtk_action_set_visible (find_action (etoolbar, "MoveToolItem"), (toolitem != NULL) && editable); +} + +static void +set_edit_mode (EggEditableToolbar *etoolbar, + gboolean mode) +{ + EggEditableToolbarPrivate *priv = etoolbar->priv; + int i, l, n_items; + + i = priv->edit_mode; + if (mode) + { + priv->edit_mode++; + } + else + { + g_return_if_fail (priv->edit_mode > 0); + priv->edit_mode--; + } + i *= priv->edit_mode; + + if (i == 0) + { + for (i = get_n_toolbars (etoolbar)-1; i >= 0; i--) + { + GtkWidget *toolbar; + + toolbar = get_toolbar_nth (etoolbar, i); + n_items = gtk_toolbar_get_n_items (GTK_TOOLBAR (toolbar)); + + if (n_items == 0 && priv->edit_mode == 0) + { + egg_toolbars_model_remove_toolbar (priv->model, i); + } + else + { + for (l = 0; l < n_items; l++) + { + GtkToolItem *item; + + item = gtk_toolbar_get_nth_item (GTK_TOOLBAR (toolbar), l); + + configure_item_cursor (item, etoolbar); + configure_item_sensitivity (item, etoolbar); + } + } + } + } } static void @@ -1044,15 +1465,24 @@ egg_editable_toolbar_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - EggEditableToolbar *t = EGG_EDITABLE_TOOLBAR (object); + EggEditableToolbar *etoolbar = EGG_EDITABLE_TOOLBAR (object); switch (prop_id) { case PROP_UI_MANAGER: - egg_editable_toolbar_set_ui_manager (t, g_value_get_object (value)); + egg_editable_toolbar_set_ui_manager (etoolbar, g_value_get_object (value)); break; case PROP_TOOLBARS_MODEL: - egg_editable_toolbar_set_model (t, g_value_get_object (value)); + egg_editable_toolbar_set_model (etoolbar, g_value_get_object (value)); + break; + case PROP_SELECTED: + egg_editable_toolbar_set_selected (etoolbar, g_value_get_object (value)); + break; + case PROP_POPUP_PATH: + etoolbar->priv->popup_path = g_strdup (g_value_get_string (value)); + break; + case PROP_EDIT_MODE: + set_edit_mode (etoolbar, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1066,15 +1496,21 @@ egg_editable_toolbar_get_property (GObject *object, GValue *value, GParamSpec *pspec) { - EggEditableToolbar *t = EGG_EDITABLE_TOOLBAR (object); + EggEditableToolbar *etoolbar = EGG_EDITABLE_TOOLBAR (object); switch (prop_id) { case PROP_UI_MANAGER: - g_value_set_object (value, t->priv->manager); + g_value_set_object (value, etoolbar->priv->manager); break; case PROP_TOOLBARS_MODEL: - g_value_set_object (value, t->priv->model); + g_value_set_object (value, etoolbar->priv->model); + break; + case PROP_SELECTED: + g_value_set_object (value, etoolbar->priv->selected); + break; + case PROP_EDIT_MODE: + g_value_set_boolean (value, etoolbar->priv->edit_mode>0); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1089,7 +1525,7 @@ egg_editable_toolbar_class_init (EggEditableToolbarClass *klass) parent_class = g_type_class_peek_parent (klass); - object_class->finalize = egg_editable_toolbar_finalize; + object_class->dispose = egg_editable_toolbar_dispose; object_class->set_property = egg_editable_toolbar_set_property; object_class->get_property = egg_editable_toolbar_get_property; @@ -1107,130 +1543,94 @@ egg_editable_toolbar_class_init (EggEditableToolbarClass *klass) "UI-Mmanager", "UI Manager", GTK_TYPE_UI_MANAGER, - G_PARAM_READWRITE)); + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); g_object_class_install_property (object_class, PROP_TOOLBARS_MODEL, g_param_spec_object ("model", "Model", "Toolbars Model", EGG_TYPE_TOOLBARS_MODEL, - G_PARAM_READWRITE)); - - g_type_class_add_private (object_class, sizeof (EggEditableToolbarPrivate)); -} - -static void -egg_editable_toolbar_init (EggEditableToolbar *t) -{ - t->priv = EGG_EDITABLE_TOOLBAR_GET_PRIVATE (t); -} - -static void -egg_editable_toolbar_finalize (GObject *object) -{ - EggEditableToolbar *t = EGG_EDITABLE_TOOLBAR (object); - - if (t->priv->fixed_toolbar) - { - g_object_unref (t->priv->fixed_toolbar); - } + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + g_object_class_install_property (object_class, + PROP_SELECTED, + g_param_spec_object ("selected", + "Selected", + "Selected toolitem", + GTK_TYPE_TOOL_ITEM, + G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); - if (t->priv->manager) - { - g_object_unref (t->priv->manager); - } + g_object_class_install_property (object_class, + PROP_POPUP_PATH, + g_param_spec_string ("popup-path", + "popup-path", + "popup-path", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); - if (t->priv->model) - { - egg_editable_toolbar_disconnect_model (t); - g_object_unref (t->priv->model); - } + g_object_class_install_property (object_class, + PROP_EDIT_MODE, + g_param_spec_boolean ("edit-mode", + "Edit-Mode", + "Edit Mode", + FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); - G_OBJECT_CLASS (parent_class)->finalize (object); + g_type_class_add_private (object_class, sizeof (EggEditableToolbarPrivate)); } GtkWidget * -egg_editable_toolbar_new (GtkUIManager *manager) +egg_editable_toolbar_new (GtkUIManager *manager, + const char *popup_path) { - return GTK_WIDGET (g_object_new (EGG_TYPE_EDITABLE_TOOLBAR, - "ui-manager", manager, - NULL)); + return GTK_WIDGET (g_object_new (EGG_TYPE_EDITABLE_TOOLBAR, + "ui-manager", manager, + "popup-path", popup_path, + NULL)); } GtkWidget * -egg_editable_toolbar_new_with_model (GtkUIManager *manager, - EggToolbarsModel *model) +egg_editable_toolbar_new_with_model (GtkUIManager *manager, + EggToolbarsModel *model, + const char *popup_path) { return GTK_WIDGET (g_object_new (EGG_TYPE_EDITABLE_TOOLBAR, - "ui-manager", manager, - "model", model, + "ui-manager", manager, + "model", model, + "popup-path", popup_path, NULL)); } gboolean egg_editable_toolbar_get_edit_mode (EggEditableToolbar *etoolbar) { - return etoolbar->priv->edit_mode; + EggEditableToolbarPrivate *priv = etoolbar->priv; + + return priv->edit_mode > 0; } void egg_editable_toolbar_set_edit_mode (EggEditableToolbar *etoolbar, - gboolean mode) + gboolean mode) { - int i, l, n_toolbars, n_items; - - etoolbar->priv->edit_mode = mode; - - n_toolbars = get_n_toolbars (etoolbar); - for (i = 0; i < n_toolbars; i++) - { - GtkWidget *toolbar; - - toolbar = get_toolbar_nth (etoolbar, i); - n_items = gtk_toolbar_get_n_items (GTK_TOOLBAR (toolbar)); - for (l = 0; l < n_items; l++) - { - GtkToolItem *item; - const char *action_name, *type; - gboolean is_separator; - GtkAction *action = NULL; - - egg_toolbars_model_item_nth (etoolbar->priv->model, i, l, - &is_separator, &action_name, &type); - action = find_action (etoolbar, action_name); - - item = gtk_toolbar_get_nth_item (GTK_TOOLBAR (toolbar), l); - gtk_tool_item_set_use_drag_window (item, mode); - - if (mode) - { - set_drag_cursor (GTK_WIDGET (item)); - gtk_widget_set_sensitive (GTK_WIDGET (item), TRUE); - set_item_drag_source (etoolbar->priv->model, GTK_WIDGET (item), - action, is_separator, type); - } - else - { - unset_drag_cursor (GTK_WIDGET (item)); - gtk_drag_source_unset (GTK_WIDGET (item)); + set_edit_mode (etoolbar, mode); + g_object_notify (G_OBJECT (etoolbar), "edit-mode"); +} - if (!is_separator) - { - g_object_notify (G_OBJECT (action), "sensitive"); - } - } - } - } +void +egg_editable_toolbar_add_visibility (EggEditableToolbar *etoolbar, + const char *path) +{ + etoolbar->priv->visibility_paths = g_list_prepend + (etoolbar->priv->visibility_paths, g_strdup (path)); } void egg_editable_toolbar_show (EggEditableToolbar *etoolbar, - const char *name) + const char *name) { + EggEditableToolbarPrivate *priv = etoolbar->priv; + EggToolbarsModel *model = priv->model; int i, n_toolbars; - EggToolbarsModel *model = etoolbar->priv->model; - - g_return_if_fail (model != NULL); n_toolbars = egg_toolbars_model_n_toolbars (model); for (i = 0; i < n_toolbars; i++) @@ -1239,20 +1639,19 @@ egg_editable_toolbar_show (EggEditableToolbar *etoolbar, toolbar_name = egg_toolbars_model_toolbar_nth (model, i); if (strcmp (toolbar_name, name) == 0) - { - gtk_widget_show (get_dock_nth (etoolbar, i)); - } + { + gtk_widget_show (get_dock_nth (etoolbar, i)); + } } } void egg_editable_toolbar_hide (EggEditableToolbar *etoolbar, - const char *name) + const char *name) { + EggEditableToolbarPrivate *priv = etoolbar->priv; + EggToolbarsModel *model = priv->model; int i, n_toolbars; - EggToolbarsModel *model = etoolbar->priv->model; - - g_return_if_fail (model != NULL); n_toolbars = egg_toolbars_model_n_toolbars (model); for (i = 0; i < n_toolbars; i++) @@ -1268,57 +1667,28 @@ egg_editable_toolbar_hide (EggEditableToolbar *etoolbar, } void -egg_editable_toolbar_set_fixed (EggEditableToolbar *toolbar, - GtkToolbar *fixed_toolbar) +egg_editable_toolbar_set_fixed (EggEditableToolbar *etoolbar, + GtkToolbar *toolbar) { - g_return_if_fail (EGG_IS_EDITABLE_TOOLBAR (toolbar)); - g_return_if_fail (!fixed_toolbar || GTK_IS_TOOLBAR (fixed_toolbar)); + EggEditableToolbarPrivate *priv = etoolbar->priv; - if (toolbar->priv->fixed_toolbar) - { - unparent_fixed (toolbar); - g_object_unref (toolbar->priv->fixed_toolbar); - toolbar->priv->fixed_toolbar = NULL; - } + g_return_if_fail (!toolbar || GTK_IS_TOOLBAR (toolbar)); - if (fixed_toolbar) + if (priv->fixed_toolbar) { - toolbar->priv->fixed_toolbar = GTK_WIDGET (fixed_toolbar); - gtk_toolbar_set_show_arrow (fixed_toolbar, FALSE); - g_object_ref (fixed_toolbar); - gtk_object_sink (GTK_OBJECT (fixed_toolbar)); + unparent_fixed (etoolbar); + g_object_unref (priv->fixed_toolbar); + priv->fixed_toolbar = NULL; } - update_fixed (toolbar); -} - -void -egg_editable_toolbar_set_drag_dest (EggEditableToolbar *etoolbar, - const GtkTargetEntry *targets, - gint n_targets, - const char *toolbar_name) -{ - int i, n_toolbars; - EggToolbarsModel *model = etoolbar->priv->model; - - g_return_if_fail (model != NULL); - - n_toolbars = egg_toolbars_model_n_toolbars (model); - for (i = 0; i < n_toolbars; i++) + if (toolbar) { - const char *name; - - name = egg_toolbars_model_toolbar_nth (model, i); - if (strcmp (toolbar_name, name) == 0) - { - GtkWidget *widget = get_toolbar_nth (etoolbar, i); - - gtk_drag_dest_unset (widget); - gtk_drag_dest_set (widget, 0, - targets, n_targets, - GDK_ACTION_MOVE | GDK_ACTION_COPY); - } + priv->fixed_toolbar = GTK_WIDGET (toolbar); + gtk_toolbar_set_show_arrow (toolbar, FALSE); + g_object_ref_sink (toolbar); } + + update_fixed (etoolbar); } #define DEFAULT_ICON_HEIGHT 20 diff --git a/cut-n-paste/toolbar-editor/egg-editable-toolbar.h b/cut-n-paste/toolbar-editor/egg-editable-toolbar.h index 9f143da..8a4e85e 100644 --- a/cut-n-paste/toolbar-editor/egg-editable-toolbar.h +++ b/cut-n-paste/toolbar-editor/egg-editable-toolbar.h @@ -29,6 +29,7 @@ #include #include #include +#include G_BEGIN_DECLS @@ -60,12 +61,15 @@ struct _EggEditableToolbarClass }; GType egg_editable_toolbar_get_type (void); -GtkWidget *egg_editable_toolbar_new (GtkUIManager *manager); +GtkWidget *egg_editable_toolbar_new (GtkUIManager *manager, + const char *visibility_path); GtkWidget *egg_editable_toolbar_new_with_model (GtkUIManager *manager, - EggToolbarsModel *model); + EggToolbarsModel *model, + const char *visibility_path); void egg_editable_toolbar_set_model (EggEditableToolbar *etoolbar, EggToolbarsModel *model); EggToolbarsModel *egg_editable_toolbar_get_model (EggEditableToolbar *etoolbar); +GtkUIManager *egg_editable_toolbar_get_manager (EggEditableToolbar *etoolbar); void egg_editable_toolbar_set_edit_mode (EggEditableToolbar *etoolbar, gboolean mode); gboolean egg_editable_toolbar_get_edit_mode (EggEditableToolbar *etoolbar); @@ -73,13 +77,15 @@ void egg_editable_toolbar_show (EggEditableToolbar *etoolbar, const char *name); void egg_editable_toolbar_hide (EggEditableToolbar *etoolbar, const char *name); -void egg_editable_toolbar_set_drag_dest (EggEditableToolbar *etoolbar, - const GtkTargetEntry *targets, - gint n_targets, - const char *toolbar_name); void egg_editable_toolbar_set_fixed (EggEditableToolbar *etoolbar, GtkToolbar *fixed_toolbar); +GtkWidget * egg_editable_toolbar_get_selected (EggEditableToolbar *etoolbar); +void egg_editable_toolbar_set_selected (EggEditableToolbar *etoolbar, + GtkWidget *widget); + +void egg_editable_toolbar_add_visibility (EggEditableToolbar *etoolbar, + const char *path); /* Private Functions */ diff --git a/cut-n-paste/toolbar-editor/egg-toolbar-editor.c b/cut-n-paste/toolbar-editor/egg-toolbar-editor.c index bd79724..0564c6f 100644 --- a/cut-n-paste/toolbar-editor/egg-toolbar-editor.c +++ b/cut-n-paste/toolbar-editor/egg-toolbar-editor.c @@ -22,7 +22,6 @@ #include "egg-toolbar-editor.h" #include "egg-editable-toolbar.h" -#include "eggintl.h" #include #include @@ -34,6 +33,8 @@ #include #include #include +#include +#include static const GtkTargetEntry dest_drag_types[] = { {EGG_TOOLBAR_ITEM_TYPE, GTK_TARGET_SAME_APP, 0}, @@ -46,7 +47,6 @@ static const GtkTargetEntry source_drag_types[] = { static void egg_toolbar_editor_class_init (EggToolbarEditorClass *klass); static void egg_toolbar_editor_init (EggToolbarEditor *t); static void egg_toolbar_editor_finalize (GObject *object); -static void update_actions_list (EggToolbarEditor *editor); static void update_editor_sheet (EggToolbarEditor *editor); enum @@ -67,9 +67,8 @@ struct EggToolbarEditorPrivate GtkWidget *table; GtkWidget *scrolled_window; - - GList *default_actions_list; - GList *actions_list; + GList *actions_list; + GList *factory_list; }; GType @@ -100,27 +99,18 @@ egg_toolbar_editor_get_type (void) } static gint -compare_actions (gconstpointer a, - gconstpointer b) +compare_items (gconstpointer a, + gconstpointer b) { - GValue value_a = { 0, }, value_b = { 0, }; - const char *short_label_a, *short_label_b; - int ret; - - g_value_init (&value_a, G_TYPE_STRING); - g_object_get_property (G_OBJECT (a), "short_label", &value_a); - short_label_a = g_value_get_string (&value_a); - - g_value_init (&value_b, G_TYPE_STRING); - g_object_get_property (G_OBJECT (b), "short_label", &value_b); - short_label_b = g_value_get_string (&value_b); - - ret = g_utf8_collate (short_label_a, short_label_b); - - g_value_unset (&value_a); - g_value_unset (&value_b); - - return ret; + const GtkWidget *item1 = a; + const GtkWidget *item2 = b; + + char *key1 = g_object_get_data (G_OBJECT (item1), + "egg-collate-key"); + char *key2 = g_object_get_data (G_OBJECT (item2), + "egg-collate-key"); + + return strcmp (key1, key2); } static GtkAction * @@ -157,11 +147,19 @@ egg_toolbar_editor_set_ui_manager (EggToolbarEditor *t, } static void +item_added_or_removed_cb (EggToolbarsModel *model, + int tpos, + int ipos, + EggToolbarEditor *editor) +{ + update_editor_sheet (editor); +} + +static void toolbar_removed_cb (EggToolbarsModel *model, int position, EggToolbarEditor *editor) { - update_actions_list (editor); update_editor_sheet (editor); } @@ -172,7 +170,13 @@ egg_toolbar_editor_set_model (EggToolbarEditor *t, g_return_if_fail (EGG_IS_TOOLBAR_EDITOR (t)); t->priv->model = g_object_ref (model); + + update_editor_sheet (t); + g_signal_connect_object (model, "item_added", + G_CALLBACK (item_added_or_removed_cb), t, 0); + g_signal_connect_object (model, "item_removed", + G_CALLBACK (item_added_or_removed_cb), t, 0); g_signal_connect_object (model, "toolbar_removed", G_CALLBACK (toolbar_removed_cb), t, 0); } @@ -232,7 +236,7 @@ egg_toolbar_editor_class_init (EggToolbarEditorClass *klass) "UI-Manager", "UI Manager", GTK_TYPE_UI_MANAGER, - G_PARAM_READWRITE | + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_TOOLBARS_MODEL, @@ -240,7 +244,7 @@ egg_toolbar_editor_class_init (EggToolbarEditorClass *klass) "Model", "Toolbars Model", EGG_TYPE_TOOLBARS_MODEL, - G_PARAM_READWRITE | + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_CONSTRUCT_ONLY)); g_type_class_add_private (object_class, sizeof (EggToolbarEditorPrivate)); @@ -261,8 +265,8 @@ egg_toolbar_editor_finalize (GObject *object) g_object_unref (editor->priv->model); } - g_list_free (editor->priv->default_actions_list); g_list_free (editor->priv->actions_list); + g_list_free (editor->priv->factory_list); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -281,66 +285,14 @@ static void drag_begin_cb (GtkWidget *widget, GdkDragContext *context) { - gtk_widget_hide (widget); + gtk_widget_hide (widget); } static void drag_end_cb (GtkWidget *widget, GdkDragContext *context) { - gtk_widget_show (widget); -} - -static void -editor_drag_data_received_cb (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - GtkSelectionData *selection_data, - guint info, - guint time_, - EggToolbarEditor *editor) -{ - GtkAction *action; - const char *data; - - g_return_if_fail (EGG_IS_TOOLBAR_EDITOR (editor)); - g_return_if_fail (selection_data != NULL); - - if (selection_data->length <= 0 || selection_data->data == NULL) return; - - data = (const char *) selection_data->data; - - if (strcmp (data, "separator") == 0) return; - - action = find_action (editor, data); - g_return_if_fail (action != NULL); - - if (g_list_find (editor->priv->default_actions_list, action)) - { - editor->priv->actions_list = g_list_insert_sorted - (editor->priv->actions_list, action, compare_actions); - } - - update_editor_sheet (editor); -} - -static void -editor_drag_data_delete_cb (GtkWidget *widget, - GdkDragContext *context, - EggToolbarEditor *editor) -{ - GtkAction *action; - g_return_if_fail (EGG_IS_TOOLBAR_EDITOR (editor)); - - action = GTK_ACTION (g_object_get_data (G_OBJECT (widget), "egg-action")); - if (action) - { - editor->priv->actions_list = g_list_remove - (editor->priv->actions_list, action); - } - - update_editor_sheet (editor); + gtk_widget_show (widget); } static void @@ -351,23 +303,13 @@ drag_data_get_cb (GtkWidget *widget, guint32 time, EggToolbarEditor *editor) { - GtkAction *action; const char *target; - action = GTK_ACTION (g_object_get_data (G_OBJECT (widget), "egg-action")); - - if (action) - { - target = gtk_action_get_name (action); - } - else - { - target = "separator"; - } - - gtk_selection_data_set (selection_data, - selection_data->target, 8, - (const guchar *)target, strlen (target)); + target = g_object_get_data (G_OBJECT (widget), "egg-item-name"); + g_return_if_fail (target != NULL); + + gtk_selection_data_set (selection_data, selection_data->target, 8, + (const guchar *) target, strlen (target)); } static gchar * @@ -400,14 +342,12 @@ static void set_drag_cursor (GtkWidget *widget) { GdkCursor *cursor; - GdkPixbuf *pixbuf; - - pixbuf = gdk_pixbuf_new_from_file (CURSOR_DIR "/hand-open.png", NULL); - cursor = gdk_cursor_new_from_pixbuf (gdk_display_get_default (), pixbuf, 12, 12); + + /* FIXME multihead */ + cursor = gdk_cursor_new (GDK_HAND2); gdk_window_set_cursor (widget->window, cursor); gdk_cursor_unref (cursor); - g_object_unref (pixbuf); } static void @@ -454,8 +394,6 @@ editor_create_item (EggToolbarEditor *editor, source_drag_types, G_N_ELEMENTS (source_drag_types), action); g_signal_connect (event_box, "drag_data_get", G_CALLBACK (drag_data_get_cb), editor); - g_signal_connect (event_box, "drag_data_delete", - G_CALLBACK (editor_drag_data_delete_cb), editor); g_signal_connect_after (event_box, "realize", G_CALLBACK (event_box_realize_cb), icon); @@ -482,80 +420,176 @@ editor_create_item (EggToolbarEditor *editor, return event_box; } -static void -update_editor_sheet (EggToolbarEditor *editor) +static GtkWidget * +editor_create_item_from_name (EggToolbarEditor *editor, + const char * name, + GdkDragAction drag_action) { - GList *l; - GList *to_drag; - int x, y, height, width; - GtkWidget *table; - GtkWidget *viewport; GtkWidget *item; - GtkWidget *icon; - - g_return_if_fail (EGG_IS_TOOLBAR_EDITOR (editor)); - - viewport = GTK_BIN (editor->priv->scrolled_window)->child; - if (viewport) + const char *item_name; + const char *stock_id; + const char *short_label; + const char *collate_key; + + if (strcmp (name, "_separator") == 0) { - table = GTK_BIN (viewport)->child; - gtk_container_remove (GTK_CONTAINER (viewport), table); + GtkWidget *icon; + + icon = _egg_editable_toolbar_new_separator_image (); + short_label = _("Separator"); + item_name = strdup (name); + collate_key = g_utf8_collate_key (short_label, -1); + item = editor_create_item (editor, GTK_IMAGE (icon), + short_label, drag_action); } - table = gtk_table_new (0, 0, TRUE); - editor->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 (editor->priv->scrolled_window), table); - gtk_drag_dest_set (table, GTK_DEST_DEFAULT_ALL, - dest_drag_types, G_N_ELEMENTS (dest_drag_types), GDK_ACTION_MOVE); - g_signal_connect (table, "drag_data_received", - G_CALLBACK (editor_drag_data_received_cb), editor); - - to_drag = editor->priv->actions_list; - - x = y = 0; - width = 4; - height = (g_list_length (to_drag)) / width + 1; - gtk_table_resize (GTK_TABLE (editor->priv->table), height, width); - - for (l = to_drag; l != NULL; l = l->next) + else { - GtkAction *action = (l->data); - const char *stock_id, *short_label; GValue value = { 0, }; + GtkAction *action; + GtkWidget *icon; + + action = find_action (editor, name); + g_return_val_if_fail (action != NULL, NULL); g_value_init (&value, G_TYPE_STRING); g_object_get_property (G_OBJECT (action), "stock_id", &value); stock_id = g_value_get_string (&value); - icon = gtk_image_new_from_stock - (stock_id ? stock_id : GTK_STOCK_DND, - GTK_ICON_SIZE_LARGE_TOOLBAR); + icon = gtk_image_new_from_stock (stock_id ? stock_id : GTK_STOCK_DND, + GTK_ICON_SIZE_LARGE_TOOLBAR); g_value_unset (&value); - + g_value_init (&value, G_TYPE_STRING); g_object_get_property (G_OBJECT (action), "short_label", &value); short_label = g_value_get_string (&value); + + item_name = strdup (name); + collate_key = g_utf8_collate_key (short_label, -1); item = editor_create_item (editor, GTK_IMAGE (icon), - short_label, GDK_ACTION_MOVE); + short_label, drag_action); g_value_unset (&value); - g_object_set_data (G_OBJECT (item), "egg-action", action); - gtk_table_attach_defaults (GTK_TABLE (editor->priv->table), - item, x, x + 1, y, y + 1); + } + + g_object_set_data_full (G_OBJECT (item), "egg-collate-key", + (gpointer) collate_key, g_free); + g_object_set_data_full (G_OBJECT (item), "egg-item-name", + (gpointer) item_name, g_free); + + return item; +} - x++; - if (x >= width) - { - x = 0; - y++; - } +static gint +append_table (GtkTable *table, GList *items, gint y, gint width) +{ + if (items != NULL) + { + gint x = 0, height; + GtkWidget *alignment; + GtkWidget *item; + + height = g_list_length (items) / width + 1; + gtk_table_resize (table, height, width); + + if (y > 0) + { + item = gtk_hseparator_new (); + alignment = gtk_alignment_new (0.5, 0.5, 1.0, 0.0); + gtk_container_add (GTK_CONTAINER (alignment), item); + gtk_widget_show (alignment); + gtk_widget_show (item); + + gtk_table_attach_defaults (table, alignment, 0, width, y-1, y+1); + } + + for (; items != NULL; items = items->next) + { + item = items->data; + alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); + gtk_container_add (GTK_CONTAINER (alignment), item); + gtk_widget_show (alignment); + gtk_widget_show (item); + + if (x >= width) + { + x = 0; + y++; + } + gtk_table_attach_defaults (table, alignment, x, x+1, y, y+1); + x++; + } + + y++; } + return y; +} + +static void +update_editor_sheet (EggToolbarEditor *editor) +{ + gint y; + GPtrArray *items; + GList *to_move = NULL, *to_copy = NULL; + GtkWidget *table; + GtkWidget *viewport; + + g_return_if_fail (EGG_IS_TOOLBAR_EDITOR (editor)); + + /* Create new table. */ + table = gtk_table_new (0, 0, TRUE); + editor->priv->table = table; + gtk_container_set_border_width (GTK_CONTAINER (table), 12); + gtk_table_set_row_spacings (GTK_TABLE (table), 24); + gtk_widget_show (table); + gtk_drag_dest_set (table, GTK_DEST_DEFAULT_ALL, + dest_drag_types, G_N_ELEMENTS (dest_drag_types), + GDK_ACTION_MOVE | GDK_ACTION_COPY); + + /* Build two lists of items (one for copying, one for moving). */ + items = egg_toolbars_model_get_name_avail (editor->priv->model); + while (items->len > 0) + { + GtkWidget *item; + const char *name; + gint flags; + + name = g_ptr_array_index (items, 0); + g_ptr_array_remove_index_fast (items, 0); + + flags = egg_toolbars_model_get_name_flags (editor->priv->model, name); + if ((flags & EGG_TB_MODEL_NAME_INFINITE) == 0) + { + item = editor_create_item_from_name (editor, name, GDK_ACTION_MOVE); + if (item != NULL) + to_move = g_list_insert_sorted (to_move, item, compare_items); + } + else + { + item = editor_create_item_from_name (editor, name, GDK_ACTION_COPY); + if (item != NULL) + to_copy = g_list_insert_sorted (to_copy, item, compare_items); + } + } + + /* Add them to the sheet. */ + y = 0; + y = append_table (GTK_TABLE (table), to_move, y, 4); + y = append_table (GTK_TABLE (table), to_copy, y, 4); + + g_list_free (to_move); + g_list_free (to_copy); + g_ptr_array_free (items, TRUE); + + /* Delete old table. */ + viewport = GTK_BIN (editor->priv->scrolled_window)->child; + if (viewport) + { + gtk_container_remove (GTK_CONTAINER (viewport), + GTK_BIN (viewport)->child); + } + + /* Add table to window. */ + gtk_scrolled_window_add_with_viewport + (GTK_SCROLLED_WINDOW (editor->priv->scrolled_window), table); - icon = _egg_editable_toolbar_new_separator_image (); - item = editor_create_item (editor, GTK_IMAGE (icon), _("Separator"), - GDK_ACTION_COPY); - gtk_table_attach_defaults (GTK_TABLE (editor->priv->table), - item, x, x + 1, y, y + 1); } static void @@ -578,113 +612,8 @@ egg_toolbar_editor_init (EggToolbarEditor *t) t->priv = EGG_TOOLBAR_EDITOR_GET_PRIVATE (t); t->priv->manager = NULL; - t->priv->default_actions_list = NULL; t->priv->actions_list = NULL; setup_editor (t); } -void -egg_toolbar_editor_add_action (EggToolbarEditor *editor, - const char *action_name) -{ - GtkAction *action; - - action = find_action (editor, action_name); - g_return_if_fail (action != NULL); - - editor->priv->default_actions_list = g_list_insert_sorted - (editor->priv->default_actions_list, action, compare_actions); -} - -static void -parse_item_list (EggToolbarEditor *t, - xmlNodePtr child) -{ - while (child) - { - if (xmlStrEqual (child->name, (const xmlChar*) "toolitem")) - { - xmlChar *name; - - name = xmlGetProp (child, (const xmlChar*) "name"); - egg_toolbar_editor_add_action (t, (const char*)name); - xmlFree (name); - } - child = child->next; - } -} - -static gboolean -model_has_action (EggToolbarsModel *model, GtkAction *action) -{ - int i, l, n_items, n_toolbars; - - n_toolbars = egg_toolbars_model_n_toolbars (model); - for (i = 0; i < n_toolbars; i++) - { - n_items = egg_toolbars_model_n_items (model, i); - for (l = 0; l < n_items; l++) - { - const char *name; - const char *action_name; - gboolean sep; - - egg_toolbars_model_item_nth (model, i, l, &sep, &name, NULL); - action_name = gtk_action_get_name (action); - if (!sep && strcmp (name, action_name) == 0) return TRUE; - } - } - - return FALSE; -} - -static void -update_actions_list (EggToolbarEditor *editor) -{ - GList *l; - - if (editor->priv->actions_list) - g_list_free (editor->priv->actions_list); - - /* Remove the already used items */ - editor->priv->actions_list = NULL; - - for (l = editor->priv->default_actions_list; l != NULL; l = l->next) - { - GtkAction *action = GTK_ACTION (l->data); - - if (!model_has_action (editor->priv->model, action)) - { - editor->priv->actions_list = g_list_insert_sorted - (editor->priv->actions_list, action, compare_actions); - } - } -} - -void -egg_toolbar_editor_load_actions (EggToolbarEditor *editor, - const char *xml_file) -{ - xmlDocPtr doc; - xmlNodePtr root; - xmlNodePtr child; - - doc = xmlParseFile (xml_file); - root = xmlDocGetRootElement (doc); - child = root->children; - - while (child) - { - if (xmlStrEqual (child->name, (const xmlChar*) "available")) - { - parse_item_list (editor, child->children); - } - child = child->next; - } - - xmlFreeDoc (doc); - - update_actions_list (editor); - update_editor_sheet (editor); -} diff --git a/cut-n-paste/toolbar-editor/egg-toolbar-editor.h b/cut-n-paste/toolbar-editor/egg-toolbar-editor.h index e1e1f35..e29e548 100644 --- a/cut-n-paste/toolbar-editor/egg-toolbar-editor.h +++ b/cut-n-paste/toolbar-editor/egg-toolbar-editor.h @@ -56,11 +56,6 @@ struct EggToolbarEditorClass GType egg_toolbar_editor_get_type (void); GtkWidget *egg_toolbar_editor_new (GtkUIManager *manager, EggToolbarsModel *model); -void egg_toolbar_editor_load_actions (EggToolbarEditor *editor, - const char *xml_file); - -void egg_toolbar_editor_add_action (EggToolbarEditor *editor, - const char *action_name); G_END_DECLS diff --git a/cut-n-paste/toolbar-editor/egg-toolbars-model.c b/cut-n-paste/toolbar-editor/egg-toolbars-model.c index 56f4c8f..f0a5b0f 100644 --- a/cut-n-paste/toolbar-editor/egg-toolbars-model.c +++ b/cut-n-paste/toolbar-editor/egg-toolbars-model.c @@ -31,7 +31,7 @@ #include static void egg_toolbars_model_class_init (EggToolbarsModelClass *klass); -static void egg_toolbars_model_init (EggToolbarsModel *t); +static void egg_toolbars_model_init (EggToolbarsModel *model); static void egg_toolbars_model_finalize (GObject *object); enum @@ -41,9 +41,6 @@ enum TOOLBAR_ADDED, TOOLBAR_CHANGED, TOOLBAR_REMOVED, - GET_ITEM_TYPE, - GET_ITEM_ID, - GET_ITEM_DATA, LAST_SIGNAL }; @@ -55,9 +52,7 @@ typedef struct typedef struct { - char *id; - char *type; - gboolean separator; + char *name; } EggToolbarsItem; static guint signals[LAST_SIGNAL] = { 0 }; @@ -69,6 +64,8 @@ static GObjectClass *parent_class = NULL; struct EggToolbarsModelPrivate { GNode *toolbars; + GList *types; + GHashTable *flags; }; GType @@ -103,14 +100,15 @@ egg_toolbars_model_get_type (void) } static xmlDocPtr -egg_toolbars_model_to_xml (EggToolbarsModel *t) +egg_toolbars_model_to_xml (EggToolbarsModel *model) { GNode *l1, *l2, *tl; + GList *l3; xmlDocPtr doc; - g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), NULL); + g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), NULL); - tl = t->priv->toolbars; + tl = model->priv->toolbars; xmlIndentTreeOutput = TRUE; doc = xmlNewDoc ((const xmlChar*) "1.0"); @@ -123,25 +121,46 @@ egg_toolbars_model_to_xml (EggToolbarsModel *t) tnode = xmlNewChild (doc->children, NULL, (const xmlChar*) "toolbar", NULL); xmlSetProp (tnode, (const xmlChar*) "name", (const xmlChar*) toolbar->name); + xmlSetProp (tnode, (const xmlChar*) "hidden", + (toolbar->flags&EGG_TB_MODEL_HIDDEN) ? (const xmlChar*) "true" : (const xmlChar*) "false"); + xmlSetProp (tnode, (const xmlChar*) "editable", + (toolbar->flags&EGG_TB_MODEL_NOT_EDITABLE) ? (const xmlChar*) "false" : (const xmlChar*) "true"); for (l2 = l1->children; l2 != NULL; l2 = l2->next) { xmlNodePtr node; EggToolbarsItem *item = l2->data; - if (item->separator) - { - node = xmlNewChild (tnode, NULL, (const xmlChar*) "separator", NULL); - } - else - { - char *data; + if (strcmp (item->name, "_separator") == 0) + { + node = xmlNewChild (tnode, NULL, (const xmlChar*) "separator", NULL); + continue; + } + + node = xmlNewChild (tnode, NULL, (const xmlChar*) "toolitem", NULL); + xmlSetProp (node, (const xmlChar*) "name", (const xmlChar*) item->name); - node = xmlNewChild (tnode, NULL, (const xmlChar*) "toolitem", NULL); - data = egg_toolbars_model_get_item_data (t, item->type, item->id); - xmlSetProp (node, (const xmlChar*) "type", (const xmlChar*) item->type); - xmlSetProp (node, (const xmlChar*) "name", (const xmlChar*) data); - g_free (data); + /* Add 'data' nodes for each data type which can be written out for this + * item. Only write types which can be used to restore the data. */ + for (l3 = model->priv->types; l3 != NULL; l3 = l3->next) + { + EggToolbarsItemType *type = l3->data; + if (type->get_name != NULL && type->get_data != NULL) + { + xmlNodePtr dnode; + char *tmp; + + tmp = type->get_data (type, item->name); + if (tmp != NULL) + { + dnode = xmlNewTextChild (node, NULL, (const xmlChar*) "data", (const xmlChar*) tmp); + g_free (tmp); + + tmp = gdk_atom_name (type->type); + xmlSetProp (dnode, (const xmlChar*) "type", (const xmlChar*) tmp); + g_free (tmp); + } + } } } } @@ -206,24 +225,50 @@ safe_save_xml (const char *xml_file, xmlDocPtr doc) } void -egg_toolbars_model_save (EggToolbarsModel *t, - const char *xml_file, - const char *version) +egg_toolbars_model_save_toolbars (EggToolbarsModel *model, + const char *xml_file, + const char *version) { xmlDocPtr doc; xmlNodePtr root; - g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t)); + g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model)); - doc = egg_toolbars_model_to_xml (t); + doc = egg_toolbars_model_to_xml (model); root = xmlDocGetRootElement (doc); xmlSetProp (root, (const xmlChar*) "version", (const xmlChar*) version); safe_save_xml (xml_file, doc); xmlFreeDoc (doc); } -static EggToolbarsToolbar * -toolbars_toolbar_new (const char *name) +static gboolean +is_unique (EggToolbarsModel *model, + EggToolbarsItem *idata) +{ + EggToolbarsItem *idata2; + GNode *toolbar, *item; + + + for(toolbar = g_node_first_child (model->priv->toolbars); + toolbar != NULL; toolbar = g_node_next_sibling (toolbar)) + { + for(item = g_node_first_child (toolbar); + item != NULL; item = g_node_next_sibling (item)) + { + idata2 = item->data; + + if (idata != idata2 && strcmp (idata->name, idata2->name) == 0) + { + return FALSE; + } + } + } + + return TRUE; +} + +static GNode * +toolbar_node_new (const char *name) { EggToolbarsToolbar *toolbar; @@ -231,58 +276,69 @@ toolbars_toolbar_new (const char *name) toolbar->name = g_strdup (name); toolbar->flags = 0; - return toolbar; + return g_node_new (toolbar); } -static EggToolbarsItem * -toolbars_item_new (const char *id, - const char *type, - gboolean separator) +static GNode * +item_node_new (const char *name, EggToolbarsModel *model) { EggToolbarsItem *item; + int flags; - g_return_val_if_fail (id != NULL, NULL); - g_return_val_if_fail (type != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); item = g_new (EggToolbarsItem, 1); - item->id = g_strdup (id); - item->type = g_strdup (type); - item->separator = separator; + item->name = g_strdup (name); + + flags = GPOINTER_TO_INT (g_hash_table_lookup (model->priv->flags, item->name)); + if ((flags & EGG_TB_MODEL_NAME_INFINITE) == 0) + g_hash_table_insert (model->priv->flags, + g_strdup (item->name), + GINT_TO_POINTER (flags | EGG_TB_MODEL_NAME_USED)); - return item; + return g_node_new (item); } static void -free_toolbar_node (GNode *toolbar_node) +item_node_free (GNode *item_node, EggToolbarsModel *model) { - EggToolbarsToolbar *toolbar = toolbar_node->data; + EggToolbarsItem *item = item_node->data; + int flags; - g_free (toolbar->name); - g_free (toolbar); + flags = GPOINTER_TO_INT (g_hash_table_lookup (model->priv->flags, item->name)); + if ((flags & EGG_TB_MODEL_NAME_INFINITE) == 0 && is_unique (model, item)) + g_hash_table_insert (model->priv->flags, + g_strdup (item->name), + GINT_TO_POINTER (flags & ~EGG_TB_MODEL_NAME_USED)); - g_node_destroy (toolbar_node); + g_free (item->name); + g_free (item); + + g_node_destroy (item_node); } static void -free_item_node (GNode *item_node) +toolbar_node_free (GNode *toolbar_node, EggToolbarsModel *model) { - EggToolbarsItem *item = item_node->data; + EggToolbarsToolbar *toolbar = toolbar_node->data; - g_free (item->id); - g_free (item->type); - g_free (item); + g_node_children_foreach (toolbar_node, G_TRAVERSE_ALL, + (GNodeForeachFunc) item_node_free, model); + + g_free (toolbar->name); + g_free (toolbar); - g_node_destroy (item_node); + g_node_destroy (toolbar_node); } EggTbModelFlags -egg_toolbars_model_get_flags (EggToolbarsModel *t, +egg_toolbars_model_get_flags (EggToolbarsModel *model, int toolbar_position) { GNode *toolbar_node; EggToolbarsToolbar *toolbar; - toolbar_node = g_node_nth_child (t->priv->toolbars, toolbar_position); + toolbar_node = g_node_nth_child (model->priv->toolbars, toolbar_position); g_return_val_if_fail (toolbar_node != NULL, 0); toolbar = toolbar_node->data; @@ -291,78 +347,182 @@ egg_toolbars_model_get_flags (EggToolbarsModel *t, } void -egg_toolbars_model_set_flags (EggToolbarsModel *t, +egg_toolbars_model_set_flags (EggToolbarsModel *model, int toolbar_position, EggTbModelFlags flags) { GNode *toolbar_node; EggToolbarsToolbar *toolbar; - toolbar_node = g_node_nth_child (t->priv->toolbars, toolbar_position); + toolbar_node = g_node_nth_child (model->priv->toolbars, toolbar_position); g_return_if_fail (toolbar_node != NULL); toolbar = toolbar_node->data; toolbar->flags = flags; - g_signal_emit (G_OBJECT (t), signals[TOOLBAR_CHANGED], + g_signal_emit (G_OBJECT (model), signals[TOOLBAR_CHANGED], 0, toolbar_position); } -void -egg_toolbars_model_add_separator (EggToolbarsModel *t, - int toolbar_position, - int position) + +char * +egg_toolbars_model_get_data (EggToolbarsModel *model, + GdkAtom type, + const char *name) +{ + EggToolbarsItemType *t; + char *data = NULL; + GList *l; + + if (type == GDK_NONE || type == gdk_atom_intern (EGG_TOOLBAR_ITEM_TYPE, FALSE)) + { + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (*name != 0, NULL); + return strdup (name); + } + + for (l = model->priv->types; l != NULL; l = l->next) + { + t = l->data; + if (t->type == type && t->get_data != NULL) + { + data = t->get_data (t, name); + if (data != NULL) break; + } + } + + return data; +} + +char * +egg_toolbars_model_get_name (EggToolbarsModel *model, + GdkAtom type, + const char *data, + gboolean create) +{ + EggToolbarsItemType *t; + char *name = NULL; + GList *l; + + if (type == GDK_NONE || type == gdk_atom_intern (EGG_TOOLBAR_ITEM_TYPE, FALSE)) + { + g_return_val_if_fail (data, NULL); + g_return_val_if_fail (*data, NULL); + return strdup (data); + } + + if (create) + { + for (l = model->priv->types; name == NULL && l != NULL; l = l->next) + { + t = l->data; + if (t->type == type && t->new_name != NULL) + name = t->new_name (t, data); + } + + return name; + } + else + { + for (l = model->priv->types; name == NULL && l != NULL; l = l->next) + { + t = l->data; + if (t->type == type && t->get_name != NULL) + name = t->get_name (t, data); + } + + return name; + } +} + +static gboolean +impl_add_item (EggToolbarsModel *model, + int toolbar_position, + int position, + const char *name) { GNode *parent_node; - GNode *node; - EggToolbarsItem *item; + GNode *child_node; int real_position; - g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t)); + g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), FALSE); + g_return_val_if_fail (name != NULL, FALSE); - parent_node = g_node_nth_child (t->priv->toolbars, toolbar_position); - item = toolbars_item_new ("separator", EGG_TOOLBAR_ITEM_TYPE, TRUE); - node = g_node_new (item); - g_node_insert (parent_node, position, node); + parent_node = g_node_nth_child (model->priv->toolbars, toolbar_position); + child_node = item_node_new (name, model); + g_node_insert (parent_node, position, child_node); - real_position = g_node_child_position (parent_node, node); + real_position = g_node_child_position (parent_node, child_node); - g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0, + g_signal_emit (G_OBJECT (model), signals[ITEM_ADDED], 0, toolbar_position, real_position); + + return TRUE; } -static gboolean -impl_add_item (EggToolbarsModel *t, - int toolbar_position, - int position, - const char *id, - const char *type) +gboolean +egg_toolbars_model_add_item (EggToolbarsModel *model, + int toolbar_position, + int position, + const char *name) +{ + EggToolbarsModelClass *klass = EGG_TOOLBARS_MODEL_GET_CLASS (model); + return klass->add_item (model, toolbar_position, position, name); +} + +int +egg_toolbars_model_add_toolbar (EggToolbarsModel *model, + int position, + const char *name) { - GNode *parent_node; GNode *node; - EggToolbarsItem *item; int real_position; - g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), FALSE); - g_return_val_if_fail (id != NULL, FALSE); - g_return_val_if_fail (type != NULL, FALSE); + g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), -1); - parent_node = g_node_nth_child (t->priv->toolbars, toolbar_position); - item = toolbars_item_new (id, type, FALSE); - node = g_node_new (item); - g_node_insert (parent_node, position, node); + node = toolbar_node_new (name); + g_node_insert (model->priv->toolbars, position, node); - real_position = g_node_child_position (parent_node, node); + real_position = g_node_child_position (model->priv->toolbars, node); - g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0, - toolbar_position, real_position); + g_signal_emit (G_OBJECT (model), signals[TOOLBAR_ADDED], + 0, real_position); - return TRUE; + return g_node_child_position (model->priv->toolbars, node); +} + +static char * +parse_data_list (EggToolbarsModel *model, + xmlNodePtr child, + gboolean create) +{ + char *name = NULL; + while (child && name == NULL) + { + if (xmlStrEqual (child->name, (const xmlChar*) "data")) + { + xmlChar *type = xmlGetProp (child, (const xmlChar*) "type"); + xmlChar *data = xmlNodeGetContent (child); + + if (type != NULL) + { + GdkAtom atom = gdk_atom_intern ((const char*) type, TRUE); + name = egg_toolbars_model_get_name (model, atom, (const char*) data, create); + } + + xmlFree (type); + xmlFree (data); + } + + child = child->next; + } + + return name; } static void -parse_item_list (EggToolbarsModel *t, +parse_item_list (EggToolbarsModel *model, xmlNodePtr child, int position) { @@ -370,83 +530,84 @@ parse_item_list (EggToolbarsModel *t, { if (xmlStrEqual (child->name, (const xmlChar*) "toolitem")) { - xmlChar *name, *type; - char *id; + char *name; - name = xmlGetProp (child, (const xmlChar*) "name"); - type = xmlGetProp (child, (const xmlChar*) "type"); - if (type == NULL) + /* Try to get the name using the data elements first, + as they are more 'portable' or 'persistent'. */ + name = parse_data_list (model, child->children, FALSE); + if (name == NULL) { - type = xmlCharStrdup (EGG_TOOLBAR_ITEM_TYPE); + name = parse_data_list (model, child->children, TRUE); } - - if (name != NULL && name[0] != '\0' && type != NULL) - { - id = egg_toolbars_model_get_item_id (t, (const char*)type, (const char*)name); - if (id != NULL) - { - egg_toolbars_model_add_item (t, position, -1, id, (const char*)type); + + /* If that fails, try to use the name. */ + if (name == NULL) + { + xmlChar *type = xmlGetProp (child, (const xmlChar*) "type"); + xmlChar *data = xmlGetProp (child, (const xmlChar*) "name"); + GdkAtom atom = type ? gdk_atom_intern ((const char*) type, TRUE) : GDK_NONE; + + /* If an old format, try to use it. */ + name = egg_toolbars_model_get_name (model, atom, (const char*) data, FALSE); + if (name == NULL) + { + name = egg_toolbars_model_get_name (model, atom, (const char*) data, TRUE); } - g_free (id); + + xmlFree (type); + xmlFree (data); + } + + if (name != NULL) + { + egg_toolbars_model_add_item (model, position, -1, name); + g_free (name); } - xmlFree (name); - xmlFree (type); } else if (xmlStrEqual (child->name, (const xmlChar*) "separator")) { - egg_toolbars_model_add_separator (t, position, -1); + egg_toolbars_model_add_item (model, position, -1, "_separator"); } child = child->next; } } -int -egg_toolbars_model_add_toolbar (EggToolbarsModel *t, - int position, - const char *name) -{ - GNode *node; - int real_position; - - g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), -1); - - node = g_node_new (toolbars_toolbar_new (name)); - g_node_insert (t->priv->toolbars, position, node); - - real_position = g_node_child_position (t->priv->toolbars, node); - - g_signal_emit (G_OBJECT (t), signals[TOOLBAR_ADDED], - 0, real_position); - - return g_node_child_position (t->priv->toolbars, node); -} - static void -parse_toolbars (EggToolbarsModel *t, +parse_toolbars (EggToolbarsModel *model, xmlNodePtr child) { while (child) { if (xmlStrEqual (child->name, (const xmlChar*) "toolbar")) { - xmlChar *name; - xmlChar *style; + xmlChar *string; int position; - - name = xmlGetProp (child, (const xmlChar*) "name"); - position = egg_toolbars_model_add_toolbar (t, -1, (const char*) name); - xmlFree (name); - - style = xmlGetProp (child, (const xmlChar*) "style"); - if (style && xmlStrEqual (style, (const xmlChar*) "icons-only")) - { - /* FIXME: use toolbar position instead of 0 */ - egg_toolbars_model_set_flags (t, 0, EGG_TB_MODEL_ICONS); - } - xmlFree (style); - - parse_item_list (t, child->children, position); + EggTbModelFlags flags; + + string = xmlGetProp (child, (const xmlChar*) "name"); + position = egg_toolbars_model_add_toolbar (model, -1, (const char*) string); + flags = egg_toolbars_model_get_flags (model, position); + xmlFree (string); + + string = xmlGetProp (child, (const xmlChar*) "editable"); + if (string && xmlStrEqual (string, (const xmlChar*) "false")) + flags |= EGG_TB_MODEL_NOT_EDITABLE; + xmlFree (string); + + string = xmlGetProp (child, (const xmlChar*) "hidden"); + if (string && xmlStrEqual (string, (const xmlChar*) "true")) + flags |= EGG_TB_MODEL_HIDDEN; + xmlFree (string); + + string = xmlGetProp (child, (const xmlChar*) "style"); + if (string && xmlStrEqual (string, (const xmlChar*) "icons-only")) + flags |= EGG_TB_MODEL_ICONS; + xmlFree (string); + + egg_toolbars_model_set_flags (model, position, flags); + + parse_item_list (model, child->children, position); } child = child->next; @@ -454,13 +615,13 @@ parse_toolbars (EggToolbarsModel *t, } gboolean -egg_toolbars_model_load (EggToolbarsModel *t, - const char *xml_file) +egg_toolbars_model_load_toolbars (EggToolbarsModel *model, + const char *xml_file) { xmlDocPtr doc; xmlNodePtr root; - g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), FALSE); + g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), FALSE); if (!xml_file || !g_file_test (xml_file, G_FILE_TEST_EXISTS)) return FALSE; @@ -472,67 +633,76 @@ egg_toolbars_model_load (EggToolbarsModel *t, } root = xmlDocGetRootElement (doc); - parse_toolbars (t, root->children); + parse_toolbars (model, root->children); xmlFreeDoc (doc); return TRUE; } -static char * -impl_get_item_id (EggToolbarsModel *t, - const char *type, - const char *data) +static void +parse_available_list (EggToolbarsModel *model, + xmlNodePtr child) { - if (strcmp (type, EGG_TOOLBAR_ITEM_TYPE) == 0) + gint flags; + + while (child) { - return g_strdup (data); - } + if (xmlStrEqual (child->name, (const xmlChar*) "toolitem")) + { + xmlChar *name; - return NULL; + name = xmlGetProp (child, (const xmlChar*) "name"); + flags = egg_toolbars_model_get_name_flags + (model, (const char*)name); + egg_toolbars_model_set_name_flags + (model, (const char*)name, flags | EGG_TB_MODEL_NAME_KNOWN); + xmlFree (name); + } + child = child->next; + } } -static char * -impl_get_item_data (EggToolbarsModel *t, - const char *type, - const char *id) +static void +parse_names (EggToolbarsModel *model, + xmlNodePtr child) { - if (strcmp (type, EGG_TOOLBAR_ITEM_TYPE) == 0) + while (child) { - return g_strdup (id); - } + if (xmlStrEqual (child->name, (const xmlChar*) "available")) + { + parse_available_list (model, child->children); + } - return NULL; + child = child->next; + } } -static char * -impl_get_item_type (EggToolbarsModel *t, - GdkAtom type) +gboolean +egg_toolbars_model_load_names (EggToolbarsModel *model, + const char *xml_file) { - if (gdk_atom_intern (EGG_TOOLBAR_ITEM_TYPE, FALSE) == type) - { - return g_strdup (EGG_TOOLBAR_ITEM_TYPE); - } + xmlDocPtr doc; + xmlNodePtr root; - return NULL; -} + g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), FALSE); -static gboolean -_egg_accumulator_STRING (GSignalInvocationHint *ihint, - GValue *return_accu, - const GValue *handler_return, - gpointer dummy) -{ - gboolean continue_emission; - const char *retval; + if (!xml_file || !g_file_test (xml_file, G_FILE_TEST_EXISTS)) return FALSE; - retval = g_value_get_string (handler_return); - g_value_set_string (return_accu, retval); - continue_emission = !retval || !retval[0]; - - return continue_emission; -} + doc = xmlParseFile (xml_file); + if (doc == NULL) + { + g_warning ("Failed to load XML data from %s", xml_file); + return FALSE; + } + root = xmlDocGetRootElement (doc); + parse_names (model, root->children); + + xmlFreeDoc (doc); + + return TRUE; +} static void egg_toolbars_model_class_init (EggToolbarsModelClass *klass) @@ -544,9 +714,6 @@ egg_toolbars_model_class_init (EggToolbarsModelClass *klass) object_class->finalize = egg_toolbars_model_finalize; klass->add_item = impl_add_item; - klass->get_item_id = impl_get_item_id; - klass->get_item_data = impl_get_item_data; - klass->get_item_type = impl_get_item_type; signals[ITEM_ADDED] = g_signal_new ("item_added", @@ -583,58 +750,31 @@ egg_toolbars_model_class_init (EggToolbarsModelClass *klass) G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_changed), NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); - signals[GET_ITEM_TYPE] = - g_signal_new ("get_item_type", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EggToolbarsModelClass, get_item_type), - _egg_accumulator_STRING, NULL, - _egg_marshal_STRING__POINTER, - G_TYPE_STRING, 1, G_TYPE_POINTER); - signals[GET_ITEM_ID] = - g_signal_new ("get_item_id", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EggToolbarsModelClass, get_item_id), - _egg_accumulator_STRING, NULL, - _egg_marshal_STRING__STRING_STRING, - G_TYPE_STRING, 2, G_TYPE_STRING, G_TYPE_STRING); - signals[GET_ITEM_DATA] = - g_signal_new ("get_item_data", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EggToolbarsModelClass, get_item_data), - _egg_accumulator_STRING, NULL, - _egg_marshal_STRING__STRING_STRING, - G_TYPE_STRING, 2, G_TYPE_STRING, G_TYPE_STRING); g_type_class_add_private (object_class, sizeof (EggToolbarsModelPrivate)); } static void -egg_toolbars_model_init (EggToolbarsModel *t) +egg_toolbars_model_init (EggToolbarsModel *model) { - t->priv =EGG_TOOLBARS_MODEL_GET_PRIVATE (t); - - t->priv->toolbars = g_node_new (NULL); -} + model->priv =EGG_TOOLBARS_MODEL_GET_PRIVATE (model); -static void -free_toolbar (GNode *toolbar_node) -{ - g_node_children_foreach (toolbar_node, G_TRAVERSE_ALL, - (GNodeForeachFunc) free_item_node, NULL); - free_toolbar_node (toolbar_node); + model->priv->toolbars = g_node_new (NULL); + model->priv->flags = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + egg_toolbars_model_set_name_flags (model, "_separator", + EGG_TB_MODEL_NAME_KNOWN | + EGG_TB_MODEL_NAME_INFINITE); } static void egg_toolbars_model_finalize (GObject *object) { - EggToolbarsModel *t = EGG_TOOLBARS_MODEL (object); + EggToolbarsModel *model = EGG_TOOLBARS_MODEL (object); - g_node_children_foreach (t->priv->toolbars, G_TRAVERSE_ALL, - (GNodeForeachFunc) free_toolbar, NULL); - g_node_destroy (t->priv->toolbars); + g_node_children_foreach (model->priv->toolbars, G_TRAVERSE_ALL, + (GNodeForeachFunc) toolbar_node_free, model); + g_node_destroy (model->priv->toolbars); + g_hash_table_destroy (model->priv->flags); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -646,51 +786,51 @@ egg_toolbars_model_new (void) } void -egg_toolbars_model_remove_toolbar (EggToolbarsModel *t, +egg_toolbars_model_remove_toolbar (EggToolbarsModel *model, int position) { GNode *node; EggTbModelFlags flags; - g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t)); + g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model)); - flags = egg_toolbars_model_get_flags (t, position); + flags = egg_toolbars_model_get_flags (model, position); if (!(flags & EGG_TB_MODEL_NOT_REMOVABLE)) { - node = g_node_nth_child (t->priv->toolbars, position); + node = g_node_nth_child (model->priv->toolbars, position); g_return_if_fail (node != NULL); - free_toolbar_node (node); + toolbar_node_free (node, model); - g_signal_emit (G_OBJECT (t), signals[TOOLBAR_REMOVED], + g_signal_emit (G_OBJECT (model), signals[TOOLBAR_REMOVED], 0, position); } } void -egg_toolbars_model_remove_item (EggToolbarsModel *t, +egg_toolbars_model_remove_item (EggToolbarsModel *model, int toolbar_position, int position) { GNode *node, *toolbar; - g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t)); + g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model)); - toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position); + toolbar = g_node_nth_child (model->priv->toolbars, toolbar_position); g_return_if_fail (toolbar != NULL); node = g_node_nth_child (toolbar, position); g_return_if_fail (node != NULL); - free_item_node (node); + item_node_free (node, model); - g_signal_emit (G_OBJECT (t), signals[ITEM_REMOVED], 0, + g_signal_emit (G_OBJECT (model), signals[ITEM_REMOVED], 0, toolbar_position, position); } void -egg_toolbars_model_move_item (EggToolbarsModel *t, +egg_toolbars_model_move_item (EggToolbarsModel *model, int toolbar_position, int position, int new_toolbar_position, @@ -698,12 +838,12 @@ egg_toolbars_model_move_item (EggToolbarsModel *t, { GNode *node, *toolbar, *new_toolbar; - g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t)); + g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model)); - toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position); + toolbar = g_node_nth_child (model->priv->toolbars, toolbar_position); g_return_if_fail (toolbar != NULL); - new_toolbar = g_node_nth_child (t->priv->toolbars, new_toolbar_position); + new_toolbar = g_node_nth_child (model->priv->toolbars, new_toolbar_position); g_return_if_fail (new_toolbar != NULL); node = g_node_nth_child (toolbar, position); @@ -711,74 +851,125 @@ egg_toolbars_model_move_item (EggToolbarsModel *t, g_node_unlink (node); - g_signal_emit (G_OBJECT (t), signals[ITEM_REMOVED], 0, + g_signal_emit (G_OBJECT (model), signals[ITEM_REMOVED], 0, toolbar_position, position); g_node_insert (new_toolbar, new_position, node); - g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0, + g_signal_emit (G_OBJECT (model), signals[ITEM_ADDED], 0, new_toolbar_position, new_position); } +void +egg_toolbars_model_delete_item (EggToolbarsModel *model, + const char *name) +{ + EggToolbarsItem *idata; + EggToolbarsToolbar *tdata; + GNode *toolbar, *item, *next; + int tpos, ipos; + + g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model)); + + toolbar = g_node_first_child (model->priv->toolbars); + tpos = 0; + + while (toolbar != NULL) + { + item = g_node_first_child (toolbar); + ipos = 0; + + /* Don't delete toolbars that were already empty */ + if (item == NULL) + { + toolbar = g_node_next_sibling (toolbar); + continue; + } + + while (item != NULL) + { + next = g_node_next_sibling (item); + idata = item->data; + if (strcmp (idata->name, name) == 0) + { + item_node_free (item, model); + g_signal_emit (G_OBJECT (model), + signals[ITEM_REMOVED], + 0, tpos, ipos); + } + else + { + ipos++; + } + + item = next; + } + + next = g_node_next_sibling (toolbar); + tdata = toolbar->data; + if (!(tdata->flags & EGG_TB_MODEL_NOT_REMOVABLE) && + g_node_first_child (toolbar) == NULL) + { + toolbar_node_free (toolbar, model); + + g_signal_emit (G_OBJECT (model), + signals[TOOLBAR_REMOVED], + 0, tpos); + } + else + { + tpos++; + } + + toolbar = next; + } +} + int -egg_toolbars_model_n_items (EggToolbarsModel *t, +egg_toolbars_model_n_items (EggToolbarsModel *model, int toolbar_position) { GNode *toolbar; - toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position); + toolbar = g_node_nth_child (model->priv->toolbars, toolbar_position); g_return_val_if_fail (toolbar != NULL, -1); return g_node_n_children (toolbar); } -void -egg_toolbars_model_item_nth (EggToolbarsModel *t, +const char * +egg_toolbars_model_item_nth (EggToolbarsModel *model, int toolbar_position, - int position, - gboolean *is_separator, - const char **id, - const char **type) + int position) { GNode *toolbar; GNode *item; EggToolbarsItem *idata; - toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position); - g_return_if_fail (toolbar != NULL); + toolbar = g_node_nth_child (model->priv->toolbars, toolbar_position); + g_return_val_if_fail (toolbar != NULL, NULL); item = g_node_nth_child (toolbar, position); - g_return_if_fail (item != NULL); + g_return_val_if_fail (item != NULL, NULL); idata = item->data; - - *is_separator = idata->separator; - - if (id) - { - *id = idata->id; - } - - if (type) - { - *type = idata->type; - } + return idata->name; } int -egg_toolbars_model_n_toolbars (EggToolbarsModel *t) +egg_toolbars_model_n_toolbars (EggToolbarsModel *model) { - return g_node_n_children (t->priv->toolbars); + return g_node_n_children (model->priv->toolbars); } const char * -egg_toolbars_model_toolbar_nth (EggToolbarsModel *t, +egg_toolbars_model_toolbar_nth (EggToolbarsModel *model, int position) { GNode *toolbar; EggToolbarsToolbar *tdata; - toolbar = g_node_nth_child (t->priv->toolbars, position); + toolbar = g_node_nth_child (model->priv->toolbars, position); g_return_val_if_fail (toolbar != NULL, NULL); tdata = toolbar->data; @@ -786,48 +977,42 @@ egg_toolbars_model_toolbar_nth (EggToolbarsModel *t, return tdata->name; } -gboolean -egg_toolbars_model_add_item (EggToolbarsModel *t, - int toolbar_position, - int position, - const char *id, - const char *type) +GList * +egg_toolbars_model_get_types (EggToolbarsModel *model) { - EggToolbarsModelClass *klass = EGG_TOOLBARS_MODEL_GET_CLASS (t); - return klass->add_item (t, toolbar_position, position, id, type); + return model->priv->types; } -char * -egg_toolbars_model_get_item_id (EggToolbarsModel *t, - const char *type, - const char *name) +void +egg_toolbars_model_set_types (EggToolbarsModel *model, GList *types) { - char *retval; - - g_signal_emit (t, signals[GET_ITEM_ID], 0, type, name, &retval); - - return retval; + model->priv->types = types; } -char * -egg_toolbars_model_get_item_data (EggToolbarsModel *t, - const char *type, - const char *id) +static void +fill_avail_array (gpointer key, gpointer value, GPtrArray *array) { - char *retval; - - g_signal_emit (t, signals[GET_ITEM_DATA], 0, type, id, &retval); - - return retval; + int flags = GPOINTER_TO_INT (value); + if ((flags & EGG_TB_MODEL_NAME_KNOWN) && !(flags & EGG_TB_MODEL_NAME_USED)) + g_ptr_array_add (array, key); } -char * -egg_toolbars_model_get_item_type (EggToolbarsModel *t, - GdkAtom type) +GPtrArray * +egg_toolbars_model_get_name_avail (EggToolbarsModel *model) { - char *retval; + GPtrArray *array = g_ptr_array_new (); + g_hash_table_foreach (model->priv->flags, (GHFunc) fill_avail_array, array); + return array; +} - g_signal_emit (t, signals[GET_ITEM_TYPE], 0, type, &retval); +gint +egg_toolbars_model_get_name_flags (EggToolbarsModel *model, const char *name) +{ + return GPOINTER_TO_INT (g_hash_table_lookup (model->priv->flags, name)); +} - return retval; +void +egg_toolbars_model_set_name_flags (EggToolbarsModel *model, const char *name, gint flags) +{ + g_hash_table_insert (model->priv->flags, g_strdup (name), GINT_TO_POINTER (flags)); } diff --git a/cut-n-paste/toolbar-editor/egg-toolbars-model.h b/cut-n-paste/toolbar-editor/egg-toolbars-model.h index aaaa214..6961ee4 100644 --- a/cut-n-paste/toolbar-editor/egg-toolbars-model.h +++ b/cut-n-paste/toolbar-editor/egg-toolbars-model.h @@ -43,14 +43,23 @@ typedef struct EggToolbarsModelClass EggToolbarsModelClass; typedef enum { EGG_TB_MODEL_NOT_REMOVABLE = 1 << 0, - EGG_TB_MODEL_BOTH = 1 << 1, - EGG_TB_MODEL_BOTH_HORIZ = 1 << 2, - EGG_TB_MODEL_ICONS = 1 << 3, - EGG_TB_MODEL_TEXT = 1 << 4, - EGG_TB_MODEL_STYLES_MASK = 0x1F, - EGG_TB_MODEL_ACCEPT_ITEMS_ONLY = 1 << 5 + EGG_TB_MODEL_NOT_EDITABLE = 1 << 1, + EGG_TB_MODEL_BOTH = 1 << 2, + EGG_TB_MODEL_BOTH_HORIZ = 1 << 3, + EGG_TB_MODEL_ICONS = 1 << 4, + EGG_TB_MODEL_TEXT = 1 << 5, + EGG_TB_MODEL_STYLES_MASK = 0x3C, + EGG_TB_MODEL_ACCEPT_ITEMS_ONLY = 1 << 6, + EGG_TB_MODEL_HIDDEN = 1 << 7 } EggTbModelFlags; +typedef enum +{ + EGG_TB_MODEL_NAME_USED = 1 << 0, + EGG_TB_MODEL_NAME_INFINITE = 1 << 1, + EGG_TB_MODEL_NAME_KNOWN = 1 << 2 +} EggTbModelNameFlags; + struct EggToolbarsModel { GObject parent_object; @@ -76,57 +85,83 @@ struct EggToolbarsModelClass int position); void (* toolbar_removed) (EggToolbarsModel *model, int position); - char * (* get_item_type) (EggToolbarsModel *model, - GdkAtom dnd_type); - char * (* get_item_id) (EggToolbarsModel *model, - const char *type, - const char *data); - char * (* get_item_data) (EggToolbarsModel *model, - const char *type, - const char *id); /* Virtual Table */ gboolean (* add_item) (EggToolbarsModel *t, int toolbar_position, int position, - const char *id, - const char *type); + const char *name); +}; + +typedef struct EggToolbarsItemType EggToolbarsItemType; + +struct EggToolbarsItemType +{ + GdkAtom type; + + gboolean (* has_data) (EggToolbarsItemType *type, + const char *name); + char * (* get_data) (EggToolbarsItemType *type, + const char *name); + + char * (* new_name) (EggToolbarsItemType *type, + const char *data); + char * (* get_name) (EggToolbarsItemType *type, + const char *data); }; GType egg_toolbars_model_flags_get_type (void); GType egg_toolbars_model_get_type (void); EggToolbarsModel *egg_toolbars_model_new (void); -gboolean egg_toolbars_model_load (EggToolbarsModel *model, +gboolean egg_toolbars_model_load_names (EggToolbarsModel *model, + const char *xml_file); +gboolean egg_toolbars_model_load_toolbars (EggToolbarsModel *model, const char *xml_file); -void egg_toolbars_model_save (EggToolbarsModel *model, +void egg_toolbars_model_save_toolbars (EggToolbarsModel *model, const char *xml_file, const char *version); -int egg_toolbars_model_add_toolbar (EggToolbarsModel *model, - int position, - const char *name); + +/* Functions for manipulating the types of portable data this toolbar understands. */ +GList * egg_toolbars_model_get_types (EggToolbarsModel *model); +void egg_toolbars_model_set_types (EggToolbarsModel *model, + GList *types); + +/* Functions for converting between name and portable data. */ +char * egg_toolbars_model_get_name (EggToolbarsModel *model, + GdkAtom type, + const char *data, + gboolean create); +char * egg_toolbars_model_get_data (EggToolbarsModel *model, + GdkAtom type, + const char *name); + +/* Functions for retrieving what items are available for adding to the toolbars. */ +GPtrArray * egg_toolbars_model_get_name_avail (EggToolbarsModel *model); +gint egg_toolbars_model_get_name_flags (EggToolbarsModel *model, + const char *name); +void egg_toolbars_model_set_name_flags (EggToolbarsModel *model, + const char *name, + gint flags); + +/* Functions for manipulating flags on individual toolbars. */ EggTbModelFlags egg_toolbars_model_get_flags (EggToolbarsModel *model, int toolbar_position); void egg_toolbars_model_set_flags (EggToolbarsModel *model, int toolbar_position, EggTbModelFlags flags); -void egg_toolbars_model_add_separator (EggToolbarsModel *model, - int toolbar_position, + +/* Functions for adding and removing toolbars. */ +int egg_toolbars_model_add_toolbar (EggToolbarsModel *model, + int position, + const char *name); +void egg_toolbars_model_remove_toolbar (EggToolbarsModel *model, int position); -char *egg_toolbars_model_get_item_type (EggToolbarsModel *model, - GdkAtom dnd_type); -char *egg_toolbars_model_get_item_id (EggToolbarsModel *model, - const char *type, - const char *name); -char *egg_toolbars_model_get_item_data (EggToolbarsModel *model, - const char *type, - const char *id); + +/* Functions for adding, removing and moving items. */ gboolean egg_toolbars_model_add_item (EggToolbarsModel *model, int toolbar_position, int position, - const char *id, - const char *type); -void egg_toolbars_model_remove_toolbar (EggToolbarsModel *model, - int position); + const char *name); void egg_toolbars_model_remove_item (EggToolbarsModel *model, int toolbar_position, int position); @@ -135,14 +170,17 @@ void egg_toolbars_model_move_item (EggToolbarsModel *model, int position, int new_toolbar_position, int new_position); +void egg_toolbars_model_delete_item (EggToolbarsModel *model, + const char *name); + +/* Functions for accessing the names of items. */ int egg_toolbars_model_n_items (EggToolbarsModel *model, int toolbar_position); -void egg_toolbars_model_item_nth (EggToolbarsModel *model, +const char * egg_toolbars_model_item_nth (EggToolbarsModel *model, int toolbar_position, - int position, - gboolean *is_separator, - const char **id, - const char **type); + int position); + +/* Functions for accessing the names of toolbars. */ int egg_toolbars_model_n_toolbars (EggToolbarsModel *model); const char *egg_toolbars_model_toolbar_nth (EggToolbarsModel *model, int position); diff --git a/cut-n-paste/toolbar-editor/eggintl.h b/cut-n-paste/toolbar-editor/eggintl.h deleted file mode 100644 index a427185..0000000 --- a/cut-n-paste/toolbar-editor/eggintl.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __EGG_INTL_H__ -#define __EGG_INTL_H__ - -/* We don't support gettext yet, dunno if we should /Anders */ -#define _(x) (x) -#define N_(x) (x) - -#endif /* __EGG_INTL_H__ */ diff --git a/cut-n-paste/toolbar-editor/eggtreemultidnd.c b/cut-n-paste/toolbar-editor/eggtreemultidnd.c new file mode 100644 index 0000000..3a7da91 --- /dev/null +++ b/cut-n-paste/toolbar-editor/eggtreemultidnd.c @@ -0,0 +1,414 @@ +/* eggtreemultidnd.c + * Copyright (C) 2001 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include "eggtreemultidnd.h" + +#define EGG_TREE_MULTI_DND_STRING "EggTreeMultiDndString" + +typedef struct +{ + guint pressed_button; + gint x; + gint y; + guint motion_notify_handler; + guint button_release_handler; + guint drag_data_get_handler; + GSList *event_list; +} EggTreeMultiDndData; + +/* CUT-N-PASTE from gtktreeview.c */ +typedef struct _TreeViewDragInfo TreeViewDragInfo; +struct _TreeViewDragInfo +{ + GdkModifierType start_button_mask; + GtkTargetList *source_target_list; + GdkDragAction source_actions; + + GtkTargetList *dest_target_list; + + guint source_set : 1; + guint dest_set : 1; +}; + + +GType +egg_tree_multi_drag_source_get_type (void) +{ + static GType our_type = 0; + + if (!our_type) + { + static const GTypeInfo our_info = + { + sizeof (EggTreeMultiDragSourceIface), /* class_size */ + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL + }; + + our_type = g_type_register_static (G_TYPE_INTERFACE, "EggTreeMultiDragSource", &our_info, 0); + } + + return our_type; +} + + +/** + * egg_tree_multi_drag_source_row_draggable: + * @drag_source: a #EggTreeMultiDragSource + * @path: row on which user is initiating a drag + * + * Asks the #EggTreeMultiDragSource whether a particular row can be used as + * the source of a DND operation. If the source doesn't implement + * this interface, the row is assumed draggable. + * + * Return value: %TRUE if the row can be dragged + **/ +gboolean +egg_tree_multi_drag_source_row_draggable (EggTreeMultiDragSource *drag_source, + GList *path_list) +{ + EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); + + g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); + g_return_val_if_fail (iface->row_draggable != NULL, FALSE); + g_return_val_if_fail (path_list != NULL, FALSE); + + if (iface->row_draggable) + return (* iface->row_draggable) (drag_source, path_list); + else + return TRUE; +} + + +/** + * egg_tree_multi_drag_source_drag_data_delete: + * @drag_source: a #EggTreeMultiDragSource + * @path: row that was being dragged + * + * Asks the #EggTreeMultiDragSource to delete the row at @path, because + * it was moved somewhere else via drag-and-drop. Returns %FALSE + * if the deletion fails because @path no longer exists, or for + * some model-specific reason. Should robustly handle a @path no + * longer found in the model! + * + * Return value: %TRUE if the row was successfully deleted + **/ +gboolean +egg_tree_multi_drag_source_drag_data_delete (EggTreeMultiDragSource *drag_source, + GList *path_list) +{ + EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); + + g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); + g_return_val_if_fail (iface->drag_data_delete != NULL, FALSE); + g_return_val_if_fail (path_list != NULL, FALSE); + + return (* iface->drag_data_delete) (drag_source, path_list); +} + +/** + * egg_tree_multi_drag_source_drag_data_get: + * @drag_source: a #EggTreeMultiDragSource + * @path: row that was dragged + * @selection_data: a #EggSelectionData to fill with data from the dragged row + * + * Asks the #EggTreeMultiDragSource to fill in @selection_data with a + * representation of the row at @path. @selection_data->target gives + * the required type of the data. Should robustly handle a @path no + * longer found in the model! + * + * Return value: %TRUE if data of the required type was provided + **/ +gboolean +egg_tree_multi_drag_source_drag_data_get (EggTreeMultiDragSource *drag_source, + GList *path_list, + GtkSelectionData *selection_data) +{ + EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE (drag_source); + + g_return_val_if_fail (EGG_IS_TREE_MULTI_DRAG_SOURCE (drag_source), FALSE); + g_return_val_if_fail (iface->drag_data_get != NULL, FALSE); + g_return_val_if_fail (path_list != NULL, FALSE); + g_return_val_if_fail (selection_data != NULL, FALSE); + + return (* iface->drag_data_get) (drag_source, path_list, selection_data); +} + +static void +stop_drag_check (GtkWidget *widget) +{ + EggTreeMultiDndData *priv_data; + GSList *l; + + priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); + + for (l = priv_data->event_list; l != NULL; l = l->next) + gdk_event_free (l->data); + + g_slist_free (priv_data->event_list); + priv_data->event_list = NULL; + g_signal_handler_disconnect (widget, priv_data->motion_notify_handler); + g_signal_handler_disconnect (widget, priv_data->button_release_handler); +} + +static gboolean +egg_tree_multi_drag_button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + EggTreeMultiDndData *priv_data; + GSList *l; + + priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); + + for (l = priv_data->event_list; l != NULL; l = l->next) + gtk_propagate_event (widget, l->data); + + stop_drag_check (widget); + + return FALSE; +} + +static void +selection_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GList **list_ptr; + + list_ptr = (GList **) data; + + *list_ptr = g_list_prepend (*list_ptr, gtk_tree_row_reference_new (model, path)); +} + +static void +path_list_free (GList *path_list) +{ + g_list_foreach (path_list, (GFunc) gtk_tree_row_reference_free, NULL); + g_list_free (path_list); +} + +static void +set_context_data (GdkDragContext *context, + GList *path_list) +{ + g_object_set_data_full (G_OBJECT (context), + "egg-tree-view-multi-source-row", + path_list, + (GDestroyNotify) path_list_free); +} + +static GList * +get_context_data (GdkDragContext *context) +{ + return g_object_get_data (G_OBJECT (context), + "egg-tree-view-multi-source-row"); +} + +/* CUT-N-PASTE from gtktreeview.c */ +static TreeViewDragInfo* +get_info (GtkTreeView *tree_view) +{ + return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info"); +} + + +static void +egg_tree_multi_drag_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + GtkTreeView *tree_view; + GtkTreeModel *model; + TreeViewDragInfo *di; + GList *path_list; + + tree_view = GTK_TREE_VIEW (widget); + + model = gtk_tree_view_get_model (tree_view); + + if (model == NULL) + return; + + di = get_info (GTK_TREE_VIEW (widget)); + + if (di == NULL) + return; + + path_list = get_context_data (context); + + if (path_list == NULL) + return; + + /* We can implement the GTK_TREE_MODEL_ROW target generically for + * any model; for DragSource models there are some other targets + * we also support. + */ + + if (EGG_IS_TREE_MULTI_DRAG_SOURCE (model)) + { + egg_tree_multi_drag_source_drag_data_get (EGG_TREE_MULTI_DRAG_SOURCE (model), + path_list, + selection_data); + } +} + +static gboolean +egg_tree_multi_drag_motion_event (GtkWidget *widget, + GdkEventMotion *event, + gpointer data) +{ + EggTreeMultiDndData *priv_data; + + priv_data = g_object_get_data (G_OBJECT (widget), EGG_TREE_MULTI_DND_STRING); + + if (gtk_drag_check_threshold (widget, + priv_data->x, + priv_data->y, + event->x, + event->y)) + { + GList *path_list = NULL; + GtkTreeSelection *selection; + GtkTreeModel *model; + GdkDragContext *context; + TreeViewDragInfo *di; + + di = get_info (GTK_TREE_VIEW (widget)); + + if (di == NULL) + return FALSE; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + stop_drag_check (widget); + gtk_tree_selection_selected_foreach (selection, selection_foreach, &path_list); + path_list = g_list_reverse (path_list); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); + if (egg_tree_multi_drag_source_row_draggable (EGG_TREE_MULTI_DRAG_SOURCE (model), path_list)) + { + + context = gtk_drag_begin (widget, + di->source_target_list, + di->source_actions, + priv_data->pressed_button, + (GdkEvent*)event); + set_context_data (context, path_list); + gtk_drag_set_icon_default (context); + + } + else + { + path_list_free (path_list); + } + } + + return TRUE; +} + +static gboolean +egg_tree_multi_drag_button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + GtkTreeView *tree_view; + GtkTreePath *path = NULL; + GtkTreeViewColumn *column = NULL; + gint cell_x, cell_y; + GtkTreeSelection *selection; + EggTreeMultiDndData *priv_data; + + tree_view = GTK_TREE_VIEW (widget); + priv_data = g_object_get_data (G_OBJECT (tree_view), EGG_TREE_MULTI_DND_STRING); + if (priv_data == NULL) + { + priv_data = g_new0 (EggTreeMultiDndData, 1); + g_object_set_data (G_OBJECT (tree_view), EGG_TREE_MULTI_DND_STRING, priv_data); + } + + if (g_slist_find (priv_data->event_list, event)) + return FALSE; + + if (priv_data->event_list) + { + /* save the event to be propagated in order */ + priv_data->event_list = g_slist_append (priv_data->event_list, gdk_event_copy ((GdkEvent*)event)); + return TRUE; + } + + if (event->type == GDK_2BUTTON_PRESS) + return FALSE; + + gtk_tree_view_get_path_at_pos (tree_view, + event->x, event->y, + &path, &column, + &cell_x, &cell_y); + + selection = gtk_tree_view_get_selection (tree_view); + + if (path && gtk_tree_selection_path_is_selected (selection, path)) + { + priv_data->pressed_button = event->button; + priv_data->x = event->x; + priv_data->y = event->y; + priv_data->event_list = g_slist_append (priv_data->event_list, gdk_event_copy ((GdkEvent*)event)); + priv_data->motion_notify_handler = + g_signal_connect (G_OBJECT (tree_view), "motion_notify_event", G_CALLBACK (egg_tree_multi_drag_motion_event), NULL); + priv_data->button_release_handler = + g_signal_connect (G_OBJECT (tree_view), "button_release_event", G_CALLBACK (egg_tree_multi_drag_button_release_event), NULL); + + if (priv_data->drag_data_get_handler == 0) + { + priv_data->drag_data_get_handler = + g_signal_connect (G_OBJECT (tree_view), "drag_data_get", G_CALLBACK (egg_tree_multi_drag_drag_data_get), NULL); + } + + gtk_tree_path_free (path); + + return TRUE; + } + + if (path) + { + gtk_tree_path_free (path); + } + + return FALSE; +} + +void +egg_tree_multi_drag_add_drag_support (GtkTreeView *tree_view) +{ + g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); + g_signal_connect (G_OBJECT (tree_view), "button_press_event", G_CALLBACK (egg_tree_multi_drag_button_press_event), NULL); +} + diff --git a/cut-n-paste/toolbar-editor/eggtreemultidnd.h b/cut-n-paste/toolbar-editor/eggtreemultidnd.h new file mode 100644 index 0000000..810d48e --- /dev/null +++ b/cut-n-paste/toolbar-editor/eggtreemultidnd.h @@ -0,0 +1,76 @@ +/* eggtreednd.h + * Copyright (C) 2001 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_TREE_MULTI_DND_H__ +#define __EGG_TREE_MULTI_DND_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define EGG_TYPE_TREE_MULTI_DRAG_SOURCE (egg_tree_multi_drag_source_get_type ()) +#define EGG_TREE_MULTI_DRAG_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE, EggTreeMultiDragSource)) +#define EGG_IS_TREE_MULTI_DRAG_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE)) +#define EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), EGG_TYPE_TREE_MULTI_DRAG_SOURCE, EggTreeMultiDragSourceIface)) + +typedef struct _EggTreeMultiDragSource EggTreeMultiDragSource; /* Dummy typedef */ +typedef struct _EggTreeMultiDragSourceIface EggTreeMultiDragSourceIface; + +struct _EggTreeMultiDragSourceIface +{ + GTypeInterface g_iface; + + /* VTable - not signals */ + gboolean (* row_draggable) (EggTreeMultiDragSource *drag_source, + GList *path_list); + + gboolean (* drag_data_get) (EggTreeMultiDragSource *drag_source, + GList *path_list, + GtkSelectionData *selection_data); + + gboolean (* drag_data_delete) (EggTreeMultiDragSource *drag_source, + GList *path_list); +}; + +GType egg_tree_multi_drag_source_get_type (void) G_GNUC_CONST; + +/* Returns whether the given row can be dragged */ +gboolean egg_tree_multi_drag_source_row_draggable (EggTreeMultiDragSource *drag_source, + GList *path_list); + +/* Deletes the given row, or returns FALSE if it can't */ +gboolean egg_tree_multi_drag_source_drag_data_delete (EggTreeMultiDragSource *drag_source, + GList *path_list); + + +/* Fills in selection_data with type selection_data->target based on the row + * denoted by path, returns TRUE if it does anything + */ +gboolean egg_tree_multi_drag_source_drag_data_get (EggTreeMultiDragSource *drag_source, + GList *path_list, + GtkSelectionData *selection_data); +void egg_tree_multi_drag_add_drag_support (GtkTreeView *tree_view); + + + +G_END_DECLS + +#endif /* __EGG_TREE_MULTI_DND_H__ */ -- cgit v0.9.1