Merge lp:~charlesk/indicator-datetime/cpp into lp:indicator-datetime/14.04

Proposed by Charles Kerr
Status: Merged
Merged at revision: 298
Proposed branch: lp:~charlesk/indicator-datetime/cpp
Merge into: lp:indicator-datetime/14.04
Diff against target: 15815 lines (+8344/-6365)
101 files modified
CMakeLists.txt (+11/-7)
README (+53/-0)
cmake/GCov.cmake (+2/-1)
debian/control (+4/-0)
include/CMakeLists.txt (+1/-0)
include/datetime/CMakeLists.txt (+2/-0)
include/datetime/actions-live.h (+60/-0)
include/datetime/actions.h (+74/-0)
include/datetime/appointment.h (+55/-0)
include/datetime/clock-mock.h (+61/-0)
include/datetime/clock.h (+99/-0)
include/datetime/date-time.h (+68/-0)
include/datetime/dbus-shared.h (+25/-0)
include/datetime/exporter.h (+74/-0)
include/datetime/formatter.h (+138/-0)
include/datetime/locations-settings.h (+55/-0)
include/datetime/locations.h (+79/-0)
include/datetime/menu.h (+85/-0)
include/datetime/planner-eds.h (+49/-0)
include/datetime/planner.h (+76/-0)
include/datetime/settings-live.h (+70/-0)
include/datetime/settings-shared.h (+49/-0)
include/datetime/settings.h (+65/-0)
include/datetime/state.h (+75/-0)
include/datetime/timezone-file.h (+63/-0)
include/datetime/timezone-geoclue.h (+69/-0)
include/datetime/timezone.h (+45/-0)
include/datetime/timezones-live.h (+56/-0)
include/datetime/timezones.h (+59/-0)
include/datetime/utils.h (+54/-0)
panel-gnome/CMakeLists.txt (+7/-3)
panel-unity/CMakeLists.txt (+6/-3)
panel/datetime-prefs-locations.c (+14/-14)
panel/datetime-prefs.c (+29/-25)
po/POTFILES.in (+3/-3)
src/CMakeLists.txt (+23/-28)
src/actions-live.cpp (+217/-0)
src/actions.cpp (+266/-0)
src/appointment.cpp (+48/-0)
src/clock-live.c (+0/-278)
src/clock-live.cpp (+163/-0)
src/clock-live.h (+0/-73)
src/clock.c (+0/-110)
src/clock.cpp (+93/-0)
src/clock.h (+0/-76)
src/date-time.cpp (+159/-0)
src/dbus-shared.h (+0/-24)
src/exporter.cpp (+145/-0)
src/formatter-desktop.cpp (+169/-0)
src/formatter.cpp (+267/-0)
src/locations-settings.cpp (+92/-0)
src/locations.cpp (+59/-0)
src/main.c (+0/-83)
src/main.cpp (+86/-0)
src/menu.cpp (+598/-0)
src/planner-eds.c (+0/-653)
src/planner-eds.cpp (+425/-0)
src/planner-eds.h (+0/-58)
src/planner.c (+0/-281)
src/planner.h (+0/-167)
src/service.c (+0/-2432)
src/service.h (+0/-84)
src/settings-live.cpp (+257/-0)
src/settings-shared.h (+0/-50)
src/timezone-file.c (+0/-212)
src/timezone-file.cpp (+103/-0)
src/timezone-file.h (+0/-58)
src/timezone-geoclue.c (+0/-227)
src/timezone-geoclue.cpp (+250/-0)
src/timezone-geoclue.h (+0/-57)
src/timezone.c (+0/-134)
src/timezone.h (+0/-72)
src/timezones-live.cpp (+72/-0)
src/utils.c (+0/-466)
src/utils.h (+0/-66)
tests/CMakeLists.txt (+37/-9)
tests/Makefile.am.strings (+0/-38)
tests/actions-mock.h (+82/-0)
tests/geoclue-fixture.h (+150/-0)
tests/glib-fixture.h (+58/-40)
tests/planner-mock.c (+0/-178)
tests/planner-mock.h (+0/-58)
tests/state-fixture.h (+60/-0)
tests/state-mock.h (+43/-0)
tests/test-actions.cpp (+232/-0)
tests/test-clock.cpp (+140/-0)
tests/test-dbus-fixture.h (+102/-0)
tests/test-exporter.cpp (+134/-0)
tests/test-formatter.cc (+0/-98)
tests/test-formatter.cpp (+256/-0)
tests/test-indicator.cc (+0/-92)
tests/test-live-actions.cpp (+403/-0)
tests/test-locations.cpp (+169/-0)
tests/test-menus.cpp (+524/-0)
tests/test-planner.cpp (+85/-0)
tests/test-settings.cpp (+191/-0)
tests/test-timezone-file.cpp (+133/-0)
tests/test-timezone-geoclue.cpp (+48/-0)
tests/test-timezones.cpp (+124/-0)
tests/test-utils.cpp (+93/-107)
trim-lcov.py (+53/-0)
To merge this branch: bzr merge lp:~charlesk/indicator-datetime/cpp
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Pete Woods Pending
Review via email: mp+202719@code.launchpad.net

Commit message

Merge a refactor of indicator-datetime designed around making its components testable in isolation and in groups.

Description of the change

This is the long promised super-testable indicator-datetime refactor.

Basic overview of the code:

  The app's model is represented by the "State" class, and "Menu" objects
  are the corresponding views. "State" is a simple container for various
  properties, and menus connect to those properties' changed() signals to
  know when the view needs to be refreshed.

  As main.c shows, the app's very simple flow is to instantiate a state,
  buiid menus as Views to the state, and export the menus on DBus.

  State is a simple aggregate of its components (such as a "Clock"
  or "Planner" object to get the current time and upcoming appointments,
  respectively), so you can plug in different components for production
  and testing. By mixing-and-matching components as needed, you can
  test specific components in isolation, test how more than one
  components interact, or plug in all-live components for production.

  Once you have the state, the rest is straightforward: use MenuFactory
  to create Menu objects for each profile, then export them to DBus
  using the Exporter class.

  See also the README for suggestions on which actual files to read
  first when you're getting started with this codebase.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~charlesk/indicator-datetime/cpp updated
348. By Charles Kerr

add libdbustest1-dev to debian/control's Build-Depends to pick up dbus-test-runner's dbusmock interface for the geoclue unit tests.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~charlesk/indicator-datetime/cpp updated
349. By Charles Kerr

update POTFILES.in

350. By Charles Kerr

silence compiler warning

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~charlesk/indicator-datetime/cpp updated
351. By Charles Kerr

make utils.cpp's generate_full_format_string_at_time() a standalone function so that the panels can use the utils functions without a libindicatordatetime dependency

352. By Charles Kerr

cleanup from previous commit: since Formatter code was migrated to utils.c so that it could be used standalone by the panels, there's now code duplication between Utils and Formatter. Remove code duplication s.t. Formatter uses the Utils code as well.

353. By Charles Kerr

fix bootstrap error in unit tests by ensuring we always use the local gschema instead of the one preinstalled on the system

354. By Charles Kerr

fix free-memory-read bug found by valgrind testing

355. By Charles Kerr

fix Task leak found by valgrind testing

356. By Charles Kerr

fix GDateTime leak found by valgrind testing

357. By Charles Kerr

fix g_date_time_format() leak found by valgrind testing

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~charlesk/indicator-datetime/cpp updated
358. By Charles Kerr

ensure the unit tests' default locale supports utf-8

359. By Charles Kerr

add dbus-test-runner and python3-dbusmock to Build-Depends; they're needed by the unit tests.

360. By Charles Kerr

comment out unit tests that require a version of dbus-test-runner that hasn't landed yet.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Sebastien Bacher (seb128) wrote :

I've built/tested that a bit on my trusty desktop, it seems to work mostly fine (even fixing some bugs on the way like the tz change not being picked up or the week number setting not applying until restart), good work!

Small user comments:
- the "add an event" item is not enabled while I've evolution installed (that used to work)
- toggle the preference to show or not the calendar widget doesn't work dynamically

lp:~charlesk/indicator-datetime/cpp updated
361. By Charles Kerr

sync with lp:~larsu/indicator-datetime/reset-date and add corresponding unit tests.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~charlesk/indicator-datetime/cpp updated
362. By Charles Kerr

sync with lp:~seb128/indicator-datetime/use-correct-gtkbuilder-location

363. By Charles Kerr

fix instant calendar toggle issue reported in testing by seb128; add a test for this regression

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~charlesk/indicator-datetime/cpp updated
364. By Charles Kerr

fix disabled 'Add Event…' menuitem issue reported in testing by seb128; add a test for this regression

365. By Charles Kerr

sync with trunk

366. By Charles Kerr

remove unused old file

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Sebastien Bacher (seb128) wrote :

testing the current version on the phone, I noticed those changes/issues:

- the indicator menu is "current date/add an event/configure" (where the "add an event" does nothing), it used to be "current date/clock app/configure"

- when changing the timezone, in the system settings, the hour doesn't change in the indicator (not even at the next minute) (/etc/timezone is correctly updated and the system settings panel has the right time after changing)

Revision history for this message
Thomas Strehl (strehl-t) wrote :

the second issue is not a new regression, see https://bugs.launchpad.net/indicator-datetime/+bug/1267111

Revision history for this message
Sebastien Bacher (seb128) wrote :

@Thomas: right, in fact the issue has been fixed in the 3.10/pre-refactoring codebase, it needs to be fixed there as well, see Charle's comment on https://bugs.launchpad.net/ubuntu/+source/indicator-datetime/+bug/1271484/comments/3

Revision history for this message
Sebastien Bacher (seb128) wrote :

