on aea520f help sign in
unity8/plugins/Unity/Indicators/menucontentactivator.cpp
344 lines 8.9 kB history raw
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 */
19 #include "menucontentactivator.h"
21// Essentially a QTimer wrapper
22class ContentTimer : public UnityIndicators::AbstractTimer
24 Q_OBJECT
25public:
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(); }
35private:
36 QTimer m_timer;
37};
39class MenuContentActivatorPrivate : public QObject
41 Q_OBJECT
42public:
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 {}
52 ~MenuContentActivatorPrivate()
53 {
54 qDeleteAll(m_content);
55 m_content.clear();
56 }
58 int findNextInactiveDelta(bool* finished = NULL);
60 static int content_count(QQmlListProperty<MenuContentState> *prop);
61 static MenuContentState* content_at(QQmlListProperty<MenuContentState> *prop, int index);
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};
72MenuContentActivator::MenuContentActivator(QObject* parent)
73 : QObject(parent),
74 d(new MenuContentActivatorPrivate(this))
76 qRegisterMetaType<QQmlListProperty<MenuContentState> > ("QQmlListProperty<MenuContentState>");
78 setContentTimer(new ContentTimer(this));
79 d->m_timer->setInterval(75);
82MenuContentActivator::~MenuContentActivator()
84 delete d;
87void MenuContentActivator::restart()
89 // when we start, make sure we have the base index in the list.
90 setMenuContentState(d->m_baseIndex, true);
91 setDelta(0);
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 }
102 if (!d->m_running) {
103 d->m_running = true;
104 Q_EMIT runningChanged(true);
105 }
108void MenuContentActivator::stop()
110 d->m_timer->stop();
111 if (!d->m_running) {
112 d->m_running = false;
113 Q_EMIT runningChanged(false);
114 }
117void MenuContentActivator::clear()
119 qDeleteAll(d->m_content);
120 d->m_content.clear();
122 setDelta(0);
123 d->m_timer->stop();
125 Q_EMIT contentChanged();
128bool MenuContentActivator::isMenuContentActive(int index) const
130 if (d->m_content.contains(index))
131 return d->m_content[index]->isActive();
132 return false;
135void MenuContentActivator::setRunning(bool running)
137 if (running) {
138 restart();
139 } else {
140 stop();
141 }
144bool MenuContentActivator::isRunning() const
146 return d->m_running;
149void MenuContentActivator::setBaseIndex(int index)
151 if (d->m_baseIndex != index) {
152 d->m_baseIndex = index;
154 if (isRunning()) {
155 restart();
156 }
158 Q_EMIT baseIndexChanged(index);
159 }
162int MenuContentActivator::baseIndex() const
164 return d->m_baseIndex;
167void MenuContentActivator::setCount(int count)
169 if (d->m_count != count) {
170 d->m_count = count;
171 Q_EMIT countChanged(count);
173 if (isRunning()) {
174 restart();
175 }
176 }
179int MenuContentActivator::count() const
181 return d->m_count;
184void MenuContentActivator::setDelta(int delta)
186 if (d->m_delta != delta) {
187 d->m_delta = delta;
188 Q_EMIT deltaChanged(d->m_delta);
189 }
192int MenuContentActivator::delta() const
194 return d->m_delta;
197QQmlListProperty<MenuContentState> MenuContentActivator::content()
199 return QQmlListProperty<MenuContentState>(this,
200 0,
201 MenuContentActivatorPrivate::content_count,
202 MenuContentActivatorPrivate::content_at);
205void MenuContentActivator::onTimeout()
207 bool finished = false;
208 int tempDelta = d->findNextInactiveDelta(&finished);
209 if (!finished) {
210 setMenuContentState(d->m_baseIndex + tempDelta, true);
211 setDelta(tempDelta);
212 }
214 if (finished) {
215 d->m_timer->stop();
216 }
219void MenuContentActivator::setContentTimer(UnityIndicators::AbstractTimer *timer)
221 int interval = 0;
222 bool timerWasRunning = false;
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 }
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 }
242void MenuContentActivator::setMenuContentState(int index, bool active)
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 }
252int MenuContentActivatorPrivate::findNextInactiveDelta(bool* finished)
254 if (m_count == 0 || m_baseIndex >= m_count) {
255 if (finished) *finished = true;
256 return 0;
257 }
259 int tmpDelta = m_delta;
260 bool topReached = false, bottomReached = false;
261 while(true) {
263 // prechecks for bottom and top limits.
264 if (tmpDelta > 0 && bottomReached) tmpDelta = -tmpDelta;
265 if (tmpDelta < 0 && topReached) tmpDelta = (-tmpDelta) + 1;
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 }
295 if (q->isMenuContentActive(m_baseIndex + tmpDelta)) {
296 continue;
297 }
298 break;
299 }
300 if (finished) *finished = false;
301 return tmpDelta;
304int MenuContentActivatorPrivate::content_count(QQmlListProperty<MenuContentState> *prop)
306 MenuContentActivator *p = qobject_cast<MenuContentActivator*>(prop->object);
307 // we'll create MenuContentState on demand.
308 return p->count();
311MenuContentState* MenuContentActivatorPrivate::content_at(QQmlListProperty<MenuContentState> *prop, int index)
313 MenuContentActivator *p = qobject_cast<MenuContentActivator*>(prop->object);
314 MenuContentActivatorPrivate *d = p->d;
316 if (!d->m_content.contains(index)) {
317 MenuContentState* content = new MenuContentState(false);
318 d->m_content[index] = content;
319 return content;
320 }
322 return d->m_content[index];
325MenuContentState::MenuContentState(bool active)
326 : m_active(active)
330bool MenuContentState::isActive() const
332 return m_active;
335void MenuContentState::setActive(bool active)
337 if (m_active != active) {
338 m_active = active;
339 Q_EMIT activeChanged();
340 }
343// Because we are defining a new QObject-based class (ContentTimer) here.
344#include "menucontentactivator.moc"