aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Kerr <charles.kerr@canonical.com>2014-01-14 23:07:10 -0600
committerCharles Kerr <charles.kerr@canonical.com>2014-01-14 23:07:10 -0600
commitee64bb2698adfe27e55615a8856b0e2c78ad8469 (patch)
treeb8fb6e1440ac700f7f51e5c765303abb315c6399
parent3b8833efe6ab21387b6f73b4a4ef757445801623 (diff)
downloadayatana-indicator-datetime-ee64bb2698adfe27e55615a8856b0e2c78ad8469.tar.gz
ayatana-indicator-datetime-ee64bb2698adfe27e55615a8856b0e2c78ad8469.tar.bz2
ayatana-indicator-datetime-ee64bb2698adfe27e55615a8856b0e2c78ad8469.zip
Function: add fully-tested ActionGroups, per-profile Menus, state object.
Form: Add code annotations/comments. Remove dead code. Use Mir style guide. Todo: GSettings toggles, sync with new dbus-test-runner API, get GNOME Panel building again
-rw-r--r--CMakeLists.txt2
-rw-r--r--include/datetime/actions-live.h57
-rw-r--r--include/datetime/actions.h70
-rw-r--r--include/datetime/appointment.h4
-rw-r--r--include/datetime/clock-mock.h28
-rw-r--r--include/datetime/clock.h25
-rw-r--r--include/datetime/date-time.h103
-rw-r--r--include/datetime/dbus-shared.h37
-rw-r--r--include/datetime/formatter.h29
-rw-r--r--include/datetime/locations-settings.h11
-rw-r--r--include/datetime/locations.h38
-rw-r--r--include/datetime/menu.h82
-rw-r--r--include/datetime/planner-eds.h2
-rw-r--r--include/datetime/planner-mock.h44
-rw-r--r--include/datetime/planner.h3
-rw-r--r--include/datetime/service.h72
-rw-r--r--include/datetime/settings-live.h57
-rw-r--r--include/datetime/settings-shared.h6
-rw-r--r--include/datetime/settings.h63
-rw-r--r--include/datetime/state.h68
-rw-r--r--include/datetime/timezone-file.h13
-rw-r--r--include/datetime/timezone-geoclue.h12
-rw-r--r--include/datetime/timezone.h4
-rw-r--r--include/datetime/timezones-live.h13
-rw-r--r--include/datetime/timezones.h4
-rw-r--r--include/datetime/utils.h28
-rw-r--r--panel/CMakeLists.txt2
-rw-r--r--src/CMakeLists.txt11
-rw-r--r--src/actions-live.cpp84
-rw-r--r--src/actions.cpp215
-rw-r--r--src/clock-live.cpp84
-rw-r--r--src/clock.cpp32
-rw-r--r--src/formatter-desktop.cpp258
-rw-r--r--src/formatter.cpp146
-rw-r--r--src/locations-settings.cpp59
-rw-r--r--src/locations.cpp33
-rw-r--r--src/main.c83
-rw-r--r--src/main.cpp81
-rw-r--r--src/menu.cpp518
-rw-r--r--src/planner-eds.cpp283
-rw-r--r--src/planner-eds.h58
-rw-r--r--src/planner.h167
-rw-r--r--src/service.cpp140
-rw-r--r--src/settings-live.cpp293
-rw-r--r--src/timezone-file.cpp18
-rw-r--r--src/timezone-geoclue.cpp66
-rw-r--r--src/timezones-live.cpp34
-rw-r--r--src/utils.cpp139
-rw-r--r--tests/CMakeLists.txt27
-rw-r--r--tests/Makefile.am.strings38
-rw-r--r--tests/actions-mock.h88
-rw-r--r--tests/glib-fixture.h85
-rw-r--r--tests/planner-mock.c34
-rw-r--r--tests/state-fixture.h75
-rw-r--r--tests/test-actions.cc173
-rw-r--r--tests/test-clock.cc176
-rw-r--r--tests/test-core.cc148
-rw-r--r--tests/test-dbus-fixture.h100
-rw-r--r--tests/test-formatter.cc61
-rw-r--r--tests/test-indicator.cc92
-rw-r--r--tests/test-locations.cc136
-rw-r--r--tests/test-menus.cc406
-rw-r--r--tests/test-planner-eds.cc70
-rw-r--r--tests/test-planner.cc49
-rw-r--r--tests/test-skew.cc209
-rw-r--r--tests/test-timezone-file.cc60
-rw-r--r--tests/test-timezone-geoclue.cc28
-rw-r--r--tests/test-timezones.cc83
-rw-r--r--tests/test-utils.cc153
69 files changed, 3962 insertions, 2008 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1fdd4a3..da97a6d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -75,7 +75,7 @@ add_custom_target (cppcheck COMMAND cppcheck --enable=all -q --error-exitcode=2
##
set (CC_WARNING_ARGS " -Wall -Wshadow -Wextra -Wunused -Wformat=2 -Wno-missing-field-initializers")
-set (CXX_WARNING_ARGS " -Wall -Wextra -pedantic")
+set (CXX_WARNING_ARGS " -Wall -Wextra -pedantic -Wno-missing-field-initializers")
include_directories (${CMAKE_CURRENT_SOURCE_DIR}/include)
include_directories (${CMAKE_CURRENT_BINARY_DIR}/include)
diff --git a/include/datetime/actions-live.h b/include/datetime/actions-live.h
new file mode 100644
index 0000000..2059a4d
--- /dev/null
+++ b/include/datetime/actions-live.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#ifndef INDICATOR_DATETIME_ACTIONS_LIVE_H
+#define INDICATOR_DATETIME_ACTIONS_LIVE_H
+
+#include <datetime/actions.h>
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/**
+ * \brief Production implentation of the Actions interface.
+ *
+ * Delegates URLs, sets the timezone via org.freedesktop.timedate1, etc.
+ *
+ * @see MockActions
+ */
+class LiveActions: public Actions
+{
+public:
+ LiveActions(std::shared_ptr<State>& state): Actions(state) {}
+ ~LiveActions() =default;
+
+ void open_desktop_settings();
+ void open_phone_settings();
+ void open_phone_clock();
+ void open_phone_planner();
+ void open_planner_at(const DateTime&);
+ void open_calendar_at(const DateTime&);
+ void open_appointment(const std::string& uid);
+ void set_location(const std::string& zone, const std::string& name);
+ void set_calendar_date(const DateTime&);
+};
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
+#endif // INDICATOR_DATETIME_ACTIONS_H
diff --git a/include/datetime/actions.h b/include/datetime/actions.h
new file mode 100644
index 0000000..ed45c3c
--- /dev/null
+++ b/include/datetime/actions.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#ifndef INDICATOR_DATETIME_ACTIONS_H
+#define INDICATOR_DATETIME_ACTIONS_H
+
+#include <datetime/date-time.h>
+#include <datetime/state.h>
+
+#include <memory> // shared_ptr
+#include <string>
+
+#include <gio/gio.h> // GSimpleActionGroup
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/**
+ * Interface for all the actions that can be activated by users via the menu.
+ */
+class Actions
+{
+public:
+ virtual void open_desktop_settings() =0;
+ virtual void open_phone_settings() =0;
+ virtual void open_phone_clock_app() =0;
+ virtual void open_planner() =0;
+ virtual void open_planner_at(const DateTime&) =0;
+ virtual void open_appointment(const std::string& uid) =0;
+ virtual void set_location(const std::string& zone, const std::string& name)=0;
+ virtual void set_calendar_date(const DateTime&) =0;
+
+ GActionGroup* action_group() { return G_ACTION_GROUP(m_actions); }
+ std::shared_ptr<State> state() { return m_state; }
+
+protected:
+ Actions(std::shared_ptr<State>& state);
+ virtual ~Actions();
+
+private:
+ std::shared_ptr<State> m_state;
+ GSimpleActionGroup* m_actions = nullptr;
+
+ // we've got raw pointers in here, so disable copying
+ Actions(const Actions&) =delete;
+ Actions& operator=(const Actions&) =delete;
+};
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
+#endif // INDICATOR_DATETIME_ACTIONS_H
diff --git a/include/datetime/appointment.h b/include/datetime/appointment.h
index 098b0d0..e034c08 100644
--- a/include/datetime/appointment.h
+++ b/include/datetime/appointment.h
@@ -28,7 +28,9 @@ namespace indicator {
namespace datetime {
/**
- * PODS representing a calendar appointment
+ * \brief Plain Old Data Structure that represents a calendar appointment.
+ *
+ * @see Planner
*/
struct Appointment
{
diff --git a/include/datetime/clock-mock.h b/include/datetime/clock-mock.h
index 814b29a..19a859b 100644
--- a/include/datetime/clock-mock.h
+++ b/include/datetime/clock-mock.h
@@ -30,30 +30,28 @@ namespace datetime {
****
***/
+/**
+ * \brief A clock that uses a client-provided time instead of the system time.
+ */
class MockClock: public Clock
{
public:
+ MockClock(const DateTime& dt): m_localtime(dt) {}
+ ~MockClock() =default;
- MockClock(GDateTime * dt) { setLocaltime(dt); }
-
- ~MockClock() {
- g_clear_pointer(&localtime_, g_date_time_unref);
- }
-
- GDateTime* localtime() const {
- g_assert (localtime_ != nullptr);
- return g_date_time_ref(localtime_);
- }
+ DateTime localtime() const { return m_localtime; }
- void setLocaltime(GDateTime* dt) {
- g_clear_pointer(&localtime_, g_date_time_unref);
- localtime_ = g_date_time_ref(dt);
+ void set_localtime(const DateTime& dt) {
+ const auto old_day = m_localtime.day_of_year();
+ m_localtime = dt;
skewDetected();
+ const auto new_day = m_localtime.day_of_year();
+ if (old_day != new_day)
+ dateChanged();
}
private:
-
- GDateTime * localtime_ = nullptr;
+ DateTime m_localtime;
};
} // namespace datetime
diff --git a/include/datetime/clock.h b/include/datetime/clock.h
index 978be27..c8e6c16 100644
--- a/include/datetime/clock.h
+++ b/include/datetime/clock.h
@@ -20,12 +20,12 @@
#ifndef INDICATOR_DATETIME_CLOCK_H
#define INDICATOR_DATETIME_CLOCK_H
+#include <datetime/date-time.h>
#include <datetime/timezones.h>
#include <core/property.h>
#include <core/signal.h>
-#include <glib.h>
#include <gio/gio.h>
#include <set>
@@ -45,9 +45,10 @@ class Clock
{
public:
virtual ~Clock();
- virtual GDateTime* localtime() const = 0;
- core::Property<std::set<std::string> > timezones;
+ virtual DateTime localtime() const =0;
+ core::Property<std::set<std::string>> timezones;
core::Signal<> skewDetected;
+ core::Signal<> dateChanged;
protected:
Clock();
@@ -56,12 +57,13 @@ private:
static void onSystemBusReady(GObject*, GAsyncResult*, gpointer);
static void onPrepareForSleep(GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant*, gpointer);
+ GCancellable * m_cancellable = nullptr;
+ GDBusConnection * m_system_bus = nullptr;
+ unsigned int m_sleep_subscription_id = 0;
+
+ // we've got raw pointers in here, so disable copying
Clock(const Clock&) =delete;
Clock& operator=(const Clock&) =delete;
-
- GCancellable * cancellable_ = nullptr;
- GDBusConnection * system_bus_ = nullptr;
- unsigned int sleep_subscription_id_ = 0;
};
/***
@@ -71,16 +73,17 @@ private:
/**
* \brief A live clock that provides the actual system time.
*
- * Adds another clock skew detection test: wakes up every
- * skewTestIntervalSec seconds to see how much time has passed
- * since the last time it checked.
+ * This subclass also adds another clock skew detection test:
+ * it wakes up every skewTestIntervalSec seconds to see how
+ * much time has passed since the last wakeup. If the answer
+ * isn't what it expected, the skewDetected signal is triggered.
*/
class LiveClock: public Clock
{
public:
LiveClock (const std::shared_ptr<Timezones>& zones);
virtual ~LiveClock();
- virtual GDateTime* localtime() const;
+ virtual DateTime localtime() const;
core::Property<unsigned int> skewTestIntervalSec;
private:
diff --git a/include/datetime/date-time.h b/include/datetime/date-time.h
index bbcd00a..5b9421f 100644
--- a/include/datetime/date-time.h
+++ b/include/datetime/date-time.h
@@ -22,6 +22,7 @@
#include <glib.h> // GDateTime
+#include <ctime> // time_t
#include <memory> // std::shared_ptr
namespace unity {
@@ -29,61 +30,111 @@ namespace indicator {
namespace datetime {
/**
- * C++ wrapper class for GDateTime
+ * \brief A simple C++ wrapper for GDateTime to simplify ownership/refcounts
*/
class DateTime
{
public:
- GDateTime* get() const
- {
- return dt_.get();
+ explicit DateTime(GDateTime* in=nullptr) { reset(in); }
+
+ explicit DateTime(time_t t) { reset(g_date_time_new_from_unix_local(t)); }
+
+ static DateTime NowLocal() {
+ GDateTime * gdt = g_date_time_new_now_local();
+ DateTime dt(gdt);
+ g_date_time_unref(gdt);
+ return dt;
+ }
+
+ DateTime to_timezone(const std::string& zone) const {
+ auto gtz = g_time_zone_new(zone.c_str());
+ auto gdt = g_date_time_to_timezone(get(), gtz);
+ DateTime dt(gdt);
+ g_time_zone_unref(gtz);
+ g_date_time_unref(gdt);
+ return dt;
}
- GDateTime* operator()() const
- {
+
+ GDateTime* get() const {
+ g_assert(m_dt);
+ return m_dt.get();
+ }
+
+ GDateTime* operator()() const {
return get();
}
- void set (GDateTime* in) {
- auto deleter = [](GDateTime* dt){g_date_time_unref(dt);};
- dt_ = std::shared_ptr<GDateTime>(g_date_time_ref(in), deleter);
+
+ std::string format(const std::string& fmt) const {
+ auto str = g_date_time_format(get(), fmt.c_str());
+ std::string ret = str;
+ g_free(str);
+ return ret;
+ }
+
+ int day_of_month() const { return g_date_time_get_day_of_month(get()); }
+
+ int64_t to_unix() const { return g_date_time_to_unix(get()); }
+
+ int day_of_year() const { return m_dt ? g_date_time_get_day_of_year(get()) : -1; }
+
+ void reset(GDateTime* in=nullptr) {
+ if (in) {
+ auto deleter = [](GDateTime* dt){g_date_time_unref(dt);};
+ m_dt = std::shared_ptr<GDateTime>(g_date_time_ref(in), deleter);
+ g_assert(m_dt);
+ } else {
+ m_dt.reset();
+ }
}
- DateTime& operator=(GDateTime* in)
- {
- set (in);
+ DateTime& operator=(GDateTime* in) {
+ reset(in);
return *this;
}
- DateTime& operator=(const DateTime& in)
- {
- set (in.get());
+ DateTime& operator=(const DateTime& in) {
+ m_dt = in.m_dt;
return *this;
}
- bool operator<(const DateTime& that) const
- {
- return g_date_time_compare (get(), that.get()) < 0;
+ gint64 difference(const DateTime& that) const {
+ const auto dt = get();
+ const auto tdt = that.get();
+
+ gint64 ret;
+ if (dt && tdt)
+ ret = g_date_time_difference(dt, tdt);
+ else if (dt)
+ ret = to_unix();
+ else if (tdt)
+ ret = that.to_unix();
+ else
+ ret = 0;
+ return ret;
+ }
+
+ bool operator<(const DateTime& that) const {
+ return g_date_time_compare(get(), that.get()) < 0;
}
- bool operator!=(const DateTime& that) const
- {
- return !(*this == that);
+ bool operator!=(const DateTime& that) const {
+ // return true if this isn't set, or if it's not equal
+ return (!m_dt) || !(*this == that);
}
- bool operator==(const DateTime& that) const
- {
+ bool operator==(const DateTime& that) const {
GDateTime * dt = get();
GDateTime * tdt = that.get();
if (!dt && !tdt) return true;
if (!dt || !tdt) return false;
- return g_date_time_compare (get(), that.get()) == 0;
+ return g_date_time_compare(get(), that.get()) == 0;
}
private:
-
- std::shared_ptr<GDateTime> dt_;
+ std::shared_ptr<GDateTime> m_dt;
};
} // namespace datetime
diff --git a/include/datetime/dbus-shared.h b/include/datetime/dbus-shared.h
index 24319e3..c5ff6ab 100644
--- a/include/datetime/dbus-shared.h
+++ b/include/datetime/dbus-shared.h
@@ -1,24 +1,25 @@
/*
-An indicator to show date and time information.
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Ted Gould <ted@canonical.com>
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
-Copyright 2010 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@canonical.com>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
#define BUS_NAME "com.canonical.indicator.datetime"
+
#define BUS_PATH "/com/canonical/indicator/datetime"
diff --git a/include/datetime/formatter.h b/include/datetime/formatter.h
index 66dc212..09ed035 100644
--- a/include/datetime/formatter.h
+++ b/include/datetime/formatter.h
@@ -37,7 +37,26 @@ class DateTime;
***/
/**
- * \brief Provides the right time format strings based on the profile and user's settings
+ * \brief Provide the strftime() format strings
+ *
+ * This mission's been moved out into its own class because there are
+ * a lot of options and edge cases:
+ *
+ * - The default time format can change based on the locale.
+ *
+ * - The user's settings can change or completely override the format string.
+ *
+ * - The time formats are different on the Phone and Desktop profiles.
+ *
+ * - The time format string in the Locations' menuitems uses (mostly)
+ * the same time format as the header, except for some changes.
+ *
+ * - The 'current time' format string in the Locations' menuitems also
+ * prepends the string 'Yesterday' or 'Today' if it differs from the
+ * local time, so Formatter needs to have a Clock for its state.
+ *
+ * So the Formatter monitors system settings, the current timezone, etc.
+ * and upate its time format properties appropriately.
*/
class Formatter
{
@@ -51,7 +70,8 @@ public:
/** \brief Signal to denote when the relativeFormat has changed.
When this is emitted, clients will want to rebuild their
- menuitems that contain relative time strings */
+ menuitems that contain relative time strings
+ (ie, the Appointments and Locations menuitems) */
core::Signal<> relativeFormatChanged;
/** \brief Generate a relative time format for some time (or time range)
@@ -60,19 +80,18 @@ public:
std::string getRelativeFormat(GDateTime* then, GDateTime* then_end=nullptr) const;
protected:
-
Formatter(const std::shared_ptr<Clock>&);
virtual ~Formatter();
/** \brief Returns true if the current locale prefers 12h display instead of 24h */
static bool is_locale_12h();
- static const char * getDefaultHeaderTimeFormat(bool twelvehour, bool show_seconds);
+ static const char* getDefaultHeaderTimeFormat(bool twelvehour, bool show_seconds);
/** \brief Translate the string based on LC_TIME instead of LC_MESSAGES.
The intent of this is to let users set LC_TIME to override
their other locale settings when generating time format string */
- static const char * T_(const char * fmt);
+ static const char* T_(const char * fmt);
private:
diff --git a/include/datetime/locations-settings.h b/include/datetime/locations-settings.h
index d343fe3..eaabf73 100644
--- a/include/datetime/locations-settings.h
+++ b/include/datetime/locations-settings.h
@@ -32,8 +32,8 @@ namespace datetime {
class Timezones;
/**
- * \brief An ordered list of Location objects found from
- * the system timezone and from the user's GSettings
+ * \brief Settings implentation which builds its list from the
+ * user's GSettings and from the Timezones passed in the ctor.
*/
class SettingsLocations: public Locations
{
@@ -42,11 +42,12 @@ public:
* @param[in] schemaId the settings schema to load
* @param[in] timezones the timezones to always show first in the list
*/
- SettingsLocations (const std::string& schemaId, const std::shared_ptr<Timezones>& timezones);
+ SettingsLocations (const std::string& schemaId,
+ const std::shared_ptr<Timezones>& timezones);
protected:
- std::unique_ptr<GSettings,std::function<void(GSettings*)>> settings_;
- std::shared_ptr<Timezones> timezones_;
+ std::unique_ptr<GSettings,std::function<void(GSettings*)>> m_settings;
+ std::shared_ptr<Timezones> m_timezones;
private:
static void onSettingsChanged (gpointer gself);
diff --git a/include/datetime/locations.h b/include/datetime/locations.h
index a06d1cc..ee67615 100644
--- a/include/datetime/locations.h
+++ b/include/datetime/locations.h
@@ -20,6 +20,8 @@
#ifndef INDICATOR_DATETIME_LOCATIONS_H
#define INDICATOR_DATETIME_LOCATIONS_H
+#include <datetime/date-time.h>
+
#include <core/property.h>
#include <string>
@@ -31,28 +33,42 @@ namespace datetime {
/**
* \brief A physical place and its timezone; eg, "America/Chicago" + "Oklahoma City"
+ *
+ * @see Locations
*/
-struct Location
+class Location
{
- /** timezone; eg, "America/Chicago" */
- std::string zone;
-
- /* human-readable location name; eg, "Oklahoma City" */
- std::string name;
+public:
+ const std::string& zone() const { return m_zone; }
- /** offset from UTC in microseconds */
- int64_t offset = 0;
+ const std::string& name() const { return m_name; }
bool operator== (const Location& that) const
{
- return (name == that.name) && (zone == that.zone) && (offset == that.offset);
+ return (name() == that.name()) &&
+ (zone() == that.zone()) &&
+ (m_offset == that.m_offset);
}
Location (const std::string& zone, const std::string& name);
+
+private:
+
+ /** timezone; eg, "America/Chicago" */
+ std::string m_zone;
+
+ /* human-readable location name; eg, "Oklahoma City" */
+ std::string m_name;
+
+ /** offset from UTC in microseconds */
+ int64_t m_offset = 0;
};
/**
- * A container for an ordered list of Locations.
+ * Container which holds an ordered list of Locations
+ *
+ * @see Location
+ * @see State
*/
class Locations
{
@@ -61,7 +77,7 @@ public:
virtual ~Locations() =default;
/** \brief an ordered list of Location items */
- core::Property<std::vector<Location> > locations;
+ core::Property<std::vector<Location>> locations;
};
} // namespace datetime
diff --git a/include/datetime/menu.h b/include/datetime/menu.h
new file mode 100644
index 0000000..0bc3781
--- /dev/null
+++ b/include/datetime/menu.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#ifndef INDICATOR_DATETIME_MENU_H
+#define INDICATOR_DATETIME_MENU_H
+
+#include <datetime/actions.h>
+#include <datetime/state.h>
+
+#include <memory> // std::shared_ptr
+#include <vector>
+
+#include <gio/gio.h> // GMenuModel
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/**
+ * \brief A menu for a specific profile; eg, Desktop or Phone.
+ *
+ * @see MenuFactory
+ */
+class Menu
+{
+public:
+ enum Profile { Desktop, DesktopGreeter, Phone, PhoneGreeter, NUM_PROFILES };
+ enum Section { Calendar, Appointments, Locations, Settings, NUM_SECTIONS };
+ const std::string& name() const { return m_name; }
+ Profile profile() const { return m_profile; }
+ GMenuModel* menu_model() { return G_MENU_MODEL(m_menu); }
+
+protected:
+ Menu (Profile profile_in, const std::string& name_in): m_profile(profile_in), m_name(name_in) {}
+ virtual ~Menu() =default;
+ GMenu* m_menu = nullptr;
+
+private:
+ const Profile m_profile;
+ const std::string m_name;
+
+ // we've got raw pointers in here, so disable copying
+ Menu(const Menu&) =delete;
+ Menu& operator=(const Menu&) =delete;
+};
+
+/**
+ * \brief Builds a Menu for a given state and profile
+ */
+class MenuFactory
+{
+public:
+ MenuFactory (std::shared_ptr<Actions>& actions, std::shared_ptr<State>& state);
+ std::shared_ptr<Menu> buildMenu(Menu::Profile profile);
+ std::shared_ptr<State> state() { return m_state; }
+
+private:
+ std::shared_ptr<Actions> m_actions;
+ std::shared_ptr<State> m_state;
+};
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
+#endif // INDICATOR_DATETIME_MENU_H
diff --git a/include/datetime/planner-eds.h b/include/datetime/planner-eds.h
index 43f222e..f3abce0 100644
--- a/include/datetime/planner-eds.h
+++ b/include/datetime/planner-eds.h
@@ -39,7 +39,7 @@ public:
private:
class Impl;
- std::unique_ptr<Impl> impl_;
+ std::unique_ptr<Impl> p;
};
} // namespace datetime
diff --git a/include/datetime/planner-mock.h b/include/datetime/planner-mock.h
new file mode 100644
index 0000000..bb3ff53
--- /dev/null
+++ b/include/datetime/planner-mock.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#ifndef INDICATOR_DATETIME_PLANNER_MOCK_H
+#define INDICATOR_DATETIME_PLANNER_MOCK_H
+
+#include <datetime/planner.h>
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/**
+ * \brief Planner which does nothing on its own and requires
+ * its client to set its appointments property.
+ */
+class MockPlanner: public Planner
+{
+public:
+ MockPlanner() =default;
+ virtual ~MockPlanner() =default;
+};
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
+#endif // INDICATOR_DATETIME_PLANNER_MOCK_H
diff --git a/include/datetime/planner.h b/include/datetime/planner.h
index 4d27a2b..198b6fa 100644
--- a/include/datetime/planner.h
+++ b/include/datetime/planner.h
@@ -33,6 +33,9 @@ namespace datetime {
/**
* \brief Simple appointment book
+ *
+ * @see EdsPlanner
+ * @see State
*/
class Planner
{
diff --git a/include/datetime/service.h b/include/datetime/service.h
new file mode 100644
index 0000000..c7171b7
--- /dev/null
+++ b/include/datetime/service.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#ifndef INDICATOR_DATETIME_EXPORTER_H
+#define INDICATOR_DATETIME_EXPORTER_H
+
+#include <datetime/menu.h>
+
+#include <core/signal.h>
+
+#include <gio/gio.h> // GActionGroup
+
+#include <memory> // std::shared_ptr
+#include <vector>
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/**
+ * \brief Exports actions and menus to DBus.
+ */
+class Service
+{
+public:
+ Service() =default;
+ ~Service();
+
+ core::Signal<> name_lost;
+
+ void publish (GActionGroup* actions, std::vector<std::shared_ptr<Menu>>& menus);
+
+private:
+ static void on_bus_acquired(GDBusConnection*, const gchar *name, gpointer gthis);
+ void on_bus_acquired(GDBusConnection*, const gchar *name);
+
+ static void on_name_lost(GDBusConnection*, const gchar *name, gpointer gthis);
+ void on_name_lost(GDBusConnection*, const gchar *name);
+
+ std::set<guint> m_exported_menu_ids;
+ guint m_own_id = 0;
+ guint m_exported_actions_id = 0;
+ GDBusConnection * m_dbus_connection = nullptr;
+ GActionGroup* m_actions = nullptr;
+ std::vector<std::shared_ptr<Menu>> m_menus;
+
+ // we've got raw pointers and gsignal tags in here, so disable copying
+ Service(const Service&) =delete;
+ Service& operator=(const Service&) =delete;
+};
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
+#endif // INDICATOR_DATETIME_EXPORTER_H
diff --git a/include/datetime/settings-live.h b/include/datetime/settings-live.h
new file mode 100644
index 0000000..44e27b0
--- /dev/null
+++ b/include/datetime/settings-live.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#ifndef INDICATOR_DATETIME_SETTINGS_LIVE_H
+#define INDICATOR_DATETIME_SETTINGS_LIVE_H
+
+#include <datetime/settings.h> // parent class
+
+#include <gio/gio.h> // GSettings
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/**
+ * \brief #Settings implementation which uses GSettings.
+ */
+class LiveSettings: public Settings
+{
+public:
+ LiveSettings();
+ virtual ~LiveSettings();
+
+private:
+ void update_show_clock();
+
+ void update_key(const std::string& key);
+ static void on_changed(GSettings*, gchar*, gpointer);
+
+ GSettings* m_settings;
+
+ // we've got a raw pointer here, so disable copying
+ LiveSettings(const LiveSettings&) =delete;
+ LiveSettings& operator=(const LiveSettings&) =delete;
+};
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
+#endif // INDICATOR_DATETIME_SETTINGS_LIVE_H
diff --git a/include/datetime/settings-shared.h b/include/datetime/settings-shared.h
index 896db95..17a8ef0 100644
--- a/include/datetime/settings-shared.h
+++ b/include/datetime/settings-shared.h
@@ -18,8 +18,8 @@
* Charles Kerr <charles.kerr@canonical.com>
*/
-#ifndef __DATETIME_SETTINGS_SHARED_H__
-#define __DATETIME_SETTINGS_SHARED_H__
+#ifndef INDICATOR_DATETIME_SETTINGS_SHARED
+#define INDICATOR_DATETIME_SETTINGS_SHARED
typedef enum
{
@@ -46,4 +46,4 @@ TimeFormatMode;
#define SETTINGS_LOCATIONS_S "locations"
#define SETTINGS_TIMEZONE_NAME_S "timezone-name"
-#endif /* __DATETIME_SETTINGS_SHARED_H__ */
+#endif // INDICATOR_DATETIME_SETTINGS_SHARED
diff --git a/include/datetime/settings.h b/include/datetime/settings.h
new file mode 100644
index 0000000..3d4bc33
--- /dev/null
+++ b/include/datetime/settings.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#ifndef INDICATOR_DATETIME_SETTINGS_H
+#define INDICATOR_DATETIME_SETTINGS_H
+
+#include <datetime/settings-shared.h>
+
+#include <core/property.h>
+
+#include <vector>
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/**
+ * \brief Interface that represents user-configurable settings.
+ *
+ * See the descriptions in data/com.canonical.indicator.datetime.gschema.xml
+ * For more information.
+ */
+class Settings
+{
+public:
+ Settings() =default;
+ virtual ~Settings() =default;
+
+ core::Property<TimeFormatMode> time_format_mode;
+ core::Property<bool> show_clock;
+ core::Property<bool> show_day;
+ core::Property<bool> show_year;
+ core::Property<bool> show_seconds;
+ core::Property<std::string> custom_time_format;
+ core::Property<bool> show_calendar;
+ core::Property<bool> show_events;
+ core::Property<bool> show_locations;
+ core::Property<bool> show_auto_detected_location;
+ core::Property<std::vector<std::string>> locations;
+ core::Property<std::string> timezone_name;
+};
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
+#endif // INDICATOR_DATETIME_SETTINGS_H
diff --git a/include/datetime/state.h b/include/datetime/state.h
new file mode 100644
index 0000000..a82bb4b
--- /dev/null
+++ b/include/datetime/state.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#ifndef INDICATOR_DATETIME_STATE_H
+#define INDICATOR_DATETIME_STATE_H
+
+#include <datetime/clock.h>
+#include <datetime/timezones.h>
+#include <datetime/planner.h>
+#include <datetime/locations.h>
+
+#include <core/property.h>
+
+#include <memory> // std::shared_ptr
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/**
+ * \brief Aggregates all the classes that represent the backend state.
+ *
+ * This is where the app comes together. It's a model that aggregates
+ * all of the backend appointments/alarms, locations, timezones,
+ * system time, and so on. The "view" code (ie, the Menus) need to
+ * respond to Signals from the State and update themselves accordingly.
+ *
+ * @see Menu
+ * @see MenuFactory
+ * @see Timezones
+ * @see Clock
+ * @see Planner
+ * @see Locations
+ */
+struct State
+{
+ std::shared_ptr<Timezones> timezones;
+ std::shared_ptr<Clock> clock;
+ std::shared_ptr<Planner> planner;
+ std::shared_ptr<Locations> locations;
+
+ core::Property<bool> show_events;
+ core::Property<bool> show_clock;
+ core::Property<DateTime> calendar_day;
+ core::Property<bool> show_week_numbers;
+};
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
+#endif // INDICATOR_DATETIME_STATE_H
diff --git a/include/datetime/timezone-file.h b/include/datetime/timezone-file.h
index 39a3d83..7f47df6 100644
--- a/include/datetime/timezone-file.h
+++ b/include/datetime/timezone-file.h
@@ -43,15 +43,18 @@ public:
private:
void setFilename(const std::string& filename);
- void clear();
static void onFileChanged(gpointer gself);
+ void clear();
void reload();
- std::string filename_;
- GFileMonitor * monitor_ = nullptr;
- unsigned long monitor_handler_id_ = 0;
-};
+ std::string m_filename;
+ GFileMonitor * m_monitor = nullptr;
+ unsigned long m_monitor_handler_id = 0;
+ // we have raw pointers and glib tags in here, so disable copying
+ FileTimezone(const FileTimezone&) =delete;
+ FileTimezone& operator=(const FileTimezone&) =delete;
+};
} // namespace datetime
} // namespace indicator
diff --git a/include/datetime/timezone-geoclue.h b/include/datetime/timezone-geoclue.h
index 382b3cc..4a5b726 100644
--- a/include/datetime/timezone-geoclue.h
+++ b/include/datetime/timezone-geoclue.h
@@ -50,10 +50,14 @@ private:
void setTimezoneFromAddressVariant (GVariant*);
static GVariant * call_finish (GObject*, GAsyncResult*);
- GCancellable * cancellable_ = nullptr;
- GDBusConnection * connection_ = nullptr;
- std::string client_object_path_;
- guint signal_subscription_ = 0;
+ GCancellable * m_cancellable = nullptr;
+ GDBusConnection * m_connection = nullptr;
+ std::string m_client_object_path;
+ guint m_signal_subscription = 0;
+
+ // we've got pointers and gsignal tags in here, so don't allow copying
+ GeoclueTimezone(const GeoclueTimezone&) =delete;
+ GeoclueTimezone& operator=(const GeoclueTimezone&) =delete;
};
diff --git a/include/datetime/timezone.h b/include/datetime/timezone.h
index 218e219..ffa5a84 100644
--- a/include/datetime/timezone.h
+++ b/include/datetime/timezone.h
@@ -28,11 +28,11 @@ namespace unity {
namespace indicator {
namespace datetime {
-/** \brief Base class for objects that use various means to detect the system's timezone */
+/** \brief Base a timezone, such as "America/Chicago". */
class Timezone
{
protected:
- Timezone() {}
+ Timezone() =default;
public:
//virtual ~Timezone() {}
diff --git a/include/datetime/timezones-live.h b/include/datetime/timezones-live.h
index 3075bd8..5f2cb3e 100644
--- a/include/datetime/timezones-live.h
+++ b/include/datetime/timezones-live.h
@@ -31,7 +31,7 @@ namespace indicator {
namespace datetime {
/**
- * \brief Timezones object that uses a #FileTimezone and #GeoclueTimezone
+ * \brief #Timezones object that uses a #FileTimezone and #GeoclueTimezone
* to detect what timezone we're in
*/
class LiveTimezones: public Timezones
@@ -40,13 +40,14 @@ public:
LiveTimezones(const std::string& filename);
/** \brief Whether or not to track location by IP address */
- core::Property<bool> geolocationEnabled = core::Property<bool>(false);
+ core::Property<bool> geolocation_enabled = core::Property<bool>(false);
private:
- FileTimezone file_;
- std::shared_ptr<GeoclueTimezone> geo_;
- void updateGeolocation();
- void updateTimezones();
+ void update_geolocation();
+ void update_timezones();
+
+ FileTimezone m_file;
+ std::shared_ptr<GeoclueTimezone> m_geo;
};
} // namespace datetime
diff --git a/include/datetime/timezones.h b/include/datetime/timezones.h
index 0b97683..10c4e97 100644
--- a/include/datetime/timezones.h
+++ b/include/datetime/timezones.h
@@ -28,13 +28,11 @@ namespace unity {
namespace indicator {
namespace datetime {
-/** \brief Aggregates one or more timezone detectors and decides which to use */
+/** \brief Aggregates one or more timezone detectors and decides which to give precedence to */
class Timezones
{
public:
-
Timezones() =default;
-
virtual ~Timezones() =default;
/**
diff --git a/include/datetime/utils.h b/include/datetime/utils.h
index bd2e132..fbc80d7 100644
--- a/include/datetime/utils.h
+++ b/include/datetime/utils.h
@@ -20,8 +20,8 @@ You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __DATETIME_UTILS_H__
-#define __DATETIME_UTILS_H__
+#ifndef INDICATOR_DATETIME_UTILS_H
+#define INDICATOR_DATETIME_UTILS_H
#include <glib.h>
#include <gio/gio.h> /* GSettings */
@@ -37,31 +37,9 @@ void split_settings_location (const char * location,
gchar * get_current_zone_name (const char * location,
GSettings * settings);
-#if 0
-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_terse_header_time_format_string (void);
-
-const gchar * get_full_time_format_string (GSettings * settings);
-
-gchar * generate_terse_format_string_at_time (GDateTime * now,
- GDateTime * time);
-
-gchar * generate_full_format_string (gboolean show_day,
- gboolean show_date,
- gboolean show_year,
- GSettings * settings);
-#endif
-
gchar * generate_full_format_string_at_time (GDateTime * now,
GDateTime * time);
G_END_DECLS
-#endif
+#endif /* INDICATOR_DATETIME_UTILS_H */
diff --git a/panel/CMakeLists.txt b/panel/CMakeLists.txt
index 4ac3289..c165326 100644
--- a/panel/CMakeLists.txt
+++ b/panel/CMakeLists.txt
@@ -2,6 +2,8 @@ set (PANEL_LIB "indicator-datetime")
add_definitions (-DPKGDATADIR="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}")
+SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g ${CXX_WARNING_ARGS}")
+
add_library (${PANEL_LIB} SHARED
datetime-prefs.c
datetime-prefs-locations.c
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2c847ff..976adc3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -12,13 +12,18 @@ if (BUILD_PANEL)
endif ()
add_library (${SERVICE_LIB} STATIC
+ actions.cpp
+ actions-live.cpp
clock.cpp
clock-live.cpp
formatter.cpp
formatter-desktop.cpp
locations.cpp
locations-settings.cpp
+ menu.cpp
planner-eds.cpp
+ service.cpp
+ settings-live.cpp
timezone-file.cpp
timezone-geoclue.cpp
timezones-live.cpp
@@ -27,9 +32,9 @@ include_directories (${CMAKE_SOURCE_DIR})
link_directories (${SERVICE_DEPS_LIBRARY_DIRS})
-#add_executable (${SERVICE_EXEC} main.c)
-#target_link_libraries (${SERVICE_EXEC} ${SERVICE_LIB} ${SERVICE_DEPS_LIBRARIES} ${GCOV_LIBS})
-#install (TARGETS ${SERVICE_EXEC} RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR})
+add_executable (${SERVICE_EXEC} main.cpp)
+target_link_libraries (${SERVICE_EXEC} ${SERVICE_LIB} ${SERVICE_DEPS_LIBRARIES} ${GCOV_LIBS})
+install (TARGETS ${SERVICE_EXEC} RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR})
# common properties
#set_property (TARGET ${SERVICE_LIB} ${SERVICE_EXEC}
diff --git a/src/actions-live.cpp b/src/actions-live.cpp
new file mode 100644
index 0000000..08e1466
--- /dev/null
+++ b/src/actions-live.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#include <datetime/actions-live.h>
+
+#include <glib.h>
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/***
+****
+***/
+
+void LiveActions::open_desktop_settings()
+{
+ g_message ("%s", G_STRFUNC);
+}
+
+void LiveActions::open_phone_settings()
+{
+ g_message("%s", G_STRFUNC);
+}
+
+void LiveActions::open_phone_clock()
+{
+ g_message("%s", G_STRFUNC);
+}
+
+void LiveActions::open_phone_planner()
+{
+ g_message("%s", G_STRFUNC);
+}
+
+void LiveActions::open_planner_at(const DateTime&)
+{
+ g_message("%s", G_STRFUNC);
+}
+
+void LiveActions::open_calendar_at(const DateTime&)
+{
+ g_message("%s", G_STRFUNC);
+}
+
+void LiveActions::open_appointment(const std::string& uid)
+{
+ g_message("%s - %s", G_STRFUNC, uid.c_str());
+}
+
+void LiveActions::set_location(const std::string& zone, const std::string& name)
+{
+ g_message("%s - %s %s", G_STRFUNC, zone.c_str(), name.c_str());
+}
+
+void LiveActions::set_calendar_date(const DateTime&)
+{
+ g_message("%s", G_STRFUNC);
+}
+
+
+/***
+****
+***/
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
diff --git a/src/actions.cpp b/src/actions.cpp
new file mode 100644
index 0000000..4efe950
--- /dev/null
+++ b/src/actions.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#include <datetime/actions.h>
+#include <datetime/utils.h> // split_settings_location()
+
+#include <glib.h>
+#include <gio/gio.h>
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/***
+****
+***/
+
+namespace
+{
+
+void on_desktop_settings_activated(GSimpleAction * /*action*/,
+ GVariant * /*param*/,
+ gpointer gself)
+{
+ static_cast<Actions*>(gself)->open_desktop_settings();
+}
+
+void on_phone_settings_activated(GSimpleAction * /*action*/,
+ GVariant * /*param*/,
+ gpointer gself)
+{
+ static_cast<Actions*>(gself)->open_phone_settings();
+}
+
+void on_phone_clock_activated(GSimpleAction * /*action*/,
+ GVariant * /*param*/,
+ gpointer gself)
+{
+ static_cast<Actions*>(gself)->open_phone_clock_app();
+}
+
+void on_activate_appointment(GSimpleAction * /*action*/,
+ GVariant * param,
+ gpointer gself)
+{
+ const auto uid = g_variant_get_string(param, nullptr);
+ auto self = static_cast<Actions*>(gself);
+
+ g_return_if_fail(uid && *uid);
+
+ // find url of the upcoming appointment with this uid
+ for (auto& appt : self->state()->planner->upcoming.get())
+ {
+ if (appt.uid == uid)
+ {
+ const auto url = appt.url;
+ g_debug("%s: uid[%s] -> url[%s]", G_STRFUNC, uid, url.c_str());
+ self->open_appointment(url);
+ break;
+ }
+ }
+}
+
+void on_activate_planner(GSimpleAction * /*action*/,
+ GVariant * param,
+ gpointer gself)
+{
+ const auto at = g_variant_get_int64(param);
+ auto self = static_cast<Actions*>(gself);
+
+ if (at)
+ {
+ auto gdt = g_date_time_new_from_unix_local(at);
+ self->open_planner_at(DateTime(gdt));
+ g_date_time_unref(gdt);
+ }
+ else // no time specified...
+ {
+ self->open_planner();
+ }
+}
+
+void on_set_location(GSimpleAction * /*action*/,
+ GVariant * param,
+ gpointer gself)
+{
+ char * zone;
+ char * name;
+ split_settings_location(g_variant_get_string(param, nullptr), &zone, &name);
+ static_cast<Actions*>(gself)->set_location(zone, name);
+ g_free(name);
+ g_free(zone);
+}
+
+static void on_calendar_activated(GSimpleAction * /*action*/,
+ GVariant * state,
+ gpointer gself)
+{
+ const time_t t = g_variant_get_int64(state);
+
+ g_return_if_fail(t != 0);
+
+ static_cast<Actions*>(gself)->set_calendar_date(DateTime(t));
+}
+
+GVariant* create_default_header_state()
+{
+ GVariantBuilder b;
+ g_variant_builder_init(&b, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add(&b, "{sv}", "accessible-desc", g_variant_new_string("accessible-desc"));
+ g_variant_builder_add(&b, "{sv}", "label", g_variant_new_string("label"));
+ g_variant_builder_add(&b, "{sv}", "title", g_variant_new_string("title"));
+ g_variant_builder_add(&b, "{sv}", "visible", g_variant_new_boolean(true));
+ return g_variant_builder_end(&b);
+}
+
+GVariant* create_calendar_state(std::shared_ptr<State>& state)
+{
+ gboolean days[32] = { 0 };
+ for(const auto& appt : state->planner->thisMonth.get())
+ days[appt.begin.day_of_month()] = true;
+
+ GVariantBuilder day_builder;
+ g_variant_builder_init(&day_builder, G_VARIANT_TYPE("ai"));
+ for (int i=0; i<G_N_ELEMENTS(days); i++)
+ if (days[i])
+ g_variant_builder_add(&day_builder, "i", i);
+
+ GVariantBuilder dict_builder;
+ g_variant_builder_init(&dict_builder, G_VARIANT_TYPE_DICTIONARY);
+
+ auto key = "appointment-days";
+ auto v = g_variant_builder_end(&day_builder);
+ g_variant_builder_add(&dict_builder, "{sv}", key, v);
+
+ key = "calendar-day";
+ v = g_variant_new_int64(state->calendar_day.get().to_unix());
+ g_variant_builder_add(&dict_builder, "{sv}", key, v);
+
+ key = "show-week-numbers";
+ v = g_variant_new_boolean(state->show_week_numbers.get());
+ g_variant_builder_add(&dict_builder, "{sv}", key, v);
+
+ return g_variant_builder_end(&dict_builder);
+}
+} // anonymous namespace
+
+/***
+****
+***/
+
+Actions::Actions(std::shared_ptr<State>& state):
+ m_state(state),
+ m_actions(g_simple_action_group_new())
+{
+ GActionEntry entries[] = {
+ { "activate-desktop-settings", on_desktop_settings_activated },
+ { "activate-phone-settings", on_phone_settings_activated },
+ { "activate-phone-clock-app", on_phone_clock_activated },
+ { "activate-appointment", on_activate_appointment, "s", nullptr },
+ { "activate-planner", on_activate_planner, "x", nullptr },
+ { "set-location", on_set_location, "s" }
+ };
+
+ g_action_map_add_action_entries(G_ACTION_MAP(m_actions),
+ entries,
+ G_N_ELEMENTS(entries),
+ this);
+
+ // add the header actions
+ auto gam = G_ACTION_MAP(m_actions);
+ auto v = create_default_header_state();
+ auto a = g_simple_action_new_stateful("desktop-header", nullptr, v);
+ g_action_map_add_action(gam, G_ACTION(a));
+ a = g_simple_action_new_stateful("desktop-greeter-header", nullptr, v);
+ g_action_map_add_action(gam, G_ACTION(a));
+ a = g_simple_action_new_stateful("phone-header", nullptr, v);
+ g_action_map_add_action(gam, G_ACTION(a));
+ a = g_simple_action_new_stateful("phone-greeter-header", nullptr, v);
+ g_action_map_add_action(gam, G_ACTION(a));
+
+ // add the calendar action
+ v = create_calendar_state(state);
+ a = g_simple_action_new_stateful("calendar", G_VARIANT_TYPE_INT64, v);
+ g_action_map_add_action(gam, G_ACTION(a));
+ g_signal_connect(a, "activate", G_CALLBACK(on_calendar_activated), this);
+ //m_calendar_action = a;
+
+ // FIXME: rebuild the calendar state when show-week-number changes
+}
+
+Actions::~Actions()
+{
+ g_clear_object(&m_actions);
+}
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
diff --git a/src/clock-live.cpp b/src/clock-live.cpp
index 80e91a3..1fadfe8 100644
--- a/src/clock-live.cpp
+++ b/src/clock-live.cpp
@@ -28,53 +28,56 @@ class LiveClock::Impl
public:
Impl(LiveClock& owner, const std::shared_ptr<Timezones>& tzd):
- owner_(owner),
- timezones_(tzd)
+ m_owner(owner),
+ m_timezones(tzd)
{
- if (timezones_)
+ if (m_timezones)
{
- timezones_->timezone.changed().connect ([this](const std::string& z) {setTimezone(z);});
- setTimezone(timezones_->timezone.get());
+ m_timezones->timezone.changed().connect([this](const std::string& z) {setTimezone(z);});
+ setTimezone(m_timezones->timezone.get());
}
- owner_.skewTestIntervalSec.changed().connect([this](unsigned int intervalSec) {setInterval(intervalSec);});
- setInterval(owner_.skewTestIntervalSec.get());
+ m_owner.skewTestIntervalSec.changed().connect([this](unsigned int intervalSec) {setInterval(intervalSec);});
+ setInterval(m_owner.skewTestIntervalSec.get());
}
~Impl()
{
clearTimer();
- g_clear_pointer (&timezone_, g_time_zone_unref);
+ g_clear_pointer(&m_timezone, g_time_zone_unref);
}
- GDateTime* localtime() const
+ DateTime localtime() const
{
- g_assert (timezone_ != nullptr);
+ g_assert(m_timezone != nullptr);
- return g_date_time_new_now (timezone_);
+ auto gdt = g_date_time_new_now(m_timezone);
+ DateTime ret(gdt);
+ g_date_time_unref(gdt);
+ return ret;
}
private:
- void setTimezone (const std::string& str)
+ void setTimezone(const std::string& str)
{
- g_clear_pointer (&timezone_, g_time_zone_unref);
- timezone_= g_time_zone_new (str.c_str());
- owner_.skewDetected();
+ g_clear_pointer(&m_timezone, g_time_zone_unref);
+ m_timezone= g_time_zone_new(str.c_str());
+ m_owner.skewDetected();
}
private:
void clearTimer()
{
- if (skew_timeout_id_)
+ if (m_skew_timeout_id)
{
- g_source_remove(skew_timeout_id_);
- skew_timeout_id_ = 0;
+ g_source_remove(m_skew_timeout_id);
+ m_skew_timeout_id = 0;
}
- g_clear_pointer(&prev_datetime_, g_date_time_unref);
+ m_prev_datetime.reset();
}
void setInterval(unsigned int seconds)
@@ -83,50 +86,53 @@ private:
if (seconds > 0)
{
- prev_datetime_ = owner_.localtime();
- skew_timeout_id_ = g_timeout_add_seconds(seconds, onTimerPulse, this);
+ m_prev_datetime = localtime();
+ m_skew_timeout_id = g_timeout_add_seconds(seconds, onTimerPulse, this);
}
}
static gboolean onTimerPulse(gpointer gself)
{
- auto self = static_cast<Impl*>(gself);
+ static_cast<Impl*>(gself)->onTimerPulse();
+ return G_SOURCE_CONTINUE;
+ }
+ void onTimerPulse()
+ {
// check to see if too much time passed since the last check */
- GDateTime * now = self->owner_.localtime();
- const GTimeSpan diff = g_date_time_difference(now, self->prev_datetime_);
+ const auto now = localtime();
+ const auto diff = now.difference (m_prev_datetime);
const GTimeSpan fuzz = 5;
- const GTimeSpan max = (self->owner_.skewTestIntervalSec.get() + fuzz) * G_USEC_PER_SEC;
+ const GTimeSpan max = (m_owner.skewTestIntervalSec.get() + fuzz) * G_USEC_PER_SEC;
if (abs(diff) > max)
- self->owner_.skewDetected();
+ m_owner.skewDetected();
- // update prev_datetime
- g_clear_pointer(&self->prev_datetime_, g_date_time_unref);
- self->prev_datetime_ = now;
+ // check to see if the day has changed
+ if (now.day_of_year() != m_prev_datetime.day_of_year())
+ m_owner.dateChanged();
- return G_SOURCE_CONTINUE;
+ // update m_prev_datetime
+ m_prev_datetime = now;
}
protected:
- LiveClock& owner_;
- GTimeZone * timezone_ = nullptr;
- std::shared_ptr<Timezones> timezones_;
+ LiveClock& m_owner;
+ GTimeZone * m_timezone = nullptr;
+ std::shared_ptr<Timezones> m_timezones;
- GDateTime * prev_datetime_ = nullptr;
- unsigned int skew_timeout_id_ = 0;
- unsigned int sleep_subscription_id_ = 0;
+ DateTime m_prev_datetime;
+ unsigned int m_skew_timeout_id = 0;
};
LiveClock::LiveClock(const std::shared_ptr<Timezones>& tzd):
- p (new Impl (*this, tzd))
+ p(new Impl(*this, tzd))
{
}
LiveClock::~LiveClock() =default;
-GDateTime *
-LiveClock::localtime() const
+DateTime LiveClock::localtime() const
{
return p->localtime();
}
diff --git a/src/clock.cpp b/src/clock.cpp
index 4a75ceb..f3f5d70 100644
--- a/src/clock.cpp
+++ b/src/clock.cpp
@@ -31,9 +31,9 @@ namespace datetime {
***/
Clock::Clock():
- cancellable_(g_cancellable_new())
+ m_cancellable(g_cancellable_new())
{
- g_bus_get(G_BUS_TYPE_SYSTEM, cancellable_, onSystemBusReady, this);
+ g_bus_get(G_BUS_TYPE_SYSTEM, m_cancellable, onSystemBusReady, this);
timezones.changed().connect([this](const std::set<std::string>& timezones){
g_message ("timezones changed... new count is %d", (int)timezones.size());
@@ -43,13 +43,13 @@ Clock::Clock():
Clock::~Clock()
{
- g_cancellable_cancel(cancellable_);
- g_clear_object(&cancellable_);
+ g_cancellable_cancel(m_cancellable);
+ g_clear_object(&m_cancellable);
- if (sleep_subscription_id_)
- g_dbus_connection_signal_unsubscribe(system_bus_ , sleep_subscription_id_);
+ if (m_sleep_subscription_id)
+ g_dbus_connection_signal_unsubscribe(m_system_bus, m_sleep_subscription_id);
- g_clear_object(&system_bus_);
+ g_clear_object(&m_system_bus);
}
void
@@ -61,9 +61,9 @@ Clock::onSystemBusReady(GObject*, GAsyncResult * res, gpointer gself)
{
auto self = static_cast<Clock*>(gself);
- self->system_bus_ = system_bus;
+ self->m_system_bus = system_bus;
- self->sleep_subscription_id_ = g_dbus_connection_signal_subscribe(
+ self->m_sleep_subscription_id = g_dbus_connection_signal_subscribe(
system_bus,
nullptr,
"org.freedesktop.login1.Manager", // interface
@@ -78,13 +78,13 @@ Clock::onSystemBusReady(GObject*, GAsyncResult * res, gpointer gself)
}
void
-Clock::onPrepareForSleep(GDBusConnection * connection G_GNUC_UNUSED,
- const gchar * sender_name G_GNUC_UNUSED,
- const gchar * object_path G_GNUC_UNUSED,
- const gchar * interface_name G_GNUC_UNUSED,
- const gchar * signal_name G_GNUC_UNUSED,
- GVariant * parameters G_GNUC_UNUSED,
- gpointer gself)
+Clock::onPrepareForSleep(GDBusConnection* /*connection*/,
+ const gchar* /*sender_name*/,
+ const gchar* /*object_path*/,
+ const gchar* /*interface_name*/,
+ const gchar* /*signal_name*/,
+ GVariant* /*parameters*/,
+ gpointer gself)
{
static_cast<Clock*>(gself)->skewDetected();
}
diff --git a/src/formatter-desktop.cpp b/src/formatter-desktop.cpp
index 8390967..3f942f4 100644
--- a/src/formatter-desktop.cpp
+++ b/src/formatter-desktop.cpp
@@ -35,165 +35,167 @@ class DesktopFormatter::Impl
{
public:
- Impl (DesktopFormatter * owner, const std::shared_ptr<Clock>& clock):
- owner_(owner),
- clock_(clock),
- settings_(g_settings_new(SETTINGS_INTERFACE))
- {
- const gchar * const keys[] = { "changed::" SETTINGS_SHOW_SECONDS_S,
- "changed::" SETTINGS_TIME_FORMAT_S,
- "changed::" SETTINGS_TIME_FORMAT_S,
- "changed::" SETTINGS_CUSTOM_TIME_FORMAT_S,
- "changed::" SETTINGS_SHOW_DAY_S,
- "changed::" SETTINGS_SHOW_DATE_S,
- "changed::" SETTINGS_SHOW_YEAR_S };
- for (guint i=0, n=G_N_ELEMENTS(keys); i<n; i++)
- g_signal_connect(settings_, keys[i], G_CALLBACK(onSettingsChanged), this);
-
- rebuildHeaderFormat();
- }
+Impl(DesktopFormatter * owner, const std::shared_ptr<Clock>& clock):
+ m_owner(owner),
+ m_clock(clock),
+ m_settings(g_settings_new(SETTINGS_INTERFACE))
+{
+ const gchar * const keys[] = { "changed::" SETTINGS_SHOW_SECONDS_S,
+ "changed::" SETTINGS_TIME_FORMAT_S,
+ "changed::" SETTINGS_TIME_FORMAT_S,
+ "changed::" SETTINGS_CUSTOM_TIME_FORMAT_S,
+ "changed::" SETTINGS_SHOW_DAY_S,
+ "changed::" SETTINGS_SHOW_DATE_S,
+ "changed::" SETTINGS_SHOW_YEAR_S };
+ for(const auto& key : keys)
+ g_signal_connect(m_settings, key, G_CALLBACK(onSettingsChanged), this);
+
+ rebuildHeaderFormat();
+}
- ~Impl()
- {
- g_signal_handlers_disconnect_by_data (settings_, this);
- g_object_unref (settings_);
- }
+~Impl()
+{
+ g_signal_handlers_disconnect_by_data(m_settings, this);
+ g_object_unref(m_settings);
+}
private:
- static void onSettingsChanged (GSettings * changed G_GNUC_UNUSED,
- const gchar * key G_GNUC_UNUSED,
- gpointer gself)
- {
- static_cast<Impl*>(gself)->rebuildHeaderFormat();
- }
+static void onSettingsChanged(GSettings * /*changed*/,
+ const gchar * /*key*/,
+ gpointer gself)
+{
+ static_cast<Impl*>(gself)->rebuildHeaderFormat();
+}
- void rebuildHeaderFormat()
- {
- gchar * fmt = getHeaderLabelFormatString (settings_);
- owner_->headerFormat.set(fmt);
- g_free (fmt);
- }
+void rebuildHeaderFormat()
+{
+ auto fmt = getHeaderLabelFormatString(m_settings);
+ m_owner->headerFormat.set(fmt);
+ g_free(fmt);
+}
private:
- gchar* getHeaderLabelFormatString (GSettings * s) const
- {
- char * fmt;
- const TimeFormatMode mode = (TimeFormatMode) g_settings_get_enum (s, SETTINGS_TIME_FORMAT_S);
-
- if (mode == TIME_FORMAT_MODE_CUSTOM)
- {
- fmt = g_settings_get_string (s, SETTINGS_CUSTOM_TIME_FORMAT_S);
- }
- else
- {
- const bool show_day = g_settings_get_boolean (s, SETTINGS_SHOW_DAY_S);
- const bool show_date = g_settings_get_boolean (s, SETTINGS_SHOW_DATE_S);
- const bool show_year = show_date && g_settings_get_boolean (s, SETTINGS_SHOW_YEAR_S);
- const char * date_fmt = getDateFormat (show_day, show_date, show_year);
- const char * time_fmt = getFullTimeFormatString (s);
- fmt = joinDateAndTimeFormatStrings (date_fmt, time_fmt);
- }
-
- return fmt;
- }
+gchar* getHeaderLabelFormatString(GSettings* s) const
+{
+ char * fmt;
+ const auto mode = g_settings_get_enum(s, SETTINGS_TIME_FORMAT_S);
- const gchar* T_(const gchar* in) const
+ if (mode == TIME_FORMAT_MODE_CUSTOM)
{
- return owner_->T_(in);
+ fmt = g_settings_get_string(s, SETTINGS_CUSTOM_TIME_FORMAT_S);
}
-
- const gchar* getDateFormat (bool show_day, bool show_date, bool show_year) const
+ else
{
- const char * fmt;
-
- if (show_day && show_date && show_year)
- /* TRANSLATORS: a strftime(3) format showing the weekday, date, and year */
- fmt = T_("%a %b %e %Y");
- else if (show_day && show_date)
- fmt = T_("%a %b %e");
- else if (show_day && show_year)
- /* TRANSLATORS: a strftime(3) format showing the weekday and year. */
- fmt = T_("%a %Y");
- else if (show_day)
- /* TRANSLATORS: a strftime(3) format showing the weekday. */
- fmt = T_("%a");
- else if (show_date && show_year)
- /* TRANSLATORS: a strftime(3) format showing the date and year */
- fmt = T_("%b %e %Y");
- else if (show_date)
- /* TRANSLATORS: a strftime(3) format showing the date */
- fmt = T_("%b %e");
- else if (show_year)
- /* TRANSLATORS: a strftime(3) format showing the year */
- fmt = T_("%Y");
- else
- fmt = nullptr;
-
- return fmt;
+ const auto show_day = g_settings_get_boolean(s, SETTINGS_SHOW_DAY_S);
+ const auto show_date = g_settings_get_boolean(s, SETTINGS_SHOW_DATE_S);
+ const auto show_year = show_date && g_settings_get_boolean(s, SETTINGS_SHOW_YEAR_S);
+ const auto date_fmt = getDateFormat(show_day, show_date, show_year);
+ const auto time_fmt = getFullTimeFormatString(s);
+ fmt = joinDateAndTimeFormatStrings(date_fmt, time_fmt);
}
- const gchar * getFullTimeFormatString (GSettings * settings) const
- {
- const bool show_seconds = g_settings_get_boolean (settings, SETTINGS_SHOW_SECONDS_S);
+ return fmt;
+}
+
+const gchar* T_(const gchar* in) const
+{
+ return m_owner->T_(in);
+}
- bool twelvehour;
- switch (g_settings_get_enum (settings, SETTINGS_TIME_FORMAT_S))
- {
- case TIME_FORMAT_MODE_LOCALE_DEFAULT:
- twelvehour = is_locale_12h();
- break;
+const gchar* getDateFormat(bool show_day, bool show_date, bool show_year) const
+{
+ const char * fmt;
+
+ if (show_day && show_date && show_year)
+ /* TRANSLATORS: a strftime(3) format showing the weekday, date, and year */
+ fmt = T_("%a %b %e %Y");
+ else if (show_day && show_date)
+ /* TRANSLATORS: a strftime(3) format showing the weekday and date */
+ fmt = T_("%a %b %e");
+ else if (show_day && show_year)
+ /* TRANSLATORS: a strftime(3) format showing the weekday and year. */
+ fmt = T_("%a %Y");
+ else if (show_day)
+ /* TRANSLATORS: a strftime(3) format showing the weekday. */
+ fmt = T_("%a");
+ else if (show_date && show_year)
+ /* TRANSLATORS: a strftime(3) format showing the date and year */
+ fmt = T_("%b %e %Y");
+ else if (show_date)
+ /* TRANSLATORS: a strftime(3) format showing the date */
+ fmt = T_("%b %e");
+ else if (show_year)
+ /* TRANSLATORS: a strftime(3) format showing the year */
+ fmt = T_("%Y");
+ else
+ fmt = nullptr;
+
+ return fmt;
+}
- case TIME_FORMAT_MODE_24_HOUR:
- twelvehour = FALSE;
- break;
+const gchar* getFullTimeFormatString(GSettings* settings) const
+{
+ auto show_seconds = g_settings_get_boolean(settings, SETTINGS_SHOW_SECONDS_S);
+
+ bool twelvehour;
+ switch (g_settings_get_enum(settings, SETTINGS_TIME_FORMAT_S))
+ {
+ case TIME_FORMAT_MODE_LOCALE_DEFAULT:
+ twelvehour = is_locale_12h();
+ break;
- default:
- twelvehour = TRUE;
- break;
- }
+ case TIME_FORMAT_MODE_24_HOUR:
+ twelvehour = false;
+ break;
- return owner_->getDefaultHeaderTimeFormat (twelvehour, show_seconds);
+ default:
+ twelvehour = true;
+ break;
}
- gchar* joinDateAndTimeFormatStrings (const char * date_string, const char * time_string) const
+ return m_owner->getDefaultHeaderTimeFormat(twelvehour, show_seconds);
+}
+
+gchar* joinDateAndTimeFormatStrings(const char* date_string,
+ const char* time_string) const
+{
+ 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\u2003%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("%s\u2003%s", date_string, time_string);
+ }
+ else if (date_string)
+ {
+ str = g_strdup(date_string);
+ }
+ else // time_string
{
- 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\u2003%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 ("%s\u2003%s", date_string, time_string);
- }
- else if (date_string)
- {
- str = g_strdup (date_string);
- }
- else // time_string
- {
- str = g_strdup (time_string);
- }
-
- return str;
+ str = g_strdup(time_string);
}
+ return str;
+}
+
private:
- DesktopFormatter * const owner_;
- std::shared_ptr<Clock> clock_;
- GSettings * settings_;
+DesktopFormatter * const m_owner;
+std::shared_ptr<Clock> m_clock;
+GSettings * m_settings;
};
/***
****
***/
-DesktopFormatter::DesktopFormatter (const std::shared_ptr<Clock>& clock):
+DesktopFormatter::DesktopFormatter(const std::shared_ptr<Clock>& clock):
Formatter(clock),
p(new Impl(this, clock))
{
diff --git a/src/formatter.cpp b/src/formatter.cpp
index 4e2f582..1f26cc7 100644
--- a/src/formatter.cpp
+++ b/src/formatter.cpp
@@ -30,16 +30,16 @@
namespace
{
-void clearTimer (guint& tag)
+void clearTimer(guint& tag)
{
if (tag)
{
- g_source_remove (tag);
+ g_source_remove(tag);
tag = 0;
}
}
-guint calculate_milliseconds_until_next_minute (GDateTime * now)
+guint calculate_milliseconds_until_next_minute(GDateTime * now)
{
GDateTime * next;
GDateTime * start_of_next;
@@ -47,12 +47,12 @@ guint calculate_milliseconds_until_next_minute (GDateTime * now)
guint interval_msec;
next = g_date_time_add_minutes(now, 1);
- start_of_next = g_date_time_new_local(g_date_time_get_year (next),
- g_date_time_get_month (next),
- g_date_time_get_day_of_month (next),
- g_date_time_get_hour (next),
- g_date_time_get_minute (next),
- 0.1);
+ start_of_next = g_date_time_new_local(g_date_time_get_year(next),
+ g_date_time_get_month(next),
+ g_date_time_get_day_of_month(next),
+ g_date_time_get_hour(next),
+ g_date_time_get_minute(next),
+ 0.1);
interval_usec = g_date_time_difference(start_of_next, now);
interval_msec = (interval_usec + 999) / 1000;
@@ -62,12 +62,12 @@ guint calculate_milliseconds_until_next_minute (GDateTime * now)
return interval_msec;
}
-gint calculate_milliseconds_until_next_second (GDateTime * now)
+gint calculate_milliseconds_until_next_second(GDateTime * now)
{
gint interval_usec;
guint interval_msec;
- interval_usec = G_USEC_PER_SEC - g_date_time_get_microsecond (now);
+ interval_usec = G_USEC_PER_SEC - g_date_time_get_microsecond(now);
interval_msec = (interval_usec + 999) / 1000;
return interval_msec;
}
@@ -94,7 +94,7 @@ gint calculate_milliseconds_until_next_second (GDateTime * now)
* (examples: Newfoundland UTC-03:30, Nepal UTC+05:45), refreshing on the hour
* is not enough. We need to refresh at HH:00, HH:15, HH:30, and HH:45.
*/
-guint calculate_seconds_until_next_fifteen_minutes (GDateTime * now)
+guint calculate_seconds_until_next_fifteen_minutes(GDateTime * now)
{
char * str;
gint minute;
@@ -106,23 +106,22 @@ guint calculate_seconds_until_next_fifteen_minutes (GDateTime * now)
minute = g_date_time_get_minute(now);
minute = 15 - (minute % 15);
next = g_date_time_add_minutes(now, minute);
- start_of_next = g_date_time_new_local(g_date_time_get_year (next),
- g_date_time_get_month (next),
- g_date_time_get_day_of_month (next),
- g_date_time_get_hour (next),
- g_date_time_get_minute (next),
+ start_of_next = g_date_time_new_local(g_date_time_get_year(next),
+ g_date_time_get_month(next),
+ g_date_time_get_day_of_month(next),
+ g_date_time_get_hour(next),
+ g_date_time_get_minute(next),
0.1);
str = g_date_time_format(start_of_next, "%F %T");
- g_debug ("%s %s the next timestamp rebuild will be at %s", G_STRLOC, G_STRFUNC, str);
- g_free (str);
+ g_debug("%s %s the next timestamp rebuild will be at %s", G_STRLOC, G_STRFUNC, str);
+ g_free(str);
diff = g_date_time_difference(start_of_next, now);
seconds = (diff + (G_TIME_SPAN_SECOND-1)) / G_TIME_SPAN_SECOND;
g_date_time_unref(start_of_next);
g_date_time_unref(next);
-
return seconds;
}
} // anonymous namespace
@@ -137,11 +136,12 @@ class Formatter::Impl
{
public:
- Impl (Formatter* owner, const std::shared_ptr<Clock>& clock):
- owner_(owner),
- clock_(clock)
+ Impl(Formatter* owner, const std::shared_ptr<Clock>& clock):
+ m_owner(owner),
+ m_clock(clock)
{
- owner_->headerFormat.changed().connect([this](const std::string& fmt G_GNUC_UNUSED){updateHeader();});
+ m_owner->headerFormat.changed().connect([this](const std::string& /*fmt*/){updateHeader();});
+ m_clock->skewDetected.connect([this](){updateHeader();});
updateHeader();
restartRelativeTimer();
@@ -149,30 +149,25 @@ public:
~Impl()
{
- clearTimer(header_timer_);
+ clearTimer(m_header_timer);
}
private:
void updateHeader()
{
- GDateTime * now = clock_->localtime();
- const time_t unix = g_date_time_to_unix (now);
- struct tm tm;
- localtime_r (&unix, &tm);
- char str[512];
- strftime (str, sizeof(str), owner_->headerFormat.get().c_str(), &tm);
- owner_->header.set (str);
- g_date_time_unref (now);
+ const auto fmt = m_owner->headerFormat.get();
+ const auto str = m_clock->localtime().format(fmt);
+ m_owner->header.set(str);
restartHeaderTimer();
}
void restartHeaderTimer()
{
- clearTimer(header_timer_);
+ clearTimer(m_header_timer);
- const std::string fmt = owner_->headerFormat.get();
+ const std::string fmt = m_owner->headerFormat.get();
const bool header_shows_seconds = (fmt.find("%s") != std::string::npos)
|| (fmt.find("%S") != std::string::npos)
|| (fmt.find("%T") != std::string::npos)
@@ -180,17 +175,17 @@ private:
|| (fmt.find("%c") != std::string::npos);
guint interval_msec;
- GDateTime * now = clock_->localtime();
+ const auto now = m_clock->localtime();
+ auto str = now.format("%F %T");
if (header_shows_seconds)
- interval_msec = calculate_milliseconds_until_next_second (now);
+ interval_msec = calculate_milliseconds_until_next_second(now.get());
else
- interval_msec = calculate_milliseconds_until_next_minute (now);
- g_date_time_unref (now);
+ interval_msec = calculate_milliseconds_until_next_minute(now.get());
interval_msec += 50; // add a small margin to ensure the callback
// fires /after/ next is reached
- header_timer_ = g_timeout_add_full(G_PRIORITY_HIGH, interval_msec, onHeaderTimer, this, nullptr);
+ m_header_timer = g_timeout_add_full(G_PRIORITY_HIGH, interval_msec, onHeaderTimer, this, nullptr);
}
static gboolean onHeaderTimer(gpointer gself)
@@ -203,29 +198,28 @@ private:
void restartRelativeTimer()
{
- clearTimer(relative_timer_);
+ clearTimer(m_relative_timer);
- GDateTime * now = clock_->localtime();
- const guint seconds = calculate_seconds_until_next_fifteen_minutes(now);
- relative_timer_ = g_timeout_add_seconds(seconds, onRelativeTimer, this);
- g_date_time_unref(now);
+ const auto now = m_clock->localtime();
+ const auto seconds = calculate_seconds_until_next_fifteen_minutes(now.get());
+ m_relative_timer = g_timeout_add_seconds(seconds, onRelativeTimer, this);
}
static gboolean onRelativeTimer(gpointer gself)
{
auto self = static_cast<Formatter::Impl*>(gself);
- self->owner_->relativeFormatChanged();
+ self->m_owner->relativeFormatChanged();
self->restartRelativeTimer();
return G_SOURCE_REMOVE;
}
private:
- Formatter * const owner_;
- guint header_timer_ = 0;
- guint relative_timer_ = 0;
+ Formatter * const m_owner;
+ guint m_header_timer = 0;
+ guint m_relative_timer = 0;
public:
- std::shared_ptr<Clock> clock_;
+ std::shared_ptr<Clock> m_clock;
};
/***
@@ -233,7 +227,7 @@ public:
***/
Formatter::Formatter(const std::shared_ptr<Clock>& clock):
- p (new Formatter::Impl(this, clock))
+ p(new Formatter::Impl(this, clock))
{
}
@@ -244,12 +238,11 @@ Formatter::~Formatter()
bool
Formatter::is_locale_12h()
{
- static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k", nullptr};
- const char *t_fmt = nl_langinfo (T_FMT);
- int i;
+ static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k"};
+ const auto t_fmt = nl_langinfo(T_FMT);
- for (i=0; formats_24h[i]; ++i)
- if (strstr (t_fmt, formats_24h[i]))
+ for (const auto& needle : formats_24h)
+ if (strstr(t_fmt, needle))
return false;
return true;
@@ -272,7 +265,7 @@ Formatter::T_(const char *msg)
*/
char *message_locale = g_strdup(setlocale(LC_MESSAGES, nullptr));
- const char *time_locale = setlocale (LC_TIME, nullptr);
+ const char *time_locale = setlocale(LC_TIME, nullptr);
char *language = g_strdup(g_getenv("LANGUAGE"));
const char *rv;
@@ -329,15 +322,15 @@ typedef enum
}
date_proximity_t;
-date_proximity_t getDateProximity (GDateTime * now, GDateTime * time)
+date_proximity_t getDateProximity(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);
+ 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;
@@ -347,12 +340,12 @@ date_proximity_t getDateProximity (GDateTime * now, GDateTime * time)
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);
+ 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);
+ g_date_time_unref(tomorrow);
}
// does it happen this week?
@@ -361,17 +354,17 @@ date_proximity_t getDateProximity (GDateTime * now, GDateTime * time)
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);
+ 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)
+ if (g_date_time_compare(time, week_bound) <= 0)
prox = DATE_PROXIMITY_WEEK;
- g_date_time_unref (week_bound);
- g_date_time_unref (week);
+ g_date_time_unref(week_bound);
+ g_date_time_unref(week);
}
return prox;
@@ -398,12 +391,12 @@ std::string
Formatter::getRelativeFormat(GDateTime* then, GDateTime* then_end) const
{
std::string ret;
- GDateTime * now = p->clock_->localtime();
+ auto now = p->m_clock->localtime().get();
if (then != nullptr)
{
- const bool full_day = then_end && (g_date_time_difference (then_end, then) >= G_TIME_SPAN_DAY);
- const auto prox = getDateProximity (now, then);
+ const bool full_day = then_end && (g_date_time_difference(then_end, then) >= G_TIME_SPAN_DAY);
+ const auto prox = getDateProximity(now, then);
if (full_day)
{
@@ -440,14 +433,13 @@ Formatter::getRelativeFormat(GDateTime* then, GDateTime* then_end) const
then the time should be followed by its timezone. */
if ((then_end != nullptr) &&
(!full_day) &&
- ((g_date_time_get_utc_offset (now) != g_date_time_get_utc_offset (then))))
+ ((g_date_time_get_utc_offset(now) != g_date_time_get_utc_offset(then))))
{
ret += ' ';
- ret += g_date_time_get_timezone_abbreviation (then);
+ ret += g_date_time_get_timezone_abbreviation(then);
}
}
- g_date_time_unref (now);
return ret;
}
diff --git a/src/locations-settings.cpp b/src/locations-settings.cpp
index ed8f998..646a360 100644
--- a/src/locations-settings.cpp
+++ b/src/locations-settings.cpp
@@ -29,16 +29,16 @@ namespace unity {
namespace indicator {
namespace datetime {
-SettingsLocations::SettingsLocations (const std::string& schemaId,
- const std::shared_ptr<Timezones>& timezones):
- timezones_(timezones)
+SettingsLocations::SettingsLocations(const std::string& schemaId,
+ const std::shared_ptr<Timezones>& timezones):
+ m_timezones(timezones)
{
- auto deleter = [&](GSettings* s){g_object_unref(s);};
- settings_ = std::unique_ptr<GSettings,std::function<void(GSettings*)>>(g_settings_new(schemaId.c_str()), deleter);
+ auto deleter = [](GSettings* s){g_object_unref(s);};
+ m_settings = std::unique_ptr<GSettings,std::function<void(GSettings*)>>(g_settings_new(schemaId.c_str()), deleter);
const char * keys[] = { "changed::" SETTINGS_LOCATIONS_S,
"changed::" SETTINGS_SHOW_LOCATIONS_S };
- for (int i=0, n=G_N_ELEMENTS(keys); i<n; i++)
- g_signal_connect_swapped (settings_.get(), keys[i], G_CALLBACK(onSettingsChanged), this);
+ for (const auto& key : keys)
+ g_signal_connect_swapped(m_settings.get(), key, G_CALLBACK(onSettingsChanged), this);
timezones->timezone.changed().connect([this](const std::string&){reload();});
timezones->timezones.changed().connect([this](const std::set<std::string>&){reload();});
@@ -47,7 +47,7 @@ SettingsLocations::SettingsLocations (const std::string& schemaId,
}
void
-SettingsLocations::onSettingsChanged (gpointer gself)
+SettingsLocations::onSettingsChanged(gpointer gself)
{
static_cast<SettingsLocations*>(gself)->reload();
}
@@ -56,48 +56,49 @@ void
SettingsLocations::reload()
{
std::vector<Location> v;
+ auto settings = m_settings.get();
// add the primary timezone first
- std::string zone = timezones_->timezone.get();
+ auto zone = m_timezones->timezone.get();
if (!zone.empty())
{
- gchar * name = get_current_zone_name (zone.c_str(), settings_.get());
- Location l (zone, name);
- v.push_back (l);
- g_free (name);
+ gchar * name = get_current_zone_name(zone.c_str(), settings);
+ Location l(zone, name);
+ v.push_back(l);
+ g_free(name);
}
// add the other detected timezones
- for (const auto& zone : timezones_->timezones.get())
+ for (const auto& zone : m_timezones->timezones.get())
{
- gchar * name = get_current_zone_name (zone.c_str(), settings_.get());
- Location l (zone, name);
- if (std::find (v.begin(), v.end(), l) == v.end())
- v.push_back (l);
- g_free (name);
+ gchar * name = get_current_zone_name(zone.c_str(), settings);
+ Location l(zone, name);
+ if (std::find(v.begin(), v.end(), l) == v.end())
+ v.push_back(l);
+ g_free(name);
}
// maybe add the user-specified locations
- if (g_settings_get_boolean (settings_.get(), SETTINGS_SHOW_LOCATIONS_S))
+ if (g_settings_get_boolean(settings, SETTINGS_SHOW_LOCATIONS_S))
{
- gchar ** user_locations = g_settings_get_strv (settings_.get(), SETTINGS_LOCATIONS_S);
+ gchar ** user_locations = g_settings_get_strv(settings, SETTINGS_LOCATIONS_S);
for (int i=0; user_locations[i]; i++)
{
gchar * zone;
gchar * name;
- split_settings_location (user_locations[i], &zone, &name);
- Location l (zone, name);
- if (std::find (v.begin(), v.end(), l) == v.end())
- v.push_back (l);
- g_free (name);
- g_free (zone);
+ split_settings_location(user_locations[i], &zone, &name);
+ Location l(zone, name);
+ if (std::find(v.begin(), v.end(), l) == v.end())
+ v.push_back(l);
+ g_free(name);
+ g_free(zone);
}
- g_strfreev (user_locations);
+ g_strfreev(user_locations);
}
- locations.set (v);
+ locations.set(v);
}
} // namespace datetime
diff --git a/src/locations.cpp b/src/locations.cpp
index 5c3c52b..d6ab73a 100644
--- a/src/locations.cpp
+++ b/src/locations.cpp
@@ -26,16 +26,39 @@ namespace indicator {
namespace datetime {
Location::Location(const std::string& zone_, const std::string& name_):
- zone(zone_),
- name(name_)
+ m_zone(zone_),
+ m_name(name_)
{
- GTimeZone * gzone = g_time_zone_new (zone.c_str());
- GDateTime * gtime = g_date_time_new_now (gzone);
- offset = g_date_time_get_utc_offset (gtime);
+ auto gzone = g_time_zone_new (zone().c_str());
+ auto gtime = g_date_time_new_now (gzone);
+ m_offset = g_date_time_get_utc_offset (gtime);
g_date_time_unref (gtime);
g_time_zone_unref (gzone);
}
+#if 0
+DateTime Location::localtime(const DateTime& reference_point) const
+{
+GDateTime * g_date_time_to_timezone (GDateTime *datetime,
+ GTimeZone *tz);
+ auto gzone = g_time_zone_new(zone().c_str());
+ const auto gtime = reference_point.get();
+ auto glocal = g_date_time_new (gzone,
+ g_date_time_get_year(gtime),
+ g_date_time_get_month(gtime),
+ g_date_time_get_day_of_month(gtime),
+ g_date_time_get_hour(gtime),
+ g_date_time_get_minute(gtime),
+ g_date_time_get_seconds(gtime));
+ DateTime local(glocal);
+ g_date_time_unref(glocal);
+ g_message("reference: %zu", (size_t)reference_point.to_unix(), (size_t)local.to_unix());
+ //g_date_time_unref(gtime);
+ g_time_zone_unref(gzone);
+ return local;
+}
+#endif
+
} // namespace datetime
} // namespace indicator
} // namespace unity
diff --git a/src/main.c b/src/main.c
deleted file mode 100644
index 868d41b..0000000
--- a/src/main.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2013 Canonical Ltd.
- *
- * Authors:
- * Charles Kerr <charles.kerr@canonical.com>
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 3, as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranties of
- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <locale.h>
-#include <stdlib.h> /* exit() */
-
-#include <glib/gi18n.h>
-#include <gio/gio.h>
-#include <libnotify/notify.h>
-
-#include "clock-live.h"
-#include "planner-eds.h"
-#include "service.h"
-
-/***
-****
-***/
-
-static void
-on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop)
-{
- g_message ("exiting: service couldn't acquire or lost ownership of busname");
-
- g_main_loop_quit ((GMainLoop*)loop);
-}
-
-int
-main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED)
-{
- IndicatorDatetimeClock * clock;
- IndicatorDatetimePlanner * planner;
- IndicatorDatetimeService * service;
- GMainLoop * loop;
-
- /* Work around a deadlock in glib's type initialization. It can be
- * removed when https://bugzilla.gnome.org/show_bug.cgi?id=674885 is
- * fixed.
- */
- g_type_ensure (G_TYPE_DBUS_CONNECTION);
-
- /* boilerplate i18n */
- setlocale (LC_ALL, "");
- bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
- textdomain (GETTEXT_PACKAGE);
-
- /* init libnotify */
- if (!notify_init ("indicator-datetime-service"))
- g_critical ("libnotify initialization failed");
-
- /* create the service */
- clock = indicator_datetime_clock_live_new ();
- planner = indicator_datetime_planner_eds_new ();
- service = indicator_datetime_service_new (clock, planner);
-
- /* run */
- loop = g_main_loop_new (NULL, FALSE);
- g_signal_connect (service, INDICATOR_DATETIME_SERVICE_SIGNAL_NAME_LOST,
- G_CALLBACK(on_name_lost), loop);
- g_main_loop_run (loop);
- g_main_loop_unref (loop);
-
- /* cleanup */
- g_object_unref (service);
- g_object_unref (planner);
- g_object_unref (clock);
- return 0;
-}
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..c246296
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <datetime/clock.h>
+#include <datetime/formatter.h>
+#include <datetime/locations-settings.h>
+#include <datetime/menu.h>
+#include <datetime/planner-eds.h>
+#include <datetime/service.h>
+#include <datetime/settings-shared.h>
+#include <datetime/state.h>
+#include <datetime/timezones-live.h>
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <libnotify/notify.h>
+
+#include <iostream>
+
+#include <locale.h>
+#include <stdlib.h> /* exit() */
+
+using namespace unity::indicator::datetime;
+
+int
+main(int /*argc*/, char** /*argv*/)
+{
+ // Work around a deadlock in glib's type initialization.
+ // It can be removed when https://bugzilla.gnome.org/show_bug.cgi?id=674885 is fixed.
+ g_type_ensure(G_TYPE_DBUS_CONNECTION);
+
+ // boilerplate i18n
+ setlocale(LC_ALL, "");
+ bindtextdomain(GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ textdomain(GETTEXT_PACKAGE);
+
+ // init libnotify
+ if(!notify_init("indicator-datetime-service"))
+ g_critical("libnotify initialization failed");
+
+ // build the menu factory
+ GActionGroup * actions = G_ACTION_GROUP(g_simple_action_group_new());
+ std::shared_ptr<Timezones> timezones(new LiveTimezones(TIMEZONE_FILE));
+ std::shared_ptr<Clock> clock(new LiveClock(timezones));
+ std::shared_ptr<Planner> planner(new PlannerEds);
+ std::shared_ptr<Locations> locations(new SettingsLocations(SETTINGS_INTERFACE, timezones));
+ planner->time = clock->localtime();
+ MenuFactory factory(actions, timezones, clock, planner, locations);
+
+ // create the menus
+ std::vector<std::shared_ptr<Menu>> menus;
+ menus.push_back(factory.buildMenu(MenuFactory::Desktop));
+
+ // export them
+ auto loop = g_main_loop_new(nullptr, false);
+ Service service;
+ service.name_lost.connect([loop](){
+ g_message("exiting: service couldn't acquire or lost ownership of busname");
+ g_main_loop_quit(loop);
+ });
+ service.publish(actions, menus);
+ g_main_loop_run(loop);
+ g_main_loop_unref(loop);
+ return 0;
+}
diff --git a/src/menu.cpp b/src/menu.cpp
new file mode 100644
index 0000000..76306cc
--- /dev/null
+++ b/src/menu.cpp
@@ -0,0 +1,518 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#include <datetime/menu.h>
+
+#include <datetime/clock.h>
+#include <datetime/formatter.h>
+#include <datetime/locations.h>
+#include <datetime/planner.h>
+#include <datetime/state.h>
+#include <datetime/timezones.h>
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/****
+*****
+****/
+
+#define ALARM_CLOCK_ICON_NAME "alarm-clock"
+#define CALENDAR_ICON_NAME "calendar"
+
+class MenuImpl: public Menu
+{
+protected:
+ MenuImpl(const Menu::Profile profile_in,
+ const std::string& name_in,
+ std::shared_ptr<State>& state,
+ std::shared_ptr<Actions>& actions,
+ std::shared_ptr<Formatter> formatter):
+ Menu(profile_in, name_in),
+ m_state(state),
+ m_actions(actions),
+ m_formatter(formatter)
+ {
+ // initialize the menu
+ create_gmenu();
+ for (int i=0; i<NUM_SECTIONS; i++)
+ update_section(Section(i));
+
+ // listen for state changes so we can update the menu accordingly
+ m_formatter->header.changed().connect([this](const std::string&){
+ update_header();
+ });
+ m_formatter->headerFormat.changed().connect([this](const std::string&){
+ update_section(Locations); // need to update x-canonical-time-format
+ });
+ m_formatter->relativeFormatChanged.connect([this](){
+ update_section(Appointments); // uses formatter.getRelativeFormat()
+ update_section(Locations); // uses formatter.getRelativeFormat()
+ });
+ m_state->show_clock.changed().connect([this](bool){
+ update_header(); // update header's label
+ update_section(Locations); // locations' relative time may have changed
+ });
+ m_state->show_events.changed().connect([this](bool){
+ update_section(Appointments); // showing events got toggled
+ });
+ m_state->planner->upcoming.changed().connect([this](const std::vector<Appointment>&){
+ update_section(Appointments); // "upcoming" is the list of Appointments we show
+ });
+ m_state->clock->dateChanged.connect([this](){
+ update_section(Calendar); // need to update the Date menuitem
+ update_section(Locations); // locations' relative time may have changed
+ });
+ m_state->locations->locations.changed().connect([this](const std::vector<Location>&) {
+ update_section(Locations); // "locations" is the list of Locations we show
+ });
+ }
+
+ virtual ~MenuImpl()
+ {
+ g_clear_object(&m_menu);
+ g_clear_pointer(&m_serialized_alarm_icon, g_variant_unref);
+ g_clear_pointer(&m_serialized_calendar_icon, g_variant_unref);
+ }
+
+ virtual GVariant* create_header_state() =0;
+
+ void update_header()
+ {
+ auto action_group = m_actions->action_group();
+ auto action_name = name() + "-header";
+ auto state = create_header_state();
+ g_action_group_change_action_state(action_group, action_name.c_str(), state);
+ }
+
+ std::shared_ptr<State> m_state;
+ std::shared_ptr<Actions> m_actions;
+ std::shared_ptr<Formatter> m_formatter;
+ GMenu* m_submenu = nullptr;
+
+ GVariant* get_serialized_alarm_icon()
+ {
+ if (G_UNLIKELY(m_serialized_alarm_icon == nullptr))
+ {
+ auto i = g_themed_icon_new_with_default_fallbacks(ALARM_CLOCK_ICON_NAME);
+ m_serialized_alarm_icon = g_icon_serialize(i);
+ g_object_unref(i);
+ }
+
+ return m_serialized_alarm_icon;
+ }
+
+private:
+
+ GVariant* get_serialized_calendar_icon()
+ {
+ if (G_UNLIKELY(m_serialized_calendar_icon == nullptr))
+ {
+ auto i = g_themed_icon_new_with_default_fallbacks(CALENDAR_ICON_NAME);
+ m_serialized_calendar_icon = g_icon_serialize(i);
+ g_object_unref(i);
+ }
+
+ return m_serialized_calendar_icon;
+ }
+
+ void create_gmenu()
+ {
+ g_assert(m_submenu == nullptr);
+
+ m_submenu = g_menu_new();
+
+ // build placeholders for the sections
+ for(int i=0; i<NUM_SECTIONS; i++)
+ {
+ GMenuItem * item = g_menu_item_new(nullptr, nullptr);
+ g_menu_append_item(m_submenu, item);
+ g_object_unref(item);
+ }
+
+ // add submenu to the header
+ const auto detailed_action = std::string("indicator.") + name() + "-header";
+ auto header = g_menu_item_new(nullptr, detailed_action.c_str());
+ g_menu_item_set_attribute(header, "x-canonical-type", "s",
+ "com.canonical.indicator.root");
+ g_menu_item_set_submenu(header, G_MENU_MODEL(m_submenu));
+ g_object_unref(m_submenu);
+
+ // add header to the menu
+ m_menu = g_menu_new();
+ g_menu_append_item(m_menu, header);
+ g_object_unref(header);
+ }
+
+ GMenuModel* create_calendar_section(Profile profile)
+ {
+ const bool allow_activation = (profile == Desktop)
+ || (profile == Phone);
+ const bool show_calendar = (profile == Desktop)
+ || (profile == DesktopGreeter);
+ auto menu = g_menu_new();
+
+ // add a menuitem that shows the current date
+ auto label = m_state->clock->localtime().format(_("%A, %e %B %Y"));
+ auto item = g_menu_item_new (label.c_str(), nullptr);
+ auto v = get_serialized_calendar_icon();
+ g_menu_item_set_attribute_value (item, G_MENU_ATTRIBUTE_ICON, v);
+ if (allow_activation)
+ {
+ v = g_variant_new_int64(0);
+ const char* action = "indicator.activate-planner";
+ g_menu_item_set_action_and_target_value (item, action, v);
+ }
+ g_menu_append_item(menu, item);
+ g_object_unref(item);
+
+ // add calendar
+ if (show_calendar)
+ {
+ item = g_menu_item_new ("[calendar]", NULL);
+ v = g_variant_new_int64(0);
+ g_menu_item_set_action_and_target_value (item, "indicator.calendar", v);
+ g_menu_item_set_attribute (item, "x-canonical-type",
+ "s", "com.canonical.indicator.calendar");
+ if (allow_activation)
+ {
+ g_menu_item_set_attribute (item, "activation-action",
+ "s", "indicator.activate-planner");
+ }
+ g_menu_append_item (menu, item);
+ g_object_unref (item);
+ }
+
+ return G_MENU_MODEL(menu);
+ }
+
+ void add_appointments(GMenu* menu, Profile profile)
+ {
+ int n = 0;
+ const int MAX_APPTS = 5;
+ std::set<std::string> added;
+
+ for (const auto& appt : m_state->planner->upcoming.get())
+ {
+ if (n++ >= MAX_APPTS)
+ break;
+
+ if (added.count(appt.uid))
+ continue;
+
+ added.insert(appt.uid);
+
+ GDateTime* begin = appt.begin();
+ GDateTime* end = appt.end();
+ auto fmt = m_formatter->getRelativeFormat(begin, end);
+ auto unix_time = g_date_time_to_unix(begin);
+
+ auto menu_item = g_menu_item_new (appt.summary.c_str(), nullptr);
+ g_menu_item_set_attribute (menu_item, "x-canonical-time", "x", unix_time);
+ g_menu_item_set_attribute (menu_item, "x-canonical-time-format", "s", fmt.c_str());
+
+ if (appt.has_alarms)
+ {
+ g_menu_item_set_attribute (menu_item, "x-canonical-type", "s", "com.canonical.indicator.alarm");
+ g_menu_item_set_attribute_value(menu_item, G_MENU_ATTRIBUTE_ICON, get_serialized_alarm_icon());
+ }
+ else
+ {
+ g_menu_item_set_attribute (menu_item, "x-canonical-type", "s", "com.canonical.indicator.appointment");
+
+ if (!appt.color.empty())
+ g_menu_item_set_attribute (menu_item, "x-canonical-color", "s", appt.color.c_str());
+ }
+
+ if (profile == Phone)
+ g_menu_item_set_action_and_target_value (menu_item,
+ "indicator.activate-appointment",
+ g_variant_new_string (appt.uid.c_str()));
+ else
+ 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);
+ }
+ }
+
+ GMenuModel* create_appointments_section(Profile profile)
+ {
+ auto menu = g_menu_new();
+
+ if (((profile==Phone) || (profile==Desktop)) && m_state->show_events.get())
+ {
+ add_appointments (menu, profile);
+
+ // add the 'Add Event…' menuitem
+ auto menu_item = g_menu_item_new(_("Add Event…"), nullptr);
+ const gchar* action_name = "indicator.activate_planner";
+ auto v = g_variant_new_int64(0);
+ g_menu_item_set_action_and_target_value(menu_item, action_name, v);
+ g_menu_append_item(menu, menu_item);
+ g_object_unref(menu_item);
+ }
+
+ return G_MENU_MODEL(menu);
+ }
+
+ GMenuModel* create_locations_section(Profile profile)
+ {
+ GMenu* menu = g_menu_new();
+
+ if (profile == Desktop)
+ {
+ const auto now = m_state->clock->localtime();
+
+ for(const auto& location : m_state->locations->locations.get())
+ {
+ const auto& zone = location.zone();
+ const auto& name = location.name();
+ const auto zone_now = now.to_timezone(zone);
+ const auto fmt = m_formatter->getRelativeFormat(zone_now.get());
+ auto detailed_action = g_strdup_printf("indicator.set-location::%s %s", zone.c_str(), name.c_str());
+ auto i = g_menu_item_new (name.c_str(), detailed_action);
+ g_menu_item_set_attribute(i, "x-canonical-type", "s", "com.canonical.indicator.location");
+ g_menu_item_set_attribute(i, "x-canonical-timezone", "s", zone.c_str());
+ g_menu_item_set_attribute(i, "x-canonical-time-format", "s", fmt.c_str());
+ g_menu_append_item (menu, i);
+ g_object_unref(i);
+ g_free(detailed_action);
+ }
+ }
+
+ return G_MENU_MODEL(menu);
+ }
+
+ GMenuModel* create_settings_section(Profile profile)
+ {
+ auto menu = g_menu_new();
+
+ if (profile == Desktop)
+ {
+ g_menu_append (menu, _("Date & Time Settings…"), "indicator.activate-desktop-settings");
+ }
+ else if (profile == Phone)
+ {
+ g_menu_append (menu, _("Time & Date settings…"), "indicator.activate-phone-settings");
+ }
+
+ return G_MENU_MODEL (menu);
+ }
+
+ void update_section(Section section)
+ {
+ GMenuModel * model;
+ const auto p = profile();
+
+ switch (section)
+ {
+ case Calendar: model = create_calendar_section(p); break;
+ case Appointments: model = create_appointments_section(p); break;
+ case Locations: model = create_locations_section(p); break;
+ case Settings: model = create_settings_section(p); break;
+ default: g_warn_if_reached();
+ }
+
+ if (model)
+ {
+ g_menu_remove(m_submenu, section);
+ g_menu_insert_section(m_submenu, section, nullptr, model);
+ g_object_unref(model);
+ }
+ }
+
+//private:
+ GVariant * m_serialized_alarm_icon = nullptr;
+ GVariant * m_serialized_calendar_icon = nullptr;
+
+}; // class MenuImpl
+
+
+
+/***
+****
+***/
+
+class DesktopBaseMenu: public MenuImpl
+{
+protected:
+ DesktopBaseMenu(Menu::Profile profile_,
+ const std::string& name_,
+ std::shared_ptr<State>& state_,
+ std::shared_ptr<Actions>& actions_):
+ MenuImpl(profile_, name_, state_, actions_,
+ std::shared_ptr<Formatter>(new DesktopFormatter(state_->clock)))
+ {
+ update_header();
+ }
+
+ GVariant* create_header_state()
+ {
+ const auto visible = m_state->show_clock.get();
+ const auto title = _("Date and Time");
+ auto label = g_variant_new_string(m_formatter->header.get().c_str());
+
+ GVariantBuilder b;
+ g_variant_builder_init(&b, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add(&b, "{sv}", "accessible-desc", label);
+ g_variant_builder_add(&b, "{sv}", "label", label);
+ g_variant_builder_add(&b, "{sv}", "title", g_variant_new_string(title));
+ g_variant_builder_add(&b, "{sv}", "visible", g_variant_new_boolean(visible));
+ return g_variant_builder_end(&b);
+ }
+};
+
+class DesktopMenu: public DesktopBaseMenu
+{
+public:
+ DesktopMenu(std::shared_ptr<State>& state_, std::shared_ptr<Actions>& actions_):
+ DesktopBaseMenu(Desktop,"desktop", state_, actions_) {}
+};
+
+class DesktopGreeterMenu: public DesktopBaseMenu
+{
+public:
+ DesktopGreeterMenu(std::shared_ptr<State>& state_, std::shared_ptr<Actions>& actions_):
+ DesktopBaseMenu(DesktopGreeter,"desktop-greeter", state_, actions_) {}
+};
+
+class PhoneBaseMenu: public MenuImpl
+{
+protected:
+ PhoneBaseMenu(Menu::Profile profile_,
+ const std::string& name_,
+ std::shared_ptr<State>& state_,
+ std::shared_ptr<Actions>& actions_):
+ MenuImpl(profile_, name_, state_, actions_,
+ std::shared_ptr<Formatter>(new PhoneFormatter(state_->clock)))
+ {
+ update_header();
+ }
+
+ GVariant* create_header_state()
+ {
+ // are there alarms?
+ bool has_alarms = false;
+ for(const auto& appointment : m_state->planner->upcoming.get())
+ if((has_alarms = appointment.has_alarms))
+ break;
+
+ GVariantBuilder b;
+ g_variant_builder_init(&b, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add(&b, "{sv}", "title", g_variant_new_string (_("Upcoming")));
+ g_variant_builder_add(&b, "{sv}", "visible", g_variant_new_boolean (TRUE));
+ if (has_alarms)
+ {
+ auto label = m_formatter->header.get();
+ auto a11y = g_strdup_printf(_("%s (has alarms)"), label.c_str());
+ g_variant_builder_add(&b, "{sv}", "label", g_variant_new_string(label.c_str()));
+ g_variant_builder_add(&b, "{sv}", "accessible-desc", g_variant_new_take_string(a11y));
+ g_variant_builder_add(&b, "{sv}", "icon", get_serialized_alarm_icon());
+ }
+ else
+ {
+ auto v = g_variant_new_string(m_formatter->header.get().c_str());
+ g_variant_builder_add(&b, "{sv}", "label", v);
+ g_variant_builder_add(&b, "{sv}", "accessible-desc", v);
+ }
+ return g_variant_builder_end (&b);
+ }
+};
+
+class PhoneMenu: public PhoneBaseMenu
+{
+public:
+ PhoneMenu(std::shared_ptr<State>& state_,
+ std::shared_ptr<Actions>& actions_):
+ PhoneBaseMenu(Phone, "phone", state_, actions_) {}
+};
+
+class PhoneGreeterMenu: public PhoneBaseMenu
+{
+public:
+ PhoneGreeterMenu(std::shared_ptr<State>& state_,
+ std::shared_ptr<Actions>& actions_):
+ PhoneBaseMenu(PhoneGreeter, "phone-greeter", state_, actions_) {}
+};
+
+/****
+*****
+****/
+
+MenuFactory::MenuFactory(std::shared_ptr<Actions>& actions_,
+ std::shared_ptr<State>& state_):
+ m_actions(actions_),
+ m_state(state_)
+{
+}
+
+std::shared_ptr<Menu>
+MenuFactory::buildMenu(Menu::Profile profile)
+{
+ std::shared_ptr<Menu> menu;
+ m_state->show_clock.set (true); // FIXME
+
+ //std::shared_ptr<State> state(new State);
+ //state->clock = clock;
+ //state->planner = planner;
+ //state->locations = locations;
+
+ switch (profile)
+ {
+ case Menu::Desktop:
+ m_state->show_events.set(true); // FIXME
+ menu.reset(new DesktopMenu(m_state, m_actions));
+ break;
+
+ case Menu::DesktopGreeter:
+ m_state->show_events.set(true); // FIXME
+ menu.reset(new DesktopGreeterMenu(m_state, m_actions));
+ break;
+
+ case Menu::Phone:
+ m_state->show_events.set(true); // FIXME
+ menu.reset(new PhoneMenu(m_state, m_actions));
+ break;
+
+ case Menu::PhoneGreeter:
+ m_state->show_events.set(false); // FIXME
+ menu.reset(new PhoneGreeterMenu(m_state, m_actions));
+ break;
+
+ default:
+ g_warn_if_reached();
+ break;
+ }
+
+ return menu;
+}
+
+/****
+*****
+****/
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
diff --git a/src/planner-eds.cpp b/src/planner-eds.cpp
index 804d98e..6abaf3e 100644
--- a/src/planner-eds.cpp
+++ b/src/planner-eds.cpp
@@ -34,21 +34,21 @@ namespace datetime {
*****
****/
-G_DEFINE_QUARK ("source-client", source_client)
+G_DEFINE_QUARK("source-client", source_client)
class PlannerEds::Impl
{
public:
- Impl (PlannerEds& owner):
- owner_(owner),
- cancellable_(g_cancellable_new())
+ Impl(PlannerEds& owner):
+ m_owner(owner),
+ m_cancellable(g_cancellable_new())
{
- e_source_registry_new (cancellable_, on_source_registry_ready, this);
+ e_source_registry_new(m_cancellable, on_source_registry_ready, this);
- owner_.time.changed().connect([this](const DateTime& dt) {
- g_message ("planner's datetime property changed to %s; calling rebuildSoon()", g_date_time_format(dt.get(), "%F %T"));
+ m_owner.time.changed().connect([this](const DateTime& dt) {
+ g_message("planner's datetime property changed to %s; calling rebuildSoon()", g_date_time_format(dt.get(), "%F %T"));
rebuildSoon();
});
@@ -57,46 +57,46 @@ public:
~Impl()
{
- g_cancellable_cancel (cancellable_);
- g_clear_object (&cancellable_);
+ g_cancellable_cancel(m_cancellable);
+ g_clear_object(&m_cancellable);
- if (rebuild_tag_)
- g_source_remove (rebuild_tag_);
+ if (m_rebuild_tag)
+ g_source_remove(m_rebuild_tag);
- if (source_registry_)
- g_signal_handlers_disconnect_by_data (source_registry_, this);
- g_clear_object (&source_registry_);
+ if (m_source_registry)
+ g_signal_handlers_disconnect_by_data(m_source_registry, this);
+ g_clear_object(&m_source_registry);
}
private:
- static void on_source_registry_ready (GObject* /*source*/, GAsyncResult* res, gpointer gself)
+ static void on_source_registry_ready(GObject* /*source*/, GAsyncResult* res, gpointer gself)
{
- GError * error = NULL;
- auto r = e_source_registry_new_finish (res, &error);
- if (error != NULL)
+ GError * error = nullptr;
+ auto r = e_source_registry_new_finish(res, &error);
+ if (error != nullptr)
{
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("indicator-datetime cannot show EDS appointments: %s", error->message);
+ if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning("indicator-datetime cannot show EDS appointments: %s", error->message);
- g_error_free (error);
+ g_error_free(error);
}
else
{
auto self = static_cast<Impl*>(gself);
- g_signal_connect (r, "source-added", G_CALLBACK(on_source_added), self);
- g_signal_connect (r, "source-removed", G_CALLBACK(on_source_removed), self);
- g_signal_connect (r, "source-changed", G_CALLBACK(on_source_changed), self);
- g_signal_connect (r, "source-disabled", G_CALLBACK(on_source_disabled), self);
- g_signal_connect (r, "source-enabled", G_CALLBACK(on_source_enabled), self);
+ g_signal_connect(r, "source-added", G_CALLBACK(on_source_added), self);
+ g_signal_connect(r, "source-removed", G_CALLBACK(on_source_removed), self);
+ g_signal_connect(r, "source-changed", G_CALLBACK(on_source_changed), self);
+ g_signal_connect(r, "source-disabled", G_CALLBACK(on_source_disabled), self);
+ g_signal_connect(r, "source-enabled", G_CALLBACK(on_source_enabled), self);
- self->source_registry_ = r;
+ self->m_source_registry = r;
- GList* sources = e_source_registry_list_sources (r, E_SOURCE_EXTENSION_CALENDAR);
+ GList* sources = e_source_registry_list_sources(r, E_SOURCE_EXTENSION_CALENDAR);
for (auto l=sources; l!=nullptr; l=l->next)
- on_source_added (r, E_SOURCE(l->data), gself);
- g_list_free_full (sources, g_object_unref);
+ on_source_added(r, E_SOURCE(l->data), gself);
+ g_list_free_full(sources, g_object_unref);
}
}
@@ -104,74 +104,74 @@ private:
{
auto self = static_cast<PlannerEds::Impl*>(gself);
- self->sources_.insert(E_SOURCE(g_object_ref(source)));
+ self->m_sources.insert(E_SOURCE(g_object_ref(source)));
if (e_source_get_enabled(source))
on_source_enabled(registry, source, gself);
}
- static void on_source_enabled (ESourceRegistry* /*registry*/, ESource* source, gpointer gself)
+ static void on_source_enabled(ESourceRegistry* /*registry*/, ESource* source, gpointer gself)
{
auto self = static_cast<PlannerEds::Impl*>(gself);
- e_cal_client_connect (source,
- E_CAL_CLIENT_SOURCE_TYPE_EVENTS,
- self->cancellable_,
- on_client_connected,
- gself);
+ e_cal_client_connect(source,
+ E_CAL_CLIENT_SOURCE_TYPE_EVENTS,
+ self->m_cancellable,
+ on_client_connected,
+ gself);
}
- static void on_client_connected (GObject* /*source*/, GAsyncResult * res, gpointer gself)
+ static void on_client_connected(GObject* /*source*/, GAsyncResult * res, gpointer gself)
{
GError * error = nullptr;
- EClient * client = e_cal_client_connect_finish (res, &error);
+ EClient * client = e_cal_client_connect_finish(res, &error);
if (error)
{
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("indicator-datetime cannot connect to EDS source: %s", error->message);
+ if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning("indicator-datetime cannot connect to EDS source: %s", error->message);
- g_error_free (error);
+ g_error_free(error);
}
else
{
// we've got a new connected ECalClient, so store it & notify clients
- g_object_set_qdata_full (G_OBJECT(e_client_get_source(client)),
- source_client_quark(),
- client,
- g_object_unref);
+ g_object_set_qdata_full(G_OBJECT(e_client_get_source(client)),
+ source_client_quark(),
+ client,
+ g_object_unref);
- g_message ("client connected; calling rebuildSoon()");
+ g_message("client connected; calling rebuildSoon()");
static_cast<Impl*>(gself)->rebuildSoon();
}
}
- static void on_source_disabled (ESourceRegistry* /*registry*/, ESource* source, gpointer gself)
+ static void on_source_disabled(ESourceRegistry* /*registry*/, ESource* source, gpointer gself)
{
gpointer e_cal_client;
// if this source has a connected ECalClient, remove it & notify clients
- if ((e_cal_client = g_object_steal_qdata (G_OBJECT(source), source_client_quark())))
+ if ((e_cal_client = g_object_steal_qdata(G_OBJECT(source), source_client_quark())))
{
- g_object_unref (e_cal_client);
+ g_object_unref(e_cal_client);
- g_message ("source disabled; calling rebuildSoon()");
+ g_message("source disabled; calling rebuildSoon()");
static_cast<Impl*>(gself)->rebuildSoon();
}
}
- static void on_source_removed (ESourceRegistry* registry, ESource* source, gpointer gself)
+ static void on_source_removed(ESourceRegistry* registry, ESource* source, gpointer gself)
{
auto self = static_cast<PlannerEds::Impl*>(gself);
- on_source_disabled (registry, source, gself);
+ on_source_disabled(registry, source, gself);
- self->sources_.erase (source);
- g_object_unref (source);
+ self->m_sources.erase(source);
+ g_object_unref(source);
}
- static void on_source_changed (ESourceRegistry* /*registry*/, ESource* /*source*/, gpointer gself)
+ static void on_source_changed(ESourceRegistry* /*registry*/, ESource* /*source*/, gpointer gself)
{
- g_message ("source changed; calling rebuildSoon()");
+ g_message("source changed; calling rebuildSoon()");
static_cast<Impl*>(gself)->rebuildSoon();
}
@@ -181,44 +181,44 @@ private:
struct Task
{
- Impl* impl_;
- appointment_func func_;
- std::vector<Appointment> appointments_;
- Task (Impl* impl, const appointment_func& func): impl_(impl), func_(func) {}
+ Impl* p;
+ appointment_func func;
+ std::vector<Appointment> appointments;
+ Task(Impl* p_in, const appointment_func& func_in): p(p_in), func(func_in) {}
};
struct AppointmentSubtask
{
- std::shared_ptr<Task> task_;
- ECalClient * client_;
- std::string color_;
- AppointmentSubtask (const std::shared_ptr<Task>& task, ECalClient* client, const char* color):
- task_(task), client_(client), color_(color) {}
+ std::shared_ptr<Task> task;
+ ECalClient* client;
+ std::string color;
+ AppointmentSubtask(const std::shared_ptr<Task>& task_in, ECalClient* client_in, const char* color_in):
+ task(task_in), client(client_in), color(color_in) {}
};
void rebuildSoon()
{
const static guint ARBITRARY_INTERVAL_SECS = 2;
- if (rebuild_tag_ == 0)
- rebuild_tag_ = g_timeout_add_seconds (ARBITRARY_INTERVAL_SECS, rebuildNowStatic, this);
+ if (m_rebuild_tag == 0)
+ m_rebuild_tag = g_timeout_add_seconds(ARBITRARY_INTERVAL_SECS, rebuildNowStatic, this);
}
- static gboolean rebuildNowStatic (gpointer gself)
+ static gboolean rebuildNowStatic(gpointer gself)
{
auto self = static_cast<Impl*>(gself);
- self->rebuild_tag_ = 0;
+ self->m_rebuild_tag = 0;
self->rebuildNow();
return G_SOURCE_REMOVE;
}
void rebuildNow()
{
- GDateTime* calendar_date = owner_.time.get().get();
+ auto calendar_date = m_owner.time.get().get();
GDateTime* begin;
GDateTime* end;
int y, m, d;
- g_message ("in rebuildNow");
+ g_message("in rebuildNow");
// get all the appointments in the calendar month
g_date_time_get_ymd(calendar_date, &y, &m, &d);
@@ -227,7 +227,7 @@ private:
if (begin && end)
{
getAppointments(begin, end, [this](const std::vector<Appointment>& appointments) {
- g_message ("got %d appointments in this calendar month", (int)appointments.size());
+ g_message("got %d appointments in this calendar month", (int)appointments.size());
});
}
g_clear_pointer(&begin, g_date_time_unref);
@@ -239,7 +239,7 @@ private:
if (begin && end)
{
getAppointments(begin, end, [this](const std::vector<Appointment>& appointments) {
- g_message ("got %d upcoming appointments", (int)appointments.size());
+ g_message("got %d upcoming appointments", (int)appointments.size());
});
}
g_clear_pointer(&begin, g_date_time_unref);
@@ -251,8 +251,8 @@ private:
{
const auto begin = g_date_time_to_unix(begin_dt);
const auto end = g_date_time_to_unix(end_dt);
- g_message ("getting all appointments from [%s ... %s]", g_date_time_format (begin_dt, "%F %T"),
- g_date_time_format (end_dt, "%F %T"));
+ g_message("getting all appointments from [%s ... %s]", g_date_time_format(begin_dt, "%F %T"),
+ g_date_time_format(end_dt, "%F %T"));
/**
*** init the default timezone
@@ -260,75 +260,76 @@ private:
icaltimezone * default_timezone = nullptr;
- const auto tz = g_date_time_get_timezone_abbreviation (owner_.time.get().get());
- g_message ("%s tz is %s", G_STRLOC, tz);
+ const auto tz = g_date_time_get_timezone_abbreviation(m_owner.time.get().get());
+ g_message("%s tz is %s", G_STRLOC, tz);
if (tz && *tz)
{
- default_timezone = icaltimezone_get_builtin_timezone (tz);
+ default_timezone = icaltimezone_get_builtin_timezone(tz);
if (default_timezone == nullptr) // maybe str is a tzid?
- default_timezone = icaltimezone_get_builtin_timezone_from_tzid (tz);
+ default_timezone = icaltimezone_get_builtin_timezone_from_tzid(tz);
- g_debug ("default_timezone is %p", default_timezone);
+ g_debug("default_timezone is %p", default_timezone);
}
/**
*** walk through the sources to build the appointment list
**/
- std::shared_ptr<Task> main_task (new Task(this, func), [](Task* task){
+ std::shared_ptr<Task> main_task(new Task(this, func), [](Task* task){
g_message("time to delete task %p", task);
- task->func_(task->appointments_);
+ task->func(task->appointments);
});
- for (auto& source : sources_)
+ for (auto& source : m_sources)
{
- auto client = E_CAL_CLIENT (g_object_get_qdata (G_OBJECT(source), source_client_quark()));
+ auto client = E_CAL_CLIENT(g_object_get_qdata(G_OBJECT(source), source_client_quark()));
if (client == nullptr)
continue;
if (default_timezone != nullptr)
- e_cal_client_set_default_timezone (client, default_timezone);
+ e_cal_client_set_default_timezone(client, default_timezone);
// start a new subtask to enumerate all the components in this client.
- auto extension = e_source_get_extension (source, E_SOURCE_EXTENSION_CALENDAR);
- const auto color = e_source_selectable_get_color (E_SOURCE_SELECTABLE(extension));
- g_message ("calling e_cal_client_generate_instances for %p", client);
- e_cal_client_generate_instances (client,
- begin,
- end,
- cancellable_,
- my_get_appointments_foreach,
- new AppointmentSubtask (main_task, client, color),
- [](gpointer g){delete static_cast<AppointmentSubtask*>(g);});
+ auto extension = e_source_get_extension(source, E_SOURCE_EXTENSION_CALENDAR);
+ const auto color = e_source_selectable_get_color(E_SOURCE_SELECTABLE(extension));
+ g_message("calling e_cal_client_generate_instances for %p", client);
+ e_cal_client_generate_instances(client,
+ begin,
+ end,
+ m_cancellable,
+ my_get_appointments_foreach,
+ new AppointmentSubtask (main_task, client, color),
+ [](gpointer g){delete static_cast<AppointmentSubtask*>(g);});
}
}
struct UrlSubtask
{
- std::shared_ptr<Task> task_;
- Appointment appointment_;
- UrlSubtask (const std::shared_ptr<Task>& task, const Appointment& appointment): task_(task), appointment_(appointment) {}
+ std::shared_ptr<Task> task;
+ Appointment appointment;
+ UrlSubtask(const std::shared_ptr<Task>& task_in, const Appointment& appointment_in):
+ task(task_in), appointment(appointment_in) {}
};
static gboolean
- my_get_appointments_foreach (ECalComponent* component,
- time_t begin,
- time_t end,
- gpointer gsubtask)
+ my_get_appointments_foreach(ECalComponent* component,
+ time_t begin,
+ time_t end,
+ gpointer gsubtask)
{
const auto vtype = e_cal_component_get_vtype(component);
auto subtask = static_cast<AppointmentSubtask*>(gsubtask);
if ((vtype == E_CAL_COMPONENT_EVENT) || (vtype == E_CAL_COMPONENT_TODO))
{
- const gchar* uid = NULL;
- e_cal_component_get_uid (component, &uid);
+ const gchar* uid = nullptr;
+ e_cal_component_get_uid(component, &uid);
auto status = ICAL_STATUS_NONE;
- e_cal_component_get_status (component, &status);
+ e_cal_component_get_status(component, &status);
- if ((uid != NULL) &&
+ if ((uid != nullptr) &&
(status != ICAL_STATUS_COMPLETED) &&
(status != ICAL_STATUS_CANCELLED))
{
@@ -339,78 +340,78 @@ private:
however, since design only allows daily recurrence,
that's all we support here. */
GSList * recur_list;
- e_cal_component_get_rrule_list (component, &recur_list);
- for (auto l=recur_list; l!=NULL; l=l->next)
+ e_cal_component_get_rrule_list(component, &recur_list);
+ for (auto l=recur_list; l!=nullptr; l=l->next)
{
const auto recur = static_cast<struct icalrecurrencetype*>(l->data);
appointment.is_daily |= ((recur->freq == ICAL_DAILY_RECURRENCE)
&& (recur->interval == 1));
}
- e_cal_component_free_recur_list (recur_list);
+ e_cal_component_free_recur_list(recur_list);
ECalComponentText text;
text.value = "";
- e_cal_component_get_summary (component, &text);
+ e_cal_component_get_summary(component, &text);
- appointment.begin = g_date_time_new_from_unix_local (begin);
- appointment.end = g_date_time_new_from_unix_local (end);
- appointment.color = subtask->color_;
+ appointment.begin = g_date_time_new_from_unix_local(begin);
+ appointment.end = g_date_time_new_from_unix_local(end);
+ appointment.color = subtask->color;
appointment.is_event = vtype == E_CAL_COMPONENT_EVENT;
appointment.summary = text.value;
appointment.uid = uid;
- GList * alarm_uids = e_cal_component_get_alarm_uids (component);
+ GList * alarm_uids = e_cal_component_get_alarm_uids(component);
appointment.has_alarms = alarm_uids != nullptr;
- cal_obj_uid_list_free (alarm_uids);
-
- e_cal_client_get_attachment_uris (subtask->client_,
- uid,
- NULL,
- subtask->task_->impl_->cancellable_,
- on_appointment_uris_ready,
- new UrlSubtask(subtask->task_, appointment));
+ cal_obj_uid_list_free(alarm_uids);
+
+ e_cal_client_get_attachment_uris(subtask->client,
+ uid,
+ nullptr,
+ subtask->task->p->m_cancellable,
+ on_appointment_uris_ready,
+ new UrlSubtask(subtask->task, appointment));
}
}
return G_SOURCE_CONTINUE;
}
- static void on_appointment_uris_ready (GObject* client, GAsyncResult* res, gpointer gsubtask)
+ static void on_appointment_uris_ready(GObject* client, GAsyncResult* res, gpointer gsubtask)
{
auto subtask = static_cast<UrlSubtask*>(gsubtask);
GSList * uris = nullptr;
GError * error = nullptr;
- e_cal_client_get_attachment_uris_finish (E_CAL_CLIENT(client), res, &uris, &error);
- if (error != NULL)
+ e_cal_client_get_attachment_uris_finish(E_CAL_CLIENT(client), res, &uris, &error);
+ if (error != nullptr)
{
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("Error getting appointment uris: %s", error->message);
+ if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning("Error getting appointment uris: %s", error->message);
- g_error_free (error);
+ g_error_free(error);
}
- else if (uris != NULL)
+ else if (uris != nullptr)
{
- subtask->appointment_.url = (const char*) uris->data; // copy the first URL
- g_debug ("found url '%s' for appointment '%s'", subtask->appointment_.url.c_str(), subtask->appointment_.summary.c_str());
- e_client_util_free_string_slist (uris);
+ subtask->appointment.url = (const char*) uris->data; // copy the first URL
+ g_debug("found url '%s' for appointment '%s'", subtask->appointment.url.c_str(), subtask->appointment.summary.c_str());
+ e_client_util_free_string_slist(uris);
}
- g_message ("adding appointment '%s' '%s'", subtask->appointment_.summary.c_str(), subtask->appointment_.url.c_str());
- subtask->task_->appointments_.push_back (subtask->appointment_);
+ g_message("adding appointment '%s' '%s'", subtask->appointment.summary.c_str(), subtask->appointment.url.c_str());
+ subtask->task->appointments.push_back(subtask->appointment);
delete subtask;
}
private:
- PlannerEds& owner_;
- std::set<ESource*> sources_;
- GCancellable * cancellable_ = nullptr;
- ESourceRegistry * source_registry_ = nullptr;
- guint rebuild_tag_ = 0;
+ PlannerEds& m_owner;
+ std::set<ESource*> m_sources;
+ GCancellable * m_cancellable = nullptr;
+ ESourceRegistry * m_source_registry = nullptr;
+ guint m_rebuild_tag = 0;
};
-PlannerEds::PlannerEds(): impl_(new Impl(*this)) {}
+PlannerEds::PlannerEds(): p(new Impl(*this)) {}
PlannerEds::~PlannerEds() =default;
diff --git a/src/planner-eds.h b/src/planner-eds.h
deleted file mode 100644
index dea9371..0000000
--- a/src/planner-eds.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2013 Canonical Ltd.
- *
- * Authors:
- * Charles Kerr <charles.kerr@canonical.com>
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 3, as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranties of
- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __INDICATOR_DATETIME_PLANNER_EDS__H__
-#define __INDICATOR_DATETIME_PLANNER_EDS__H__
-
-#include "planner.h" /* parent class */
-
-G_BEGIN_DECLS
-
-#define INDICATOR_TYPE_DATETIME_PLANNER_EDS (indicator_datetime_planner_eds_get_type())
-#define INDICATOR_DATETIME_PLANNER_EDS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_PLANNER_EDS, IndicatorDatetimePlannerEds))
-#define INDICATOR_DATETIME_PLANNER_EDS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_DATETIME_PLANNER_EDS, IndicatorDatetimePlannerEdsClass))
-#define INDICATOR_IS_DATETIME_PLANNER_EDS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_DATETIME_PLANNER_EDS))
-
-typedef struct _IndicatorDatetimePlannerEds IndicatorDatetimePlannerEds;
-typedef struct _IndicatorDatetimePlannerEdsPriv IndicatorDatetimePlannerEdsPriv;
-typedef struct _IndicatorDatetimePlannerEdsClass IndicatorDatetimePlannerEdsClass;
-
-GType indicator_datetime_planner_eds_get_type (void);
-
-/**
- * An IndicatorDatetimePlanner which uses Evolution Data Server
- * to get its list of appointments.
- */
-struct _IndicatorDatetimePlannerEds
-{
- /*< private >*/
- IndicatorDatetimePlanner parent;
- IndicatorDatetimePlannerEdsPriv * priv;
-};
-
-struct _IndicatorDatetimePlannerEdsClass
-{
- IndicatorDatetimePlannerClass parent_class;
-};
-
-IndicatorDatetimePlanner * indicator_datetime_planner_eds_new (void);
-
-G_END_DECLS
-
-#endif /* __INDICATOR_DATETIME_PLANNER_EDS__H__ */
diff --git a/src/planner.h b/src/planner.h
deleted file mode 100644
index ffe8937..0000000
--- a/src/planner.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2013 Canonical Ltd.
- *
- * Authors:
- * Charles Kerr <charles.kerr@canonical.com>
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 3, as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranties of
- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __INDICATOR_DATETIME_PLANNER__H__
-#define __INDICATOR_DATETIME_PLANNER__H__
-
-#include <glib.h>
-#include <glib-object.h> /* parent class */
-#include <gio/gio.h>
-
-G_BEGIN_DECLS
-
-#define INDICATOR_TYPE_DATETIME_PLANNER (indicator_datetime_planner_get_type())
-#define INDICATOR_DATETIME_PLANNER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_PLANNER, IndicatorDatetimePlanner))
-#define INDICATOR_DATETIME_PLANNER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_DATETIME_PLANNER, IndicatorDatetimePlannerClass))
-#define INDICATOR_DATETIME_PLANNER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), INDICATOR_TYPE_DATETIME_PLANNER, IndicatorDatetimePlannerClass))
-#define INDICATOR_IS_DATETIME_PLANNER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_DATETIME_PLANNER))
-
-typedef struct _IndicatorDatetimePlanner IndicatorDatetimePlanner;
-typedef struct _IndicatorDatetimePlannerPriv IndicatorDatetimePlannerPriv;
-typedef struct _IndicatorDatetimePlannerClass IndicatorDatetimePlannerClass;
-
-GType indicator_datetime_planner_get_type (void);
-
-struct IndicatorDatetimeAppt
-{
- gchar * color;
- gchar * summary;
- gchar * url;
- gchar * uid;
- GDateTime * begin;
- GDateTime * end;
- gboolean is_event;
- gboolean is_daily;
- gboolean has_alarms;
-};
-
-/**
- * Abstract Base Class for objects that provides appointments and events.
- *
- * These will be listed in the appointments section of indicator-datetime's menu.
- */
-struct _IndicatorDatetimePlanner
-{
- /*< private >*/
- GObject parent;
- IndicatorDatetimePlannerPriv * priv;
-};
-
-struct _IndicatorDatetimePlannerClass
-{
- GObjectClass parent_class;
-
- /* signals */
-
- void (*appointments_changed) (IndicatorDatetimePlanner * self);
-
- /* virtual functions */
-
- void (*get_appointments) (IndicatorDatetimePlanner * self,
- GDateTime * begin,
- GDateTime * end,
- GAsyncReadyCallback callback,
- gpointer user_data);
-
- GSList* (*get_appointments_finish) (IndicatorDatetimePlanner * self,
- GAsyncResult * res,
- GError ** error);
-
-
- gboolean (*is_configured) (IndicatorDatetimePlanner * self);
- void (*activate) (IndicatorDatetimePlanner * self);
- void (*activate_time) (IndicatorDatetimePlanner * self, GDateTime *);
-};
-
-/***
-****
-***/
-
-void indicator_datetime_appt_free (struct IndicatorDatetimeAppt * appt);
-
-/**
- * Get a list of appointments, sorted by start time.
- */
-void indicator_datetime_planner_get_appointments (IndicatorDatetimePlanner * self,
- GDateTime * begin,
- GDateTime * end,
- GAsyncReadyCallback callback,
- gpointer user_data);
-
-/**
- * Finishes the async call begun with indicator_datetime_planner_get_appointments()
- *
- * To free the list properly, use indicator_datetime_planner_free_appointments()
- *
- * Return value: (element-type IndicatorDatetimeAppt)
- * (transfer full):
- * list of appointments
- */
-GSList * indicator_datetime_planner_get_appointments_finish (IndicatorDatetimePlanner * self,
- GAsyncResult * res,
- GError ** error);
-
-/**
- * Convenience function for freeing a GSList of IndicatorDatetimeAppt.
- *
- * Equivalent to g_slist_free_full (list, (GDestroyNotify)indicator_datetime_appt_free);
- */
-void indicator_datetime_planner_free_appointments (GSList *);
-
-
-/**
- * Returns false if the planner's backend is not configured.
- *
- * This can be used on startup to determine whether or not to use this planner.
- */
-gboolean indicator_datetime_planner_is_configured (IndicatorDatetimePlanner * self);
-
-/**
- * Activate this planner.
- *
- * This is used to activate the planner's backend's event editor.
- */
-void indicator_datetime_planner_activate (IndicatorDatetimePlanner * self);
-
-/**
- * Activate this planner.
- *
- * This is used to activate the planner's backend's event editor,
- * with an added hint of the specific time that the user would like to edit.
- */
-void indicator_datetime_planner_activate_time (IndicatorDatetimePlanner * self, GDateTime * time);
-
-/**
- * Set the timezone.
- *
- * This is used as a default timezone if the backend's events don't provide their own.
- */
-void indicator_datetime_planner_set_timezone (IndicatorDatetimePlanner * self, const char * timezone);
-
-const char * indicator_datetime_planner_get_timezone (IndicatorDatetimePlanner * self);
-
-
-/**
- * Emits the "appointments-changed" signal. This should only be called by subclasses.
- */
-void indicator_datetime_planner_emit_appointments_changed (IndicatorDatetimePlanner * self);
-
-G_END_DECLS
-
-#endif /* __INDICATOR_DATETIME_PLANNER__H__ */
diff --git a/src/service.cpp b/src/service.cpp
new file mode 100644
index 0000000..0671c61
--- /dev/null
+++ b/src/service.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#include <datetime/service.h>
+#include <datetime/dbus-shared.h>
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/***
+****
+***/
+
+Service::~Service()
+{
+ if (m_dbus_connection != nullptr)
+ {
+ for(auto& id : m_exported_menu_ids)
+ g_dbus_connection_unexport_menu_model(m_dbus_connection, id);
+
+ if (m_exported_actions_id)
+ g_dbus_connection_unexport_action_group(m_dbus_connection, m_exported_actions_id);
+ }
+
+ if (m_own_id)
+ g_bus_unown_name(m_own_id);
+
+ g_clear_object(&m_dbus_connection);
+}
+
+/***
+****
+***/
+
+void
+Service::on_bus_acquired(GDBusConnection* connection, const gchar* name, gpointer gthis)
+{
+ g_debug("bus acquired: %s", name);
+ static_cast<Service*>(gthis)->on_bus_acquired(connection, name);
+}
+
+void
+Service::on_bus_acquired(GDBusConnection* connection, const gchar* /*name*/)
+{
+ m_dbus_connection = static_cast<GDBusConnection*>(g_object_ref(G_OBJECT(connection)));
+
+ // export the actions
+ GError * error = nullptr;
+ const auto id = g_dbus_connection_export_action_group(m_dbus_connection, BUS_PATH, m_actions, &error);
+ if (id)
+ {
+ m_exported_actions_id = id;
+ }
+ else
+ {
+ g_warning("cannot export action group: %s", error->message);
+ g_clear_error(&error);
+ }
+
+ // export the menus
+ for(auto& menu : m_menus)
+ {
+ const auto path = std::string(BUS_PATH) + "/" + menu->name();
+ const auto id = g_dbus_connection_export_menu_model(m_dbus_connection, path.c_str(), menu->menu_model(), &error);
+ if (id)
+ {
+ m_exported_menu_ids.insert(id);
+ }
+ else
+ {
+ g_warning("cannot export %s menu: %s", menu->name().c_str(), error->message);
+ g_clear_error(&error);
+ }
+ }
+}
+
+/***
+****
+***/
+
+void
+Service::on_name_lost(GDBusConnection* connection, const gchar* name, gpointer gthis)
+{
+ g_debug("name lost: %s", name);
+ static_cast<Service*>(gthis)->on_name_lost(connection, name);
+}
+
+void
+Service::on_name_lost(GDBusConnection* /*connection*/, const gchar* /*name*/)
+{
+ name_lost();
+}
+
+/***
+****
+***/
+
+void
+Service::publish(GActionGroup* actions, std::vector<std::shared_ptr<Menu>>& menus)
+{
+ m_actions = actions;
+ m_menus = menus;
+ m_own_id = g_bus_own_name(G_BUS_TYPE_SESSION,
+ BUS_NAME,
+ G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
+ on_bus_acquired,
+ nullptr,
+ on_name_lost,
+ this,
+ nullptr);
+}
+
+/***
+****
+***/
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
diff --git a/src/settings-live.cpp b/src/settings-live.cpp
new file mode 100644
index 0000000..74085a9
--- /dev/null
+++ b/src/settings-live.cpp
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#include <datetime/settings-live.h>
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/***
+****
+***/
+
+LiveSettings::~LiveSettings()
+{
+ g_clear_object(&m_settings);
+}
+
+LiveSettings::LiveSettings():
+ m_settings(g_settings_new(SETTINGS_INTERFACE))
+{
+ g_signal_connect (m_settings, "changed", G_CALLBACK(on_changed), this);
+
+ update_show_clock();
+}
+
+void LiveSettings::update_show_clock()
+{
+ auto val = g_settings_get_boolean(m_settings, SETTINGS_SHOW_CLOCK_S);
+ show_clock.set(val);
+}
+
+void LiveSettings::on_changed(GSettings* /*settings*/,
+ gchar* key,
+ gpointer gself)
+{
+ static_cast<LiveSettings*>(gself)->update_key(key);
+}
+
+void LiveSettings::update_key(const std::string& key)
+{
+ if (key == SETTINGS_SHOW_CLOCK_S)
+ {
+ update_show_clock();
+ }
+}
+
+/***
+****
+***/
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
+#if 0
+ else if (!g_strcmp0(key, TIME_FORMAT_S))
+ {
+ }
+ else if (!g_strcmp0(key, SETTINGS_TIME_FORMAT_S))
+ {
+ }
+ else if (!g_strcmp0(key, SETTINGS_SHOW_SECONDS_S))
+ {
+ }
+ else if (!g_strcmp0(key, SETTINGS_SHOW_DAY_S))
+ {
+ }
+ else if (!g_strcmp0(key, SETTINGS_SHOW_DATE_S))
+ {
+ }
+ else if (!g_strcmp0(key, SETTINGS_SHOW_YEAR_S))
+ {
+ }
+ else if (!g_strcmp0(key, SETTINGS_SHOW_CUSTOM_TIME_FORMAT_S))
+ {
+ }
+ else if (!g_strcmp0(key, SETTINGS_SHOW_CALENDAR_S))
+ {
+ }
+ else if (!g_strcmp0(key, SETTINGS_SHOW_WEEK_NUMBERS_S))
+ {
+ }
+ else if (!g_strcmp0(key, SETTINGS_SHOW_EVENTS_S))
+ {
+ }
+ else if (!g_strcmp0(key, SETTINGS_SHOW_LOCATIONS_S))
+ {
+ }
+ else if (!g_strcmp0(key, SETTINGS_TIMEZONE_NAME_S))
+ {
+ }
+ else if (!g_strcmp0(key, SETTINGS_SHOW_DETECTED_S))
+ {
+ }
+ else if (!g_strcmp0(key, SETTINGS_LOCATIONS_S))
+ {
+ }
+#define SETTINGS_SHOW_DETECTED_S "show-auto-detected-location"
+#define SETTINGS_LOCATIONS_S "locations"
+#define SETTINGS_TIMEZONE_NAME_S "timezone-name"
+ zzz
+ "show-clock"
+
+void user_function (GSettings *settings,
+ gchar *key,
+ gpointer user_data) : Has Details
+
+ for (i=0, n=G_N_ELEMENTS(header_settings); i<n; i++)
+ {
+ g_string_printf (gstr, "changed::%s", header_settings[i]);
+ g_signal_connect_swapped (p->settings, gstr->str,
+ G_CALLBACK(rebuild_header_soon), self);
+ }
+
+
+ const char * const calendar_settings[] = {
+ SETTINGS_SHOW_CALENDAR_S,
+ SETTINGS_SHOW_WEEK_NUMBERS_S
+ };
+ const char * const appointment_settings[] = {
+ SETTINGS_SHOW_EVENTS_S,
+ SETTINGS_TIME_FORMAT_S,
+ SETTINGS_SHOW_SECONDS_S
+ };
+ const char * const location_settings[] = {
+ SETTINGS_TIME_FORMAT_S,
+ SETTINGS_SHOW_SECONDS_S,
+ SETTINGS_CUSTOM_TIME_FORMAT_S,
+ SETTINGS_SHOW_LOCATIONS_S,
+ SETTINGS_LOCATIONS_S,
+ SETTINGS_SHOW_DETECTED_S,
+ SETTINGS_TIMEZONE_NAME_S
+ };
+ const char * const time_format_string_settings[] = {
+ SETTINGS_TIME_FORMAT_S,
+ SETTINGS_SHOW_SECONDS_S,
+ SETTINGS_CUSTOM_TIME_FORMAT_S
+ };
+
+
+ /***
+ **** Listen for settings changes
+ ***/
+
+ for (i=0, n=G_N_ELEMENTS(header_settings); i<n; i++)
+ {
+ g_string_printf (gstr, "changed::%s", header_settings[i]);
+ g_signal_connect_swapped (p->settings, gstr->str,
+ G_CALLBACK(rebuild_header_soon), self);
+ }
+
+}
+
+
+#ifndef INDICATOR_DATETIME_SETTINGS_LIVE_H
+#define INDICATOR_DATETIME_SETTINGS_LIVE_H
+
+#include <datetime/settings.h> // parent class
+
+#include <glib.h> // GSettings
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/**
+ * \brief #Settings implementation which uses GSettings.
+ */
+class LiveSettings
+{
+public:
+ LiveSettings();
+ virtual ~LiveSettings();
+
+private:
+ GSettings* m_settings;
+
+ // we've got a raw pointer here, so disable copying
+ LiveSettings(const LiveSettings&) =delete;
+ LiveSettings& operator=(const LiveSettings&) =delete;
+};
+
+
+#endif // INDICATOR_DATETIME_SETTINGS_LIVE_H
+/*
+ * Copyright 2010 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Ted Gould <ted@canonical.com>
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#ifndef INDICATOR_DATETIME_SETTINGS_SHARED
+#define INDICATOR_DATETIME_SETTINGS_SHARED
+
+typedef enum
+{
+ TIME_FORMAT_MODE_LOCALE_DEFAULT,
+ TIME_FORMAT_MODE_12_HOUR,
+ TIME_FORMAT_MODE_24_HOUR,
+ TIME_FORMAT_MODE_CUSTOM
+}
+TimeFormatMode;
+
+
+#endif // INDICATOR_DATETIME_SETTINGS_SHARED
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#ifndef INDICATOR_DATETIME_SETTINGS_H
+#define INDICATOR_DATETIME_SETTINGS_H
+
+#include <datetime/settings-shared.h>
+
+#include <core/property.h>
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+/**
+ * \brief Interface that represents user-configurable settings.
+ *
+ * See the descriptions in data/com.canonical.indicator.datetime.gschema.xml
+ * For more information.
+ */
+class Settings
+{
+public:
+ Settings() =default;
+ virtual ~Settings =default;
+
+ core::Property<TimeFormatMode> time_format_mode;
+ core::Property<bool> show_clock;
+ core::Property<bool> show_day;
+ core::Property<bool> show_year;
+ core::Property<bool> show_seconds;
+ core::Property<std::string> custom_time_format;
+ core::Property<bool> show_calendar;
+ core::Property<bool> show_events;
+ core::Property<bool> show_locations;
+ core::Property<bool> show_auto_detected_location;
+ core::Property<std::vector<std::string>> locations;
+ core::Property<std::string> timezone_name;
+};
+
+#endif // INDICATOR_DATETIME_SETTINGS_H
+#endif
diff --git a/src/timezone-file.cpp b/src/timezone-file.cpp
index f1d0dca..3a0c240 100644
--- a/src/timezone-file.cpp
+++ b/src/timezone-file.cpp
@@ -26,12 +26,12 @@ namespace datetime {
void
FileTimezone::clear()
{
- if (monitor_handler_id_)
- g_signal_handler_disconnect(monitor_, monitor_handler_id_);
+ if (m_monitor_handler_id)
+ g_signal_handler_disconnect(m_monitor, m_monitor_handler_id);
- g_clear_object (&monitor_);
+ g_clear_object (&m_monitor);
- filename_.clear();
+ m_filename.clear();
}
void
@@ -39,11 +39,11 @@ FileTimezone::setFilename(const std::string& filename)
{
clear();
- filename_ = filename;
+ m_filename = filename;
auto file = g_file_new_for_path(filename.c_str());
GError * err = nullptr;
- monitor_ = g_file_monitor_file(file, G_FILE_MONITOR_NONE, nullptr, &err);
+ m_monitor = g_file_monitor_file(file, G_FILE_MONITOR_NONE, nullptr, &err);
g_object_unref(file);
if (err)
{
@@ -52,7 +52,7 @@ FileTimezone::setFilename(const std::string& filename)
}
else
{
- monitor_handler_id_ = g_signal_connect_swapped(monitor_, "changed", G_CALLBACK(onFileChanged), this);
+ m_monitor_handler_id = g_signal_connect_swapped(m_monitor, "changed", G_CALLBACK(onFileChanged), this);
g_debug("%s Monitoring timezone file '%s'", G_STRLOC, filename.c_str());
}
@@ -71,9 +71,9 @@ FileTimezone::reload()
GError * err = nullptr;
gchar * str = nullptr;
- if (!g_file_get_contents(filename_.c_str(), &str, nullptr, &err))
+ if (!g_file_get_contents(m_filename.c_str(), &str, nullptr, &err))
{
- g_warning("%s Unable to read timezone file '%s': %s", G_STRLOC, filename_.c_str(), err->message);
+ g_warning("%s Unable to read timezone file '%s': %s", G_STRLOC, m_filename.c_str(), err->message);
g_error_free(err);
}
else
diff --git a/src/timezone-geoclue.cpp b/src/timezone-geoclue.cpp
index f6d1f5e..b8847a4 100644
--- a/src/timezone-geoclue.cpp
+++ b/src/timezone-geoclue.cpp
@@ -27,20 +27,20 @@ namespace datetime {
GeoclueTimezone::GeoclueTimezone():
- cancellable_(g_cancellable_new())
+ m_cancellable(g_cancellable_new())
{
- g_bus_get(G_BUS_TYPE_SESSION, cancellable_, on_bus_got, this);
+ g_bus_get(G_BUS_TYPE_SESSION, m_cancellable, on_bus_got, this);
}
GeoclueTimezone::~GeoclueTimezone()
{
- g_cancellable_cancel(cancellable_);
- g_object_unref(cancellable_);
+ g_cancellable_cancel(m_cancellable);
+ g_object_unref(m_cancellable);
- if (signal_subscription_)
- g_dbus_connection_signal_unsubscribe(connection_, signal_subscription_);
+ if (m_signal_subscription)
+ g_dbus_connection_signal_unsubscribe(m_connection, m_signal_subscription);
- g_object_unref(connection_);
+ g_object_unref(m_connection);
}
/***
@@ -48,7 +48,9 @@ GeoclueTimezone::~GeoclueTimezone()
***/
void
-GeoclueTimezone::on_bus_got(GObject * source G_GNUC_UNUSED, GAsyncResult * res, gpointer gself)
+GeoclueTimezone::on_bus_got(GObject* /*source*/,
+ GAsyncResult* res,
+ gpointer gself)
{
GError * error;
GDBusConnection * connection;
@@ -66,9 +68,9 @@ GeoclueTimezone::on_bus_got(GObject * source G_GNUC_UNUSED, GAsyncResult * res,
{
auto self = static_cast<GeoclueTimezone*>(gself);
- self->connection_ = connection;
+ self->m_connection = connection;
- g_dbus_connection_call(self->connection_,
+ g_dbus_connection_call(self->m_connection,
GEOCLUE_BUS_NAME,
"/org/freedesktop/Geoclue/Master",
"org.freedesktop.Geoclue.Master",
@@ -77,7 +79,7 @@ GeoclueTimezone::on_bus_got(GObject * source G_GNUC_UNUSED, GAsyncResult * res,
G_VARIANT_TYPE("(o)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
- self->cancellable_,
+ self->m_cancellable,
on_client_created,
self);
}
@@ -93,51 +95,51 @@ GeoclueTimezone::on_client_created(GObject * source, GAsyncResult * res, gpointe
auto self = static_cast<GeoclueTimezone*>(gself);
GVariant * child = g_variant_get_child_value(result, 0);
- self->client_object_path_ = g_variant_get_string(child, nullptr);
+ self->m_client_object_path = g_variant_get_string(child, nullptr);
g_variant_unref(child);
g_variant_unref(result);
- self->signal_subscription_ = g_dbus_connection_signal_subscribe(
- self->connection_,
+ self->m_signal_subscription = g_dbus_connection_signal_subscribe(
+ self->m_connection,
GEOCLUE_BUS_NAME,
"org.freedesktop.Geoclue.Address", // inteface
"AddressChanged", // signal name
- self->client_object_path_.c_str(), // object path
+ self->m_client_object_path.c_str(), // object path
nullptr, // arg0
G_DBUS_SIGNAL_FLAGS_NONE,
on_address_changed,
self,
nullptr);
- g_dbus_connection_call(self->connection_,
+ g_dbus_connection_call(self->m_connection,
GEOCLUE_BUS_NAME,
- self->client_object_path_.c_str(),
+ self->m_client_object_path.c_str(),
"org.freedesktop.Geoclue.MasterClient",
"SetRequirements",
g_variant_new("(iibi)", 2, 0, FALSE, 1023),
nullptr,
G_DBUS_CALL_FLAGS_NONE,
-1,
- self->cancellable_,
+ self->m_cancellable,
on_requirements_set,
self);
}
}
void
-GeoclueTimezone::on_address_changed(GDBusConnection * connection G_GNUC_UNUSED,
- const gchar * sender_name G_GNUC_UNUSED,
- const gchar * object_path G_GNUC_UNUSED,
- const gchar * interface_name G_GNUC_UNUSED,
- const gchar * signal_name G_GNUC_UNUSED,
- GVariant * parameters,
- gpointer gself)
+GeoclueTimezone::on_address_changed(GDBusConnection* /*connection*/,
+ const gchar* /*sender_name*/,
+ const gchar* /*object_path*/,
+ const gchar* /*interface_name*/,
+ const gchar* /*signal_name*/,
+ GVariant* parameters,
+ gpointer gself)
{
static_cast<GeoclueTimezone*>(gself)->setTimezoneFromAddressVariant(parameters);
}
void
-GeoclueTimezone::on_requirements_set(GObject * source, GAsyncResult * res, gpointer gself)
+GeoclueTimezone::on_requirements_set(GObject* source, GAsyncResult* res, gpointer gself)
{
GVariant * result;
@@ -145,16 +147,16 @@ GeoclueTimezone::on_requirements_set(GObject * source, GAsyncResult * res, gpoin
{
auto self = static_cast<GeoclueTimezone*>(gself);
- g_dbus_connection_call(self->connection_,
+ g_dbus_connection_call(self->m_connection,
GEOCLUE_BUS_NAME,
- self->client_object_path_.c_str(),
+ self->m_client_object_path.c_str(),
"org.freedesktop.Geoclue.MasterClient",
"AddressStart",
nullptr,
nullptr,
G_DBUS_CALL_FLAGS_NONE,
-1,
- self->cancellable_,
+ self->m_cancellable,
on_address_started,
self);
@@ -171,16 +173,16 @@ GeoclueTimezone::on_address_started(GObject * source, GAsyncResult * res, gpoint
{
auto self = static_cast<GeoclueTimezone*>(gself);
- g_dbus_connection_call(self->connection_,
+ g_dbus_connection_call(self->m_connection,
GEOCLUE_BUS_NAME,
- self->client_object_path_.c_str(),
+ self->m_client_object_path.c_str(),
"org.freedesktop.Geoclue.Address",
"GetAddress",
nullptr,
G_VARIANT_TYPE("(ia{ss}(idd))"),
G_DBUS_CALL_FLAGS_NONE,
-1,
- self->cancellable_,
+ self->m_cancellable,
on_address_got,
self);
diff --git a/src/timezones-live.cpp b/src/timezones-live.cpp
index cb5e2bc..dc14021 100644
--- a/src/timezones-live.cpp
+++ b/src/timezones-live.cpp
@@ -24,37 +24,35 @@ namespace unity {
namespace indicator {
namespace datetime {
-LiveTimezones::LiveTimezones (const std::string& filename):
- file_ (filename)
+LiveTimezones::LiveTimezones(const std::string& filename):
+ m_file(filename)
{
- file_.timezone.changed().connect([this](const std::string&){updateTimezones();});
+ m_file.timezone.changed().connect([this](const std::string&){update_timezones();});
- geolocationEnabled.changed().connect([this](bool){updateGeolocation();});
- updateGeolocation();
+ geolocation_enabled.changed().connect([this](bool){update_geolocation();});
+ update_geolocation();
- updateTimezones();
+ update_timezones();
}
-void
-LiveTimezones::updateGeolocation()
+void LiveTimezones::update_geolocation()
{
- geo_.reset();
+ m_geo.reset();
- if (geolocationEnabled.get())
+ if(geolocation_enabled.get())
{
- GeoclueTimezone * geo = new GeoclueTimezone();
- geo->timezone.changed().connect([this](const std::string&){updateTimezones();});
- geo_.reset(geo);
+ auto geo = new GeoclueTimezone();
+ geo->timezone.changed().connect([this](const std::string&){update_timezones();});
+ m_geo.reset(geo);
}
}
-void
-LiveTimezones::updateTimezones()
+void LiveTimezones::update_timezones()
{
- const std::string a = file_.timezone.get();
- const std::string b = geo_ ? geo_->timezone.get() : "";
+ const auto a = m_file.timezone.get();
+ const auto b = m_geo ? m_geo->timezone.get() : "";
- timezone.set (a.empty() ? b : a);
+ timezone.set(a.empty() ? b : a);
std::set<std::string> zones;
if (!a.empty())
diff --git a/src/utils.cpp b/src/utils.cpp
index 42e034e..acd9796 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -37,104 +37,101 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
/* Check the system locale setting to see if the format is 24-hour
time or 12-hour time */
gboolean
-is_locale_12h (void)
+is_locale_12h()
{
- static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k", NULL};
- const char *t_fmt = nl_langinfo (T_FMT);
- int i;
+ const char *t_fmt = nl_langinfo(T_FMT);
- for (i = 0; formats_24h[i]; ++i) {
- if (strstr (t_fmt, formats_24h[i])) {
- return FALSE;
- }
- }
+ static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k"};
+ for(const auto& format : formats_24h)
+ if(strstr(t_fmt, format) != nullptr)
+ return false;
- return TRUE;
+ return true;
}
void
-split_settings_location (const gchar * location, gchar ** zone, gchar ** name)
+split_settings_location(const gchar* location, gchar** zone, gchar** name)
{
- gchar * location_dup;
- gchar * first;
+ auto location_dup = g_strdup(location);
+ g_strstrip(location_dup);
- location_dup = g_strdup (location);
- g_strstrip (location_dup);
+ gchar* first;
+ if((first = strchr(location_dup, ' ')))
+ *first = '\0';
- if ((first = strchr (location_dup, ' ')))
- *first = '\0';
-
- if (zone != NULL)
+ if(zone)
{
- *zone = location_dup;
+ *zone = location_dup;
}
- if (name != NULL)
+ if(name != nullptr)
{
- gchar * after = first ? g_strstrip (first + 1) : NULL;
+ gchar* after = first ? g_strstrip(first + 1) : nullptr;
- if (after && *after)
+ if(after && *after)
{
- *name = g_strdup (after);
+ *name = g_strdup(after);
}
- else /* make the name from zone */
+ else // make the name from zone
{
- gchar * chr = strrchr (location_dup, '/');
- after = g_strdup (chr ? chr + 1 : location_dup);
+ gchar * chr = strrchr(location_dup, '/');
+ after = g_strdup(chr ? chr + 1 : location_dup);
- /* replace underscores with spaces */
- for (chr=after; chr && *chr; chr++)
- if (*chr == '_')
- *chr = ' ';
+ // replace underscores with spaces
+ for(chr=after; chr && *chr; chr++)
+ if(*chr == '_')
+ *chr = ' ';
- *name = after;
+ *name = after;
}
}
}
-gchar *
-get_current_zone_name (const gchar * location, GSettings * settings)
+gchar*
+get_current_zone_name(const gchar* location, GSettings* settings)
{
- gchar * new_zone, * new_name;
- gchar * tz_name;
- gchar * old_zone, * old_name;
- gchar * rv;
-
- split_settings_location (location, &new_zone, &new_name);
-
- tz_name = g_settings_get_string (settings, SETTINGS_TIMEZONE_NAME_S);
- split_settings_location (tz_name, &old_zone, &old_name);
- g_free (tz_name);
-
- /* new_name is always just a sanitized version of a timezone.
- old_name is potentially a saved "pretty" version of a timezone name from
- geonames. So we prefer to use it if available and the zones match. */
-
- if (g_strcmp0 (old_zone, new_zone) == 0) {
- rv = old_name;
- old_name = NULL;
- }
- else {
- rv = new_name;
- new_name = NULL;
- }
-
- g_free (new_zone);
- g_free (old_zone);
- g_free (new_name);
- g_free (old_name);
-
- return rv;
+ gchar* new_zone;
+ gchar* new_name;
+ split_settings_location(location, &new_zone, &new_name);
+
+ auto tz_name = g_settings_get_string(settings, SETTINGS_TIMEZONE_NAME_S);
+ gchar* old_zone;
+ gchar* old_name;
+ split_settings_location(tz_name, &old_zone, &old_name);
+ g_free(tz_name);
+
+ /* new_name is always just a sanitized version of a timezone.
+ old_name is potentially a saved "pretty" version of a timezone name from
+ geonames. So we prefer to use it if available and the zones match. */
+
+ gchar* rv;
+ if (g_strcmp0(old_zone, new_zone) == 0)
+ {
+ rv = old_name;
+ old_name = nullptr;
+ }
+ else
+ {
+ rv = new_name;
+ new_name = nullptr;
+ }
+
+ g_free(new_zone);
+ g_free(old_zone);
+ g_free(new_name);
+ g_free(old_name);
+ return rv;
}
gchar* generate_full_format_string_at_time(GDateTime* now, GDateTime* then)
{
- using unity::indicator::datetime::Clock;
- using unity::indicator::datetime::MockClock;
- using unity::indicator::datetime::DesktopFormatter;
-
- std::shared_ptr<Clock> clock(new MockClock(now));
- DesktopFormatter formatter(clock);
- return g_strdup (formatter.getRelativeFormat(then).c_str());
+ using unity::indicator::datetime::Clock;
+ using unity::indicator::datetime::DateTime;
+ using unity::indicator::datetime::MockClock;
+ using unity::indicator::datetime::DesktopFormatter;
+
+ std::shared_ptr<Clock> clock(new MockClock(DateTime(now)));
+ DesktopFormatter formatter(clock);
+ return g_strdup(formatter.getRelativeFormat(then).c_str());
}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index a424858..fb55f5a 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -32,12 +32,6 @@ include_directories (${DBUSTEST_INCLUDE_DIRS})
add_definitions (-DSANDBOX="${CMAKE_CURRENT_BINARY_DIR}")
-# test-core
-set (TEST_NAME test-core)
-add_executable (${TEST_NAME} ${TEST_NAME}.cc)
-add_test (${TEST_NAME} ${TEST_NAME})
-target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
-
# test-timezone-file
set (TEST_NAME test-timezone-file)
add_executable (${TEST_NAME} ${TEST_NAME}.cc)
@@ -76,18 +70,31 @@ add_test (${TEST_NAME} ${TEST_NAME})
add_dependencies (${TEST_NAME} libindicatordatetimeservice)
target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
-# test-planner-eds
-set (TEST_NAME test-planner-eds)
+# test-locations
+set (TEST_NAME test-locations)
add_executable (${TEST_NAME} ${TEST_NAME}.cc)
add_test (${TEST_NAME} ${TEST_NAME})
add_dependencies (${TEST_NAME} libindicatordatetimeservice)
target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
-# test-locations
-set (TEST_NAME test-locations)
+# test-actions
+set (TEST_NAME test-actions)
+add_executable (${TEST_NAME} ${TEST_NAME}.cc)
+add_test (${TEST_NAME} ${TEST_NAME})
+add_dependencies (${TEST_NAME} libindicatordatetimeservice)
+target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
+
+# test-menus
+set (TEST_NAME test-menus)
add_executable (${TEST_NAME} ${TEST_NAME}.cc)
add_test (${TEST_NAME} ${TEST_NAME})
add_dependencies (${TEST_NAME} libindicatordatetimeservice)
target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
+# test-desktop
+#set (TEST_NAME test-desktop)
+#add_executable (${TEST_NAME} ${TEST_NAME}.cc)
+#add_test (${TEST_NAME} ${TEST_NAME})
+#add_dependencies (${TEST_NAME} libindicatordatetimeservice)
+#target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
diff --git a/tests/Makefile.am.strings b/tests/Makefile.am.strings
deleted file mode 100644
index 4a89e8f..0000000
--- a/tests/Makefile.am.strings
+++ /dev/null
@@ -1,38 +0,0 @@
-TESTS += \
- test-ellipsis \
- test-space-ellipsis \
- test-ascii-quotes
-
-#####
-# Tests for there being proper ellipsis instead of three periods in a row
-#####
-test-ellipsis: $(top_srcdir)/po
- @echo "#!/bin/bash" > $@
- @echo "(cd $(top_srcdir)/po && make $(GETTEXT_PACKAGE).pot)" >> $@
- @echo "grep -c -e \"^msgid.*\.\.\.\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"Ellipsis found in user visible strings\" >&2 && exit 1" >> $@
- @echo "exit 0" >> $@
- @chmod +x $@
-
-#####
-# Tests for there being a space before an ellipsis
-#####
-test-space-ellipsis: $(top_srcdir)/po
- @echo "#!/bin/bash" > $@
- @echo "(cd $(top_srcdir)/po && make $(GETTEXT_PACKAGE).pot)" >> $@
- @echo "grep -c -e \"^msgid.* …\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"Space before ellipsis found in user visible strings\" >&2 && exit 1" >> $@
- @echo "exit 0" >> $@
- @chmod +x $@
-
-#####
-# Tests for ASCII quote types
-#####
-test-ascii-quotes: $(top_srcdir)/po
- @echo "#!/bin/bash" > $@
- @echo "(cd $(top_srcdir)/po && make $(GETTEXT_PACKAGE).pot)" >> $@
- @echo "grep -c -e \"^msgid \\\".*'.*\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"ASCII apostrophe found in user visible strings\" >&2 && exit 1" >> $@
- @echo "grep -c -e \"^msgid \\\".*\\\".*\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"ASCII quote found in user visible strings\" >&2 && exit 1" >> $@
- @echo "grep -c -e \"^msgid \\\".*\\\`.*\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"ASCII backtick found in user visible strings\" >&2 && exit 1" >> $@
- @echo "exit 0" >> $@
- @chmod +x $@
-
-CLEANFILES += $(TESTS)
diff --git a/tests/actions-mock.h b/tests/actions-mock.h
new file mode 100644
index 0000000..112900b
--- /dev/null
+++ b/tests/actions-mock.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#ifndef INDICATOR_DATETIME_ACTIONS_MOCK_H
+#define INDICATOR_DATETIME_ACTIONS_MOCK_H
+
+#include <datetime/actions.h>
+
+#include <set>
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+class MockActions: public Actions
+{
+public:
+ MockActions(std::shared_ptr<State>& state_in): Actions(state_in) {}
+ ~MockActions() =default;
+
+ enum Action { OpenDesktopSettings, OpenPhoneSettings, OpenPhoneClockApp,
+ OpenPlanner, OpenPlannerAt, OpenAppointment,
+ SetLocation, SetCalendarDate };
+ const std::vector<Action>& history() const { return m_history; }
+ const DateTime& date_time() const { return m_date_time; }
+ const std::string& zone() const { return m_zone; }
+ const std::string& name() const { return m_name; }
+ const std::string& url() const { return m_url; }
+ void clear() { m_history.clear(); m_zone.clear(); m_name.clear(); }
+
+ void open_desktop_settings() { m_history.push_back(OpenDesktopSettings); }
+
+ void open_phone_settings() { m_history.push_back(OpenPhoneSettings); }
+
+ void open_phone_clock_app() { m_history.push_back(OpenPhoneClockApp); }
+
+ void open_planner() { m_history.push_back(OpenPlanner); }
+
+ void open_planner_at(const DateTime& date_time_) {
+ m_history.push_back(OpenPlannerAt);
+ m_date_time = date_time_;
+ }
+
+ void set_location(const std::string& zone_, const std::string& name_) {
+ m_history.push_back(SetLocation);
+ m_zone = zone_;
+ m_name = name_;
+ }
+
+ void open_appointment(const std::string& url_) {
+ m_history.push_back(OpenAppointment);
+ m_url = url_;
+ }
+
+ void set_calendar_date(const DateTime& date_time_) {
+ m_history.push_back(SetCalendarDate);
+ m_date_time = date_time_;
+ }
+
+private:
+ std::string m_url;
+ std::string m_zone;
+ std::string m_name;
+ DateTime m_date_time;
+ std::vector<Action> m_history;
+};
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
+
+#endif // INDICATOR_DATETIME_ACTIONS_MOCK_H
diff --git a/tests/glib-fixture.h b/tests/glib-fixture.h
index 043b7e3..3f517d4 100644
--- a/tests/glib-fixture.h
+++ b/tests/glib-fixture.h
@@ -25,6 +25,8 @@
#include <gtest/gtest.h>
+#include <locale.h> // setlocale()
+
class GlibFixture : public ::testing::Test
{
private:
@@ -35,96 +37,101 @@ class GlibFixture : public ::testing::Test
std::map<GLogLevelFlags,int> logCounts;
- void testLogCount (GLogLevelFlags log_level, int expected G_GNUC_UNUSED)
+ void testLogCount(GLogLevelFlags log_level, int /*expected*/)
{
#if 0
- EXPECT_EQ (expected, logCounts[log_level]);
+ EXPECT_EQ(expected, logCounts[log_level]);
#endif
- logCounts.erase (log_level);
+ logCounts.erase(log_level);
}
private:
- static void default_log_handler (const gchar * log_domain,
- GLogLevelFlags log_level,
- const gchar * message,
- gpointer self)
+ static void default_log_handler(const gchar * log_domain,
+ GLogLevelFlags log_level,
+ const gchar * message,
+ gpointer self)
{
- g_print ("%s - %d - %s\n", log_domain, (int)log_level, message);
+ g_print("%s - %d - %s\n", log_domain, (int)log_level, message);
static_cast<GlibFixture*>(self)->logCounts[log_level]++;
}
protected:
- virtual void SetUp ()
+ virtual void SetUp()
{
- loop = g_main_loop_new (NULL, FALSE);
+ setlocale(LC_ALL, "");
+
+ loop = g_main_loop_new(nullptr, false);
- //g_log_set_default_handler (default_log_handler, this);
+ //g_log_set_default_handler(default_log_handler, this);
// only use local, temporary settings
- g_setenv ("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE);
- g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
- g_debug ("SCHEMA_DIR is %s", SCHEMA_DIR);
+ g_assert(g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, true));
+ g_assert(g_setenv("GSETTINGS_BACKEND", "memory", true));
+ g_debug("SCHEMA_DIR is %s", SCHEMA_DIR);
+
+ g_unsetenv("DISPLAY");
+
}
virtual void TearDown()
{
#if 0
// confirm there aren't any unexpected log messages
- EXPECT_EQ (0, logCounts[G_LOG_LEVEL_ERROR]);
- EXPECT_EQ (0, logCounts[G_LOG_LEVEL_CRITICAL]);
- EXPECT_EQ (0, logCounts[G_LOG_LEVEL_WARNING]);
- EXPECT_EQ (0, logCounts[G_LOG_LEVEL_MESSAGE]);
- EXPECT_EQ (0, logCounts[G_LOG_LEVEL_INFO]);
+ EXPECT_EQ(0, logCounts[G_LOG_LEVEL_ERROR]);
+ EXPECT_EQ(0, logCounts[G_LOG_LEVEL_CRITICAL]);
+ EXPECT_EQ(0, logCounts[G_LOG_LEVEL_WARNING]);
+ EXPECT_EQ(0, logCounts[G_LOG_LEVEL_MESSAGE]);
+ EXPECT_EQ(0, logCounts[G_LOG_LEVEL_INFO]);
#endif
// revert to glib's log handler
- //g_log_set_default_handler (realLogHandler, this);
+ //g_log_set_default_handler(realLogHandler, this);
- g_clear_pointer (&loop, g_main_loop_unref);
+ g_clear_pointer(&loop, g_main_loop_unref);
}
private:
static gboolean
- wait_for_signal__timeout (gpointer name)
+ wait_for_signal__timeout(gpointer name)
{
- g_error ("%s: timed out waiting for signal '%s'", G_STRLOC, (char*)name);
+ g_error("%s: timed out waiting for signal '%s'", G_STRLOC, (char*)name);
return G_SOURCE_REMOVE;
}
static gboolean
- wait_msec__timeout (gpointer loop)
+ wait_msec__timeout(gpointer loop)
{
- g_main_loop_quit (static_cast<GMainLoop*>(loop));
+ g_main_loop_quit(static_cast<GMainLoop*>(loop));
return G_SOURCE_CONTINUE;
}
protected:
/* convenience func to loop while waiting for a GObject's signal */
- void wait_for_signal (gpointer o, const gchar * signal, const int timeout_seconds=5)
+ void wait_for_signal(gpointer o, const gchar * signal, const int timeout_seconds=5)
{
// wait for the signal or for timeout, whichever comes first
- const auto handler_id = g_signal_connect_swapped (o, signal,
- G_CALLBACK(g_main_loop_quit),
- loop);
- const auto timeout_id = g_timeout_add_seconds (timeout_seconds,
- wait_for_signal__timeout,
- loop);
- g_main_loop_run (loop);
- g_source_remove (timeout_id);
- g_signal_handler_disconnect (o, handler_id);
+ const auto handler_id = g_signal_connect_swapped(o, signal,
+ G_CALLBACK(g_main_loop_quit),
+ loop);
+ const auto timeout_id = g_timeout_add_seconds(timeout_seconds,
+ wait_for_signal__timeout,
+ loop);
+ g_main_loop_run(loop);
+ g_source_remove(timeout_id);
+ g_signal_handler_disconnect(o, handler_id);
}
/* convenience func to loop for N msec */
- void wait_msec (int msec=50)
+ void wait_msec(int msec=50)
{
- const auto id = g_timeout_add (msec, wait_msec__timeout, loop);
- g_main_loop_run (loop);
- g_source_remove (id);
+ const auto id = g_timeout_add(msec, wait_msec__timeout, loop);
+ g_main_loop_run(loop);
+ g_source_remove(id);
}
GMainLoop * loop;
diff --git a/tests/planner-mock.c b/tests/planner-mock.c
index e67ad7e..df5413e 100644
--- a/tests/planner-mock.c
+++ b/tests/planner-mock.c
@@ -39,7 +39,7 @@ G_DEFINE_TYPE (IndicatorDatetimePlannerMock,
static void
my_get_appointments (IndicatorDatetimePlanner * planner,
GDateTime * begin_datetime,
- GDateTime * end_datetime G_GNUC_UNUSED,
+ GDateTime * /*end_datetime*/,
GAsyncReadyCallback callback,
gpointer user_data)
{
@@ -88,34 +88,34 @@ my_get_appointments (IndicatorDatetimePlanner * planner,
}
static GSList *
-my_get_appointments_finish (IndicatorDatetimePlanner * self G_GNUC_UNUSED,
- GAsyncResult * res,
- GError ** error)
+my_get_appointments_finish (IndicatorDatetimePlanner* /*self*/,
+ GAsyncResult* res,
+ GError** error)
{
- return g_task_propagate_pointer (G_TASK(res), error);
+ return g_task_propagate_pointer(G_TASK(res), error);
}
static gboolean
-my_is_configured (IndicatorDatetimePlanner * planner)
+my_is_configured(IndicatorDatetimePlanner* planner)
{
IndicatorDatetimePlannerMock * self;
- self = INDICATOR_DATETIME_PLANNER_MOCK (planner);
+ self = INDICATOR_DATETIME_PLANNER_MOCK(planner);
return self->priv->is_configured;
}
static void
-my_activate (IndicatorDatetimePlanner * self G_GNUC_UNUSED)
+my_activate(IndicatorDatetimePlanner* /*self*/)
{
- g_message ("%s %s", G_STRLOC, G_STRFUNC);
+ g_message("%s %s", G_STRLOC, G_STRFUNC);
}
static void
-my_activate_time (IndicatorDatetimePlanner * self G_GNUC_UNUSED,
- GDateTime * activate_time)
+my_activate_time(IndicatorDatetimePlanner* /*self*/,
+ GDateTime* activate_time)
{
- gchar * str = g_date_time_format (activate_time, "%F %T");
- g_message ("%s %s: %s", G_STRLOC, G_STRFUNC, str);
- g_free (str);
+ gchar * str = g_date_time_format(activate_time, "%F %T");
+ g_message("%s %s: %s", G_STRLOC, G_STRFUNC, str);
+ g_free(str);
}
/***
@@ -123,9 +123,9 @@ my_activate_time (IndicatorDatetimePlanner * self G_GNUC_UNUSED,
***/
static void
-my_dispose (GObject * o)
+my_dispose(GObject * o)
{
- G_OBJECT_CLASS (indicator_datetime_planner_mock_parent_class)->dispose (o);
+ G_OBJECT_CLASS(indicator_datetime_planner_mock_parent_class)->dispose(o);
}
/***
@@ -133,7 +133,7 @@ my_dispose (GObject * o)
***/
static void
-indicator_datetime_planner_mock_class_init (IndicatorDatetimePlannerMockClass * klass)
+indicator_datetime_planner_mock_class_init(IndicatorDatetimePlannerMockClass* klass)
{
GObjectClass * object_class;
IndicatorDatetimePlannerClass * planner_class;
diff --git a/tests/state-fixture.h b/tests/state-fixture.h
new file mode 100644
index 0000000..0286ea9
--- /dev/null
+++ b/tests/state-fixture.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#include "glib-fixture.h"
+#include "actions-mock.h"
+
+#include <datetime/clock-mock.h>
+#include <datetime/formatter.h>
+#include <datetime/locations.h>
+#include <datetime/menu.h>
+#include <datetime/planner-mock.h>
+#include <datetime/service.h>
+#include <datetime/state.h>
+#include <datetime/timezones.h>
+
+using namespace unity::indicator::datetime;
+
+class StateFixture: public GlibFixture
+{
+private:
+ typedef GlibFixture super;
+
+protected:
+ std::shared_ptr<MockClock> m_clock;
+ std::shared_ptr<State> m_state;
+ std::shared_ptr<MockActions> m_mock_actions;
+ std::shared_ptr<Actions> m_actions;
+
+ virtual void SetUp()
+ {
+ super::SetUp();
+
+ // first, build a mock backend state
+ const DateTime now = DateTime::NowLocal();
+ m_clock.reset(new MockClock(now));
+ m_state.reset(new State);
+ m_state->timezones.reset(new Timezones);
+ m_state->clock = std::dynamic_pointer_cast<Clock>(m_clock);
+ m_state->planner.reset(new MockPlanner);
+ m_state->planner->time = now;
+ m_state->locations.reset(new Locations);
+ m_state->calendar_day = now;
+
+ // build the actions on top of the state
+ m_mock_actions.reset(new MockActions(m_state));
+ m_actions = std::dynamic_pointer_cast<Actions>(m_mock_actions);
+ }
+
+ virtual void TearDown()
+ {
+ m_actions.reset();
+ m_mock_actions.reset();
+ m_state.reset();
+ m_clock.reset();
+
+ super::TearDown();
+ }
+};
+
diff --git a/tests/test-actions.cc b/tests/test-actions.cc
new file mode 100644
index 0000000..4329608
--- /dev/null
+++ b/tests/test-actions.cc
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#include <datetime/actions.h>
+
+#include "state-fixture.h"
+
+using namespace unity::indicator::datetime;
+
+typedef StateFixture ActionsFixture;
+
+TEST_F(ActionsFixture, ActionsExist)
+{
+ EXPECT_TRUE(m_actions != nullptr);
+
+ const char* names[] = { "desktop-header",
+ "calendar",
+ "set-location",
+ "activate-planner",
+ "activate-appointment",
+ "activate-phone-settings",
+ "activate-phone-clock-app",
+ "activate-desktop-settings" };
+ for(const auto& name: names)
+ {
+ EXPECT_TRUE(g_action_group_has_action(m_actions->action_group(), name));
+ }
+}
+
+TEST_F(ActionsFixture, ActivateDesktopSettings)
+{
+ const auto action_name = "activate-desktop-settings";
+ const auto expected_action = MockActions::OpenDesktopSettings;
+
+ auto action_group = m_actions->action_group();
+ auto history = m_mock_actions->history();
+ EXPECT_EQ(0, history.size());
+ EXPECT_TRUE(g_action_group_has_action(action_group, action_name));
+
+ g_action_group_activate_action(action_group, action_name, nullptr);
+ history = m_mock_actions->history();
+ EXPECT_EQ(1, history.size());
+ EXPECT_EQ(expected_action, history[0]);
+}
+
+TEST_F(ActionsFixture, ActivatePhoneSettings)
+{
+ const auto action_name = "activate-phone-settings";
+ const auto expected_action = MockActions::OpenPhoneSettings;
+
+ auto action_group = m_actions->action_group();
+ EXPECT_TRUE(m_mock_actions->history().empty());
+ EXPECT_TRUE(g_action_group_has_action(action_group, action_name));
+
+ g_action_group_activate_action(action_group, action_name, nullptr);
+ auto history = m_mock_actions->history();
+ EXPECT_EQ(1, history.size());
+ EXPECT_EQ(expected_action, history[0]);
+}
+
+TEST_F(ActionsFixture, ActivatePhoneClockApp)
+{
+ const auto action_name = "activate-phone-clock-app";
+ const auto expected_action = MockActions::OpenPhoneClockApp;
+
+ auto action_group = m_actions->action_group();
+ EXPECT_TRUE(m_mock_actions->history().empty());
+ EXPECT_TRUE(g_action_group_has_action(action_group, action_name));
+
+ g_action_group_activate_action(action_group, action_name, nullptr);
+ auto history = m_mock_actions->history();
+ EXPECT_EQ(1, history.size());
+ EXPECT_EQ(expected_action, history[0]);
+}
+
+TEST_F(ActionsFixture, ActivatePlanner)
+{
+ const auto action_name = "activate-planner";
+ auto action_group = m_actions->action_group();
+ EXPECT_TRUE(m_mock_actions->history().empty());
+ EXPECT_TRUE(g_action_group_has_action(action_group, action_name));
+
+ const auto expected_action = MockActions::OpenPlanner;
+ auto v = g_variant_new_int64(0);
+ g_action_group_activate_action(action_group, action_name, v);
+ auto history = m_mock_actions->history();
+ EXPECT_EQ(1, history.size());
+ EXPECT_EQ(expected_action, history[0]);
+}
+
+TEST_F(ActionsFixture, ActivatePlannerAt)
+{
+ const auto action_name = "activate-planner";
+ auto action_group = m_actions->action_group();
+ EXPECT_TRUE(m_mock_actions->history().empty());
+ EXPECT_TRUE(g_action_group_has_action(action_group, action_name));
+
+ const auto now = DateTime::NowLocal();
+ auto v = g_variant_new_int64(now.to_unix());
+ g_action_group_activate_action(action_group, action_name, v);
+ const auto a = MockActions::OpenPlannerAt;
+ EXPECT_EQ(std::vector<MockActions::Action>({a}), m_mock_actions->history());
+ EXPECT_EQ(now.to_unix(), m_mock_actions->date_time().to_unix());
+}
+
+TEST_F(ActionsFixture, SetLocation)
+{
+ const auto action_name = "set-location";
+ auto action_group = m_actions->action_group();
+ EXPECT_TRUE(m_mock_actions->history().empty());
+ EXPECT_TRUE(g_action_group_has_action(action_group, action_name));
+
+ auto v = g_variant_new_string("America/Chicago Oklahoma City");
+ g_action_group_activate_action(action_group, action_name, v);
+ const auto expected_action = MockActions::SetLocation;
+ ASSERT_EQ(1, m_mock_actions->history().size());
+ EXPECT_EQ(expected_action, m_mock_actions->history()[0]);
+ EXPECT_EQ("America/Chicago", m_mock_actions->zone());
+ EXPECT_EQ("Oklahoma City", m_mock_actions->name());
+}
+
+TEST_F(ActionsFixture, SetCalendarDate)
+{
+ const auto action_name = "calendar";
+ auto action_group = m_actions->action_group();
+ EXPECT_TRUE(m_mock_actions->history().empty());
+ EXPECT_TRUE(g_action_group_has_action(action_group, action_name));
+
+ auto unix = m_state->clock->localtime().to_unix();
+ auto v = g_variant_new_int64(unix);
+ g_action_group_activate_action(action_group, action_name, v);
+ const auto expected_action = MockActions::SetCalendarDate;
+ ASSERT_EQ(1, m_mock_actions->history().size());
+ EXPECT_EQ(expected_action, m_mock_actions->history()[0]);
+ EXPECT_EQ(unix, m_mock_actions->date_time().to_unix());
+}
+
+TEST_F(ActionsFixture, OpenAppointment)
+{
+ Appointment appt;
+ appt.uid = "some arbitrary uid";
+ appt.url = "http://www.canonical.com/";
+ m_state->planner->upcoming.set(std::vector<Appointment>({appt}));
+
+ const auto action_name = "activate-appointment";
+ auto action_group = m_actions->action_group();
+ EXPECT_TRUE(m_mock_actions->history().empty());
+ EXPECT_TRUE(g_action_group_has_action(action_group, action_name));
+
+ auto v = g_variant_new_string(appt.uid.c_str());
+ g_action_group_activate_action(action_group, action_name, v);
+ const auto a = MockActions::OpenAppointment;
+ ASSERT_EQ(1, m_mock_actions->history().size());
+ ASSERT_EQ(a, m_mock_actions->history()[0]);
+ EXPECT_EQ(appt.url, m_mock_actions->url());
+}
+
diff --git a/tests/test-clock.cc b/tests/test-clock.cc
index a0b4360..7d3a35e 100644
--- a/tests/test-clock.cc
+++ b/tests/test-clock.cc
@@ -37,27 +37,27 @@ class ClockFixture: public GlibFixture
typedef GlibFixture super;
static void
- on_bus_opened (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself)
+ on_bus_opened(GObject* /*object*/, GAsyncResult* res, gpointer gself)
{
auto self = static_cast<ClockFixture*>(gself);
GError * err = 0;
- self->system_bus = g_bus_get_finish (res, &err);
- g_assert_no_error (err);
+ self->system_bus = g_bus_get_finish(res, &err);
+ g_assert_no_error(err);
- g_main_loop_quit (self->loop);
+ g_main_loop_quit(self->loop);
}
static void
- on_bus_closed (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself)
+ on_bus_closed(GObject* /*object*/, GAsyncResult* res, gpointer gself)
{
auto self = static_cast<ClockFixture*>(gself);
GError * err = 0;
- g_dbus_connection_close_finish (self->system_bus, res, &err);
- g_assert_no_error (err);
+ g_dbus_connection_close_finish(self->system_bus, res, &err);
+ g_assert_no_error(err);
- g_main_loop_quit (self->loop);
+ g_main_loop_quit(self->loop);
}
protected:
@@ -65,41 +65,41 @@ class ClockFixture: public GlibFixture
GTestDBus * test_dbus;
GDBusConnection * system_bus;
- virtual void SetUp ()
+ virtual void SetUp()
{
- super::SetUp ();
+ super::SetUp();
// pull up a test dbus
- test_dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
- g_test_dbus_up (test_dbus);
- const char * address = g_test_dbus_get_bus_address (test_dbus);
- g_setenv ("DBUS_SYSTEM_BUS_ADDRESS", address, TRUE);
- g_debug ("test_dbus's address is %s", address);
+ test_dbus = g_test_dbus_new(G_TEST_DBUS_NONE);
+ g_test_dbus_up(test_dbus);
+ const char * address = g_test_dbus_get_bus_address(test_dbus);
+ g_setenv("DBUS_SYSTEM_BUS_ADDRESS", address, TRUE);
+ g_debug("test_dbus's address is %s", address);
// wait for the GDBusConnection before returning
- g_bus_get (G_BUS_TYPE_SYSTEM, nullptr, on_bus_opened, this);
- g_main_loop_run (loop);
+ g_bus_get(G_BUS_TYPE_SYSTEM, nullptr, on_bus_opened, this);
+ g_main_loop_run(loop);
}
- virtual void TearDown ()
+ virtual void TearDown()
{
// close the system bus
- g_dbus_connection_close (system_bus, nullptr, on_bus_closed, this);
- g_main_loop_run (loop);
- g_clear_object (&system_bus);
+ g_dbus_connection_close(system_bus, nullptr, on_bus_closed, this);
+ g_main_loop_run(loop);
+ g_clear_object(&system_bus);
// tear down the test dbus
- g_test_dbus_down (test_dbus);
- g_clear_object (&test_dbus);
+ g_test_dbus_down(test_dbus);
+ g_clear_object(&test_dbus);
- super::TearDown ();
+ super::TearDown();
}
public:
- void emitPrepareForSleep ()
+ void emitPrepareForSleep()
{
- g_dbus_connection_emit_signal (g_bus_get_sync (G_BUS_TYPE_SYSTEM, nullptr, nullptr),
+ g_dbus_connection_emit_signal(g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, nullptr),
NULL,
"/org/freedesktop/login1", // object path
"org.freedesktop.login1.Manager", // interface
@@ -115,93 +115,91 @@ class ClockFixture: public GlibFixture
#define TIMEZONE_FILE (SANDBOX"/timezone")
-TEST_F (ClockFixture, HelloFixture)
+TEST_F(ClockFixture, HelloFixture)
{
- std::shared_ptr<Timezones> zones (new Timezones);
+ std::shared_ptr<Timezones> zones(new Timezones);
zones->timezone.set("America/New_York");
- LiveClock clock (zones);
+ LiveClock clock(zones);
#if 0
- GTimeZone * tz_nyc = g_time_zone_new (file_timezone.c_str());
- GDateTime * now_nyc = g_date_time_new_now (tz_nyc);
+ GTimeZone * tz_nyc = g_time_zone_new(file_timezone.c_str());
+ GDateTime * now_nyc = g_date_time_new_now(tz_nyc);
GDateTime * now = clock.localtime();
- EXPECT_EQ (g_date_time_get_utc_offset(now_nyc), g_date_time_get_utc_offset(now));
- EXPECT_LE (abs(g_date_time_difference(now_nyc,now)), G_USEC_PER_SEC);
- g_date_time_unref (now);
- g_date_time_unref (now_nyc);
- g_time_zone_unref (tz_nyc);
+ EXPECT_EQ(g_date_time_get_utc_offset(now_nyc), g_date_time_get_utc_offset(now));
+ EXPECT_LE(abs(g_date_time_difference(now_nyc,now)), G_USEC_PER_SEC);
+ g_date_time_unref(now);
+ g_date_time_unref(now_nyc);
+ g_time_zone_unref(tz_nyc);
/// change the timezones!
clock.skewDetected.connect([this](){
g_main_loop_quit(loop);
});
file_timezone = "America/Los_Angeles";
- g_idle_add ([](gpointer str){
+ g_idle_add([](gpointer str){
set_file(static_cast<const char*>(str));
return G_SOURCE_REMOVE;
}, const_cast<char*>(file_timezone.c_str()));
- g_main_loop_run (loop);
+ g_main_loop_run(loop);
- GTimeZone * tz_la = g_time_zone_new (file_timezone.c_str());
- GDateTime * now_la = g_date_time_new_now (tz_la);
+ GTimeZone * tz_la = g_time_zone_new(file_timezone.c_str());
+ GDateTime * now_la = g_date_time_new_now(tz_la);
now = clock.localtime();
- EXPECT_EQ (g_date_time_get_utc_offset(now_la), g_date_time_get_utc_offset(now));
- EXPECT_LE (abs(g_date_time_difference(now_la,now)), G_USEC_PER_SEC);
- g_date_time_unref (now);
- g_date_time_unref (now_la);
- g_time_zone_unref (tz_la);
+ EXPECT_EQ(g_date_time_get_utc_offset(now_la), g_date_time_get_utc_offset(now));
+ EXPECT_LE(abs(g_date_time_difference(now_la,now)), G_USEC_PER_SEC);
+ g_date_time_unref(now);
+ g_date_time_unref(now_la);
+ g_time_zone_unref(tz_la);
#endif
}
-TEST_F (ClockFixture, TimezoneChangeTriggersSkew)
+TEST_F(ClockFixture, TimezoneChangeTriggersSkew)
{
- std::shared_ptr<Timezones> zones (new Timezones);
+ std::shared_ptr<Timezones> zones(new Timezones);
zones->timezone.set("America/New_York");
- LiveClock clock (zones);
+ LiveClock clock(zones);
//std::string file_timezone = "America/New_York";
- //set_file (file_timezone);
- //std::shared_ptr<TimezoneDetector> detector (new TimezoneDetector(TIMEZONE_FILE));
- //LiveClock clock (detector);
-
- GTimeZone * tz_nyc = g_time_zone_new ("America/New_York");
- GDateTime * now_nyc = g_date_time_new_now (tz_nyc);
- GDateTime * now = clock.localtime();
- EXPECT_EQ (g_date_time_get_utc_offset(now_nyc), g_date_time_get_utc_offset(now));
- EXPECT_LE (abs(g_date_time_difference(now_nyc,now)), G_USEC_PER_SEC);
- g_date_time_unref (now);
- g_date_time_unref (now_nyc);
- g_time_zone_unref (tz_nyc);
+ //set_file(file_timezone);
+ //std::shared_ptr<TimezoneDetector> detector(new TimezoneDetector(TIMEZONE_FILE));
+ //LiveClock clock(detector);
+
+ auto tz_nyc = g_time_zone_new("America/New_York");
+ auto now_nyc = g_date_time_new_now(tz_nyc);
+ auto now = clock.localtime();
+ EXPECT_EQ(g_date_time_get_utc_offset(now_nyc), g_date_time_get_utc_offset(now.get()));
+ EXPECT_LE(abs(g_date_time_difference(now_nyc,now.get())), G_USEC_PER_SEC);
+ g_date_time_unref(now_nyc);
+ g_time_zone_unref(tz_nyc);
/// change the timezones!
clock.skewDetected.connect([this](){
- g_main_loop_quit(loop);
- });
- g_idle_add ([](gpointer gs){
- static_cast<Timezones*>(gs)->timezone.set("America/Los_Angeles");
- return G_SOURCE_REMOVE;
- }, zones.get());
- g_main_loop_run (loop);
-
- GTimeZone * tz_la = g_time_zone_new ("America/Los_Angeles");
- GDateTime * now_la = g_date_time_new_now (tz_la);
+ g_main_loop_quit(loop);
+ });
+ g_idle_add([](gpointer gs){
+ static_cast<Timezones*>(gs)->timezone.set("America/Los_Angeles");
+ return G_SOURCE_REMOVE;
+ }, zones.get());
+ g_main_loop_run(loop);
+
+ auto tz_la = g_time_zone_new("America/Los_Angeles");
+ auto now_la = g_date_time_new_now(tz_la);
now = clock.localtime();
- EXPECT_EQ (g_date_time_get_utc_offset(now_la), g_date_time_get_utc_offset(now));
- EXPECT_LE (abs(g_date_time_difference(now_la,now)), G_USEC_PER_SEC);
- g_date_time_unref (now);
- g_date_time_unref (now_la);
- g_time_zone_unref (tz_la);
+ EXPECT_EQ(g_date_time_get_utc_offset(now_la), g_date_time_get_utc_offset(now.get()));
+ EXPECT_LE(abs(g_date_time_difference(now_la,now.get())), G_USEC_PER_SEC);
+ g_date_time_unref(now_la);
+ g_time_zone_unref(tz_la);
}
/**
* Confirm that a "PrepareForSleep" event wil trigger a skew event
*/
-TEST_F (ClockFixture, SleepTriggersSkew)
+TEST_F(ClockFixture, SleepTriggersSkew)
{
- std::shared_ptr<Timezones> zones (new Timezones);
+ std::shared_ptr<Timezones> zones(new Timezones);
zones->timezone.set("America/New_York");
- LiveClock clock (zones);
- wait_msec (500); // wait for the bus to set up
+ LiveClock clock(zones);
+ wait_msec(500); // wait for the bus to set up
bool skewed = false;
clock.skewDetected.connect([&skewed, this](){
@@ -210,12 +208,12 @@ TEST_F (ClockFixture, SleepTriggersSkew)
return G_SOURCE_REMOVE;
});
- g_idle_add ([](gpointer gself){
- static_cast<ClockFixture*>(gself)->emitPrepareForSleep();
- return G_SOURCE_REMOVE;
+ g_idle_add([](gpointer gself){
+ static_cast<ClockFixture*>(gself)->emitPrepareForSleep();
+ return G_SOURCE_REMOVE;
}, this);
- wait_msec (1000);
+ wait_msec(1000);
EXPECT_TRUE(skewed);
}
@@ -223,12 +221,12 @@ TEST_F (ClockFixture, SleepTriggersSkew)
* Confirm that normal time passing doesn't trigger a skew event.
* that idling changing the clock's time triggers a skew event
*/
-TEST_F (ClockFixture, IdleDoesNotTriggerSkew)
+TEST_F(ClockFixture, IdleDoesNotTriggerSkew)
{
- std::shared_ptr<Timezones> zones (new Timezones);
+ std::shared_ptr<Timezones> zones(new Timezones);
zones->timezone.set("America/New_York");
- LiveClock clock (zones);
- wait_msec (500); // wait for the bus to set up
+ LiveClock clock(zones);
+ wait_msec(500); // wait for the bus to set up
bool skewed = false;
clock.skewDetected.connect([&skewed](){
@@ -239,6 +237,6 @@ TEST_F (ClockFixture, IdleDoesNotTriggerSkew)
const unsigned int intervalSec = 4;
clock.skewTestIntervalSec.set(intervalSec);
- wait_msec (intervalSec * 2.5 * 1000);
- EXPECT_FALSE (skewed);
+ wait_msec(intervalSec * 2.5 * 1000);
+ EXPECT_FALSE(skewed);
}
diff --git a/tests/test-core.cc b/tests/test-core.cc
deleted file mode 100644
index 7ed38a9..0000000
--- a/tests/test-core.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-
-/*
- * Copyright 2013 Canonical Ltd.
- *
- * Authors:
- * Charles Kerr <charles.kerr@canonical.com>
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 3, as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranties of
- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <condition_variable>
-#include <mutex>
-#include <queue>
-#include <thread>
-
-#include <langinfo.h>
-#include <locale.h>
-
-#include <glib/gi18n.h>
-
-#include <core/connection.h>
-#include <core/signal.h>
-#include <core/property.h>
-
-#include "glib-fixture.h"
-
-/***
-****
-***/
-
-class CoreFixture: public GlibFixture
-{
- private:
-
- typedef GlibFixture super;
-
- protected:
-
- virtual void SetUp ()
- {
- super::SetUp ();
- }
-
- virtual void TearDown ()
- {
- super::TearDown ();
- }
-};
-
-namespace
-{
-struct EventLoop
-{
- typedef std::function<void()> Handler;
-
- void stop()
- {
- stop_requested = true;
- }
-
- void run()
- {
- while (!stop_requested)
- {
- std::unique_lock<std::mutex> ul(guard);
- wait_condition.wait_for(
- ul,
- std::chrono::milliseconds{500},
- [this]() { return handlers.size() > 0; });
-
- std::cerr << "handlers.size() is " << handlers.size() << std::endl;
- while (handlers.size() > 0)
- {
- std::cerr << "gaba begin" << std::endl;
- handlers.front()();
- std::cerr << "gaba end" << std::endl;
- handlers.pop();
- }
- }
- }
-
- void dispatch(const Handler& h)
- {
-std::cerr << "in dispatch" << std::endl;
- std::lock_guard<std::mutex> lg(guard);
- handlers.push(h);
- }
-
- bool stop_requested = false;
- std::queue<Handler> handlers;
- std::mutex guard;
- std::condition_variable wait_condition;
-};
-}
-
-
-TEST_F (CoreFixture, HelloWorld)
-{
- // We instantiate an event loop and run it on a different thread than the main one.
- EventLoop dispatcher;
- std::thread dispatcher_thread{[&dispatcher]() { dispatcher.run(); }};
- std::thread::id dispatcher_thread_id = dispatcher_thread.get_id();
-
- // The signal that we want to dispatch via the event loop.
- core::Signal<int, double> s;
-
- static const int expected_invocation_count = 10000;
-
- // Setup the connection. For each invocation we check that the id of the
- // thread the handler is being called upon equals the thread that the
- // event loop is running upon.
- auto connection = s.connect(
- [&dispatcher, dispatcher_thread_id](int value, double d)
- {
- std::cerr << "this is the lambda" << std::endl;
- EXPECT_EQ(dispatcher_thread_id,
- std::this_thread::get_id());
-
- std::cout << d << std::endl;
-
- if (value == expected_invocation_count)
- dispatcher.stop();
- });
-
- // Route the connection via the dispatcher
- connection.dispatch_via(
- std::bind(
- &EventLoop::dispatch,
- std::ref(dispatcher),
- std::placeholders::_1));
-
- // Invoke the signal from the main thread.
- for (unsigned int i = 1; i <= expected_invocation_count; i++)
- s(i, 42.);
-
- if (dispatcher_thread.joinable())
- dispatcher_thread.join();
-}
diff --git a/tests/test-dbus-fixture.h b/tests/test-dbus-fixture.h
new file mode 100644
index 0000000..fc7ab5a
--- /dev/null
+++ b/tests/test-dbus-fixture.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#include "glib-fixture.h"
+
+/***
+****
+***/
+
+class TestDBusFixture: public GlibFixture
+{
+ public:
+
+ TestDBusFixture() {}
+
+ TestDBusFixture(const std::vector<std::string>& service_dirs_in): service_dirs(service_dirs_in) {}
+
+ private:
+
+ typedef GlibFixture super;
+
+ static void
+ on_bus_opened (GObject* /*object*/, GAsyncResult * res, gpointer gself)
+ {
+ auto self = static_cast<TestDBusFixture*>(gself);
+
+ GError * err = 0;
+ self->system_bus = g_bus_get_finish (res, &err);
+ g_assert_no_error (err);
+
+ g_main_loop_quit (self->loop);
+ }
+
+ static void
+ on_bus_closed (GObject* /*object*/, GAsyncResult * res, gpointer gself)
+ {
+ auto self = static_cast<TestDBusFixture*>(gself);
+
+ GError * err = 0;
+ g_dbus_connection_close_finish (self->system_bus, res, &err);
+ g_assert_no_error (err);
+
+ g_main_loop_quit (self->loop);
+ }
+
+ protected:
+
+ GTestDBus * test_dbus;
+ GDBusConnection * system_bus;
+ const std::vector<std::string> service_dirs;
+
+ virtual void SetUp ()
+ {
+ super::SetUp ();
+
+ // pull up a test dbus
+ test_dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
+ for (const auto& dir : service_dirs)
+ g_test_dbus_add_service_dir (test_dbus, dir.c_str());
+ g_test_dbus_up (test_dbus);
+ const char * address = g_test_dbus_get_bus_address (test_dbus);
+ g_setenv ("DBUS_SYSTEM_BUS_ADDRESS", address, true);
+ g_setenv ("DBUS_SESSION_BUS_ADDRESS", address, true);
+ g_debug ("test_dbus's address is %s", address);
+
+ // wait for the GDBusConnection before returning
+ g_bus_get (G_BUS_TYPE_SYSTEM, nullptr, on_bus_opened, this);
+ g_main_loop_run (loop);
+ }
+
+ virtual void TearDown ()
+ {
+ // close the system bus
+ g_dbus_connection_close (system_bus, nullptr, on_bus_closed, this);
+ g_main_loop_run (loop);
+ g_clear_object (&system_bus);
+
+ // tear down the test dbus
+ g_test_dbus_down (test_dbus);
+ g_clear_object (&test_dbus);
+
+ super::TearDown ();
+ }
+};
diff --git a/tests/test-formatter.cc b/tests/test-formatter.cc
index 641338b..42c828c 100644
--- a/tests/test-formatter.cc
+++ b/tests/test-formatter.cc
@@ -18,9 +18,9 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "clock-mock.h"
#include "glib-fixture.h"
+#include <datetime/clock-mock.h>
#include <datetime/formatter.h>
#include <datetime/settings-shared.h>
@@ -30,9 +30,10 @@
#include <locale.h>
using unity::indicator::datetime::Clock;
+using unity::indicator::datetime::DateTime;
+using unity::indicator::datetime::DesktopFormatter;
using unity::indicator::datetime::MockClock;
using unity::indicator::datetime::PhoneFormatter;
-using unity::indicator::datetime::DesktopFormatter;
/***
****
@@ -94,7 +95,8 @@ class FormatterFixture: public GlibFixture
TEST_F (FormatterFixture, TestPhoneHeader)
{
GDateTime * now = g_date_time_new_local (2020, 10, 31, 18, 30, 59);
- std::shared_ptr<MockClock> mock (new MockClock(now));
+ std::shared_ptr<MockClock> mock (new MockClock(DateTime(now)));
+ g_date_time_unref(now);
std::shared_ptr<Clock> clock = std::dynamic_pointer_cast<Clock>(mock);
// test the default value in a 24h locale
@@ -146,8 +148,9 @@ TEST_F (FormatterFixture, TestDesktopHeader)
{ true, true, true, true, "%a %b %e %Y" EM_SPACE "%l:%M %p" }
};
- GDateTime * now = g_date_time_new_local (2020, 10, 31, 18, 30, 59);
- std::shared_ptr<MockClock> mock (new MockClock(now));
+ GDateTime * now = g_date_time_new_local(2020, 10, 31, 18, 30, 59);
+ std::shared_ptr<MockClock> mock(new MockClock(DateTime(now)));
+ g_date_time_unref(now);
std::shared_ptr<Clock> clock = std::dynamic_pointer_cast<Clock>(mock);
for (int i=0, n=G_N_ELEMENTS(test_cases); i<n; i++)
@@ -174,44 +177,44 @@ TEST_F (FormatterFixture, TestDesktopHeader)
*/
TEST_F (FormatterFixture, TestUpcomingTimes)
{
- GDateTime * a = g_date_time_new_local (2020, 10, 31, 18, 30, 59);
+ auto a = g_date_time_new_local (2020, 10, 31, 18, 30, 59);
struct {
gboolean is_12h;
GDateTime * now;
GDateTime * then;
- GDateTime * then_end;
const char * expected_format_string;
} test_cases[] = {
- { true, g_date_time_ref(a), g_date_time_ref(a), NULL, "%l:%M %p" }, // identical time
- { true, g_date_time_ref(a), g_date_time_add_hours(a,1), NULL, "%l:%M %p" }, // later today
- { true, g_date_time_ref(a), g_date_time_add_days(a,1), NULL, "Tomorrow" EM_SPACE "%l:%M %p" }, // tomorrow
- { true, g_date_time_ref(a), g_date_time_add_days(a,2), NULL, "%a" EM_SPACE "%l:%M %p" },
- { true, g_date_time_ref(a), g_date_time_add_days(a,6), NULL, "%a" EM_SPACE "%l:%M %p" },
- { true, g_date_time_ref(a), g_date_time_add_days(a,7), NULL, "%a %d %b" EM_SPACE "%l:%M %p" }, // over one week away
-
- { false, g_date_time_ref(a), g_date_time_ref(a), NULL, "%H:%M" }, // identical time
- { false, g_date_time_ref(a), g_date_time_add_hours(a,1), NULL, "%H:%M" }, // later today
- { false, g_date_time_ref(a), g_date_time_add_days(a,1), NULL, "Tomorrow" EM_SPACE "%H:%M" }, // tomorrow
- { false, g_date_time_ref(a), g_date_time_add_days(a,2), NULL, "%a" EM_SPACE "%H:%M" },
- { false, g_date_time_ref(a), g_date_time_add_days(a,6), NULL, "%a" EM_SPACE "%H:%M" },
- { false, g_date_time_ref(a), g_date_time_add_days(a,7), NULL, "%a %d %b" EM_SPACE "%H:%M" } // over one week away
+ { true, g_date_time_ref(a), g_date_time_ref(a), "%l:%M %p" }, // identical time
+ { true, g_date_time_ref(a), g_date_time_add_hours(a,1), "%l:%M %p" }, // later today
+ { true, g_date_time_ref(a), g_date_time_add_days(a,1), "Tomorrow" EM_SPACE "%l:%M %p" }, // tomorrow
+ { true, g_date_time_ref(a), g_date_time_add_days(a,2), "%a" EM_SPACE "%l:%M %p" },
+ { true, g_date_time_ref(a), g_date_time_add_days(a,6), "%a" EM_SPACE "%l:%M %p" },
+ { true, g_date_time_ref(a), g_date_time_add_days(a,7), "%a %d %b" EM_SPACE "%l:%M %p" }, // over one week away
+
+ { false, g_date_time_ref(a), g_date_time_ref(a), "%H:%M" }, // identical time
+ { false, g_date_time_ref(a), g_date_time_add_hours(a,1), "%H:%M" }, // later today
+ { false, g_date_time_ref(a), g_date_time_add_days(a,1), "Tomorrow" EM_SPACE "%H:%M" }, // tomorrow
+ { false, g_date_time_ref(a), g_date_time_add_days(a,2), "%a" EM_SPACE "%H:%M" },
+ { false, g_date_time_ref(a), g_date_time_add_days(a,6), "%a" EM_SPACE "%H:%M" },
+ { false, g_date_time_ref(a), g_date_time_add_days(a,7), "%a %d %b" EM_SPACE "%H:%M" } // over one week away
};
for (int i=0, n=G_N_ELEMENTS(test_cases); i<n; i++)
{
if (test_cases[i].is_12h ? Set12hLocale() : Set24hLocale())
{
- std::shared_ptr<MockClock> mock (new MockClock(test_cases[i].now));
+ DateTime tmp(test_cases[i].now);
+ tmp.get();
+ std::shared_ptr<MockClock> mock (new MockClock(tmp));//DateTime(test_cases[i].now)));
std::shared_ptr<Clock> clock = std::dynamic_pointer_cast<Clock>(mock);
DesktopFormatter f (clock);
- std::string fmt = f.getRelativeFormat (test_cases[i].then, test_cases[i].then_end);
+ std::string fmt = f.getRelativeFormat (test_cases[i].then);
ASSERT_STREQ (test_cases[i].expected_format_string, fmt.c_str());
g_clear_pointer (&test_cases[i].now, g_date_time_unref);
g_clear_pointer (&test_cases[i].then, g_date_time_unref);
- g_clear_pointer (&test_cases[i].then_end, g_date_time_unref);
}
}
@@ -224,11 +227,11 @@ TEST_F (FormatterFixture, TestUpcomingTimes)
*/
TEST_F (FormatterFixture, TestEventTimes)
{
- GDateTime * day = g_date_time_new_local (2013, 1, 1, 13, 0, 0);
- GDateTime * day_begin = g_date_time_new_local (2013, 1, 1, 13, 0, 0);
- GDateTime * day_end = g_date_time_add_days (day_begin, 1);
- GDateTime * tomorrow_begin = g_date_time_add_days (day_begin, 1);
- GDateTime * tomorrow_end = g_date_time_add_days (tomorrow_begin, 1);
+ auto day = g_date_time_new_local (2013, 1, 1, 13, 0, 0);
+ auto day_begin = g_date_time_new_local (2013, 1, 1, 13, 0, 0);
+ auto day_end = g_date_time_add_days (day_begin, 1);
+ auto tomorrow_begin = g_date_time_add_days (day_begin, 1);
+ auto tomorrow_end = g_date_time_add_days (tomorrow_begin, 1);
struct {
bool is_12h;
@@ -247,7 +250,7 @@ TEST_F (FormatterFixture, TestEventTimes)
{
if (test_cases[i].is_12h ? Set12hLocale() : Set24hLocale())
{
- std::shared_ptr<MockClock> mock (new MockClock(test_cases[i].now));
+ std::shared_ptr<MockClock> mock (new MockClock(DateTime(test_cases[i].now)));
std::shared_ptr<Clock> clock = std::dynamic_pointer_cast<Clock>(mock);
DesktopFormatter f (clock);
diff --git a/tests/test-indicator.cc b/tests/test-indicator.cc
deleted file mode 100644
index 2480c94..0000000
--- a/tests/test-indicator.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
-Copyright 2012 Canonical Ltd.
-
-Authors:
- Charles Kerr <charles.kerr@canonical.com>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <gtest/gtest.h>
-
-#include <glib-object.h>
-
-/***
-****
-***/
-
-namespace
-{
- void ensure_glib_initialized ()
- {
- static bool initialized = false;
-
- if (G_UNLIKELY(!initialized))
- {
- initialized = true;
- g_setenv ("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE);
- }
- }
-}
-
-/***
-****
-***/
-
-class IndicatorTest : public ::testing::Test
-{
- private:
-
- guint log_handler_id;
-
- int log_count_ipower_actual;
-
- static void log_count_func (const gchar *log_domain,
- GLogLevelFlags log_level,
- const gchar *message,
- gpointer user_data)
- {
- reinterpret_cast<IndicatorTest*>(user_data)->log_count_ipower_actual++;
- }
-
- protected:
-
- int log_count_ipower_expected;
-
- protected:
-
- virtual void SetUp()
- {
- const GLogLevelFlags flags = GLogLevelFlags(G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING);
- log_handler_id = g_log_set_handler ("Indicator-Power", flags, log_count_func, this);
- log_count_ipower_expected = 0;
- log_count_ipower_actual = 0;
-
- ensure_glib_initialized ();
- }
-
- virtual void TearDown()
- {
- ASSERT_EQ (log_count_ipower_expected, log_count_ipower_actual);
- g_log_remove_handler ("Indicator-Power", log_handler_id);
- }
-};
-
-/***
-****
-***/
-
-TEST_F(IndicatorTest, HelloWorld)
-{
- ASSERT_TRUE (TRUE);
-}
diff --git a/tests/test-locations.cc b/tests/test-locations.cc
index c833bed..edaac69 100644
--- a/tests/test-locations.cc
+++ b/tests/test-locations.cc
@@ -19,9 +19,9 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "clock-mock.h"
#include "glib-fixture.h"
+#include <datetime/clock-mock.h>
#include <datetime/locations.h>
#include <datetime/locations-settings.h>
#include <datetime/settings-shared.h>
@@ -53,120 +53,120 @@ class LocationsFixture: public GlibFixture
const std::string nyc = "America/New_York";
const std::string chicago = "America/Chicago";
- virtual void SetUp ()
+ virtual void SetUp()
{
- super::SetUp ();
+ super::SetUp();
- settings = g_settings_new (SETTINGS_INTERFACE);
+ settings = g_settings_new(SETTINGS_INTERFACE);
const gchar * location_strv[] = { "America/Los_Angeles Oakland", "America/Chicago Chicago", "America/Chicago Oklahoma City", "America/Toronto Toronto", "Europe/London London", "Europe/Berlin Berlin", NULL };
- g_settings_set_strv (settings, SETTINGS_LOCATIONS_S, location_strv);
- g_settings_set_boolean (settings, SETTINGS_SHOW_LOCATIONS_S, true);
+ g_settings_set_strv(settings, SETTINGS_LOCATIONS_S, location_strv);
+ g_settings_set_boolean(settings, SETTINGS_SHOW_LOCATIONS_S, true);
- timezones.reset (new Timezones);
- timezones->timezone.set (chicago);
- timezones->timezones.set (std::set<std::string>({ nyc, chicago }));
+ timezones.reset(new Timezones);
+ timezones->timezone.set(chicago);
+ timezones->timezones.set(std::set<std::string>({ nyc, chicago }));
}
- virtual void TearDown ()
+ virtual void TearDown()
{
- //timezones.reset (nullptr);
- g_clear_object (&settings);
+ //timezones.reset(nullptr);
+ g_clear_object(&settings);
- super::TearDown ();
+ super::TearDown();
}
};
-TEST_F (LocationsFixture, Timezones)
+TEST_F(LocationsFixture, Timezones)
{
- g_settings_set_boolean (settings, SETTINGS_SHOW_LOCATIONS_S, false);
+ g_settings_set_boolean(settings, SETTINGS_SHOW_LOCATIONS_S, false);
- SettingsLocations locations (SETTINGS_INTERFACE, timezones);
+ SettingsLocations locations(SETTINGS_INTERFACE, timezones);
std::vector<Location> l = locations.locations.get();
- EXPECT_EQ (2, l.size());
- EXPECT_EQ ("Chicago", l[0].name);
- EXPECT_EQ (chicago, l[0].zone);
- EXPECT_EQ ("New York", l[1].name);
- EXPECT_EQ (nyc, l[1].zone);
+ EXPECT_EQ(2, l.size());
+ EXPECT_EQ("Chicago", l[0].name);
+ EXPECT_EQ(chicago, l[0].zone);
+ EXPECT_EQ("New York", l[1].name);
+ EXPECT_EQ(nyc, l[1].zone);
}
-TEST_F (LocationsFixture, SettingsLocations)
+TEST_F(LocationsFixture, SettingsLocations)
{
- SettingsLocations locations (SETTINGS_INTERFACE, timezones);
+ SettingsLocations locations(SETTINGS_INTERFACE, timezones);
std::vector<Location> l = locations.locations.get();
- EXPECT_EQ (7, l.size());
- EXPECT_EQ ("Chicago", l[0].name);
- EXPECT_EQ (chicago, l[0].zone);
- EXPECT_EQ ("New York", l[1].name);
- EXPECT_EQ (nyc, l[1].zone);
- EXPECT_EQ ("Oakland", l[2].name);
- EXPECT_EQ ("America/Los_Angeles", l[2].zone);
- EXPECT_EQ ("Oklahoma City", l[3].name);
- EXPECT_EQ ("America/Chicago", l[3].zone);
- EXPECT_EQ ("Toronto", l[4].name);
- EXPECT_EQ ("America/Toronto", l[4].zone);
- EXPECT_EQ ("London", l[5].name);
- EXPECT_EQ ("Europe/London", l[5].zone);
- EXPECT_EQ ("Berlin", l[6].name);
- EXPECT_EQ ("Europe/Berlin", l[6].zone);
+ EXPECT_EQ(7, l.size());
+ EXPECT_EQ("Chicago", l[0].name);
+ EXPECT_EQ(chicago, l[0].zone);
+ EXPECT_EQ("New York", l[1].name);
+ EXPECT_EQ(nyc, l[1].zone);
+ EXPECT_EQ("Oakland", l[2].name);
+ EXPECT_EQ("America/Los_Angeles", l[2].zone);
+ EXPECT_EQ("Oklahoma City", l[3].name);
+ EXPECT_EQ("America/Chicago", l[3].zone);
+ EXPECT_EQ("Toronto", l[4].name);
+ EXPECT_EQ("America/Toronto", l[4].zone);
+ EXPECT_EQ("London", l[5].name);
+ EXPECT_EQ("Europe/London", l[5].zone);
+ EXPECT_EQ("Berlin", l[6].name);
+ EXPECT_EQ("Europe/Berlin", l[6].zone);
}
-TEST_F (LocationsFixture, ChangeLocationStrings)
+TEST_F(LocationsFixture, ChangeLocationStrings)
{
- SettingsLocations locations (SETTINGS_INTERFACE, timezones);
+ SettingsLocations locations(SETTINGS_INTERFACE, timezones);
bool locations_changed = false;
locations.locations.changed().connect([&locations_changed, this](const std::vector<Location>&){
locations_changed = true;
- g_main_loop_quit (loop);
+ g_main_loop_quit(loop);
});
- g_idle_add ([](gpointer gsettings){
+ g_idle_add([](gpointer gsettings){
const gchar * strv[] = { "America/Los_Angeles Oakland", "Europe/London London", "Europe/Berlin Berlin", NULL };
- g_settings_set_strv (static_cast<GSettings*>(gsettings), SETTINGS_LOCATIONS_S, strv);
+ g_settings_set_strv(static_cast<GSettings*>(gsettings), SETTINGS_LOCATIONS_S, strv);
return G_SOURCE_REMOVE;
}, settings);
- g_main_loop_run (loop);
+ g_main_loop_run(loop);
- EXPECT_TRUE (locations_changed);
+ EXPECT_TRUE(locations_changed);
std::vector<Location> l = locations.locations.get();
- EXPECT_EQ (5, l.size());
- EXPECT_EQ ("Chicago", l[0].name);
- EXPECT_EQ (chicago, l[0].zone);
- EXPECT_EQ ("New York", l[1].name);
- EXPECT_EQ (nyc, l[1].zone);
- EXPECT_EQ ("Oakland", l[2].name);
- EXPECT_EQ ("America/Los_Angeles", l[2].zone);
- EXPECT_EQ ("London", l[3].name);
- EXPECT_EQ ("Europe/London", l[3].zone);
- EXPECT_EQ ("Berlin", l[4].name);
- EXPECT_EQ ("Europe/Berlin", l[4].zone);
+ EXPECT_EQ(5, l.size());
+ EXPECT_EQ("Chicago", l[0].name);
+ EXPECT_EQ(chicago, l[0].zone);
+ EXPECT_EQ("New York", l[1].name);
+ EXPECT_EQ(nyc, l[1].zone);
+ EXPECT_EQ("Oakland", l[2].name);
+ EXPECT_EQ("America/Los_Angeles", l[2].zone);
+ EXPECT_EQ("London", l[3].name);
+ EXPECT_EQ("Europe/London", l[3].zone);
+ EXPECT_EQ("Berlin", l[4].name);
+ EXPECT_EQ("Europe/Berlin", l[4].zone);
locations_changed = false;
}
-TEST_F (LocationsFixture, ChangeLocationVisibility)
+TEST_F(LocationsFixture, ChangeLocationVisibility)
{
- SettingsLocations locations (SETTINGS_INTERFACE, timezones);
+ SettingsLocations locations(SETTINGS_INTERFACE, timezones);
bool locations_changed = false;
locations.locations.changed().connect([&locations_changed, this](const std::vector<Location>&){
locations_changed = true;
- g_main_loop_quit (loop);
+ g_main_loop_quit(loop);
});
- g_idle_add ([](gpointer gsettings){
- g_settings_set_boolean (static_cast<GSettings*>(gsettings), SETTINGS_SHOW_LOCATIONS_S, false);
+ g_idle_add([](gpointer gsettings){
+ g_settings_set_boolean(static_cast<GSettings*>(gsettings), SETTINGS_SHOW_LOCATIONS_S, false);
return G_SOURCE_REMOVE;
}, settings);
- g_main_loop_run (loop);
+ g_main_loop_run(loop);
- EXPECT_TRUE (locations_changed);
+ EXPECT_TRUE(locations_changed);
std::vector<Location> l = locations.locations.get();
- EXPECT_EQ (2, l.size());
- EXPECT_EQ ("Chicago", l[0].name);
- EXPECT_EQ (chicago, l[0].zone);
- EXPECT_EQ ("New York", l[1].name);
- EXPECT_EQ (nyc, l[1].zone);
+ EXPECT_EQ(2, l.size());
+ EXPECT_EQ("Chicago", l[0].name);
+ EXPECT_EQ(chicago, l[0].zone);
+ EXPECT_EQ("New York", l[1].name);
+ EXPECT_EQ(nyc, l[1].zone);
}
diff --git a/tests/test-menus.cc b/tests/test-menus.cc
new file mode 100644
index 0000000..88e4706
--- /dev/null
+++ b/tests/test-menus.cc
@@ -0,0 +1,406 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+
+#include "actions-mock.h"
+#include "state-fixture.h"
+
+#include <datetime/clock-mock.h>
+#include <datetime/formatter.h>
+#include <datetime/locations.h>
+#include <datetime/menu.h>
+#include <datetime/planner-mock.h>
+#include <datetime/service.h>
+#include <datetime/state.h>
+#include <datetime/timezones.h>
+
+#include <gio/gio.h>
+
+using namespace unity::indicator::datetime;
+
+class MenuFixture: public StateFixture
+{
+private:
+ typedef StateFixture super;
+
+protected:
+ std::shared_ptr<MenuFactory> m_menu_factory;
+ std::vector<std::shared_ptr<Menu>> m_menus;
+
+ virtual void SetUp()
+ {
+ super::SetUp();
+
+ // build the menus on top of the actions and state
+ m_menu_factory.reset(new MenuFactory(m_actions, m_state));
+ for(int i=0; i<Menu::NUM_PROFILES; i++)
+ m_menus.push_back(m_menu_factory->buildMenu(Menu::Profile(i)));
+ }
+
+ virtual void TearDown()
+ {
+ m_menus.clear();
+ m_menu_factory.reset();
+
+ super::TearDown();
+ }
+
+ void InspectHeader(GMenuModel* menu_model, const std::string& name)
+ {
+ // check that there's a header menuitem
+ EXPECT_EQ(1,g_menu_model_get_n_items(menu_model));
+ gchar* str = nullptr;
+ g_menu_model_get_item_attribute(menu_model, 0, "x-canonical-type", "s", &str);
+ EXPECT_STREQ("com.canonical.indicator.root", str);
+ g_clear_pointer(&str, g_free);
+ g_menu_model_get_item_attribute(menu_model, 0, G_MENU_ATTRIBUTE_ACTION, "s", &str);
+ const auto action_name = name + "-header";
+ EXPECT_EQ(std::string("indicator.")+action_name, str);
+ g_clear_pointer(&str, g_free);
+
+ // check the header
+ auto dict = g_action_group_get_action_state(m_actions->action_group(), action_name.c_str());
+ EXPECT_TRUE(dict != nullptr);
+ EXPECT_TRUE(g_variant_is_of_type(dict, G_VARIANT_TYPE_VARDICT));
+ auto v = g_variant_lookup_value(dict, "accessible-desc", G_VARIANT_TYPE_STRING);
+ EXPECT_TRUE(v != nullptr);
+ g_variant_unref(v);
+ v = g_variant_lookup_value(dict, "label", G_VARIANT_TYPE_STRING);
+ EXPECT_TRUE(v != nullptr);
+ g_variant_unref(v);
+ v = g_variant_lookup_value(dict, "title", G_VARIANT_TYPE_STRING);
+ EXPECT_TRUE(v != nullptr);
+ g_variant_unref(v);
+ v = g_variant_lookup_value(dict, "visible", G_VARIANT_TYPE_BOOLEAN);
+ EXPECT_TRUE(v != nullptr);
+ g_variant_unref(v);
+ g_variant_unref(dict);
+ }
+
+ void InspectCalendar(GMenuModel* menu_model, Menu::Profile profile)
+ {
+ gchar* str = nullptr;
+ const auto actions_expected = (profile == Menu::Desktop) || (profile == Menu::Phone);
+ const auto calendar_expected = (profile == Menu::Desktop) || (profile == Menu::DesktopGreeter);
+
+ // get the calendar section
+ auto submenu = g_menu_model_get_item_link(menu_model, 0, G_MENU_LINK_SUBMENU);
+ auto section = g_menu_model_get_item_link(submenu, Menu::Calendar, G_MENU_LINK_SECTION);
+
+ // should be one or two items: a date label and maybe a calendar
+ ASSERT_TRUE(section != nullptr);
+ auto n_expected = calendar_expected ? 2 : 1;
+ EXPECT_EQ(n_expected, g_menu_model_get_n_items(section));
+
+ // look at the date menuitem
+ g_menu_model_get_item_attribute(section, 0, G_MENU_ATTRIBUTE_LABEL, "s", &str);
+ const auto now = m_state->clock->localtime();
+ EXPECT_EQ(now.format("%A, %e %B %Y"), str);
+
+ g_clear_pointer(&str, g_free);
+
+ g_menu_model_get_item_attribute(section, 0, G_MENU_ATTRIBUTE_ACTION, "s", &str);
+ if (actions_expected)
+ EXPECT_STREQ("indicator.activate-planner", str);
+ else
+ EXPECT_TRUE(str == nullptr);
+ g_clear_pointer(&str, g_free);
+
+ // look at the calendar menuitem
+ if (calendar_expected)
+ {
+ g_menu_model_get_item_attribute(section, 1, "x-canonical-type", "s", &str);
+ EXPECT_STREQ("com.canonical.indicator.calendar", str);
+ g_clear_pointer(&str, g_free);
+
+ g_menu_model_get_item_attribute(section, 1, G_MENU_ATTRIBUTE_ACTION, "s", &str);
+ EXPECT_STREQ("indicator.calendar", str);
+ g_clear_pointer(&str, g_free);
+
+ g_menu_model_get_item_attribute(section, 1, "activation-action", "s", &str);
+ if (actions_expected)
+ EXPECT_STREQ("indicator.activate-planner", str);
+ else
+ EXPECT_TRUE(str == nullptr);
+ g_clear_pointer(&str, g_free);
+ }
+
+ g_clear_object(&section);
+
+ // now change the clock and see if the date label changes appropriately
+
+ auto gdt_tomorrow = g_date_time_add_days(now.get(), 1);
+ auto tomorrow = DateTime(gdt_tomorrow);
+ g_date_time_unref(gdt_tomorrow);
+ m_clock->set_localtime(tomorrow);
+ wait_msec();
+
+ section = g_menu_model_get_item_link(submenu, Menu::Calendar, G_MENU_LINK_SECTION);
+ g_menu_model_get_item_attribute(section, 0, G_MENU_ATTRIBUTE_LABEL, "s", &str);
+ EXPECT_EQ(tomorrow.format("%A, %e %B %Y"), str);
+ g_clear_pointer(&str, g_free);
+ g_clear_object(&section);
+
+ // cleanup
+ g_object_unref(submenu);
+ }
+
+ void InspectAppointments(GMenuModel* menu_model, Menu::Profile profile)
+ {
+ const bool appointments_expected = (profile == Menu::Desktop)
+ || (profile == Menu::Phone);
+
+ // get the Appointments section
+ auto submenu = g_menu_model_get_item_link(menu_model, 0, G_MENU_LINK_SUBMENU);
+
+ // there shouldn't be any menuitems when "show events" is false
+ m_state->show_events.set(false);
+ wait_msec();
+ auto section = g_menu_model_get_item_link(submenu, Menu::Appointments, G_MENU_LINK_SECTION);
+ EXPECT_EQ(0, g_menu_model_get_n_items(section));
+ g_clear_object(&section);
+
+ // when "show_events" is true,
+ // there should be an "add event" button even if there aren't any appointments
+ std::vector<Appointment> appointments;
+ m_state->show_events.set(true);
+ m_state->planner->upcoming.set(appointments);
+ wait_msec();
+ section = g_menu_model_get_item_link(submenu, Menu::Appointments, G_MENU_LINK_SECTION);
+ int expected_n = appointments_expected ? 1 : 0;
+ EXPECT_EQ(expected_n, g_menu_model_get_n_items(section));
+ g_clear_object(&section);
+
+ // try adding a few appointments and see if the menu updates itself
+
+ const auto now = m_state->clock->localtime();
+ auto gdt_tomorrow = g_date_time_add_days(now.get(), 1);
+ const auto tomorrow = DateTime(gdt_tomorrow);
+ g_date_time_unref(gdt_tomorrow);
+
+ Appointment a1; // an alarm clock appointment
+ a1.color = "red";
+ a1.summary = "Alarm";
+ a1.summary = "http://www.example.com/";
+ a1.uid = "example";
+ a1.has_alarms = true;
+ a1.begin = a1.end = tomorrow;
+ appointments.push_back(a1);
+
+ Appointment a2; // a non-alarm appointment
+ a2.color = "green";
+ a2.summary = "Other Text";
+ a2.summary = "http://www.monkey.com/";
+ a2.uid = "monkey";
+ a2.has_alarms = false;
+ a2.begin = a2.end = tomorrow;
+ appointments.push_back(a2);
+
+ m_state->planner->upcoming.set(appointments);
+ wait_msec(); // wait a moment for the menu to update
+
+ section = g_menu_model_get_item_link(submenu, Menu::Appointments, G_MENU_LINK_SECTION);
+ expected_n = appointments_expected ? 3 : 0;
+ EXPECT_EQ(expected_n, g_menu_model_get_n_items(section));
+ if (appointments_expected)
+ {
+ gchar * str = nullptr;
+
+ // test the alarm
+ // - confirm it has an x-canonical-type of "alarm"
+ g_menu_model_get_item_attribute(section, 0, "x-canonical-type", "s", &str);
+ EXPECT_STREQ("com.canonical.indicator.alarm", str);
+ g_clear_pointer(&str, g_free);
+ // - confirm it has a nonempty x-canonical-time-format
+ g_menu_model_get_item_attribute(section, 0, "x-canonical-time-format", "s", &str);
+ EXPECT_TRUE(str && *str);
+ g_clear_pointer(&str, g_free);
+ // - confirm it has a serialized icon attribute
+ auto v = g_menu_model_get_item_attribute_value(section, 0, G_MENU_ATTRIBUTE_ICON, nullptr);
+ EXPECT_TRUE(v != nullptr);
+ auto icon = g_icon_deserialize(v);
+ EXPECT_TRUE(icon != nullptr);
+ g_clear_object(&icon);
+ g_clear_pointer(&v, g_variant_unref);
+
+ // test the appointment
+ // - confirm it has an x-canonical-type of "appointment"
+ g_menu_model_get_item_attribute(section, 1, "x-canonical-type", "s", &str);
+ EXPECT_STREQ("com.canonical.indicator.appointment", str);
+ g_clear_pointer(&str, g_free);
+ // - confirm it has a nonempty x-canonical-time-format
+ g_menu_model_get_item_attribute(section, 0, "x-canonical-time-format", "s", &str);
+ EXPECT_TRUE(str && *str);
+ g_clear_pointer(&str, g_free);
+ // - confirm its color matches the one we fed the appointments vector
+ g_menu_model_get_item_attribute(section, 1, "x-canonical-color", "s", &str);
+ EXPECT_EQ(a2.color, str);
+ g_clear_pointer(&str, g_free);
+ }
+ g_clear_object(&section);
+
+ g_object_unref(submenu);
+ }
+
+ void CompareLocationsTo(GMenuModel* menu_model, const std::vector<Location>& locations)
+ {
+ // get the Locations section
+ auto submenu = g_menu_model_get_item_link(menu_model, 0, G_MENU_LINK_SUBMENU);
+ auto section = g_menu_model_get_item_link(submenu, Menu::Locations, G_MENU_LINK_SECTION);
+
+ // confirm that section's menuitems mirror the "locations" vector
+ const auto n = locations.size();
+ ASSERT_EQ(n, g_menu_model_get_n_items(section));
+ for (guint i=0; i<n; i++)
+ {
+ gchar* str = nullptr;
+
+ // confirm that the x-canonical-type is right
+ g_menu_model_get_item_attribute(section, i, "x-canonical-type", "s", &str);
+ EXPECT_STREQ("com.canonical.indicator.location", str);
+ g_clear_pointer(&str, g_free);
+
+ // confirm that the timezones match the ones in the vector
+ g_menu_model_get_item_attribute(section, i, "x-canonical-timezone", "s", &str);
+ EXPECT_EQ(locations[i].zone(), str);
+ g_clear_pointer(&str, g_free);
+
+ // confirm that x-canonical-time-format has some kind of time format string
+ g_menu_model_get_item_attribute(section, i, "x-canonical-time-format", "s", &str);
+ EXPECT_TRUE(str && *str && (strchr(str,'%')!=nullptr));
+ g_clear_pointer(&str, g_free);
+ }
+
+ g_clear_object(&section);
+ g_clear_object(&submenu);
+ }
+
+ void InspectLocations(GMenuModel* menu_model, Menu::Profile profile)
+ {
+ const bool locations_expected = profile == Menu::Desktop;
+
+ // when there aren't any locations, confirm the menu is empty
+ const std::vector<Location> empty;
+ m_state->locations->locations.set(empty);
+ wait_msec();
+ CompareLocationsTo(menu_model, empty);
+
+ // add some locations and confirm the menu picked up our changes
+ Location l1 ("America/Chicago", "Dallas");
+ Location l2 ("America/Arizona", "Phoenix");
+ std::vector<Location> locations({l1, l2});
+ m_state->locations->locations.set(locations);
+ wait_msec();
+ CompareLocationsTo(menu_model, locations_expected ? locations : empty);
+
+ // now remove one of the locations...
+ locations.pop_back();
+ m_state->locations->locations.set(locations);
+ wait_msec();
+ CompareLocationsTo(menu_model, locations_expected ? locations : empty);
+ }
+
+ void InspectSettings(GMenuModel* menu_model, Menu::Profile profile)
+ {
+ std::string expected_action;
+
+ if (profile == Menu::Desktop)
+ expected_action = "indicator.activate-desktop-settings";
+ else if (profile == Menu::Phone)
+ expected_action = "indicator.activate-phone-settings";
+
+ // get the Settings section
+ auto submenu = g_menu_model_get_item_link(menu_model, 0, G_MENU_LINK_SUBMENU);
+ auto section = g_menu_model_get_item_link(submenu, Menu::Settings, G_MENU_LINK_SECTION);
+
+ if (expected_action.empty())
+ {
+ EXPECT_EQ(0, g_menu_model_get_n_items(section));
+ }
+ else
+ {
+ EXPECT_EQ(1, g_menu_model_get_n_items(section));
+ gchar* str = nullptr;
+ g_menu_model_get_item_attribute(section, 0, G_MENU_ATTRIBUTE_ACTION, "s", &str);
+ EXPECT_EQ(expected_action, str);
+ g_clear_pointer(&str, g_free);
+ }
+
+ g_clear_object(&section);
+ g_object_unref(submenu);
+ }
+};
+
+
+TEST_F(MenuFixture, HelloWorld)
+{
+ EXPECT_EQ(Menu::NUM_PROFILES, m_menus.size());
+ for (int i=0; i<Menu::NUM_PROFILES; i++)
+ {
+ EXPECT_TRUE(m_menus[i] != false);
+ EXPECT_TRUE(m_menus[i]->menu_model() != nullptr);
+ EXPECT_EQ(i, m_menus[i]->profile());
+ }
+ EXPECT_EQ(m_menus[Menu::Desktop]->name(), "desktop");
+}
+
+TEST_F(MenuFixture, Header)
+{
+ for(auto& menu : m_menus)
+ InspectHeader(menu->menu_model(), menu->name());
+}
+
+TEST_F(MenuFixture, Sections)
+{
+ for(auto& menu : m_menus)
+ {
+ // check that the header has a submenu
+ auto menu_model = menu->menu_model();
+ auto submenu = g_menu_model_get_item_link(menu_model, 0, G_MENU_LINK_SUBMENU);
+ EXPECT_TRUE(submenu != nullptr);
+ EXPECT_EQ(Menu::NUM_SECTIONS, g_menu_model_get_n_items(submenu));
+ g_object_unref(submenu);
+ }
+}
+
+TEST_F(MenuFixture, Calendar)
+{
+ for(auto& menu : m_menus)
+ InspectCalendar(menu->menu_model(), menu->profile());
+}
+
+TEST_F(MenuFixture, Appointments)
+{
+ for(auto& menu : m_menus)
+ InspectAppointments(menu->menu_model(), menu->profile());
+}
+
+TEST_F(MenuFixture, Locations)
+{
+ for(auto& menu : m_menus)
+ InspectLocations(menu->menu_model(), menu->profile());
+}
+
+TEST_F(MenuFixture, Settings)
+{
+ for(auto& menu : m_menus)
+ InspectSettings(menu->menu_model(), menu->profile());
+}
+
+
diff --git a/tests/test-planner-eds.cc b/tests/test-planner-eds.cc
deleted file mode 100644
index 986a45e..0000000
--- a/tests/test-planner-eds.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2013 Canonical Ltd.
- *
- * Authors:
- * Charles Kerr <charles.kerr@canonical.com>
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 3, as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranties of
- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "clock-mock.h"
-#include "glib-fixture.h"
-
-#include <datetime/planner-eds.h>
-
-#include <glib/gi18n.h>
-
-#include <langinfo.h>
-#include <locale.h>
-
-using unity::indicator::datetime::Appointment;
-using unity::indicator::datetime::DateTime;
-using unity::indicator::datetime::PlannerEds;
-
-/***
-****
-***/
-
-class PlannerEdsFixture: public GlibFixture
-{
- private:
-
- typedef GlibFixture super;
-
- protected:
-
- virtual void SetUp ()
- {
- super::SetUp ();
- }
-
- virtual void TearDown ()
- {
- super::TearDown ();
- }
-};
-
-/***
-****
-***/
-
-TEST_F (PlannerEdsFixture, HelloWorld)
-{
- DateTime dt;
- dt = g_date_time_new_now_local();
-
- PlannerEds planner;
- planner.time.set (dt);
- g_main_loop_run (loop);
-}
-
diff --git a/tests/test-planner.cc b/tests/test-planner.cc
index 8c74366..3072aea 100644
--- a/tests/test-planner.cc
+++ b/tests/test-planner.cc
@@ -17,18 +17,20 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "clock-mock.h"
#include "glib-fixture.h"
#include <datetime/appointment.h>
+#include <datetime/clock-mock.h>
+#include <datetime/date-time.h>
#include <datetime/planner.h>
-
-#include <glib/gi18n.h>
+#include <datetime/planner-eds.h>
#include <langinfo.h>
#include <locale.h>
using unity::indicator::datetime::Appointment;
+using unity::indicator::datetime::DateTime;
+using unity::indicator::datetime::PlannerEds;
/***
****
@@ -36,33 +38,48 @@ using unity::indicator::datetime::Appointment;
typedef GlibFixture PlannerFixture;
+TEST_F(PlannerFixture, EDS)
+{
+ PlannerEds planner;
+ wait_msec(100);
+
+ auto now = g_date_time_new_now_local();
+ planner.time.set(DateTime(now));
+ wait_msec(2500);
+
+ std::vector<Appointment> thisMonth = planner.thisMonth.get();
+ std::cerr << thisMonth.size() << " appointments this month" << std::endl;
+ for(const auto& a : thisMonth)
+ std::cerr << a.summary << std::endl;
+}
+
-TEST_F (PlannerFixture, HelloWorld)
+TEST_F(PlannerFixture, HelloWorld)
{
- GDateTime * halloween = g_date_time_new_local (2020, 10, 31, 18, 30, 59);
- GDateTime * christmas = g_date_time_new_local (2020, 12, 25, 0, 0, 0);
+ auto halloween = g_date_time_new_local(2020, 10, 31, 18, 30, 59);
+ auto christmas = g_date_time_new_local(2020, 12, 25, 0, 0, 0);
Appointment a;
a.summary = "Test";
a.begin = halloween;
- a.end = g_date_time_add_hours (halloween, 1);
+ a.end = g_date_time_add_hours(halloween, 1);
const Appointment b = a;
a.summary = "Foo";
- EXPECT_EQ (a.summary, "Foo");
- EXPECT_EQ (b.summary, "Test");
- EXPECT_EQ (0, g_date_time_compare (a.begin(), b.begin()));
- EXPECT_EQ (0, g_date_time_compare (a.end(), b.end()));
+ EXPECT_EQ(a.summary, "Foo");
+ EXPECT_EQ(b.summary, "Test");
+ EXPECT_EQ(0, g_date_time_compare(a.begin(), b.begin()));
+ EXPECT_EQ(0, g_date_time_compare(a.end(), b.end()));
Appointment c;
c.begin = christmas;
- c.end = g_date_time_add_hours (christmas, 1);
+ c.end = g_date_time_add_hours(christmas, 1);
Appointment d;
d = c;
- EXPECT_EQ (0, g_date_time_compare (c.begin(), d.begin()));
- EXPECT_EQ (0, g_date_time_compare (c.end(), d.end()));
+ EXPECT_EQ(0, g_date_time_compare(c.begin(), d.begin()));
+ EXPECT_EQ(0, g_date_time_compare(c.end(), d.end()));
a = d;
- EXPECT_EQ (0, g_date_time_compare (d.begin(), a.begin()));
- EXPECT_EQ (0, g_date_time_compare (d.end(), a.end()));
+ EXPECT_EQ(0, g_date_time_compare(d.begin(), a.begin()));
+ EXPECT_EQ(0, g_date_time_compare(d.end(), a.end()));
}
diff --git a/tests/test-skew.cc b/tests/test-skew.cc
deleted file mode 100644
index 90c0164..0000000
--- a/tests/test-skew.cc
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright 2013 Canonical Ltd.
- *
- * Authors:
- * Charles Kerr <charles.kerr@canonical.com>
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 3, as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranties of
- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "glib-fixture.h"
-
-#include "Clock.h"
-#include "MockClock.h"
-
-/***
-****
-***/
-
-using unity::indicator::datetime::Clock;
-using unity::indicator::datetime::MockClock;
-using unity::indicator::datetime::SkewDetector;
-
-class SkewFixture: public GlibFixture
-{
- private:
-
- typedef GlibFixture super;
-
- static void
- on_bus_opened (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself)
- {
- auto self = static_cast<SkewFixture*>(gself);
-
- GError * err = 0;
- self->system_bus = g_bus_get_finish (res, &err);
- g_assert_no_error (err);
-
- g_main_loop_quit (self->loop);
- }
-
- static void
- on_bus_closed (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself)
- {
- auto self = static_cast<SkewFixture*>(gself);
-
- GError * err = 0;
- g_dbus_connection_close_finish (self->system_bus, res, &err);
- g_assert_no_error (err);
-
- g_main_loop_quit (self->loop);
- }
-
- protected:
-
- std::shared_ptr<Clock> mockClock;
- GTestDBus * test_dbus;
- GDBusConnection * system_bus;
-
- virtual void SetUp ()
- {
- super::SetUp ();
-
- // pull up a test dbus
- test_dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
- g_test_dbus_up (test_dbus);
- const char * address = g_test_dbus_get_bus_address (test_dbus);
- g_setenv ("DBUS_SYSTEM_BUS_ADDRESS", address, TRUE);
- g_debug ("test_dbus's address is %s", address);
-
- // wait for the GDBusConnection before returning
- g_bus_get (G_BUS_TYPE_SYSTEM, nullptr, on_bus_opened, this);
- g_main_loop_run (loop);
-
- // create a clock
- GDateTime * now = g_date_time_new_now_local ();
- mockClock.reset (new MockClock (now));
- g_date_time_unref (now);
- }
-
- virtual void TearDown ()
- {
- mockClock.reset();
-
- // close the system bus
- g_dbus_connection_close (system_bus, nullptr, on_bus_closed, this);
- g_main_loop_run (loop);
- g_clear_object (&system_bus);
-
- // tear down the test dbus
- g_test_dbus_down (test_dbus);
- g_clear_object (&test_dbus);
-
- super::TearDown ();
- }
-
- public:
-
- void emitPrepareForSleep ()
- {
- g_dbus_connection_emit_signal (g_bus_get_sync (G_BUS_TYPE_SYSTEM, nullptr, nullptr),
- NULL,
- "/org/freedesktop/login1", // object path
- "org.freedesktop.login1.Manager", // interface
- "PrepareForSleep", // signal name
- g_variant_new("(b)", FALSE),
- NULL);
- }
-};
-
-
-/**
- * A simple "hello world" style test.
- */
-TEST_F (SkewFixture, CanInstantiate)
-{
- SkewDetector skew (std::dynamic_pointer_cast<Clock>(mockClock));
- wait_msec (500); // wait for the bus to set up
-}
-
-
-/**
- * Confirm that changing the clock's timezone triggers a skew event
- */
-TEST_F (SkewFixture, ChangingTimezonesTriggersEvent)
-{
- SkewDetector skew (std::dynamic_pointer_cast<Clock>(mockClock));
- wait_msec (500); // wait for the bus to set up
-
- bool skewed = false;
- skew.skewDetected.connect([&skewed, this](){
- skewed = true;
- g_main_loop_quit(loop);
- return G_SOURCE_REMOVE;
- });
-
- g_idle_add([](gpointer gclock){
- GDateTime * arbitrary = g_date_time_new_local (2020, 10, 31, 18, 30, 59);
- static_cast<MockClock*>(gclock)->setLocaltime (arbitrary);
- g_date_time_unref (arbitrary);
- return G_SOURCE_REMOVE;
- }, mockClock.get());
-
- wait_msec (1000);
-
- EXPECT_TRUE (skewed);
- GDateTime * expected = g_date_time_new_local (2020, 10, 31, 18, 30, 59);
- GDateTime * actual = mockClock->localtime();
- EXPECT_EQ (0, g_date_time_compare (expected, actual));
- g_date_time_unref (actual);
- g_date_time_unref (expected);
-}
-
-/**
- * Confirm that a "PrepareForSleep" event wil trigger a skew event
- */
-TEST_F (SkewFixture, PrepareForSleep)
-{
- SkewDetector skew (std::dynamic_pointer_cast<Clock>(mockClock));
- wait_msec (500); // wait for the bus to set up
-
- bool skewed = false;
- skew.skewDetected.connect([&skewed, this](){
- skewed = true;
- g_main_loop_quit(loop);
- return G_SOURCE_REMOVE;
- });
-
- g_idle_add ([](gpointer gself){
- static_cast<SkewFixture*>(gself)->emitPrepareForSleep();
- return G_SOURCE_REMOVE;
- }, this);
-
- wait_msec (1000);
- EXPECT_TRUE(skewed);
-}
-
-
-/**
- * Confirm that normal time passing doesn't trigger a skew event.
- * that idling changing the clock's time triggers a skew event
- */
-TEST_F (SkewFixture, IdleDoesNotTriggerEvent)
-{
- SkewDetector skew (std::dynamic_pointer_cast<Clock>(mockClock));
- wait_msec (500); // wait for the bus to set up
-
- bool skewed = false;
- skew.skewDetected.connect([&skewed](){
- skewed = true;
- g_warn_if_reached();
- //abort();
- return G_SOURCE_REMOVE;
- });
-
- const unsigned int intervalSec = 4;
- skew.intervalSec.set(intervalSec);
- wait_msec (intervalSec * 2.5 * 1000);
- EXPECT_FALSE (skewed);
-}
diff --git a/tests/test-timezone-file.cc b/tests/test-timezone-file.cc
index 510d12c..453b353 100644
--- a/tests/test-timezone-file.cc
+++ b/tests/test-timezone-file.cc
@@ -52,25 +52,25 @@ class TimezoneFixture: public GlibFixture
protected:
- virtual void SetUp ()
+ virtual void SetUp()
{
- super::SetUp ();
+ super::SetUp();
}
- virtual void TearDown ()
+ virtual void TearDown()
{
- super::TearDown ();
+ super::TearDown();
}
public:
/* convenience func to set the timezone file */
- void set_file (const std::string& text)
+ void set_file(const std::string& text)
{
- FILE * fp = fopen (TIMEZONE_FILE, "w+");
- fprintf (fp, "%s\n", text.c_str());
- fclose (fp);
- sync ();
+ auto fp = fopen(TIMEZONE_FILE, "w+");
+ fprintf(fp, "%s\n", text.c_str());
+ fclose(fp);
+ sync();
}
};
@@ -78,56 +78,56 @@ class TimezoneFixture: public GlibFixture
/**
* Test that timezone-file warns, but doesn't crash, if the timezone file doesn't exist
*/
-TEST_F (TimezoneFixture, NoFile)
+TEST_F(TimezoneFixture, NoFile)
{
- remove (TIMEZONE_FILE);
- ASSERT_FALSE (g_file_test (TIMEZONE_FILE, G_FILE_TEST_EXISTS));
+ remove(TIMEZONE_FILE);
+ ASSERT_FALSE(g_file_test(TIMEZONE_FILE, G_FILE_TEST_EXISTS));
- FileTimezone tz (TIMEZONE_FILE);
- testLogCount (G_LOG_LEVEL_WARNING, 1);
+ FileTimezone tz(TIMEZONE_FILE);
+ testLogCount(G_LOG_LEVEL_WARNING, 1);
}
/**
* Test that timezone-file picks up the initial value
*/
-TEST_F (TimezoneFixture, InitialValue)
+TEST_F(TimezoneFixture, InitialValue)
{
const std::string expected_timezone = "America/Chicago";
- set_file (expected_timezone);
- FileTimezone tz (TIMEZONE_FILE);
- ASSERT_EQ (expected_timezone, tz.timezone.get());
+ set_file(expected_timezone);
+ FileTimezone tz(TIMEZONE_FILE);
+ ASSERT_EQ(expected_timezone, tz.timezone.get());
}
/**
* Test that clearing the timezone results in an empty string
*/
-TEST_F (TimezoneFixture, ChangedValue)
+TEST_F(TimezoneFixture, ChangedValue)
{
const std::string initial_timezone = "America/Chicago";
const std::string changed_timezone = "America/New_York";
- set_file (initial_timezone);
+ set_file(initial_timezone);
- FileTimezone tz (TIMEZONE_FILE);
- ASSERT_EQ (initial_timezone, tz.timezone.get());
+ FileTimezone tz(TIMEZONE_FILE);
+ ASSERT_EQ(initial_timezone, tz.timezone.get());
bool changed = false;
auto connection = tz.timezone.changed().connect(
[&changed, this](const std::string& s){
- g_message ("timezone changed to %s", s.c_str());
+ g_message("timezone changed to %s", s.c_str());
changed = true;
- g_main_loop_quit (loop);
+ g_main_loop_quit(loop);
});
- g_idle_add ([](gpointer gself){
- static_cast<TimezoneFixture*>(gself)->set_file ("America/New_York");
- // static_cast<FileTimezone*>(gtz)->timezone.set ("America/New_York");
+ g_idle_add([](gpointer gself){
+ static_cast<TimezoneFixture*>(gself)->set_file("America/New_York");
+ // static_cast<FileTimezone*>(gtz)->timezone.set("America/New_York");
return G_SOURCE_REMOVE;
}, this);//&tz);
- g_main_loop_run (loop);
+ g_main_loop_run(loop);
- ASSERT_TRUE (changed);
- ASSERT_EQ (changed_timezone, tz.timezone.get());
+ ASSERT_TRUE(changed);
+ ASSERT_EQ(changed_timezone, tz.timezone.get());
}
diff --git a/tests/test-timezone-geoclue.cc b/tests/test-timezone-geoclue.cc
index a577fbd..4bf08a7 100644
--- a/tests/test-timezone-geoclue.cc
+++ b/tests/test-timezone-geoclue.cc
@@ -46,21 +46,21 @@ namespace
const std::string& timezone_): mock(mock_), obj_client(obj_client_), timezone(timezone_) {}
};
- gboolean emit_address_changed_idle (gpointer gdata)
+ gboolean emit_address_changed_idle(gpointer gdata)
{
auto data = static_cast<EmitAddressChangedData*>(gdata);
GError * error = nullptr;
- dbus_test_dbus_mock_object_emit_signal (data->mock, data->obj_client,
+ dbus_test_dbus_mock_object_emit_signal(data->mock, data->obj_client,
"org.freedesktop.Geoclue.Address",
"AddressChanged",
G_VARIANT_TYPE("(ia{ss}(idd))"),
- g_variant_new_parsed ("(1385238033, {'timezone': 'America/Chicago'}, (3, 0.0, 0.0))"),
+ g_variant_new_parsed("(1385238033, {'timezone': 'America/Chicago'}, (3, 0.0, 0.0))"),
&error);
if (error)
{
- g_warning ("%s: %s", G_STRFUNC, error->message);
- g_error_free (error);
+ g_warning("%s: %s", G_STRFUNC, error->message);
+ g_error_free(error);
}
delete data;
@@ -69,29 +69,29 @@ namespace
}
#endif
-TEST_F (TimezoneGeoclueFixture, ChangeDetected)
+TEST_F(TimezoneGeoclueFixture, ChangeDetected)
{
// const std::string timezone_1 = "America/Denver";
const std::string timezone_2 = "America/Chicago";
GeoclueTimezone tz;
- wait_msec (500); // wait for the bus to get set up
- EXPECT_EQ (timezone_1, tz.timezone.get());
+ wait_msec(500); // wait for the bus to get set up
+ EXPECT_EQ(timezone_1, tz.timezone.get());
// start listening for a timezone change, then change the timezone
bool changed = false;
auto connection = tz.timezone.changed().connect(
[&changed, this](const std::string& s){
- g_debug ("timezone changed to %s", s.c_str());
+ g_debug("timezone changed to %s", s.c_str());
changed = true;
- g_main_loop_quit (loop);
+ g_main_loop_quit(loop);
});
- setGeoclueTimezoneOnIdle (timezone_2);
- //g_timeout_add (50, emit_address_changed_idle, new EmitAddressChangedData(mock, obj_client, timezone_2.c_str()));
- g_main_loop_run (loop);
- EXPECT_EQ (timezone_2, tz.timezone.get());
+ setGeoclueTimezoneOnIdle(timezone_2);
+ //g_timeout_add(50, emit_address_changed_idle, new EmitAddressChangedData(mock, obj_client, timezone_2.c_str()));
+ g_main_loop_run(loop);
+ EXPECT_EQ(timezone_2, tz.timezone.get());
}
diff --git a/tests/test-timezones.cc b/tests/test-timezones.cc
index cda53a6..d3c8e3a 100644
--- a/tests/test-timezones.cc
+++ b/tests/test-timezones.cc
@@ -33,33 +33,34 @@ typedef GeoclueFixture TimezonesFixture;
namespace
{
/* convenience func to set the timezone file */
- void set_file (const std::string& text)
+ void set_file(const std::string& text)
{
- FILE * fp = fopen (TIMEZONE_FILE, "w+");
- fprintf (fp, "%s\n", text.c_str());
- fclose (fp);
- sync ();
+ auto fp = fopen(TIMEZONE_FILE, "w+");
+ fprintf(fp, "%s\n", text.c_str());
+ fclose(fp);
+ sync();
}
}
-TEST_F (TimezonesFixture, ManagerTest)
+TEST_F(TimezonesFixture, ManagerTest)
{
std::string timezone_file = "America/New_York";
std::string timezone_geo = "America/Denver";
- set_file (timezone_file);
- LiveTimezones z (TIMEZONE_FILE);
- wait_msec (500); // wait for the bus to get set up
- EXPECT_EQ (timezone_file, z.timezone.get());
- std::set<std::string> zones = z.timezones.get();
- EXPECT_EQ (1, zones.size());
- EXPECT_EQ (1, zones.count(timezone_file));
+ set_file(timezone_file);
+ LiveTimezones z(TIMEZONE_FILE);
+ wait_msec(500); // wait for the bus to get set up
+ EXPECT_EQ(timezone_file, z.timezone.get());
+ auto zones = z.timezones.get();
+ //std::set<std::string> zones = z.timezones.get();
+ EXPECT_EQ(1, zones.size());
+ EXPECT_EQ(1, zones.count(timezone_file));
bool zone_changed = false;
auto zone_connection = z.timezone.changed().connect([&zone_changed, this](const std::string&) {
zone_changed = true;
- g_main_loop_quit (loop);
+ g_main_loop_quit(loop);
});
// start listening for a timezone change, then change the timezone
@@ -67,24 +68,24 @@ TEST_F (TimezonesFixture, ManagerTest)
auto zones_connection = z.timezones.changed().connect([&zones_changed, &zones, this](const std::set<std::string>& timezones) {
zones_changed = true;
zones = timezones;
- g_main_loop_quit (loop);
+ g_main_loop_quit(loop);
});
- g_idle_add ([](gpointer gz) {
+ g_idle_add([](gpointer gz) {
auto az = static_cast<LiveTimezones*>(gz);
- g_message ("geolocation was %d", (int)az->geolocationEnabled.get());
- g_message ("turning geolocation on");
+ g_message("geolocation was %d", (int)az->geolocationEnabled.get());
+ g_message("turning geolocation on");
az->geolocationEnabled.set(true);
return G_SOURCE_REMOVE;
}, &z);
// turn on geoclue during the idle... this should add timezone_1 to the 'timezones' property
- g_main_loop_run (loop);
- EXPECT_TRUE (zones_changed);
- EXPECT_EQ (timezone_file, z.timezone.get());
- EXPECT_EQ (2, zones.size());
- EXPECT_EQ (1, zones.count(timezone_file));
- EXPECT_EQ (1, zones.count(timezone_geo));
+ g_main_loop_run(loop);
+ EXPECT_TRUE(zones_changed);
+ EXPECT_EQ(timezone_file, z.timezone.get());
+ EXPECT_EQ(2, zones.size());
+ EXPECT_EQ(1, zones.count(timezone_file));
+ EXPECT_EQ(1, zones.count(timezone_geo));
zones_changed = false;
// now tweak the geoclue value... the geoclue-detected timezone should change,
@@ -92,28 +93,28 @@ TEST_F (TimezonesFixture, ManagerTest)
zone_changed = false;
zones_changed = false;
timezone_geo = "America/Chicago";
- setGeoclueTimezoneOnIdle (timezone_geo);
- g_main_loop_run (loop);
- EXPECT_FALSE (zone_changed);
- EXPECT_TRUE (zones_changed);
- EXPECT_EQ (timezone_file, z.timezone.get());
- EXPECT_EQ (2, zones.size());
- EXPECT_EQ (1, zones.count(timezone_file));
- EXPECT_EQ (1, zones.count(timezone_geo));
+ setGeoclueTimezoneOnIdle(timezone_geo);
+ g_main_loop_run(loop);
+ EXPECT_FALSE(zone_changed);
+ EXPECT_TRUE(zones_changed);
+ EXPECT_EQ(timezone_file, z.timezone.get());
+ EXPECT_EQ(2, zones.size());
+ EXPECT_EQ(1, zones.count(timezone_file));
+ EXPECT_EQ(1, zones.count(timezone_geo));
// now set the file value... this should change both the primary property and set property
zone_changed = false;
zones_changed = false;
timezone_file = "America/Los_Angeles";
- EXPECT_EQ (0, zones.count(timezone_file));
- g_idle_add ([](gpointer str) {set_file(static_cast<const char*>(str)); return G_SOURCE_REMOVE;}, const_cast<char*>(timezone_file.c_str()));
- g_main_loop_run (loop);
- EXPECT_TRUE (zone_changed);
- EXPECT_TRUE (zones_changed);
- EXPECT_EQ (timezone_file, z.timezone.get());
- EXPECT_EQ (2, zones.size());
- EXPECT_EQ (1, zones.count(timezone_file));
- EXPECT_EQ (1, zones.count(timezone_geo));
+ EXPECT_EQ(0, zones.count(timezone_file));
+ g_idle_add([](gpointer str) {set_file(static_cast<const char*>(str)); return G_SOURCE_REMOVE;}, const_cast<char*>(timezone_file.c_str()));
+ g_main_loop_run(loop);
+ EXPECT_TRUE(zone_changed);
+ EXPECT_TRUE(zones_changed);
+ EXPECT_EQ(timezone_file, z.timezone.get());
+ EXPECT_EQ(2, zones.size());
+ EXPECT_EQ(1, zones.count(timezone_file));
+ EXPECT_EQ(1, zones.count(timezone_geo));
diff --git a/tests/test-utils.cc b/tests/test-utils.cc
index d0f277b..8246396 100644
--- a/tests/test-utils.cc
+++ b/tests/test-utils.cc
@@ -1,21 +1,21 @@
/*
-Copyright 2012 Canonical Ltd.
-
-Authors:
- Charles Kerr <charles.kerr@canonical.com>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
#include <gtest/gtest.h>
@@ -27,36 +27,33 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
****
***/
-TEST (UtilsTest, SplitSettingsLocation)
+TEST(UtilsTest, SplitSettingsLocation)
{
- guint i;
- guint n;
-
- struct {
- const char * location;
- const char * expected_zone;
- const char * expected_name;
- } test_cases[] = {
- { "America/Chicago Chicago", "America/Chicago", "Chicago" },
- { "America/Chicago Oklahoma City", "America/Chicago", "Oklahoma City" },
- { "America/Los_Angeles", "America/Los_Angeles", "Los Angeles" },
- { "America/Los_Angeles ", "America/Los_Angeles", "Los Angeles" },
- { " America/Los_Angeles", "America/Los_Angeles", "Los Angeles" },
- { " America/Los_Angeles ", "America/Los_Angeles", "Los Angeles" },
- { "UTC UTC", "UTC", "UTC" }
- };
-
- for (i=0, n=G_N_ELEMENTS(test_cases); i<n; i++)
+ struct {
+ const char * location;
+ const char * expected_zone;
+ const char * expected_name;
+ } test_cases[] = {
+ { "America/Chicago Chicago", "America/Chicago", "Chicago" },
+ { "America/Chicago Oklahoma City", "America/Chicago", "Oklahoma City" },
+ { "America/Los_Angeles", "America/Los_Angeles", "Los Angeles" },
+ { "America/Los_Angeles ", "America/Los_Angeles", "Los Angeles" },
+ { " America/Los_Angeles", "America/Los_Angeles", "Los Angeles" },
+ { " America/Los_Angeles ", "America/Los_Angeles", "Los Angeles" },
+ { "UTC UTC", "UTC", "UTC" }
+ };
+
+ for(guint i=0, n=G_N_ELEMENTS(test_cases); i<n; i++)
{
- char * zone = NULL;
- char * name = NULL;
+ char * zone = NULL;
+ char * name = NULL;
- split_settings_location (test_cases[i].location, &zone, &name);
- ASSERT_STREQ (test_cases[i].expected_zone, zone);
- ASSERT_STREQ (test_cases[i].expected_name, name);
+ split_settings_location(test_cases[i].location, &zone, &name);
+ ASSERT_STREQ(test_cases[i].expected_zone, zone);
+ ASSERT_STREQ(test_cases[i].expected_name, name);
- g_free (zone);
- g_free (name);
+ g_free(zone);
+ g_free(name);
}
}
@@ -66,47 +63,43 @@ TEST (UtilsTest, SplitSettingsLocation)
#define EM_SPACE "\xE2\x80\x82"
-TEST (UtilsTest, GenerateTerseFormatString)
+TEST(UtilsTest, GenerateTerseFormatString)
{
- guint i;
- guint n;
- GDateTime * arbitrary_day = g_date_time_new_local (2013, 6, 25, 12, 34, 56);
- GDateTime * on_the_hour = g_date_time_new_local (2013, 6, 25, 12, 0, 0);
-
- struct {
- GDateTime * now;
- GDateTime * time;
- const char * expected_format_string;
- } test_cases[] = {
- { g_date_time_ref(arbitrary_day), g_date_time_ref(arbitrary_day), "%l:%M %p" }, /* identical time */
- { g_date_time_ref(arbitrary_day), g_date_time_add_hours(arbitrary_day,1), "%l:%M %p" }, /* later today */
- { g_date_time_ref(arbitrary_day), g_date_time_add_days(arbitrary_day,1), "Tomorrow" EM_SPACE "%l:%M %p" }, /* tomorrow */
- { g_date_time_ref(arbitrary_day), g_date_time_add_days(arbitrary_day,2), "%a" EM_SPACE "%l:%M %p" },
- { g_date_time_ref(arbitrary_day), g_date_time_add_days(arbitrary_day,6), "%a" EM_SPACE "%l:%M %p" },
- { g_date_time_ref(arbitrary_day), g_date_time_add_days(arbitrary_day,7), "%d %b" EM_SPACE "%l:%M %p" }, /* over one week away */
-
- { g_date_time_ref(on_the_hour), g_date_time_ref(on_the_hour), "%l %p" }, /* identical time */
- { g_date_time_ref(on_the_hour), g_date_time_add_hours(on_the_hour,1), "%l %p" }, /* later today */
- { g_date_time_ref(on_the_hour), g_date_time_add_days(on_the_hour,1), "Tomorrow" EM_SPACE "%l %p" }, /* tomorrow */
- { g_date_time_ref(on_the_hour), g_date_time_add_days(on_the_hour,2), "%a" EM_SPACE "%l %p" },
- { g_date_time_ref(on_the_hour), g_date_time_add_days(on_the_hour,6), "%a" EM_SPACE "%l %p" },
- { g_date_time_ref(on_the_hour), g_date_time_add_days(on_the_hour,7), "%d %b" EM_SPACE "%l %p" }, /* over one week away */
- };
-
- for (i=0, n=G_N_ELEMENTS(test_cases); i<n; i++)
+ auto arbitrary_day = g_date_time_new_local(2013, 6, 25, 12, 34, 56);
+ auto on_the_hour = g_date_time_new_local(2013, 6, 25, 12, 0, 0);
+
+ struct {
+ GDateTime * now;
+ GDateTime * time;
+ const char * expected_format_string;
+ } test_cases[] = {
+ { g_date_time_ref(arbitrary_day), g_date_time_ref(arbitrary_day), "%l:%M %p" }, /* identical time */
+ { g_date_time_ref(arbitrary_day), g_date_time_add_hours(arbitrary_day,1), "%l:%M %p" }, /* later today */
+ { g_date_time_ref(arbitrary_day), g_date_time_add_days(arbitrary_day,1), "Tomorrow" EM_SPACE "%l:%M %p" }, /* tomorrow */
+ { g_date_time_ref(arbitrary_day), g_date_time_add_days(arbitrary_day,2), "%a" EM_SPACE "%l:%M %p" },
+ { g_date_time_ref(arbitrary_day), g_date_time_add_days(arbitrary_day,6), "%a" EM_SPACE "%l:%M %p" },
+ { g_date_time_ref(arbitrary_day), g_date_time_add_days(arbitrary_day,7), "%d %b" EM_SPACE "%l:%M %p" }, /* over one week away */
+
+ { g_date_time_ref(on_the_hour), g_date_time_ref(on_the_hour), "%l %p" }, /* identical time */
+ { g_date_time_ref(on_the_hour), g_date_time_add_hours(on_the_hour,1), "%l %p" }, /* later today */
+ { g_date_time_ref(on_the_hour), g_date_time_add_days(on_the_hour,1), "Tomorrow" EM_SPACE "%l %p" }, /* tomorrow */
+ { g_date_time_ref(on_the_hour), g_date_time_add_days(on_the_hour,2), "%a" EM_SPACE "%l %p" },
+ { g_date_time_ref(on_the_hour), g_date_time_add_days(on_the_hour,6), "%a" EM_SPACE "%l %p" },
+ { g_date_time_ref(on_the_hour), g_date_time_add_days(on_the_hour,7), "%d %b" EM_SPACE "%l %p" }, /* over one week away */
+ };
+
+ for(guint i=0, n=G_N_ELEMENTS(test_cases); i<n; i++)
{
- char * format_string;
-
- format_string = generate_terse_format_string_at_time (test_cases[i].now,
- test_cases[i].time);
+ auto format_string = generate_terse_format_string_at_time(test_cases[i].now,
+ test_cases[i].time);
- ASSERT_STREQ (test_cases[i].expected_format_string, format_string);
+ ASSERT_STREQ(test_cases[i].expected_format_string, format_string);
- g_free (format_string);
- g_date_time_unref (test_cases[i].now);
- g_date_time_unref (test_cases[i].time);
+ g_free(format_string);
+ g_date_time_unref(test_cases[i].now);
+ g_date_time_unref(test_cases[i].time);
}
- g_date_time_unref (arbitrary_day);
- g_date_time_unref (on_the_hour);
+ g_date_time_unref(arbitrary_day);
+ g_date_time_unref(on_the_hour);
}