(well, to be exact, Charles' comment stated that the issue was fixed in the refactoring, which seems to not be true)

Revision history for this message
Charles Kerr (charlesk) wrote :

> the indicator menu is "current date/add an event/configure" (where the "add an event" does nothing), it used to be "current date/clock app/configure"

Confirmed, will fix ASAP.

> when changing the timezone, in the system settings, the hour doesn't change in the indicator

I'm not able to reproduce this using this MP, will follow up with seb128 in irc.

lp:~charlesk/indicator-datetime/cpp updated
367. By Charles Kerr

fix 'clock app' menuitem on phone profile reported by seb128 and update the corresponding unit tests

368. By Charles Kerr

as per review, don't inline getters

369. By Charles Kerr

as per review, don't inline unless there are performance issues

370. By Charles Kerr

as per review, make explicit the dependency injection that was implicit in main()

371. By Charles Kerr

as per review, constify getters where possible. This isn't always possible due to system APIs asking for non-const pointers.

372. By Charles Kerr

as per review, there were a few places that accidentally passed a shared_ptr<X>& instead of a const shared_ptr<X>&

373. By Charles Kerr

following on the review comment covered in the last commit, use shared_ptr<const X> instead of shared_ptr<X> where possible.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Charles Kerr (charlesk) wrote :

seb128, there seems to be a separate issue with monitoring /etc/timezone on the phone that's contributing to the timezone issue you're seeing, and I don't think it's specific to indicator-dateteime so let's handle it separately from this MP.

I've written up what I found this afternoon at https://bugs.launchpad.net/ubuntu/+source/indicator-datetime/+bug/1271484/comments/4 instead of in this MP.

lp:~charlesk/indicator-datetime/cpp updated
374. By Charles Kerr

remove dead files

375. By Charles Kerr

copyediting: as per review, use name_of_thing() instead of get_name_of_thing() or getNameOfThing()

376. By Charles Kerr

copyediting: remove dead '#if 0''ed code

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Sebastien Bacher (seb128) wrote :

@Thomas: "Finally land this. Other, still open bugs will be fixed in subsequent commits." doesn't seem like a nice commit message, can we rather have one that describe what the changes are about?

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-01-10 01:45:41 +0000
3+++ CMakeLists.txt 2014-01-31 00:43:10 +0000
4@@ -40,8 +40,9 @@
5 libedataserver-1.2>=3.5
6 libnotify>=0.7.6
7 url-dispatcher-1>=1
8+ properties-cpp>=0.0.1
9 json-glib-1.0>=0.16.2)
10-include_directories (${SERVICE_INCLUDE_DIRS})
11+include_directories (SYSTEM ${SERVICE_DEPS_INCLUDE_DIRS})
12
13 pkg_check_modules (PANEL_DEPS
14 glib-2.0>=2.36
15@@ -86,12 +87,14 @@
16 ##
17
18 set (CC_WARNING_ARGS " -Wall -Wshadow -Wextra -Wunused -Wformat=2 -Wno-missing-field-initializers")
19+set (CXX_WARNING_ARGS " -Wall -Wextra -pedantic -Wno-missing-field-initializers")
20
21-include_directories (${CMAKE_CURRENT_SOURCE_DIR}/src)
22-include_directories (${CMAKE_CURRENT_BINARY_DIR}/src)
23+include_directories (${CMAKE_CURRENT_SOURCE_DIR}/include)
24+include_directories (${CMAKE_CURRENT_BINARY_DIR}/include)
25
26 # testing & coverage
27 if (${enable_tests})
28+ pkg_check_modules (DBUSTEST REQUIRED dbustest-1>=14.04.0)
29 set (GTEST_SOURCE_DIR /usr/src/gtest/src)
30 set (GTEST_INCLUDE_DIR ${GTEST_SOURCE_DIR}/..)
31 set (GTEST_LIBS -lpthread)
32@@ -102,16 +105,17 @@
33 endif ()
34
35 # actually build things
36-add_subdirectory (src)
37+add_subdirectory(include)
38+add_subdirectory(src)
39 if (BUILD_PANEL)
40 add_subdirectory (panel-gnome)
41 endif ()
42 if (BUILD_UNITY_PANEL)
43 add_subdirectory (panel-unity)
44 endif ()
45-add_subdirectory (data)
46-add_subdirectory (po)
47+add_subdirectory(data)
48+add_subdirectory(po)
49 if (${enable_tests})
50- add_subdirectory (tests)
51+ add_subdirectory(tests)
52 endif ()
53
54
55=== modified file 'README'
56--- README 2013-10-09 16:39:36 +0000
57+++ README 2014-01-31 00:43:10 +0000
58@@ -68,3 +68,56 @@
59 - x-canonical-time-format s strftime format string
60
61
62+
63+CODE
64+====
65+
66+Model
67+
68+ The app's model is represented by the "State" class, and "Menu" objects
69+ are the corresponding views. "State" is a simple container for various
70+ properties, and menus connect to those properties' changed() signals to
71+ know when the view needs to be refreshed.
72+
73+ As one can see in main.c, the app's very simple flow is to instantiate
74+ a state and its properties, build menus that correspond to the state,
75+ and export the menus on DBus.
76+
77+ Because State is a simple aggregate of its components (such as a "Clock"
78+ or "Planner" object to get the current time and upcoming appointments,
79+ respectively), one can plug in live components for production and mock
80+ components for unit tests. The entire backend can be mix-and-matched by
81+ adding the desired test-or-production components.
82+
83+ Start with:
84+ include/datetime/state.h
85+ include/datetime/clock.h
86+ include/datetime/locations.h
87+ include/datetime/planner.h
88+ include/datetime/settings.h
89+ include/datetime/timezones.h
90+
91+ Implementations:
92+ include/datetime/settings-live.h
93+ include/datetime/locations-settings.h
94+ include/datetime/planner-eds.h
95+ include/datetime/timezones-live.h
96+
97+View
98+
99+ Menu is a mostly-opaque class to wrap GMenu code. Its subclasses contain
100+ the per-profile logic of which sections/menuitems to show and which to hide.
101+ Menus are instantiated via the MenuFactory, which takes a state and profile.
102+
103+ Actions is a mostly-opaque class to wrap our GActionGroup. Its subclasses
104+ contain the code that actually executed when an action is triggered (ie,
105+ LiveActions for production and MockActions for testing).
106+
107+ Exporter exports the Actions and Menus onto the DBus, and also emits a
108+ signal if/when the busname is lost so indicator-datetime-service knows
109+ when to exit.
110+
111+ include/datetime/menu.h
112+ include/datetime/actions.h
113+ include/datetime/exporter.h
114+
115
116=== modified file 'cmake/GCov.cmake'
117--- cmake/GCov.cmake 2013-10-18 19:22:54 +0000
118+++ cmake/GCov.cmake 2014-01-31 00:43:10 +0000
119@@ -29,7 +29,8 @@
120 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
121 COMMAND "${CMAKE_CTEST_COMMAND}" --force-new-ctest-process --verbose
122 COMMAND "${LCOV_EXECUTABLE}" --directory ${CMAKE_BINARY_DIR} --capture | ${CMAKE_SOURCE_DIR}/trim-lcov.py > dconf-lcov.info
123- COMMAND LANG=C "${GENHTML_EXECUTABLE}" --prefix ${CMAKE_BINARY_DIR} --output-directory lcov-html --legend --show-details dconf-lcov.info
124+ COMMAND "${LCOV_EXECUTABLE}" -r dconf-lcov.info /usr/include/\\* -o nosys-lcov.info
125+ COMMAND LANG=C "${GENHTML_EXECUTABLE}" --prefix ${CMAKE_BINARY_DIR} --output-directory lcov-html --legend --show-details nosys-lcov.info
126 COMMAND ${CMAKE_COMMAND} -E echo ""
127 COMMAND ${CMAKE_COMMAND} -E echo "file://${CMAKE_BINARY_DIR}/lcov-html/index.html"
128 COMMAND ${CMAKE_COMMAND} -E echo "")
129
130=== modified file 'debian/control'
131--- debian/control 2014-01-14 04:41:03 +0000
132+++ debian/control 2014-01-31 00:43:10 +0000
133@@ -5,6 +5,8 @@
134 # language-pack-en-base is for the unit tests s.t. we can test in 12h and 24h locales
135 Build-Depends: cmake,
136 dbus,
137+ dbus-test-runner,
138+ python3-dbusmock,
139 debhelper (>= 9),
140 dh-translations,
141 intltool (>= 0.35.0),
142@@ -28,6 +30,8 @@
143 libunity-control-center-dev,
144 libtimezonemap1-dev,
145 liburl-dispatcher1-dev,
146+ libproperties-cpp-dev,
147+ libdbustest1-dev,
148 locales,
149 Standards-Version: 3.9.3
150 Homepage: https://launchpad.net/indicator-datetime
151
152=== added directory 'include'
153=== added file 'include/CMakeLists.txt'
154--- include/CMakeLists.txt 1970-01-01 00:00:00 +0000
155+++ include/CMakeLists.txt 2014-01-31 00:43:10 +0000
156@@ -0,0 +1,1 @@
157+add_subdirectory(datetime)
158
159=== added directory 'include/datetime'
160=== added file 'include/datetime/CMakeLists.txt'
161--- include/datetime/CMakeLists.txt 1970-01-01 00:00:00 +0000
162+++ include/datetime/CMakeLists.txt 2014-01-31 00:43:10 +0000
163@@ -0,0 +1,2 @@
164+
165+
166
167=== added file 'include/datetime/actions-live.h'
168--- include/datetime/actions-live.h 1970-01-01 00:00:00 +0000
169+++ include/datetime/actions-live.h 2014-01-31 00:43:10 +0000
170@@ -0,0 +1,60 @@
171+/*
172+ * Copyright 2013 Canonical Ltd.
173+ *
174+ * This program is free software: you can redistribute it and/or modify it
175+ * under the terms of the GNU General Public License version 3, as published
176+ * by the Free Software Foundation.
177+ *
178+ * This program is distributed in the hope that it will be useful, but
179+ * WITHOUT ANY WARRANTY; without even the implied warranties of
180+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
181+ * PURPOSE. See the GNU General Public License for more details.
182+ *
183+ * You should have received a copy of the GNU General Public License along
184+ * with this program. If not, see <http://www.gnu.org/licenses/>.
185+ *
186+ * Authors:
187+ * Charles Kerr <charles.kerr@canonical.com>
188+ */
189+
190+#ifndef INDICATOR_DATETIME_ACTIONS_LIVE_H
191+#define INDICATOR_DATETIME_ACTIONS_LIVE_H
192+
193+#include <datetime/actions.h>
194+
195+namespace unity {
196+namespace indicator {
197+namespace datetime {
198+
199+/**
200+ * \brief Production implementation of the Actions interface.
201+ *
202+ * Delegates URLs, sets the timezone via org.freedesktop.timedate1, etc.
203+ *
204+ * @see MockActions
205+ */
206+class LiveActions: public Actions
207+{
208+public:
209+ LiveActions(const std::shared_ptr<State>& state_in);
210+ ~LiveActions() =default;
211+
212+ void open_desktop_settings();
213+ void open_phone_settings();
214+ void open_phone_clock_app();
215+ void open_planner();
216+ void open_planner_at(const DateTime&);
217+ void open_appointment(const std::string& uid);
218+ void set_location(const std::string& zone, const std::string& name);
219+ void set_calendar_date(const DateTime&);
220+
221+protected:
222+ virtual void execute_command(const std::string& command);
223+ virtual void dispatch_url(const std::string& url);
224+};
225+
226+} // namespace datetime
227+} // namespace indicator
228+} // namespace unity
229+
230+#endif // INDICATOR_DATETIME_ACTIONS_H
231
232=== added file 'include/datetime/actions.h'
233--- include/datetime/actions.h 1970-01-01 00:00:00 +0000
234+++ include/datetime/actions.h 2014-01-31 00:43:10 +0000
235@@ -0,0 +1,74 @@
236+/*
237+ * Copyright 2013 Canonical Ltd.
238+ *
239+ * This program is free software: you can redistribute it and/or modify it
240+ * under the terms of the GNU General Public License version 3, as published
241+ * by the Free Software Foundation.
242+ *
243+ * This program is distributed in the hope that it will be useful, but
244+ * WITHOUT ANY WARRANTY; without even the implied warranties of
245+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
246+ * PURPOSE. See the GNU General Public License for more details.
247+ *
248+ * You should have received a copy of the GNU General Public License along
249+ * with this program. If not, see <http://www.gnu.org/licenses/>.
250+ *
251+ * Authors:
252+ * Charles Kerr <charles.kerr@canonical.com>
253+ */
254+
255+#ifndef INDICATOR_DATETIME_ACTIONS_H
256+#define INDICATOR_DATETIME_ACTIONS_H
257+
258+#include <datetime/date-time.h>
259+#include <datetime/state.h>
260+
261+#include <memory> // shared_ptr
262+#include <string>
263+
264+#include <gio/gio.h> // GSimpleActionGroup
265+
266+namespace unity {
267+namespace indicator {
268+namespace datetime {
269+
270+/**
271+ * \brief Interface for all the actions that can be activated by users.
272+ *
273+ * This is a simple C++ wrapper around our GActionGroup that gets exported
274+ * onto the bus. Subclasses implement the actual code that should be run
275+ * when a particular action is triggered.
276+ */
277+class Actions
278+{
279+public:
280+ virtual void open_desktop_settings() =0;
281+ virtual void open_phone_settings() =0;
282+ virtual void open_phone_clock_app() =0;
283+ virtual void open_planner() =0;
284+ virtual void open_planner_at(const DateTime&) =0;
285+ virtual void open_appointment(const std::string& uid) =0;
286+ virtual void set_location(const std::string& zone, const std::string& name)=0;
287+ void set_calendar_date(const DateTime&);
288+ GActionGroup* action_group();
289+ const std::shared_ptr<State> state() const;
290+
291+protected:
292+ Actions(const std::shared_ptr<State>& state);
293+ virtual ~Actions();
294+
295+private:
296+ std::shared_ptr<State> m_state;
297+ GSimpleActionGroup* m_actions = nullptr;
298+ void update_calendar_state();
299+
300+ // we've got raw pointers in here, so disable copying
301+ Actions(const Actions&) =delete;
302+ Actions& operator=(const Actions&) =delete;
303+};
304+
305+} // namespace datetime
306+} // namespace indicator
307+} // namespace unity
308+
309+#endif // INDICATOR_DATETIME_ACTIONS_H
310
311=== added file 'include/datetime/appointment.h'
312--- include/datetime/appointment.h 1970-01-01 00:00:00 +0000
313+++ include/datetime/appointment.h 2014-01-31 00:43:10 +0000
314@@ -0,0 +1,55 @@
315+/*
316+ * Copyright 2013 Canonical Ltd.
317+ *
318+ * This program is free software: you can redistribute it and/or modify it
319+ * under the terms of the GNU General Public License version 3, as published
320+ * by the Free Software Foundation.
321+ *
322+ * This program is distributed in the hope that it will be useful, but
323+ * WITHOUT ANY WARRANTY; without even the implied warranties of
324+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
325+ * PURPOSE. See the GNU General Public License for more details.
326+ *
327+ * You should have received a copy of the GNU General Public License along
328+ * with this program. If not, see <http://www.gnu.org/licenses/>.
329+ *
330+ * Authors:
331+ * Charles Kerr <charles.kerr@canonical.com>
332+ */
333+
334+#ifndef INDICATOR_DATETIME_APPOINTMENT_H
335+#define INDICATOR_DATETIME_APPOINTMENT_H
336+
337+#include <datetime/date-time.h>
338+#include <string>
339+
340+namespace unity {
341+namespace indicator {
342+namespace datetime {
343+
344+/**
345+ * \brief Plain Old Data Structure that represents a calendar appointment.
346+ *
347+ * @see Planner
348+ */
349+struct Appointment
350+{
351+public:
352+ std::string color;
353+ std::string summary;
354+ std::string url;
355+ std::string uid;
356+ bool is_event = false;
357+ bool is_daily = false;
358+ bool has_alarms = false;
359+ DateTime begin;
360+ DateTime end;
361+
362+ bool operator== (const Appointment& that) const;
363+};
364+
365+} // namespace datetime
366+} // namespace indicator
367+} // namespace unity
368+
369+#endif // INDICATOR_DATETIME_APPOINTMENT_H
370
371=== added file 'include/datetime/clock-mock.h'
372--- include/datetime/clock-mock.h 1970-01-01 00:00:00 +0000
373+++ include/datetime/clock-mock.h 2014-01-31 00:43:10 +0000
374@@ -0,0 +1,61 @@
375+/*
376+ * Copyright 2013 Canonical Ltd.
377+ *
378+ * This program is free software: you can redistribute it and/or modify it
379+ * under the terms of the GNU General Public License version 3, as published
380+ * by the Free Software Foundation.
381+ *
382+ * This program is distributed in the hope that it will be useful, but
383+ * WITHOUT ANY WARRANTY; without even the implied warranties of
384+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
385+ * PURPOSE. See the GNU General Public License for more details.
386+ *
387+ * You should have received a copy of the GNU General Public License along
388+ * with this program. If not, see <http://www.gnu.org/licenses/>.
389+ *
390+ * Authors:
391+ * Charles Kerr <charles.kerr@canonical.com>
392+ */
393+
394+#ifndef INDICATOR_DATETIME_CLOCK_MOCK_H
395+#define INDICATOR_DATETIME_CLOCK_MOCK_H
396+
397+#include <datetime/clock.h>
398+
399+namespace unity {
400+namespace indicator {
401+namespace datetime {
402+
403+/***
404+****
405+***/
406+
407+/**
408+ * \brief A clock that uses a client-provided time instead of the system time.
409+ */
410+class MockClock: public Clock
411+{
412+public:
413+ MockClock(const DateTime& dt): m_localtime(dt) {}
414+ ~MockClock() =default;
415+
416+ DateTime localtime() const { return m_localtime; }
417+
418+ void set_localtime(const DateTime& dt) {
419+ const auto old = m_localtime;
420+ m_localtime = dt;
421+ if (!DateTime::is_same_minute(old, m_localtime))
422+ minute_changed();
423+ if (!DateTime::is_same_day(old, m_localtime))
424+ date_changed();
425+ }
426+
427+private:
428+ DateTime m_localtime;
429+};
430+
431+} // namespace datetime
432+} // namespace indicator
433+} // namespace unity
434+
435+#endif // INDICATOR_DATETIME_CLOCK_MOCK_H
436
437=== added file 'include/datetime/clock.h'
438--- include/datetime/clock.h 1970-01-01 00:00:00 +0000
439+++ include/datetime/clock.h 2014-01-31 00:43:10 +0000
440@@ -0,0 +1,99 @@
441+/*
442+ * Copyright 2013 Canonical Ltd.
443+ *
444+ * This program is free software: you can redistribute it and/or modify it
445+ * under the terms of the GNU General Public License version 3, as published
446+ * by the Free Software Foundation.
447+ *
448+ * This program is distributed in the hope that it will be useful, but
449+ * WITHOUT ANY WARRANTY; without even the implied warranties of
450+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
451+ * PURPOSE. See the GNU General Public License for more details.
452+ *
453+ * You should have received a copy of the GNU General Public License along
454+ * with this program. If not, see <http://www.gnu.org/licenses/>.
455+ *
456+ * Authors:
457+ * Charles Kerr <charles.kerr@canonical.com>
458+ */
459+
460+#ifndef INDICATOR_DATETIME_CLOCK_H
461+#define INDICATOR_DATETIME_CLOCK_H
462+
463+#include <datetime/date-time.h>
464+
465+#include <core/property.h>
466+#include <core/signal.h>
467+
468+#include <gio/gio.h> // GDBusConnection
469+
470+#include <memory> // std::shared_ptr, std::unique_ptr
471+
472+namespace unity {
473+namespace indicator {
474+namespace datetime {
475+
476+/**
477+ * \brief A clock.
478+ */
479+class Clock
480+{
481+public:
482+ virtual ~Clock();
483+ virtual DateTime localtime() const =0;
484+
485+ /** \brief A signal which fires when the clock's minute changes */
486+ core::Signal<> minute_changed;
487+
488+ /** \brief A signal which fires when the clock's date changes */
489+ core::Signal<> date_changed;
490+
491+protected:
492+ Clock();
493+
494+ /** \brief Compares old and new times, emits minute_changed() or date_changed() signals if appropriate */
495+ void maybe_emit (const DateTime& a, const DateTime& b);
496+
497+private:
498+ static void on_system_bus_ready(GObject*, GAsyncResult*, gpointer);
499+ static void on_prepare_for_sleep(GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant*, gpointer);
500+
501+ GCancellable * m_cancellable = nullptr;
502+ GDBusConnection * m_system_bus = nullptr;
503+ unsigned int m_sleep_subscription_id = 0;
504+
505+ // we've got raw pointers and GSignal tags in here, so disable copying
506+ Clock(const Clock&) =delete;
507+ Clock& operator=(const Clock&) =delete;
508+};
509+
510+/***
511+****
512+***/
513+
514+class Timezones;
515+
516+/**
517+ * \brief A live #Clock that provides the actual system time.
518+ */
519+class LiveClock: public Clock
520+{
521+public:
522+ LiveClock (const std::shared_ptr<const Timezones>& zones);
523+ virtual ~LiveClock();
524+ virtual DateTime localtime() const;
525+
526+private:
527+ class Impl;
528+ std::unique_ptr<Impl> p;
529+};
530+
531+/***
532+****
533+***/
534+
535+} // namespace datetime
536+} // namespace indicator
537+} // namespace unity
538+
539+#endif // INDICATOR_DATETIME_CLOCK_H
540
541=== added file 'include/datetime/date-time.h'
542--- include/datetime/date-time.h 1970-01-01 00:00:00 +0000
543+++ include/datetime/date-time.h 2014-01-31 00:43:10 +0000
544@@ -0,0 +1,68 @@
545+/*
546+ * Copyright 2013 Canonical Ltd.
547+ *
548+ * This program is free software: you can redistribute it and/or modify it
549+ * under the terms of the GNU General Public License version 3, as published
550+ * by the Free Software Foundation.
551+ *
552+ * This program is distributed in the hope that it will be useful, but
553+ * WITHOUT ANY WARRANTY; without even the implied warranties of
554+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
555+ * PURPOSE. See the GNU General Public License for more details.
556+ *
557+ * You should have received a copy of the GNU General Public License along
558+ * with this program. If not, see <http://www.gnu.org/licenses/>.
559+ *
560+ * Authors:
561+ * Charles Kerr <charles.kerr@canonical.com>
562+ */
563+
564+#ifndef INDICATOR_DATETIME_DATETIME_H
565+#define INDICATOR_DATETIME_DATETIME_H
566+
567+#include <glib.h> // GDateTime
568+
569+#include <ctime> // time_t
570+#include <memory> // std::shared_ptr
571+
572+namespace unity {
573+namespace indicator {
574+namespace datetime {
575+
576+/**
577+ * \brief A simple C++ wrapper for GDateTime to simplify ownership/refcounts
578+ */
579+class DateTime
580+{
581+public:
582+ static DateTime NowLocal();
583+ explicit DateTime(time_t t);
584+ explicit DateTime(GDateTime* in=nullptr);
585+ DateTime& operator=(GDateTime* in);
586+ DateTime& operator=(const DateTime& in);
587+ DateTime to_timezone(const std::string& zone) const;
588+ void reset(GDateTime* in=nullptr);
589+
590+ GDateTime* get() const;
591+ GDateTime* operator()() const {return get();}
592+
593+ std::string format(const std::string& fmt) const;
594+ int day_of_month() const;
595+ int64_t to_unix() const;
596+
597+ bool operator<(const DateTime& that) const;
598+ bool operator!=(const DateTime& that) const;
599+ bool operator==(const DateTime& that) const;
600+
601+ static bool is_same_day(const DateTime& a, const DateTime& b);
602+ static bool is_same_minute(const DateTime& a, const DateTime& b);
603+
604+private:
605+ std::shared_ptr<GDateTime> m_dt;
606+};
607+
608+} // namespace datetime
609+} // namespace indicator
610+} // namespace unity
611+
612+#endif // INDICATOR_DATETIME_DATETIME_H
613
614=== added file 'include/datetime/dbus-shared.h'
615--- include/datetime/dbus-shared.h 1970-01-01 00:00:00 +0000
616+++ include/datetime/dbus-shared.h 2014-01-31 00:43:10 +0000
617@@ -0,0 +1,25 @@
618+/*
619+ * Copyright 2013 Canonical Ltd.
620+ *
621+ * This program is free software: you can redistribute it and/or modify it
622+ * under the terms of the GNU General Public License version 3, as published
623+ * by the Free Software Foundation.
624+ *
625+ * This program is distributed in the hope that it will be useful, but
626+ * WITHOUT ANY WARRANTY; without even the implied warranties of
627+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
628+ * PURPOSE. See the GNU General Public License for more details.
629+ *
630+ * You should have received a copy of the GNU General Public License along
631+ * with this program. If not, see <http://www.gnu.org/licenses/>.
632+ *
633+ * Authors:
634+ * Ted Gould <ted@canonical.com>
635+ * Charles Kerr <charles.kerr@canonical.com>
636+ */
637+
638+
639+#define BUS_NAME "com.canonical.indicator.datetime"
640+
641+#define BUS_PATH "/com/canonical/indicator/datetime"
642+
643
644=== added file 'include/datetime/exporter.h'
645--- include/datetime/exporter.h 1970-01-01 00:00:00 +0000
646+++ include/datetime/exporter.h 2014-01-31 00:43:10 +0000
647@@ -0,0 +1,74 @@
648+/*
649+ * Copyright 2013 Canonical Ltd.
650+ *
651+ * This program is free software: you can redistribute it and/or modify it
652+ * under the terms of the GNU General Public License version 3, as published
653+ * by the Free Software Foundation.
654+ *
655+ * This program is distributed in the hope that it will be useful, but
656+ * WITHOUT ANY WARRANTY; without even the implied warranties of
657+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
658+ * PURPOSE. See the GNU General Public License for more details.
659+ *
660+ * You should have received a copy of the GNU General Public License along
661+ * with this program. If not, see <http://www.gnu.org/licenses/>.
662+ *
663+ * Authors:
664+ * Charles Kerr <charles.kerr@canonical.com>
665+ */
666+
667+#ifndef INDICATOR_DATETIME_EXPORTER_H
668+#define INDICATOR_DATETIME_EXPORTER_H
669+
670+#include <datetime/actions.h>
671+#include <datetime/menu.h>
672+
673+#include <core/signal.h>
674+
675+#include <gio/gio.h> // GActionGroup
676+
677+#include <memory> // std::shared_ptr
678+#include <vector>
679+
680+namespace unity {
681+namespace indicator {
682+namespace datetime {
683+
684+/**
685+ * \brief Exports actions and menus to DBus.
686+ */
687+class Exporter
688+{
689+public:
690+ Exporter() =default;
691+ ~Exporter();
692+
693+ core::Signal<> name_lost;
694+
695+ void publish(const std::shared_ptr<Actions>& actions,
696+ const std::vector<std::shared_ptr<Menu>>& menus);
697+
698+private:
699+ static void on_bus_acquired(GDBusConnection*, const gchar *name, gpointer gthis);
700+ void on_bus_acquired(GDBusConnection*, const gchar *name);
701+
702+ static void on_name_lost(GDBusConnection*, const gchar *name, gpointer gthis);
703+ void on_name_lost(GDBusConnection*, const gchar *name);
704+
705+ std::set<guint> m_exported_menu_ids;
706+ guint m_own_id = 0;
707+ guint m_exported_actions_id = 0;
708+ GDBusConnection * m_dbus_connection = nullptr;
709+ std::shared_ptr<Actions> m_actions;
710+ std::vector<std::shared_ptr<Menu>> m_menus;
711+
712+ // we've got raw pointers and gsignal tags in here, so disable copying
713+ Exporter(const Exporter&) =delete;
714+ Exporter& operator=(const Exporter&) =delete;
715+};
716+
717+} // namespace datetime
718+} // namespace indicator
719+} // namespace unity
720+
721+#endif // INDICATOR_DATETIME_EXPORTER_H
722
723=== added file 'include/datetime/formatter.h'
724--- include/datetime/formatter.h 1970-01-01 00:00:00 +0000
725+++ include/datetime/formatter.h 2014-01-31 00:43:10 +0000
726@@ -0,0 +1,138 @@
727+/*
728+ * Copyright 2013 Canonical Ltd.
729+ *
730+ * This program is free software: you can redistribute it and/or modify it
731+ * under the terms of the GNU General Public License version 3, as published
732+ * by the Free Software Foundation.
733+ *
734+ * This program is distributed in the hope that it will be useful, but
735+ * WITHOUT ANY WARRANTY; without even the implied warranties of
736+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
737+ * PURPOSE. See the GNU General Public License for more details.
738+ *
739+ * You should have received a copy of the GNU General Public License along
740+ * with this program. If not, see <http://www.gnu.org/licenses/>.
741+ *
742+ * Authors:
743+ * Charles Kerr <charles.kerr@canonical.com>
744+ */
745+
746+#ifndef INDICATOR_DATETIME_FORMATTER_H
747+#define INDICATOR_DATETIME_FORMATTER_H
748+
749+#include <core/property.h>
750+#include <core/signal.h>
751+
752+#include <datetime/clock.h>
753+#include <datetime/settings.h>
754+#include <datetime/utils.h> // is_locale_12h()
755+
756+#include <glib.h>
757+
758+#include <string>
759+#include <memory>
760+
761+namespace unity {
762+namespace indicator {
763+namespace datetime {
764+
765+class Clock;
766+class DateTime;
767+
768+/***
769+****
770+***/
771+
772+/**
773+ * \brief Provide the strftime() format strings
774+ *
775+ * This is a simple goal, but getting there has a lot of options and edge cases:
776+ *
777+ * - The default time format can change based on the locale.
778+ *
779+ * - The user's settings can change or completely override the format string.
780+ *
781+ * - The time formats are different on the Phone and Desktop profiles.
782+ *
783+ * - The time format string in the Locations' menuitems uses (mostly)
784+ * the same time format as the header, except for some changes.
785+ *
786+ * - The 'current time' format string in the Locations' menuitems also
787+ * prepends the string 'Yesterday' or 'Today' if it differs from the
788+ * local time, so Formatter needs to have a Clock for its state.
789+ *
790+ * So the Formatter monitors system settings, the current timezone, etc.
791+ * and upate its time format properties appropriately.
792+ */
793+class Formatter
794+{
795+public:
796+
797+ /** \brief The time format string for the menu header */
798+ core::Property<std::string> header_format;
799+
800+ /** \brief The time string for the menu header. (eg, the header_format + the clock's time */
801+ core::Property<std::string> header;
802+
803+ /** \brief Signal to denote when the relativeFormat has changed.
804+ When this is emitted, clients will want to rebuild their
805+ menuitems that contain relative time strings
806+ (ie, the Appointments and Locations menuitems) */
807+ core::Signal<> relative_format_changed;
808+
809+ /** \brief Generate a relative time format for some time (or time range)
810+ from the current clock's value. For example, a full-day interval
811+ starting at the end of the current clock's day yields "Tomorrow" */
812+ std::string relative_format(GDateTime* then, GDateTime* then_end=nullptr) const;
813+
814+protected:
815+ Formatter(const std::shared_ptr<const Clock>&);
816+ virtual ~Formatter();
817+
818+ static const char* default_header_time_format(bool twelvehour, bool show_seconds);
819+
820+private:
821+
822+ Formatter(const Formatter&) =delete;
823+ Formatter& operator=(const Formatter&) =delete;
824+
825+ class Impl;
826+ std::unique_ptr<Impl> p;
827+};
828+
829+
830+/**
831+ * \brief A Formatter for the Desktop and DesktopGreeter profiles.
832+ */
833+class DesktopFormatter: public Formatter
834+{
835+public:
836+ DesktopFormatter(const std::shared_ptr<const Clock>&, const std::shared_ptr<const Settings>&);
837+
838+private:
839+ std::shared_ptr<const Settings> m_settings;
840+
841+ void rebuildHeaderFormat();
842+ const gchar* getFullTimeFormatString() const;
843+ std::string getHeaderLabelFormatString() const;
844+ const gchar* getDateFormat(bool show_day, bool show_date, bool show_year) const;
845+
846+};
847+
848+
849+/**
850+ * \brief A Formatter for Phone and PhoneGreeter profiles.
851+ */
852+class PhoneFormatter: public Formatter
853+{
854+public:
855+ PhoneFormatter(const std::shared_ptr<const Clock>& clock): Formatter(clock) {
856+ header_format.set(default_header_time_format(is_locale_12h(), false));
857+ }
858+};
859+
860+} // namespace datetime
861+} // namespace indicator
862+} // namespace unity
863+
864+#endif // INDICATOR_DATETIME_CLOCK_H
865
866=== added file 'include/datetime/locations-settings.h'
867--- include/datetime/locations-settings.h 1970-01-01 00:00:00 +0000
868+++ include/datetime/locations-settings.h 2014-01-31 00:43:10 +0000
869@@ -0,0 +1,55 @@
870+/*
871+ * Copyright 2013 Canonical Ltd.
872+ *
873+ * This program is free software: you can redistribute it and/or modify it
874+ * under the terms of the GNU General Public License version 3, as published
875+ * by the Free Software Foundation.
876+ *
877+ * This program is distributed in the hope that it will be useful, but
878+ * WITHOUT ANY WARRANTY; without even the implied warranties of
879+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
880+ * PURPOSE. See the GNU General Public License for more details.
881+ *
882+ * You should have received a copy of the GNU General Public License along
883+ * with this program. If not, see <http://www.gnu.org/licenses/>.
884+ *
885+ * Authors:
886+ * Charles Kerr <charles.kerr@canonical.com>
887+ */
888+
889+#ifndef INDICATOR_DATETIME_SETTINGS_LOCATIONS_H
890+#define INDICATOR_DATETIME_SETTINGS_LOCATIONS_H
891+
892+#include <datetime/locations.h> // base class
893+
894+#include <datetime/settings.h>
895+#include <datetime/timezones.h>
896+
897+namespace unity {
898+namespace indicator {
899+namespace datetime {
900+
901+/**
902+ * \brief #Locations implementation which builds its list from the #Settings.
903+ */
904+class SettingsLocations: public Locations
905+{
906+public:
907+ /**
908+ * @param[in] settings the #Settings whose locations property is to be used
909+ * @param[in] timezones the #Timezones to always show first in the list
910+ */
911+ SettingsLocations (const std::shared_ptr<const Settings>& settings,
912+ const std::shared_ptr<const Timezones>& timezones);
913+
914+private:
915+ std::shared_ptr<const Settings> m_settings;
916+ std::shared_ptr<const Timezones> m_timezones;
917+ void reload();
918+};
919+
920+} // namespace datetime
921+} // namespace indicator
922+} // namespace unity
923+
924+#endif // INDICATOR_DATETIME_SETTINGS_LOCATIONS_H
925
926=== added file 'include/datetime/locations.h'
927--- include/datetime/locations.h 1970-01-01 00:00:00 +0000
928+++ include/datetime/locations.h 2014-01-31 00:43:10 +0000
929@@ -0,0 +1,79 @@
930+/*
931+ * Copyright 2013 Canonical Ltd.
932+ *
933+ * This program is free software: you can redistribute it and/or modify it
934+ * under the terms of the GNU General Public License version 3, as published
935+ * by the Free Software Foundation.
936+ *
937+ * This program is distributed in the hope that it will be useful, but
938+ * WITHOUT ANY WARRANTY; without even the implied warranties of
939+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
940+ * PURPOSE. See the GNU General Public License for more details.
941+ *
942+ * You should have received a copy of the GNU General Public License along
943+ * with this program. If not, see <http://www.gnu.org/licenses/>.
944+ *
945+ * Authors:
946+ * Charles Kerr <charles.kerr@canonical.com>
947+ */
948+
949+#ifndef INDICATOR_DATETIME_LOCATIONS_H
950+#define INDICATOR_DATETIME_LOCATIONS_H
951+
952+#include <datetime/date-time.h>
953+
954+#include <core/property.h>
955+
956+#include <string>
957+#include <vector>
958+
959+namespace unity {
960+namespace indicator {
961+namespace datetime {
962+
963+/**
964+ * \brief A physical place and its timezone; eg, "America/Chicago" + "Oklahoma City"
965+ *
966+ * @see Locations
967+ */
968+class Location
969+{
970+public:
971+ Location (const std::string& zone, const std::string& name);
972+ const std::string& zone() const;
973+ const std::string& name() const;
974+ bool operator== (const Location& that) const;
975+
976+private:
977+
978+ /** timezone; eg, "America/Chicago" */
979+ std::string m_zone;
980+
981+ /* human-readable location name; eg, "Oklahoma City" */
982+ std::string m_name;
983+
984+ /** offset from UTC in microseconds */
985+ int64_t m_offset = 0;
986+};
987+
988+/**
989+ * Container which holds an ordered list of Locations
990+ *
991+ * @see Location
992+ * @see State
993+ */
994+class Locations
995+{
996+public:
997+ Locations() =default;
998+ virtual ~Locations() =default;
999+
1000+ /** \brief an ordered list of Location items */
1001+ core::Property<std::vector<Location>> locations;
1002+};
1003+
1004+} // namespace datetime
1005+} // namespace indicator
1006+} // namespace unity
1007+
1008+#endif // INDICATOR_DATETIME_LOCATIONS_H
1009
1010=== added file 'include/datetime/menu.h'
1011--- include/datetime/menu.h 1970-01-01 00:00:00 +0000
1012+++ include/datetime/menu.h 2014-01-31 00:43:10 +0000
1013@@ -0,0 +1,85 @@
1014+/*
1015+ * Copyright 2013 Canonical Ltd.
1016+ *
1017+ * This program is free software: you can redistribute it and/or modify it
1018+ * under the terms of the GNU General Public License version 3, as published
1019+ * by the Free Software Foundation.
1020+ *
1021+ * This program is distributed in the hope that it will be useful, but
1022+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1023+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1024+ * PURPOSE. See the GNU General Public License for more details.
1025+ *
1026+ * You should have received a copy of the GNU General Public License along
1027+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1028+ *
1029+ * Authors:
1030+ * Charles Kerr <charles.kerr@canonical.com>
1031+ */
1032+
1033+#ifndef INDICATOR_DATETIME_MENU_H
1034+#define INDICATOR_DATETIME_MENU_H
1035+
1036+#include <datetime/actions.h>
1037+#include <datetime/state.h>
1038+
1039+#include <memory> // std::shared_ptr
1040+#include <vector>
1041+
1042+#include <gio/gio.h> // GMenuModel
1043+
1044+namespace unity {
1045+namespace indicator {
1046+namespace datetime {
1047+
1048+/**
1049+ * \brief A menu for a specific profile; eg, Desktop or Phone.
1050+ *
1051+ * @see MenuFactory
1052+ * @see Exporter
1053+ */
1054+class Menu
1055+{
1056+public:
1057+ enum Profile { Desktop, DesktopGreeter, Phone, PhoneGreeter, NUM_PROFILES };
1058+ enum Section { Calendar, Appointments, Locations, Settings, NUM_SECTIONS };
1059+ const std::string& name() const;
1060+ Profile profile() const;
1061+ GMenuModel* menu_model();
1062+
1063+protected:
1064+ Menu (Profile profile_in, const std::string& name_in);
1065+ virtual ~Menu() =default;
1066+ GMenu* m_menu = nullptr;
1067+
1068+private:
1069+ const Profile m_profile;
1070+ const std::string m_name;
1071+
1072+ // we've got raw pointers in here, so disable copying
1073+ Menu(const Menu&) =delete;
1074+ Menu& operator=(const Menu&) =delete;
1075+};
1076+
1077+/**
1078+ * \brief Builds a Menu for a given state and profile
1079+ *
1080+ * @see Menu
1081+ * @see Exporter
1082+ */
1083+class MenuFactory
1084+{
1085+public:
1086+ MenuFactory (const std::shared_ptr<Actions>& actions, const std::shared_ptr<const State>& state);
1087+ std::shared_ptr<Menu> buildMenu(Menu::Profile profile);
1088+
1089+private:
1090+ std::shared_ptr<Actions> m_actions;
1091+ std::shared_ptr<const State> m_state;
1092+};
1093+
1094+} // namespace datetime
1095+} // namespace indicator
1096+} // namespace unity
1097+
1098+#endif // INDICATOR_DATETIME_MENU_H
1099
1100=== added file 'include/datetime/planner-eds.h'
1101--- include/datetime/planner-eds.h 1970-01-01 00:00:00 +0000
1102+++ include/datetime/planner-eds.h 2014-01-31 00:43:10 +0000
1103@@ -0,0 +1,49 @@
1104+/*
1105+ * Copyright 2013 Canonical Ltd.
1106+ *
1107+ * This program is free software: you can redistribute it and/or modify it
1108+ * under the terms of the GNU General Public License version 3, as published
1109+ * by the Free Software Foundation.
1110+ *
1111+ * This program is distributed in the hope that it will be useful, but
1112+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1113+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1114+ * PURPOSE. See the GNU General Public License for more details.
1115+ *
1116+ * You should have received a copy of the GNU General Public License along
1117+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1118+ *
1119+ * Authors:
1120+ * Charles Kerr <charles.kerr@canonical.com>
1121+ */
1122+
1123+#ifndef INDICATOR_DATETIME_PLANNER_EDS_H
1124+#define INDICATOR_DATETIME_PLANNER_EDS_H
1125+
1126+#include <datetime/planner.h>
1127+
1128+#include <memory> // unique_ptr
1129+
1130+namespace unity {
1131+namespace indicator {
1132+namespace datetime {
1133+
1134+/**
1135+ * \brief Planner which uses EDS as its backend
1136+ */
1137+class PlannerEds: public Planner
1138+{
1139+public:
1140+ PlannerEds();
1141+ virtual ~PlannerEds();
1142+
1143+private:
1144+ class Impl;
1145+ std::unique_ptr<Impl> p;
1146+};
1147+
1148+} // namespace datetime
1149+} // namespace indicator
1150+} // namespace unity
1151+
1152+#endif // INDICATOR_DATETIME_PLANNER_EDS_H
1153
1154=== added file 'include/datetime/planner.h'
1155--- include/datetime/planner.h 1970-01-01 00:00:00 +0000
1156+++ include/datetime/planner.h 2014-01-31 00:43:10 +0000
1157@@ -0,0 +1,76 @@
1158+/*
1159+ * Copyright 2013 Canonical Ltd.
1160+ *
1161+ * This program is free software: you can redistribute it and/or modify it
1162+ * under the terms of the GNU General Public License version 3, as published
1163+ * by the Free Software Foundation.
1164+ *
1165+ * This program is distributed in the hope that it will be useful, but
1166+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1167+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1168+ * PURPOSE. See the GNU General Public License for more details.
1169+ *
1170+ * You should have received a copy of the GNU General Public License along
1171+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1172+ *
1173+ * Authors:
1174+ * Charles Kerr <charles.kerr@canonical.com>
1175+ */
1176+
1177+#ifndef INDICATOR_DATETIME_PLANNER_H
1178+#define INDICATOR_DATETIME_PLANNER_H
1179+
1180+#include <datetime/appointment.h>
1181+#include <datetime/date-time.h>
1182+
1183+#include <core/property.h>
1184+
1185+#include <vector>
1186+
1187+namespace unity {
1188+namespace indicator {
1189+namespace datetime {
1190+
1191+/**
1192+ * \brief Simple appointment book
1193+ *
1194+ * @see EdsPlanner
1195+ * @see State
1196+ */
1197+class Planner
1198+{
1199+public:
1200+ virtual ~Planner() =default;
1201+
1202+ /**
1203+ * \brief Timestamp used to determine the appointments in the `upcoming' and `this_month' properties.
1204+ * Setting this value will cause the planner to re-query its backend and
1205+ * update the `upcoming' and `this_month' properties.
1206+ */
1207+ core::Property<DateTime> time;
1208+
1209+ /**
1210+ * \brief The next few appointments that follow the time specified in the time property.
1211+ */
1212+ core::Property<std::vector<Appointment>> upcoming;
1213+
1214+ /**
1215+ * \brief The appointments that occur in the same month as the time property
1216+ */
1217+ core::Property<std::vector<Appointment>> this_month;
1218+
1219+protected:
1220+ Planner() =default;
1221+
1222+private:
1223+
1224+ // disable copying
1225+ Planner(const Planner&) =delete;
1226+ Planner& operator=(const Planner&) =delete;
1227+};
1228+
1229+} // namespace datetime
1230+} // namespace indicator
1231+} // namespace unity
1232+
1233+#endif // INDICATOR_DATETIME_PLANNER_H
1234
1235=== added file 'include/datetime/settings-live.h'
1236--- include/datetime/settings-live.h 1970-01-01 00:00:00 +0000
1237+++ include/datetime/settings-live.h 2014-01-31 00:43:10 +0000
1238@@ -0,0 +1,70 @@
1239+/*
1240+ * Copyright 2013 Canonical Ltd.
1241+ *
1242+ * This program is free software: you can redistribute it and/or modify it
1243+ * under the terms of the GNU General Public License version 3, as published
1244+ * by the Free Software Foundation.
1245+ *
1246+ * This program is distributed in the hope that it will be useful, but
1247+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1248+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1249+ * PURPOSE. See the GNU General Public License for more details.
1250+ *
1251+ * You should have received a copy of the GNU General Public License along
1252+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1253+ *
1254+ * Authors:
1255+ * Charles Kerr <charles.kerr@canonical.com>
1256+ */
1257+
1258+#ifndef INDICATOR_DATETIME_SETTINGS_LIVE_H
1259+#define INDICATOR_DATETIME_SETTINGS_LIVE_H
1260+
1261+#include <datetime/settings.h> // parent class
1262+
1263+#include <gio/gio.h> // GSettings
1264+
1265+namespace unity {
1266+namespace indicator {
1267+namespace datetime {
1268+
1269+/**
1270+ * \brief #Settings implementation which uses GSettings.
1271+ */
1272+class LiveSettings: public Settings
1273+{
1274+public:
1275+ LiveSettings();
1276+ virtual ~LiveSettings();
1277+
1278+private:
1279+ static void on_changed(GSettings*, gchar*, gpointer);
1280+ void update_key(const std::string& key);
1281+
1282+ void update_custom_time_format();
1283+ void update_locations();
1284+ void update_show_calendar();
1285+ void update_show_clock();
1286+ void update_show_date();
1287+ void update_show_day();
1288+ void update_show_detected_locations();
1289+ void update_show_events();
1290+ void update_show_locations();
1291+ void update_show_seconds();
1292+ void update_show_week_numbers();
1293+ void update_show_year();
1294+ void update_time_format_mode();
1295+ void update_timezone_name();
1296+
1297+ GSettings* m_settings;
1298+
1299+ // we've got a raw pointer here, so disable copying
1300+ LiveSettings(const LiveSettings&) =delete;
1301+ LiveSettings& operator=(const LiveSettings&) =delete;
1302+};
1303+
1304+} // namespace datetime
1305+} // namespace indicator
1306+} // namespace unity
1307+
1308+#endif // INDICATOR_DATETIME_SETTINGS_LIVE_H
1309
1310=== added file 'include/datetime/settings-shared.h'
1311--- include/datetime/settings-shared.h 1970-01-01 00:00:00 +0000
1312+++ include/datetime/settings-shared.h 2014-01-31 00:43:10 +0000
1313@@ -0,0 +1,49 @@
1314+/*
1315+ * Copyright 2010 Canonical Ltd.
1316+ *
1317+ * This program is free software: you can redistribute it and/or modify it
1318+ * under the terms of the GNU General Public License version 3, as published
1319+ * by the Free Software Foundation.
1320+ *
1321+ * This program is distributed in the hope that it will be useful, but
1322+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1323+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1324+ * PURPOSE. See the GNU General Public License for more details.
1325+ *
1326+ * You should have received a copy of the GNU General Public License along
1327+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1328+ *
1329+ * Authors:
1330+ * Ted Gould <ted@canonical.com>
1331+ * Charles Kerr <charles.kerr@canonical.com>
1332+ */
1333+
1334+#ifndef INDICATOR_DATETIME_SETTINGS_SHARED
1335+#define INDICATOR_DATETIME_SETTINGS_SHARED
1336+
1337+typedef enum
1338+{
1339+ TIME_FORMAT_MODE_LOCALE_DEFAULT,
1340+ TIME_FORMAT_MODE_12_HOUR,
1341+ TIME_FORMAT_MODE_24_HOUR,
1342+ TIME_FORMAT_MODE_CUSTOM
1343+}
1344+TimeFormatMode;
1345+
1346+#define SETTINGS_INTERFACE "com.canonical.indicator.datetime"
1347+#define SETTINGS_SHOW_CLOCK_S "show-clock"
1348+#define SETTINGS_TIME_FORMAT_S "time-format"
1349+#define SETTINGS_SHOW_SECONDS_S "show-seconds"
1350+#define SETTINGS_SHOW_DAY_S "show-day"
1351+#define SETTINGS_SHOW_DATE_S "show-date"
1352+#define SETTINGS_SHOW_YEAR_S "show-year"
1353+#define SETTINGS_CUSTOM_TIME_FORMAT_S "custom-time-format"
1354+#define SETTINGS_SHOW_CALENDAR_S "show-calendar"
1355+#define SETTINGS_SHOW_WEEK_NUMBERS_S "show-week-numbers"
1356+#define SETTINGS_SHOW_EVENTS_S "show-events"
1357+#define SETTINGS_SHOW_LOCATIONS_S "show-locations"
1358+#define SETTINGS_SHOW_DETECTED_S "show-auto-detected-location"
1359+#define SETTINGS_LOCATIONS_S "locations"
1360+#define SETTINGS_TIMEZONE_NAME_S "timezone-name"
1361+
1362+#endif // INDICATOR_DATETIME_SETTINGS_SHARED
1363
1364=== added file 'include/datetime/settings.h'
1365--- include/datetime/settings.h 1970-01-01 00:00:00 +0000
1366+++ include/datetime/settings.h 2014-01-31 00:43:10 +0000
1367@@ -0,0 +1,65 @@
1368+/*
1369+ * Copyright 2013 Canonical Ltd.
1370+ *
1371+ * This program is free software: you can redistribute it and/or modify it
1372+ * under the terms of the GNU General Public License version 3, as published
1373+ * by the Free Software Foundation.
1374+ *
1375+ * This program is distributed in the hope that it will be useful, but
1376+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1377+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1378+ * PURPOSE. See the GNU General Public License for more details.
1379+ *
1380+ * You should have received a copy of the GNU General Public License along
1381+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1382+ *
1383+ * Authors:
1384+ * Charles Kerr <charles.kerr@canonical.com>
1385+ */
1386+
1387+#ifndef INDICATOR_DATETIME_SETTINGS_H
1388+#define INDICATOR_DATETIME_SETTINGS_H
1389+
1390+#include <datetime/settings-shared.h>
1391+
1392+#include <core/property.h>
1393+
1394+#include <vector>
1395+
1396+namespace unity {
1397+namespace indicator {
1398+namespace datetime {
1399+
1400+/**
1401+ * \brief Interface that represents user-configurable settings.
1402+ *
1403+ * See the descriptions in data/com.canonical.indicator.datetime.gschema.xml
1404+ * for more information on specific properties.
1405+ */
1406+class Settings
1407+{
1408+public:
1409+ Settings() =default;
1410+ virtual ~Settings() =default;
1411+
1412+ core::Property<std::string> custom_time_format;
1413+ core::Property<std::vector<std::string>> locations;
1414+ core::Property<bool> show_calendar;
1415+ core::Property<bool> show_clock;
1416+ core::Property<bool> show_date;
1417+ core::Property<bool> show_day;
1418+ core::Property<bool> show_detected_location;
1419+ core::Property<bool> show_events;
1420+ core::Property<bool> show_locations;
1421+ core::Property<bool> show_seconds;
1422+ core::Property<bool> show_week_numbers;
1423+ core::Property<bool> show_year;
1424+ core::Property<TimeFormatMode> time_format_mode;
1425+ core::Property<std::string> timezone_name;
1426+};
1427+
1428+} // namespace datetime
1429+} // namespace indicator
1430+} // namespace unity
1431+
1432+#endif // INDICATOR_DATETIME_SETTINGS_H
1433
1434=== added file 'include/datetime/state.h'
1435--- include/datetime/state.h 1970-01-01 00:00:00 +0000
1436+++ include/datetime/state.h 2014-01-31 00:43:10 +0000
1437@@ -0,0 +1,75 @@
1438+/*
1439+ * Copyright 2013 Canonical Ltd.
1440+ *
1441+ * This program is free software: you can redistribute it and/or modify it
1442+ * under the terms of the GNU General Public License version 3, as published
1443+ * by the Free Software Foundation.
1444+ *
1445+ * This program is distributed in the hope that it will be useful, but
1446+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1447+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1448+ * PURPOSE. See the GNU General Public License for more details.
1449+ *
1450+ * You should have received a copy of the GNU General Public License along
1451+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1452+ *
1453+ * Authors:
1454+ * Charles Kerr <charles.kerr@canonical.com>
1455+ */
1456+
1457+#ifndef INDICATOR_DATETIME_STATE_H
1458+#define INDICATOR_DATETIME_STATE_H
1459+
1460+#include <datetime/clock.h>
1461+#include <datetime/locations.h>
1462+#include <datetime/planner.h>
1463+#include <datetime/settings.h>
1464+#include <datetime/timezones.h>
1465+
1466+#include <core/property.h>
1467+
1468+#include <memory> // std::shared_ptr
1469+
1470+namespace unity {
1471+namespace indicator {
1472+namespace datetime {
1473+
1474+/**
1475+ * \brief Aggregates all the classes that represent the backend state.
1476+ *
1477+ * This is where the app comes together. It's a model that aggregates
1478+ * all of the backend appointments/alarms, locations, timezones,
1479+ * system time, and so on. The "view" code (ie, the Menus) need to
1480+ * respond to Signals from the State and update themselves accordingly.
1481+ *
1482+ * @see Menu
1483+ * @see MenuFactory
1484+ * @see Timezones
1485+ * @see Clock
1486+ * @see Planner
1487+ * @see Locations
1488+ * @see Settings
1489+ */
1490+struct State
1491+{
1492+ /** \brief The current time. Used by the header, by the date menuitem,
1493+ and by the locations for relative timestamp */
1494+ std::shared_ptr<Clock> clock;
1495+
1496+ /** \brief The locations to be displayed in the Locations
1497+ section of the #Menu */
1498+ std::shared_ptr<Locations> locations;
1499+
1500+ /** \brief The appointments to be displayed in the Calendar and
1501+ Appointments sections of the #Menu */
1502+ std::shared_ptr<Planner> planner;
1503+
1504+ /** \brief Configuration options that modify the view */
1505+ std::shared_ptr<Settings> settings;
1506+};
1507+
1508+} // namespace datetime
1509+} // namespace indicator
1510+} // namespace unity
1511+
1512+#endif // INDICATOR_DATETIME_STATE_H
1513
1514=== added file 'include/datetime/timezone-file.h'
1515--- include/datetime/timezone-file.h 1970-01-01 00:00:00 +0000
1516+++ include/datetime/timezone-file.h 2014-01-31 00:43:10 +0000
1517@@ -0,0 +1,63 @@
1518+/*
1519+ * Copyright 2013 Canonical Ltd.
1520+ *
1521+ * This program is free software: you can redistribute it and/or modify it
1522+ * under the terms of the GNU General Public License version 3, as published
1523+ * by the Free Software Foundation.
1524+ *
1525+ * This program is distributed in the hope that it will be useful, but
1526+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1527+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1528+ * PURPOSE. See the GNU General Public License for more details.
1529+ *
1530+ * You should have received a copy of the GNU General Public License along
1531+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1532+ *
1533+ * Authors:
1534+ * Charles Kerr <charles.kerr@canonical.com>
1535+ */
1536+
1537+#ifndef INDICATOR_DATETIME_FILE_TIMEZONE_H
1538+#define INDICATOR_DATETIME_FILE_TIMEZONE_H
1539+
1540+#include <datetime/timezone.h> // base class
1541+
1542+#include <string> // std::string
1543+
1544+#include <glib.h>
1545+#include <gio/gio.h>
1546+
1547+namespace unity {
1548+namespace indicator {
1549+namespace datetime {
1550+
1551+/**
1552+ * \brief A #Timezone that gets its information from monitoring a file, such as /etc/timezone
1553+ */
1554+class FileTimezone: public Timezone
1555+{
1556+public:
1557+ FileTimezone();
1558+ FileTimezone(const std::string& filename);
1559+ ~FileTimezone();
1560+
1561+private:
1562+ void setFilename(const std::string& filename);
1563+ static void onFileChanged(gpointer gself);
1564+ void clear();
1565+ void reload();
1566+
1567+ std::string m_filename;
1568+ GFileMonitor * m_monitor = nullptr;
1569+ unsigned long m_monitor_handler_id = 0;
1570+
1571+ // we have raw pointers and glib tags in here, so disable copying
1572+ FileTimezone(const FileTimezone&) =delete;
1573+ FileTimezone& operator=(const FileTimezone&) =delete;
1574+};
1575+
1576+} // namespace datetime
1577+} // namespace indicator
1578+} // namespace unity
1579+
1580+#endif // INDICATOR_DATETIME_FILE_TIMEZONE_H
1581
1582=== added file 'include/datetime/timezone-geoclue.h'
1583--- include/datetime/timezone-geoclue.h 1970-01-01 00:00:00 +0000
1584+++ include/datetime/timezone-geoclue.h 2014-01-31 00:43:10 +0000
1585@@ -0,0 +1,69 @@
1586+/*
1587+ * Copyright 2013 Canonical Ltd.
1588+ *
1589+ * This program is free software: you can redistribute it and/or modify it
1590+ * under the terms of the GNU General Public License version 3, as published
1591+ * by the Free Software Foundation.
1592+ *
1593+ * This program is distributed in the hope that it will be useful, but
1594+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1595+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1596+ * PURPOSE. See the GNU General Public License for more details.
1597+ *
1598+ * You should have received a copy of the GNU General Public License along
1599+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1600+ *
1601+ * Authors:
1602+ * Charles Kerr <charles.kerr@canonical.com>
1603+ */
1604+
1605+#ifndef INDICATOR_DATETIME_GEOCLUE_TIMEZONE_H
1606+#define INDICATOR_DATETIME_GEOCLUE_TIMEZONE_H
1607+
1608+#include <datetime/timezone.h> // base class
1609+
1610+#include <string>
1611+
1612+#include <glib.h>
1613+#include <gio/gio.h>
1614+
1615+namespace unity {
1616+namespace indicator {
1617+namespace datetime {
1618+
1619+/**
1620+ * \brief A #Timezone that gets its information from asking GeoClue
1621+ */
1622+class GeoclueTimezone: public Timezone
1623+{
1624+public:
1625+ GeoclueTimezone();
1626+ ~GeoclueTimezone();
1627+
1628+private:
1629+ static void on_bus_got (GObject*, GAsyncResult*, gpointer);
1630+ static void on_client_created (GObject*, GAsyncResult*, gpointer);
1631+ static void on_address_changed (GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant*, gpointer);
1632+ static void on_requirements_set (GObject*, GAsyncResult*, gpointer);
1633+ static void on_address_started (GObject*, GAsyncResult*, gpointer);
1634+ static void on_address_got (GObject*, GAsyncResult*, gpointer);
1635+ void setTimezoneFromAddressVariant (GVariant*);
1636+ static GVariant * call_finish (GObject*, GAsyncResult*);
1637+
1638+ GCancellable * m_cancellable = nullptr;
1639+ GDBusConnection * m_connection = nullptr;
1640+ std::string m_client_object_path;
1641+ guint m_signal_subscription = 0;
1642+
1643+ // we've got pointers and gsignal tags in here, so don't allow copying
1644+ GeoclueTimezone(const GeoclueTimezone&) =delete;
1645+ GeoclueTimezone& operator=(const GeoclueTimezone&) =delete;
1646+};
1647+
1648+
1649+} // namespace datetime
1650+} // namespace indicator
1651+} // namespace unity
1652+
1653+#endif // INDICATOR_DATETIME_GEOCLUE_TIMEZONE_H
1654+
1655
1656=== added file 'include/datetime/timezone.h'
1657--- include/datetime/timezone.h 1970-01-01 00:00:00 +0000
1658+++ include/datetime/timezone.h 2014-01-31 00:43:10 +0000
1659@@ -0,0 +1,45 @@
1660+/*
1661+ * Copyright 2013 Canonical Ltd.
1662+ *
1663+ * This program is free software: you can redistribute it and/or modify it
1664+ * under the terms of the GNU General Public License version 3, as published
1665+ * by the Free Software Foundation.
1666+ *
1667+ * This program is distributed in the hope that it will be useful, but
1668+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1669+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1670+ * PURPOSE. See the GNU General Public License for more details.
1671+ *
1672+ * You should have received a copy of the GNU General Public License along
1673+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1674+ *
1675+ * Authors:
1676+ * Charles Kerr <charles.kerr@canonical.com>
1677+ */
1678+
1679+#ifndef INDICATOR_DATETIME_TIMEZONE_H
1680+#define INDICATOR_DATETIME_TIMEZONE_H
1681+
1682+#include <core/property.h>
1683+
1684+#include <string>
1685+
1686+namespace unity {
1687+namespace indicator {
1688+namespace datetime {
1689+
1690+/** \brief Base a timezone, such as "America/Chicago". */
1691+class Timezone
1692+{
1693+protected:
1694+ Timezone() =default;
1695+
1696+public:
1697+ core::Property<std::string> timezone;
1698+};
1699+
1700+} // namespace datetime
1701+} // namespace indicator
1702+} // namespace unity
1703+
1704+#endif // INDICATOR_DATETIME_TIMEZONE_H
1705
1706=== added file 'include/datetime/timezones-live.h'
1707--- include/datetime/timezones-live.h 1970-01-01 00:00:00 +0000
1708+++ include/datetime/timezones-live.h 2014-01-31 00:43:10 +0000
1709@@ -0,0 +1,56 @@
1710+/*
1711+ * Copyright 2013 Canonical Ltd.
1712+ *
1713+ * This program is free software: you can redistribute it and/or modify it
1714+ * under the terms of the GNU General Public License version 3, as published
1715+ * by the Free Software Foundation.
1716+ *
1717+ * This program is distributed in the hope that it will be useful, but
1718+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1719+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1720+ * PURPOSE. See the GNU General Public License for more details.
1721+ *
1722+ * You should have received a copy of the GNU General Public License along
1723+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1724+ *
1725+ * Authors:
1726+ * Charles Kerr <charles.kerr@canonical.com>
1727+ */
1728+
1729+#ifndef INDICATOR_DATETIME_LIVE_TIMEZONES_H
1730+#define INDICATOR_DATETIME_LIVE_TIMEZONES_H
1731+
1732+#include <datetime/settings.h>
1733+#include <datetime/timezones.h>
1734+#include <datetime/timezone-file.h>
1735+#include <datetime/timezone-geoclue.h>
1736+
1737+#include <memory> // shared_ptr<>
1738+
1739+namespace unity {
1740+namespace indicator {
1741+namespace datetime {
1742+
1743+/**
1744+ * \brief #Timezones object that uses a #FileTimezone and #GeoclueTimezone
1745+ * to detect what timezone we're in
1746+ */
1747+class LiveTimezones: public Timezones
1748+{
1749+public:
1750+ LiveTimezones(const std::shared_ptr<const Settings>& settings, const std::string& filename);
1751+
1752+private:
1753+ void update_geolocation();
1754+ void update_timezones();
1755+
1756+ FileTimezone m_file;
1757+ std::shared_ptr<const Settings> m_settings;
1758+ std::shared_ptr<GeoclueTimezone> m_geo;
1759+};
1760+
1761+} // namespace datetime
1762+} // namespace indicator
1763+} // namespace unity
1764+
1765+#endif // INDICATOR_DATETIME_LIVE_TIMEZONES_H
1766
1767=== added file 'include/datetime/timezones.h'
1768--- include/datetime/timezones.h 1970-01-01 00:00:00 +0000
1769+++ include/datetime/timezones.h 2014-01-31 00:43:10 +0000
1770@@ -0,0 +1,59 @@
1771+/*
1772+ * Copyright 2013 Canonical Ltd.
1773+ *
1774+ * This program is free software: you can redistribute it and/or modify it
1775+ * under the terms of the GNU General Public License version 3, as published
1776+ * by the Free Software Foundation.
1777+ *
1778+ * This program is distributed in the hope that it will be useful, but
1779+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1780+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1781+ * PURPOSE. See the GNU General Public License for more details.
1782+ *
1783+ * You should have received a copy of the GNU General Public License along
1784+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1785+ *
1786+ * Authors:
1787+ * Charles Kerr <charles.kerr@canonical.com>
1788+ */
1789+
1790+#ifndef INDICATOR_DATETIME_TIMEZONES_H
1791+#define INDICATOR_DATETIME_TIMEZONES_H
1792+
1793+#include <datetime/timezone.h>
1794+
1795+#include <core/property.h>
1796+
1797+namespace unity {
1798+namespace indicator {
1799+namespace datetime {
1800+
1801+/**
1802+ * \brief Helper class which aggregates one or more timezones
1803+ *
1804+ * @see LiveClock
1805+ * @see SettingsLocations
1806+ */
1807+class Timezones
1808+{
1809+public:
1810+ Timezones() =default;
1811+ virtual ~Timezones() =default;
1812+
1813+ /**
1814+ * \brief the current timezone
1815+ */
1816+ core::Property<std::string> timezone;
1817+
1818+ /**
1819+ * \brief all the detected timezones.
1820+ * The count is >1 iff the detection mechamisms disagree.
1821+ */
1822+ core::Property<std::set<std::string> > timezones;
1823+};
1824+
1825+} // namespace datetime
1826+} // namespace indicator
1827+} // namespace unity
1828+
1829+#endif // INDICATOR_DATETIME_TIMEZONES_H
1830
1831=== added file 'include/datetime/utils.h'
1832--- include/datetime/utils.h 1970-01-01 00:00:00 +0000
1833+++ include/datetime/utils.h 2014-01-31 00:43:10 +0000
1834@@ -0,0 +1,54 @@
1835+/*
1836+ * Copyright 2010, 2014 Canonical Ltd.
1837+ *
1838+ * This program is free software: you can redistribute it and/or modify it
1839+ * under the terms of the GNU General Public License version 3, as published
1840+ * by the Free Software Foundation.
1841+ *
1842+ * This program is distributed in the hope that it will be useful, but
1843+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1844+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1845+ * PURPOSE. See the GNU General Public License for more details.
1846+ *
1847+ * You should have received a copy of the GNU General Public License along
1848+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1849+ *
1850+ * Authors:
1851+ * Michael Terry <michael.terry@canonical.com>
1852+ * Charles Kerr <charles.kerr@canonical.com>
1853+ */
1854+
1855+#ifndef INDICATOR_DATETIME_UTILS_H
1856+#define INDICATOR_DATETIME_UTILS_H
1857+
1858+#include <glib.h>
1859+#include <gio/gio.h> /* GSettings */
1860+
1861+G_BEGIN_DECLS
1862+
1863+/** \brief Returns true if the current locale prefers 12h display instead of 24h */
1864+gboolean is_locale_12h (void);
1865+
1866+void split_settings_location (const char * location,
1867+ char ** zone,
1868+ char ** name);
1869+
1870+gchar * get_timezone_name (const char * timezone,
1871+ GSettings * settings);
1872+
1873+gchar * get_beautified_timezone_name (const char * timezone,
1874+ const char * saved_location);
1875+
1876+gchar * generate_full_format_string_at_time (GDateTime * now,
1877+ GDateTime * then_begin,
1878+ GDateTime * then_end);
1879+
1880+/** \brief Translate the string based on LC_TIME instead of LC_MESSAGES.
1881+ The intent of this is to let users set LC_TIME to override
1882+ their other locale settings when generating time format string */
1883+const char* T_ (const char * msg);
1884+
1885+
1886+G_END_DECLS
1887+
1888+#endif /* INDICATOR_DATETIME_UTILS_H */
1889
1890=== modified file 'panel-gnome/CMakeLists.txt'
1891--- panel-gnome/CMakeLists.txt 2014-01-10 01:45:41 +0000
1892+++ panel-gnome/CMakeLists.txt 2014-01-31 00:43:10 +0000
1893@@ -2,16 +2,20 @@
1894
1895 add_definitions (-DPKGDATADIR="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}")
1896
1897+
1898+SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -g")
1899+SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g ${CXX_WARNING_ARGS}")
1900+
1901 add_library (${PANEL_LIB} SHARED
1902 ${CMAKE_SOURCE_DIR}/panel/datetime-prefs.c
1903 ${CMAKE_SOURCE_DIR}/panel/datetime-prefs-locations.c
1904 ${CMAKE_SOURCE_DIR}/panel/datetime-prefs-locations.h
1905 ${CMAKE_SOURCE_DIR}/src/utils.c
1906- ${CMAKE_SOURCE_DIR}/src/utils.h
1907- ${CMAKE_SOURCE_DIR}/src/settings-shared.h)
1908+ ${CMAKE_SOURCE_DIR}/include/datetime/utils.h
1909+ ${CMAKE_SOURCE_DIR}/include/datetime/settings-shared.h)
1910 set_property (TARGET ${PANEL_LIB} PROPERTY OUTPUT_NAME indicator-datetime)
1911
1912-include_directories (${PANEL_DEPS_INCLUDE_DIRS})
1913+include_directories (SYSTEM ${PANEL_DEPS_INCLUDE_DIRS})
1914
1915 link_directories (${PANEL_DEPS_LIBRARY_DIRS})
1916
1917
1918=== modified file 'panel-unity/CMakeLists.txt'
1919--- panel-unity/CMakeLists.txt 2014-01-10 01:45:41 +0000
1920+++ panel-unity/CMakeLists.txt 2014-01-31 00:43:10 +0000
1921@@ -2,16 +2,19 @@
1922
1923 add_definitions (-DPKGDATADIR="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}")
1924
1925+SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -g")
1926+SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g ${CXX_WARNING_ARGS}")
1927+
1928 add_library (${PANEL_LIB} SHARED
1929 ${CMAKE_SOURCE_DIR}/panel/datetime-prefs.c
1930 ${CMAKE_SOURCE_DIR}/panel/datetime-prefs-locations.c
1931 ${CMAKE_SOURCE_DIR}/panel/datetime-prefs-locations.h
1932 ${CMAKE_SOURCE_DIR}/src/utils.c
1933- ${CMAKE_SOURCE_DIR}/src/utils.h
1934- ${CMAKE_SOURCE_DIR}/src/settings-shared.h)
1935+ ${CMAKE_SOURCE_DIR}/include/datetime/utils.h
1936+ ${CMAKE_SOURCE_DIR}/include/datetime/settings-shared.h)
1937 set_property (TARGET ${PANEL_LIB} PROPERTY OUTPUT_NAME indicator-datetime)
1938
1939-include_directories (${UNITY_PANEL_DEPS_INCLUDE_DIRS})
1940+include_directories (SYSTEM ${UNITY_PANEL_DEPS_INCLUDE_DIRS})
1941
1942 link_directories (${UNITY_PANEL_DEPS_LIBRARY_DIRS})
1943
1944
1945=== modified file 'panel/datetime-prefs-locations.c'
1946--- panel/datetime-prefs-locations.c 2014-01-29 18:49:55 +0000
1947+++ panel/datetime-prefs-locations.c 2014-01-31 00:43:10 +0000
1948@@ -24,20 +24,23 @@
1949 #include "config.h"
1950 #endif
1951
1952+#include "datetime-prefs-locations.h"
1953+
1954+#include <datetime/settings-shared.h>
1955+#include <datetime/utils.h>
1956+
1957+#include <timezonemap/timezone-completion.h>
1958+
1959+#include <glib/gi18n-lib.h>
1960+#include <gtk/gtk.h>
1961+
1962 #include <stdlib.h>
1963 #include <time.h> /* time_t */
1964-#include <glib/gi18n-lib.h>
1965-#include <gtk/gtk.h>
1966-#include <timezonemap/timezone-completion.h>
1967-
1968-#include "datetime-prefs-locations.h"
1969-#include "settings-shared.h"
1970-#include "utils.h"
1971
1972 #if USE_UNITY
1973-#define DATETIME_DIALOG_UI_FILE PKGDATADIR "/unity-control-center/datetime-dialog.ui"
1974+ #define DATETIME_DIALOG_UI_FILE PKGDATADIR "/unity-control-center/datetime-dialog.ui"
1975 #else
1976-#define DATETIME_DIALOG_UI_FILE PKGDATADIR "/gnome-control-center/datetime-dialog.ui"
1977+ #define DATETIME_DIALOG_UI_FILE PKGDATADIR "/gnome-control-center/datetime-dialog.ui"
1978 #endif
1979
1980 #define COL_NAME 0
1981@@ -314,7 +317,7 @@
1982
1983 gtk_list_store_set (store, &iter,
1984 COL_VISIBLE_NAME, new_text,
1985- COL_ICON, correct ? NULL : GTK_STOCK_DIALOG_ERROR,
1986+ COL_ICON, correct ? NULL : "dialog-error",
1987 -1);
1988 }
1989 }
1990@@ -429,7 +432,6 @@
1991
1992 g_signal_handlers_block_by_func (store, save_when_idle, dlg);
1993
1994- GSettings * settings = g_settings_new (SETTINGS_INTERFACE);
1995 GtkTreeIter iter;
1996 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
1997 GDateTime * now = g_date_time_new_now_local ();
1998@@ -441,7 +443,7 @@
1999 if (strzone && *strzone) {
2000 GTimeZone * tz = g_time_zone_new (strzone);
2001 GDateTime * now_tz = g_date_time_to_timezone (now, tz);
2002- gchar * format = generate_full_format_string_at_time (now, now_tz, settings);
2003+ gchar * format = generate_full_format_string_at_time (now, now_tz, NULL);
2004 gchar * time_str = g_date_time_format (now_tz, format);
2005 gchar * old_time_str;
2006
2007@@ -460,8 +462,6 @@
2008 g_date_time_unref (now);
2009 }
2010
2011- g_object_unref (settings);
2012-
2013 g_signal_handlers_unblock_by_func (store, save_when_idle, dlg);
2014
2015 return TRUE;
2016
2017=== modified file 'panel/datetime-prefs.c'
2018--- panel/datetime-prefs.c 2014-01-10 01:45:41 +0000
2019+++ panel/datetime-prefs.c 2014-01-31 00:43:10 +0000
2020@@ -25,26 +25,30 @@
2021 #include "config.h"
2022 #endif
2023
2024+#include "datetime-prefs-locations.h"
2025+
2026+#include <datetime/dbus-shared.h>
2027+#include <datetime/settings-shared.h>
2028+#include <datetime/utils.h>
2029+
2030+#include <polkit/polkit.h>
2031+#include <timezonemap/cc-timezone-map.h>
2032+#include <timezonemap/timezone-completion.h>
2033+
2034+#include <glib/gi18n-lib.h>
2035+#include <gdk/gdkkeysyms.h>
2036+#include <gtk/gtk.h>
2037+
2038+#ifdef USE_UNITY
2039+ #include <libunity-control-center/cc-panel.h>
2040+#else
2041+ #include <libgnome-control-center/cc-panel.h>
2042+#endif
2043+
2044 #include <stdlib.h>
2045 #include <libintl.h>
2046 #include <locale.h>
2047 #include <langinfo.h>
2048-#include <glib/gi18n-lib.h>
2049-#include <gdk/gdkkeysyms.h>
2050-#include <gtk/gtk.h>
2051-#include <polkit/polkit.h>
2052-#if USE_UNITY
2053-#include <libunity-control-center/cc-panel.h>
2054-#else
2055-#include <libgnome-control-center/cc-panel.h>
2056-#endif
2057-#include <timezonemap/cc-timezone-map.h>
2058-#include <timezonemap/timezone-completion.h>
2059-
2060-#include "dbus-shared.h"
2061-#include "settings-shared.h"
2062-#include "utils.h"
2063-#include "datetime-prefs-locations.h"
2064
2065 #if USE_UNITY
2066 #define DATETIME_DIALOG_UI_FILE PKGDATADIR "/unity-control-center/datetime-dialog.ui"
2067@@ -225,12 +229,12 @@
2068 static void
2069 sync_entry (IndicatorDatetimePanel * self, const gchar * location)
2070 {
2071- gchar * name = get_current_zone_name (location, self->priv->settings);
2072+ gchar * name = get_timezone_name (location, self->priv->settings);
2073 gtk_entry_set_text (GTK_ENTRY (self->priv->tz_entry), name);
2074 g_free (name);
2075
2076- gtk_entry_set_icon_from_stock (GTK_ENTRY (self->priv->tz_entry),
2077- GTK_ENTRY_ICON_SECONDARY, NULL);
2078+ gtk_entry_set_icon_from_icon_name (GTK_ENTRY (self->priv->tz_entry),
2079+ GTK_ENTRY_ICON_SECONDARY, NULL);
2080 }
2081
2082 static void
2083@@ -295,10 +299,10 @@
2084 {
2085 if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
2086 {
2087- const gchar *timezone = g_variant_get_string (value, NULL);
2088+ const gchar * str = g_variant_get_string (value, NULL);
2089
2090- cc_timezone_map_set_timezone (priv->tzmap, timezone);
2091- sync_entry (self, timezone);
2092+ cc_timezone_map_set_timezone (priv->tzmap, str);
2093+ sync_entry (self, str);
2094 g_signal_connect (priv->tzmap, "location-changed", G_CALLBACK (tz_changed), self);
2095 }
2096 g_variant_unref (value);
2097@@ -640,13 +644,13 @@
2098 gchar * zone;
2099 g_object_get (location, "zone", &zone, NULL);
2100
2101- gchar * name = get_current_zone_name (zone, self->priv->settings);
2102+ gchar * name = get_timezone_name (zone, self->priv->settings);
2103 gboolean correct = (g_strcmp0 (gtk_entry_get_text (entry), name) == 0);
2104 g_free (name);
2105 g_free (zone);
2106
2107- gtk_entry_set_icon_from_stock (entry, GTK_ENTRY_ICON_SECONDARY,
2108- correct ? NULL : GTK_STOCK_DIALOG_ERROR);
2109+ gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY,
2110+ correct ? NULL : "dialog-error");
2111 gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY,
2112 _("You need to choose a location to change the time zone."));
2113 gtk_entry_set_icon_activatable (entry, GTK_ENTRY_ICON_SECONDARY, FALSE);
2114
2115=== modified file 'po/POTFILES.in'
2116--- po/POTFILES.in 2014-01-10 01:45:41 +0000
2117+++ po/POTFILES.in 2014-01-31 00:43:10 +0000
2118@@ -1,6 +1,6 @@
2119-src/service.c
2120-src/settings-shared.h
2121-src/utils.c
2122+src/formatter.cpp
2123+src/formatter-desktop.cpp
2124+src/menu.cpp
2125 panel/datetime-prefs.c
2126 panel/datetime-prefs-locations.c
2127 [type: gettext/glade]data/datetime-dialog.ui
2128
2129=== modified file 'src/CMakeLists.txt'
2130--- src/CMakeLists.txt 2013-12-13 15:44:46 +0000
2131+++ src/CMakeLists.txt 2014-01-31 00:43:10 +0000
2132@@ -1,6 +1,9 @@
2133 set (SERVICE_LIB "indicatordatetimeservice")
2134 set (SERVICE_EXEC "indicator-datetime-service")
2135
2136+SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -g ${CXX_WARNING_ARGS} ${GCOV_FLAGS}")
2137+SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g ${CXX_WARNING_ARGS} ${GCOV_FLAGS}")
2138+
2139 add_definitions (-DTIMEZONE_FILE="/etc/timezone"
2140 -DG_LOG_DOMAIN="Indicator-Datetime")
2141
2142@@ -10,36 +13,28 @@
2143 endif ()
2144
2145 add_library (${SERVICE_LIB} STATIC
2146- clock.c
2147- clock.h
2148- clock-live.c
2149- clock-live.h
2150- planner.c
2151- planner.h
2152- planner-eds.c
2153- planner-eds.h
2154- service.c
2155- service.h
2156- timezone.c
2157- timezone.h
2158- timezone-file.c
2159- timezone-file.h
2160- timezone-geoclue.c
2161- timezone-geoclue.h
2162- utils.c
2163- utils.h
2164- dbus-shared.h
2165- settings-shared.h)
2166-include_directories (${SERVICE_DEPS_INCLUDE_DIRS})
2167+ actions.cpp
2168+ actions-live.cpp
2169+ appointment.cpp
2170+ clock.cpp
2171+ clock-live.cpp
2172+ date-time.cpp
2173+ exporter.cpp
2174+ formatter.cpp
2175+ formatter-desktop.cpp
2176+ locations.cpp
2177+ locations-settings.cpp
2178+ menu.cpp
2179+ planner-eds.cpp
2180+ settings-live.cpp
2181+ timezone-file.cpp
2182+ timezone-geoclue.cpp
2183+ timezones-live.cpp
2184+ utils.c)
2185+include_directories (${CMAKE_SOURCE_DIR})
2186 link_directories (${SERVICE_DEPS_LIBRARY_DIRS})
2187
2188-add_executable (${SERVICE_EXEC} main.c)
2189+add_executable (${SERVICE_EXEC} main.cpp)
2190 target_link_libraries (${SERVICE_EXEC} ${SERVICE_LIB} ${SERVICE_DEPS_LIBRARIES} ${GCOV_LIBS})
2191 install (TARGETS ${SERVICE_EXEC} RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR})
2192
2193-# common properties
2194-set_property (TARGET ${SERVICE_LIB} ${SERVICE_EXEC}
2195- APPEND_STRING PROPERTY COMPILE_FLAGS
2196- " -g ${CC_WARNING_ARGS} ${GCOV_FLAGS}")
2197-
2198-
2199
2200=== added file 'src/actions-live.cpp'
2201--- src/actions-live.cpp 1970-01-01 00:00:00 +0000
2202+++ src/actions-live.cpp 2014-01-31 00:43:10 +0000
2203@@ -0,0 +1,217 @@
2204+/*
2205+ * Copyright 2013 Canonical Ltd.
2206+ *
2207+ * This program is free software: you can redistribute it and/or modify it
2208+ * under the terms of the GNU General Public License version 3, as published
2209+ * by the Free Software Foundation.
2210+ *
2211+ * This program is distributed in the hope that it will be useful, but
2212+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2213+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2214+ * PURPOSE. See the GNU General Public License for more details.
2215+ *
2216+ * You should have received a copy of the GNU General Public License along
2217+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2218+ *
2219+ * Authors:
2220+ * Charles Kerr <charles.kerr@canonical.com>
2221+ */
2222+
2223+#include <datetime/actions-live.h>
2224+
2225+#include <url-dispatcher.h>
2226+
2227+#include <glib.h>
2228+
2229+namespace unity {
2230+namespace indicator {
2231+namespace datetime {
2232+
2233+/***
2234+****
2235+***/
2236+
2237+LiveActions::LiveActions(const std::shared_ptr<State>& state_in):
2238+ Actions(state_in)
2239+{
2240+}
2241+
2242+void LiveActions::execute_command(const std::string& cmdstr)
2243+{
2244+ const auto cmd = cmdstr.c_str();
2245+ g_debug("Issuing command '%s'", cmd);
2246+
2247+ GError* error = nullptr;
2248+ if (!g_spawn_command_line_async(cmd, &error))
2249+ {
2250+ g_warning("Unable to start \"%s\": %s", cmd, error->message);
2251+ g_error_free(error);
2252+ }
2253+}
2254+
2255+void LiveActions::dispatch_url(const std::string& url)
2256+{
2257+ url_dispatch_send(url.c_str(), nullptr, nullptr);
2258+}
2259+
2260+/***
2261+****
2262+***/
2263+
2264+void LiveActions::open_desktop_settings()
2265+{
2266+ auto path = g_find_program_in_path("unity-control-center");
2267+
2268+ if ((path != nullptr) && (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity") == 0))
2269+ {
2270+ execute_command("unity-control-center datetime");
2271+ }
2272+ else
2273+ {
2274+#ifdef HAVE_CCPANEL
2275+ execute_command("gnome-control-center indicator-datetime");
2276+#else
2277+ execute_command("gnome-control-center datetime");
2278+#endif
2279+ }
2280+
2281+ g_free (path);
2282+}
2283+
2284+void LiveActions::open_planner()
2285+{
2286+ execute_command("evolution -c calendar");
2287+}
2288+
2289+void LiveActions::open_phone_settings()
2290+{
2291+ dispatch_url("settings:///system/time-date");
2292+}
2293+
2294+void LiveActions::open_phone_clock_app()
2295+{
2296+ dispatch_url("appid://com.ubuntu.clock/clock/current-user-version");
2297+}
2298+
2299+void LiveActions::open_planner_at(const DateTime& dt)
2300+{
2301+ auto cmd = dt.format("evolution \"calendar:///?startdate=%Y%m%d\"");
2302+ execute_command(cmd.c_str());
2303+}
2304+
2305+void LiveActions::open_appointment(const std::string& uid)
2306+{
2307+ for(const auto& appt : state()->planner->upcoming.get())
2308+ {
2309+ if(appt.uid != uid)
2310+ continue;
2311+
2312+ if (!appt.url.empty())
2313+ dispatch_url(appt.url);
2314+ break;
2315+ }
2316+}
2317+
2318+/***
2319+****
2320+***/
2321+
2322+namespace
2323+{
2324+
2325+struct setlocation_data
2326+{
2327+ std::string tzid;
2328+ std::string name;
2329+ std::shared_ptr<Settings> settings;
2330+};
2331+
2332+static void
2333+on_datetime1_set_timezone_response(GObject * object,
2334+ GAsyncResult * res,
2335+ gpointer gdata)
2336+{
2337+ GError* err = nullptr;
2338+ auto response = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), res, &err);
2339+ auto data = static_cast<struct setlocation_data*>(gdata);
2340+
2341+ if (err != nullptr)
2342+ {
2343+ if (!g_error_matches(err, G_IO_ERROR, G_IO_ERROR_CANCELLED))
2344+ g_warning("Could not set new timezone: %s", err->message);
2345+
2346+ g_error_free(err);
2347+ }
2348+ else
2349+ {
2350+ data->settings->timezone_name.set(data->tzid + " " + data->name);
2351+ g_variant_unref(response);
2352+ }
2353+
2354+ delete data;
2355+}
2356+
2357+static void
2358+on_datetime1_proxy_ready (GObject * object G_GNUC_UNUSED,
2359+ GAsyncResult * res,
2360+ gpointer gdata)
2361+{
2362+ auto data = static_cast<struct setlocation_data*>(gdata);
2363+
2364+ GError * err = nullptr;
2365+ auto proxy = g_dbus_proxy_new_for_bus_finish(res, &err);
2366+ if (err != NULL)
2367+ {
2368+ if (!g_error_matches(err, G_IO_ERROR, G_IO_ERROR_CANCELLED))
2369+ g_warning("Could not grab DBus proxy for timedated: %s", err->message);
2370+
2371+ g_error_free(err);
2372+
2373+ delete data;
2374+ }
2375+ else
2376+ {
2377+ g_dbus_proxy_call(proxy,
2378+ "SetTimezone",
2379+ g_variant_new ("(sb)", data->tzid.c_str(), TRUE),
2380+ G_DBUS_CALL_FLAGS_NONE,
2381+ -1,
2382+ nullptr,
2383+ on_datetime1_set_timezone_response,
2384+ data);
2385+
2386+ g_object_unref (proxy);
2387+ }
2388+}
2389+
2390+} // unnamed namespace
2391+
2392+
2393+void LiveActions::set_location(const std::string& tzid, const std::string& name)
2394+{
2395+ g_return_if_fail(!tzid.empty());
2396+ g_return_if_fail(!name.empty());
2397+
2398+ auto data = new struct setlocation_data;
2399+ data->tzid = tzid;
2400+ data->name = name;
2401+ data->settings = state()->settings;
2402+
2403+ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
2404+ G_DBUS_PROXY_FLAGS_NONE,
2405+ nullptr,
2406+ "org.freedesktop.timedate1",
2407+ "/org/freedesktop/timedate1",
2408+ "org.freedesktop.timedate1",
2409+ nullptr,
2410+ on_datetime1_proxy_ready,
2411+ data);
2412+}
2413+
2414+/***
2415+****
2416+***/
2417+
2418+} // namespace datetime
2419+} // namespace indicator
2420+} // namespace unity
2421
2422=== added file 'src/actions.cpp'
2423--- src/actions.cpp 1970-01-01 00:00:00 +0000
2424+++ src/actions.cpp 2014-01-31 00:43:10 +0000
2425@@ -0,0 +1,266 @@
2426+/*
2427+ * Copyright 2013 Canonical Ltd.
2428+ *
2429+ * This program is free software: you can redistribute it and/or modify it
2430+ * under the terms of the GNU General Public License version 3, as published
2431+ * by the Free Software Foundation.
2432+ *
2433+ * This program is distributed in the hope that it will be useful, but
2434+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2435+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2436+ * PURPOSE. See the GNU General Public License for more details.
2437+ *
2438+ * You should have received a copy of the GNU General Public License along
2439+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2440+ *
2441+ * Authors:
2442+ * Charles Kerr <charles.kerr@canonical.com>
2443+ */
2444+
2445+#include <datetime/actions.h>
2446+#include <datetime/utils.h> // split_settings_location()
2447+
2448+#include <glib.h>
2449+#include <gio/gio.h>
2450+
2451+namespace unity {
2452+namespace indicator {
2453+namespace datetime {
2454+
2455+/***
2456+****
2457+***/
2458+
2459+namespace
2460+{
2461+
2462+void on_desktop_settings_activated(GSimpleAction * /*action*/,
2463+ GVariant * /*param*/,
2464+ gpointer gself)
2465+{
2466+ static_cast<Actions*>(gself)->open_desktop_settings();
2467+}
2468+
2469+void on_phone_settings_activated(GSimpleAction * /*action*/,
2470+ GVariant * /*param*/,
2471+ gpointer gself)
2472+{
2473+ static_cast<Actions*>(gself)->open_phone_settings();
2474+}
2475+
2476+void on_phone_clock_activated(GSimpleAction * /*action*/,
2477+ GVariant * /*param*/,
2478+ gpointer gself)
2479+{
2480+ static_cast<Actions*>(gself)->open_phone_clock_app();
2481+}
2482+
2483+void on_activate_appointment(GSimpleAction * /*action*/,
2484+ GVariant * param,
2485+ gpointer gself)
2486+{
2487+ const auto uid = g_variant_get_string(param, nullptr);
2488+ auto self = static_cast<Actions*>(gself);
2489+
2490+ g_return_if_fail(uid && *uid);
2491+
2492+ // find url of the upcoming appointment with this uid
2493+ for (const auto& appt : self->state()->planner->upcoming.get())
2494+ {
2495+ if (appt.uid == uid)
2496+ {
2497+ const auto url = appt.url;
2498+ g_debug("%s: uid[%s] -> url[%s]", G_STRFUNC, uid, url.c_str());
2499+ self->open_appointment(url);
2500+ break;
2501+ }
2502+ }
2503+}
2504+
2505+void on_activate_planner(GSimpleAction * /*action*/,
2506+ GVariant * param,
2507+ gpointer gself)
2508+{
2509+ const auto at = g_variant_get_int64(param);
2510+ auto self = static_cast<Actions*>(gself);
2511+
2512+ if (at)
2513+ {
2514+ auto gdt = g_date_time_new_from_unix_local(at);
2515+ self->open_planner_at(DateTime(gdt));
2516+ g_date_time_unref(gdt);
2517+ }
2518+ else // no time specified...
2519+ {
2520+ self->open_planner();
2521+ }
2522+}
2523+
2524+void on_set_location(GSimpleAction * /*action*/,
2525+ GVariant * param,
2526+ gpointer gself)
2527+{
2528+ char * zone;
2529+ char * name;
2530+ split_settings_location(g_variant_get_string(param, nullptr), &zone, &name);
2531+ static_cast<Actions*>(gself)->set_location(zone, name);
2532+ g_free(name);
2533+ g_free(zone);
2534+}
2535+
2536+void on_calendar_active_changed(GSimpleAction * /*action*/,
2537+ GVariant * state,
2538+ gpointer gself)
2539+{
2540+ // reset the date when the menu is shown
2541+ if (g_variant_get_boolean(state))
2542+ {
2543+ auto self = static_cast<Actions*>(gself);
2544+
2545+ self->set_calendar_date(self->state()->clock->localtime());
2546+ }
2547+}
2548+
2549+void on_calendar_activated(GSimpleAction * /*action*/,
2550+ GVariant * state,
2551+ gpointer gself)
2552+{
2553+ const time_t t = g_variant_get_int64(state);
2554+
2555+ g_return_if_fail(t != 0);
2556+
2557+ static_cast<Actions*>(gself)->set_calendar_date(DateTime(t));
2558+}
2559+
2560+GVariant* create_default_header_state()
2561+{
2562+ GVariantBuilder b;
2563+ g_variant_builder_init(&b, G_VARIANT_TYPE_VARDICT);
2564+ g_variant_builder_add(&b, "{sv}", "accessible-desc", g_variant_new_string("accessible-desc"));
2565+ g_variant_builder_add(&b, "{sv}", "label", g_variant_new_string("label"));
2566+ g_variant_builder_add(&b, "{sv}", "title", g_variant_new_string("title"));
2567+ g_variant_builder_add(&b, "{sv}", "visible", g_variant_new_boolean(true));
2568+ return g_variant_builder_end(&b);
2569+}
2570+
2571+GVariant* create_calendar_state(const std::shared_ptr<State>& state)
2572+{
2573+ gboolean days[32] = { 0 };
2574+ for (const auto& appt : state->planner->this_month.get())
2575+ days[appt.begin.day_of_month()] = true;
2576+
2577+ GVariantBuilder day_builder;
2578+ g_variant_builder_init(&day_builder, G_VARIANT_TYPE("ai"));
2579+ for (guint i=0; i<G_N_ELEMENTS(days); i++)
2580+ if (days[i])
2581+ g_variant_builder_add(&day_builder, "i", i);
2582+
2583+ GVariantBuilder dict_builder;
2584+ g_variant_builder_init(&dict_builder, G_VARIANT_TYPE_DICTIONARY);
2585+
2586+ auto key = "appointment-days";
2587+ auto v = g_variant_builder_end(&day_builder);
2588+ g_variant_builder_add(&dict_builder, "{sv}", key, v);
2589+
2590+ key = "calendar-day";
2591+ v = g_variant_new_int64(state->planner->time.get().to_unix());
2592+ g_variant_builder_add(&dict_builder, "{sv}", key, v);
2593+
2594+ key = "show-week-numbers";
2595+ v = g_variant_new_boolean(state->settings->show_week_numbers.get());
2596+ g_variant_builder_add(&dict_builder, "{sv}", key, v);
2597+
2598+ return g_variant_builder_end(&dict_builder);
2599+}
2600+} // unnamed namespace
2601+
2602+/***
2603+****
2604+***/
2605+
2606+Actions::Actions(const std::shared_ptr<State>& state):
2607+ m_state(state),
2608+ m_actions(g_simple_action_group_new())
2609+{
2610+ GActionEntry entries[] = {
2611+ { "activate-desktop-settings", on_desktop_settings_activated },
2612+ { "activate-phone-settings", on_phone_settings_activated },
2613+ { "activate-phone-clock-app", on_phone_clock_activated },
2614+ { "activate-appointment", on_activate_appointment, "s", nullptr },
2615+ { "activate-planner", on_activate_planner, "x", nullptr },
2616+ { "calendar-active", nullptr, nullptr, "false", on_calendar_active_changed },
2617+ { "set-location", on_set_location, "s" }
2618+ };
2619+
2620+ g_action_map_add_action_entries(G_ACTION_MAP(m_actions),
2621+ entries,
2622+ G_N_ELEMENTS(entries),
2623+ this);
2624+
2625+ // add the header actions
2626+ auto gam = G_ACTION_MAP(m_actions);
2627+ auto v = create_default_header_state();
2628+ auto a = g_simple_action_new_stateful("desktop-header", nullptr, v);
2629+ g_action_map_add_action(gam, G_ACTION(a));
2630+ a = g_simple_action_new_stateful("desktop_greeter-header", nullptr, v);
2631+ g_action_map_add_action(gam, G_ACTION(a));
2632+ a = g_simple_action_new_stateful("phone-header", nullptr, v);
2633+ g_action_map_add_action(gam, G_ACTION(a));
2634+ a = g_simple_action_new_stateful("phone_greeter-header", nullptr, v);
2635+ g_action_map_add_action(gam, G_ACTION(a));
2636+
2637+ // add the calendar action
2638+ v = create_calendar_state(state);
2639+ a = g_simple_action_new_stateful("calendar", G_VARIANT_TYPE_INT64, v);
2640+ g_action_map_add_action(gam, G_ACTION(a));
2641+ g_signal_connect(a, "activate", G_CALLBACK(on_calendar_activated), this);
2642+
2643+ ///
2644+ /// Keep our GActionGroup's action's states in sync with m_state
2645+ ///
2646+
2647+ m_state->planner->time.changed().connect([this](const DateTime&){
2648+ update_calendar_state();
2649+ });
2650+ m_state->planner->this_month.changed().connect([this](const std::vector<Appointment>&){
2651+ update_calendar_state();
2652+ });
2653+ m_state->settings->show_week_numbers.changed().connect([this](bool){
2654+ update_calendar_state();
2655+ });
2656+
2657+ // FIXME: rebuild the calendar state when show-week-number changes
2658+}
2659+
2660+Actions::~Actions()
2661+{
2662+ g_clear_object(&m_actions);
2663+}
2664+
2665+void Actions::update_calendar_state()
2666+{
2667+ g_action_group_change_action_state(action_group(),
2668+ "calendar",
2669+ create_calendar_state(m_state));
2670+}
2671+
2672+void Actions::set_calendar_date(const DateTime& date)
2673+{
2674+ m_state->planner->time.set(date);
2675+}
2676+
2677+GActionGroup* Actions::action_group()
2678+{
2679+ return G_ACTION_GROUP(m_actions);
2680+}
2681+
2682+const std::shared_ptr<State> Actions::state() const
2683+{
2684+ return m_state;
2685+}
2686+
2687+
2688+
2689+} // namespace datetime
2690+} // namespace indicator
2691+} // namespace unity
2692
2693=== added file 'src/appointment.cpp'
2694--- src/appointment.cpp 1970-01-01 00:00:00 +0000
2695+++ src/appointment.cpp 2014-01-31 00:43:10 +0000
2696@@ -0,0 +1,48 @@
2697+/*
2698+ * Copyright 2013 Canonical Ltd.
2699+ *
2700+ * This program is free software: you can redistribute it and/or modify it
2701+ * under the terms of the GNU General Public License version 3, as published
2702+ * by the Free Software Foundation.
2703+ *
2704+ * This program is distributed in the hope that it will be useful, but
2705+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2706+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2707+ * PURPOSE. See the GNU General Public License for more details.
2708+ *
2709+ * You should have received a copy of the GNU General Public License along
2710+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2711+ *
2712+ * Authors:
2713+ * Charles Kerr <charles.kerr@canonical.com>
2714+ */
2715+
2716+#include <datetime/appointment.h>
2717+
2718+namespace unity {
2719+namespace indicator {
2720+namespace datetime {
2721+
2722+/****
2723+*****
2724+****/
2725+
2726+bool Appointment::operator==(const Appointment& that) const
2727+{
2728+ return (color==that.color)
2729+ && (summary==that.summary)
2730+ && (url==that.url)
2731+ && (uid==that.uid)
2732+ && (is_event==that.is_event)
2733+ && (has_alarms==that.has_alarms)
2734+ && (begin==that.begin)
2735+ && (end==that.end);
2736+}
2737+
2738+/****
2739+*****
2740+****/
2741+
2742+} // namespace datetime
2743+} // namespace indicator
2744+} // namespace unity
2745
2746=== removed file 'src/clock-live.c'
2747--- src/clock-live.c 2013-11-14 22:52:32 +0000
2748+++ src/clock-live.c 1970-01-01 00:00:00 +0000
2749@@ -1,278 +0,0 @@
2750-/*
2751- * Copyright 2013 Canonical Ltd.
2752- *
2753- * Authors:
2754- * Charles Kerr <charles.kerr@canonical.com>
2755- *
2756- * This program is free software: you can redistribute it and/or modify it
2757- * under the terms of the GNU General Public License version 3, as published
2758- * by the Free Software Foundation.
2759- *
2760- * This program is distributed in the hope that it will be useful, but
2761- * WITHOUT ANY WARRANTY; without even the implied warranties of
2762- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2763- * PURPOSE. See the GNU General Public License for more details.
2764- *
2765- * You should have received a copy of the GNU General Public License along
2766- * with this program. If not, see <http://www.gnu.org/licenses/>.
2767- */
2768-
2769-#include <glib.h>
2770-#include <gio/gio.h>
2771-
2772-#include "clock-live.h"
2773-#include "settings-shared.h"
2774-#include "timezone-file.h"
2775-#include "timezone-geoclue.h"
2776-
2777-/***
2778-**** private struct
2779-***/
2780-
2781-struct _IndicatorDatetimeClockLivePriv
2782-{
2783- GSettings * settings;
2784-
2785- GSList * timezones; /* IndicatorDatetimeTimezone */
2786- gchar ** timezones_strv;
2787- GTimeZone * localtime_zone;
2788-};
2789-
2790-typedef IndicatorDatetimeClockLivePriv priv_t;
2791-
2792-/***
2793-**** GObject boilerplate
2794-***/
2795-
2796-static void indicator_datetime_clock_interface_init (
2797- IndicatorDatetimeClockInterface * iface);
2798-
2799-G_DEFINE_TYPE_WITH_CODE (
2800- IndicatorDatetimeClockLive,
2801- indicator_datetime_clock_live,
2802- G_TYPE_OBJECT,
2803- G_IMPLEMENT_INTERFACE (INDICATOR_TYPE_DATETIME_CLOCK,
2804- indicator_datetime_clock_interface_init))
2805-
2806-/***
2807-**** Timezones
2808-***/
2809-
2810-static void
2811-on_current_timezone_changed (IndicatorDatetimeClockLive * self)
2812-{
2813- priv_t * p = self->priv;
2814-
2815- /* Invalidate the timezone information.
2816- These fields will be lazily regenerated by rebuild_timezones() */
2817- g_clear_pointer (&p->timezones_strv, g_strfreev);
2818- g_clear_pointer (&p->localtime_zone, g_time_zone_unref);
2819-
2820- indicator_datetime_clock_emit_changed (INDICATOR_DATETIME_CLOCK (self));
2821-}
2822-
2823-static void
2824-set_detect_location_enabled (IndicatorDatetimeClockLive * self, gboolean enabled)
2825-{
2826- GSList * l;
2827- priv_t * p = self->priv;
2828- gboolean changed = FALSE;
2829-
2830- /* clear out the old timezone objects */
2831- if (p->timezones != NULL)
2832- {
2833- for (l=p->timezones; l!=NULL; l=l->next)
2834- {
2835- g_signal_handlers_disconnect_by_func (l->data, on_current_timezone_changed, self);
2836- g_object_unref (l->data);
2837- }
2838-
2839- g_slist_free (p->timezones);
2840- p->timezones = NULL;
2841- changed = TRUE;
2842- }
2843-
2844- /* maybe add new timezone objects */
2845- if (enabled)
2846- {
2847- p->timezones = g_slist_append (p->timezones, indicator_datetime_timezone_geoclue_new ());
2848- p->timezones = g_slist_append (p->timezones, indicator_datetime_timezone_file_new (TIMEZONE_FILE));
2849-
2850- for (l=p->timezones; l!=NULL; l=l->next)
2851- {
2852- g_signal_connect_swapped (l->data, "notify::timezone",
2853- G_CALLBACK(on_current_timezone_changed), self);
2854- }
2855-
2856- changed = TRUE;
2857- }
2858-
2859- if (changed)
2860- on_current_timezone_changed (self);
2861-}
2862-
2863-/* When the 'auto-detect timezone' boolean setting changes,
2864- start or stop watching geoclue and /etc/timezone */
2865-static void
2866-on_detect_location_changed (IndicatorDatetimeClockLive * self)
2867-{
2868- const gboolean enabled = g_settings_get_boolean (self->priv->settings, SETTINGS_SHOW_DETECTED_S);
2869- set_detect_location_enabled (self, enabled);
2870-}
2871-
2872-/***
2873-**** IndicatorDatetimeClock virtual functions
2874-***/
2875-
2876-static void
2877-rebuild_timezones (IndicatorDatetimeClockLive * self)
2878-{
2879- priv_t * p;
2880- GHashTable * hash;
2881- GSList * l;
2882- int i;
2883- GHashTableIter iter;
2884- gpointer key;
2885-
2886- p = self->priv;
2887-
2888- /* Build a hashtable of timezone strings.
2889- This will weed out duplicates. */
2890- hash = g_hash_table_new (g_str_hash, g_str_equal);
2891- for (l=p->timezones; l!=NULL; l=l->next)
2892- {
2893- const gchar * tz = indicator_datetime_timezone_get_timezone (l->data);
2894- if (tz && *tz)
2895- g_hash_table_add (hash, (gpointer) tz);
2896- }
2897-
2898- /* rebuild p->timezone_strv */
2899- g_strfreev (p->timezones_strv);
2900- p->timezones_strv = g_new0 (gchar*, g_hash_table_size(hash) + 1);
2901- i = 0;
2902- g_hash_table_iter_init (&iter, hash);
2903- while (g_hash_table_iter_next (&iter, &key, NULL))
2904- p->timezones_strv[i++] = g_strdup (key);
2905-
2906- /* rebuild localtime_zone */
2907- g_clear_pointer (&p->localtime_zone, g_time_zone_unref);
2908- p->localtime_zone = g_time_zone_new (p->timezones_strv ? p->timezones_strv[0] : NULL);
2909-
2910- /* cleanup */
2911- g_hash_table_unref (hash);
2912-}
2913-
2914-static const gchar **
2915-my_get_timezones (IndicatorDatetimeClock * clock)
2916-{
2917- IndicatorDatetimeClockLive * self = INDICATOR_DATETIME_CLOCK_LIVE (clock);
2918- priv_t * p = self->priv;
2919-
2920- if (G_UNLIKELY (p->timezones_strv == NULL))
2921- rebuild_timezones (self);
2922-
2923- return (const gchar **) p->timezones_strv;
2924-}
2925-
2926-static GDateTime *
2927-my_get_localtime (IndicatorDatetimeClock * clock)
2928-{
2929- IndicatorDatetimeClockLive * self = INDICATOR_DATETIME_CLOCK_LIVE (clock);
2930- priv_t * p = self->priv;
2931-
2932- if (G_UNLIKELY (p->localtime_zone == NULL))
2933- rebuild_timezones (self);
2934-
2935- return g_date_time_new_now (p->localtime_zone);
2936-}
2937-
2938-/***
2939-**** GObject virtual functions
2940-***/
2941-
2942-static void
2943-my_dispose (GObject * o)
2944-{
2945- IndicatorDatetimeClockLive * self;
2946- priv_t * p;
2947-
2948- self = INDICATOR_DATETIME_CLOCK_LIVE(o);
2949- p = self->priv;
2950-
2951- if (p->settings != NULL)
2952- {
2953- g_signal_handlers_disconnect_by_data (p->settings, self);
2954- g_clear_object (&p->settings);
2955- }
2956-
2957- set_detect_location_enabled (self, FALSE);
2958-
2959- G_OBJECT_CLASS (indicator_datetime_clock_live_parent_class)->dispose (o);
2960-}
2961-
2962-static void
2963-my_finalize (GObject * o)
2964-{
2965- IndicatorDatetimeClockLive * self;
2966- priv_t * p;
2967-
2968- self = INDICATOR_DATETIME_CLOCK_LIVE(o);
2969- p = self->priv;
2970-
2971- g_clear_pointer (&p->localtime_zone, g_time_zone_unref);
2972- g_strfreev (p->timezones_strv);
2973-
2974- G_OBJECT_CLASS (indicator_datetime_clock_live_parent_class)->dispose (o);
2975-}
2976-
2977-/***
2978-**** Instantiation
2979-***/
2980-
2981-static void
2982-indicator_datetime_clock_live_class_init (IndicatorDatetimeClockLiveClass * klass)
2983-{
2984- GObjectClass * object_class = G_OBJECT_CLASS (klass);
2985-
2986- object_class->dispose = my_dispose;
2987- object_class->finalize = my_finalize;
2988-
2989- g_type_class_add_private (klass,
2990- sizeof (IndicatorDatetimeClockLivePriv));
2991-}
2992-
2993-static void
2994-indicator_datetime_clock_interface_init (IndicatorDatetimeClockInterface * iface)
2995-{
2996- iface->get_localtime = my_get_localtime;
2997- iface->get_timezones = my_get_timezones;
2998-}
2999-
3000-static void
3001-indicator_datetime_clock_live_init (IndicatorDatetimeClockLive * self)
3002-{
3003- IndicatorDatetimeClockLivePriv * p;
3004-
3005- p = G_TYPE_INSTANCE_GET_PRIVATE (self,
3006- INDICATOR_TYPE_DATETIME_CLOCK_LIVE,
3007- IndicatorDatetimeClockLivePriv);
3008- self->priv = p;
3009-
3010- p->settings = g_settings_new (SETTINGS_INTERFACE);
3011- g_signal_connect_swapped (p->settings, "changed::" SETTINGS_SHOW_DETECTED_S,
3012- G_CALLBACK(on_detect_location_changed), self);
3013-
3014- on_detect_location_changed (self);
3015-}
3016-
3017-/***
3018-**** Public API
3019-***/
3020-
3021-IndicatorDatetimeClock *
3022-indicator_datetime_clock_live_new (void)
3023-{
3024- gpointer o = g_object_new (INDICATOR_TYPE_DATETIME_CLOCK_LIVE, NULL);
3025-
3026- return INDICATOR_DATETIME_CLOCK (o);
3027-}
3028
3029=== added file 'src/clock-live.cpp'
3030--- src/clock-live.cpp 1970-01-01 00:00:00 +0000
3031+++ src/clock-live.cpp 2014-01-31 00:43:10 +0000
3032@@ -0,0 +1,163 @@
3033+/*
3034+ * Copyright 2013 Canonical Ltd.
3035+ *
3036+ * This program is free software: you can redistribute it and/or modify it
3037+ * under the terms of the GNU General Public License version 3, as published
3038+ * by the Free Software Foundation.
3039+ *
3040+ * This program is distributed in the hope that it will be useful, but
3041+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3042+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3043+ * PURPOSE. See the GNU General Public License for more details.
3044+ *
3045+ * You should have received a copy of the GNU General Public License along
3046+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3047+ *
3048+ * Authors:
3049+ * Charles Kerr <charles.kerr@canonical.com>
3050+ */
3051+
3052+#include <datetime/clock.h>
3053+#include <datetime/timezones.h>
3054+
3055+namespace unity {
3056+namespace indicator {
3057+namespace datetime {
3058+
3059+/***
3060+****
3061+***/
3062+
3063+namespace
3064+{
3065+
3066+void clearTimer(guint& tag)
3067+{
3068+ if (tag)
3069+ {
3070+ g_source_remove(tag);
3071+ tag = 0;
3072+ }
3073+}
3074+
3075+guint calculate_milliseconds_until_next_minute(const DateTime& now)
3076+{
3077+ auto next = g_date_time_add_minutes(now.get(), 1);
3078+ auto start_of_next = g_date_time_add_seconds (next, -g_date_time_get_seconds(next));
3079+ const auto interval_usec = g_date_time_difference(start_of_next, now.get());
3080+ const guint interval_msec = (interval_usec + 999) / 1000;
3081+ g_date_time_unref(start_of_next);
3082+ g_date_time_unref(next);
3083+ g_assert (interval_msec <= 60000);
3084+ return interval_msec;
3085+}
3086+
3087+} // unnamed namespace
3088+
3089+
3090+class LiveClock::Impl
3091+{
3092+public:
3093+
3094+ Impl(LiveClock& owner, const std::shared_ptr<const Timezones>& tzd):
3095+ m_owner(owner),
3096+ m_timezones(tzd)
3097+ {
3098+ if (m_timezones)
3099+ {
3100+ m_timezones->timezone.changed().connect([this](const std::string& z) {setTimezone(z);});
3101+ setTimezone(m_timezones->timezone.get());
3102+ }
3103+
3104+ restart_minute_timer();
3105+ }
3106+
3107+ ~Impl()
3108+ {
3109+ clearTimer(m_timer);
3110+
3111+ g_clear_pointer(&m_timezone, g_time_zone_unref);
3112+ }
3113+
3114+ DateTime localtime() const
3115+ {
3116+ g_assert(m_timezone != nullptr);
3117+
3118+ auto gdt = g_date_time_new_now(m_timezone);
3119+ DateTime ret(gdt);
3120+ g_date_time_unref(gdt);
3121+ return ret;
3122+ }
3123+
3124+private:
3125+
3126+ void setTimezone(const std::string& str)
3127+ {
3128+ g_clear_pointer(&m_timezone, g_time_zone_unref);
3129+ m_timezone = g_time_zone_new(str.c_str());
3130+ m_owner.minute_changed();
3131+ }
3132+
3133+ /***
3134+ ****
3135+ ***/
3136+
3137+ void restart_minute_timer()
3138+ {
3139+ clearTimer(m_timer);
3140+
3141+ // maybe emit change signals
3142+ const auto now = localtime();
3143+ if (!DateTime::is_same_minute(m_prev_datetime, now))
3144+ m_owner.minute_changed();
3145+ if (!DateTime::is_same_day(m_prev_datetime, now))
3146+ m_owner.date_changed();
3147+
3148+ // queue up a timer to fire at the next minute
3149+ m_prev_datetime = now;
3150+ auto interval_msec = calculate_milliseconds_until_next_minute(now);
3151+ interval_msec += 50; // add a small margin to ensure the callback
3152+ // fires /after/ next is reached
3153+ m_timer = g_timeout_add_full(G_PRIORITY_HIGH,
3154+ interval_msec,
3155+ on_minute_timer_reached,
3156+ this,
3157+ nullptr);
3158+ }
3159+
3160+ static gboolean on_minute_timer_reached(gpointer gself)
3161+ {
3162+ static_cast<LiveClock::Impl*>(gself)->restart_minute_timer();
3163+ return G_SOURCE_REMOVE;
3164+ }
3165+
3166+protected:
3167+
3168+ LiveClock& m_owner;
3169+ GTimeZone* m_timezone = nullptr;
3170+ std::shared_ptr<const Timezones> m_timezones;
3171+
3172+ DateTime m_prev_datetime;
3173+ unsigned int m_timer = 0;
3174+};
3175+
3176+LiveClock::LiveClock(const std::shared_ptr<const Timezones>& tzd):
3177+ p(new Impl(*this, tzd))
3178+{
3179+}
3180+
3181+LiveClock::~LiveClock() =default;
3182+
3183+DateTime LiveClock::localtime() const
3184+{
3185+ return p->localtime();
3186+}
3187+
3188+/***
3189+****
3190+***/
3191+
3192+} // namespace datetime
3193+} // namespace indicator
3194+} // namespace unity
3195+
3196
3197=== removed file 'src/clock-live.h'
3198--- src/clock-live.h 2013-10-17 21:32:44 +0000
3199+++ src/clock-live.h 1970-01-01 00:00:00 +0000
3200@@ -1,73 +0,0 @@
3201-/*
3202- * Copyright 2013 Canonical Ltd.
3203- *
3204- * Authors:
3205- * Charles Kerr <charles.kerr@canonical.com>
3206- *
3207- * This program is free software: you can redistribute it and/or modify it
3208- * under the terms of the GNU General Public License version 3, as published
3209- * by the Free Software Foundation.
3210- *
3211- * This program is distributed in the hope that it will be useful, but
3212- * WITHOUT ANY WARRANTY; without even the implied warranties of
3213- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3214- * PURPOSE. See the GNU General Public License for more details.
3215- *
3216- * You should have received a copy of the GNU General Public License along
3217- * with this program. If not, see <http://www.gnu.org/licenses/>.
3218- */
3219-
3220-#ifndef __INDICATOR_DATETIME_CLOCK_LIVE__H__
3221-#define __INDICATOR_DATETIME_CLOCK_LIVE__H__
3222-
3223-#include <glib-object.h> /* parent class */
3224-
3225-#include "clock.h"
3226-
3227-G_BEGIN_DECLS
3228-
3229-#define INDICATOR_TYPE_DATETIME_CLOCK_LIVE \
3230- (indicator_datetime_clock_live_get_type())
3231-
3232-#define INDICATOR_DATETIME_CLOCK_LIVE(o) \
3233- (G_TYPE_CHECK_INSTANCE_CAST ((o), \
3234- INDICATOR_TYPE_DATETIME_CLOCK_LIVE, \
3235- IndicatorDatetimeClockLive))
3236-
3237-#define INDICATOR_DATETIME_CLOCK_LIVE_GET_CLASS(o) \
3238- (G_TYPE_INSTANCE_GET_CLASS ((o), \
3239- INDICATOR_TYPE_DATETIME_CLOCK_LIVE, \
3240- IndicatorDatetimeClockLiveClass))
3241-
3242-#define INDICATOR_IS_DATETIME_CLOCK_LIVE(o) \
3243- (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
3244- INDICATOR_TYPE_DATETIME_CLOCK_LIVE))
3245-
3246-typedef struct _IndicatorDatetimeClockLive
3247- IndicatorDatetimeClockLive;
3248-typedef struct _IndicatorDatetimeClockLivePriv
3249- IndicatorDatetimeClockLivePriv;
3250-typedef struct _IndicatorDatetimeClockLiveClass
3251- IndicatorDatetimeClockLiveClass;
3252-
3253-/**
3254- * An IndicatorDatetimeClock which gives live clock times
3255- * from timezones determined by geoclue and /etc/timezone
3256- */
3257-struct _IndicatorDatetimeClockLive
3258-{
3259- GObject parent_instance;
3260-
3261- IndicatorDatetimeClockLivePriv * priv;
3262-};
3263-
3264-struct _IndicatorDatetimeClockLiveClass
3265-{
3266- GObjectClass parent_class;
3267-};
3268-
3269-IndicatorDatetimeClock * indicator_datetime_clock_live_new (void);
3270-
3271-G_END_DECLS
3272-
3273-#endif /* __INDICATOR_DATETIME_CLOCK_LIVE__H__ */
3274
3275=== removed file 'src/clock.c'
3276--- src/clock.c 2013-10-24 21:47:08 +0000
3277+++ src/clock.c 1970-01-01 00:00:00 +0000
3278@@ -1,110 +0,0 @@
3279-/*
3280- * Copyright 2013 Canonical Ltd.
3281- *
3282- * Authors:
3283- * Charles Kerr <charles.kerr@canonical.com>
3284- *
3285- * This program is free software: you can redistribute it and/or modify it
3286- * under the terms of the GNU General Public License version 3, as published
3287- * by the Free Software Foundation.
3288- *
3289- * This program is distributed in the hope that it will be useful, but
3290- * WITHOUT ANY WARRANTY; without even the implied warranties of
3291- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3292- * PURPOSE. See the GNU General Public License for more details.
3293- *
3294- * You should have received a copy of the GNU General Public License along
3295- * with this program. If not, see <http://www.gnu.org/licenses/>.
3296- */
3297-
3298-#include "clock.h"
3299-
3300-enum
3301-{
3302- SIGNAL_CHANGED,
3303- SIGNAL_LAST
3304-};
3305-
3306-static guint signals[SIGNAL_LAST] = { 0 };
3307-
3308-G_DEFINE_INTERFACE (IndicatorDatetimeClock,
3309- indicator_datetime_clock,
3310- G_TYPE_OBJECT);
3311-
3312-static void
3313-indicator_datetime_clock_default_init (IndicatorDatetimeClockInterface * klass)
3314-{
3315- signals[SIGNAL_CHANGED] = g_signal_new (
3316- "changed",
3317- G_TYPE_FROM_CLASS(klass),
3318- G_SIGNAL_RUN_LAST,
3319- G_STRUCT_OFFSET (IndicatorDatetimeClockInterface, changed),
3320- NULL, NULL,
3321- g_cclosure_marshal_VOID__VOID,
3322- G_TYPE_NONE, 0);
3323-}
3324-
3325-/***
3326-**** PUBLIC API
3327-***/
3328-
3329-/**
3330- * Get a strv of timezones.
3331- *
3332- * Return value: (element-type char*)
3333- * (transfer full):
3334- * array of timezone strings
3335- */
3336-const gchar **
3337-indicator_datetime_clock_get_timezones (IndicatorDatetimeClock * self)
3338-{
3339- const gchar ** timezones;
3340- IndicatorDatetimeClockInterface * iface;
3341-
3342- g_return_val_if_fail (INDICATOR_IS_DATETIME_CLOCK(self), NULL);
3343- iface = INDICATOR_DATETIME_CLOCK_GET_INTERFACE(self);
3344-
3345- if (iface->get_timezones != NULL)
3346- timezones = iface->get_timezones (self);
3347- else
3348- timezones = NULL;
3349-
3350- return timezones;
3351-}
3352-
3353-/**
3354- * Get the current time.
3355- *
3356- * Return value: (element-type GDateTime*)
3357- * (transfer full):
3358- * the current time.
3359- */
3360-GDateTime *
3361-indicator_datetime_clock_get_localtime (IndicatorDatetimeClock * self)
3362-{
3363- GDateTime * now;
3364- IndicatorDatetimeClockInterface * iface;
3365-
3366- g_return_val_if_fail (INDICATOR_IS_DATETIME_CLOCK(self), NULL);
3367- iface = INDICATOR_DATETIME_CLOCK_GET_INTERFACE(self);
3368-
3369- if (iface->get_localtime != NULL)
3370- now = iface->get_localtime (self);
3371- else
3372- now = NULL;
3373-
3374- return now;
3375-}
3376-
3377-/**
3378- * Emits the "changed" signal.
3379- *
3380- * This should only be called by subclasses.
3381- */
3382-void
3383-indicator_datetime_clock_emit_changed (IndicatorDatetimeClock * self)
3384-{
3385- g_return_if_fail (INDICATOR_IS_DATETIME_CLOCK (self));
3386-
3387- g_signal_emit (self, signals[SIGNAL_CHANGED], 0, NULL);
3388-}
3389
3390=== added file 'src/clock.cpp'
3391--- src/clock.cpp 1970-01-01 00:00:00 +0000
3392+++ src/clock.cpp 2014-01-31 00:43:10 +0000
3393@@ -0,0 +1,93 @@
3394+/*
3395+ * Copyright 2013 Canonical Ltd.
3396+ *
3397+ * This program is free software: you can redistribute it and/or modify it
3398+ * under the terms of the GNU General Public License version 3, as published
3399+ * by the Free Software Foundation.
3400+ *
3401+ * This program is distributed in the hope that it will be useful, but
3402+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3403+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3404+ * PURPOSE. See the GNU General Public License for more details.
3405+ *
3406+ * You should have received a copy of the GNU General Public License along
3407+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3408+ *
3409+ * Authors:
3410+ * Charles Kerr <charles.kerr@canonical.com>
3411+ */
3412+
3413+#include <datetime/clock.h>
3414+
3415+#include <glib.h>
3416+#include <gio/gio.h>
3417+
3418+namespace unity {
3419+namespace indicator {
3420+namespace datetime {
3421+
3422+/***
3423+****
3424+***/
3425+
3426+Clock::Clock():
3427+ m_cancellable(g_cancellable_new())
3428+{
3429+ g_bus_get(G_BUS_TYPE_SYSTEM, m_cancellable, on_system_bus_ready, this);
3430+}
3431+
3432+Clock::~Clock()
3433+{
3434+ g_cancellable_cancel(m_cancellable);
3435+ g_clear_object(&m_cancellable);
3436+
3437+ if (m_sleep_subscription_id)
3438+ g_dbus_connection_signal_unsubscribe(m_system_bus, m_sleep_subscription_id);
3439+
3440+ g_clear_object(&m_system_bus);
3441+}
3442+
3443+void
3444+Clock::on_system_bus_ready(GObject*, GAsyncResult * res, gpointer gself)
3445+{
3446+ GDBusConnection * system_bus;
3447+
3448+ if ((system_bus = g_bus_get_finish(res, nullptr)))
3449+ {
3450+ auto self = static_cast<Clock*>(gself);
3451+
3452+ self->m_system_bus = system_bus;
3453+
3454+ self->m_sleep_subscription_id = g_dbus_connection_signal_subscribe(
3455+ system_bus,
3456+ nullptr,
3457+ "org.freedesktop.login1.Manager", // interface
3458+ "PrepareForSleep", // signal name
3459+ "/org/freedesktop/login1", // object path
3460+ nullptr, // arg0
3461+ G_DBUS_SIGNAL_FLAGS_NONE,
3462+ on_prepare_for_sleep,
3463+ self,
3464+ nullptr);
3465+ }
3466+}
3467+
3468+void
3469+Clock::on_prepare_for_sleep(GDBusConnection* /*connection*/,
3470+ const gchar* /*sender_name*/,
3471+ const gchar* /*object_path*/,
3472+ const gchar* /*interface_name*/,
3473+ const gchar* /*signal_name*/,
3474+ GVariant* /*parameters*/,
3475+ gpointer gself)
3476+{
3477+ static_cast<Clock*>(gself)->minute_changed();
3478+}
3479+
3480+/***
3481+****
3482+***/
3483+
3484+} // namespace datetime
3485+} // namespace indicator
3486+} // namespace unity
3487
3488=== removed file 'src/clock.h'
3489--- src/clock.h 2013-10-17 23:15:33 +0000
3490+++ src/clock.h 1970-01-01 00:00:00 +0000
3491@@ -1,76 +0,0 @@
3492-/*
3493- * Copyright 2013 Canonical Ltd.
3494- *
3495- * Authors:
3496- * Charles Kerr <charles.kerr@canonical.com>
3497- *
3498- * This program is free software: you can redistribute it and/or modify it
3499- * under the terms of the GNU General Public License version 3, as published
3500- * by the Free Software Foundation.
3501- *
3502- * This program is distributed in the hope that it will be useful, but
3503- * WITHOUT ANY WARRANTY; without even the implied warranties of
3504- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3505- * PURPOSE. See the GNU General Public License for more details.
3506- *
3507- * You should have received a copy of the GNU General Public License along
3508- * with this program. If not, see <http://www.gnu.org/licenses/>.
3509- */
3510-
3511-#ifndef __INDICATOR_DATETIME_CLOCK__H__
3512-#define __INDICATOR_DATETIME_CLOCK__H__
3513-
3514-#include <glib-object.h>
3515-
3516-G_BEGIN_DECLS
3517-
3518-#define INDICATOR_TYPE_DATETIME_CLOCK \
3519- (indicator_datetime_clock_get_type ())
3520-
3521-#define INDICATOR_DATETIME_CLOCK(obj) \
3522- (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
3523- INDICATOR_TYPE_DATETIME_CLOCK, \
3524- IndicatorDatetimeClock))
3525-
3526-#define INDICATOR_IS_DATETIME_CLOCK(obj) \
3527- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_TYPE_DATETIME_CLOCK))
3528-
3529-#define INDICATOR_DATETIME_CLOCK_GET_INTERFACE(inst) \
3530- (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
3531- INDICATOR_TYPE_DATETIME_CLOCK, \
3532- IndicatorDatetimeClockInterface))
3533-
3534-typedef struct _IndicatorDatetimeClock
3535- IndicatorDatetimeClock;
3536-
3537-typedef struct _IndicatorDatetimeClockInterface
3538- IndicatorDatetimeClockInterface;
3539-
3540-struct _IndicatorDatetimeClockInterface
3541-{
3542- GTypeInterface parent_iface;
3543-
3544- /* signals */
3545- void (*changed) (IndicatorDatetimeClock * self);
3546-
3547- /* virtual functions */
3548- const gchar** (*get_timezones) (IndicatorDatetimeClock * self);
3549- GDateTime* (*get_localtime) (IndicatorDatetimeClock * self);
3550-};
3551-
3552-GType indicator_datetime_clock_get_type (void);
3553-
3554-/***
3555-****
3556-***/
3557-
3558-const gchar ** indicator_datetime_clock_get_timezones (IndicatorDatetimeClock * clock);
3559-
3560-GDateTime * indicator_datetime_clock_get_localtime (IndicatorDatetimeClock * clock);
3561-
3562-void indicator_datetime_clock_emit_changed (IndicatorDatetimeClock * clock);
3563-
3564-
3565-G_END_DECLS
3566-
3567-#endif /* __INDICATOR_DATETIME_CLOCK__H__ */
3568
3569=== added file 'src/date-time.cpp'
3570--- src/date-time.cpp 1970-01-01 00:00:00 +0000
3571+++ src/date-time.cpp 2014-01-31 00:43:10 +0000
3572@@ -0,0 +1,159 @@
3573+/*
3574+ * Copyright 2013 Canonical Ltd.
3575+ *
3576+ * This program is free software: you can redistribute it and/or modify it
3577+ * under the terms of the GNU General Public License version 3, as published
3578+ * by the Free Software Foundation.
3579+ *
3580+ * This program is distributed in the hope that it will be useful, but
3581+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3582+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3583+ * PURPOSE. See the GNU General Public License for more details.
3584+ *
3585+ * You should have received a copy of the GNU General Public License along
3586+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3587+ *
3588+ * Authors:
3589+ * Charles Kerr <charles.kerr@canonical.com>
3590+ */
3591+
3592+#include <datetime/date-time.h>
3593+
3594+namespace unity {
3595+namespace indicator {
3596+namespace datetime {
3597+
3598+/***
3599+****
3600+***/
3601+
3602+DateTime::DateTime(GDateTime* gdt)
3603+{
3604+ reset(gdt);
3605+}
3606+
3607+DateTime& DateTime::operator=(GDateTime* gdt)
3608+{
3609+ reset(gdt);
3610+ return *this;
3611+}
3612+
3613+DateTime& DateTime::operator=(const DateTime& that)
3614+{
3615+ m_dt = that.m_dt;
3616+ return *this;
3617+}
3618+
3619+DateTime::DateTime(time_t t)
3620+{
3621+ GDateTime * gdt = g_date_time_new_from_unix_local(t);
3622+ reset(gdt);
3623+ g_date_time_unref(gdt);
3624+}
3625+
3626+DateTime DateTime::NowLocal()
3627+{
3628+ GDateTime * gdt = g_date_time_new_now_local();
3629+ DateTime dt(gdt);
3630+ g_date_time_unref(gdt);
3631+ return dt;
3632+}
3633+
3634+DateTime DateTime::to_timezone(const std::string& zone) const
3635+{
3636+ auto gtz = g_time_zone_new(zone.c_str());
3637+ auto gdt = g_date_time_to_timezone(get(), gtz);
3638+ DateTime dt(gdt);
3639+ g_time_zone_unref(gtz);
3640+ g_date_time_unref(gdt);
3641+ return dt;
3642+}
3643+
3644+GDateTime* DateTime::get() const
3645+{
3646+ g_assert(m_dt);
3647+ return m_dt.get();
3648+}
3649+
3650+std::string DateTime::format(const std::string& fmt) const
3651+{
3652+ const auto str = g_date_time_format(get(), fmt.c_str());
3653+ std::string ret = str;
3654+ g_free(str);
3655+ return ret;
3656+}
3657+
3658+int DateTime::day_of_month() const
3659+{
3660+ return g_date_time_get_day_of_month(get());
3661+}
3662+
3663+int64_t DateTime::to_unix() const
3664+{
3665+ return g_date_time_to_unix(get());
3666+}
3667+
3668+void DateTime::reset(GDateTime* in)
3669+{
3670+ if (in)
3671+ {
3672+ auto deleter = [](GDateTime* dt){g_date_time_unref(dt);};
3673+ m_dt = std::shared_ptr<GDateTime>(g_date_time_ref(in), deleter);
3674+ g_assert(m_dt);
3675+ }
3676+ else
3677+ {
3678+ m_dt.reset();
3679+ }
3680+}
3681+
3682+bool DateTime::operator<(const DateTime& that) const
3683+{
3684+ return g_date_time_compare(get(), that.get()) < 0;
3685+}
3686+
3687+bool DateTime::operator!=(const DateTime& that) const
3688+{
3689+ // return true if this isn't set, or if it's not equal
3690+ return (!m_dt) || !(*this == that);
3691+}
3692+
3693+bool DateTime::operator==(const DateTime& that) const
3694+{
3695+ auto dt = get();
3696+ auto tdt = that.get();
3697+ if (!dt && !tdt) return true;
3698+ if (!dt || !tdt) return false;
3699+ return g_date_time_compare(get(), that.get()) == 0;
3700+}
3701+
3702+bool DateTime::is_same_day(const DateTime& a, const DateTime& b)
3703+{
3704+ // it's meaningless to compare uninitialized dates
3705+ if (!a.m_dt || !b.m_dt)
3706+ return false;
3707+
3708+ const auto adt = a.get();
3709+ const auto bdt = b.get();
3710+ return (g_date_time_get_year(adt) == g_date_time_get_year(bdt))
3711+ && (g_date_time_get_day_of_year(adt) == g_date_time_get_day_of_year(bdt));
3712+}
3713+
3714+bool DateTime::is_same_minute(const DateTime& a, const DateTime& b)
3715+{
3716+ if (!is_same_day(a,b))
3717+ return false;
3718+
3719+ const auto adt = a.get();
3720+ const auto bdt = b.get();
3721+ return (g_date_time_get_hour(adt) == g_date_time_get_hour(bdt))
3722+ && (g_date_time_get_minute(adt) == g_date_time_get_minute(bdt));
3723+}
3724+
3725+/***
3726+****
3727+***/
3728+
3729+} // namespace datetime
3730+} // namespace indicator
3731+} // namespace unity
3732
3733=== removed file 'src/dbus-shared.h'
3734--- src/dbus-shared.h 2013-06-19 06:26:32 +0000
3735+++ src/dbus-shared.h 1970-01-01 00:00:00 +0000
3736@@ -1,24 +0,0 @@
3737-/*
3738-An indicator to show date and time information.
3739-
3740-Copyright 2010 Canonical Ltd.
3741-
3742-Authors:
3743- Ted Gould <ted@canonical.com>
3744-
3745-This program is free software: you can redistribute it and/or modify it
3746-under the terms of the GNU General Public License version 3, as published
3747-by the Free Software Foundation.
3748-
3749-This program is distributed in the hope that it will be useful, but
3750-WITHOUT ANY WARRANTY; without even the implied warranties of
3751-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3752-PURPOSE. See the GNU General Public License for more details.
3753-
3754-You should have received a copy of the GNU General Public License along
3755-with this program. If not, see <http://www.gnu.org/licenses/>.
3756-*/
3757-
3758-#define BUS_NAME "com.canonical.indicator.datetime"
3759-#define BUS_PATH "/com/canonical/indicator/datetime"
3760-
3761
3762=== added file 'src/exporter.cpp'
3763--- src/exporter.cpp 1970-01-01 00:00:00 +0000
3764+++ src/exporter.cpp 2014-01-31 00:43:10 +0000
3765@@ -0,0 +1,145 @@
3766+/*
3767+ * Copyright 2013 Canonical Ltd.
3768+ *
3769+ * This program is free software: you can redistribute it and/or modify it
3770+ * under the terms of the GNU General Public License version 3, as published
3771+ * by the Free Software Foundation.
3772+ *
3773+ * This program is distributed in the hope that it will be useful, but
3774+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3775+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3776+ * PURPOSE. See the GNU General Public License for more details.
3777+ *
3778+ * You should have received a copy of the GNU General Public License along
3779+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3780+ *
3781+ * Authors:
3782+ * Charles Kerr <charles.kerr@canonical.com>
3783+ */
3784+
3785+#include <datetime/dbus-shared.h>
3786+#include <datetime/exporter.h>
3787+
3788+#include <glib/gi18n.h>
3789+#include <gio/gio.h>
3790+
3791+namespace unity {
3792+namespace indicator {
3793+namespace datetime {
3794+
3795+/***
3796+****
3797+***/
3798+
3799+Exporter::~Exporter()
3800+{
3801+ if (m_dbus_connection != nullptr)
3802+ {
3803+ for(auto& id : m_exported_menu_ids)
3804+ g_dbus_connection_unexport_menu_model(m_dbus_connection, id);
3805+
3806+ if (m_exported_actions_id)
3807+ g_dbus_connection_unexport_action_group(m_dbus_connection, m_exported_actions_id);
3808+ }
3809+
3810+ if (m_own_id)
3811+ g_bus_unown_name(m_own_id);
3812+
3813+ g_clear_object(&m_dbus_connection);
3814+}
3815+
3816+/***
3817+****
3818+***/
3819+
3820+void
3821+Exporter::on_bus_acquired(GDBusConnection* connection, const gchar* name, gpointer gthis)
3822+{
3823+ g_debug("bus acquired: %s", name);
3824+ static_cast<Exporter*>(gthis)->on_bus_acquired(connection, name);
3825+}
3826+
3827+void
3828+Exporter::on_bus_acquired(GDBusConnection* connection, const gchar* /*name*/)
3829+{
3830+ m_dbus_connection = static_cast<GDBusConnection*>(g_object_ref(G_OBJECT(connection)));
3831+
3832+ // export the actions
3833+ GError * error = nullptr;
3834+ const auto id = g_dbus_connection_export_action_group(m_dbus_connection,
3835+ BUS_PATH,
3836+ m_actions->action_group(),
3837+ &error);
3838+ if (id)
3839+ {
3840+ m_exported_actions_id = id;
3841+ }
3842+ else
3843+ {
3844+ g_warning("cannot export action group: %s", error->message);
3845+ g_clear_error(&error);
3846+ }
3847+
3848+ // export the menus
3849+ for(auto& menu : m_menus)
3850+ {
3851+ const auto path = std::string(BUS_PATH) + "/" + menu->name();
3852+ const auto id = g_dbus_connection_export_menu_model(m_dbus_connection, path.c_str(), menu->menu_model(), &error);
3853+ if (id)
3854+ {
3855+ m_exported_menu_ids.insert(id);
3856+ }
3857+ else
3858+ {
3859+ if (error != nullptr)
3860+ g_warning("cannot export %s menu: %s", menu->name().c_str(), error->message);
3861+ g_clear_error(&error);
3862+ }
3863+ }
3864+}
3865+
3866+/***
3867+****
3868+***/
3869+
3870+void
3871+Exporter::on_name_lost(GDBusConnection* connection, const gchar* name, gpointer gthis)
3872+{
3873+ g_debug("name lost: %s", name);
3874+ static_cast<Exporter*>(gthis)->on_name_lost(connection, name);
3875+}
3876+
3877+void
3878+Exporter::on_name_lost(GDBusConnection* /*connection*/, const gchar* /*name*/)
3879+{
3880+ name_lost();
3881+}
3882+
3883+/***
3884+****
3885+***/
3886+
3887+void
3888+Exporter::publish(const std::shared_ptr<Actions>& actions,
3889+ const std::vector<std::shared_ptr<Menu>>& menus)
3890+{
3891+ m_actions = actions;
3892+ m_menus = menus;
3893+ m_own_id = g_bus_own_name(G_BUS_TYPE_SESSION,
3894+ BUS_NAME,
3895+ G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
3896+ on_bus_acquired,
3897+ nullptr,
3898+ on_name_lost,
3899+ this,
3900+ nullptr);
3901+}
3902+
3903+/***
3904+****
3905+***/
3906+
3907+} // namespace datetime
3908+} // namespace indicator
3909+} // namespace unity
3910+
3911
3912=== added file 'src/formatter-desktop.cpp'
3913--- src/formatter-desktop.cpp 1970-01-01 00:00:00 +0000
3914+++ src/formatter-desktop.cpp 2014-01-31 00:43:10 +0000
3915@@ -0,0 +1,169 @@
3916+/*
3917+ * Copyright 2013 Canonical Ltd.
3918+ *
3919+ * This program is free software: you can redistribute it and/or modify it
3920+ * under the terms of the GNU General Public License version 3, as published
3921+ * by the Free Software Foundation.
3922+ *
3923+ * This program is distributed in the hope that it will be useful, but
3924+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3925+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3926+ * PURPOSE. See the GNU General Public License for more details.
3927+ *
3928+ * You should have received a copy of the GNU General Public License along
3929+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3930+ *
3931+ * Authors:
3932+ * Charles Kerr <charles.kerr@canonical.com>
3933+ */
3934+
3935+#include <datetime/formatter.h>
3936+#include <datetime/utils.h> // T_()
3937+
3938+namespace unity {
3939+namespace indicator {
3940+namespace datetime {
3941+
3942+/***
3943+****
3944+***/
3945+
3946+namespace
3947+{
3948+
3949+std::string joinDateAndTimeFormatStrings(const char* date_string,
3950+ const char* time_string)
3951+{
3952+ std::string str;
3953+
3954+ if (date_string && time_string)
3955+ {
3956+ /* TRANSLATORS: This is a format string passed to strftime to
3957+ * combine the date and the time. The value of "%s\u2003%s"
3958+ * will result in a string like this in US English 12-hour time:
3959+ * 'Fri Jul 16 11:50 AM'. The space in between date and time is
3960+ * a Unicode en space (E28082 in UTF-8 hex). */
3961+ str = date_string;
3962+ str += "\u2003";
3963+ str += time_string;
3964+ }
3965+ else if (date_string)
3966+ {
3967+ str = date_string;
3968+ }
3969+ else // time_string
3970+ {
3971+ str = time_string;
3972+ }
3973+
3974+ return str;
3975+}
3976+} // unnamed namespace
3977+
3978+/***
3979+****
3980+***/
3981+
3982+DesktopFormatter::DesktopFormatter(const std::shared_ptr<const Clock>& clock_in,
3983+ const std::shared_ptr<const Settings>& settings_in):
3984+ Formatter(clock_in),
3985+ m_settings(settings_in)
3986+{
3987+ m_settings->show_day.changed().connect([this](bool){rebuildHeaderFormat();});
3988+ m_settings->show_date.changed().connect([this](bool){rebuildHeaderFormat();});
3989+ m_settings->show_year.changed().connect([this](bool){rebuildHeaderFormat();});
3990+ m_settings->show_seconds.changed().connect([this](bool){rebuildHeaderFormat();});
3991+ m_settings->time_format_mode.changed().connect([this](TimeFormatMode){rebuildHeaderFormat();});
3992+ m_settings->custom_time_format.changed().connect([this](const std::string&){rebuildHeaderFormat();});
3993+
3994+ rebuildHeaderFormat();
3995+}
3996+
3997+void DesktopFormatter::rebuildHeaderFormat()
3998+{
3999+ header_format.set(getHeaderLabelFormatString());
4000+}
4001+
4002+std::string DesktopFormatter::getHeaderLabelFormatString() const
4003+{
4004+ std::string fmt;
4005+ const auto mode = m_settings->time_format_mode.get();
4006+
4007+ if (mode == TIME_FORMAT_MODE_CUSTOM)
4008+ {
4009+ fmt = m_settings->custom_time_format.get();
4010+ }
4011+ else
4012+ {
4013+ const auto show_day = m_settings->show_day.get();
4014+ const auto show_date = m_settings->show_date.get();
4015+ const auto show_year = show_date && m_settings->show_year.get();
4016+ const auto date_fmt = getDateFormat(show_day, show_date, show_year);
4017+ const auto time_fmt = getFullTimeFormatString();
4018+ fmt = joinDateAndTimeFormatStrings(date_fmt, time_fmt);
4019+ }
4020+
4021+ return fmt;
4022+}
4023+
4024+const gchar* DesktopFormatter::getFullTimeFormatString() const
4025+{
4026+ const auto show_seconds = m_settings->show_seconds.get();
4027+
4028+ bool twelvehour;
4029+ switch (m_settings->time_format_mode.get())
4030+ {
4031+ case TIME_FORMAT_MODE_LOCALE_DEFAULT:
4032+ twelvehour = is_locale_12h();
4033+ break;
4034+
4035+ case TIME_FORMAT_MODE_24_HOUR:
4036+ twelvehour = false;
4037+ break;
4038+
4039+ default:
4040+ twelvehour = true;
4041+ break;
4042+ }
4043+
4044+ return default_header_time_format(twelvehour, show_seconds);
4045+}
4046+
4047+const gchar* DesktopFormatter::getDateFormat(bool show_day, bool show_date, bool show_year) const
4048+{
4049+ const char * fmt;
4050+
4051+ if (show_day && show_date && show_year)
4052+ /* TRANSLATORS: a strftime(3) format showing the weekday, date, and year */
4053+ fmt = T_("%a %b %e %Y");
4054+ else if (show_day && show_date)
4055+ /* TRANSLATORS: a strftime(3) format showing the weekday and date */
4056+ fmt = T_("%a %b %e");
4057+ else if (show_day && show_year)
4058+ /* TRANSLATORS: a strftime(3) format showing the weekday and year. */
4059+ fmt = T_("%a %Y");
4060+ else if (show_day)
4061+ /* TRANSLATORS: a strftime(3) format showing the weekday. */
4062+ fmt = T_("%a");
4063+ else if (show_date && show_year)
4064+ /* TRANSLATORS: a strftime(3) format showing the date and year */
4065+ fmt = T_("%b %e %Y");
4066+ else if (show_date)
4067+ /* TRANSLATORS: a strftime(3) format showing the date */
4068+ fmt = T_("%b %e");
4069+ else if (show_year)
4070+ /* TRANSLATORS: a strftime(3) format showing the year */
4071+ fmt = T_("%Y");
4072+ else
4073+ fmt = nullptr;
4074+
4075+ return fmt;
4076+}
4077+
4078+/***
4079+****
4080+***/
4081+
4082+} // namespace datetime
4083+} // namespace indicator
4084+} // namespace unity
4085
4086=== added file 'src/formatter.cpp'
4087--- src/formatter.cpp 1970-01-01 00:00:00 +0000
4088+++ src/formatter.cpp 2014-01-31 00:43:10 +0000
4089@@ -0,0 +1,267 @@
4090+/*
4091+ * Copyright 2013 Canonical Ltd.
4092+ *
4093+ * This program is free software: you can redistribute it and/or modify it
4094+ * under the terms of the GNU General Public License version 3, as published
4095+ * by the Free Software Foundation.
4096+ *
4097+ * This program is distributed in the hope that it will be useful, but
4098+ * WITHOUT ANY WARRANTY; without even the implied warranties of
4099+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4100+ * PURPOSE. See the GNU General Public License for more details.
4101+ *
4102+ * You should have received a copy of the GNU General Public License along
4103+ * with this program. If not, see <http://www.gnu.org/licenses/>.
4104+ *
4105+ * Authors:
4106+ * Charles Kerr <charles.kerr@canonical.com>
4107+ */
4108+
4109+#include <datetime/formatter.h>
4110+
4111+#include <datetime/clock.h>
4112+#include <datetime/utils.h> // T_()
4113+
4114+#include <glib.h>
4115+#include <glib/gi18n.h>
4116+
4117+#include <locale.h> // setlocale()
4118+#include <langinfo.h> // nl_langinfo()
4119+#include <string.h> // strstr()
4120+
4121+namespace unity {
4122+namespace indicator {
4123+namespace datetime {
4124+
4125+/***
4126+****
4127+***/
4128+
4129+namespace
4130+{
4131+
4132+void clear_timer(guint& tag)
4133+{
4134+ if (tag)
4135+ {
4136+ g_source_remove(tag);
4137+ tag = 0;
4138+ }
4139+}
4140+
4141+gint calculate_milliseconds_until_next_second(const DateTime& now)
4142+{
4143+ gint interval_usec;
4144+ guint interval_msec;
4145+
4146+ interval_usec = G_USEC_PER_SEC - g_date_time_get_microsecond(now.get());
4147+ interval_msec = (interval_usec + 999) / 1000;
4148+ return interval_msec;
4149+}
4150+
4151+/*
4152+ * We periodically rebuild the sections that have time format strings
4153+ * that are dependent on the current time:
4154+ *
4155+ * 1. appointment menuitems' time format strings depend on the
4156+ * current time; for example, they don't show the day of week
4157+ * if the appointment is today.
4158+ *
4159+ * 2. location menuitems' time format strings depend on the
4160+ * current time; for example, they don't show the day of the week
4161+ * if the local date and location date are the same.
4162+ *
4163+ * 3. the "local date" menuitem in the calendar section is,
4164+ * obviously, dependent on the local time.
4165+ *
4166+ * In short, we want to update whenever the number of days between two zone
4167+ * might have changed. We do that by updating when either zone's day changes.
4168+ *
4169+ * Since not all UTC offsets are evenly divisible by hours
4170+ * (examples: Newfoundland UTC-03:30, Nepal UTC+05:45), refreshing on the hour
4171+ * is not enough. We need to refresh at HH:00, HH:15, HH:30, and HH:45.
4172+ */
4173+guint calculate_seconds_until_next_fifteen_minutes(GDateTime * now)
4174+{
4175+ char * str;
4176+ gint minute;
4177+ guint seconds;
4178+ GTimeSpan diff;
4179+ GDateTime * next;
4180+ GDateTime * start_of_next;
4181+
4182+ minute = g_date_time_get_minute(now);
4183+ minute = 15 - (minute % 15);
4184+ next = g_date_time_add_minutes(now, minute);
4185+ start_of_next = g_date_time_new_local(g_date_time_get_year(next),
4186+ g_date_time_get_month(next),
4187+ g_date_time_get_day_of_month(next),
4188+ g_date_time_get_hour(next),
4189+ g_date_time_get_minute(next),
4190+ 0.1);
4191+
4192+ str = g_date_time_format(start_of_next, "%F %T");
4193+ g_debug("%s %s the next timestamp rebuild will be at %s", G_STRLOC, G_STRFUNC, str);
4194+ g_free(str);
4195+
4196+ diff = g_date_time_difference(start_of_next, now);
4197+ seconds = (diff + (G_TIME_SPAN_SECOND-1)) / G_TIME_SPAN_SECOND;
4198+
4199+ g_date_time_unref(start_of_next);
4200+ g_date_time_unref(next);
4201+ return seconds;
4202+}
4203+} // unnamed namespace
4204+
4205+
4206+class Formatter::Impl
4207+{
4208+public:
4209+
4210+ Impl(Formatter* owner, const std::shared_ptr<const Clock>& clock):
4211+ m_owner(owner),
4212+ m_clock(clock)
4213+ {
4214+ m_owner->header_format.changed().connect([this](const std::string& /*fmt*/){update_header();});
4215+ m_clock->minute_changed.connect([this](){update_header();});
4216+ update_header();
4217+
4218+ restartRelativeTimer();
4219+ }
4220+
4221+ ~Impl()
4222+ {
4223+ clear_timer(m_header_seconds_timer);
4224+ clear_timer(m_relative_timer);
4225+ }
4226+
4227+private:
4228+
4229+ static bool format_shows_seconds(const std::string& fmt)
4230+ {
4231+ return (fmt.find("%s") != std::string::npos)
4232+ || (fmt.find("%S") != std::string::npos)
4233+ || (fmt.find("%T") != std::string::npos)
4234+ || (fmt.find("%X") != std::string::npos)
4235+ || (fmt.find("%c") != std::string::npos);
4236+ }
4237+
4238+ void update_header()
4239+ {
4240+ // update the header property
4241+ const auto fmt = m_owner->header_format.get();
4242+ const auto str = m_clock->localtime().format(fmt);
4243+ m_owner->header.set(str);
4244+
4245+ // if the header needs to show seconds, set a timer.
4246+ if (format_shows_seconds(fmt))
4247+ start_header_timer();
4248+ else
4249+ clear_timer(m_header_seconds_timer);
4250+ }
4251+
4252+ // we've got a header format that shows seconds,
4253+ // so we need to update it every second
4254+ void start_header_timer()
4255+ {
4256+ clear_timer(m_header_seconds_timer);
4257+
4258+ const auto now = m_clock->localtime();
4259+ auto interval_msec = calculate_milliseconds_until_next_second(now);
4260+ interval_msec += 50; // add a small margin to ensure the callback
4261+ // fires /after/ next is reached
4262+ m_header_seconds_timer = g_timeout_add_full(G_PRIORITY_HIGH,
4263+ interval_msec,
4264+ on_header_timer,
4265+ this,
4266+ nullptr);
4267+ }
4268+
4269+ static gboolean on_header_timer(gpointer gself)
4270+ {
4271+ static_cast<Formatter::Impl*>(gself)->update_header();
4272+ return G_SOURCE_REMOVE;
4273+ }
4274+
4275+private:
4276+
4277+ void restartRelativeTimer()
4278+ {
4279+ clear_timer(m_relative_timer);
4280+
4281+ const auto now = m_clock->localtime();
4282+ const auto seconds = calculate_seconds_until_next_fifteen_minutes(now.get());
4283+ m_relative_timer = g_timeout_add_seconds(seconds, onRelativeTimer, this);
4284+ }
4285+
4286+ static gboolean onRelativeTimer(gpointer gself)
4287+ {
4288+ auto self = static_cast<Formatter::Impl*>(gself);
4289+ self->m_owner->relative_format_changed();
4290+ self->restartRelativeTimer();
4291+ return G_SOURCE_REMOVE;
4292+ }
4293+
4294+private:
4295+ Formatter* const m_owner;
4296+ guint m_header_seconds_timer = 0;
4297+ guint m_relative_timer = 0;
4298+
4299+public:
4300+ std::shared_ptr<const Clock> m_clock;
4301+};
4302+
4303+/***
4304+****
4305+***/
4306+
4307+Formatter::Formatter(const std::shared_ptr<const Clock>& clock):
4308+ p(new Formatter::Impl(this, clock))
4309+{
4310+}
4311+
4312+Formatter::~Formatter()
4313+{
4314+}
4315+
4316+const char*
4317+Formatter::default_header_time_format(bool twelvehour, bool show_seconds)
4318+{
4319+ const char* fmt;
4320+
4321+ if (twelvehour && show_seconds)
4322+ /* TRANSLATORS: a strftime(3) format for 12hr time w/seconds */
4323+ fmt = T_("%l:%M:%S %p");
4324+ else if (twelvehour)
4325+ /* TRANSLATORS: a strftime(3) format for 12hr time */
4326+ fmt = T_("%l:%M %p");
4327+ else if (show_seconds)
4328+ /* TRANSLATORS: a strftime(3) format for 24hr time w/seconds */
4329+ fmt = T_("%H:%M:%S");
4330+ else
4331+ /* TRANSLATORS: a strftime(3) format for 24hr time */
4332+ fmt = T_("%H:%M");
4333+
4334+ return fmt;
4335+}
4336+
4337+/***
4338+****
4339+***/
4340+
4341+std::string
4342+Formatter::relative_format(GDateTime* then_begin, GDateTime* then_end) const
4343+{
4344+ auto cstr = generate_full_format_string_at_time (p->m_clock->localtime().get(), then_begin, then_end);
4345+ const std::string ret = cstr;
4346+ g_free (cstr);
4347+ return ret;
4348+}
4349+
4350+/***
4351+****
4352+***/
4353+
4354+} // namespace datetime
4355+} // namespace indicator
4356+} // namespace unity
4357
4358=== added file 'src/locations-settings.cpp'
4359--- src/locations-settings.cpp 1970-01-01 00:00:00 +0000
4360+++ src/locations-settings.cpp 2014-01-31 00:43:10 +0000
4361@@ -0,0 +1,92 @@
4362+/*
4363+ * Copyright 2013 Canonical Ltd.
4364+ *
4365+ * This program is free software: you can redistribute it and/or modify it
4366+ * under the terms of the GNU General Public License version 3, as published
4367+ * by the Free Software Foundation.
4368+ *
4369+ * This program is distributed in the hope that it will be useful, but
4370+ * WITHOUT ANY WARRANTY; without even the implied warranties of
4371+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4372+ * PURPOSE. See the GNU General Public License for more details.
4373+ *
4374+ * You should have received a copy of the GNU General Public License along
4375+ * with this program. If not, see <http://www.gnu.org/licenses/>.
4376+ *
4377+ * Authors:
4378+ * Charles Kerr <charles.kerr@canonical.com>
4379+ */
4380+
4381+#include <datetime/locations-settings.h>
4382+
4383+#include <datetime/settings-shared.h>
4384+#include <datetime/timezones.h>
4385+#include <datetime/utils.h>
4386+
4387+#include <algorithm> // std::find()
4388+
4389+namespace unity {
4390+namespace indicator {
4391+namespace datetime {
4392+
4393+SettingsLocations::SettingsLocations(const std::shared_ptr<const Settings>& settings,
4394+ const std::shared_ptr<const Timezones>& timezones):
4395+ m_settings(settings),
4396+ m_timezones(timezones)
4397+{
4398+ m_settings->locations.changed().connect([this](const std::vector<std::string>&){reload();});
4399+ m_settings->show_locations.changed().connect([this](bool){reload();});
4400+ m_timezones->timezone.changed().connect([this](const std::string&){reload();});
4401+ m_timezones->timezones.changed().connect([this](const std::set<std::string>&){reload();});
4402+
4403+ reload();
4404+}
4405+
4406+void
4407+SettingsLocations::reload()
4408+{
4409+ std::vector<Location> v;
4410+ const std::string timezone_name = m_settings->timezone_name.get();
4411+
4412+ // add the primary timezone first
4413+ auto zone = m_timezones->timezone.get();
4414+ if (!zone.empty())
4415+ {
4416+ gchar * name = get_beautified_timezone_name(zone.c_str(), timezone_name.c_str());
4417+ Location l(zone, name);
4418+ v.push_back(l);
4419+ g_free(name);
4420+ }
4421+
4422+ // add the other detected timezones
4423+ for(const auto& zone : m_timezones->timezones.get())
4424+ {
4425+ gchar * name = get_beautified_timezone_name(zone.c_str(), timezone_name.c_str());
4426+ Location l(zone, name);
4427+ if (std::find(v.begin(), v.end(), l) == v.end())
4428+ v.push_back(l);
4429+ g_free(name);
4430+ }
4431+
4432+ // maybe add the user-specified locations
4433+ if (m_settings->show_locations.get())
4434+ {
4435+ for(const auto& locstr : m_settings->locations.get())
4436+ {
4437+ gchar* zone;
4438+ gchar* name;
4439+ split_settings_location(locstr.c_str(), &zone, &name);
4440+ Location loc(zone, name);
4441+ if (std::find(v.begin(), v.end(), loc) == v.end())
4442+ v.push_back(loc);
4443+ g_free(name);
4444+ g_free(zone);
4445+ }
4446+ }
4447+
4448+ locations.set(v);
4449+}
4450+
4451+} // namespace datetime
4452+} // namespace indicator
4453+} // namespace unity
4454
4455=== added file 'src/locations.cpp'
4456--- src/locations.cpp 1970-01-01 00:00:00 +0000
4457+++ src/locations.cpp 2014-01-31 00:43:10 +0000
4458@@ -0,0 +1,59 @@
4459+/*
4460+ * Copyright 2013 Canonical Ltd.
4461+ *
4462+ * This program is free software: you can redistribute it and/or modify it
4463+ * under the terms of the GNU General Public License version 3, as published
4464+ * by the Free Software Foundation.
4465+ *
4466+ * This program is distributed in the hope that it will be useful, but
4467+ * WITHOUT ANY WARRANTY; without even the implied warranties of
4468+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4469+ * PURPOSE. See the GNU General Public License for more details.
4470+ *
4471+ * You should have received a copy of the GNU General Public License along
4472+ * with this program. If not, see <http://www.gnu.org/licenses/>.
4473+ *
4474+ * Authors:
4475+ * Charles Kerr <charles.kerr@canonical.com>
4476+ */
4477+
4478+#include <datetime/locations.h>
4479+
4480+#include <glib.h>
4481+
4482+namespace unity {
4483+namespace indicator {
4484+namespace datetime {
4485+
4486+const std::string& Location::zone() const
4487+{
4488+ return m_zone;
4489+}
4490+
4491+const std::string& Location::name() const
4492+{
4493+ return m_name;
4494+}
4495+
4496+bool Location::operator== (const Location& that) const
4497+{
4498+ return (m_name == that.m_name)
4499+ && (m_zone == that.m_zone)
4500+ && (m_offset == that.m_offset);
4501+}
4502+
4503+
4504+Location::Location(const std::string& zone_, const std::string& name_):
4505+ m_zone(zone_),
4506+ m_name(name_)
4507+{
4508+ auto gzone = g_time_zone_new (zone().c_str());
4509+ auto gtime = g_date_time_new_now (gzone);
4510+ m_offset = g_date_time_get_utc_offset (gtime);
4511+ g_date_time_unref (gtime);
4512+ g_time_zone_unref (gzone);
4513+}
4514+
4515+} // namespace datetime
4516+} // namespace indicator
4517+} // namespace unity
4518
4519=== removed file 'src/main.c'
4520--- src/main.c 2013-10-30 23:49:58 +0000
4521+++ src/main.c 1970-01-01 00:00:00 +0000
4522@@ -1,83 +0,0 @@
4523-/*
4524- * Copyright 2013 Canonical Ltd.
4525- *
4526- * Authors:
4527- * Charles Kerr <charles.kerr@canonical.com>
4528- *
4529- * This program is free software: you can redistribute it and/or modify it
4530- * under the terms of the GNU General Public License version 3, as published
4531- * by the Free Software Foundation.
4532- *
4533- * This program is distributed in the hope that it will be useful, but
4534- * WITHOUT ANY WARRANTY; without even the implied warranties of
4535- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4536- * PURPOSE. See the GNU General Public License for more details.
4537- *
4538- * You should have received a copy of the GNU General Public License along
4539- * with this program. If not, see <http://www.gnu.org/licenses/>.
4540- */
4541-
4542-#include <locale.h>
4543-#include <stdlib.h> /* exit() */
4544-
4545-#include <glib/gi18n.h>
4546-#include <gio/gio.h>
4547-#include <libnotify/notify.h>
4548-
4549-#include "clock-live.h"
4550-#include "planner-eds.h"
4551-#include "service.h"
4552-
4553-/***
4554-****
4555-***/
4556-
4557-static void
4558-on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop)
4559-{
4560- g_message ("exiting: service couldn't acquire or lost ownership of busname");
4561-
4562- g_main_loop_quit ((GMainLoop*)loop);
4563-}
4564-
4565-int
4566-main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED)
4567-{
4568- IndicatorDatetimeClock * clock;
4569- IndicatorDatetimePlanner * planner;
4570- IndicatorDatetimeService * service;
4571- GMainLoop * loop;
4572-
4573- /* Work around a deadlock in glib's type initialization. It can be
4574- * removed when https://bugzilla.gnome.org/show_bug.cgi?id=674885 is
4575- * fixed.
4576- */
4577- g_type_ensure (G_TYPE_DBUS_CONNECTION);
4578-
4579- /* boilerplate i18n */
4580- setlocale (LC_ALL, "");
4581- bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
4582- textdomain (GETTEXT_PACKAGE);
4583-
4584- /* init libnotify */
4585- if (!notify_init ("indicator-datetime-service"))
4586- g_critical ("libnotify initialization failed");
4587-
4588- /* create the service */
4589- clock = indicator_datetime_clock_live_new ();
4590- planner = indicator_datetime_planner_eds_new ();
4591- service = indicator_datetime_service_new (clock, planner);
4592-
4593- /* run */
4594- loop = g_main_loop_new (NULL, FALSE);
4595- g_signal_connect (service, INDICATOR_DATETIME_SERVICE_SIGNAL_NAME_LOST,
4596- G_CALLBACK(on_name_lost), loop);
4597- g_main_loop_run (loop);
4598- g_main_loop_unref (loop);
4599-
4600- /* cleanup */
4601- g_object_unref (service);
4602- g_object_unref (planner);
4603- g_object_unref (clock);
4604- return 0;
4605-}
4606
4607=== added file 'src/main.cpp'
4608--- src/main.cpp 1970-01-01 00:00:00 +0000
4609+++ src/main.cpp 2014-01-31 00:43:10 +0000
4610@@ -0,0 +1,86 @@
4611+/*
4612+ * Copyright 2013 Canonical Ltd.
4613+ *
4614+ * Authors:
4615+ * Charles Kerr <charles.kerr@canonical.com>
4616+ *
4617+ * This program is free software: you can redistribute it and/or modify it
4618+ * under the terms of the GNU General Public License version 3, as published
4619+ * by the Free Software Foundation.
4620+ *
4621+ * This program is distributed in the hope that it will be useful, but
4622+ * WITHOUT ANY WARRANTY; without even the implied warranties of
4623+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4624+ * PURPOSE. See the GNU General Public License for more details.
4625+ *
4626+ * You should have received a copy of the GNU General Public License along
4627+ * with this program. If not, see <http://www.gnu.org/licenses/>.
4628+ */
4629+
4630+
4631+
4632+#include <datetime/actions-live.h>
4633+#include <datetime/clock.h>
4634+#include <datetime/exporter.h>
4635+#include <datetime/locations-settings.h>
4636+#include <datetime/menu.h>
4637+#include <datetime/planner-eds.h>
4638+#include <datetime/settings-live.h>
4639+#include <datetime/state.h>
4640+#include <datetime/timezones-live.h>
4641+
4642+#include <glib/gi18n.h> // bindtextdomain()
4643+#include <gio/gio.h>
4644+#include <libnotify/notify.h>
4645+
4646+#include <locale.h>
4647+#include <stdlib.h> // exit()
4648+
4649+using namespace unity::indicator::datetime;
4650+
4651+int
4652+main(int /*argc*/, char** /*argv*/)
4653+{
4654+ // Work around a deadlock in glib's type initialization.
4655+ // It can be removed when https://bugzilla.gnome.org/show_bug.cgi?id=674885 is fixed.
4656+ g_type_ensure(G_TYPE_DBUS_CONNECTION);
4657+
4658+ // boilerplate i18n
4659+ setlocale(LC_ALL, "");
4660+ bindtextdomain(GETTEXT_PACKAGE, GNOMELOCALEDIR);
4661+ textdomain(GETTEXT_PACKAGE);
4662+
4663+ // init libnotify
4664+ if(!notify_init("indicator-datetime-service"))
4665+ g_critical("libnotify initialization failed");
4666+
4667+ // build the state, actions, and menufactory
4668+ std::shared_ptr<State> state(new State);
4669+ std::shared_ptr<Settings> live_settings(new LiveSettings);
4670+ std::shared_ptr<Timezones> live_timezones(new LiveTimezones(live_settings, TIMEZONE_FILE));
4671+ std::shared_ptr<Clock> live_clock(new LiveClock(live_timezones));
4672+ state->settings = live_settings;
4673+ state->clock = live_clock;
4674+ state->locations.reset(new SettingsLocations(live_settings, live_timezones));
4675+ state->planner.reset(new PlannerEds);
4676+ state->planner->time = live_clock->localtime();
4677+ std::shared_ptr<Actions> actions(new LiveActions(state));
4678+ MenuFactory factory(actions, state);
4679+
4680+ // create the menus
4681+ std::vector<std::shared_ptr<Menu>> menus;
4682+ for(int i=0, n=Menu::NUM_PROFILES; i<n; i++)
4683+ menus.push_back(factory.buildMenu(Menu::Profile(i)));
4684+
4685+ // export them & run until we lose the busname
4686+ auto loop = g_main_loop_new(nullptr, false);
4687+ Exporter exporter;
4688+ exporter.name_lost.connect([loop](){
4689+ g_message("%s exiting; failed/lost bus ownership", GETTEXT_PACKAGE);
4690+ g_main_loop_quit(loop);
4691+ });
4692+ exporter.publish(actions, menus);
4693+ g_main_loop_run(loop);
4694+ g_main_loop_unref(loop);
4695+ return 0;
4696+}
4697
4698=== added file 'src/menu.cpp'
4699--- src/menu.cpp 1970-01-01 00:00:00 +0000
4700+++ src/menu.cpp 2014-01-31 00:43:10 +0000
4701@@ -0,0 +1,598 @@
4702+/*
4703+ * Copyright 2013 Canonical Ltd.
4704+ *
4705+ * This program is free software: you can redistribute it and/or modify it
4706+ * under the terms of the GNU General Public License version 3, as published
4707+ * by the Free Software Foundation.
4708+ *
4709+ * This program is distributed in the hope that it will be useful, but
4710+ * WITHOUT ANY WARRANTY; without even the implied warranties of
4711+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4712+ * PURPOSE. See the GNU General Public License for more details.
4713+ *
4714+ * You should have received a copy of the GNU General Public License along
4715+ * with this program. If not, see <http://www.gnu.org/licenses/>.
4716+ *
4717+ * Authors:
4718+ * Charles Kerr <charles.kerr@canonical.com>
4719+ */
4720+
4721+#include <datetime/menu.h>
4722+
4723+#include <datetime/formatter.h>
4724+#include <datetime/state.h>
4725+
4726+#include <json-glib/json-glib.h>
4727+
4728+#include <glib/gi18n.h>
4729+#include <gio/gio.h>
4730+
4731+namespace unity {
4732+namespace indicator {
4733+namespace datetime {
4734+
4735+/****
4736+*****
4737+****/
4738+
4739+Menu::Menu (Profile profile_in, const std::string& name_in):
4740+ m_profile(profile_in),
4741+ m_name(name_in)
4742+{
4743+}
4744+
4745+const std::string& Menu::name() const
4746+{
4747+ return m_name;
4748+}
4749+
4750+Menu::Profile Menu::profile() const
4751+{
4752+ return m_profile;
4753+}
4754+
4755+GMenuModel* Menu::menu_model()
4756+{
4757+ return G_MENU_MODEL(m_menu);
4758+}
4759+
4760+
4761+/****
4762+*****
4763+****/
4764+
4765+
4766+#define FALLBACK_ALARM_CLOCK_ICON_NAME "clock"
4767+#define CALENDAR_ICON_NAME "calendar"
4768+
4769+class MenuImpl: public Menu
4770+{
4771+protected:
4772+ MenuImpl(const Menu::Profile profile_in,
4773+ const std::string& name_in,
4774+ std::shared_ptr<const State>& state,
4775+ std::shared_ptr<Actions>& actions,
4776+ std::shared_ptr<const Formatter> formatter):
4777+ Menu(profile_in, name_in),
4778+ m_state(state),
4779+ m_actions(actions),
4780+ m_formatter(formatter)
4781+ {
4782+ // preload the alarm icon from click
4783+ m_serialized_alarm_icon = create_alarm_icon();
4784+
4785+ // initialize the menu
4786+ create_gmenu();
4787+ for (int i=0; i<NUM_SECTIONS; i++)
4788+ update_section(Section(i));
4789+
4790+ // listen for state changes so we can update the menu accordingly
4791+ m_formatter->header.changed().connect([this](const std::string&){
4792+ update_header();
4793+ });
4794+ m_formatter->header_format.changed().connect([this](const std::string&){
4795+ update_section(Locations); // need to update x-canonical-time-format
4796+ });
4797+ m_formatter->relative_format_changed.connect([this](){
4798+ update_section(Appointments); // uses formatter.relative_format()
4799+ update_section(Locations); // uses formatter.relative_format()
4800+ });
4801+ m_state->settings->show_clock.changed().connect([this](bool){
4802+ update_header(); // update header's label
4803+ update_section(Locations); // locations' relative time may have changed
4804+ });
4805+ m_state->settings->show_calendar.changed().connect([this](bool){
4806+ update_section(Calendar);
4807+ });
4808+ m_state->settings->show_events.changed().connect([this](bool){
4809+ update_section(Appointments); // showing events got toggled
4810+ });
4811+ m_state->planner->upcoming.changed().connect([this](const std::vector<Appointment>&){
4812+ update_section(Appointments); // "upcoming" is the list of Appointments we show
4813+ });
4814+ m_state->clock->date_changed.connect([this](){
4815+ update_section(Calendar); // need to update the Date menuitem
4816+ update_section(Locations); // locations' relative time may have changed
4817+ });
4818+ m_state->locations->locations.changed().connect([this](const std::vector<Location>&) {
4819+ update_section(Locations); // "locations" is the list of Locations we show
4820+ });
4821+ }
4822+
4823+ virtual ~MenuImpl()
4824+ {
4825+ g_clear_object(&m_menu);
4826+ g_clear_pointer(&m_serialized_alarm_icon, g_variant_unref);
4827+ g_clear_pointer(&m_serialized_calendar_icon, g_variant_unref);
4828+ }
4829+
4830+ virtual GVariant* create_header_state() =0;
4831+
4832+ void update_header()
4833+ {
4834+ auto action_group = m_actions->action_group();
4835+ auto action_name = name() + "-header";
4836+ auto state = create_header_state();
4837+ g_action_group_change_action_state(action_group, action_name.c_str(), state);
4838+ }
4839+
4840+ std::shared_ptr<const State> m_state;
4841+ std::shared_ptr<Actions> m_actions;
4842+ std::shared_ptr<const Formatter> m_formatter;
4843+ GMenu* m_submenu = nullptr;
4844+
4845+ GVariant* get_serialized_alarm_icon() { return m_serialized_alarm_icon; }
4846+
4847+private:
4848+
4849+ /* try to get the clock app's filename from click. (/$pkgdir/$icon) */
4850+ static GVariant* create_alarm_icon()
4851+ {
4852+ GVariant* serialized = nullptr;
4853+ gchar* icon_filename = nullptr;
4854+ gchar* standard_error = nullptr;
4855+ gchar* pkgdir = nullptr;
4856+
4857+ g_spawn_command_line_sync("click pkgdir com.ubuntu.clock", &pkgdir, &standard_error, nullptr, nullptr);
4858+ g_clear_pointer(&standard_error, g_free);
4859+ if (pkgdir != nullptr)
4860+ {
4861+ gchar* manifest = nullptr;
4862+ g_strstrip(pkgdir);
4863+ g_spawn_command_line_sync("click info com.ubuntu.clock", &manifest, &standard_error, nullptr, nullptr);
4864+ g_clear_pointer(&standard_error, g_free);
4865+ if (manifest != nullptr)
4866+ {
4867+ JsonParser* parser = json_parser_new();
4868+ if (json_parser_load_from_data(parser, manifest, -1, nullptr))
4869+ {
4870+ JsonNode* root = json_parser_get_root(parser); /* transfer-none */
4871+ if ((root != nullptr) && (JSON_NODE_TYPE(root) == JSON_NODE_OBJECT))
4872+ {
4873+ JsonObject* o = json_node_get_object(root); /* transfer-none */
4874+ const gchar* icon_name = json_object_get_string_member(o, "icon");
4875+ if (icon_name != nullptr)
4876+ icon_filename = g_build_filename(pkgdir, icon_name, nullptr);
4877+ }
4878+ }
4879+ g_object_unref(parser);
4880+ g_free(manifest);
4881+ }
4882+ g_free(pkgdir);
4883+ }
4884+
4885+ if (icon_filename != nullptr)
4886+ {
4887+ GFile* file = g_file_new_for_path(icon_filename);
4888+ GIcon* icon = g_file_icon_new(file);
4889+
4890+ serialized = g_icon_serialize(icon);
4891+
4892+ g_object_unref(icon);
4893+ g_object_unref(file);
4894+ g_free(icon_filename);
4895+ }
4896+
4897+ if (serialized == nullptr)
4898+ {
4899+ auto i = g_themed_icon_new_with_default_fallbacks(FALLBACK_ALARM_CLOCK_ICON_NAME);
4900+ serialized = g_icon_serialize(i);
4901+ g_object_unref(i);
4902+ }
4903+
4904+ return serialized;
4905+ }
4906+
4907+ GVariant* get_serialized_calendar_icon()
4908+ {
4909+ if (G_UNLIKELY(m_serialized_calendar_icon == nullptr))
4910+ {
4911+ auto i = g_themed_icon_new_with_default_fallbacks(CALENDAR_ICON_NAME);
4912+ m_serialized_calendar_icon = g_icon_serialize(i);
4913+ g_object_unref(i);
4914+ }
4915+
4916+ return m_serialized_calendar_icon;
4917+ }
4918+
4919+ void create_gmenu()
4920+ {
4921+ g_assert(m_submenu == nullptr);
4922+
4923+ m_submenu = g_menu_new();
4924+
4925+ // build placeholders for the sections
4926+ for(int i=0; i<NUM_SECTIONS; i++)
4927+ {
4928+ GMenuItem * item = g_menu_item_new(nullptr, nullptr);
4929+ g_menu_append_item(m_submenu, item);
4930+ g_object_unref(item);
4931+ }
4932+
4933+ // add submenu to the header
4934+ const auto detailed_action = std::string("indicator.") + name() + "-header";
4935+ auto header = g_menu_item_new(nullptr, detailed_action.c_str());
4936+ g_menu_item_set_attribute(header, "x-canonical-type", "s",
4937+ "com.canonical.indicator.root");
4938+ g_menu_item_set_attribute(header, "submenu-action", "s",
4939+ "indicator.calendar-active");
4940+ g_menu_item_set_submenu(header, G_MENU_MODEL(m_submenu));
4941+ g_object_unref(m_submenu);
4942+
4943+ // add header to the menu
4944+ m_menu = g_menu_new();
4945+ g_menu_append_item(m_menu, header);
4946+ g_object_unref(header);
4947+ }
4948+
4949+ GMenuModel* create_calendar_section(Profile profile)
4950+ {
4951+ const bool allow_activation = (profile == Desktop)
4952+ || (profile == Phone);
4953+ const bool show_calendar = m_state->settings->show_calendar.get() &&
4954+ ((profile == Desktop) || (profile == DesktopGreeter));
4955+ auto menu = g_menu_new();
4956+
4957+ // add a menuitem that shows the current date
4958+ auto label = m_state->clock->localtime().format(_("%A, %e %B %Y"));
4959+ auto item = g_menu_item_new (label.c_str(), nullptr);
4960+ auto v = get_serialized_calendar_icon();
4961+ g_menu_item_set_attribute_value (item, G_MENU_ATTRIBUTE_ICON, v);
4962+ if (allow_activation)
4963+ {
4964+ v = g_variant_new_int64(0);
4965+ const char* action = "indicator.activate-planner";
4966+ g_menu_item_set_action_and_target_value (item, action, v);
4967+ }
4968+ g_menu_append_item(menu, item);
4969+ g_object_unref(item);
4970+
4971+ // add calendar
4972+ if (show_calendar)
4973+ {
4974+ item = g_menu_item_new ("[calendar]", NULL);
4975+ v = g_variant_new_int64(0);
4976+ g_menu_item_set_action_and_target_value (item, "indicator.calendar", v);
4977+ g_menu_item_set_attribute (item, "x-canonical-type",
4978+ "s", "com.canonical.indicator.calendar");
4979+ if (allow_activation)
4980+ {
4981+ g_menu_item_set_attribute (item, "activation-action",
4982+ "s", "indicator.activate-planner");
4983+ }
4984+ g_menu_append_item (menu, item);
4985+ g_object_unref (item);
4986+ }
4987+
4988+ return G_MENU_MODEL(menu);
4989+ }
4990+
4991+ void add_appointments(GMenu* menu, Profile profile)
4992+ {
4993+ int n = 0;
4994+ const int MAX_APPTS = 5;
4995+ std::set<std::string> added;
4996+
4997+ for (const auto& appt : m_state->planner->upcoming.get())
4998+ {
4999+ if (n++ >= MAX_APPTS)
5000+ break;
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches