/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */ /* Balsa E-Mail Client * Copyright (C) 1997-2002 Stuart Parmenter and others, * See the file AUTHORS for a list. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include "config.h" #include #include #include "libbalsa.h" #include "balsa-app.h" #include "balsa-icons.h" #include "balsa-index.h" #include "balsa-mblist.h" #include "balsa-message.h" #include "folder-conf.h" #include "mailbox-conf.h" #include "main-window.h" #include "message-window.h" #include "pref-manager.h" #include "print.h" #include "sendmsg-window.h" #include "store-address.h" #include "save-restore.h" #include "toolbar-prefs.h" #include "libinit_balsa/init_balsa.h" #ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #define OLD_BALSA_COMPATIBILITY_TRANSLATION /* Enumeration for GtkTreeModel columns. */ enum { TP_TEXT_COLUMN, TP_ICON_COLUMN, TP_ITEM_COLUMN, TP_N_COLUMNS }; static GtkWidget *customize_widget; /* Structure associated with each notebook page. */ typedef struct ToolbarPage_ ToolbarPage; struct ToolbarPage_ { BalsaToolbarModel *model; GtkWidget *available; GtkWidget *current; GtkWidget *toolbar; GtkWidget *add_button; GtkWidget *remove_button; GtkWidget *back_button; GtkWidget *forward_button; GtkWidget *standard_button; gboolean needs_refresh; }; /* Callbacks. */ static void tp_dialog_response_cb(GtkDialog * dialog, gint response, gpointer data); static void add_button_cb(GtkWidget *, ToolbarPage * page); static void remove_button_cb(GtkWidget *, ToolbarPage * page); static void back_button_cb(GtkWidget *, ToolbarPage * page); static void forward_button_cb(GtkWidget *, ToolbarPage * page); static void wrap_toggled_cb(GtkWidget * widget, GtkNotebook * notebook); static void available_selection_changed_cb(GtkTreeSelection * selection, ToolbarPage * page); static void current_selection_changed_cb(GtkTreeSelection * selection, ToolbarPage * page); static void available_row_activated_cb(GtkTreeView * treeview, GtkTreeIter * arg1, GtkTreePath * arg2, ToolbarPage * page); static void current_row_activated_cb(GtkTreeView * treeview, GtkTreeIter * arg1, GtkTreePath * arg2, ToolbarPage * page); /* Helpers. */ static GtkWidget *create_toolbar_page(BalsaToolbarModel * model); static GtkWidget *tp_list_new(void); static gboolean tp_list_iter_is_first(GtkWidget * list, GtkTreeIter * iter); static gboolean tp_list_iter_is_last(GtkWidget * list, GtkTreeIter * iter); static void tp_page_refresh_available(ToolbarPage * page); static void tp_page_refresh_current(ToolbarPage * page); static void tp_page_refresh_preview(ToolbarPage * page); static void tp_page_swap_rows(ToolbarPage * page, gboolean forward); static void tp_page_add_selected(ToolbarPage * page); static void tp_page_remove_selected(ToolbarPage * page); static void tp_store_set(GtkListStore * store, GtkTreeIter * iter, gint item); static void replace_nl_with_space(char* str); /* Public methods. */ /* create the toolbar-customization dialog */ void customize_dialog_cb(GtkWidget * widget, gpointer data) { GtkWidget *notebook; GtkWidget *child; GtkWidget *option_frame; GtkWidget *option_box; GtkWidget *wrap_button; GnomeApp *active_window = GNOME_APP(data); /* There can only be one */ if (customize_widget) { gdk_window_raise(customize_widget->window); return; } customize_widget = gtk_dialog_new_with_buttons(_("Customize Toolbars"), GTK_WINDOW(active_window), GTK_DIALOG_MODAL| GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, GTK_STOCK_HELP, GTK_RESPONSE_HELP, NULL); g_object_add_weak_pointer(G_OBJECT(customize_widget), (gpointer) & customize_widget); g_signal_connect(G_OBJECT(customize_widget), "response", G_CALLBACK(tp_dialog_response_cb), NULL); notebook = gtk_notebook_new(); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(customize_widget)->vbox), notebook); gtk_window_set_wmclass(GTK_WINDOW(customize_widget), "customize", "Balsa"); gtk_window_set_default_size(GTK_WINDOW(customize_widget), 600, 440); child = create_toolbar_page(balsa_window_get_toolbar_model()); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), child, gtk_label_new(_("Main window"))); child = create_toolbar_page(sendmsg_window_get_toolbar_model()); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), child, gtk_label_new(_("Compose window"))); child = create_toolbar_page(message_window_get_toolbar_model()); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), child, gtk_label_new(_("Message window"))); option_frame = gtk_frame_new(_("Toolbar options")); gtk_container_set_border_width(GTK_CONTAINER(option_frame), 6); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(customize_widget)->vbox), option_frame, FALSE, FALSE, 0); option_box = gtk_vbox_new(FALSE, 6); gtk_container_set_border_width(GTK_CONTAINER(option_box), 6); gtk_container_add(GTK_CONTAINER(option_frame), option_box); wrap_button = gtk_check_button_new_with_mnemonic(_("_Wrap button labels")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wrap_button), balsa_app.toolbar_wrap_button_text); g_signal_connect(G_OBJECT(wrap_button), "toggled", G_CALLBACK(wrap_toggled_cb), notebook); gtk_box_pack_start(GTK_BOX(option_box), wrap_button, FALSE, FALSE, 0); gtk_widget_show_all(customize_widget); } /* get_toolbar_button_index: id - button id returns -1 on failure. */ int get_toolbar_button_index(const char *id) { #ifdef OLD_BALSA_COMPATIBILITY_TRANSLATION static const struct { gchar *new; gchar *old; } button_converter[] = { { BALSA_PIXMAP_ATTACHMENT, GNOME_STOCK_ATTACH }, { BALSA_PIXMAP_NEW, GNOME_STOCK_MAIL_NEW }, { BALSA_PIXMAP_CONTINUE, GNOME_STOCK_MAIL }, { BALSA_PIXMAP_RECEIVE, GNOME_STOCK_MAIL_RCV }, { BALSA_PIXMAP_REPLY, GNOME_STOCK_MAIL_RPL }, { BALSA_PIXMAP_REPLY_ALL, "reply_to_all" }, { BALSA_PIXMAP_REPLY_GROUP, "reply_to_group" }, { BALSA_PIXMAP_FORWARD, GNOME_STOCK_MAIL_FWD }, { BALSA_PIXMAP_NEXT, GTK_STOCK_GO_FORWARD }, { BALSA_PIXMAP_PREVIOUS, GTK_STOCK_GO_BACK }, { BALSA_PIXMAP_PRINT, GTK_STOCK_PRINT }, { BALSA_PIXMAP_SAVE, GTK_STOCK_SAVE }, { BALSA_PIXMAP_SEND, GNOME_STOCK_MAIL_SND }, { BALSA_PIXMAP_TRASH, GNOME_STOCK_TRASH }, { BALSA_PIXMAP_TRASH_EMPTY, "empty_trash" }, { BALSA_PIXMAP_NEXT_UNREAD, "next_unread" }, { BALSA_PIXMAP_NEXT_FLAGGED, "next_flagged" }, { BALSA_PIXMAP_SHOW_HEADERS, "show_all_headers" }, { BALSA_PIXMAP_SHOW_PREVIEW, "show_preview" }, { BALSA_PIXMAP_MARKED_NEW, "flag_unread" }, { BALSA_PIXMAP_MARKED_ALL, "mark_all" }, { BALSA_PIXMAP_IDENTITY, "identity" }, { BALSA_PIXMAP_CLOSE_MBOX, GTK_STOCK_CLOSE }, { BALSA_PIXMAP_OTHER_CLOSE, "close_mbox" }, { NULL, NULL } }; #endif int i; g_return_val_if_fail(id, -1); for(i=0; iactive; j = gtk_notebook_get_current_page(notebook); for (i = 0; (child = gtk_notebook_get_nth_page(notebook, i)); i++) { page = g_object_get_data(G_OBJECT(child), BALSA_KEY_TOOLBAR_PAGE); balsa_toolbar_refresh(page->toolbar); } } /* Button callbacks: each makes the appropriate change to the * page->current GtkTreeView, then refreshes the page's * BalsaToolbarModel and GtkToolbar; add_button_cb and remove_button_cb * also refresh the page's available GtkTreeView. */ static void back_button_cb(GtkWidget * widget, ToolbarPage * page) { tp_page_swap_rows(page, FALSE); } static void forward_button_cb(GtkWidget * widget, ToolbarPage * page) { tp_page_swap_rows(page, TRUE); } static void add_button_cb(GtkWidget *widget, ToolbarPage * page) { tp_page_add_selected(page); } static void remove_button_cb(GtkWidget *widget, ToolbarPage * page) { tp_page_remove_selected(page); } static void standard_button_cb(GtkWidget *widget, ToolbarPage * page) { balsa_toolbar_model_clear(page->model); balsa_toolbar_refresh(page->toolbar); tp_page_refresh_available(page); tp_page_refresh_current(page); } /* Callback for the "row-activated" signal for the available list. */ static void available_row_activated_cb(GtkTreeView * treeview, GtkTreeIter * arg1, GtkTreePath * arg2, ToolbarPage * page) { tp_page_add_selected(page); } /* Callback for the selection "changed" signal for the available list. */ static void available_selection_changed_cb(GtkTreeSelection * selection, ToolbarPage * page) { gtk_widget_set_sensitive(page->add_button, gtk_tree_selection_get_selected(selection, NULL, NULL)); } /* Callback for the "row-activated" signal for the current list. */ static void current_row_activated_cb(GtkTreeView * treeview, GtkTreeIter * arg1, GtkTreePath * arg2, ToolbarPage * page) { tp_page_remove_selected(page); } /* Callback for the selection "changed" signal for the destination list. */ static void current_selection_changed_cb(GtkTreeSelection * selection, ToolbarPage * page) { GtkTreeModel *model; GtkTreeIter iter; gboolean remove = FALSE; gboolean back = FALSE; gboolean forward = FALSE; if (gtk_tree_selection_get_selected(selection, &model, &iter)) { remove = TRUE; back = !tp_list_iter_is_first(page->current, &iter); forward = !tp_list_iter_is_last(page->current, &iter); } gtk_widget_set_sensitive(page->remove_button, remove); gtk_widget_set_sensitive(page->back_button, back); gtk_widget_set_sensitive(page->forward_button, forward); } /* Callback for the "response" signal of the dialog. */ static void tp_dialog_response_cb(GtkDialog * dialog, gint response, gpointer data) { GError *err = NULL; switch (response) { case GTK_RESPONSE_DELETE_EVENT: case GTK_RESPONSE_CLOSE: update_all_toolbars(); gtk_widget_destroy(GTK_WIDGET(dialog)); break; case GTK_RESPONSE_HELP: gnome_help_display("balsa", "toolbar-prefs", &err); if (err) { balsa_information(LIBBALSA_INFORMATION_WARNING, _("Error displaying toolbar help: %s\n"), err->message); g_error_free(err); } break; default: break; } } /* Helpers. */ /* Create a page for the main notebook. */ static GtkWidget* create_toolbar_page(BalsaToolbarModel * model) { GtkWidget *outer_box; GtkWidget *toolbar_frame, *toolbar_scroll; GtkWidget *toolbar_ctlbox; GtkWidget *lower_ctlbox, *button_box, *move_button_box, *center_button_box; GtkWidget *list_frame, *list_scroll; GtkWidget *destination_frame, *destination_scroll; ToolbarPage *page; GtkTreeSelection *selection; page = g_new(ToolbarPage, 1); page->model = model; page->needs_refresh = FALSE; /* The "window itself" */ outer_box=gtk_vbox_new(FALSE, 0); g_object_set_data(G_OBJECT(outer_box), BALSA_KEY_TOOLBAR_PAGE, page); /* Preview display */ toolbar_frame=gtk_frame_new(_("Preview")); gtk_container_set_border_width(GTK_CONTAINER(toolbar_frame), 5); gtk_box_pack_start(GTK_BOX(outer_box), toolbar_frame, FALSE, FALSE, 0); toolbar_ctlbox=gtk_vbox_new(FALSE, 5); gtk_container_add(GTK_CONTAINER(toolbar_frame), toolbar_ctlbox); gtk_container_set_border_width(GTK_CONTAINER(toolbar_ctlbox), 5); /* The preview is an actual, fully functional toolbar */ page->toolbar = balsa_toolbar_new(model); g_object_add_weak_pointer(G_OBJECT(page->toolbar), (gpointer) & page->toolbar); gtk_toolbar_set_style(GTK_TOOLBAR(page->toolbar), GTK_TOOLBAR_BOTH); /* embedded in a scrolled_window */ toolbar_scroll=gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(toolbar_scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER); gtk_box_pack_start(GTK_BOX(toolbar_ctlbox), toolbar_scroll, TRUE, TRUE, 0); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(toolbar_scroll), page->toolbar); /* Standard button */ page->standard_button = gtk_button_new_with_mnemonic(_("_Restore toolbar to standard buttons")); gtk_box_pack_start(GTK_BOX(toolbar_ctlbox), page->standard_button, FALSE, FALSE, 0); /* Done with preview */ /* Box for lower half of window */ lower_ctlbox=gtk_hbox_new(FALSE, 5); gtk_container_set_border_width(GTK_CONTAINER(lower_ctlbox), 5); gtk_box_pack_start(GTK_BOX(outer_box), lower_ctlbox, TRUE, TRUE, 0); /* A list to show the available items */ list_scroll=gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(list_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); list_frame=gtk_frame_new(_("Available buttons")); page->available = tp_list_new(); gtk_box_pack_start(GTK_BOX(lower_ctlbox), list_frame, TRUE, TRUE, 0); gtk_container_add(GTK_CONTAINER(list_frame), list_scroll); gtk_container_add(GTK_CONTAINER(list_scroll), page->available); /* Done with available list */ /* Another list to show the current tools */ destination_scroll=gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(destination_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); destination_frame=gtk_frame_new(_("Current toolbar")); page->current = tp_list_new(); /* Done with destination list */ /* Button box */ center_button_box=gtk_vbox_new(TRUE, 0); button_box=gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(lower_ctlbox), center_button_box, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(center_button_box), button_box, FALSE, FALSE, 0); page->back_button = balsa_stock_button_with_label(GTK_STOCK_GO_UP, _("Up")); gtk_box_pack_start(GTK_BOX(button_box), page->back_button, FALSE, FALSE, 0); move_button_box=gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(button_box), move_button_box, FALSE, FALSE, 0); page->remove_button = balsa_stock_button_with_label(GTK_STOCK_GO_BACK, "-"); gtk_box_pack_start(GTK_BOX(move_button_box), page->remove_button, FALSE, FALSE, 0); page->add_button = balsa_stock_button_with_label(GTK_STOCK_GO_FORWARD, "+"); gtk_box_pack_start(GTK_BOX(move_button_box), page->add_button, FALSE, FALSE, 0); page->forward_button = balsa_stock_button_with_label(GTK_STOCK_GO_DOWN, _("Down")); gtk_box_pack_start(GTK_BOX(button_box), page->forward_button, FALSE, FALSE, 0); /* Pack destination list */ gtk_box_pack_start(GTK_BOX(lower_ctlbox), destination_frame, TRUE, TRUE, 0); gtk_container_add(GTK_CONTAINER(destination_frame), destination_scroll); gtk_container_add(GTK_CONTAINER(destination_scroll), page->current); /* UI signals */ g_signal_connect(G_OBJECT(page->available), "row-activated", G_CALLBACK(available_row_activated_cb), page); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(page->available)); g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(available_selection_changed_cb), page); g_signal_connect(G_OBJECT(page->current), "row-activated", G_CALLBACK(current_row_activated_cb), page); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(page->current)); g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(current_selection_changed_cb), page); g_signal_connect(G_OBJECT(page->add_button), "clicked", G_CALLBACK(add_button_cb), page); g_signal_connect(G_OBJECT(page->remove_button), "clicked", G_CALLBACK(remove_button_cb), page); g_signal_connect(G_OBJECT(page->forward_button), "clicked", G_CALLBACK(forward_button_cb), page); g_signal_connect(G_OBJECT(page->back_button), "clicked", G_CALLBACK(back_button_cb), page); g_signal_connect(G_OBJECT(page->standard_button), "clicked", G_CALLBACK(standard_button_cb), page); gtk_widget_set_sensitive(page->add_button, FALSE); gtk_widget_set_sensitive(page->remove_button, FALSE); gtk_widget_set_sensitive(page->back_button, FALSE); gtk_widget_set_sensitive(page->forward_button, FALSE); tp_page_refresh_available(page); tp_page_refresh_current(page); return outer_box; } /* Refresh the page's available GtkTreeView. */ static void tp_page_refresh_available(ToolbarPage * page) { GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(page->available)); GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path; GSList *legal = balsa_toolbar_model_get_legal(page->model); GSList *current = balsa_toolbar_model_get_current(page->model); int item; /* save currently selected path, or point path to the first row */ if (gtk_tree_selection_get_selected(selection, &model, &iter)) path = gtk_tree_model_get_path(model, &iter); else { path = gtk_tree_path_new(); gtk_tree_path_down(path); } gtk_list_store_clear(GTK_LIST_STORE(model)); for (item = 0; item < toolbar_button_count; item++) { if (item > 0 && (!g_slist_find_custom(legal, toolbar_buttons[item].pixmap_id, (GCompareFunc) strcmp) || g_slist_find_custom(current, toolbar_buttons[item].pixmap_id, (GCompareFunc) strcmp))) continue; gtk_list_store_append(GTK_LIST_STORE(model), &iter); tp_store_set(GTK_LIST_STORE(model), &iter, item); } if (gtk_tree_model_get_iter(model, &iter, path) || gtk_tree_path_prev(path)) { gtk_tree_selection_select_path(selection, path); gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(page->available), path, NULL, FALSE, 0, 0); } gtk_tree_path_free(path); } /* Refresh the page's current GtkTreeView. */ static void tp_page_refresh_current(ToolbarPage * page) { GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(page->current)); GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path; int item; GSList *list; /* save currently selected path, or point path to the first row */ if (gtk_tree_selection_get_selected(selection, &model, &iter)) path = gtk_tree_model_get_path(model, &iter); else { path = gtk_tree_path_new(); gtk_tree_path_down(path); } gtk_list_store_clear(GTK_LIST_STORE(model)); for (list = balsa_toolbar_model_get_current(page->model); list; list = g_slist_next(list)) { item = get_toolbar_button_index(list->data); if (item < 0) continue; gtk_list_store_append(GTK_LIST_STORE(model), &iter); tp_store_set(GTK_LIST_STORE(model), &iter, item); } if (gtk_tree_model_get_iter(model, &iter, path) || gtk_tree_path_prev(path)) { gtk_tree_selection_select_path(selection, path); gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(page->current), path, NULL, FALSE, 0, 0); } gtk_tree_path_free(path); } /* Refresh a page after its destination TreeView has changed. */ static void tp_page_refresh_preview(ToolbarPage * page) { GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(page->current)); GtkTreeIter iter; gboolean valid; balsa_toolbar_model_clear(page->model); for (valid = gtk_tree_model_get_iter_first(model, &iter); valid; valid = gtk_tree_model_iter_next(model, &iter)) { gint item; gtk_tree_model_get(model, &iter, TP_ITEM_COLUMN, &item, -1); if (item >= 0 && item < toolbar_button_count) balsa_toolbar_model_insert_icon(page->model, toolbar_buttons[item].pixmap_id, -1); } balsa_toolbar_refresh(page->toolbar); } /* Create a GtkTreeView for an icon list. */ static GtkWidget * tp_list_new(void) { GtkListStore *list_store; GtkTreeView *view; GtkCellRenderer *renderer; GtkTreeViewColumn *column; list_store = gtk_list_store_new(TP_N_COLUMNS, G_TYPE_STRING, /* TP_TEXT_COLUMN */ GDK_TYPE_PIXBUF, /* TP_ICON_COLUMN */ G_TYPE_INT /* TP_ITEM_COLUMN */ ); view = GTK_TREE_VIEW(gtk_tree_view_new_with_model (GTK_TREE_MODEL(list_store))); g_object_unref(list_store); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "text", TP_TEXT_COLUMN, NULL); gtk_tree_view_append_column(view, column); renderer = gtk_cell_renderer_pixbuf_new(); column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "pixbuf", TP_ICON_COLUMN, NULL); gtk_tree_view_append_column(view, column); gtk_tree_view_set_headers_visible(view, FALSE); return GTK_WIDGET(view); } /* Test whether the iter addresses the first row. */ static gboolean tp_list_iter_is_first(GtkWidget * list, GtkTreeIter * iter) { GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list)); GtkTreePath *path = gtk_tree_model_get_path(model, iter); gboolean ret_val = !gtk_tree_path_prev(path); gtk_tree_path_free(path); return ret_val; } /* Test whether the iter addresses the last row. */ static gboolean tp_list_iter_is_last(GtkWidget * list, GtkTreeIter * iter) { GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list)); GtkTreeIter tmp_iter = *iter; return !gtk_tree_model_iter_next(model, &tmp_iter); } /* Swap the currently selected row in page->current * with the next or previous row. */ static void tp_page_swap_rows(ToolbarPage * page, gboolean forward) { GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(page->current)); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(page->current)); GtkTreeIter iter; GtkTreeIter tmp_iter; GtkTreePath *tmp_path; gint item, tmp_item; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(page->current)); if (!gtk_tree_selection_get_selected(selection, &model, &iter)) return; if (forward) { tmp_iter = iter; if (!gtk_tree_model_iter_next(model, &tmp_iter)) return; tmp_path = gtk_tree_model_get_path(model, &tmp_iter); } else { tmp_path = gtk_tree_model_get_path(model, &iter); if (!gtk_tree_path_prev(tmp_path)) { gtk_tree_path_free(tmp_path); return; } gtk_tree_model_get_iter(model, &tmp_iter, tmp_path); } gtk_tree_model_get(model, &iter, TP_ITEM_COLUMN, &item, -1); gtk_tree_model_get(model, &tmp_iter, TP_ITEM_COLUMN, &tmp_item, -1); tp_store_set(GTK_LIST_STORE(model), &tmp_iter, item); tp_store_set(GTK_LIST_STORE(model), &iter, tmp_item); gtk_tree_selection_select_path(selection, tmp_path); gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(page->current), tmp_path, NULL, FALSE, 0, 0); gtk_tree_path_free(tmp_path); tp_page_refresh_preview(page); } /* Add an item to a GtkTreeView's GtkListStore. */ static void tp_store_set(GtkListStore * store, GtkTreeIter * iter, gint item) { GdkPixbuf *pixbuf; gchar *text; text = g_strdup(_(toolbar_buttons[item].button_text)); replace_nl_with_space(text); pixbuf = (item > 0 ? gtk_widget_render_icon(customize_widget, toolbar_buttons[item].pixmap_id, GTK_ICON_SIZE_LARGE_TOOLBAR, "Balsa") : NULL); gtk_list_store_set(store, iter, TP_TEXT_COLUMN, text, TP_ICON_COLUMN, pixbuf, TP_ITEM_COLUMN, item, -1); g_free(text); if (pixbuf) g_object_unref(pixbuf); } /* Add an item to the current list. */ static void tp_page_add_selected(ToolbarPage * page) { gint item = 0; GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; GtkTreeIter sibling; GtkTreePath *path; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(page->available)); if (!gtk_tree_selection_get_selected(selection, &model, &iter)) return; gtk_tree_model_get(model, &iter, TP_ITEM_COLUMN, &item, -1); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(page->current)); if (gtk_tree_selection_get_selected(selection, &model, &sibling)) gtk_list_store_insert_before(GTK_LIST_STORE(model), &iter, &sibling); else gtk_list_store_append(GTK_LIST_STORE(model), &iter); tp_store_set(GTK_LIST_STORE(model), &iter, item); path = gtk_tree_model_get_path(model, &iter); gtk_tree_selection_select_path(selection, path); gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(page->current), path, NULL, FALSE, 0, 0); gtk_tree_path_free(path); tp_page_refresh_preview(page); tp_page_refresh_available(page); } /* Remove an item from the page's current list. */ static void tp_page_remove_selected(ToolbarPage * page) { GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(page->current)); GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path; if (!gtk_tree_selection_get_selected(selection, &model, &iter)) return; path = gtk_tree_model_get_path(model, &iter); gtk_list_store_remove(GTK_LIST_STORE(model), &iter); if (gtk_tree_model_get_iter(model, &iter, path) || gtk_tree_path_prev(path)) { gtk_tree_selection_select_path(selection, path); gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(page->current), path, NULL, FALSE, 0, 0); } gtk_tree_path_free(path); tp_page_refresh_preview(page); tp_page_refresh_available(page); } /* Unwrap text. */ static void replace_nl_with_space(char* str) { while(*str) { if(*str == '\n') *str=' '; str++; } }