diff options
author | Charles Kerr <charles.kerr@canonical.com> | 2012-05-21 15:29:19 -0500 |
---|---|---|
committer | Charles Kerr <charles.kerr@canonical.com> | 2012-05-21 15:29:19 -0500 |
commit | a93b2144e216afa7b6a61129929bc201ce58d6b1 (patch) | |
tree | 5feadcf211b12bc34bf8a5359f0e4606ef3b8d82 | |
parent | 12a756e980c71b80940a5a611e24645cf398d67e (diff) | |
parent | b51315028eb616e966ca761e50c6b1114680c364 (diff) | |
download | ayatana-indicator-datetime-a93b2144e216afa7b6a61129929bc201ce58d6b1.tar.gz ayatana-indicator-datetime-a93b2144e216afa7b6a61129929bc201ce58d6b1.tar.bz2 ayatana-indicator-datetime-a93b2144e216afa7b6a61129929bc201ce58d6b1.zip |
merge lp:~charlesk/indicator-datetime/lp-833325 to have locations follow the sort order specified in https://wiki.ubuntu.com/TimeAndDate
-rw-r--r-- | data/com.canonical.indicator.datetime.gschema.xml | 7 | ||||
-rw-r--r-- | data/datetime-dialog.ui | 58 | ||||
-rw-r--r-- | src/datetime-prefs-locations.c | 170 | ||||
-rw-r--r-- | src/datetime-prefs.c | 2 | ||||
-rw-r--r-- | src/datetime-service.c | 39 | ||||
-rw-r--r-- | src/settings-shared.h | 1 |
6 files changed, 254 insertions, 23 deletions
diff --git a/data/com.canonical.indicator.datetime.gschema.xml b/data/com.canonical.indicator.datetime.gschema.xml index 8ce75e6..4f831d5 100644 --- a/data/com.canonical.indicator.datetime.gschema.xml +++ b/data/com.canonical.indicator.datetime.gschema.xml @@ -85,6 +85,13 @@ Shows events from Evolution in indicator-datetime's menu. </description> </key> + <key name="show-auto-detected-location" type="b"> + <default>false</default> + <summary>Show the auto-detected location in the indicator</summary> + <description> + Shows your current location (determined from geoclue and /etc/timezone) in indicator-datetime's menu. + </description> + </key> <key name="show-locations" type="b"> <default>false</default> <summary>Show locations in the indicator</summary> diff --git a/data/datetime-dialog.ui b/data/datetime-dialog.ui index f3110ec..2b4cf67 100644 --- a/data/datetime-dialog.ui +++ b/data/datetime-dialog.ui @@ -28,6 +28,8 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="model">locationsStore</property> + <property name="headers_visible">False</property> + <property name="headers_clickable">False</property> <property name="reorderable">True</property> <property name="search_column">0</property> </object> @@ -54,6 +56,7 @@ <object class="GtkHBox" id="hbox10"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="spacing">4</property> <child> <object class="GtkButton" id="addButton"> <property name="visible">True</property> @@ -104,10 +107,46 @@ <property name="position">1</property> </packing> </child> + <child> + <object class="GtkButton" id="sortByNameButton"> + <property name="label" translatable="yes">Sort by _Name</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <accelerator key="n" signal="clicked" modifiers="GDK_MOD1_MASK"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">6</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkButton" id="sortByTimeButton"> + <property name="label" translatable="yes">Sort by _Time</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <accelerator key="t" signal="clicked" modifiers="GDK_MOD1_MASK"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">3</property> + </packing> + </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> + <property name="padding">4</property> <property name="position">2</property> </packing> </child> @@ -679,6 +718,23 @@ </packing> </child> <child> + <object class="GtkCheckButton" id="showDetectedCheck"> + <property name="label" translatable="yes">Time in _auto-detected location</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + <child> <object class="GtkCheckButton" id="showLocationsCheck"> <property name="label" translatable="yes">Time in _other locations</property> <property name="visible">True</property> @@ -719,7 +775,7 @@ <packing> <property name="expand">True</property> <property name="fill">True</property> - <property name="position">5</property> + <property name="position">6</property> </packing> </child> </object> diff --git a/src/datetime-prefs-locations.c b/src/datetime-prefs-locations.c index 0f21a5e..33fd660 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) { @@ -430,6 +562,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) { @@ -477,6 +629,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); @@ -489,12 +642,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); diff --git a/src/datetime-prefs.c b/src/datetime-prefs.c index 611d9ef..d80a59f 100644 --- a/src/datetime-prefs.c +++ b/src/datetime-prefs.c @@ -733,6 +733,8 @@ indicator_datetime_panel_init (IndicatorDatetimePanel * self) "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (conf, SETTINGS_SHOW_EVENTS_S, WIG ("showEventsCheck"), "active", G_SETTINGS_BIND_DEFAULT); + g_settings_bind (conf, SETTINGS_SHOW_DETECTED_S, WIG ("showDetectedCheck"), + "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (conf, SETTINGS_SHOW_LOCATIONS_S, WIG ("showLocationsCheck"), "active", G_SETTINGS_BIND_DEFAULT); diff --git a/src/datetime-service.c b/src/datetime-service.c index d264900..0219cfb 100644 --- a/src/datetime-service.c +++ b/src/datetime-service.c @@ -115,6 +115,7 @@ struct TimeLocation gint32 offset; gchar * zone; gchar * name; + gboolean visible; }; static void time_location_free (struct TimeLocation * loc) @@ -124,7 +125,7 @@ time_location_free (struct TimeLocation * loc) g_free (loc); } static struct TimeLocation* -time_location_new (const char * zone, const char * name, time_t now) +time_location_new (const char * zone, const char * name, gboolean visible, time_t now) { struct TimeLocation * loc = g_new (struct TimeLocation, 1); GTimeZone * tz = g_time_zone_new (zone); @@ -132,6 +133,7 @@ time_location_new (const char * zone, const char * name, time_t now) loc->offset = g_time_zone_get_offset (tz, interval); loc->zone = g_strdup (zone); loc->name = g_strdup (name); + loc->visible = visible; g_time_zone_unref (tz); g_debug ("%s zone '%s' name '%s' offset is %d", G_STRLOC, zone, name, (int)loc->offset); return loc; @@ -139,22 +141,22 @@ time_location_new (const char * zone, const char * name, time_t now) static int time_location_compare (const struct TimeLocation * a, const struct TimeLocation * b) { - int ret; - if (a->offset != b->offset) /* primary key s.t. we can sort by timezone order */ - ret = a->offset - b->offset; - else + int ret = a->offset - b->offset; /* primary key */ + if (!ret) ret = g_strcmp0 (a->name, b->name); /* secondary key */ + if (!ret) + ret = a->visible - b->visible; /* tertiary key */ g_debug ("%s comparing '%s' (%d) to '%s' (%d), returning %d", G_STRLOC, a->name, (int)a->offset, b->name, (int)b->offset, ret); return ret; } static GSList* -locations_add (GSList * locations, const char * zone, const char * name, time_t now) +locations_add (GSList * locations, const char * zone, const char * name, gboolean visible, time_t now) { - struct TimeLocation * loc = time_location_new (zone, name, now); + struct TimeLocation * loc = time_location_new (zone, name, visible, now); if (g_slist_find_custom (locations, loc, (GCompareFunc)time_location_compare) == NULL) { g_debug ("%s Adding zone '%s', name '%s'", G_STRLOC, zone, name); - locations = g_slist_prepend (locations, loc); + locations = g_slist_append (locations, loc); } else { g_debug("%s Skipping duplicate zone '%s' name '%s'", G_STRLOC, zone, name); time_location_free (loc); @@ -188,15 +190,17 @@ update_location_menu_items (void) /* maybe add geo_timezone */ if (geo_timezone != NULL) { + const gboolean visible = g_settings_get_boolean (conf, SETTINGS_SHOW_DETECTED_S); gchar * name = get_current_zone_name (geo_timezone); - locations = locations_add (locations, geo_timezone, name, now); + locations = locations_add (locations, geo_timezone, name, visible, now); g_free (name); } /* maybe add current_timezone */ if (current_timezone != NULL) { + const gboolean visible = g_settings_get_boolean (conf, SETTINGS_SHOW_DETECTED_S); gchar * name = get_current_zone_name (current_timezone); - locations = locations_add (locations, current_timezone, name, now); + locations = locations_add (locations, current_timezone, name, visible, now); g_free (name); } @@ -205,12 +209,13 @@ update_location_menu_items (void) if (user_locations != NULL) { gint i; const guint location_count = g_strv_length (user_locations); + const gboolean visible = g_settings_get_boolean (conf, SETTINGS_SHOW_LOCATIONS_S); g_debug ("%s Found %u user-specified locations", G_STRLOC, location_count); for (i=0; i<location_count; i++) { gchar * zone; gchar * name; split_settings_location (user_locations[i], &zone, &name); - locations = locations_add (locations, zone, name, now); + locations = locations_add (locations, zone, name, visible, now); g_free (name); g_free (zone); } @@ -218,13 +223,10 @@ update_location_menu_items (void) user_locations = NULL; } - /* sort the list by timezone offset */ - locations = g_slist_sort (locations, (GCompareFunc)time_location_compare); - /* finally create menuitems for each location */ gint offset = dbusmenu_menuitem_get_position (locations_separator, root)+1; - const gboolean show_locations = g_settings_get_boolean (conf, SETTINGS_SHOW_LOCATIONS_S); GSList * l; + gboolean have_visible_location = FALSE; for (l=locations; l!=NULL; l=l->next) { struct TimeLocation * loc = l->data; g_debug("%s Adding location: zone '%s', name '%s'", G_STRLOC, loc->zone, loc->name); @@ -234,17 +236,19 @@ update_location_menu_items (void) dbusmenu_menuitem_property_set (item, TIMEZONE_MENUITEM_PROP_ZONE, loc->zone); dbusmenu_menuitem_property_set_bool (item, TIMEZONE_MENUITEM_PROP_RADIO, FALSE); dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE); - dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, show_locations); + dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, loc->visible); dbusmenu_menuitem_child_add_position (root, item, offset++); g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(quick_set_tz), NULL); location_menu_items = g_slist_append (location_menu_items, item); + if (loc->visible) + have_visible_location = TRUE; time_location_free (loc); } g_slist_free (locations); locations = NULL; /* if there's at least one item being shown, show the separator too */ - dbusmenu_menuitem_property_set_bool (locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, show_locations && (location_menu_items!=NULL)); + dbusmenu_menuitem_property_set_bool (locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, have_visible_location); } /* Update the current timezone */ @@ -1090,6 +1094,7 @@ build_menus (DbusmenuMenuitem * root) update_location_menu_items(); g_signal_connect (conf, "changed::" SETTINGS_SHOW_LOCATIONS_S, G_CALLBACK (show_locations_changed), NULL); + g_signal_connect (conf, "changed::" SETTINGS_SHOW_DETECTED_S, G_CALLBACK (show_locations_changed), NULL); g_signal_connect (conf, "changed::" SETTINGS_LOCATIONS_S, G_CALLBACK (show_locations_changed), NULL); g_signal_connect (conf, "changed::" SETTINGS_SHOW_EVENTS_S, G_CALLBACK (show_events_changed), NULL); g_signal_connect (conf, "changed::" SETTINGS_TIME_FORMAT_S, G_CALLBACK (time_format_changed), NULL); diff --git a/src/settings-shared.h b/src/settings-shared.h index da66205..8c14f1e 100644 --- a/src/settings-shared.h +++ b/src/settings-shared.h @@ -33,6 +33,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #define SETTINGS_SHOW_WEEK_NUMBERS_S "show-week-numbers" #define SETTINGS_SHOW_EVENTS_S "show-events" #define SETTINGS_SHOW_LOCATIONS_S "show-locations" +#define SETTINGS_SHOW_DETECTED_S "show-auto-detected-location" #define SETTINGS_LOCATIONS_S "locations" #define SETTINGS_TIMEZONE_NAME_S "timezone-name" |