--- a/src/gtksavedstatuses.c Sat Aug 19 00:24:14 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1623 +0,0 @@ -/** - * @file gtksavedstatus.c GTK+ Saved Status Editor UI - * @ingroup gtkui - * - * gaim - * - * Gaim is the legal property of its developers, whose names are too numerous - * to list here. Please refer to the COPYRIGHT file distributed with this - * source distribution. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "account.h" -#include "internal.h" -#include "notify.h" -#include "request.h" -#include "savedstatuses.h" -#include "status.h" -#include "util.h" - -#include "gtkblist.h" -#include "gtkexpander.h" -#include "gtkgaim.h" -#include "gtkimhtml.h" -#include "gtkimhtmltoolbar.h" -#include "gtksavedstatuses.h" -#include "gtkstock.h" -#include "gtkutils.h" - -/* - * TODO: Should attach to the account-deleted and account-added signals - * and update the GtkListStores in any StatusEditor windows that - * may be open. - */ - -/** - * These are used for the GtkTreeView when you're scrolling through - * all your saved statuses. - */ -enum -{ - STATUS_WINDOW_COLUMN_TITLE, - STATUS_WINDOW_COLUMN_TYPE, - STATUS_WINDOW_COLUMN_MESSAGE, - /** A hidden column containing a pointer to the editor for this saved status. */ - STATUS_WINDOW_COLUMN_WINDOW, - STATUS_WINDOW_NUM_COLUMNS -}; - -/** - * These is used for the GtkTreeView containing the list of accounts - * at the bottom of the window when you're editing a particular - * saved status. - */ -enum -{ - /** A hidden column containing a pointer to the GaimAccount. */ - STATUS_EDITOR_COLUMN_ACCOUNT, - /** A hidden column containing a pointer to the editor for this substatus. */ - STATUS_EDITOR_COLUMN_WINDOW, - STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, - STATUS_EDITOR_COLUMN_ICON, - STATUS_EDITOR_COLUMN_SCREENNAME, - /** A hidden column containing the ID of this GaimStatusType. */ - STATUS_EDITOR_COLUMN_STATUS_ID, - STATUS_EDITOR_COLUMN_STATUS_NAME, - STATUS_EDITOR_COLUMN_STATUS_MESSAGE, - STATUS_EDITOR_NUM_COLUMNS -}; - -/** - * These are used in the GtkComboBox to select the specific - * GaimStatusType when setting a substatus for a particular saved - * status. - */ -enum -{ - SUBSTATUS_COLUMN_ICON, - /** A hidden column containing the ID of this GaimStatusType. */ - SUBSTATUS_COLUMN_STATUS_ID, - SUBSTATUS_COLUMN_STATUS_NAME, - SUBSTATUS_NUM_COLUMNS -}; - -typedef struct -{ - GtkWidget *window; - GtkListStore *model; - GtkWidget *treeview; - GtkWidget *use_button; - GtkWidget *modify_button; - GtkWidget *delete_button; -} StatusWindow; - -typedef struct -{ - GtkWidget *window; - GtkListStore *model; - GtkWidget *treeview; - GtkButton *saveanduse_button; - GtkButton *save_button; - - gchar *original_title; - GtkEntry *title; - GtkOptionMenu *type; - GtkIMHtml *message; -} StatusEditor; - -typedef struct -{ - StatusEditor *status_editor; - GaimAccount *account; - - GtkWidget *window; - GtkListStore *model; - GtkComboBox *box; - GtkIMHtml *message; - GtkIMHtmlToolbar *toolbar; -} SubStatusEditor; - -static StatusWindow *status_window = NULL; - - -/************************************************************************** -* Status window -**************************************************************************/ - -static gboolean -status_window_find_savedstatus(GtkTreeIter *iter, const char *title) -{ - GtkTreeModel *model; - char *cur; - - if ((status_window == NULL) || (title == NULL)) - return FALSE; - - model = GTK_TREE_MODEL(status_window->model); - - if (!gtk_tree_model_get_iter_first(model, iter)) - return FALSE; - - do { - gtk_tree_model_get(model, iter, STATUS_WINDOW_COLUMN_TITLE, &cur, -1); - if (!strcmp(title, cur)) - { - g_free(cur); - return TRUE; - } - g_free(cur); - } while (gtk_tree_model_iter_next(model, iter)); - - return FALSE; -} - -static gboolean -status_window_destroy_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) -{ - StatusWindow *dialog = user_data; - - dialog->window = NULL; - gaim_gtk_status_window_hide(); - - return FALSE; -} - -#if !GTK_CHECK_VERSION(2,2,0) -static void -count_selected_helper(GtkTreeModel *model, GtkTreePath *path, - GtkTreeIter *iter, gpointer user_data) -{ - (*(gint *)user_data)++; -} - -static void -list_selected_helper(GtkTreeModel *model, GtkTreePath *path, - GtkTreeIter *iter, gpointer user_data) -{ - GList **list = (GList **)user_data; - *list = g_list_append(*list, gtk_tree_path_copy(path)); -} -#endif - -static void -status_window_use_cb(GtkButton *button, StatusWindow *dialog) -{ - GtkTreeSelection *selection; - GtkTreeIter iter; - GList *list = NULL; - int num_selected = 0; - - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); - -#if GTK_CHECK_VERSION(2,2,0) - num_selected = gtk_tree_selection_count_selected_rows(selection); -#else - gtk_tree_selection_selected_foreach(selection, count_selected_helper, &num_selected); -#endif - if (num_selected != 1) - /* - * This shouldn't happen because the "Use" button should have - * been grayed out. Oh well. - */ - return; - -#if GTK_CHECK_VERSION(2,2,0) - list = gtk_tree_selection_get_selected_rows(selection, NULL); -#else - gtk_tree_selection_selected_foreach(selection, list_selected_helper, &list); -#endif - - if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), - &iter, list->data)) - { - gchar *title; - GaimSavedStatus *saved_status; - gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, - STATUS_WINDOW_COLUMN_TITLE, &title, - -1); - saved_status = gaim_savedstatus_find(title); - g_free(title); - gaim_savedstatus_activate(saved_status); - } - - g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL); - g_list_free(list); -} - -static void -status_window_add_cb(GtkButton *button, gpointer user_data) -{ - gaim_gtk_status_editor_show(FALSE, NULL); -} - -static void -status_window_modify_foreach(GtkTreeModel *model, GtkTreePath *path, - GtkTreeIter *iter, gpointer user_data) -{ - gchar *title; - GaimSavedStatus *saved_status; - - gtk_tree_model_get(model, iter, STATUS_WINDOW_COLUMN_TITLE, &title, -1); - saved_status = gaim_savedstatus_find(title); - g_free(title); - gaim_gtk_status_editor_show(TRUE, saved_status); -} - -static void -status_window_modify_cb(GtkButton *button, gpointer user_data) -{ - StatusWindow *dialog = user_data; - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); - - gtk_tree_selection_selected_foreach(selection, status_window_modify_foreach, user_data); -} - -static void -status_window_delete_confirm_cb(char *title) -{ - GtkTreeIter iter; - - if (status_window_find_savedstatus(&iter, title)) - gtk_list_store_remove(status_window->model, &iter); - - gaim_savedstatus_delete(title); - - g_free(title); -} - -static void -status_window_delete_foreach(GtkTreeModel *model, GtkTreePath *path, - GtkTreeIter *iter, gpointer user_data) -{ - char *title; - char *buf; - - gtk_tree_model_get(model, iter, STATUS_WINDOW_COLUMN_TITLE, &title, -1); - - buf = g_strdup_printf(_("Are you sure you want to delete %s?"), title); - gaim_request_action(status_window, NULL, buf, NULL, 0, title, 2, - _("Delete"), status_window_delete_confirm_cb, - _("Cancel"), g_free); - g_free(buf); -} - -static void -status_window_delete_cb(GtkButton *button, gpointer user_data) -{ - StatusWindow *dialog = user_data; - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); - - gtk_tree_selection_selected_foreach(selection, status_window_delete_foreach, user_data); -} - -static void -status_window_close_cb(GtkButton *button, gpointer user_data) -{ - gaim_gtk_status_window_hide(); -} - -static void -status_selected_cb(GtkTreeSelection *sel, gpointer user_data) -{ - StatusWindow *dialog = user_data; - int num_selected = 0; - -#if GTK_CHECK_VERSION(2,2,0) - num_selected = gtk_tree_selection_count_selected_rows(sel); -#else - gtk_tree_selection_selected_foreach(sel, count_selected_helper, &num_selected); -#endif - - gtk_widget_set_sensitive(dialog->use_button, (num_selected == 1)); - gtk_widget_set_sensitive(dialog->modify_button, (num_selected > 0)); - gtk_widget_set_sensitive(dialog->delete_button, (num_selected > 0)); -} - -static void -add_status_to_saved_status_list(GtkListStore *model, GaimSavedStatus *saved_status) -{ - GtkTreeIter iter; - const char *title; - const char *type; - char *message; - - if (gaim_savedstatus_is_transient(saved_status)) - return; - - title = gaim_savedstatus_get_title(saved_status); - type = gaim_primitive_get_name_from_type(gaim_savedstatus_get_type(saved_status)); - message = gaim_markup_strip_html(gaim_savedstatus_get_message(saved_status)); - - gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, - STATUS_WINDOW_COLUMN_TITLE, title, - STATUS_WINDOW_COLUMN_TYPE, type, - STATUS_WINDOW_COLUMN_MESSAGE, message, - -1); - free(message); -} - -static void -populate_saved_status_list(StatusWindow *dialog) -{ - const GList *saved_statuses; - - gtk_list_store_clear(dialog->model); - - for (saved_statuses = gaim_savedstatuses_get_all(); saved_statuses != NULL; - saved_statuses = g_list_next(saved_statuses)) - { - add_status_to_saved_status_list(dialog->model, saved_statuses->data); - } -} - -static gboolean -search_func(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer search_data) -{ - gboolean result; - char *haystack; - - gtk_tree_model_get(model, iter, column, &haystack, -1); - - result = (gaim_strcasestr(haystack, key) == NULL); - - g_free(haystack); - - return result; -} - -static void -savedstatus_activated_cb(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *column, StatusWindow *dialog) -{ - status_window_modify_cb(NULL, dialog); -} - -static GtkWidget * -create_saved_status_list(StatusWindow *dialog) -{ - GtkWidget *sw; - GtkWidget *treeview; - GtkTreeSelection *sel; - GtkTreeViewColumn *column; - GtkCellRenderer *renderer; - - /* Create the scrolled window */ - sw = gtk_scrolled_window_new(0, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - - /* Create the list model */ - dialog->model = gtk_list_store_new(STATUS_WINDOW_NUM_COLUMNS, - G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_POINTER); - - /* Create the treeview */ - treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model)); - dialog->treeview = treeview; - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); - g_signal_connect(G_OBJECT(treeview), "row-activated", - G_CALLBACK(savedstatus_activated_cb), dialog); - - sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE); - g_signal_connect(G_OBJECT(sel), "changed", - G_CALLBACK(status_selected_cb), dialog); - - gtk_container_add(GTK_CONTAINER(sw), treeview); - - /* Add columns */ - column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_title(column, _("Title")); - gtk_tree_view_column_set_resizable(column, TRUE); - gtk_tree_view_column_set_min_width(column, 100); - gtk_tree_view_column_set_sort_column_id(column, - STATUS_WINDOW_COLUMN_TITLE); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, renderer, TRUE); - gtk_tree_view_column_add_attribute(column, renderer, "text", - STATUS_WINDOW_COLUMN_TITLE); -#if GTK_CHECK_VERSION(2,6,0) - g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); -#endif - - column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_title(column, _("Type")); - gtk_tree_view_column_set_resizable(column, TRUE); - gtk_tree_view_column_set_sort_column_id(column, - STATUS_WINDOW_COLUMN_TYPE); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, renderer, TRUE); - gtk_tree_view_column_add_attribute(column, renderer, "text", - STATUS_WINDOW_COLUMN_TYPE); - - column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_title(column, _("Message")); - gtk_tree_view_column_set_resizable(column, TRUE); - gtk_tree_view_column_set_sort_column_id(column, - STATUS_WINDOW_COLUMN_MESSAGE); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, renderer, TRUE); - gtk_tree_view_column_add_attribute(column, renderer, "text", - STATUS_WINDOW_COLUMN_MESSAGE); -#if GTK_CHECK_VERSION(2,6,0) - g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); -#endif - - /* Enable CTRL+F searching */ - gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), STATUS_WINDOW_COLUMN_TITLE); - gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(treeview), search_func, NULL, NULL); - - /* Sort the title column by default */ - gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dialog->model), - STATUS_WINDOW_COLUMN_TITLE, - GTK_SORT_ASCENDING); - - /* Populate list */ - populate_saved_status_list(dialog); - - gtk_widget_show_all(sw); - - return sw; -} - -static gboolean -configure_cb(GtkWidget *widget, GdkEventConfigure *event, StatusWindow *dialog) -{ - if (GTK_WIDGET_VISIBLE(widget)) - { - gaim_prefs_set_int("/gaim/gtk/status/dialog/width", event->width); - gaim_prefs_set_int("/gaim/gtk/status/dialog/height", event->height); - } - - return FALSE; -} - -void -gaim_gtk_status_window_show(void) -{ - StatusWindow *dialog; - GtkWidget *bbox; - GtkWidget *button; - GtkWidget *list; - GtkWidget *vbox; - GtkWidget *win; - int width, height; - - if (status_window != NULL) - { - gtk_window_present(GTK_WINDOW(status_window->window)); - return; - } - - status_window = dialog = g_new0(StatusWindow, 1); - - width = gaim_prefs_get_int("/gaim/gtk/status/dialog/width"); - height = gaim_prefs_get_int("/gaim/gtk/status/dialog/height"); - - dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_default_size(GTK_WINDOW(win), width, height); - gtk_window_set_role(GTK_WINDOW(win), "statuses"); - gtk_window_set_title(GTK_WINDOW(win), _("Saved Statuses")); - gtk_container_set_border_width(GTK_CONTAINER(win), GAIM_HIG_BORDER); - - g_signal_connect(G_OBJECT(win), "delete_event", - G_CALLBACK(status_window_destroy_cb), dialog); - g_signal_connect(G_OBJECT(win), "configure_event", - G_CALLBACK(configure_cb), dialog); - - /* Setup the vbox */ - vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); - gtk_container_add(GTK_CONTAINER(win), vbox); - - /* List of saved status states */ - list = create_saved_status_list(dialog); - gtk_box_pack_start(GTK_BOX(vbox), list, TRUE, TRUE, 0); - - /* Button box. */ - bbox = gtk_hbutton_box_new(); - gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE); - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); - gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); - - /* Use button */ - button = gaim_pixbuf_button_from_stock(_("_Use"), GTK_STOCK_EXECUTE, - GAIM_BUTTON_HORIZONTAL); - dialog->use_button = button; - gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); - gtk_widget_set_sensitive(button, FALSE); - - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(status_window_use_cb), dialog); - - /* Add button */ - button = gtk_button_new_from_stock(GTK_STOCK_ADD); - gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(status_window_add_cb), dialog); - - /* Modify button */ - button = gtk_button_new_from_stock(GAIM_STOCK_MODIFY); - dialog->modify_button = button; - gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); - gtk_widget_set_sensitive(button, FALSE); - - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(status_window_modify_cb), dialog); - - /* Delete button */ - button = gtk_button_new_from_stock(GTK_STOCK_DELETE); - dialog->delete_button = button; - gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); - gtk_widget_set_sensitive(button, FALSE); - - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(status_window_delete_cb), dialog); - - /* Close button */ - button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); - gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(status_window_close_cb), dialog); - - gtk_widget_show_all(win); -} - -void -gaim_gtk_status_window_hide(void) -{ - if (status_window == NULL) - return; - - if (status_window->window != NULL) - gtk_widget_destroy(status_window->window); - - gaim_request_close_with_handle(status_window); - gaim_notify_close_with_handle(status_window); - g_free(status_window); - status_window = NULL; -} - - -/************************************************************************** -* Status editor -**************************************************************************/ - -static void substatus_editor_cancel_cb(GtkButton *button, gpointer user_data); - -static void -status_editor_remove_dialog(StatusEditor *dialog) -{ - GtkTreeModel *model; - GtkTreeIter iter; - - /* Remove the reference to this dialog from our parent's list store */ - if (status_window_find_savedstatus(&iter, dialog->original_title)) - { - gtk_list_store_set(status_window->model, &iter, - STATUS_WINDOW_COLUMN_WINDOW, NULL, - -1); - } - - /* Close any substatus editors that may be open */ - model = GTK_TREE_MODEL(dialog->model); - if (gtk_tree_model_get_iter_first(model, &iter)) - { - do { - SubStatusEditor *substatus_dialog; - - gtk_tree_model_get(model, &iter, - STATUS_EDITOR_COLUMN_WINDOW, &substatus_dialog, - -1); - if (substatus_dialog != NULL) - { - gtk_list_store_set(dialog->model, &iter, - STATUS_EDITOR_COLUMN_WINDOW, NULL, - -1); - substatus_editor_cancel_cb(NULL, substatus_dialog); - } - } while (gtk_tree_model_iter_next(model, &iter)); - } -} - - -static gboolean -status_editor_destroy_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) -{ - StatusEditor *dialog = user_data; - - status_editor_remove_dialog(dialog); - g_free(dialog->original_title); - g_free(dialog); - - return FALSE; -} - -static void -status_editor_cancel_cb(GtkButton *button, gpointer user_data) -{ - StatusEditor *dialog = user_data; - - status_editor_remove_dialog(dialog); - gtk_widget_destroy(dialog->window); - g_free(dialog->original_title); - g_free(dialog); -} - -static void -status_editor_ok_cb(GtkButton *button, gpointer user_data) -{ - StatusEditor *dialog = user_data; - const char *title; - GaimStatusPrimitive type; - char *message, *unformatted; - GaimSavedStatus *saved_status = NULL; - GtkTreeModel *model; - GtkTreeIter iter; - - title = gtk_entry_get_text(dialog->title); - - /* - * If we're saving this status, and the title is already taken - * then show an error dialog and don't do anything. - */ - if (((button == dialog->saveanduse_button) || (button == dialog->save_button)) && - (gaim_savedstatus_find(title) != NULL) && - ((dialog->original_title == NULL) || (strcmp(title, dialog->original_title)))) - { - gaim_notify_error(status_window, NULL, _("Title already in use. You must " - "choose a unique title."), NULL); - return; - } - - type = gtk_option_menu_get_history(dialog->type) + (GAIM_STATUS_UNSET + 1); - message = gtk_imhtml_get_markup(dialog->message); - unformatted = gaim_markup_strip_html(message); - - /* - * If we're editing an old status, then lookup the old status. - * Note: It is possible that it has been deleted or renamed - * or something, and no longer exists. - */ - if (dialog->original_title != NULL) - { - GtkTreeIter iter; - - saved_status = gaim_savedstatus_find(dialog->original_title); - - if (status_window_find_savedstatus(&iter, dialog->original_title)) - gtk_list_store_remove(status_window->model, &iter); - } - - if (saved_status == NULL) - { - /* This is a new status */ - if ((button == dialog->saveanduse_button) - || (button == dialog->save_button)) - saved_status = gaim_savedstatus_new(title, type); - else - saved_status = gaim_savedstatus_new(NULL, type); - } - else - { - /* Modify the old status */ - if (strcmp(title, dialog->original_title)) - gaim_savedstatus_set_title(saved_status, title); - gaim_savedstatus_set_type(saved_status, type); - } - - if (*unformatted == '\0') - gaim_savedstatus_set_message(saved_status, NULL); - else - gaim_savedstatus_set_message(saved_status, message); - - /* Set any substatuses */ - model = GTK_TREE_MODEL(dialog->model); - if (gtk_tree_model_get_iter_first(model, &iter)) - { - do { - GaimAccount *account; - gboolean enabled; - char *id; - char *message; - GaimStatusType *type; - - gtk_tree_model_get(model, &iter, - STATUS_EDITOR_COLUMN_ACCOUNT, &account, - STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, &enabled, - STATUS_EDITOR_COLUMN_STATUS_ID, &id, - STATUS_EDITOR_COLUMN_STATUS_MESSAGE, &message, - -1); - if (enabled) - { - type = gaim_account_get_status_type(account, id); - gaim_savedstatus_set_substatus(saved_status, account, type, message); - } - else - { - gaim_savedstatus_unset_substatus(saved_status, account); - } - g_free(id); - g_free(message); - } while (gtk_tree_model_iter_next(model, &iter)); - } - - g_free(message); - g_free(unformatted); - - status_editor_remove_dialog(dialog); - gtk_widget_destroy(dialog->window); - g_free(dialog->original_title); - - if (status_window != NULL) - add_status_to_saved_status_list(status_window->model, saved_status); - - /* If they clicked on "Save & Use" or "Use," then activate the status */ - if (button != dialog->save_button) - gaim_savedstatus_activate(saved_status); - - g_free(dialog); -} - -static void -editor_title_changed_cb(GtkWidget *widget, gpointer user_data) -{ - StatusEditor *dialog = user_data; - const gchar *text; - - text = gtk_entry_get_text(dialog->title); - - gtk_widget_set_sensitive(GTK_WIDGET(dialog->saveanduse_button), (*text != '\0')); - gtk_widget_set_sensitive(GTK_WIDGET(dialog->save_button), (*text != '\0')); -} - -static GtkWidget * -create_status_type_menu(GaimStatusPrimitive type) -{ - int i; - GtkWidget *dropdown; - GtkWidget *menu; - GtkWidget *item; - - dropdown = gtk_option_menu_new(); - menu = gtk_menu_new(); - - for (i = GAIM_STATUS_UNSET + 1; i < GAIM_STATUS_NUM_PRIMITIVES; i++) - { - item = gtk_menu_item_new_with_label(gaim_primitive_get_name_from_type(i)); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - } - - gtk_menu_set_active(GTK_MENU(menu), type - (GAIM_STATUS_UNSET + 1)); - gtk_option_menu_set_menu(GTK_OPTION_MENU(dropdown), menu); - gtk_widget_show_all(menu); - - return dropdown; -} - -static void edit_substatus(StatusEditor *status_editor, GaimAccount *account); - -static void -edit_substatus_cb(GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col, gpointer user_data) -{ - StatusEditor *dialog = user_data; - GtkTreeIter iter; - GaimAccount *account; - - gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path); - gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, - STATUS_EDITOR_COLUMN_ACCOUNT, &account, - -1); - - edit_substatus(dialog, account); -} - -static void -status_editor_substatus_cb(GtkCellRendererToggle *renderer, gchar *path_str, gpointer data) -{ - StatusEditor *dialog = (StatusEditor *)data; - GtkTreeIter iter; - gboolean enabled; - GaimAccount *account; - - gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(dialog->model), &iter, path_str); - gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, - STATUS_EDITOR_COLUMN_ACCOUNT, &account, - STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, &enabled, - -1); - - enabled = !enabled; - - if (enabled) - { - edit_substatus(dialog, account); - } - else - { - /* Remove the substatus */ - gtk_list_store_set(dialog->model, &iter, - STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, enabled, - STATUS_EDITOR_COLUMN_STATUS_ID, NULL, - STATUS_EDITOR_COLUMN_STATUS_NAME, NULL, - STATUS_EDITOR_COLUMN_STATUS_MESSAGE, NULL, - -1); - } -} - -static void -status_editor_add_columns(StatusEditor *dialog) -{ - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - - /* Enable Different status column */ - renderer = gtk_cell_renderer_toggle_new(); - gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(dialog->treeview), - -1, _("Different"), - renderer, - "active", STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, - NULL); - g_signal_connect(G_OBJECT(renderer), "toggled", - G_CALLBACK(status_editor_substatus_cb), dialog); - - /* Screen Name column */ - column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_resizable(column, TRUE); - gtk_tree_view_column_set_title(column, _("Screen Name")); - gtk_tree_view_insert_column(GTK_TREE_VIEW(dialog->treeview), column, -1); - gtk_tree_view_column_set_resizable(column, TRUE); - - /* Icon */ - renderer = gtk_cell_renderer_pixbuf_new(); - gtk_tree_view_column_pack_start(column, renderer, FALSE); - gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", - STATUS_EDITOR_COLUMN_ICON); - - /* Screen Name */ - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, renderer, TRUE); - gtk_tree_view_column_add_attribute(column, renderer, "text", - STATUS_EDITOR_COLUMN_SCREENNAME); - - /* Status column */ - column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_resizable(column, TRUE); - gtk_tree_view_column_set_title(column, _("Status")); - gtk_tree_view_insert_column(GTK_TREE_VIEW(dialog->treeview), column, -1); - gtk_tree_view_column_set_resizable(column, TRUE); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, renderer, TRUE); - gtk_tree_view_column_add_attribute(column, renderer, "text", - STATUS_EDITOR_COLUMN_STATUS_NAME); - - /* Message column */ - column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_resizable(column, TRUE); - gtk_tree_view_column_set_title(column, _("Message")); - gtk_tree_view_insert_column(GTK_TREE_VIEW(dialog->treeview), column, -1); - gtk_tree_view_column_set_resizable(column, TRUE); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, renderer, TRUE); - gtk_tree_view_column_add_attribute(column, renderer, "text", - STATUS_EDITOR_COLUMN_STATUS_MESSAGE); - - g_signal_connect(G_OBJECT(dialog->treeview), "row-activated", - G_CALLBACK(edit_substatus_cb), dialog); -} - -static void -status_editor_set_account(GtkListStore *store, GaimAccount *account, - GtkTreeIter *iter, GaimSavedStatusSub *substatus) -{ - GdkPixbuf *pixbuf; - const char *id = NULL, *name = NULL, *message = NULL; - - pixbuf = gaim_gtk_create_prpl_icon(account, 0.5); - if ((pixbuf != NULL) && !gaim_account_is_connected(account)) - { - gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.0, FALSE); - } - - if (substatus != NULL) - { - const GaimStatusType *type; - - type = gaim_savedstatus_substatus_get_type(substatus); - id = gaim_status_type_get_id(type); - name = gaim_status_type_get_name(type); - if (gaim_status_type_get_attr(type, "message")) - message = gaim_savedstatus_substatus_get_message(substatus); - } - - gtk_list_store_set(store, iter, - STATUS_EDITOR_COLUMN_ACCOUNT, account, - STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, (substatus != NULL), - STATUS_EDITOR_COLUMN_ICON, pixbuf, - STATUS_EDITOR_COLUMN_SCREENNAME, gaim_account_get_username(account), - STATUS_EDITOR_COLUMN_STATUS_ID, id, - STATUS_EDITOR_COLUMN_STATUS_NAME, name, - STATUS_EDITOR_COLUMN_STATUS_MESSAGE, message, - -1); - - if (pixbuf != NULL) - g_object_unref(G_OBJECT(pixbuf)); -} - -static void -status_editor_add_account(StatusEditor *dialog, GaimAccount *account, - GaimSavedStatusSub *substatus) -{ - GtkTreeIter iter; - - gtk_list_store_append(dialog->model, &iter); - - status_editor_set_account(dialog->model, account, &iter, substatus); -} - -static void -status_editor_populate_list(StatusEditor *dialog, GaimSavedStatus *saved_status) -{ - GList *iter; - GaimSavedStatusSub *substatus; - - gtk_list_store_clear(dialog->model); - - for (iter = gaim_accounts_get_all(); iter != NULL; iter = iter->next) - { - GaimAccount *account = (GaimAccount *)iter->data; - - if (saved_status != NULL) - substatus = gaim_savedstatus_get_substatus(saved_status, account); - else - substatus = NULL; - - status_editor_add_account(dialog, account, substatus); - } -} - -void -gaim_gtk_status_editor_show(gboolean edit, GaimSavedStatus *saved_status) -{ - GtkTreeIter iter; - StatusEditor *dialog; - GtkSizeGroup *sg; - GtkWidget *bbox; - GtkWidget *button; - GtkWidget *dbox; - GtkWidget *expander; - GtkWidget *dropdown; - GtkWidget *entry; - GtkWidget *frame; - GtkWidget *hbox; - GtkWidget *label; - GtkWidget *sw; - GtkWidget *text; - GtkWidget *toolbar; - GtkWidget *vbox; - GtkWidget *win; - GList *focus_chain = NULL; - - if (edit) - { - g_return_if_fail(saved_status != NULL); - g_return_if_fail(!gaim_savedstatus_is_transient(saved_status)); - } - - /* Find a possible window for this saved status and present it */ - if (edit && status_window_find_savedstatus(&iter, gaim_savedstatus_get_title(saved_status))) - { - gtk_tree_model_get(GTK_TREE_MODEL(status_window->model), &iter, - STATUS_WINDOW_COLUMN_WINDOW, &dialog, - -1); - if (dialog != NULL) - { - gtk_window_present(GTK_WINDOW(dialog->window)); - return; - } - } - - dialog = g_new0(StatusEditor, 1); - if (edit && status_window_find_savedstatus(&iter, gaim_savedstatus_get_title(saved_status))) - { - gtk_list_store_set(status_window->model, &iter, - STATUS_WINDOW_COLUMN_WINDOW, dialog, - -1); - } - - if (edit) - dialog->original_title = g_strdup(gaim_savedstatus_get_title(saved_status)); - - dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_role(GTK_WINDOW(win), "status"); - gtk_window_set_title(GTK_WINDOW(win), _("Status")); - gtk_window_set_resizable(GTK_WINDOW(win), FALSE); - gtk_container_set_border_width(GTK_CONTAINER(win), GAIM_HIG_BORDER); - - g_signal_connect(G_OBJECT(win), "delete_event", - G_CALLBACK(status_editor_destroy_cb), dialog); - - /* Setup the vbox */ - vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); - gtk_container_add(GTK_CONTAINER(win), vbox); - - sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - - /* Title */ - hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic(_("_Title:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_size_group_add_widget(sg, label); - - entry = gtk_entry_new(); - dialog->title = GTK_ENTRY(entry); - if ((saved_status != NULL) - && !gaim_savedstatus_is_transient(saved_status) - && (gaim_savedstatus_get_title(saved_status) != NULL)) - gtk_entry_set_text(GTK_ENTRY(entry), gaim_savedstatus_get_title(saved_status)); - gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); - g_signal_connect(G_OBJECT(entry), "changed", - G_CALLBACK(editor_title_changed_cb), dialog); - - /* Status type */ - hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic(_("_Status:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_size_group_add_widget(sg, label); - - if (saved_status != NULL) - dropdown = create_status_type_menu(gaim_savedstatus_get_type(saved_status)); - else - dropdown = create_status_type_menu(GAIM_STATUS_AWAY); - dialog->type = GTK_OPTION_MENU(dropdown); - gtk_box_pack_start(GTK_BOX(hbox), dropdown, TRUE, TRUE, 0); - - /* Status message */ - hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic(_("_Message:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_size_group_add_widget(sg, label); - - frame = gaim_gtk_create_imhtml(TRUE, &text, &toolbar, NULL); - dialog->message = GTK_IMHTML(text); - gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0); - focus_chain = g_list_prepend(focus_chain, dialog->message); - gtk_container_set_focus_chain(GTK_CONTAINER(hbox), focus_chain); - - if ((saved_status != NULL) && (gaim_savedstatus_get_message(saved_status) != NULL)) - gtk_imhtml_append_text(GTK_IMHTML(text), - gaim_savedstatus_get_message(saved_status), 0); - - /* Different status message expander */ - expander = gtk_expander_new_with_mnemonic(_("Use a _different status for some accounts")); - gtk_box_pack_start(GTK_BOX(vbox), expander, FALSE, FALSE, 0); - - /* Setup the box that the expander will cover */ - dbox = gtk_vbox_new(FALSE, GAIM_HIG_CAT_SPACE); - gtk_container_add(GTK_CONTAINER(expander), dbox); - - /* Different status message treeview */ - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), - GTK_SHADOW_IN); - gtk_box_pack_start(GTK_BOX(dbox), sw, TRUE, TRUE, 0); - - /* Create the list model */ - dialog->model = gtk_list_store_new(STATUS_EDITOR_NUM_COLUMNS, - G_TYPE_POINTER, - G_TYPE_POINTER, - G_TYPE_BOOLEAN, - GDK_TYPE_PIXBUF, - G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_STRING); - - /* Create the treeview */ - dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model)); - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(dialog->treeview), TRUE); - gtk_widget_set_size_request(dialog->treeview, 400, 250); - gtk_container_add(GTK_CONTAINER(sw), dialog->treeview); - - /* Add columns */ - status_editor_add_columns(dialog); - - /* Populate list */ - status_editor_populate_list(dialog, saved_status); - - /* Expand the treeview if we have substatuses */ - gtk_expander_set_expanded(GTK_EXPANDER(expander), - (saved_status != NULL) && gaim_savedstatus_has_substatuses(saved_status)); - - /* Button box */ - bbox = gtk_hbutton_box_new(); - gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE); - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); - gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); - - /* Cancel button */ - button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); - gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(status_editor_cancel_cb), dialog); - - /* Use button */ - button = gaim_pixbuf_button_from_stock(_("_Use"), GTK_STOCK_EXECUTE, - GAIM_BUTTON_HORIZONTAL); - gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(status_editor_ok_cb), dialog); - - /* Save & Use button */ - button = gaim_pixbuf_button_from_stock(_("Sa_ve & Use"), GTK_STOCK_OK, - GAIM_BUTTON_HORIZONTAL); - dialog->saveanduse_button = GTK_BUTTON(button); - gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); - if (dialog->original_title == NULL) - gtk_widget_set_sensitive(button, FALSE); - - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(status_editor_ok_cb), dialog); - - /* Save button */ - button = gtk_button_new_from_stock(GTK_STOCK_SAVE); - dialog->save_button = GTK_BUTTON(button); - gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); - if (dialog->original_title == NULL) - gtk_widget_set_sensitive(button, FALSE); - - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(status_editor_ok_cb), dialog); - - gtk_widget_show_all(win); -} - - -/************************************************************************** -* SubStatus editor -**************************************************************************/ - -static void -substatus_selection_changed_cb(GtkComboBox *box, gpointer user_data) -{ - SubStatusEditor *select = user_data; - GtkTreeIter iter; - char *id; - GaimStatusType *type; - - if (!gtk_combo_box_get_active_iter(box, &iter)) - return; - gtk_tree_model_get(GTK_TREE_MODEL(select->model), &iter, - SUBSTATUS_COLUMN_STATUS_ID, &id, - -1); - type = gaim_account_get_status_type(select->account, id); - g_free(id); - - if (gaim_status_type_get_attr(type, "message") == NULL) - { - gtk_widget_set_sensitive(GTK_WIDGET(select->message), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(select->toolbar), FALSE); - } - else - { - gtk_widget_set_sensitive(GTK_WIDGET(select->message), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(select->toolbar), TRUE); - } -} - -static gboolean -status_editor_find_account_in_treemodel(GtkTreeIter *iter, - StatusEditor *status_editor, - GaimAccount *account) -{ - GtkTreeModel *model; - GaimAccount *cur; - - g_return_val_if_fail(status_editor != NULL, FALSE); - g_return_val_if_fail(account != NULL, FALSE); - - model = GTK_TREE_MODEL(status_editor->model); - - if (!gtk_tree_model_get_iter_first(model, iter)) - return FALSE; - - do { - gtk_tree_model_get(model, iter, STATUS_EDITOR_COLUMN_ACCOUNT, &cur, -1); - if (cur == account) - return TRUE; - } while (gtk_tree_model_iter_next(model, iter)); - - return FALSE; -} - -static void -substatus_editor_remove_dialog(SubStatusEditor *dialog) -{ - GtkTreeIter iter; - - if (status_editor_find_account_in_treemodel(&iter, dialog->status_editor, dialog->account)) - { - /* Remove the reference to this dialog from our parent's list store */ - gtk_list_store_set(dialog->status_editor->model, &iter, - STATUS_EDITOR_COLUMN_WINDOW, NULL, - -1); - } -} - -static gboolean -substatus_editor_destroy_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) -{ - SubStatusEditor *dialog = user_data; - - substatus_editor_remove_dialog(dialog); - g_free(dialog); - - return FALSE; -} - -static void -substatus_editor_cancel_cb(GtkButton *button, gpointer user_data) -{ - SubStatusEditor *dialog = user_data; - - substatus_editor_remove_dialog(dialog); - gtk_widget_destroy(dialog->window); - g_free(dialog); -} - - -static void -substatus_editor_ok_cb(GtkButton *button, gpointer user_data) -{ - SubStatusEditor *dialog = user_data; - StatusEditor *status_editor; - GtkTreeIter iter; - GaimStatusType *type; - char *id = NULL; - char *message = NULL; - const char *name = NULL; - - if (!gtk_combo_box_get_active_iter(dialog->box, &iter)) - { - gtk_widget_destroy(dialog->window); - g_free(dialog); - return; - } - - gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, - SUBSTATUS_COLUMN_STATUS_ID, &id, - -1); - type = gaim_account_get_status_type(dialog->account, id); - if (gaim_status_type_get_attr(type, "message") != NULL) - message = gtk_imhtml_get_text(GTK_IMHTML(dialog->message), NULL, NULL); - name = gaim_status_type_get_name(type); - - status_editor = dialog->status_editor; - - if (status_editor_find_account_in_treemodel(&iter, status_editor, dialog->account)) - { - gtk_list_store_set(status_editor->model, &iter, - STATUS_EDITOR_COLUMN_ENABLE_SUBSTATUS, TRUE, - STATUS_EDITOR_COLUMN_STATUS_ID, id, - STATUS_EDITOR_COLUMN_STATUS_NAME, name, - STATUS_EDITOR_COLUMN_STATUS_MESSAGE, message, - STATUS_EDITOR_COLUMN_WINDOW, NULL, - -1); - } - - gtk_widget_destroy(dialog->window); - g_free(id); - g_free(message); - g_free(dialog); -} - -static void -edit_substatus(StatusEditor *status_editor, GaimAccount *account) -{ - char *tmp; - SubStatusEditor *dialog; - GtkSizeGroup *sg; - GtkWidget *bbox; - GtkWidget *button; - GtkWidget *combo; - GtkWidget *hbox; - GtkWidget *frame; - GtkWidget *label; - GtkWidget *text; - GtkWidget *toolbar; - GtkWidget *vbox; - GtkWidget *win; - GtkTreeIter iter; - GtkCellRenderer *rend; - const char *status_id = NULL; - const GList *list; - gboolean select = FALSE; - - g_return_if_fail(status_editor != NULL); - g_return_if_fail(account != NULL); - - status_editor_find_account_in_treemodel(&iter, status_editor, account); - gtk_tree_model_get(GTK_TREE_MODEL(status_editor->model), &iter, - STATUS_EDITOR_COLUMN_WINDOW, &dialog, - -1); - if (dialog != NULL) - { - gtk_window_present(GTK_WINDOW(dialog->window)); - return; - } - - dialog = g_new0(SubStatusEditor, 1); - gtk_list_store_set(status_editor->model, &iter, - STATUS_EDITOR_COLUMN_WINDOW, dialog, - -1); - dialog->status_editor = status_editor; - dialog->account = account; - - dialog->window = win = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_role(GTK_WINDOW(win), "substatus"); - tmp = g_strdup_printf(_("Status for %s"), gaim_account_get_username(account)); - gtk_window_set_title(GTK_WINDOW(win), tmp); - g_free(tmp); - gtk_window_set_resizable(GTK_WINDOW(win), FALSE); - gtk_container_set_border_width(GTK_CONTAINER(win), GAIM_HIG_BORDER); - - g_signal_connect(G_OBJECT(win), "delete_event", - G_CALLBACK(substatus_editor_destroy_cb), dialog); - - /* Setup the vbox */ - vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); - gtk_container_add(GTK_CONTAINER(win), vbox); - - sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - - /* Status type */ - hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic(_("_Status:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_size_group_add_widget(sg, label); - - dialog->model = gtk_list_store_new(SUBSTATUS_NUM_COLUMNS, - GDK_TYPE_PIXBUF, - G_TYPE_STRING, - G_TYPE_STRING); - combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(dialog->model)); - dialog->box = GTK_COMBO_BOX(combo); - - rend = GTK_CELL_RENDERER(gtk_cell_renderer_pixbuf_new()); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), rend, FALSE); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), rend, - "pixbuf", SUBSTATUS_COLUMN_ICON, NULL); - - rend = GTK_CELL_RENDERER(gtk_cell_renderer_text_new()); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), rend, TRUE); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), rend, - "text", SUBSTATUS_COLUMN_STATUS_NAME, NULL); - - g_signal_connect(G_OBJECT(combo), "changed", - G_CALLBACK(substatus_selection_changed_cb), dialog); - - gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 0); - - /* Status mesage */ - hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic(_("_Message:")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); - gtk_size_group_add_widget(sg, label); - - frame = gaim_gtk_create_imhtml(TRUE, &text, &toolbar, NULL); - dialog->message = GTK_IMHTML(text); - dialog->toolbar = GTK_IMHTMLTOOLBAR(toolbar); - gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0); - - /* Button box */ - bbox = gtk_hbutton_box_new(); - gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE); - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); - gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); - - /* Cancel button */ - button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); - gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(substatus_editor_cancel_cb), dialog); - - /* OK button */ - button = gtk_button_new_from_stock(GTK_STOCK_OK); - gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(button), "clicked", - G_CALLBACK(substatus_editor_ok_cb), dialog); - - /* Seed the input widgets with the current values */ - /* TODO: Get the current values from our parent's list store, not the saved_status! */ - if (status_editor->original_title != NULL) - { - GaimSavedStatus *saved_status = NULL; - GaimSavedStatusSub *substatus = NULL; - - saved_status = gaim_savedstatus_find(status_editor->original_title); - if (saved_status != NULL) - substatus = gaim_savedstatus_get_substatus(saved_status, account); - - if (substatus != NULL) - { - gtk_imhtml_append_text(dialog->message, - gaim_savedstatus_substatus_get_message(substatus), - 0); - status_id = gaim_status_type_get_id(gaim_savedstatus_substatus_get_type(substatus)); - } - /* TODO: Else get the generic status type from our parent */ - } - - for (list = gaim_account_get_status_types(account); list; list = list->next) - { - GaimStatusType *status_type; - GdkPixbuf *pixbuf; - const char *id, *name; - - status_type = list->data; - - /* Only allow users to select statuses that are flagged as "user settable" */ - if (!gaim_status_type_is_user_settable(status_type)) - continue; - - id = gaim_status_type_get_id(status_type); - pixbuf = gaim_gtk_create_prpl_icon_with_status(account, status_type, 0.5); - name = gaim_status_type_get_name(status_type); - - gtk_list_store_append(dialog->model, &iter); - gtk_list_store_set(dialog->model, &iter, - SUBSTATUS_COLUMN_ICON, pixbuf, - SUBSTATUS_COLUMN_STATUS_ID, id, - SUBSTATUS_COLUMN_STATUS_NAME, name, - -1); - if (pixbuf != NULL) - g_object_unref(pixbuf); - if ((status_id != NULL) && !strcmp(status_id, id)) - { - gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo), &iter); - select = TRUE; - } - } - - if (!select) - gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0); - - gtk_widget_show_all(win); -} - - -/************************************************************************** - * Utilities * - **************************************************************************/ - -static void -status_menu_cb(GtkComboBox *widget, void(*callback)(GaimSavedStatus*)) -{ - GtkTreeIter iter; - gchar *title = NULL; - - if (!gtk_combo_box_get_active_iter(widget, &iter)) - return; - - gtk_tree_model_get(gtk_combo_box_get_model(widget), &iter, - STATUS_WINDOW_COLUMN_TITLE, &title, -1); - callback(gaim_savedstatus_find(title)); - g_free(title); -} - -static gint -saved_status_sort_alphabetically_func(gconstpointer a, gconstpointer b) -{ - const GaimSavedStatus *saved_status_a = a; - const GaimSavedStatus *saved_status_b = b; - return g_utf8_collate(gaim_savedstatus_get_title(saved_status_a), - gaim_savedstatus_get_title(saved_status_b)); -} - -GtkWidget *gaim_gtk_status_menu(GaimSavedStatus *current_status, GCallback callback) -{ - GtkWidget *combobox; - GList *sorted, *cur; - int i; - int index = -1; - - combobox = gtk_combo_box_new_text(); - - sorted = g_list_copy((GList *)gaim_savedstatuses_get_all()); - sorted = g_list_sort(sorted, saved_status_sort_alphabetically_func); - for (cur = sorted, i = 0; - cur != NULL; - cur = g_list_next(cur)) - { - GaimSavedStatus *status = (GaimSavedStatus *)cur->data; - if (!gaim_savedstatus_is_transient(status)) - { - gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), - gaim_savedstatus_get_title(status)); - if (status == current_status) - index = i; - i++; - } - } - g_list_free(sorted); - - gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), index); - g_signal_connect(G_OBJECT(combobox), "changed", G_CALLBACK(status_menu_cb), callback); - - return combobox; -} - - -/************************************************************************** -* GTK+ saved status glue -**************************************************************************/ - -void * -gaim_gtk_status_get_handle(void) -{ - static int handle; - - return &handle; -} - -void -gaim_gtk_status_init(void) -{ - gaim_prefs_add_none("/gaim/gtk/status"); - gaim_prefs_add_none("/gaim/gtk/status/dialog"); - gaim_prefs_add_int("/gaim/gtk/status/dialog/width", 550); - gaim_prefs_add_int("/gaim/gtk/status/dialog/height", 250); -} - -void -gaim_gtk_status_uninit(void) -{ - gaim_gtk_status_window_hide(); -}