~diegosarmentero/unity8/app-preview

« back to all changes in this revision

Viewing changes to plugins/Unity/Indicators/menucontentactivator.cpp

  • Committer: Diego Sarmentero
  • Date: 2013-07-22 23:43:12 UTC
  • mfrom: (121.2.6 unity8)
  • Revision ID: diego.sarmentero@gmail.com-20130722234312-a6uvi5pk4n7os96b
merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 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: Nick Dedekind <nick.dedekind@canonical.com>
 
17
 */
 
18
 
 
19
 #include "menucontentactivator.h"
 
20
 
 
21
// Essentially a QTimer wrapper
 
22
class ContentTimer : public UnityIndicators::AbstractTimer
 
23
{
 
24
    Q_OBJECT
 
25
public:
 
26
    ContentTimer(QObject *parent) : UnityIndicators::AbstractTimer(parent) {
 
27
        m_timer.setSingleShot(false);
 
28
        connect(&m_timer, &QTimer::timeout,
 
29
                this, &UnityIndicators::AbstractTimer::timeout);
 
30
    }
 
31
    virtual int interval() const { return m_timer.interval(); }
 
32
    virtual void setInterval(int msecs) { m_timer.setInterval(msecs); }
 
33
    virtual void start() { m_timer.start(); UnityIndicators::AbstractTimer::start(); }
 
34
    virtual void stop() { m_timer.stop(); UnityIndicators::AbstractTimer::stop(); }
 
35
private:
 
36
    QTimer m_timer;
 
37
};
 
38
 
 
39
class MenuContentActivatorPrivate : public QObject
 
40
{
 
41
    Q_OBJECT
 
42
public:
 
43
    MenuContentActivatorPrivate(MenuContentActivator* parent)
 
44
    :   m_running(false),
 
45
        m_baseIndex(0),
 
46
        m_delta(0),
 
47
        m_count(0),
 
48
        m_timer(NULL),
 
49
        q(parent)
 
50
    {}
 
51
 
 
52
    ~MenuContentActivatorPrivate()
 
53
    {
 
54
        qDeleteAll(m_content);
 
55
        m_content.clear();
 
56
    }
 
57
 
 
58
    int findNextInactiveDelta(bool* finished = NULL);
 
59
 
 
60
    static int content_count(QQmlListProperty<MenuContentState> *prop);
 
61
    static MenuContentState* content_at(QQmlListProperty<MenuContentState> *prop, int index);
 
62
 
 
63
    bool m_running;
 
64
    int m_baseIndex;
 
65
    int m_delta;
 
66
    int m_count;
 
67
    UnityIndicators::AbstractTimer* m_timer;
 
68
    QMap<int, MenuContentState*> m_content;
 
69
    MenuContentActivator* q;
 
70
};
 
71
 
 
72
MenuContentActivator::MenuContentActivator(QObject* parent)
 
73
    :   QObject(parent),
 
74
        d(new MenuContentActivatorPrivate(this))
 
75
{
 
76
    qRegisterMetaType<QQmlListProperty<MenuContentState> > ("QQmlListProperty<MenuContentState>");
 
77
 
 
78
    setContentTimer(new ContentTimer(this));
 
79
    d->m_timer->setInterval(75);
 
80
}
 
81
 
 
82
MenuContentActivator::~MenuContentActivator()
 
83
{
 
84
    delete d;
 
85
}
 
86
 
 
87
void MenuContentActivator::restart()
 
88
{
 
89
    // when we start, make sure we have the base index in the list.
 
90
    setMenuContentState(d->m_baseIndex, true);
 
91
    setDelta(0);
 
92
 
 
93
    // check if we've finished before starting the timer.
 
94
    bool finished = false;
 
95
    d->findNextInactiveDelta(&finished);
 
96
    if (!finished) {
 
97
        d->m_timer->start();
 
98
    } else {
 
99
        d->m_timer->stop();
 
100
    }
 
101
 
 
102
    if (!d->m_running) {
 
103
        d->m_running = true;
 
104
        Q_EMIT runningChanged(true);
 
105
    }
 
106
}
 
107
 
 
108
void MenuContentActivator::stop()
 
