/* * finch * * Finch 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #include #include #include #include "gntstatus.h" static struct { GntWidget *window; GntWidget *tree; } statuses; typedef struct { PurpleSavedStatus *saved; GntWidget *window; GntWidget *title; GntWidget *type; GntWidget *message; GntWidget *tree; GHashTable *hash; /* list of windows for substatuses */ } EditStatus; typedef struct { PurpleAccount *account; const PurpleStatusType *type; char *message; } RowInfo; typedef struct { GntWidget *window; GntWidget *type; GntWidget *message; EditStatus *parent; RowInfo *key; } EditSubStatus; static GList *edits; /* List of opened edit-status dialogs */ static void reset_status_window(G_GNUC_UNUSED GntWidget *widget, G_GNUC_UNUSED gpointer data) { statuses.window = NULL; statuses.tree = NULL; } static void populate_statuses(GntTree *tree) { GList *list; for (list = purple_savedstatuses_get_all(); list; list = list->next) { PurpleSavedStatus *saved = list->data; const char *title, *type, *message; if (purple_savedstatus_is_transient(saved)) continue; title = purple_savedstatus_get_title(saved); type = purple_primitive_get_name_from_type(purple_savedstatus_get_primitive_type(saved)); message = purple_savedstatus_get_message(saved); /* XXX: Strip possible markups */ gnt_tree_add_row_last(tree, saved, gnt_tree_create_row(tree, title, type, message), NULL); } } static void really_delete_status(PurpleSavedStatus *saved) { GList *iter; for (iter = edits; iter; iter = iter->next) { EditStatus *edit = iter->data; if (edit->saved == saved) { gnt_widget_destroy(edit->window); break; } } if (statuses.tree) gnt_tree_remove(GNT_TREE(statuses.tree), saved); purple_savedstatus_delete(purple_savedstatus_get_title(saved)); } static void ask_before_delete(G_GNUC_UNUSED GntWidget *button, G_GNUC_UNUSED gpointer data) { char *ask; PurpleSavedStatus *saved; g_return_if_fail(statuses.tree != NULL); saved = gnt_tree_get_selection_data(GNT_TREE(statuses.tree)); ask = g_strdup_printf(_("Are you sure you want to delete \"%s\""), purple_savedstatus_get_title(saved)); purple_request_action(saved, _("Delete Status"), ask, NULL, 0, NULL, saved, 2, _("Delete"), really_delete_status, _("Cancel"), NULL); g_free(ask); } static void use_savedstatus_cb(G_GNUC_UNUSED GntWidget *widget, G_GNUC_UNUSED gpointer data) { g_return_if_fail(statuses.tree != NULL); purple_savedstatus_activate(gnt_tree_get_selection_data(GNT_TREE(statuses.tree))); } static void edit_savedstatus_cb(G_GNUC_UNUSED GntWidget *widget, G_GNUC_UNUSED gpointer data) { g_return_if_fail(statuses.tree != NULL); finch_savedstatus_edit(gnt_tree_get_selection_data(GNT_TREE(statuses.tree))); } void finch_savedstatus_show_all(void) { GntWidget *window, *tree, *box, *button; int widths[] = {25, 12, 35}; if (statuses.window) { gnt_window_present(statuses.window); return; } statuses.window = window = gnt_vbox_new(FALSE); gnt_box_set_toplevel(GNT_BOX(window), TRUE); gnt_box_set_title(GNT_BOX(window), _("Saved Statuses")); gnt_box_set_fill(GNT_BOX(window), FALSE); gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); gnt_box_set_pad(GNT_BOX(window), 0); /* XXX: Add some sorting function to sort alphabetically, perhaps */ statuses.tree = tree = gnt_tree_new_with_columns(3); gnt_tree_set_column_titles(GNT_TREE(tree), _("Title"), _("Type"), _("Message")); gnt_tree_set_show_title(GNT_TREE(tree), TRUE); gnt_tree_set_column_width_ratio(GNT_TREE(tree), widths); gnt_widget_set_size(tree, 72, 0); gnt_box_add_widget(GNT_BOX(window), tree); populate_statuses(GNT_TREE(tree)); box = gnt_hbox_new(FALSE); gnt_box_add_widget(GNT_BOX(window), box); button = gnt_button_new(_("Use")); gnt_box_add_widget(GNT_BOX(box), button); g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(use_savedstatus_cb), NULL); button = gnt_button_new(_("Add")); gnt_box_add_widget(GNT_BOX(box), button); gnt_util_set_trigger_widget(tree, GNT_KEY_INS, button); g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(finch_savedstatus_edit), NULL); button = gnt_button_new(_("Edit")); gnt_box_add_widget(GNT_BOX(box), button); g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(edit_savedstatus_cb), NULL); button = gnt_button_new(_("Delete")); gnt_box_add_widget(GNT_BOX(box), button); gnt_util_set_trigger_widget(tree, GNT_KEY_DEL, button); g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(ask_before_delete), NULL); button = gnt_button_new(_("Close")); gnt_box_add_widget(GNT_BOX(box), button); g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), window); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(reset_status_window), NULL); gnt_widget_show(window); } static void destroy_substatus_win(G_GNUC_UNUSED PurpleAccount *account, EditSubStatus *sub, G_GNUC_UNUSED gpointer data) { gnt_widget_destroy(sub->window); /* the "destroy" callback will remove entry from the hashtable */ } static void free_key(gpointer key, G_GNUC_UNUSED gpointer n) { RowInfo *row = key; g_free(row->message); g_free(key); } static void update_edit_list(G_GNUC_UNUSED GntWidget *widget, EditStatus *edit) { edits = g_list_remove(edits, edit); purple_notify_close_with_handle(edit); g_hash_table_foreach(edit->hash, (GHFunc)destroy_substatus_win, NULL); g_list_foreach((GList*)gnt_tree_get_rows(GNT_TREE(edit->tree)), free_key, NULL); g_free(edit); } static void set_substatuses(EditStatus *edit) { GList *iter; for (iter = gnt_tree_get_rows(GNT_TREE(edit->tree)); iter; iter = iter->next) { RowInfo *key = iter->data; if (gnt_tree_get_choice(GNT_TREE(edit->tree), key)) { purple_savedstatus_set_substatus(edit->saved, key->account, key->type, key->message); } } } static void use_trans_status_cb(G_GNUC_UNUSED GntWidget *button, EditStatus *edit) { const char *message; PurpleStatusPrimitive prim; PurpleSavedStatus *saved; message = gnt_entry_get_text(GNT_ENTRY(edit->message)); prim = GPOINTER_TO_INT(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(edit->type))); saved = purple_savedstatus_find_transient_by_type_and_message(prim, message); if (saved == NULL) { saved = purple_savedstatus_new(NULL, prim); edit->saved = saved; set_substatuses(edit); } purple_savedstatus_set_message(saved, message); purple_savedstatus_activate(saved); gnt_widget_destroy(edit->window); } static void save_savedstatus_cb(GntWidget *button, EditStatus *edit) { const char *title, *message; PurpleStatusPrimitive prim; PurpleSavedStatus *find; title = gnt_entry_get_text(GNT_ENTRY(edit->title)); message = gnt_entry_get_text(GNT_ENTRY(edit->message)); if (!message || !*message) message = NULL; prim = GPOINTER_TO_INT(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(edit->type))); if (!title || !*title) { purple_notify_error(edit, _("Error"), _("Invalid title"), _("Please enter a non-empty title for the status."), NULL); gnt_box_give_focus_to_child(GNT_BOX(edit->window), edit->title); return; } find = purple_savedstatus_find(title); if (find && find != edit->saved) { purple_notify_error(edit, _("Error"), _("Duplicate title"), _("Please enter a different title for the status."), NULL); gnt_box_give_focus_to_child(GNT_BOX(edit->window), edit->title); return; } if (edit->saved == NULL) { edit->saved = purple_savedstatus_new(title, prim); purple_savedstatus_set_message(edit->saved, message); set_substatuses(edit); if (statuses.tree) gnt_tree_add_row_last(GNT_TREE(statuses.tree), edit->saved, gnt_tree_create_row(GNT_TREE(statuses.tree), title, purple_primitive_get_name_from_type(prim), message), NULL); } else { purple_savedstatus_set_title(edit->saved, title); purple_savedstatus_set_primitive_type(edit->saved, prim); purple_savedstatus_set_message(edit->saved, message); if (statuses.tree) { gnt_tree_change_text(GNT_TREE(statuses.tree), edit->saved, 0, title); gnt_tree_change_text(GNT_TREE(statuses.tree), edit->saved, 1, purple_primitive_get_name_from_type(prim)); gnt_tree_change_text(GNT_TREE(statuses.tree), edit->saved, 2, message); } } if (g_object_get_data(G_OBJECT(button), "use")) purple_savedstatus_activate(edit->saved); gnt_widget_destroy(edit->window); } static void add_substatus(EditStatus *edit, PurpleAccount *account) { PurpleContactInfo *info = PURPLE_CONTACT_INFO(account); PurpleSavedStatusSub *sub = NULL; GntTreeRow *row = NULL; char *name; const char *type = NULL, *message = NULL; RowInfo *key; if(!edit || !edit->tree) { return; } if(edit->saved) { sub = purple_savedstatus_get_substatus(edit->saved, account); } key = g_new0(RowInfo, 1); key->account = account; if(sub) { key->type = purple_savedstatus_substatus_get_status_type(sub); type = purple_status_type_get_name(key->type); message = purple_savedstatus_substatus_get_message(sub); key->message = g_strdup(message); } name = g_strdup_printf("%s (%s)", purple_contact_info_get_username(info), purple_account_get_protocol_name(account)); row = gnt_tree_create_row(GNT_TREE(edit->tree), name, type ? type : "", message ? message : ""); gnt_tree_add_choice(GNT_TREE(edit->tree), key, row, NULL, NULL); if(sub) { gnt_tree_set_choice(GNT_TREE(edit->tree), key, TRUE); } g_free(name); } static void substatus_window_destroy_cb(G_GNUC_UNUSED GntWidget *window, EditSubStatus *sub) { g_hash_table_remove(sub->parent->hash, sub->key->account); g_free(sub); } static void save_substatus_cb(G_GNUC_UNUSED GntWidget *widget, EditSubStatus *sub) { PurpleSavedStatus *saved = sub->parent->saved; RowInfo *row = sub->key; const char *message; PurpleStatusType *type; type = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(sub->type)); message = gnt_entry_get_text(GNT_ENTRY(sub->message)); row->type = type; row->message = g_strdup(message); if (saved) /* Save the substatus if the savedstatus actually exists. */ purple_savedstatus_set_substatus(saved, row->account, type, message); gnt_tree_set_choice(GNT_TREE(sub->parent->tree), row, TRUE); gnt_tree_change_text(GNT_TREE(sub->parent->tree), row, 1, purple_status_type_get_name(type)); gnt_tree_change_text(GNT_TREE(sub->parent->tree), row, 2, message); gnt_widget_destroy(sub->window); } static gboolean popup_substatus(GntTree *tree, const char *key, EditStatus *edit) { if (key[0] == ' ' && key[1] == 0) { EditSubStatus *sub; GntWidget *window, *combo, *entry, *box, *button, *l; PurpleContactInfo *info = NULL; PurpleSavedStatusSub *substatus = NULL; GList *iter; char *name; RowInfo *selected = gnt_tree_get_selection_data(tree); PurpleAccount *account = selected->account; if (gnt_tree_get_choice(tree, selected)) { /* There was a savedstatus for this account. Now remove it. */ g_free(selected->message); selected->type = NULL; selected->message = NULL; /* XXX: should we really be saving it right now? */ purple_savedstatus_unset_substatus(edit->saved, account); gnt_tree_change_text(tree, account, 1, NULL); gnt_tree_change_text(tree, account, 2, NULL); return FALSE; } if (g_hash_table_lookup(edit->hash, account)) return TRUE; if (edit->saved) substatus = purple_savedstatus_get_substatus(edit->saved, account); sub = g_new0(EditSubStatus, 1); sub->parent = edit; sub->key = selected; sub->window = window = gnt_vbox_new(FALSE); gnt_box_set_toplevel(GNT_BOX(window), TRUE); gnt_box_set_title(GNT_BOX(window), _("Substatus")); /* XXX: a better title */ gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); box = gnt_hbox_new(FALSE); gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Account:"))); info = PURPLE_CONTACT_INFO(account); name = g_strdup_printf("%s (%s)", purple_contact_info_get_username(info), purple_account_get_protocol_name(account)); gnt_box_add_widget(GNT_BOX(box), gnt_label_new(name)); g_free(name); gnt_box_add_widget(GNT_BOX(window), box); box = gnt_hbox_new(FALSE); gnt_box_add_widget(GNT_BOX(box), (l = gnt_label_new(_("Status:")))); gnt_widget_set_size(l, 0, 1); /* I don't like having to do this */ sub->type = combo = gnt_combo_box_new(); gnt_box_add_widget(GNT_BOX(box), combo); gnt_box_add_widget(GNT_BOX(window), box); for (iter = purple_account_get_status_types(account); iter; iter = iter->next) { PurpleStatusType *type = iter->data; if (!purple_status_type_is_user_settable(type)) continue; gnt_combo_box_add_data(GNT_COMBO_BOX(combo), type, purple_status_type_get_name(type)); } box = gnt_hbox_new(FALSE); gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Message:"))); sub->message = entry = gnt_entry_new(substatus ? purple_savedstatus_substatus_get_message(substatus) : NULL); gnt_box_add_widget(GNT_BOX(box), entry); gnt_box_add_widget(GNT_BOX(window), box); box = gnt_hbox_new(FALSE); button = gnt_button_new(_("Cancel")); g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), window); gnt_box_add_widget(GNT_BOX(box), button); button = gnt_button_new(_("Save")); g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(save_substatus_cb), sub); gnt_box_add_widget(GNT_BOX(box), button); gnt_box_add_widget(GNT_BOX(window), box); gnt_widget_show(window); g_hash_table_insert(edit->hash, account, sub); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(substatus_window_destroy_cb), sub); return TRUE; } return FALSE; } void finch_savedstatus_edit(PurpleSavedStatus *saved) { GListModel *manager_model = NULL; EditStatus *edit; GntWidget *window, *box, *button, *entry, *combo, *label, *tree; PurpleStatusPrimitive prims[] = {PURPLE_STATUS_AVAILABLE, PURPLE_STATUS_AWAY, PURPLE_STATUS_INVISIBLE, PURPLE_STATUS_OFFLINE, PURPLE_STATUS_UNSET}, current; guint n_items = 0; int i; if (saved) { GList *iter; for (iter = edits; iter; iter = iter->next) { edit = iter->data; if (edit->saved == saved) return; } } edit = g_new0(EditStatus, 1); edit->saved = saved; edit->window = window = gnt_vbox_new(FALSE); gnt_box_set_toplevel(GNT_BOX(window), TRUE); gnt_box_set_title(GNT_BOX(window), _("Edit Status")); gnt_box_set_fill(GNT_BOX(window), TRUE); gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID); gnt_box_set_pad(GNT_BOX(window), 0); edits = g_list_append(edits, edit); /* Title */ box = gnt_hbox_new(FALSE); gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_LEFT); gnt_box_add_widget(GNT_BOX(window), box); gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Title"))); edit->title = entry = gnt_entry_new(saved ? purple_savedstatus_get_title(saved) : NULL); gnt_box_add_widget(GNT_BOX(box), entry); /* Type */ box = gnt_hbox_new(FALSE); gnt_box_add_widget(GNT_BOX(window), box); gnt_box_add_widget(GNT_BOX(box), label = gnt_label_new(_("Status"))); gnt_widget_set_size(label, 0, 1); edit->type = combo = gnt_combo_box_new(); gnt_box_add_widget(GNT_BOX(box), combo); current = saved ? purple_savedstatus_get_primitive_type(saved) : PURPLE_STATUS_UNSET; for (i = 0; prims[i] != PURPLE_STATUS_UNSET; i++) { gnt_combo_box_add_data(GNT_COMBO_BOX(combo), GINT_TO_POINTER(prims[i]), purple_primitive_get_name_from_type(prims[i])); if (prims[i] == current) gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), GINT_TO_POINTER(current)); } /* Message */ box = gnt_hbox_new(FALSE); gnt_box_add_widget(GNT_BOX(window), box); gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Message"))); edit->message = entry = gnt_entry_new(saved ? purple_savedstatus_get_message(saved) : NULL); gnt_box_add_widget(GNT_BOX(window), entry); gnt_box_add_widget(GNT_BOX(window), gnt_hline_new()); gnt_box_add_widget(GNT_BOX(window), gnt_label_new(_("Use a different status for some accounts"))); edit->hash = g_hash_table_new(g_direct_hash, g_direct_equal); edit->tree = tree = gnt_tree_new_with_columns(3); gnt_box_add_widget(GNT_BOX(window), tree); gnt_tree_set_show_title(GNT_TREE(tree), TRUE); gnt_tree_set_column_titles(GNT_TREE(tree), _("Account"), _("Status"), _("Message")); gnt_tree_set_col_width(GNT_TREE(tree), 0, 30); gnt_tree_set_col_width(GNT_TREE(tree), 1, 10); gnt_tree_set_col_width(GNT_TREE(tree), 2, 30); manager_model = purple_account_manager_get_default_as_model(); n_items = g_list_model_get_n_items(manager_model); for(guint index = 0; index < n_items; index++) { PurpleAccount *account = g_list_model_get_item(manager_model, index); add_substatus(edit, account); g_object_unref(account); } g_signal_connect(G_OBJECT(tree), "key_pressed", G_CALLBACK(popup_substatus), edit); /* The buttons */ box = gnt_hbox_new(FALSE); gnt_box_add_widget(GNT_BOX(window), box); /* Use */ button = gnt_button_new(_("Use")); gnt_box_add_widget(GNT_BOX(box), button); g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(use_trans_status_cb), edit); /* Save */ button = gnt_button_new(_("Save")); gnt_box_add_widget(GNT_BOX(box), button); g_object_set_data(G_OBJECT(button), "use", NULL); g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(save_savedstatus_cb), edit); /* Save and Use */ button = gnt_button_new(_("Save and Use")); gnt_box_add_widget(GNT_BOX(box), button); g_object_set_data(G_OBJECT(button), "use", GINT_TO_POINTER(TRUE)); g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(save_savedstatus_cb), edit); /* Cancel */ button = gnt_button_new(_("Cancel")); gnt_box_add_widget(GNT_BOX(box), button); g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), window); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(update_edit_list), edit); gnt_widget_show(window); }