aboutsummaryrefslogtreecommitdiff
path: root/src/datetime-prefs-locations.c
diff options
context:
space:
mode:
authorCharles Kerr <charles.kerr@canonical.com>2012-05-17 15:53:17 -0500
committerCharles Kerr <charles.kerr@canonical.com>2012-05-17 15:53:17 -0500
commitb51315028eb616e966ca761e50c6b1114680c364 (patch)
treef909e19f5c96ee45f5f706661e6272a2b60cb508 /src/datetime-prefs-locations.c
parentda61c2a69e259b029c39a6deb0f65217d90e73e4 (diff)
downloadayatana-indicator-datetime-b51315028eb616e966ca761e50c6b1114680c364.tar.gz
ayatana-indicator-datetime-b51315028eb616e966ca761e50c6b1114680c364.tar.bz2
ayatana-indicator-datetime-b51315028eb616e966ca761e50c6b1114680c364.zip
Modify the timezone location sorting to follow mpt's design at https://wiki.ubuntu.com/TimeAndDate
- the auto-detected location, if enabled, is listed before user-specified locations - Locations in the indicator always mirror the Locations Dialog's ordering - Added sort-by-name and sort-by-time buttons in the Locations Dialog
Diffstat (limited to 'src/datetime-prefs-locations.c')
-rw-r--r--src/datetime-prefs-locations.c170
1 files changed, 165 insertions, 5 deletions
diff --git a/src/datetime-prefs-locations.c b/src/datetime-prefs-locations.c
index 9f5b42c..0bea7d9 100644
--- a/src/datetime-prefs-locations.c
+++ b/src/datetime-prefs-locations.c
@@ -44,6 +44,138 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
static gboolean update_times (GtkWidget * dlg);
static void save_when_idle (GtkWidget * dlg);
+/***
+**** Sorting
+***/
+
+/**
+ * A temporary struct used for sorting
+ */
+struct TimeLocation
+{
+ gchar * collated_name;
+ gint pos;
+ gint32 offset;
+};
+
+static struct TimeLocation*
+time_location_new (const char * zone, const char * name, int pos, time_t now)
+{
+ struct TimeLocation * loc = g_new (struct TimeLocation, 1);
+ GTimeZone * tz = g_time_zone_new (zone);
+ const gint interval = g_time_zone_find_interval (tz, G_TIME_TYPE_UNIVERSAL, now);
+ loc->offset = g_time_zone_get_offset (tz, interval);
+ loc->collated_name = g_utf8_collate_key (name, -1);
+ loc->pos = pos;
+ g_time_zone_unref (tz);
+ return loc;
+}
+
+static void
+time_location_free (struct TimeLocation * loc)
+{
+ g_free (loc->collated_name);
+ g_free (loc);
+}
+
+static GSList*
+time_location_array_new_from_model (GtkTreeModel * model)
+{
+ int pos = 0;
+ GtkTreeIter iter;
+ GSList * list = NULL;
+ const time_t now = time (NULL);
+
+ if (gtk_tree_model_get_iter_first (model, &iter)) do
+ {
+ gchar * zone = NULL;
+ gchar * name = NULL;
+
+ gtk_tree_model_get (model, &iter,
+ COL_ZONE, &zone,
+ COL_VISIBLE_NAME, &name,
+ -1);
+ list = g_slist_prepend (list, time_location_new (zone, name, pos++, now));
+
+ g_free (name);
+ g_free (zone);
+ }
+ while (gtk_tree_model_iter_next (model, &iter));
+
+ return g_slist_reverse (list);
+}
+
+static void
+handle_sort(GtkWidget * button, GtkTreeView * tree_view, GCompareFunc compare)
+{
+ GtkTreeModel * model = gtk_tree_view_get_model (tree_view);
+ GSList * l;
+ GSList * list = g_slist_sort (time_location_array_new_from_model(model), compare);
+
+ gint i;
+ gint * reorder = g_new (gint, g_slist_length(list));
+ for (i=0, l=list; l!=NULL; l=l->next, i++)
+ reorder[i] = ((struct TimeLocation*)l->data)->pos;
+ gtk_list_store_reorder (GTK_LIST_STORE(model), reorder);
+
+ g_free (reorder);
+ g_slist_free_full (list, (GDestroyNotify)time_location_free);
+}
+
+static gint
+time_location_compare_by_name (gconstpointer ga, gconstpointer gb)
+{
+ const struct TimeLocation * a = ga;
+ const struct TimeLocation * b = gb;
+ int ret = g_strcmp0 (a->collated_name, b->collated_name); /* primary key */
+ if (!ret)
+ ret = a->offset - b->offset; /* secondary key */
+ return ret;
+}
+static void
+handle_sort_by_name (GtkWidget * button, GtkTreeView * tree_view)
+{
+ handle_sort (button, tree_view, time_location_compare_by_name);
+}
+
+static gint
+time_location_compare_by_time (gconstpointer ga, gconstpointer gb)
+{
+ const struct TimeLocation * a = ga;
+ const struct TimeLocation * b = gb;
+ int ret = a->offset - b->offset; /* primary key */
+ if (!ret)
+ ret = g_strcmp0 (a->collated_name, b->collated_name); /* secondary key */
+ return ret;
+}
+static void
+handle_sort_by_time (GtkWidget * button, GtkTreeView * tree_view)
+{
+ handle_sort (button, tree_view, time_location_compare_by_time);
+}
+
+static gboolean
+time_location_list_test_sorted (GSList * list, GCompareFunc compare)
+{
+ GSList * l;
+ for (l=list; l!=NULL && l->next!=NULL; l=l->next)
+ if (compare(l->data, l->next->data) > 0)
+ return FALSE;
+ return TRUE;
+}
+static void
+location_model_test_sorted (GtkTreeModel * model, gboolean * is_sorted_by_name, gboolean * is_sorted_by_time)
+{
+ GSList * list = time_location_array_new_from_model(model);
+ *is_sorted_by_name = time_location_list_test_sorted (list, time_location_compare_by_name);
+ *is_sorted_by_time = time_location_list_test_sorted (list, time_location_compare_by_time);
+ g_slist_free_full (list, (GDestroyNotify)time_location_free);
+}
+
+/***
+****
+***/
+
static void
handle_add (GtkWidget * button, GtkTreeView * tree)
{
@@ -426,6 +558,26 @@ selection_changed (GtkTreeSelection * selection, GtkWidget * remove_button)
gtk_widget_set_sensitive (remove_button, count > 0);
}
+static void
+update_button_sensitivity (GtkWidget * dlg)
+{
+ GObject * odlg = G_OBJECT(dlg);
+ GObject * completion = g_object_get_data(odlg, "completion");
+ GtkTreeModel * model = GTK_TREE_MODEL (g_object_get_data (completion, "store"));
+ gboolean is_sorted_by_name;
+ gboolean is_sorted_by_time;
+ location_model_test_sorted (model, &is_sorted_by_name, &is_sorted_by_time);
+ gtk_widget_set_sensitive (GTK_WIDGET(g_object_get_data(odlg, "sortByNameButton")), !is_sorted_by_name);
+ gtk_widget_set_sensitive (GTK_WIDGET(g_object_get_data(odlg, "sortByTimeButton")), !is_sorted_by_time);
+}
+
+static void
+model_changed (GtkWidget * dlg)
+{
+ update_button_sensitivity (dlg);
+ save_when_idle (dlg);
+}
+
GtkWidget *
datetime_setup_locations_dialog (CcTimezoneMap * map)
{
@@ -473,6 +625,7 @@ datetime_setup_locations_dialog (CcTimezoneMap * map)
g_signal_connect (tree, "query-tooltip", G_CALLBACK (query_tooltip), cell);
cell = gtk_cell_renderer_text_new ();
+ gtk_cell_renderer_set_alignment (cell, 1.0f, 0.5f);
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree), -1,
_("Time"), cell,
"text", COL_TIME, NULL);
@@ -485,12 +638,19 @@ datetime_setup_locations_dialog (CcTimezoneMap * map)
g_signal_connect (WIG ("addButton"), "clicked", G_CALLBACK (handle_add), tree);
g_signal_connect (WIG ("removeButton"), "clicked", G_CALLBACK (handle_remove), tree);
- fill_from_settings (store, conf);
- g_signal_connect_swapped (store, "row-deleted", G_CALLBACK (save_when_idle), dlg);
- g_signal_connect_swapped (store, "row-inserted", G_CALLBACK (save_when_idle), dlg);
- g_signal_connect_swapped (store, "row-changed", G_CALLBACK (save_when_idle), dlg);
- g_signal_connect_swapped (store, "rows-reordered", G_CALLBACK (save_when_idle), dlg);
+ GtkWidget * w = WIG ("sortByNameButton");
+ g_signal_connect (w, "clicked", G_CALLBACK (handle_sort_by_name), tree);
+ g_object_set_data (G_OBJECT(dlg), "sortByNameButton", w);
+
+ w = WIG ("sortByTimeButton");
+ g_signal_connect (w, "clicked", G_CALLBACK (handle_sort_by_time), tree);
+ g_object_set_data (G_OBJECT(dlg), "sortByTimeButton", w);
+ fill_from_settings (store, conf);
+ g_signal_connect_swapped (store, "row-deleted", G_CALLBACK (model_changed), dlg);
+ g_signal_connect_swapped (store, "row-inserted", G_CALLBACK (model_changed), dlg);
+ g_signal_connect_swapped (store, "row-changed", G_CALLBACK (model_changed), dlg);
+ g_signal_connect_swapped (store, "rows-reordered", G_CALLBACK (model_changed), dlg);
g_object_set_data_full (G_OBJECT (dlg), "conf", g_object_ref (conf), g_object_unref);
g_object_set_data_full (G_OBJECT (dlg), "completion", completion, g_object_unref);
g_signal_connect (dlg, "destroy", G_CALLBACK (dialog_closed), store);