aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Kerr <charles.kerr@canonical.com>2012-05-21 15:29:19 -0500
committerCharles Kerr <charles.kerr@canonical.com>2012-05-21 15:29:19 -0500
commita93b2144e216afa7b6a61129929bc201ce58d6b1 (patch)
tree5feadcf211b12bc34bf8a5359f0e4606ef3b8d82
parent12a756e980c71b80940a5a611e24645cf398d67e (diff)
parentb51315028eb616e966ca761e50c6b1114680c364 (diff)
downloadayatana-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.xml7
-rw-r--r--data/datetime-dialog.ui58
-rw-r--r--src/datetime-prefs-locations.c170
-rw-r--r--src/datetime-prefs.c2
-rw-r--r--src/datetime-service.c39
-rw-r--r--src/settings-shared.h1
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"