~charlesk/indicator-datetime/cpp

« back to all changes in this revision

Viewing changes to src/formatter.cpp

  • Committer: Charles Kerr
  • Date: 2014-01-22 20:28:20 UTC
  • Revision ID: charles.kerr@canonical.com-20140122202820-o2geguxf83q6wbl3
Alarms is going to need to know when the clock's minute changes. We already have a timer for that in Formatter, so move it from there to Clock and add a corresponding public signal Clock.minuteChanged that both Formatter and Alarms can use. Sync unit tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
#include <langinfo.h> // nl_langinfo()
29
29
#include <string.h> // strstr()
30
30
 
 
31
namespace unity {
 
32
namespace indicator {
 
33
namespace datetime {
 
34
 
 
35
/***
 
36
****
 
37
***/
 
38
 
31
39
namespace
32
40
{
33
 
void clearTimer(guint& tag)
 
41
 
 
42
void clear_timer(guint& tag)
34
43
{
35
44
    if (tag)
36
45
    {
39
48
    }
40
49
}
41
50
 
42
 
guint calculate_milliseconds_until_next_minute(GDateTime * now)
43
 
{
44
 
    GDateTime * next;
45
 
    GDateTime * start_of_next;
46
 
    GTimeSpan interval_usec;
47
 
    guint interval_msec;
48
 
 
49
 
    next = g_date_time_add_minutes(now, 1);
50
 
    start_of_next = g_date_time_new_local(g_date_time_get_year(next),
51
 
                                          g_date_time_get_month(next),
52
 
                                          g_date_time_get_day_of_month(next),
53
 
                                          g_date_time_get_hour(next),
54
 
                                          g_date_time_get_minute(next),
55
 
                                          0.1);
56
 
 
57
 
    interval_usec = g_date_time_difference(start_of_next, now);
58
 
    interval_msec = (interval_usec + 999) / 1000;
59
 
 
60
 
    g_date_time_unref(start_of_next);
61
 
    g_date_time_unref(next);
62
 
    return interval_msec;
63
 
}
64
 
 
65
 
gint calculate_milliseconds_until_next_second(GDateTime * now)
 
51
gint calculate_milliseconds_until_next_second(const DateTime& now)
66
52
{
67
53
    gint interval_usec;
68
54
    guint interval_msec;
69
55
 
70
 
    interval_usec = G_USEC_PER_SEC - g_date_time_get_microsecond(now);
 
56
    interval_usec = G_USEC_PER_SEC - g_date_time_get_microsecond(now.get());
71
57
    interval_msec = (interval_usec + 999) / 1000;
72
58
    return interval_msec;
73
59
}
127
113
} // unnamed namespace
128
114
 
129
115
 
130
 
 
131
 
namespace unity {
132
 
namespace indicator {
133
 
namespace datetime {
134
 
 
135
116
class Formatter::Impl
136
117
{
137
118
public:
140
121
        m_owner(owner),
141
122
        m_clock(clock)
142
123
    {
143
 
        m_owner->headerFormat.changed().connect([this](const std::string& /*fmt*/){updateHeader();});
144
 
        m_clock->skewDetected.connect([this](){updateHeader();});
145
 
        updateHeader();
 
124
        m_owner->headerFormat.changed().connect([this](const std::string& /*fmt*/){update_header();});
 
125
        m_clock->minuteChanged.connect([this](){update_header();});
 
126
        update_header();
146
127
 
147
128
        restartRelativeTimer();
148
129
    }
149
130
 
150
131
    ~Impl()
151
132
    {
152
 
        clearTimer(m_header_timer);
 
133
        clear_timer(m_header_seconds_timer);
 
134
        clear_timer(m_relative_timer);
153
135
    }
154
136
 
155
137
private:
156
138
 
157
 
    void updateHeader()
158
 
    {
 
139
    static bool format_shows_seconds(const std::string& fmt)
 
140
    {
 
141
        return (fmt.find("%s") != std::string::npos)
 
142
            || (fmt.find("%S") != std::string::npos)
 
143
            || (fmt.find("%T") != std::string::npos)
 
144
            || (fmt.find("%X") != std::string::npos)
 
145
            || (fmt.find("%c") != std::string::npos);
 
146
    }
 
147
 
 
148
    void update_header()
 
149
    {
 
150
        // update the header property
159
151
        const auto fmt = m_owner->headerFormat.get();
160
152
        const auto str = m_clock->localtime().format(fmt);
161
153
        m_owner->header.set(str);
162
154
 
163
 
        restartHeaderTimer();
 
155
        // if the header needs to show seconds, set a timer.
 
156
        if (format_shows_seconds(fmt))
 
157
            start_header_timer();
 
158
        else
 
159
            clear_timer(m_header_seconds_timer);
164
160
    }
165
161
 
166
 
    void restartHeaderTimer()
 
162
    // we've got a header format that shows seconds,
 
163
    // so we need to update it every second
 
164
    void start_header_timer()
167
165
    {
168
 
        clearTimer(m_header_timer);
169
 
 
170
 
        const auto fmt = m_owner->headerFormat.get();
171
 
        const bool header_shows_seconds = (fmt.find("%s") != std::string::npos)
172
 
                                       || (fmt.find("%S") != std::string::npos)
173
 
                                       || (fmt.find("%T") != std::string::npos)
174
 
                                       || (fmt.find("%X") != std::string::npos)
175
 
                                       || (fmt.find("%c") != std::string::npos);
176
 
 
177
 
        guint interval_msec;
 
166
        clear_timer(m_header_seconds_timer);
 
167
 
178
168
        const auto now = m_clock->localtime();
179
 
        auto str = now.format("%F %T");
180
 
        if (header_shows_seconds)
181
 
            interval_msec = calculate_milliseconds_until_next_second(now.get());
182
 
        else
183
 
            interval_msec = calculate_milliseconds_until_next_minute(now.get());
184
 
 
 
169
        auto interval_msec = calculate_milliseconds_until_next_second(now);
185
170
        interval_msec += 50; // add a small margin to ensure the callback
186
171
                             // fires /after/ next is reached
187
 
 
188
 
        m_header_timer = g_timeout_add_full(G_PRIORITY_HIGH, interval_msec, onHeaderTimer, this, nullptr);
 
172
        m_header_seconds_timer = g_timeout_add_full(G_PRIORITY_HIGH,
 
173
                                                    interval_msec,
 
174
                                                    on_header_timer,
 
175
                                                    this,
 
176
                                                    nullptr);
189
177
    }
190
178
 
191
 
    static gboolean onHeaderTimer(gpointer gself)
 
179
    static gboolean on_header_timer(gpointer gself)
192
180
    {
193
 
        static_cast<Formatter::Impl*>(gself)->updateHeader();
 
181
        static_cast<Formatter::Impl*>(gself)->update_header();
194
182
        return G_SOURCE_REMOVE;
195
183
    }
196
184
 
198
186
 
199
187
    void restartRelativeTimer()
200
188
    {
201
 
        clearTimer(m_relative_timer);
 
189
        clear_timer(m_relative_timer);
202
190
 
203
191
        const auto now = m_clock->localtime();
204
192
        const auto seconds = calculate_seconds_until_next_fifteen_minutes(now.get());
215
203
 
216
204
private:
217
205
    Formatter* const m_owner;
218
 
    guint m_header_timer = 0;
 
206
    guint m_header_seconds_timer = 0;
219
207
    guint m_relative_timer = 0;
220
208
 
221
209
public: