Unity 8
 All Classes Functions
timeformatter.cpp
1 /*
2  * Copyright 2013 Canonical Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 3.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Author: Lars Uebernickel <lars.uebernickel@canonical.com>
17  */
18 
19 #include "timeformatter.h"
20 
21 #include <gio/gio.h>
22 #include <QDateTime>
23 
24 struct TimeFormatterPrivate
25 {
26  TimeFormatter *formatter;
27 
28  QString format;
29  QString timeString;
30  qint64 time;
31 
32  GDBusConnection *system_bus;
33  guint subscription_id;
34  GCancellable *cancellable;
35 };
36 
37 static void
38 timedate1_properties_changed (GDBusConnection *connection,
39  const gchar *sender_name,
40  const gchar *object_path,
41  const gchar *interface_name,
42  const gchar *signal_name,
43  GVariant *parameters,
44  gpointer user_data)
45 {
46  Q_UNUSED(connection);
47  Q_UNUSED(sender_name);
48  Q_UNUSED(object_path);
49  Q_UNUSED(interface_name);
50  Q_UNUSED(signal_name);
51 
52  TimeFormatterPrivate *priv = (TimeFormatterPrivate *)user_data;
53  GVariant *changed;
54  GVariantIter *iter;
55  const gchar *name;
56 
57  if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)")))
58  return;
59 
60  g_variant_get (parameters, "(s@a{sv}as)", nullptr, &changed, &iter);
61 
62  if (g_variant_lookup (changed, "Timezone", "s", nullptr)) {
63  priv->formatter->update();
64  }
65  else {
66  while (g_variant_iter_next (iter, "&s", &name)) {
67  if (g_str_equal (name, "Timezone")) {
68  priv->formatter->update();
69  break;
70  }
71  }
72  }
73 
74  g_variant_unref (changed);
75  g_variant_iter_free (iter);
76 }
77 
78 static void
79 got_bus(GObject *object, GAsyncResult *result, gpointer user_data)
80 {
81  Q_UNUSED(object);
82 
83  TimeFormatterPrivate *priv = (TimeFormatterPrivate *)user_data;
84  GError *error = nullptr;
85 
86  priv->system_bus = g_bus_get_finish (result, &error);
87  if (priv->system_bus == nullptr) {
88  if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
89  qWarning("TimeFormatter: cannot connect to the system bus: %s", error->message);
90  g_error_free (error);
91  return;
92  }
93 
94  /* Listen to the PropertiesChanged on the org.freedesktop.timedate1
95  * interface from any sender. In practice, this signal will only be sent
96  * from timedated (we can trust other processes on the system bus to behave
97  * nicely). That way, we don't have to watch timedated's well-known name
98  * and keep the process alive.
99  */
100  priv->subscription_id = g_dbus_connection_signal_subscribe (priv->system_bus,
101  nullptr, /* sender */
102  "org.freedesktop.DBus.Properties",
103  "PropertiesChanged",
104  nullptr,
105  "org.freedesktop.timedate1",
106  G_DBUS_SIGNAL_FLAGS_NONE,
107  timedate1_properties_changed,
108  priv, nullptr);
109 }
110 
111 TimeFormatter::TimeFormatter(QObject *parent): QObject(parent)
112 {
113  priv = new TimeFormatterPrivate;
114  priv->formatter = this;
115  priv->time = 0;
116  priv->format = "yyyy-MM-dd hh:mm";
117  priv->system_bus = nullptr;
118  priv->subscription_id = 0;
119  priv->cancellable = g_cancellable_new ();
120 
121  g_bus_get (G_BUS_TYPE_SYSTEM, priv->cancellable, got_bus, priv);
122 }
123 
124 TimeFormatter::~TimeFormatter()
125 {
126  if (priv->system_bus) {
127  g_dbus_connection_signal_unsubscribe (priv->system_bus, priv->subscription_id);
128  g_object_unref (priv->system_bus);
129  }
130 
131  g_cancellable_cancel (priv->cancellable);
132  g_object_unref (priv->cancellable);
133 }
134 
135 QString TimeFormatter::format() const
136 {
137  return priv->format;
138 }
139 
140 QString TimeFormatter::timeString() const
141 {
142  return priv->timeString;
143 }
144 
145 qint64 TimeFormatter::time() const
146 {
147  return priv->time;
148 }
149 
150 void TimeFormatter::setFormat(const QString &format)
151 {
152  if (priv->format != format) {
153  priv->format = format;
154  Q_EMIT formatChanged(priv->format);
155  update();
156  }
157 }
158 
159 void TimeFormatter::setTime(qint64 time)
160 {
161  if (priv->time != time) {
162  priv->time = time;
163  Q_EMIT timeChanged(priv->time);
164  update();
165  }
166 }
167 
168 void TimeFormatter::update()
169 {
170  priv->timeString = formatTime();
171  Q_EMIT timeStringChanged(priv->timeString);
172 }
173 
174 QString TimeFormatter::formatTime() const
175 {
176  return QDateTime::fromMSecsSinceEpoch(time() / 1000).toString(format());
177 }
178 
179 GDateTimeFormatter::GDateTimeFormatter(QObject* parent)
180 : TimeFormatter(parent)
181 {
182 }
183 
184 QString GDateTimeFormatter::formatTime() const
185 {
186  gchar* time_string;
187  GDateTime* datetime;
188  QByteArray formatBytes = format().toUtf8();
189 
190  datetime = g_date_time_new_from_unix_local(time());
191  if (!datetime) {
192  return "";
193  }
194 
195  time_string = g_date_time_format(datetime, formatBytes.constData());
196  QString formattedTime(QString::fromUtf8(time_string));
197 
198  g_free(time_string);
199  g_date_time_unref(datetime);
200  return formattedTime;
201 }