109
{
 
110
    d->m_timer->stop();
 
111
    if (!d->m_running) {
 
112
        d->m_running = false;
 
113
        Q_EMIT runningChanged(false);
 
114
    }
 
115
}
 
116
 
 
117
void MenuContentActivator::clear()
 
118
{
 
119
    qDeleteAll(d->m_content);
 
120
    d->m_content.clear();
 
121
 
 
122
    setDelta(0);
 
123
    d->m_timer->stop();
 
124
 
 
125
    Q_EMIT contentChanged();
 
126
}
 
127
 
 
128
bool MenuContentActivator::isMenuContentActive(int index) const
 
129
{
 
130
    if (d->m_content.contains(index))
 
131
        return d->m_content[index]->isActive();
 
132
    return false;
 
133
}
 
134
 
 
135
void MenuContentActivator::setRunning(bool running)
 
136
{
 
137
    if (running) {
 
138
        restart();
 
139
    } else {
 
140
        stop();
 
141
    }
 
142
}
 
143
 
 
144
bool MenuContentActivator::isRunning() const
 
145
{
 
146
    return d->m_running;
 
147
}
 
148
 
 
149
void MenuContentActivator::setBaseIndex(int index)
 
150
{
 
151
    if (d->m_baseIndex != index) {
 
152
        d->m_baseIndex = index;
 
153
 
 
154
        if (isRunning()) {
 
155
            restart();
 
156
        }
 
157
 
 
158
        Q_EMIT baseIndexChanged(index);
 
159
    }
 
160
}
 
161
 
 
162
int MenuContentActivator::baseIndex() const
 
163
{
 
164
    return d->m_baseIndex;
 
165
}
 
166
 
 
167
void MenuContentActivator::setCount(int count)
 
168
{
 
169
    if (d->m_count != count) {
 
170
        d->m_count = count;
 
171
        Q_EMIT countChanged(count);
 
172
 
 
173
        if (isRunning()) {
 
174
            restart();
 
175
        }
 
176
    }
 
177
}
 
178
 
 
179
int MenuContentActivator::count() const
 
180
{
 
181
    return d->m_count;
 
182
}
 
183
 
 
184
void MenuContentActivator::setDelta(int delta)
 
185
{
 
186
    if (d->m_delta != delta) {
 
187
        d->m_delta = delta;
 
188
        Q_EMIT deltaChanged(d->m_delta);
 
189
    }
 
190
}
 
191
 
 
192
int MenuContentActivator::delta() const
 
193
{
 
194
    return d->m_delta;
 
195
}
 
196
 
 
197
QQmlListProperty<MenuContentState> MenuContentActivator::content()
 
198
{
 
199
    return QQmlListProperty<MenuContentState>(this,
 
200
                                            0,
 
201
                                            MenuContentActivatorPrivate::content_count,
 
202
                                            MenuContentActivatorPrivate::content_at);
 
203
}
 
204
 
 
205
void MenuContentActivator::onTimeout()
 
206
{
 
207
    bool finished = false;
 
208
    int tempDelta = d->findNextInactiveDelta(&finished);
 
209
    if (!finished) {
 
210
        setMenuContentState(d->m_baseIndex + tempDelta, true);
 
211
        setDelta(tempDelta);
 
212
    }
 
213
 
 
214
    if (finished) {
 
215
        d->m_timer->stop();
 
216
    }
 
217
}
 
218
 
 
219
void MenuContentActivator::setContentTimer(UnityIndicators::AbstractTimer *timer)
 
220
{
 
221
    int interval = 0;
 
222
    bool timerWasRunning = false;
 
223
 
 
224
    // can be null when called from the constructor
 
225
    if (d->m_timer) {
 
226
        interval = d->m_timer->interval();
 
227
        timerWasRunning = d->m_timer->isRunning();
 
228
        if (d->m_timer->parent() == this) {
 
229
            delete d->m_timer;
 
230
        }
 
231
    }
 
232
 
 
233
    d->m_timer = timer;
 
234
    timer->setInterval(interval);
 
235
    connect(timer, &UnityIndicators::AbstractTimer::timeout,
 
236
            this, &MenuContentActivator::onTimeout);
 
237
    if (timerWasRunning) {
 
238
        d->m_timer->start();
 
239
    }
 
240
}
 
