From fff19d70649589b81a896e4deb032a7bd4bdca1e Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 31 Mar 2015 18:54:04 -0500 Subject: add an Alarm class to represent ical valarm components; change the Appointment class to hold an arbitrary number of Alarms. --- src/engine-eds.cpp | 163 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 128 insertions(+), 35 deletions(-) (limited to 'src/engine-eds.cpp') diff --git a/src/engine-eds.cpp b/src/engine-eds.cpp index 47c7a9b..820d9d4 100644 --- a/src/engine-eds.cpp +++ b/src/engine-eds.cpp @@ -126,12 +126,18 @@ public: auto extension = e_source_get_extension(source, E_SOURCE_EXTENSION_CALENDAR); const auto color = e_source_selectable_get_color(E_SOURCE_SELECTABLE(extension)); g_debug("calling e_cal_client_generate_instances for %p", (void*)client); + auto subtask = new AppointmentSubtask(main_task, + client, + color, + default_timezone, + begin_timet, + end_timet); e_cal_client_generate_instances(client, begin_timet, end_timet, m_cancellable, my_get_appointments_foreach, - new AppointmentSubtask (main_task, client, color), + subtask, [](gpointer g){delete static_cast(g);}); } } @@ -409,14 +415,71 @@ private: std::shared_ptr task; ECalClient* client; std::string color; - AppointmentSubtask(const std::shared_ptr& task_in, ECalClient* client_in, const char* color_in): - task(task_in), client(client_in) + icaltimezone* default_timezone; + time_t begin; + time_t end; + + AppointmentSubtask(const std::shared_ptr& task_in, + ECalClient* client_in, + const char* color_in, + icaltimezone* default_tz, + time_t begin_, + time_t end_): + task(task_in), + client(client_in), + default_timezone(default_tz), + begin(begin_), + end(end_) { if (color_in) color = color_in; } }; + static std::string get_alarm_text(ECalComponentAlarm * alarm) + { + std::string ret; + + ECalComponentAlarmAction action; + e_cal_component_alarm_get_action(alarm, &action); + if (action == E_CAL_COMPONENT_ALARM_DISPLAY) + { + ECalComponentText text; + text.value = nullptr; + e_cal_component_alarm_get_description(alarm, &text); + if (text.value) + ret = text.value; + } + + return ret; + } + + static std::string get_alarm_sound_url(ECalComponentAlarm * alarm) + { + std::string ret; + + ECalComponentAlarmAction action; + e_cal_component_alarm_get_action(alarm, &action); + if (action == E_CAL_COMPONENT_ALARM_AUDIO) + { + icalattach* attach = nullptr; + e_cal_component_alarm_get_attach(alarm, &attach); + if (attach != nullptr) + { + if (icalattach_get_is_url (attach)) + { + const char* url = icalattach_get_url(attach); + if (url != nullptr) + ret = url; + } + + icalattach_unref(attach); + } + } + + return ret; + } + static gboolean my_get_appointments_foreach(ECalComponent* component, time_t begin, @@ -461,6 +524,7 @@ private: (status != ICAL_STATUS_COMPLETED) && (status != ICAL_STATUS_CANCELLED)) { + ECalComponentAlarmAction omit[] = { (ECalComponentAlarmAction)-1 }; // list of action types to omit, terminated with -1 Appointment appointment; ECalComponentText text; @@ -475,47 +539,76 @@ private: appointment.uid = uid; appointment.type = type; - // Look through all of this component's alarms - // for DISPLAY or AUDIO url attachments. - // If we find any, use them for appointment.url and audio_sound - auto alarm_uids = e_cal_component_get_alarm_uids(component); - for(auto walk=alarm_uids; appointment.url.empty() && walk!=nullptr; walk=walk->next) + icalcomponent * icc = e_cal_component_get_icalcomponent(component); + g_debug("%s", icalcomponent_as_ical_string(icc)); // libical owns this string; no leak + + auto e_alarms = e_cal_util_generate_alarms_for_comp(component, + subtask->begin, + subtask->end, + omit, + e_cal_client_resolve_tzid_cb, + subtask->client, + subtask->default_timezone); + + std::map alarms; + + if (e_alarms != nullptr) { - auto alarm = e_cal_component_get_alarm(component, static_cast(walk->data)); + for (auto l=e_alarms->alarms; l!=nullptr; l=l->next) + { + auto ai = static_cast(l->data); + auto a = e_cal_component_get_alarm(component, ai->auid); - ECalComponentAlarmAction action; - e_cal_component_alarm_get_action(alarm, &action); - if ((action == E_CAL_COMPONENT_ALARM_DISPLAY) || (action == E_CAL_COMPONENT_ALARM_AUDIO)) + if (a != nullptr) + { + const DateTime alarm_begin{ai->occur_start}; + auto& alarm = alarms[alarm_begin]; + + if (alarm.text.empty()) + alarm.text = get_alarm_text(a); + if (alarm.audio_url.empty()) + alarm.audio_url = get_alarm_sound_url(a); + if (!alarm.time.is_set()) + alarm.time = alarm_begin; + if (alarm.duration == std::chrono::seconds::zero()) + alarm.duration = std::chrono::seconds(ai->occur_end - ai->occur_start); + + e_cal_component_alarm_free(a); + } + } + + e_cal_component_alarms_free(e_alarms); + } + // hm, no trigger. if this came from ubuntu-clock-app, + // manually add a single trigger for the todo event's time + else if (appointment.is_ubuntu_alarm()) + { + Alarm tmp; + tmp.time = appointment.begin; + + auto auids = e_cal_component_get_alarm_uids(component); + for(auto l=auids; l!=nullptr; l=l->next) { - icalattach* attach = nullptr; - e_cal_component_alarm_get_attach(alarm, &attach); - if (attach != nullptr) + const auto auid = static_cast(l->data); + auto a = e_cal_component_get_alarm(component, auid); + if (a != nullptr) { - if (icalattach_get_is_url (attach)) - { - const char* url = icalattach_get_url(attach); - if (url != nullptr) - { - if ((action == E_CAL_COMPONENT_ALARM_DISPLAY) && appointment.url.empty()) - { - appointment.url = url; - } - else if ((action == E_CAL_COMPONENT_ALARM_AUDIO) && appointment.audio_url.empty()) - { - appointment.audio_url = url; - } - } - } - - icalattach_unref(attach); + if (tmp.text.empty()) + tmp.text = get_alarm_text(a); + if (tmp.audio_url.empty()) + tmp.audio_url = get_alarm_sound_url(a); + e_cal_component_alarm_free(a); } } + cal_obj_uid_list_free(auids); - e_cal_component_alarm_free(alarm); + alarms[tmp.time] = tmp; } - cal_obj_uid_list_free(alarm_uids); - g_debug("adding appointment '%s' '%s'", appointment.summary.c_str(), appointment.url.c_str()); + appointment.alarms.reserve(alarms.size()); + for (const auto& it : alarms) + appointment.alarms.push_back(it.second); + subtask->task->appointments.push_back(appointment); } } -- cgit v1.2.3 From e1aba742725c76257bd6845c93d3ac9a14d32089 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 3 Apr 2015 13:57:46 -0500 Subject: in EdsEngine, use empty initializer lists in the new valarm code --- src/engine-eds.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'src/engine-eds.cpp') diff --git a/src/engine-eds.cpp b/src/engine-eds.cpp index 820d9d4..ecbee59 100644 --- a/src/engine-eds.cpp +++ b/src/engine-eds.cpp @@ -444,8 +444,7 @@ private: e_cal_component_alarm_get_action(alarm, &action); if (action == E_CAL_COMPONENT_ALARM_DISPLAY) { - ECalComponentText text; - text.value = nullptr; + ECalComponentText text {}; e_cal_component_alarm_get_description(alarm, &text); if (text.value) ret = text.value; @@ -527,8 +526,7 @@ private: ECalComponentAlarmAction omit[] = { (ECalComponentAlarmAction)-1 }; // list of action types to omit, terminated with -1 Appointment appointment; - ECalComponentText text; - text.value = nullptr; + ECalComponentText text {}; e_cal_component_get_summary(component, &text); if (text.value) appointment.summary = text.value; @@ -579,8 +577,8 @@ private: e_cal_component_alarms_free(e_alarms); } - // hm, no trigger. if this came from ubuntu-clock-app, - // manually add a single trigger for the todo event's time + // hm, no alarms? if this came from ubuntu-clock-app, + // manually add a single alarm for the todo event's time else if (appointment.is_ubuntu_alarm()) { Alarm tmp; @@ -684,10 +682,10 @@ private: std::set m_sources; std::map m_clients; std::map m_views; - GCancellable* m_cancellable = nullptr; - ESourceRegistry* m_source_registry = nullptr; - guint m_rebuild_tag = 0; - time_t m_rebuild_deadline = 0; + GCancellable* m_cancellable {}; + ESourceRegistry* m_source_registry {}; + guint m_rebuild_tag {}; + time_t m_rebuild_deadline {}; }; /*** -- cgit v1.2.3 From 62d68e6453c0ad69ff4d71099441a8151e9a9bea Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sun, 5 Apr 2015 17:27:52 -0500 Subject: fix misuse of ECalComponentAlarmInstance's fields. --- src/engine-eds.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/engine-eds.cpp') diff --git a/src/engine-eds.cpp b/src/engine-eds.cpp index ecbee59..856f190 100644 --- a/src/engine-eds.cpp +++ b/src/engine-eds.cpp @@ -559,7 +559,7 @@ private: if (a != nullptr) { - const DateTime alarm_begin{ai->occur_start}; + const DateTime alarm_begin{ai->trigger}; auto& alarm = alarms[alarm_begin]; if (alarm.text.empty()) @@ -568,8 +568,6 @@ private: alarm.audio_url = get_alarm_sound_url(a); if (!alarm.time.is_set()) alarm.time = alarm_begin; - if (alarm.duration == std::chrono::seconds::zero()) - alarm.duration = std::chrono::seconds(ai->occur_end - ai->occur_start); e_cal_component_alarm_free(a); } -- cgit v1.2.3 From 453a09477ec1eb238d214f61f695a09a0d84949d Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 6 Apr 2015 09:27:01 -0500 Subject: in new code, use std::array rather than C style arrays --- src/engine-eds.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/engine-eds.cpp') diff --git a/src/engine-eds.cpp b/src/engine-eds.cpp index 856f190..2b62fd1 100644 --- a/src/engine-eds.cpp +++ b/src/engine-eds.cpp @@ -25,6 +25,7 @@ #include #include // std::sort() +#include #include // time() #include #include @@ -523,7 +524,7 @@ private: (status != ICAL_STATUS_COMPLETED) && (status != ICAL_STATUS_CANCELLED)) { - ECalComponentAlarmAction omit[] = { (ECalComponentAlarmAction)-1 }; // list of action types to omit, terminated with -1 + std::array omit = { (ECalComponentAlarmAction)-1 }; // list of action types to omit, terminated with -1 Appointment appointment; ECalComponentText text {}; @@ -543,7 +544,7 @@ private: auto e_alarms = e_cal_util_generate_alarms_for_comp(component, subtask->begin, subtask->end, - omit, + omit.data(), e_cal_client_resolve_tzid_cb, subtask->client, subtask->default_timezone); -- cgit v1.2.3 From 7e9b4645721cc76322198df3b55f4cdedc55c200 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 6 Apr 2015 13:17:39 -0500 Subject: in new EDS code, use timezones consistently --- src/engine-eds.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'src/engine-eds.cpp') diff --git a/src/engine-eds.cpp b/src/engine-eds.cpp index 2b62fd1..073b39d 100644 --- a/src/engine-eds.cpp +++ b/src/engine-eds.cpp @@ -497,11 +497,16 @@ private: auto status = ICAL_STATUS_NONE; e_cal_component_get_status(component, &status); - const auto begin_dt = DateTime(begin); - const auto end_dt = DateTime(end); + // get the timezone we want to use for generated Appointments/Alarms + const char * location = icaltimezone_get_location(subtask->default_timezone); + auto gtz = g_time_zone_new(location); + g_debug("timezone abbreviation is %s", g_time_zone_get_abbreviation (gtz, 0)); + + const DateTime begin_dt { gtz, begin }; + const DateTime end_dt { gtz, end }; g_debug ("got appointment from %s to %s, uid %s status %d", - begin_dt.format("%F %T").c_str(), - end_dt.format("%F %T").c_str(), + begin_dt.format("%F %T %z").c_str(), + end_dt.format("%F %T %z").c_str(), uid, (int)status); @@ -560,7 +565,7 @@ private: if (a != nullptr) { - const DateTime alarm_begin{ai->trigger}; + const DateTime alarm_begin{gtz, ai->trigger}; auto& alarm = alarms[alarm_begin]; if (alarm.text.empty()) @@ -608,6 +613,8 @@ private: subtask->task->appointments.push_back(appointment); } + + g_time_zone_unref(gtz); } return G_SOURCE_CONTINUE; -- cgit v1.2.3 From 7feb72952529269b9d6e8be2e04e992acb8812c7 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 6 Apr 2015 14:35:29 -0500 Subject: in EngineEds, make the ECalComponentAlarmAction 'omit' array a constexpr. --- src/engine-eds.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/engine-eds.cpp') diff --git a/src/engine-eds.cpp b/src/engine-eds.cpp index 073b39d..4435bdf 100644 --- a/src/engine-eds.cpp +++ b/src/engine-eds.cpp @@ -529,7 +529,7 @@ private: (status != ICAL_STATUS_COMPLETED) && (status != ICAL_STATUS_CANCELLED)) { - std::array omit = { (ECalComponentAlarmAction)-1 }; // list of action types to omit, terminated with -1 + constexpr std::array omit = { (ECalComponentAlarmAction)-1 }; // list of action types to omit, terminated with -1 Appointment appointment; ECalComponentText text {}; @@ -549,7 +549,7 @@ private: auto e_alarms = e_cal_util_generate_alarms_for_comp(component, subtask->begin, subtask->end, - omit.data(), + const_cast(omit.data()), e_cal_client_resolve_tzid_cb, subtask->client, subtask->default_timezone); -- cgit v1.2.3 From aa3ee9ce63f3fb92b548593d03dd427f59c33ce5 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 6 Apr 2015 14:58:34 -0500 Subject: in the EDS engine, give a better explanation in the comments how we handle alarms with no triggers, and why --- src/engine-eds.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/engine-eds.cpp') diff --git a/src/engine-eds.cpp b/src/engine-eds.cpp index 4435bdf..474bac5 100644 --- a/src/engine-eds.cpp +++ b/src/engine-eds.cpp @@ -581,8 +581,10 @@ private: e_cal_component_alarms_free(e_alarms); } - // hm, no alarms? if this came from ubuntu-clock-app, - // manually add a single alarm for the todo event's time + // Hm, no alarm triggers? + // That's a bug in alarms created by some versions of ubuntu-ui-toolkit. + // If that's what's happening here, let's handle those alarms anyway + // by effectively injecting a TRIGGER;VALUE=DURATION;RELATED=START:PT0S else if (appointment.is_ubuntu_alarm()) { Alarm tmp; -- cgit v1.2.3