diff options
author | Charles Kerr <charles.kerr@canonical.com> | 2013-07-30 21:36:32 +0000 |
---|---|---|
committer | Tarmac <Unknown> | 2013-07-30 21:36:32 +0000 |
commit | 809982d3f185c6e5480805be6e38538a3a066c63 (patch) | |
tree | 038f8062b150cd5e916fa03162c778344758ec1c | |
parent | fe279460c083468059d7a6e46a4b033ad668c8d3 (diff) | |
parent | a60f5e911160d1f0b15e40a1eefe429b5fe973f9 (diff) | |
download | ayatana-indicator-datetime-809982d3f185c6e5480805be6e38538a3a066c63.tar.gz ayatana-indicator-datetime-809982d3f185c6e5480805be6e38538a3a066c63.tar.bz2 ayatana-indicator-datetime-809982d3f185c6e5480805be6e38538a3a066c63.zip |
add a phone menu as described at https://wiki.ubuntu.com/TimeAndDate#Indicator.
Approved by Ted Gould, PS Jenkins bot.
-rw-r--r-- | README | 6 | ||||
-rw-r--r-- | data/com.canonical.indicator.datetime | 2 | ||||
-rw-r--r-- | debian/control | 2 | ||||
-rw-r--r-- | src/datetime-prefs-locations.c | 2 | ||||
-rw-r--r-- | src/planner-eds.c | 41 | ||||
-rw-r--r-- | src/planner.h | 2 | ||||
-rw-r--r-- | src/service.c | 367 | ||||
-rw-r--r-- | src/settings-shared.h | 29 | ||||
-rw-r--r-- | src/utils.c | 374 | ||||
-rw-r--r-- | src/utils.h | 31 |
10 files changed, 615 insertions, 241 deletions
@@ -42,6 +42,12 @@ CUSTOM MENUITEMS * Calendar - x-canonical-type s "com.canonical.indicator.calendar" + * Alarm + - label s short summary of the appointment + - x-canonical-type s "com.canonical.indicator.alarm" + - x-canonical-time x the date of the appointment + - x-canonical-time-format s strftime format string + * Appointment - label s short summary of the appointment - x-canonical-type s "com.canonical.indicator.appointment" diff --git a/data/com.canonical.indicator.datetime b/data/com.canonical.indicator.datetime index f1b5304..b26b5ec 100644 --- a/data/com.canonical.indicator.datetime +++ b/data/com.canonical.indicator.datetime @@ -10,5 +10,5 @@ ObjectPath=/com/canonical/indicator/datetime/desktop ObjectPath=/com/canonical/indicator/datetime/desktop_greeter [phone] -ObjectPath=/com/canonical/indicator/datetime/desktop +ObjectPath=/com/canonical/indicator/datetime/phone diff --git a/debian/control b/debian/control index b3c1db1..221bd22 100644 --- a/debian/control +++ b/debian/control @@ -34,12 +34,12 @@ Package: indicator-datetime Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, - gnome-control-center, geoclue-ubuntu-geoip | geoclue-provider, systemd-services, systemd-shim, Recommends: indicator-applet | indicator-renderer, evolution-data-server, + ubuntu-system-settings | gnome-control-center, Description: Simple clock A simple clock appearing in the indicator bar diff --git a/src/datetime-prefs-locations.c b/src/datetime-prefs-locations.c index 4bbf053..bc044a2 100644 --- a/src/datetime-prefs-locations.c +++ b/src/datetime-prefs-locations.c @@ -428,7 +428,7 @@ update_times (GtkWidget * dlg) if (strzone && *strzone) { GTimeZone * tz = g_time_zone_new (strzone); GDateTime * now_tz = g_date_time_to_timezone (now, tz); - gchar * format = generate_format_string_at_time (now, now_tz); + gchar * format = generate_full_format_string_at_time (now, now_tz); gchar * time_str = g_date_time_format (now_tz, format); gchar * old_time_str; diff --git a/src/planner-eds.c b/src/planner-eds.c index 8fdc50b..276058d 100644 --- a/src/planner-eds.c +++ b/src/planner-eds.c @@ -64,6 +64,9 @@ struct my_get_appointments_data { ESource * source; GSList * appointments; + + /* ensure that recurring events don't get multiple IndicatorDatetimeAppts */ + GHashTable * added; }; static gboolean @@ -77,12 +80,37 @@ my_get_appointments_foreach (ECalComponent * component, if ((vtype == E_CAL_COMPONENT_EVENT) || (vtype == E_CAL_COMPONENT_TODO)) { - icalproperty_status status; + const gchar * uid = NULL; + icalproperty_status status = 0; + + e_cal_component_get_uid (component, &uid); e_cal_component_get_status (component, &status); - if ((status != ICAL_STATUS_COMPLETED) && (status != ICAL_STATUS_CANCELLED)) + + if ((uid != NULL) && + (!g_hash_table_contains (data->added, uid)) && + (status != ICAL_STATUS_COMPLETED) && + (status != ICAL_STATUS_CANCELLED)) { + GList * alarm_uids; + GSList * l; + GSList * recur_list; ECalComponentText text; - struct IndicatorDatetimeAppt * appt = g_new0 (struct IndicatorDatetimeAppt, 1); + struct IndicatorDatetimeAppt * appt; + + appt = g_new0 (struct IndicatorDatetimeAppt, 1); + + /* Determine whether this is a recurring event. + NB: icalrecurrencetype supports complex recurrence patterns; + however, since design only allows daily recurrence, + that's all we support here. */ + e_cal_component_get_rrule_list (component, &recur_list); + for (l=recur_list; l!=NULL; l=l->next) + { + const struct icalrecurrencetype * recur = l->data; + appt->is_daily |= ((recur->freq == ICAL_DAILY_RECURRENCE) + && (recur->interval == 1)); + } + e_cal_component_free_recur_list (recur_list); text.value = ""; e_cal_component_get_summary (component, &text); @@ -93,7 +121,12 @@ my_get_appointments_foreach (ECalComponent * component, appt->is_event = vtype == E_CAL_COMPONENT_EVENT; appt->summary = g_strdup (text.value); + alarm_uids = e_cal_component_get_alarm_uids (component); + appt->has_alarms = alarm_uids != NULL; + cal_obj_uid_list_free (alarm_uids); + data->appointments = g_slist_prepend (data->appointments, appt); + g_hash_table_add (data->added, g_strdup(uid)); } } @@ -141,6 +174,7 @@ my_get_appointments (IndicatorDatetimePlanner * planner, data.source = NULL; data.appointments = NULL; + data.added = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); sources = e_source_registry_list_sources (p->source_registry, E_SOURCE_EXTENSION_CALENDAR); for (l=sources; l!=NULL; l=l->next) @@ -183,6 +217,7 @@ my_get_appointments (IndicatorDatetimePlanner * planner, g_list_free_full (sources, g_object_unref); g_debug ("%s EDS get_appointments returning %d appointments", G_STRLOC, g_slist_length (data.appointments)); + g_hash_table_destroy (data.added); return data.appointments; } diff --git a/src/planner.h b/src/planner.h index 7499b75..f6148c6 100644 --- a/src/planner.h +++ b/src/planner.h @@ -44,6 +44,8 @@ struct IndicatorDatetimeAppt GDateTime * begin; GDateTime * end; gboolean is_event; + gboolean is_daily; + gboolean has_alarms; }; /** diff --git a/src/service.c b/src/service.c index f0eed76..b52556d 100644 --- a/src/service.c +++ b/src/service.c @@ -59,6 +59,7 @@ enum enum { + PROFILE_PHONE, PROFILE_DESKTOP, PROFILE_GREETER, N_PROFILES @@ -66,6 +67,7 @@ enum static const char * const menu_names[N_PROFILES] = { + "phone", "desktop", "desktop_greeter" }; @@ -111,7 +113,8 @@ struct _IndicatorDatetimeServicePrivate GDateTime * calendar_date; GSimpleActionGroup * actions; - GSimpleAction * header_action; + GSimpleAction * phone_header_action; + GSimpleAction * desktop_header_action; GSimpleAction * calendar_action; GDBusProxy * login1_manager; @@ -458,23 +461,22 @@ get_header_label_format_string (IndicatorDatetimeService * self) { gboolean show_day = g_settings_get_boolean (s, SETTINGS_SHOW_DAY_S); gboolean show_date = g_settings_get_boolean (s, SETTINGS_SHOW_DATE_S); - fmt = generate_format_string_full (show_day, show_date); + fmt = generate_full_format_string (show_day, show_date); } return fmt; } static GVariant * -create_header_state (IndicatorDatetimeService * self) +create_desktop_header_state (IndicatorDatetimeService * self) { GVariantBuilder b; gchar * fmt; gchar * str; gboolean visible; GDateTime * now; - priv_t * p = self->priv; - visible = g_settings_get_boolean (p->settings, SETTINGS_SHOW_CLOCK_S); + visible = g_settings_get_boolean (self->priv->settings, SETTINGS_SHOW_CLOCK_S); /* build the time string for the label & a11y */ fmt = get_header_label_format_string (self); @@ -498,6 +500,54 @@ create_header_state (IndicatorDatetimeService * self) return g_variant_builder_end (&b); } +static gboolean +service_has_alarms (IndicatorDatetimeService * self); + +static GVariant * +create_phone_header_state (IndicatorDatetimeService * self) +{ + GVariantBuilder b; + GDateTime * now; + const gchar * fmt; + gchar * label; + gboolean has_alarms; + gchar * a11y; + + g_variant_builder_init (&b, G_VARIANT_TYPE("a{sv}")); + + /* label */ + now = indicator_datetime_service_get_localtime (self); + fmt = get_terse_time_format_string (now); + label = g_date_time_format (now, fmt); + g_variant_builder_add (&b, "{sv}", "label", g_variant_new_string (label)); + + /* icon */ + if ((has_alarms = service_has_alarms (self))) + { + GIcon * icon; + icon = g_themed_icon_new_with_default_fallbacks ("alarm-symbolic"); + g_variant_builder_add (&b, "{sv}", "icon", g_icon_serialize (icon)); + g_object_unref (icon); + } + + /* a11y */ + if (has_alarms) + a11y = g_strdup_printf (_("%s (has alarms)"), label); + else + a11y = g_strdup (label); + g_variant_builder_add (&b, "{sv}", "accessible-desc", + g_variant_new_string (a11y)); + + /* visible */ + g_variant_builder_add (&b, "{sv}", "visible", g_variant_new_boolean (TRUE)); + + /* cleanup */ + g_free (a11y); + g_free (label); + g_date_time_unref (now); + return g_variant_builder_end (&b); +} + /*** **** @@ -602,41 +652,70 @@ update_calendar_action_state (IndicatorDatetimeService * self) create_calendar_state (self)); } -static GMenuModel * -create_calendar_section (IndicatorDatetimeService * self) +static void +add_localtime_menuitem (GMenu * menu, + IndicatorDatetimeService * self, + const char * time_format, + const char * icon_name) { + GDateTime * now; char * label; GMenuItem * menu_item; - GDateTime * now; - GMenu * menu = g_menu_new (); - /* create the local date menuitem */ now = indicator_datetime_service_get_localtime (self); - label = g_date_time_format (now, _("%A, %e %B %Y")); + label = g_date_time_format (now, time_format); menu_item = g_menu_item_new (label, NULL); - g_menu_item_set_action_and_target_value (menu_item, "indicator.activate-planner", - g_variant_new_int64(0)); + if (icon_name && *icon_name) + g_menu_item_set_attribute (menu_item, G_MENU_ATTRIBUTE_ICON, "s", icon_name); + g_menu_item_set_action_and_target_value (menu_item, "indicator.activate-planner", g_variant_new_int64(0)); g_menu_append_item (menu, menu_item); + g_object_unref (menu_item); g_free (label); g_date_time_unref (now); +} + +static void +add_calendar_menuitem (GMenu * menu) +{ + char * label; + GMenuItem * menu_item; + + label = g_strdup ("[calendar]"); + menu_item = g_menu_item_new ("[calendar]", NULL); + g_menu_item_set_action_and_target_value (menu_item, "indicator.calendar", g_variant_new_int64(0)); + g_menu_item_set_attribute (menu_item, "x-canonical-type", "s", "com.canonical.indicator.calendar"); + g_menu_item_set_attribute (menu_item, "activation-action", "s", "indicator.activate-planner"); + + g_menu_append_item (menu, menu_item); + g_object_unref (menu_item); + g_free (label); +} + +static GMenuModel * +create_desktop_calendar_section (IndicatorDatetimeService * self) +{ + GMenu * menu = g_menu_new (); + + /* strftime(3) format string to show the day of the week and the date */ + add_localtime_menuitem (menu, self, _("%A, %e %B %Y"), "calendar"); - /* create the calendar menuitem */ if (g_settings_get_boolean (self->priv->settings, SETTINGS_SHOW_CALENDAR_S)) - { - label = g_strdup ("[calendar]"); - menu_item = g_menu_item_new ("[calendar]", NULL); - g_menu_item_set_action_and_target_value (menu_item, - "indicator.calendar", - g_variant_new_int64(0)); - g_menu_item_set_attribute (menu_item, "x-canonical-type", - "s", "com.canonical.indicator.calendar"); - g_menu_item_set_attribute (menu_item, "activation-action", - "s", "indicator.activate-planner"); - g_menu_append_item (menu, menu_item); - g_object_unref (menu_item); - g_free (label); - } + add_calendar_menuitem (menu); + + return G_MENU_MODEL (menu); +} + +static GMenuModel * +create_phone_calendar_section (IndicatorDatetimeService * self) +{ + GMenu * menu = g_menu_new (); + + /* strftime(3) format string to show day of week */ + add_localtime_menuitem (menu, self, _("%A"), NULL); + + /* strftime(3) format string to show date */ + add_localtime_menuitem (menu, self, _("%e %B %Y"), "calendar"); return G_MENU_MODEL (menu); } @@ -679,83 +758,135 @@ get_upcoming_appointments (IndicatorDatetimeService * self) return appts; } +static gboolean +service_has_alarms (IndicatorDatetimeService * self) +{ + gboolean has_alarms = FALSE; + GSList * appts; + GSList * l; + + appts = get_upcoming_appointments (self); + for (l=appts; l!=NULL; l=l->next) + { + struct IndicatorDatetimeAppt * appt = l->data; + if ((has_alarms = appt->has_alarms)) + break; + } + + g_slist_free_full (appts, (GDestroyNotify)indicator_datetime_appt_free); + return has_alarms; +} + static char * -get_appointment_time_format (struct IndicatorDatetimeAppt * appt, GDateTime * now) +get_appointment_time_format (struct IndicatorDatetimeAppt * appt, + GDateTime * now, + gboolean terse) { char * fmt; gboolean full_day = g_date_time_difference (appt->end, appt->begin) == G_TIME_SPAN_DAY; - if (full_day) + if (appt->is_daily) + { + const char * time_fmt = terse ? get_terse_time_format_string (appt->begin) + : get_full_time_format_string (); + fmt = join_date_and_time_format_strings (_("Daily"), time_fmt); + } + else if (full_day) { - /* TRANSLATORS: This is a strftime string for the day for full day events - in the menu. It should most likely be either '%A' for a full text day - (Wednesday) or '%a' for a shortened one (Wed). You should only need to - change for '%a' in the case of langauges with very long day names. */ + /* TRANSLATORS: a strftime(3) format showing full day events. + * "%A" means a full text day (Wednesday), "%a" means abbreviated (Wed). */ fmt = g_strdup (_("%A")); } else { - fmt = generate_format_string_at_time (now, appt->begin); + fmt = terse ? generate_terse_format_string_at_time (now, appt->begin) + : generate_full_format_string_at_time (now, appt->begin); } return fmt; } -static GMenuModel * -create_appointments_section (IndicatorDatetimeService * self) +static void +add_appointments (IndicatorDatetimeService * self, GMenu * menu, gboolean terse) { - priv_t * p = self->priv; - GMenu * menu = g_menu_new (); + GDateTime * now = indicator_datetime_service_get_localtime (self); + GSList * appts; + GSList * l; - if (g_settings_get_boolean (p->settings, SETTINGS_SHOW_EVENTS_S)) + /* build appointment menuitems */ + appts = get_upcoming_appointments (self); + for (l=appts; l!=NULL; l=l->next) { - GSList * l; - GSList * appts; + struct IndicatorDatetimeAppt * appt = l->data; + char * fmt = get_appointment_time_format (appt, now, terse); + const gint64 unix_time = g_date_time_to_unix (appt->begin); GMenuItem * menu_item; - GDateTime * now = indicator_datetime_service_get_localtime (self); - /* build appointment menuitems */ - appts = get_upcoming_appointments (self); - for (l=appts; l!=NULL; l=l->next) - { - struct IndicatorDatetimeAppt * appt = l->data; - char * fmt = get_appointment_time_format (appt, now); - const gint64 unix_time = g_date_time_to_unix (appt->begin); - - menu_item = g_menu_item_new (appt->summary, NULL); - g_menu_item_set_attribute (menu_item, "x-canonical-color", - "s", appt->color); - g_menu_item_set_attribute (menu_item, "x-canonical-time", + menu_item = g_menu_item_new (appt->summary, NULL); + + if (!appt->has_alarms) + g_menu_item_set_attribute (menu_item, "x-canonical-color", + "s", appt->color); + + g_menu_item_set_attribute (menu_item, "x-canonical-time", "x", unix_time); - g_menu_item_set_attribute (menu_item, "x-canonical-time-format", + g_menu_item_set_attribute (menu_item, "x-canonical-time-format", "s", fmt); - g_menu_item_set_attribute (menu_item, "x-canonical-type", - "s", "com.canonical.indicator.appointment"); - g_menu_item_set_action_and_target_value (menu_item, + g_menu_item_set_attribute (menu_item, "x-canonical-type", + "s", appt->has_alarms ? "com.canonical.indicator.alarm" + : "com.canonical.indicator.appointment"); + g_menu_item_set_action_and_target_value (menu_item, "indicator.activate-planner", g_variant_new_int64 (unix_time)); - g_menu_append_item (menu, menu_item); - g_object_unref (menu_item); - g_free (fmt); - } + g_menu_append_item (menu, menu_item); + g_object_unref (menu_item); + g_free (fmt); + } + + /* cleanup */ + g_date_time_unref (now); + g_slist_free_full (appts, (GDestroyNotify)indicator_datetime_appt_free); +} + +static GMenuModel * +create_phone_appointments_section (IndicatorDatetimeService * self) +{ + GMenu * menu = g_menu_new (); + GMenuItem * menu_item; + + menu_item = g_menu_item_new (_("Clock"), NULL); + g_menu_item_set_attribute (menu_item, G_MENU_ATTRIBUTE_ICON, "s", "clock"); + g_menu_append_item (menu, menu_item); + g_object_unref (menu_item); + + add_appointments (self, menu, TRUE); + + return G_MENU_MODEL (menu); +} + +static GMenuModel * +create_desktop_appointments_section (IndicatorDatetimeService * self) +{ + GMenu * menu = g_menu_new (); + + if (g_settings_get_boolean (self->priv->settings, SETTINGS_SHOW_EVENTS_S)) + { + GMenuItem * menu_item; + + add_appointments (self, menu, FALSE); - /* build 'add event' menuitem */ + /* add the 'Add Event…' menuitem */ menu_item = g_menu_item_new (_("Add Event…"), NULL); g_menu_item_set_action_and_target_value (menu_item, "indicator.activate-planner", g_variant_new_int64 (0)); g_menu_append_item (menu, menu_item); g_object_unref (menu_item); - - /* cleanup */ - g_date_time_unref (now); - g_slist_free_full (appts, (GDestroyNotify)indicator_datetime_appt_free); } return G_MENU_MODEL (menu); } - /*** **** **** LOCATIONS SECTION @@ -970,7 +1101,7 @@ create_locations_section (IndicatorDatetimeService * self) detailed_action = g_strdup_printf ("indicator.set-location::%s %s", loc->zone, loc->name); - fmt = generate_format_string_at_time (now, loc->local_time); + fmt = generate_full_format_string_at_time (now, loc->local_time); menu_item = g_menu_item_new (label, detailed_action); g_menu_item_set_attribute (menu_item, "x-canonical-type", @@ -1131,10 +1262,18 @@ on_set_location (GSimpleAction * a G_GNUC_UNUSED, ***/ static GMenuModel * -create_settings_section (IndicatorDatetimeService * self G_GNUC_UNUSED) +create_desktop_settings_section (IndicatorDatetimeService * self G_GNUC_UNUSED) { GMenu * menu = g_menu_new (); - g_menu_append (menu, _("Date & Time Settings…"), "indicator.activate-settings"); + g_menu_append (menu, _("Date & Time Settings…"), "indicator.activate-desktop-settings"); + return G_MENU_MODEL (menu); +} + +static GMenuModel * +create_phone_settings_section (IndicatorDatetimeService * self G_GNUC_UNUSED) +{ + GMenu * menu = g_menu_new (); + g_menu_append (menu, _("Time & Date settings…"), "indicator.activate-phone-settings"); return G_MENU_MODEL (menu); } @@ -1145,22 +1284,34 @@ create_menu (IndicatorDatetimeService * self, int profile) GMenu * submenu; GMenuItem * header; GMenuModel * sections[16]; + const gchar * header_action; int i; int n = 0; g_assert (0<=profile && profile<N_PROFILES); g_assert (self->priv->menus[profile].menu == NULL); - if (profile == PROFILE_DESKTOP) + switch (profile) { - sections[n++] = create_calendar_section (self); - sections[n++] = create_appointments_section (self); - sections[n++] = create_locations_section (self); - sections[n++] = create_settings_section (self); - } - else if (profile == PROFILE_GREETER) - { - sections[n++] = create_calendar_section (self); + case PROFILE_PHONE: + sections[n++] = create_phone_calendar_section (self); + sections[n++] = create_phone_appointments_section (self); + sections[n++] = create_phone_settings_section (self); + header_action = "indicator.phone-header"; + break; + + case PROFILE_DESKTOP: + sections[n++] = create_desktop_calendar_section (self); + sections[n++] = create_desktop_appointments_section (self); + sections[n++] = create_locations_section (self); + sections[n++] = create_desktop_settings_section (self); + header_action = "indicator.desktop-header"; + break; + + case PROFILE_GREETER: + sections[n++] = create_desktop_calendar_section (self); + header_action = "indicator.desktop-header"; + break; } /* add sections to the submenu */ @@ -1174,7 +1325,7 @@ create_menu (IndicatorDatetimeService * self, int profile) } /* add submenu to the header */ - header = g_menu_item_new (NULL, "indicator._header"); + header = g_menu_item_new (NULL, header_action); g_menu_item_set_attribute (header, "x-canonical-type", "s", "com.canonical.indicator.root"); g_menu_item_set_submenu (header, G_MENU_MODEL (submenu)); @@ -1203,15 +1354,15 @@ execute_command (const gchar * cmd) if (!g_spawn_command_line_async (cmd, &err)) { - g_warning ("Unable to start %s: %s", cmd, err->message); + g_warning ("Unable to start \"%s\": %s", cmd, err->message); g_error_free (err); } } static void -on_settings_activated (GSimpleAction * a G_GNUC_UNUSED, - GVariant * param G_GNUC_UNUSED, - gpointer gself G_GNUC_UNUSED) +on_desktop_settings_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself G_GNUC_UNUSED) { #ifdef HAVE_CCPANEL execute_command ("gnome-control-center indicator-datetime"); @@ -1221,6 +1372,14 @@ on_settings_activated (GSimpleAction * a G_GNUC_UNUSED, } static void +on_phone_settings_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself G_GNUC_UNUSED) +{ + execute_command ("system-settings time-date"); +} + +static void on_activate_planner (GSimpleAction * a G_GNUC_UNUSED, GVariant * param, gpointer gself) @@ -1271,7 +1430,8 @@ init_gactions (IndicatorDatetimeService * self) priv_t * p = self->priv; GActionEntry entries[] = { - { "activate-settings", on_settings_activated }, + { "activate-desktop-settings", on_desktop_settings_activated }, + { "activate-phone-settings", on_phone_settings_activated }, { "activate-planner", on_activate_planner, "x", NULL }, { "set-location", on_set_location, "s" } }; @@ -1283,10 +1443,17 @@ init_gactions (IndicatorDatetimeService * self) G_N_ELEMENTS(entries), self); - /* add the header action */ - a = g_simple_action_new_stateful ("_header", NULL, create_header_state (self)); + /* add the header actions */ + + a = g_simple_action_new_stateful ("desktop-header", NULL, + create_desktop_header_state (self)); + g_simple_action_group_insert (p->actions, G_ACTION(a)); + p->desktop_header_action = a; + + a = g_simple_action_new_stateful ("phone-header", NULL, + create_phone_header_state (self)); g_simple_action_group_insert (p->actions, G_ACTION(a)); - p->header_action = a; + p->phone_header_action = a; /* add the calendar action */ a = g_simple_action_new_stateful ("calendar", @@ -1321,23 +1488,29 @@ static void rebuild_now (IndicatorDatetimeService * self, int sections) { priv_t * p = self->priv; + struct ProfileMenuInfo * phone = &p->menus[PROFILE_PHONE]; struct ProfileMenuInfo * desktop = &p->menus[PROFILE_DESKTOP]; struct ProfileMenuInfo * greeter = &p->menus[PROFILE_GREETER]; if (sections & SECTION_HEADER) { - g_simple_action_set_state (p->header_action, create_header_state (self)); + g_simple_action_set_state (p->desktop_header_action, + create_desktop_header_state (self)); + g_simple_action_set_state (p->phone_header_action, + create_phone_header_state (self)); } if (sections & SECTION_CALENDAR) { - rebuild_section (desktop->submenu, 0, create_calendar_section (self)); - rebuild_section (greeter->submenu, 0, create_calendar_section (self)); + rebuild_section (phone->submenu, 0, create_phone_calendar_section (self)); + rebuild_section (desktop->submenu, 0, create_desktop_calendar_section (self)); + rebuild_section (greeter->submenu, 0, create_desktop_calendar_section (self)); } if (sections & SECTION_APPOINTMENTS) { - rebuild_section (desktop->submenu, 1, create_appointments_section (self)); + rebuild_section (phone->submenu, 1, create_phone_appointments_section (self)); + rebuild_section (desktop->submenu, 1, create_desktop_appointments_section (self)); } if (sections & SECTION_LOCATIONS) @@ -1347,7 +1520,8 @@ rebuild_now (IndicatorDatetimeService * self, int sections) if (sections & SECTION_SETTINGS) { - rebuild_section (desktop->submenu, 3, create_settings_section (self)); + rebuild_section (phone->submenu, 2, create_phone_settings_section (self)); + rebuild_section (desktop->submenu, 3, create_desktop_settings_section (self)); } } @@ -1586,7 +1760,8 @@ my_dispose (GObject * o) g_clear_object (&p->planner); g_clear_object (&p->calendar_action); - g_clear_object (&p->header_action); + g_clear_object (&p->desktop_header_action); + g_clear_object (&p->phone_header_action); g_clear_object (&p->conn); G_OBJECT_CLASS (indicator_datetime_service_parent_class)->dispose (o); diff --git a/src/settings-shared.h b/src/settings-shared.h index 8c14f1e..27ce34c 100644 --- a/src/settings-shared.h +++ b/src/settings-shared.h @@ -37,33 +37,4 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #define SETTINGS_LOCATIONS_S "locations" #define SETTINGS_TIMEZONE_NAME_S "timezone-name" -enum { - SETTINGS_TIME_LOCALE = 0, - SETTINGS_TIME_12_HOUR = 1, - SETTINGS_TIME_24_HOUR = 2, - SETTINGS_TIME_CUSTOM = 3 -}; - -/* TRANSLATORS: A format string for the strftime function for - a clock showing 12-hour time without seconds. */ -#define DEFAULT_TIME_12_FORMAT N_("%l:%M %p") - -/* TRANSLATORS: A format string for the strftime function for - a clock showing 24-hour time without seconds. */ -#define DEFAULT_TIME_24_FORMAT N_("%H:%M") - -#define DEFAULT_TIME_FORMAT DEFAULT_TIME_12_FORMAT -#define DEFAULT_TIME_FORMAT_WITH_DAY DEFAULT_TIME_12_FORMAT_WITH_DAY - -/* TRANSLATORS: A format string for the strftime function for - a clock showing the day of the week and the time in 12-hour format without - seconds. */ -#define DEFAULT_TIME_12_FORMAT_WITH_DAY N_("%a %l:%M %p") - -/* TRANSLATORS: A format string for the strftime function for - a clock showing the day of the week and the time in 24-hour format without - seconds. Information is available in this Launchpad answer: - https://answers.launchpad.net/ubuntu/+source/indicator-datetime/+question/149752 */ -#define DEFAULT_TIME_24_FORMAT_WITH_DAY N_("%a %H:%M") - #endif diff --git a/src/utils.c b/src/utils.c index fa54008..b99de94 100644 --- a/src/utils.c +++ b/src/utils.c @@ -118,7 +118,7 @@ get_current_zone_name (const gchar * location) } /* Translate msg according to the locale specified by LC_TIME */ -static char * +static const char * T_(const char *msg) { /* General strategy here is to make sure LANGUAGE is empty (since that @@ -154,122 +154,286 @@ T_(const char *msg) return rv; } -/* Tries to figure out what our format string should be. Lots - of translator comments in here. */ gchar * -generate_format_string_full (gboolean show_day, gboolean show_date) +join_date_and_time_format_strings (const char * date_string, + const char * time_string) { - gboolean twelvehour = TRUE; + gchar * str; + + if (date_string && time_string) + { + /* TRANSLATORS: This is a format string passed to strftime to combine the + * date and the time. The value of "%s\xE2\x80\x82%s" will result in a + * string like this in US English 12-hour time: 'Fri Jul 16 11:50 AM'. + * The space in between date and time is a Unicode en space + * (E28082 in UTF-8 hex). */ + str = g_strdup_printf (T_("%s\xE2\x80\x82%s"), date_string, time_string); + } + else if (date_string) + { + str = g_strdup_printf (T_("%s"), date_string); + } + else /* time_string */ + { + str = g_strdup_printf (T_("%s"), time_string); + } - GSettings * settings = g_settings_new (SETTINGS_INTERFACE); - gint time_mode = g_settings_get_enum (settings, SETTINGS_TIME_FORMAT_S); - gboolean show_seconds = g_settings_get_boolean (settings, SETTINGS_SHOW_SECONDS_S); - g_object_unref (settings); + return str; +} - if (time_mode == SETTINGS_TIME_LOCALE) { - twelvehour = is_locale_12h(); - } else if (time_mode == SETTINGS_TIME_24_HOUR) { - twelvehour = FALSE; - } +/*** +**** +***/ - const gchar * time_string = NULL; - if (twelvehour) { - if (show_seconds) { - /* TRANSLATORS: A format string for the strftime function for - a clock showing 12-hour time with seconds. */ - time_string = T_("%l:%M:%S %p"); - } else { - time_string = T_(DEFAULT_TIME_12_FORMAT); - } - } else { - if (show_seconds) { - /* TRANSLATORS: A format string for the strftime function for - a clock showing 24-hour time with seconds. */ - time_string = T_("%H:%M:%S"); - } else { - time_string = T_(DEFAULT_TIME_24_FORMAT); - } - } - - /* Checkpoint, let's not fail */ - g_return_val_if_fail(time_string != NULL, g_strdup(DEFAULT_TIME_FORMAT)); - - /* If there's no date or day let's just leave now and - not worry about the rest of this code */ - if (!show_date && !show_day) { - return g_strdup(time_string); - } +typedef enum +{ + DATE_PROXIMITY_TODAY, + DATE_PROXIMITY_TOMORROW, + DATE_PROXIMITY_WEEK, + DATE_PROXIMITY_FAR +} +date_proximity_t; - const gchar * date_string = NULL; - if (show_date && show_day) { - /* TRANSLATORS: This is a format string passed to strftime to represent - the day of the week, the month and the day of the month. */ - date_string = T_("%a %b %e"); - } else if (show_date) { - /* TRANSLATORS: This is a format string passed to strftime to represent - the month and the day of the month. */ - date_string = T_("%b %e"); - } else if (show_day) { - /* TRANSLATORS: This is a format string passed to strftime to represent - the day of the week. */ - date_string = T_("%a"); - } +static date_proximity_t +get_date_proximity (GDateTime * now, GDateTime * time) +{ + date_proximity_t prox = DATE_PROXIMITY_FAR; + gint now_year, now_month, now_day; + gint time_year, time_month, time_day; + + /* does it happen today? */ + g_date_time_get_ymd (now, &now_year, &now_month, &now_day); + g_date_time_get_ymd (time, &time_year, &time_month, &time_day); + if ((now_year == time_year) && (now_month == time_month) && (now_day == time_day)) + prox = DATE_PROXIMITY_TODAY; + + /* does it happen tomorrow? */ + if (prox == DATE_PROXIMITY_FAR) + { + GDateTime * tomorrow; + gint tom_year, tom_month, tom_day; + + tomorrow = g_date_time_add_days (now, 1); + g_date_time_get_ymd (tomorrow, &tom_year, &tom_month, &tom_day); + if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) + prox = DATE_PROXIMITY_TOMORROW; + + g_date_time_unref (tomorrow); + } + + /* does it happen this week? */ + if (prox == DATE_PROXIMITY_FAR) + { + GDateTime * week; + GDateTime * week_bound; + + week = g_date_time_add_days (now, 6); + week_bound = g_date_time_new_local (g_date_time_get_year(week), + g_date_time_get_month (week), + g_date_time_get_day_of_month(week), + 23, 59, 59.9); + + if (g_date_time_compare (time, week_bound) <= 0) + prox = DATE_PROXIMITY_WEEK; + + g_date_time_unref (week_bound); + g_date_time_unref (week); + } + + return prox; +} + + +/* + * "Terse" time & date format strings + * + * Used on the phone menu where space is at a premium, these strings + * express the time and date in as brief a form as possible. + * + * Examples from spec: + * 1. "Daily 6:30 AM" + * 2. "5:07 PM" (note date is omitted; today's date is implicit) + * 3. "Daily 12 PM" (note minutes are omitted for on-the-hour times) + * 4. "Tomorrow 7 AM" (note "Tomorrow" is used instead of a day of week) + */ + +static const gchar * +get_terse_date_format_string (date_proximity_t proximity) +{ + const gchar * fmt; + + switch (proximity) + { + case DATE_PROXIMITY_TODAY: + /* 'Today' is implicit in the terse case, so no string needed */ + fmt = NULL; + break; + + case DATE_PROXIMITY_TOMORROW: + fmt = T_("Tomorrow"); + break; + + case DATE_PROXIMITY_WEEK: + /* a strftime(3) fmt string for abbreviated day of week */ + fmt = T_("%a"); + break; + + default: + /* a strftime(3) fmt string for day-of-month and abbreviated month */ + fmt = T_("%d %b"); + break; + } + + return fmt; +} + +const gchar * +get_terse_time_format_string (GDateTime * time) +{ + const gchar * fmt; - /* Check point, we should have a date string */ - g_return_val_if_fail(date_string != NULL, g_strdup(time_string)); + if (g_date_time_get_minute (time) != 0) + { + /* a strftime(3) fmt string for a HH:MM 12 hour time, eg "06:59 PM" */ + fmt = T_("%I:%M %p"); + } + else + { + /* a strftime(3) fmt string for a 12 hour on-the-hour time, eg "7 PM" */ + fmt = T_("%l %p"); + } - /* TRANSLATORS: This is a format string passed to strftime to combine the - date and the time. The value of "%s\xE2\x80\x82%s" would result in a string like - this in US English 12-hour time: 'Fri Jul 16 11:50 AM'. - The space in between date and time is a Unicode en space (E28082 in UTF-8 hex). */ - return g_strdup_printf(T_("%s\xE2\x80\x82%s"), date_string, time_string); + return fmt; } gchar * -generate_format_string_at_time (GDateTime * now, GDateTime * time) +generate_terse_format_string_at_time (GDateTime * now, GDateTime * time) { - /* This is a bit less free-form than for the main "now" time label. */ - /* If it is today, just the time should be shown (e.g. “3:55 PM”) - If it is a different day this week, the day and time should be shown (e.g. “Wed 3:55 PM”) - If it is after this week, the day, date, and time should be shown (e.g. “Wed 21 Apr 3:55 PM”). - In addition, when presenting the times of upcoming events, the time should be followed by the timezone if it is different from the one the computer is currently set to. For example, “Wed 3:55 PM UTC−5”. */ - gboolean show_day = FALSE; - gboolean show_date = FALSE; - - /* First, are we same day? */ - gint time_year, time_month, time_day; - gint now_year, now_month, now_day; - g_date_time_get_ymd(time, &time_year, &time_month, &time_day); - g_date_time_get_ymd(now, &now_year, &now_month, &now_day); - - if (time_year != now_year || - time_month != now_month || - time_day != now_day) { - /* OK, different days so we must at least show the day. */ - show_day = TRUE; - - /* Is it this week? */ - /* Here, we define "is this week" as yesterday, today, or the next five days */ - GDateTime * past = g_date_time_add_days(now, -1); - GDateTime * future = g_date_time_add_days(now, 5); - GDateTime * past_bound = g_date_time_new_local(g_date_time_get_year(past), - g_date_time_get_month(past), - g_date_time_get_day_of_month(past), - 0, 0, 0.0); - GDateTime * future_bound = g_date_time_new_local(g_date_time_get_year(future), - g_date_time_get_month(future), - g_date_time_get_day_of_month(future), - 23, 59, 59.9); - if (g_date_time_compare(time, past_bound) < 0 || - g_date_time_compare(time, future_bound) > 0) { - show_date = TRUE; - } - g_date_time_unref(past); - g_date_time_unref(future); - g_date_time_unref(past_bound); - g_date_time_unref(future_bound); - } + const date_proximity_t prox = get_date_proximity (now, time); + const gchar * date_fmt = get_terse_date_format_string (prox); + const gchar * time_fmt = get_terse_time_format_string (time); + return join_date_and_time_format_strings (date_fmt, time_fmt); +} + +/*** +**** FULL +***/ + +static const gchar * +get_full_date_format_string (gboolean show_day, gboolean show_date) +{ + const gchar * fmt; + + if (show_date && show_day) + /* TRANSLATORS: a strftime(3) format showing the date and weekday */ + fmt = T_("%a %b %e"); + else if (show_date) + /* TRANSLATORS: a strftime(3) format showing the date */ + fmt = T_("%b %e"); + else if (show_day) + /* TRANSLATORS: a strftime(3) format showing the weekday */ + fmt = T_("%a"); + else + fmt = NULL; + + return fmt; +} + + +/* + * "Full" time & date format strings + * + * These are used on the desktop menu & header and honors the + * GSettings entries for 12/24hr mode and whether or not to show seconds. + * + */ + +enum +{ + SETTINGS_TIME_LOCALE = 0, + SETTINGS_TIME_12_HOUR = 1, + SETTINGS_TIME_24_HOUR = 2, + SETTINGS_TIME_CUSTOM = 3 +}; + +const gchar * +get_full_time_format_string (void) +{ + GSettings * settings; + gboolean twelvehour; + gboolean show_seconds; + const gchar * fmt; + + settings = g_settings_new (SETTINGS_INTERFACE); + + show_seconds = g_settings_get_boolean (settings, SETTINGS_SHOW_SECONDS_S); + + switch (g_settings_get_enum (settings, SETTINGS_TIME_FORMAT_S)) + { + case SETTINGS_TIME_LOCALE: + twelvehour = is_locale_12h(); + break; + + case SETTINGS_TIME_24_HOUR: + twelvehour = FALSE; + break; + + default: + twelvehour = TRUE; + break; + } + + g_object_unref (settings); + + if (twelvehour && show_seconds) + /* TRANSLATORS: a strftime(3) format for 12hr time w/seconds */ + fmt = T_("%l:%M:%S %p"); + else if (twelvehour) + /* TRANSLATORS: a strftime(3) format for 12hr time */ + fmt = T_("%l:%M %p"); + else if (show_seconds) + /* TRANSLATORS: a strftime(3) format for 24hr time w/seconds */ + fmt = T_("%H:%M:%S"); + else + /* TRANSLATORS: a strftime(3) format for 24hr time */ + fmt = T_("%H:%M"); + + return fmt; +} + +gchar * +generate_full_format_string (gboolean show_day, gboolean show_date) +{ + const gchar * date_fmt = get_full_date_format_string (show_day, show_date); + const gchar * time_fmt = get_full_time_format_string (); + return join_date_and_time_format_strings (date_fmt, time_fmt); +} + +gchar * +generate_full_format_string_at_time (GDateTime * now, GDateTime * time) +{ + gboolean show_day; + gboolean show_date; + + switch (get_date_proximity (now, time)) + { + case DATE_PROXIMITY_TODAY: + show_day = FALSE; + show_date = FALSE; + break; + + case DATE_PROXIMITY_TOMORROW: + case DATE_PROXIMITY_WEEK: + show_day = FALSE; + show_date = TRUE; + break; + + default: + show_day = TRUE; + show_date = TRUE; + break; + } - return generate_format_string_full(show_day, show_date); + return generate_full_format_string (show_day, show_date); } diff --git a/src/utils.h b/src/utils.h index 8dc2964..3b0d0a2 100644 --- a/src/utils.h +++ b/src/utils.h @@ -27,12 +27,33 @@ with this program. If not, see <http://www.gnu.org/licenses/>. G_BEGIN_DECLS -gboolean is_locale_12h (void); -void split_settings_location (const gchar * location, gchar ** zone, gchar ** name); -gchar * get_current_zone_name (const gchar * location); -gchar * generate_format_string_full (gboolean show_day, gboolean show_date); -gchar * generate_format_string_at_time (GDateTime * now, GDateTime * time); +gboolean is_locale_12h (void); +void split_settings_location (const char * location, + char ** zone, + char ** name); + +gchar * get_current_zone_name (const char * location); + +gchar* join_date_and_time_format_strings (const char * date_fmt, + const char * time_fmt); +/*** +**** +***/ + +const gchar * get_terse_time_format_string (GDateTime * time); + +const gchar * get_full_time_format_string (void); + +gchar * generate_terse_format_string_at_time (GDateTime * now, + GDateTime * time); + +gchar * generate_full_format_string (gboolean show_day, + gboolean show_date); + +gchar * generate_full_format_string_at_time (GDateTime * now, + GDateTime * time); + G_END_DECLS #endif |