241
 
 
242
void MenuContentActivator::setMenuContentState(int index, bool active)
 
243
{
 
244
    if (d->m_content.contains(index)) {
 
245
        d->m_content[index]->setActive(active);
 
246
    } else {
 
247
        d->m_content[index] = new MenuContentState(active);
 
248
        Q_EMIT contentChanged();
 
249
    }
 
250
}
 
251
 
 
252
int MenuContentActivatorPrivate::findNextInactiveDelta(bool* finished)
 
253
{
 
254
    if (m_count == 0 || m_baseIndex >= m_count) {
 
255
        if (finished) *finished = true;
 
256
        return 0;
 
257
    }
 
258
 
 
259
    int tmpDelta = m_delta;
 
260
    bool topReached = false, bottomReached = false;
 
261
    while(true) {
 
262
 
 
263
        // prechecks for bottom and top limits.
 
264
        if (tmpDelta > 0 && bottomReached) tmpDelta = -tmpDelta;
 
265
        if (tmpDelta < 0 && topReached) tmpDelta = (-tmpDelta) + 1;
 
266
 
 
267
        if (tmpDelta > 0) {
 
268
            // negative of baseIndex
 
269
            tmpDelta = -tmpDelta;
 
270
            // reached the bottom?
 
271
            if (m_baseIndex + tmpDelta < 0) {
 
272
                bottomReached = true;
 
273
                // if we've reached the top as well, then we know we're done.
 
274
                if (topReached) {
 
275
                    if (finished) *finished = true;
 
276
                    return 0;
 
277
                }
 
278
                continue;
 
279
            }
 
280
        } else {
 
281
            // positive of baseIndex
 
282
            tmpDelta = (-tmpDelta) + 1;
 
283
            // reached the top?
 
284
            if (m_baseIndex + tmpDelta >= m_count) {
 
285
                topReached = true;
 
286
                // if we've reached the bottom as well, then we know we're done.
 
287
                if (bottomReached) {
 
288
                    if (finished) *finished = true;
 
289
                    return 0;
 
290
                }
 
291
                continue;
 
292
            }
 
293
        }
 
294
 
 
295
        if (q->isMenuContentActive(m_baseIndex + tmpDelta)) {
 
296
            continue;
 
297
        }
 
298
        break;
 
299
    }
 
300
    if (finished) *finished = false;
 
301
    return tmpDelta;
 
302
}
 
303
 
 
304
int MenuContentActivatorPrivate::content_count(QQmlListProperty<MenuContentState> *prop)
 
305
{
 
306
    MenuContentActivator *p = qobject_cast<MenuContentActivator*>(prop->object);
 
307
    // we'll create MenuContentState on demand.
 
308
    return p->count();
 
309
}
 
310
 
 
311
MenuContentState* MenuContentActivatorPrivate::content_at(QQmlListProperty<MenuContentState> *prop, int index)
 
312
{
 
313
    MenuContentActivator *p = qobject_cast<MenuContentActivator*>(prop->object);
 
314
    MenuContentActivatorPrivate *d = p->d;
 
315
 
 
316
    if (!d->m_content.contains(index)) {
 
317
        MenuContentState* content = new MenuContentState(false);
 
318
        d->m_content[index] = content;
 
319
        Q_EMIT p->contentChanged();
 
320
        return content;
 
321
    }
 
322
 
 
323
    return d->m_content[index];
 
324
}
 
325
 
 
326
MenuContentState::MenuContentState(bool active)
 
327
    :   m_active(active)
 
328
{
 
329
}
 
330
 
 
331
bool MenuContentState::isActive() const
 
332
{
 
333
    return m_active;
 
334
}
 
335
 
 
336
void MenuContentState::setActive(bool active)
 
337
{
 
338
    if (m_active != active) {
 
339
        m_active = active;
 
340
        Q_EMIT activeChanged();
 
341
    }
 
342
}
 
343
 
 
344
// Because we are defining a new QObject-based class (ContentTimer) here.
 
345
#include "menucontentactivator.moc"