Mercurial > pidgin.yaz
changeset 12125:3c1bac709234
[gaim-migrate @ 14425]
Change /core/savedstatus/current and /core/savedstatus/idleaway
to ints (they used to be strings, where the value was the title of a
GaimSavedStatus).
The value is now equal to the "creation" timestamp of a saved_status.
The creation timestamp is used as the unique key. The primary reason
for this is to allow for saved statuses to have NULL titles. NULL titles
are needed for transient statuses. I also added a "last_used" timestamp.
This all paves the way for keeping track of recently used statuses
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Fri, 18 Nov 2005 07:23:29 +0000 |
parents | 9c123e27e2f6 |
children | 35c4797c5c57 |
files | src/gtkaccount.c src/gtkidle.c src/gtkstatusbox.c src/savedstatuses.c src/savedstatuses.h |
diffstat | 5 files changed, 267 insertions(+), 139 deletions(-) [+] |
line wrap: on
line diff
--- a/src/gtkaccount.c Fri Nov 18 06:35:07 2005 +0000 +++ b/src/gtkaccount.c Fri Nov 18 07:23:29 2005 +0000 @@ -1622,14 +1622,10 @@ /* If this is a new account, then sign on! */ if (new) { - const char *current_savedstatus_name; - const GaimSavedStatus *saved_status = NULL; - - current_savedstatus_name = gaim_prefs_get_string("/core/savedstatus/current"); - if (current_savedstatus_name) - saved_status = gaim_savedstatus_find(current_savedstatus_name); - - if (saved_status) { + const GaimSavedStatus *saved_status; + + saved_status = gaim_savedstatus_get_current(); + if (saved_status != NULL) { gaim_savedstatus_activate_for_account(saved_status, account); gaim_account_set_enabled(account, GAIM_GTK_UI, TRUE); } @@ -2177,7 +2173,6 @@ GtkTreeModel *model = GTK_TREE_MODEL(dialog->model); GtkTreeIter iter; gboolean enabled; - const char *current_savedstatus_name; const GaimSavedStatus *saved_status; gtk_tree_model_get_iter_from_string(model, &iter, path_str); @@ -2187,8 +2182,7 @@ -1); /* Set the statuses for this account to the current status */ - current_savedstatus_name = gaim_prefs_get_string("/core/savedstatus/current"); - saved_status = gaim_savedstatus_find(current_savedstatus_name); + saved_status = gaim_savedstatus_get_current(); gaim_savedstatus_activate_for_account(saved_status, account); gaim_account_set_enabled(account, GAIM_GTK_UI, !enabled);
--- a/src/gtkidle.c Fri Nov 18 06:35:07 2005 +0000 +++ b/src/gtkidle.c Fri Nov 18 07:23:29 2005 +0000 @@ -159,17 +159,14 @@ { if (gaim_presence_is_available(presence)) { - const char *idleaway_name; GaimSavedStatus *saved_status; gaim_debug_info("idle", "Making %s auto-away\n", gaim_account_get_username(account)); /* Mark our accounts "away" using the idleaway status */ - idleaway_name = gaim_prefs_get_string("/core/savedstatus/idleaway"); - saved_status = gaim_savedstatus_find(idleaway_name); - if (saved_status) - gaim_savedstatus_activate_for_account(saved_status, account); + saved_status = gaim_savedstatus_get_idleaway(); + gaim_savedstatus_activate_for_account(saved_status, account); gc->is_auto_away = GAIM_IDLE_AUTO_AWAY; } else { @@ -180,7 +177,6 @@ idle_time < 60 * gaim_prefs_get_int("/core/away/mins_before_away")) { /* Return from being idle */ - const char *idleaway_name; GaimSavedStatus *saved_status; if (gc->is_auto_away == GAIM_IDLE_AWAY_BUT_NOT_AUTO_AWAY) { @@ -192,10 +188,8 @@ gaim_account_get_username(account)); /* Return our account to its previous status */ - idleaway_name = gaim_prefs_get_string("/core/savedstatus/current"); - saved_status = gaim_savedstatus_find(idleaway_name); - if (saved_status) - gaim_savedstatus_activate_for_account(saved_status, account); + saved_status = gaim_savedstatus_get_idleaway(); + gaim_savedstatus_activate_for_account(saved_status, account); } } /* End of auto-away stuff */
--- a/src/gtkstatusbox.c Fri Nov 18 06:35:07 2005 +0000 +++ b/src/gtkstatusbox.c Fri Nov 18 07:23:29 2005 +0000 @@ -306,15 +306,15 @@ static void update_to_reflect_current_status(GtkGaimStatusBox *status_box) { - const char *current_savedstatus_name; GaimSavedStatus *saved_status; + GaimStatusPrimitive primitive; + const char *message; /* this function is inappropriate for ones with accounts */ if (status_box->account) return; - current_savedstatus_name = gaim_prefs_get_string("/core/savedstatus/current"); - saved_status = gaim_savedstatus_find(current_savedstatus_name); + saved_status = gaim_savedstatus_get_current(); /* * Suppress the "changed" signal because the status @@ -322,58 +322,47 @@ */ gtk_widget_set_sensitive(GTK_WIDGET(status_box), FALSE); - if (saved_status == NULL) + primitive = gaim_savedstatus_get_type(saved_status); + if (gaim_savedstatus_has_substatuses(saved_status) || + ((primitive != GAIM_STATUS_AVAILABLE) && + (primitive != GAIM_STATUS_OFFLINE) && + (primitive != GAIM_STATUS_AWAY) && + (primitive != GAIM_STATUS_HIDDEN))) { - /* Default to "available" */ - gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 0); + gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 5); } else { - GaimStatusPrimitive primitive; - const char *message; + if (primitive == GAIM_STATUS_AVAILABLE) + gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 0); + if (primitive == GAIM_STATUS_OFFLINE) + gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 3); + else if (primitive == GAIM_STATUS_AWAY) + gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 1); + else if (primitive == GAIM_STATUS_HIDDEN) + gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 2); + } - primitive = gaim_savedstatus_get_type(saved_status); - if (gaim_savedstatus_has_substatuses(saved_status) || - ((primitive != GAIM_STATUS_AVAILABLE) && - (primitive != GAIM_STATUS_OFFLINE) && - (primitive != GAIM_STATUS_AWAY) && - (primitive != GAIM_STATUS_HIDDEN))) - { - gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 5); - } - else - { - if (primitive == GAIM_STATUS_AVAILABLE) - gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 0); - if (primitive == GAIM_STATUS_OFFLINE) - gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 3); - else if (primitive == GAIM_STATUS_AWAY) - gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 1); - else if (primitive == GAIM_STATUS_HIDDEN) - gtk_combo_box_set_active(GTK_COMBO_BOX(status_box), 2); - } + message = gaim_savedstatus_get_message(saved_status); + if (!message || !*message) + { + status_box->imhtml_visible = FALSE; + gtk_widget_hide_all(status_box->vbox); + } + else + { + status_box->imhtml_visible = TRUE; + gtk_widget_show_all(status_box->vbox); - message = gaim_savedstatus_get_message(saved_status); - if (!message || !*message) - { - status_box->imhtml_visible = FALSE; - gtk_widget_hide_all(status_box->vbox); - } - else - { - status_box->imhtml_visible = TRUE; - gtk_widget_show_all(status_box->vbox); + /* + * Suppress the "changed" signal because the status + * was changed programmatically. + */ + gtk_widget_set_sensitive(GTK_WIDGET(status_box->imhtml), FALSE); - /* - * Suppress the "changed" signal because the status - * was changed programmatically. - */ - gtk_widget_set_sensitive(GTK_WIDGET(status_box->imhtml), FALSE); - - gtk_imhtml_clear(GTK_IMHTML(status_box->imhtml)); - gtk_imhtml_append_text(GTK_IMHTML(status_box->imhtml), message, 0); - gtk_widget_set_sensitive(GTK_WIDGET(status_box->imhtml), TRUE); - } + gtk_imhtml_clear(GTK_IMHTML(status_box->imhtml)); + gtk_imhtml_append_text(GTK_IMHTML(status_box->imhtml), message, 0); + gtk_widget_set_sensitive(GTK_WIDGET(status_box->imhtml), TRUE); } /* Stop suppressing the "changed" signal. */ @@ -815,8 +804,6 @@ if ((type < 0) || (type >= GAIM_STATUS_NUM_PRIMITIVES)) return; - /* TODO: Should save the previous status as a transient status? */ - if (status_box->account) { gint active; GaimStatusType *status_type; @@ -848,13 +835,10 @@ } } else { /* Save the newly selected status to prefs.xml and status.xml */ - /* TODO: This should be saved as transient. */ - const char *current = NULL; /* Has the status been really changed? */ - current = gaim_prefs_get_string("/core/savedstatus/current"); - saved_status = gaim_savedstatus_find(current); - if (saved_status && gaim_savedstatus_get_type(saved_status) == type) + saved_status = gaim_savedstatus_get_current(); + if (gaim_savedstatus_get_type(saved_status) == type) { if (!message_changed(gaim_savedstatus_get_message(saved_status), message)) changed = FALSE; @@ -862,9 +846,8 @@ if (changed) { - saved_status = gaim_savedstatus_find(_("Default")); - if (saved_status == NULL) - saved_status = gaim_savedstatus_new(_("Default"), type); + /* Create a new transient saved status */ + saved_status = gaim_savedstatus_new(NULL, type); gaim_savedstatus_set_type(saved_status, type); gaim_savedstatus_set_message(saved_status, message);
--- a/src/savedstatuses.c Fri Nov 18 06:35:07 2005 +0000 +++ b/src/savedstatuses.c Fri Nov 18 07:23:29 2005 +0000 @@ -31,12 +31,8 @@ #include "util.h" #include "xmlnode.h" -/* - * TODO: Need to allow transient statuses to have empty titles. - */ - /** - * The information of a snap-shot of the statuses of all + * The information stores a snap-shot of the statuses of all * your accounts. Basically these are your saved away messages. * There is an overall status and message that applies to * all your accounts, and then each individual account can @@ -48,19 +44,15 @@ */ struct _GaimSavedStatus { - /** - * A "transient" status is one that was used recently by - * a Gaim user, but was not explicitly created using the - * saved status UI. For example, Gaim's previous status - * is saved in the status.xml file, but should not show - * up in the UI. - */ - gboolean transient; - char *title; GaimStatusPrimitive type; char *message; + /** The timestamp when this saved status was created. This must be unique. */ + time_t creation_time; + + time_t lastused; + GList *substatuses; /**< A list of GaimSavedStatusSub's. */ }; @@ -75,9 +67,20 @@ char *message; }; -static GList *saved_statuses = NULL; -static guint save_timer = 0; -static gboolean statuses_loaded = FALSE; +static GList *saved_statuses = NULL; +static guint save_timer = 0; +static gboolean statuses_loaded = FALSE; + +/* + * This hash table keeps track of which timestamps we've + * used so that we don't have two saved statuses with the + * same 'creation_time' timestamp. The 'created' timestamp + * is used as a unique identifier. + * + * So the key in this hash table is the creation_time and + * the value is a pointer to the GaimSavedStatus. + */ +static GHashTable *creation_times; /********************************************************************* @@ -111,6 +114,26 @@ g_free(status); } +/* + * Set the timestamp for when this saved status was created, and + * make sure it is unique. + */ +static void +set_creation_time(GaimSavedStatus *status, time_t creation_time) +{ + g_return_if_fail(status != NULL); + + /* Avoid using 0 because it's an invalid hash key */ + status->creation_time = creation_time != 0 ? creation_time : 1; + + while (g_hash_table_lookup(creation_times, &status->creation_time) != NULL) + status->creation_time++; + + g_hash_table_insert(creation_times, + &status->creation_time, + status); +} + /********************************************************************* * Writing to disk * *********************************************************************/ @@ -142,14 +165,18 @@ status_to_xmlnode(GaimSavedStatus *status) { xmlnode *node, *child; - char transient[2]; + char buf[21]; GList *cur; - snprintf(transient, sizeof(transient), "%d", status->transient); + node = xmlnode_new("status"); + if (status->title != NULL) + xmlnode_set_attrib(node, "name", status->title); - node = xmlnode_new("status"); - xmlnode_set_attrib(node, "transient", transient); - xmlnode_set_attrib(node, "name", status->title); + snprintf(buf, sizeof(buf), "%lu", status->creation_time); + xmlnode_set_attrib(node, "created", buf); + + snprintf(buf, sizeof(buf), "%lu", status->lastused); + xmlnode_set_attrib(node, "lastused", buf); child = xmlnode_new_child(node, "state"); xmlnode_insert_data(child, gaim_primitive_get_id_from_type(status->type), -1); @@ -309,25 +336,30 @@ ret = g_new0(GaimSavedStatus, 1); - /* Read the transient property */ - attrib = xmlnode_get_attrib(status, "transient"); - if ((attrib != NULL) && (attrib[0] == '1')) - ret->transient = TRUE; - /* Read the title */ attrib = xmlnode_get_attrib(status, "name"); - if (attrib == NULL) - attrib = "No Title"; - /* Ensure the title is unique */ ret->title = g_strdup(attrib); - i = 2; - while (gaim_savedstatus_find(ret->title) != NULL) + + if (ret->title != NULL) { - g_free(ret->title); - ret->title = g_strdup_printf("%s %d", attrib, i); - i++; + /* Ensure the title is unique */ + i = 2; + while (gaim_savedstatus_find(ret->title) != NULL) + { + g_free(ret->title); + ret->title = g_strdup_printf("%s %d", attrib, i); + i++; + } } + /* Read the creation time */ + attrib = xmlnode_get_attrib(status, "created"); + set_creation_time(ret, (attrib != NULL ? atol(attrib) : 0)); + + /* Read the last used time */ + attrib = xmlnode_get_attrib(status, "lastused"); + ret->lastused = (attrib != NULL ? atol(attrib) : 0); + /* Read the primitive status type */ node = xmlnode_get_child(status, "state"); if ((node != NULL) && ((data = xmlnode_get_data(node)) != NULL)) @@ -395,11 +427,13 @@ GaimSavedStatus *status; /* Make sure we don't already have a saved status with this title. */ - g_return_val_if_fail(gaim_savedstatus_find(title) == NULL, NULL); + if (title != NULL) + g_return_val_if_fail(gaim_savedstatus_find(title) == NULL, NULL); status = g_new0(GaimSavedStatus, 1); status->title = g_strdup(title); status->type = type; + set_creation_time(status, time(NULL)); saved_statuses = g_list_prepend(saved_statuses, status); @@ -498,6 +532,7 @@ gaim_savedstatus_delete(const char *title) { GaimSavedStatus *status; + time_t creation_time, current, idleaway; status = gaim_savedstatus_find(title); @@ -505,10 +540,24 @@ return FALSE; saved_statuses = g_list_remove(saved_statuses, status); + creation_time = gaim_savedstatus_get_creation_time(status); + g_hash_table_remove(creation_times, &creation_time); free_statussaved(status); schedule_save(); + /* + * If we just deleted our current status or our idleaway status, + * then set the appropriate pref back to 0. + */ + current = gaim_prefs_get_int("/core/savedstatus/current"); + if (current == creation_time) + gaim_prefs_set_int("/core/savedstatus/current", 0); + + idleaway = gaim_prefs_get_int("/core/savedstatus/idleaway"); + if (idleaway == creation_time) + gaim_prefs_set_int("/core/savedstatus/idleaway", 0); + return TRUE; } @@ -519,6 +568,58 @@ } GaimSavedStatus * +gaim_savedstatus_get_current() +{ + int creation_time; + GaimSavedStatus *saved_status; + + creation_time = gaim_prefs_get_int("/core/savedstatus/current"); + + if (creation_time == 0) + { + /* + * We don't have a current saved statuses! This is either a new + * Gaim user or someone upgrading from Gaim 1.5.0 or older. Add + * a default status. + */ + saved_status = gaim_savedstatus_new(NULL, GAIM_STATUS_AVAILABLE); + gaim_savedstatus_set_message(saved_status, _("Hello!")); + } + else + { + saved_status = g_hash_table_lookup(creation_times, &creation_time); + } + + return saved_status; +} + +GaimSavedStatus * +gaim_savedstatus_get_idleaway() +{ + int creation_time; + GaimSavedStatus *saved_status; + + creation_time = gaim_prefs_get_int("/core/savedstatus/idleaway"); + + if (creation_time == 0) + { + /* + * We don't have a current saved statuses! This is either a new + * Gaim user or someone upgrading from Gaim 1.5.0 or older. Add + * a default status. + */ + saved_status = gaim_savedstatus_new(NULL, GAIM_STATUS_AWAY); + gaim_savedstatus_set_message(saved_status, _("I'm not here right now")); + } + else + { + saved_status = g_hash_table_lookup(creation_times, &creation_time); + } + + return saved_status; +} + +GaimSavedStatus * gaim_savedstatus_find(const char *title) { GList *iter; @@ -529,7 +630,7 @@ for (iter = saved_statuses; iter != NULL; iter = iter->next) { status = (GaimSavedStatus *)iter->data; - if (!strcmp(status->title, title)) + if ((status->title != NULL) && !strcmp(status->title, title)) return status; } @@ -539,7 +640,7 @@ gboolean gaim_savedstatus_is_transient(const GaimSavedStatus *saved_status) { - return saved_status->transient; + return (saved_status->title == NULL); } const char * @@ -560,6 +661,12 @@ return saved_status->message; } +time_t +gaim_savedstatus_get_creation_time(const GaimSavedStatus *saved_status) +{ + return saved_status->creation_time; +} + gboolean gaim_savedstatus_has_substatuses(const GaimSavedStatus *saved_status) { @@ -603,7 +710,7 @@ } void -gaim_savedstatus_activate(const GaimSavedStatus *saved_status) +gaim_savedstatus_activate(GaimSavedStatus *saved_status) { GList *accounts, *node; @@ -621,8 +728,13 @@ g_list_free(accounts); - gaim_prefs_set_string("/core/savedstatus/current", - gaim_savedstatus_get_title(saved_status)); + /* + * TODO: Need to rotate the old status out of here so we + * can keep track of recently used statuses. + */ + saved_status->lastused = time(NULL); + gaim_prefs_set_int("/core/savedstatus/current", + gaim_savedstatus_get_creation_time(saved_status)); } void @@ -674,25 +786,20 @@ void gaim_savedstatuses_init(void) { - load_statuses(); - - if (saved_statuses == NULL) - { - /* - * We don't have any saved statuses! This is probably a new account, - * so we add the "Default" status and the "Default when idle" status. - */ - GaimSavedStatus *saved_status; + creation_times = g_hash_table_new(g_int_hash, g_int_equal); - saved_status = gaim_savedstatus_new(_("Default"), GAIM_STATUS_AVAILABLE); - gaim_savedstatus_set_message(saved_status, _("Hello!")); + /* + * Using 0 as the creation_time is a special case. + * If someone calls gaim_savedstatus_get_current() or + * gaim_savedstatus_get_idleaway() and either of those functions + * sees a creation_time of 0, then it will create a default + * saved status and return that to the user. + */ + gaim_prefs_add_none("/core/savedstatus"); + gaim_prefs_add_int("/core/savedstatus/current", 0); + gaim_prefs_add_int("/core/savedstatus/idleaway", 0); - saved_status = gaim_savedstatus_new(_("Default when idle"), GAIM_STATUS_AWAY); - gaim_savedstatus_set_message(saved_status, _("I'm not here right now")); - } - - gaim_prefs_add_string("/core/savedstatus/current", _("Default")); - gaim_prefs_add_string("/core/savedstatus/idleaway", _("Default when idle")); + load_statuses(); } void @@ -710,5 +817,7 @@ saved_statuses = g_list_remove(saved_statuses, saved_status); free_statussaved(saved_status); } + + g_hash_table_destroy(creation_times); }
--- a/src/savedstatuses.h Fri Nov 18 06:35:07 2005 +0000 +++ b/src/savedstatuses.h Fri Nov 18 07:23:29 2005 +0000 @@ -30,6 +30,21 @@ * could really be a plugin. It's just a list of away states. When * a user chooses one of the saved states, their Gaim accounts are set * to the settings of that state. + * + * In the savedstatus API, there is the concept of a 'transient' + * saved status. A transient saved status is one that is not + * permanent. Gaim will removed it automatically if it isn't + * used for a period of time. Transient saved statuses don't + * have titles and they don't show up in the list of saved + * statuses. In fact, if a saved status does not have a title + * then it is transient. If it does have a title, then it is not + * transient. + * + * What good is a transient status, you ask? They can be used to + * keep track of the user's 5 most recently used statuses, for + * example. Basically if they just set a message on the fly, + * we'll cache it for them in case they want to use it again. If + * they don't use it again, we'll just delete it. */ /* @@ -53,7 +68,8 @@ * list of saved statuses and writes the revised list to status.xml. * * @param title The title of the saved status. This must be - * unique. + * unique. Or, if you want to create a transient + * saved status, then pass in NULL. * @param type The type of saved status. * * @return The newly created saved status, or NULL if the title you @@ -136,6 +152,21 @@ const GList *gaim_savedstatuses_get_all(void); /** + * Returns the currently selected saved status. + * + * @return A pointer to the in-use GaimSavedStatus. + */ +GaimSavedStatus *gaim_savedstatus_get_current(); + +/** + * Returns the saved status that gets used when your + * accounts become idle-away. + * + * @return A pointer to the idle-away GaimSavedStatus. + */ +GaimSavedStatus *gaim_savedstatus_get_idleaway(); + +/** * Finds a saved status with the specified title. * * @param title The name of the saved status. @@ -191,6 +222,23 @@ const char *gaim_savedstatus_get_message(const GaimSavedStatus *saved_status); /** + * Return the time in seconds-since-the-epoch when this + * saved status was created. Note: For any status created + * by Gaim 1.5.0 or older this value will be invalid and + * very small (close to 0). This is because Gaim 1.5.0 + * and older did not record the timestamp when the status + * was created. + * + * However, this value is guaranteed to be a unique + * identifier for the given saved status. + * + * @param saved_status The saved status. + * + * @return The timestamp when this saved status was created. + */ +time_t gaim_savedstatus_get_creation_time(const GaimSavedStatus *saved_status); + +/** * Determine if a given saved status has "substatuses," * or if it is a simple status (the same for all * accounts). @@ -242,7 +290,7 @@ * * @param saved_status The status you want to set your accounts to. */ -void gaim_savedstatus_activate(const GaimSavedStatus *saved_status); +void gaim_savedstatus_activate(GaimSavedStatus *saved_status); /** * Sets the statuses for a given account to those specified