on xenial help sign in
Abstract class for Journals

Vertical and Horizontal Journal were copying lots of code, now they share it properly :-)

commit88916dd1153d763cbe0334dac6f99d1d195e43e5 authorAlbert Astals <albert.astals@canonical.com> dateFri 20 Dec 2013, 17:17 (13 years ago) parent7c80d8f
8 files changed+695−988
plugins/DashViews/CMakeLists.txt+1 plugins/DashViews/abstractjournal.cpp+393 plugins/DashViews/abstractjournal.h+145 plugins/DashViews/horizontaljournal.cpp+53−385 plugins/DashViews/horizontaljournal.h+12−91 plugins/DashViews/verticaljournal.cpp+74−417 plugins/DashViews/verticaljournal.h+13−91 tests/plugins/DashViews/CMakeLists.txt+4−4
plugins/DashViews/CMakeLists.txt+1
@@ -24,6 +24,7 @@ remove_definitions(-DQT_NO_KEYWORDS)
2424set(QMLPLUGIN_SRC
2525 plugin.cpp
2626 listviewwithpageheader.cpp
27+ abstractjournal.cpp
2728 verticaljournal.cpp
2829 horizontaljournal.cpp
2930 )
plugins/DashViews/abstractjournal.cppnew file+393
@@ -0,0 +1,393 @@
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+
17+/*
18+ * The implementation is centered around m_columnVisibleItems
19+ * that holds a vector of lists. There's a list for each of the
20+ * columns the view has. In the list the items of the column are
21+ * ordered as they appear topdown in the view. m_indexColumnMap is
22+ * used when re-building the list up since given a position
23+ * in the middle of the list and the need to create the previous does
24+ * not give us enough information to know in which column we have
25+ * to position the item so that when we reach the item the view is
26+ * correctly layouted at 0 for all the columns
27+ */
28+
29+#include "abstractjournal.h"
30+
31+static const qreal bufferRatio = 0.5;
32+
33+AbstractJournal::AbstractJournal()
34+ : m_delegateModel(nullptr)
35+ , m_asyncRequestedIndex(-1)
36+ , m_columnSpacing(0)
37+ , m_rowSpacing(0)
38+ , m_delegateCreationBegin(0)
39+ , m_delegateCreationEnd(0)
40+ , m_delegateCreationBeginValid(false)
41+ , m_delegateCreationEndValid(false)
42+ , m_needsRelayout(false)
43+ , m_delegateValidated(false)
44+ , m_implicitHeightDirty(false)
45+{
46+ connect(this, SIGNAL(widthChanged()), this, SLOT(relayout()));
47+ connect(this, SIGNAL(heightChanged()), this, SLOT(onHeightChanged()));
48+}
49+
50+QAbstractItemModel *AbstractJournal::model() const
51+{
52+ return m_delegateModel ? m_delegateModel->model().value<QAbstractItemModel *>() : nullptr;
53+}
54+
55+void AbstractJournal::setModel(QAbstractItemModel *model)
56+{
57+ if (model != this->model()) {
58+ if (!m_delegateModel) {
59+ createDelegateModel();
60+ } else {
61+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
62+ disconnect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
63+ }
64+ m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
65+ connect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
66+#else
67+ disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
68+ }
69+ m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
70+ connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
71+#endif
72+
73+ cleanupExistingItems();
74+
75+ Q_EMIT modelChanged();
76+ polish();
77+ }
78+}
79+
80+QQmlComponent *AbstractJournal::delegate() const
81+{
82+ return m_delegateModel ? m_delegateModel->delegate() : nullptr;
83+}
84+
85+void AbstractJournal::setDelegate(QQmlComponent *delegate)
86+{
87+ if (delegate != this->delegate()) {
88+ if (!m_delegateModel) {
89+ createDelegateModel();
90+ }
91+
92+ cleanupExistingItems();
93+
94+ m_delegateModel->setDelegate(delegate);
95+
96+ Q_EMIT delegateChanged();
97+ m_delegateValidated = false;
98+ polish();
99+ }
100+}
101+
102+qreal AbstractJournal::columnSpacing() const
103+{
104+ return m_columnSpacing;
105+}
106+
107+void AbstractJournal::setColumnSpacing(qreal columnSpacing)
108+{
109+ if (columnSpacing != m_columnSpacing) {
110+ m_columnSpacing = columnSpacing;
111+ Q_EMIT columnSpacingChanged();
112+
113+ if (isComponentComplete()) {
114+ relayout();
115+ }
116+ }
117+}
118+
119+qreal AbstractJournal::rowSpacing() const
120+{
121+ return m_rowSpacing;
122+}
123+
124+void AbstractJournal::setRowSpacing(qreal rowSpacing)
125+{
126+ if (rowSpacing != m_rowSpacing) {
127+ m_rowSpacing = rowSpacing;
128+ Q_EMIT rowSpacingChanged();
129+
130+ if (isComponentComplete()) {
131+ relayout();
132+ }
133+ }
134+}
135+
136+qreal AbstractJournal::delegateCreationBegin() const
137+{
138+ return m_delegateCreationBegin;
139+}
140+
141+void AbstractJournal::setDelegateCreationBegin(qreal begin)
142+{
143+ m_delegateCreationBeginValid = true;
144+ if (m_delegateCreationBegin == begin)
145+ return;
146+ m_delegateCreationBegin = begin;
147+ if (isComponentComplete()) {
148+ polish();
149+ }
150+ emit delegateCreationBeginChanged();
151+}
152+
153+void AbstractJournal::resetDelegateCreationBegin()
154+{
155+ m_delegateCreationBeginValid = false;
156+ if (m_delegateCreationBegin == 0)
157+ return;
158+ m_delegateCreationBegin = 0;
159+ if (isComponentComplete()) {
160+ polish();
161+ }
162+ emit delegateCreationBeginChanged();
163+}
164+
165+qreal AbstractJournal::delegateCreationEnd() const
166+{
167+ return m_delegateCreationEnd;
168+}
169+
170+void AbstractJournal::setDelegateCreationEnd(qreal end)
171+{
172+ m_delegateCreationEndValid = true;
173+ if (m_delegateCreationEnd == end)
174+ return;
175+ m_delegateCreationEnd = end;
176+ if (isComponentComplete()) {
177+ polish();
178+ }
179+ emit delegateCreationEndChanged();
180+}
181+
182+void AbstractJournal::resetDelegateCreationEnd()
183+{
184+ m_delegateCreationEndValid = false;
185+ if (m_delegateCreationEnd == 0)
186+ return;
187+ m_delegateCreationEnd = 0;
188+ if (isComponentComplete()) {
189+ polish();
190+ }
191+ emit delegateCreationEndChanged();
192+}
193+
194+void AbstractJournal::createDelegateModel()
195+{
196+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
197+ m_delegateModel = new QQuickVisualDataModel(qmlContext(this), this);
198+ connect(m_delegateModel, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(itemCreated(int,QQuickItem*)));
199+#else
200+ m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
201+ connect(m_delegateModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(itemCreated(int,QObject*)));
202+#endif
203+ if (isComponentComplete())
204+ m_delegateModel->componentComplete();
205+}
206+
207+void AbstractJournal::refill()
208+{
209+ if (!isComponentComplete()) {
210+ return;
211+ }
212+
213+ const bool delegateRangesValid = m_delegateCreationBeginValid && m_delegateCreationEndValid;
214+ const qreal from = delegateRangesValid ? m_delegateCreationBegin : 0;
215+ const qreal to = delegateRangesValid ? m_delegateCreationEnd : from + height();
216+ const qreal buffer = (to - from) * bufferRatio;
217+ const qreal bufferFrom = from - buffer;
218+ const qreal bufferTo = to + buffer;
219+
220+ bool added = addVisibleItems(from, to, false);
221+ bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
222+ added |= addVisibleItems(bufferFrom, bufferTo, true);
223+
224+ if (added || removed) {
225+ m_implicitHeightDirty = true;
226+ }
227+}
228+
229+bool AbstractJournal::addVisibleItems(qreal fillFrom, qreal fillTo, bool asynchronous)
230+{
231+ if (!delegate())
232+ return false;
233+
234+ if (m_delegateModel->count() == 0)
235+ return false;
236+
237+ int modelIndex;
238+ qreal yPos;
239+ findBottomModelIndexToAdd(&modelIndex, &yPos);
240+ bool changed = false;
241+ while (modelIndex < m_delegateModel->count() && yPos <= fillTo) {
242+ if (!createItem(modelIndex, asynchronous))
243+ break;
244+
245+ changed = true;
246+ findBottomModelIndexToAdd(&modelIndex, &yPos);
247+ }
248+
249+ findTopModelIndexToAdd(&modelIndex, &yPos);
250+ while (modelIndex >= 0 && yPos > fillFrom) {
251+ if (!createItem(modelIndex, asynchronous))
252+ break;
253+
254+ changed = true;
255+ findTopModelIndexToAdd(&modelIndex, &yPos);
256+ }
257+
258+ return changed;
259+}
260+
261+QQuickItem *AbstractJournal::createItem(int modelIndex, bool asynchronous)
262+{
263+ if (asynchronous && m_asyncRequestedIndex != -1)
264+ return nullptr;
265+
266+ m_asyncRequestedIndex = -1;
267+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
268+ QQuickItem *item = m_delegateModel->item(modelIndex, asynchronous);
269+#else
270+ QObject* object = m_delegateModel->object(modelIndex, asynchronous);
271+ QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
272+#endif
273+ if (!item) {
274+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
275+ m_asyncRequestedIndex = modelIndex;
276+#else
277+ if (object) {
278+ m_delegateModel->release(object);
279+ if (!m_delegateValidated) {
280+ m_delegateValidated = true;
281+ QObject* delegateObj = delegate();
282+ qmlInfo(delegateObj ? delegateObj : this) << "Delegate must be of Item type";
283+ }
284+ } else {
285+ m_asyncRequestedIndex = modelIndex;
286+ }
287+#endif
288+ return nullptr;
289+ } else {
290+ positionItem(modelIndex, item);
291+ return item;
292+ }
293+}
294+
295+void AbstractJournal::releaseItem(QQuickItem *item)
296+{
297+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
298+ QQuickVisualModel::ReleaseFlags flags = m_delegateModel->release(item);
299+ if (flags & QQuickVisualModel::Destroyed) {
300+#else
301+ QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
302+ if (flags & QQmlDelegateModel::Destroyed) {
303+#endif
304+ item->setParentItem(nullptr);
305+ }
306+}
307+
308+void AbstractJournal::setImplicitHeightDirty()
309+{
310+ m_implicitHeightDirty = true;
311+}
312+
313+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
314+void AbstractJournal::itemCreated(int modelIndex, QQuickItem *item)
315+{
316+#else
317+void AbstractJournal::itemCreated(int modelIndex, QObject *object)
318+{
319+ QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
320+ if (!item) {
321+ qWarning() << "AbstractJournal::itemCreated got a non item for index" << modelIndex;
322+ return;
323+ }
324+#endif
325+ item->setParentItem(this);
326+ if (modelIndex == m_asyncRequestedIndex) {
327+ createItem(modelIndex, false);
328+ m_implicitHeightDirty = true;
329+ polish();
330+ }
331+}
332+
333+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
334+void AbstractJournal::onModelUpdated(const QQuickChangeSet &changeSet, bool reset)
335+#else
336+void AbstractJournal::onModelUpdated(const QQmlChangeSet &changeSet, bool reset)
337+#endif
338+{
339+ if (reset) {
340+ cleanupExistingItems();
341+ } else {
342+ processModelRemoves(changeSet.removes());
343+ }
344+ polish();
345+}
346+
347+
348+void AbstractJournal::relayout()
349+{
350+ m_needsRelayout = true;
351+ polish();
352+}
353+
354+void AbstractJournal::onHeightChanged()
355+{
356+ polish();
357+}
358+
359+void AbstractJournal::updatePolish()
360+{
361+ if (!model())
362+ return;
363+
364+ if (m_needsRelayout) {
365+ doRelayout();
366+ m_needsRelayout = false;
367+ m_implicitHeightDirty = true;
368+ }
369+
370+ refill();
371+
372+ const bool delegateRangesValid = m_delegateCreationBeginValid && m_delegateCreationEndValid;
373+ const qreal from = delegateRangesValid ? m_delegateCreationBegin : 0;
374+ const qreal to = delegateRangesValid ? m_delegateCreationEnd : from + height();
375+ updateItemCulling(from, to);
376+
377+ if (m_implicitHeightDirty) {
378+ calculateImplicitHeight();
379+ m_implicitHeightDirty = false;
380+ }
381+}
382+
383+void AbstractJournal::componentComplete()
384+{
385+ if (m_delegateModel)
386+ m_delegateModel->componentComplete();
387+
388+ QQuickItem::componentComplete();
389+
390+ m_needsRelayout = true;
391+
392+ polish();
393+}
plugins/DashViews/abstractjournal.hnew file+145
@@ -0,0 +1,145 @@
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+
17+#ifndef ABSTRACTJOURNAL_H
18+#define ABSTRACTJOURNAL_H
19+
20+#include <QQuickItem>
21+
22+class QAbstractItemModel;
23+class QQmlComponent;
24+#pragma GCC diagnostic push
25+#pragma GCC diagnostic ignored "-pedantic"
26+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
27+#include <private/qquickvisualdatamodel_p.h>
28+#else
29+#include <private/qqmldelegatemodel_p.h>
30+#include <qqmlinfo.h>
31+#endif
32+#pragma GCC diagnostic pop
33+
34+class AbstractJournal : public QQuickItem
35+{
36+ Q_OBJECT
37+
38+ Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged)
39+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
40+ Q_PROPERTY(qreal columnSpacing READ columnSpacing WRITE setColumnSpacing NOTIFY columnSpacingChanged)
41+ Q_PROPERTY(qreal rowSpacing READ rowSpacing WRITE setRowSpacing NOTIFY rowSpacingChanged)
42+ Q_PROPERTY(qreal delegateCreationBegin READ delegateCreationBegin
43+ WRITE setDelegateCreationBegin
44+ NOTIFY delegateCreationBeginChanged
45+ RESET resetDelegateCreationBegin)
46+ Q_PROPERTY(qreal delegateCreationEnd READ delegateCreationEnd
47+ WRITE setDelegateCreationEnd
48+ NOTIFY delegateCreationEndChanged
49+ RESET resetDelegateCreationEnd)
50+
51+friend class VerticalJournalTest;
52+friend class HorizontalJournalTest;
53+
54+public:
55+ AbstractJournal();
56+
57+ QAbstractItemModel *model() const;
58+ void setModel(QAbstractItemModel *model);
59+
60+ QQmlComponent *delegate() const;
61+ void setDelegate(QQmlComponent *delegate);
62+
63+ qreal columnSpacing() const;
64+ void setColumnSpacing(qreal columnSpacing);
65+
66+ qreal rowSpacing() const;
67+ void setRowSpacing(qreal rowSpacing);
68+
69+ qreal delegateCreationBegin() const;
70+ void setDelegateCreationBegin(qreal);
71+ void resetDelegateCreationBegin();
72+
73+ qreal delegateCreationEnd() const;
74+ void setDelegateCreationEnd(qreal);
75+ void resetDelegateCreationEnd();
76+
77+Q_SIGNALS:
78+ void modelChanged();
79+ void delegateChanged();
80+ void columnSpacingChanged();
81+ void rowSpacingChanged();
82+ void delegateCreationBeginChanged();
83+ void delegateCreationEndChanged();
84+
85+protected Q_SLOTS:
86+ void relayout();
87+
88+protected:
89+ void updatePolish() override;
90+ void componentComplete() override;
91+
92+ void releaseItem(QQuickItem *item);
93+ void setImplicitHeightDirty();
94+
95+private Q_SLOTS:
96+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
97+ void itemCreated(int modelIndex, QQuickItem *item);
98+ void onModelUpdated(const QQuickChangeSet &changeSet, bool reset);
99+#else
100+ void itemCreated(int modelIndex, QObject *object);
101+ void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
102+#endif
103+ void onHeightChanged();
104+
105+private:
106+ void createDelegateModel();
107+ void refill();
108+ bool addVisibleItems(qreal fillFrom, qreal fillTo, bool asynchronous);
109+ QQuickItem *createItem(int modelIndex, bool asynchronous);
110+
111+ virtual void findBottomModelIndexToAdd(int *modelIndex, qreal *yPos) = 0;
112+ virtual void findTopModelIndexToAdd(int *modelIndex, qreal *yPos) = 0;
113+ virtual void positionItem(int modelIndex, QQuickItem *item) = 0;
114+ virtual bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) = 0;
115+ virtual void cleanupExistingItems() = 0;
116+ virtual void doRelayout() = 0;
117+ virtual void updateItemCulling(qreal visibleFrom, qreal visibleTo) = 0;
118+ virtual void calculateImplicitHeight() = 0;
119+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
120+ virtual void processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes) = 0;
121+#else
122+ virtual void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) = 0;
123+#endif
124+
125+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
126+ QQuickVisualDataModel *m_delegateModel;
127+#else
128+ QQmlDelegateModel *m_delegateModel;
129+#endif
130+
131+ // Index we are waiting because we requested it asynchronously
132+ int m_asyncRequestedIndex;
133+
134+ int m_columnSpacing;
135+ int m_rowSpacing;
136+ qreal m_delegateCreationBegin;
137+ qreal m_delegateCreationEnd;
138+ bool m_delegateCreationBeginValid;
139+ bool m_delegateCreationEndValid;
140+ bool m_needsRelayout;
141+ bool m_delegateValidated;
142+ bool m_implicitHeightDirty;
143+};
144+
145+#endif
plugins/DashViews/horizontaljournal.cpp+53−385
@@ -43,74 +43,9 @@
4343static const qreal bufferRatio = 0.5;
4444
4545HorizontalJournal::HorizontalJournal()
46− : m_delegateModel(nullptr)
47− , m_asyncRequestedIndex(-1)
48− , m_firstVisibleIndex(-1)
46+ : m_firstVisibleIndex(-1)
4947 , m_rowHeight(0)
50− , m_columnSpacing(0)
51− , m_rowSpacing(0)
52− , m_delegateCreationBegin(0)
53− , m_delegateCreationEnd(0)
54− , m_delegateCreationBeginValid(false)
55− , m_delegateCreationEndValid(false)
56− , m_needsRelayout(false)
57− , m_delegateValidated(false)
58− , m_implicitHeightDirty(false)
5948{
60− connect(this, SIGNAL(widthChanged()), this, SLOT(relayout()));
61− connect(this, SIGNAL(heightChanged()), this, SLOT(onHeightChanged()));
62−}
63−
64−QAbstractItemModel *HorizontalJournal::model() const
65−{
66− return m_delegateModel ? m_delegateModel->model().value<QAbstractItemModel *>() : nullptr;
67−}
68−
69−void HorizontalJournal::setModel(QAbstractItemModel *model)
70−{
71− if (model != this->model()) {
72− if (!m_delegateModel) {
73− createDelegateModel();
74− } else {
75−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
76− disconnect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
77− }
78− m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
79− connect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
80−#else
81− disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
82− }
83− m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
84− connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
85−#endif
86−
87− cleanupExistingItems();
88−
89− Q_EMIT modelChanged();
90− polish();
91− }
92−}
93−
94−QQmlComponent *HorizontalJournal::delegate() const
95−{
96− return m_delegateModel ? m_delegateModel->delegate() : nullptr;
97−}
98−
99−void HorizontalJournal::setDelegate(QQmlComponent *delegate)
100−{
101− if (delegate != this->delegate()) {
102− if (!m_delegateModel) {
103− createDelegateModel();
104− }
105−
106− cleanupExistingItems();
107−
108− m_delegateModel->setDelegate(delegate);
109−
110− Q_EMIT delegateChanged();
111− m_delegateValidated = false;
112− polish();
113− }
11449}
11550
11651qreal HorizontalJournal::rowHeight() const
@@ -133,133 +68,6 @@ void HorizontalJournal::setRowHeight(qreal rowHeight)
13368 }
13469}
13570
136−qreal HorizontalJournal::columnSpacing() const
137−{
138− return m_columnSpacing;
139−}
140−
141−void HorizontalJournal::setColumnSpacing(qreal columnSpacing)
142−{
143− if (columnSpacing != m_columnSpacing) {
144− m_columnSpacing = columnSpacing;
145− Q_EMIT columnSpacingChanged();
146−
147− if (isComponentComplete()) {
148− relayout();
149− }
150− }
151−}
152−
153−qreal HorizontalJournal::rowSpacing() const
154−{
155− return m_rowSpacing;
156−}
157−
158−void HorizontalJournal::setRowSpacing(qreal rowSpacing)
159−{
160− if (rowSpacing != m_rowSpacing) {
161− m_rowSpacing = rowSpacing;
162− Q_EMIT rowSpacingChanged();
163−
164− if (isComponentComplete()) {
165− relayout();
166− }
167− }
168−}
169−
170−qreal HorizontalJournal::delegateCreationBegin() const
171−{
172− return m_delegateCreationBegin;
173−}
174−
175−void HorizontalJournal::setDelegateCreationBegin(qreal begin)
176−{
177− m_delegateCreationBeginValid = true;
178− if (m_delegateCreationBegin == begin)
179− return;
180− m_delegateCreationBegin = begin;
181− if (isComponentComplete()) {
182− polish();
183− }
184− emit delegateCreationBeginChanged();
185−}
186−
187−void HorizontalJournal::resetDelegateCreationBegin()
188−{
189− m_delegateCreationBeginValid = false;
190− if (m_delegateCreationBegin == 0)
191− return;
192− m_delegateCreationBegin = 0;
193− if (isComponentComplete()) {
194− polish();
195− }
196− emit delegateCreationBeginChanged();
197−}
198−
199−qreal HorizontalJournal::delegateCreationEnd() const
200−{
201− return m_delegateCreationEnd;
202−}
203−
204−void HorizontalJournal::setDelegateCreationEnd(qreal end)
205−{
206− m_delegateCreationEndValid = true;
207− if (m_delegateCreationEnd == end)
208− return;
209− m_delegateCreationEnd = end;
210− if (isComponentComplete()) {
211− polish();
212− }
213− emit delegateCreationEndChanged();
214−}
215−
216−void HorizontalJournal::resetDelegateCreationEnd()
217−{
218− m_delegateCreationEndValid = false;
219− if (m_delegateCreationEnd == 0)
220− return;
221− m_delegateCreationEnd = 0;
222− if (isComponentComplete()) {
223− polish();
224− }
225− emit delegateCreationEndChanged();
226−}
227−
228−void HorizontalJournal::createDelegateModel()
229−{
230−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
231− m_delegateModel = new QQuickVisualDataModel(qmlContext(this), this);
232− connect(m_delegateModel, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(itemCreated(int,QQuickItem*)));
233−#else
234− m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
235− connect(m_delegateModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(itemCreated(int,QObject*)));
236−#endif
237− if (isComponentComplete())
238− m_delegateModel->componentComplete();
239−}
240−
241−void HorizontalJournal::refill()
242−{
243− if (!isComponentComplete()) {
244− return;
245− }
246−
247− const bool delegateRangesValid = m_delegateCreationBeginValid && m_delegateCreationEndValid;
248− const qreal from = delegateRangesValid ? m_delegateCreationBegin : 0;
249− const qreal to = delegateRangesValid ? m_delegateCreationEnd : from + height();
250− const qreal buffer = (to - from) * bufferRatio;
251− const qreal bufferFrom = from - buffer;
252− const qreal bufferTo = to + buffer;
253−
254− bool added = addVisibleItems(from, to, false);
255− bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
256− added |= addVisibleItems(bufferFrom, bufferTo, true);
257−
258− if (added || removed) {
259− m_implicitHeightDirty = true;
260− }
261−}
262−
26371void HorizontalJournal::findBottomModelIndexToAdd(int *modelIndex, double *yPos)
26472{
26573 if (m_visibleItems.isEmpty()) {
@@ -268,7 +76,7 @@ void HorizontalJournal::findBottomModelIndexToAdd(int *modelIndex, double *yPos)
26876 } else {
26977 *modelIndex = m_firstVisibleIndex + m_visibleItems.count();
27078 if (m_lastInRowIndexPosition.contains(*modelIndex - 1)) {
271− *yPos = m_visibleItems.last()->y() + m_rowHeight + m_rowSpacing;
79+ *yPos = m_visibleItems.last()->y() + m_rowHeight + rowSpacing();
27280 } else {
27381 *yPos = m_visibleItems.last()->y();
27482 }
@@ -283,45 +91,13 @@ void HorizontalJournal::findTopModelIndexToAdd(int *modelIndex, double *yPos)
28391 } else {
28492 *modelIndex = m_firstVisibleIndex - 1;
28593 if (m_lastInRowIndexPosition.contains(*modelIndex)) {
286− *yPos = m_visibleItems.first()->y() - m_rowSpacing - m_rowHeight;
94+ *yPos = m_visibleItems.first()->y() - rowSpacing() - m_rowHeight;
28795 } else {
28896 *yPos = m_visibleItems.first()->y();
28997 }
29098 }
29199}
292100
293−bool HorizontalJournal::addVisibleItems(qreal fillFrom, qreal fillTo, bool asynchronous)
294−{
295− if (!delegate())
296− return false;
297−
298− if (m_delegateModel->count() == 0)
299− return false;
300−
301− int modelIndex;
302− qreal yPos;
303− findBottomModelIndexToAdd(&modelIndex, &yPos);
304− bool changed = false;
305− while (modelIndex < m_delegateModel->count() && yPos <= fillTo) {
306− if (!createItem(modelIndex, asynchronous))
307− break;
308−
309− changed = true;
310− findBottomModelIndexToAdd(&modelIndex, &yPos);
311− }
312−
313− findTopModelIndexToAdd(&modelIndex, &yPos);
314− while (modelIndex >= 0 && yPos > fillFrom) {
315− if (!createItem(modelIndex, asynchronous))
316− break;
317−
318− changed = true;
319− findTopModelIndexToAdd(&modelIndex, &yPos);
320− }
321−
322− return changed;
323−}
324−
325101bool HorizontalJournal::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
326102{
327103 bool changed = false;
@@ -345,46 +121,13 @@ bool HorizontalJournal::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
345121 return changed;
346122}
347123
348−QQuickItem *HorizontalJournal::createItem(int modelIndex, bool asynchronous)
124+void HorizontalJournal::positionItem(int modelIndex, QQuickItem *item)
349125{
350− if (asynchronous && m_asyncRequestedIndex != -1)
351− return nullptr;
352−
353− m_asyncRequestedIndex = -1;
354−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
355− QQuickItem *item = m_delegateModel->item(modelIndex, asynchronous);
356−#else
357− QObject* object = m_delegateModel->object(modelIndex, asynchronous);
358− QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
359−#endif
360− if (!item) {
361−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
362− m_asyncRequestedIndex = modelIndex;
363−#else
364− if (object) {
365− m_delegateModel->release(object);
366− if (!m_delegateValidated) {
367− m_delegateValidated = true;
368− QObject* delegateObj = delegate();
369− qmlInfo(delegateObj ? delegateObj : this) << "Delegate must be of Item type";
370− }
371− } else {
372− m_asyncRequestedIndex = modelIndex;
373− }
374−#endif
375− return nullptr;
376− } else {
377− if (item->height() != m_rowHeight) {
378− qWarning() << "Item" << modelIndex << "height is not the one that the rowHeight mandates, resetting it";
379− item->setHeight(m_rowHeight);
380− }
381− positionItem(modelIndex, item);
382− return item;
126+ if (item->height() != m_rowHeight) {
127+ qWarning() << "Item" << modelIndex << "height is not the one that the rowHeight mandates, resetting it";
128+ item->setHeight(m_rowHeight);
383129 }
384−}
385130
386−void HorizontalJournal::positionItem(int modelIndex, QQuickItem *item)
387−{
388131 if (m_visibleItems.isEmpty()) {
389132 Q_ASSERT(modelIndex == 0);
390133 item->setY(0);
@@ -395,13 +138,13 @@ void HorizontalJournal::positionItem(int modelIndex, QQuickItem *item)
395138 // modelIndex has to be either m_firstVisibleIndex - 1 or m_firstVisibleIndex + m_visibleItems.count()
396139 if (modelIndex == m_firstVisibleIndex + m_visibleItems.count()) {
397140 QQuickItem *lastItem = m_visibleItems.last();
398− if (lastItem->x() + lastItem->width() + m_columnSpacing + item->width() <= width()) {
141+ if (lastItem->x() + lastItem->width() + columnSpacing() + item->width() <= width()) {
399142 // Fits in the row
400143 item->setY(lastItem->y());
401− item->setX(lastItem->x() + lastItem->width() + m_columnSpacing);
144+ item->setX(lastItem->x() + lastItem->width() + columnSpacing());
402145 } else {
403146 // Starts a new row
404− item->setY(lastItem->y() + m_rowHeight + m_rowSpacing);
147+ item->setY(lastItem->y() + m_rowHeight + rowSpacing());
405148 item->setX(0);
406149 m_lastInRowIndexPosition[modelIndex - 1] = lastItem->x();
407150 }
@@ -410,11 +153,11 @@ void HorizontalJournal::positionItem(int modelIndex, QQuickItem *item)
410153 QQuickItem *firstItem = m_visibleItems.first();
411154 if (m_lastInRowIndexPosition.contains(modelIndex)) {
412155 // It is the last item of its row, so start a new one since we're going back
413− item->setY(firstItem->y() - m_rowSpacing - m_rowHeight);
156+ item->setY(firstItem->y() - rowSpacing() - m_rowHeight);
414157 item->setX(m_lastInRowIndexPosition[modelIndex]);
415158 } else {
416159 item->setY(firstItem->y());
417− item->setX(firstItem->x() - m_columnSpacing - item->width());
160+ item->setX(firstItem->x() - columnSpacing() - item->width());
418161 }
419162 m_firstVisibleIndex = modelIndex;
420163 m_visibleItems.prepend(item);
@@ -434,23 +177,8 @@ void HorizontalJournal::cleanupExistingItems()
434177 m_firstVisibleIndex = 0;
435178}
436179
437−void HorizontalJournal::releaseItem(QQuickItem *item)
438−{
439−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
440− QQuickVisualModel::ReleaseFlags flags = m_delegateModel->release(item);
441− if (flags & QQuickVisualModel::Destroyed) {
442−#else
443− QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
444− if (flags & QQmlDelegateModel::Destroyed) {
445−#endif
446− item->setParentItem(nullptr);
447− }
448−}
449−
450180void HorizontalJournal::calculateImplicitHeight()
451181{
452− m_implicitHeightDirty = false;
453−
454182 if (m_firstVisibleIndex >= 0) {
455183 const int nIndexes = m_firstVisibleIndex + m_visibleItems.count();
456184 const double bottomMostY = m_visibleItems.last()->y() + m_rowHeight;
@@ -462,126 +190,66 @@ void HorizontalJournal::calculateImplicitHeight()
462190}
463191
464192#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
465−void HorizontalJournal::itemCreated(int modelIndex, QQuickItem *item)
466−{
467−#else
468−void HorizontalJournal::itemCreated(int modelIndex, QObject *object)
469−{
470− QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
471− if (!item) {
472− qWarning() << "HorizontalJournal::itemCreated got a non item for index" << modelIndex;
473− return;
474− }
475−#endif
476− item->setParentItem(this);
477− if (modelIndex == m_asyncRequestedIndex) {
478− createItem(modelIndex, false);
479− m_implicitHeightDirty = true;
480− polish();
481− }
482−}
483−
484−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
485−void HorizontalJournal::onModelUpdated(const QQuickChangeSet &changeSet, bool reset)
193+void HorizontalJournal::processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes)
486194#else
487−void HorizontalJournal::onModelUpdated(const QQmlChangeSet &changeSet, bool reset)
195+void HorizontalJournal::processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes)
488196#endif
489197{
490− if (reset) {
491− cleanupExistingItems();
492− } else {
493198#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
494− Q_FOREACH(const QQuickChangeSet::Remove &remove, changeSet.removes()) {
199+ Q_FOREACH(const QQuickChangeSet::Remove &remove, removes) {
495200#else
496− Q_FOREACH(const QQmlChangeSet::Remove &remove, changeSet.removes()) {
201+ Q_FOREACH(const QQmlChangeSet::Remove &remove, removes) {
497202#endif
498− for (int i = remove.count - 1; i >= 0; --i) {
499− const int indexToRemove = remove.index + i;
500− // We only support removing from the end so
501− // any of the last items of a column has to be indexToRemove
502− const int lastIndex = m_firstVisibleIndex + m_visibleItems.count() - 1;
503− if (indexToRemove == lastIndex) {
504− releaseItem(m_visibleItems.takeLast());
505− m_lastInRowIndexPosition.remove(indexToRemove);
203+ for (int i = remove.count - 1; i >= 0; --i) {
204+ const int indexToRemove = remove.index + i;
205+ // We only support removing from the end so
206+ // any of the last items of a column has to be indexToRemove
207+ const int lastIndex = m_firstVisibleIndex + m_visibleItems.count() - 1;
208+ if (indexToRemove == lastIndex) {
209+ releaseItem(m_visibleItems.takeLast());
210+ m_lastInRowIndexPosition.remove(indexToRemove);
211+ } else {
212+ if (indexToRemove < lastIndex) {
213+ qFatal("HorizontalJournal only supports removal from the end of the model");
506214 } else {
507− if (indexToRemove < lastIndex) {
508− qFatal("HorizontalJournal only supports removal from the end of the model");
509− } else {
510− m_implicitHeightDirty = true;
511− }
215+ setImplicitHeightDirty();
512216 }
513217 }
514218 }
515− if (m_visibleItems.isEmpty()) {
516− m_firstVisibleIndex = -1;
517− }
518219 }
519− polish();
520−}
521−
522−void HorizontalJournal::relayout()
523−{
524− m_needsRelayout = true;
525− polish();
220+ if (m_visibleItems.isEmpty()) {
221+ m_firstVisibleIndex = -1;
222+ }
526223}
527224
528−void HorizontalJournal::onHeightChanged()
529−{
530− polish();
531−}
532225
533−void HorizontalJournal::updatePolish()
226+void HorizontalJournal::doRelayout()
534227{
535− if (!model())
536− return;
228+ // If m_firstVisibleIndex is not 0 we need to drop all the delegates
229+ // since we can't consistently relayout without the first item being there
537230
538− if (m_needsRelayout) {
539− // If m_firstVisibleIndex is not 0 we need to drop all the delegates
540− // since we can't consistently relayout without the first item being there
541−
542− if (m_firstVisibleIndex == 0) {
543− int i = 0;
544− const QList<QQuickItem*> allItems = m_visibleItems;
545− m_visibleItems.clear();
546− m_lastInRowIndexPosition.clear();
547− Q_FOREACH(QQuickItem *item, allItems) {
548− positionItem(i, item);
549− ++i;
550− }
551− } else {
552− Q_FOREACH(QQuickItem *item, m_visibleItems) {
553− releaseItem(item);
554− }
555− m_visibleItems.clear();
556− m_lastInRowIndexPosition.clear();
557− m_firstVisibleIndex = 0;
231+ if (m_firstVisibleIndex == 0) {
232+ int i = 0;
233+ const QList<QQuickItem*> allItems = m_visibleItems;
234+ m_visibleItems.clear();
235+ m_lastInRowIndexPosition.clear();
236+ Q_FOREACH(QQuickItem *item, allItems) {
237+ positionItem(i, item);
238+ ++i;
558239 }
559−
560− m_needsRelayout = false;
561− }
562−
563− refill();
564−
565− const bool delegateRangesValid = m_delegateCreationBeginValid && m_delegateCreationEndValid;
566− const qreal from = delegateRangesValid ? m_delegateCreationBegin : 0;
567− const qreal to = delegateRangesValid ? m_delegateCreationEnd : from + height();
568− Q_FOREACH(QQuickItem *item, m_visibleItems) {
569− QQuickItemPrivate::get(item)->setCulled(item->y() + m_rowHeight <= from || item->y() >= to);
570− }
571−
572− if (m_implicitHeightDirty) {
573− calculateImplicitHeight();
240+ } else {
241+ Q_FOREACH(QQuickItem *item, m_visibleItems) {
242+ releaseItem(item);
243+ }
244+ m_visibleItems.clear();
245+ m_lastInRowIndexPosition.clear();
246+ m_firstVisibleIndex = 0;
574247 }
575248}
576249
577−void HorizontalJournal::componentComplete()
250+void HorizontalJournal::updateItemCulling(qreal visibleFrom, qreal visibleTo)
578251{
579− if (m_delegateModel)
580− m_delegateModel->componentComplete();
581−
582− QQuickItem::componentComplete();
583−
584− m_needsRelayout = true;
585−
586− polish();
252+ Q_FOREACH(QQuickItem *item, m_visibleItems) {
253+ QQuickItemPrivate::get(item)->setCulled(item->y() + m_rowHeight <= visibleFrom || item->y() >= visibleTo);
254+ }
587255}
plugins/DashViews/horizontaljournal.h+12−91
@@ -17,17 +17,7 @@
1717#ifndef HORIZONTALJOURNAL_H
1818#define HORIZONTALJOURNAL_H
1919
20−#include <QQuickItem>
21−
22−class QAbstractItemModel;
23−class QQmlComponent;
24−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
25−class QQuickChangeSet;
26−class QQuickVisualDataModel;
27−#else
28−class QQmlChangeSet;
29−class QQmlDelegateModel;
30−#endif
20+#include "abstractjournal.h"
3121
3222 /** A horizontal journal is a view that creates delegates
3323 * based on a model and layouts them one after the other
@@ -36,111 +26,42 @@ class QQmlDelegateModel;
3626 *
3727 * All delegates are forced to rowHeight if they don't have it.
3828 */
39− class HorizontalJournal : public QQuickItem
29+ class HorizontalJournal : public AbstractJournal
4030{
4131 Q_OBJECT
4232
43− Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged)
44− Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
4533 Q_PROPERTY(qreal rowHeight READ rowHeight WRITE setRowHeight NOTIFY rowHeightChanged)
46− Q_PROPERTY(qreal columnSpacing READ columnSpacing WRITE setColumnSpacing NOTIFY columnSpacingChanged)
47− Q_PROPERTY(qreal rowSpacing READ rowSpacing WRITE setRowSpacing NOTIFY rowSpacingChanged)
48− Q_PROPERTY(qreal delegateCreationBegin READ delegateCreationBegin
49− WRITE setDelegateCreationBegin
50− NOTIFY delegateCreationBeginChanged
51− RESET resetDelegateCreationBegin)
52− Q_PROPERTY(qreal delegateCreationEnd READ delegateCreationEnd
53− WRITE setDelegateCreationEnd
54− NOTIFY delegateCreationEndChanged
55− RESET resetDelegateCreationEnd)
5634
5735friend class HorizontalJournalTest;
5836
5937public:
6038 HorizontalJournal();
6139
62− QAbstractItemModel *model() const;
63− void setModel(QAbstractItemModel *model);
64−
65− QQmlComponent *delegate() const;
66− void setDelegate(QQmlComponent *delegate);
67−
6840 qreal rowHeight() const;
6941 void setRowHeight(qreal rowHeight);
7042
71− qreal columnSpacing() const;
72− void setColumnSpacing(qreal columnSpacing);
73−
74− qreal rowSpacing() const;
75− void setRowSpacing(qreal rowSpacing);
76−
77− qreal delegateCreationBegin() const;
78− void setDelegateCreationBegin(qreal);
79− void resetDelegateCreationBegin();
80−
81− qreal delegateCreationEnd() const;
82− void setDelegateCreationEnd(qreal);
83− void resetDelegateCreationEnd();
84−
8543Q_SIGNALS:
86− void modelChanged();
87− void delegateChanged();
8844 void rowHeightChanged();
89− void columnSpacingChanged();
90− void rowSpacingChanged();
91− void delegateCreationBeginChanged();
92− void delegateCreationEndChanged();
93−
94−protected:
95− void updatePolish();
96− void componentComplete();
97−
98−private Q_SLOTS:
99−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
100− void itemCreated(int modelIndex, QQuickItem *item);
101− void onModelUpdated(const QQuickChangeSet &changeSet, bool reset);
102−#else
103− void itemCreated(int modelIndex, QObject *object);
104− void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
105−#endif
106− void relayout();
107− void onHeightChanged();
10845
10946private:
110− void createDelegateModel();
111− void refill();
112− void findBottomModelIndexToAdd(int *modelIndex, double *yPos);
113− void findTopModelIndexToAdd(int *modelIndex, double *yPos);
114− bool addVisibleItems(qreal fillFrom, qreal fillTo, bool asynchronous);
115− bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo);
116− QQuickItem *createItem(int modelIndex, bool asynchronous);
117− void positionItem(int modelIndex, QQuickItem *item);
118− void cleanupExistingItems();
119− void releaseItem(QQuickItem *item);
120− void calculateImplicitHeight();
121−
47+ void findBottomModelIndexToAdd(int *modelIndex, qreal *yPos) override;
48+ void findTopModelIndexToAdd(int *modelIndex, qreal *yPos) override;
49+ bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) override;
50+ void positionItem(int modelIndex, QQuickItem *item) override;
51+ void cleanupExistingItems() override;
52+ void calculateImplicitHeight() override;
53+ void doRelayout() override;
54+ void updateItemCulling(qreal visibleFrom, qreal visibleTo) override;
12255#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
123− QQuickVisualDataModel *m_delegateModel;
56+ void processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes) override;
12457#else
125− QQmlDelegateModel *m_delegateModel;
58+ void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) override;
12659#endif
12760
128− // Index we are waiting because we requested it asynchronously
129− int m_asyncRequestedIndex;
130−
13161 int m_firstVisibleIndex;
13262 QList<QQuickItem*> m_visibleItems;
13363 QMap<int, double> m_lastInRowIndexPosition;
13464 int m_rowHeight;
135− int m_columnSpacing;
136− int m_rowSpacing;
137− qreal m_delegateCreationBegin;
138− qreal m_delegateCreationEnd;
139− bool m_delegateCreationBeginValid;
140− bool m_delegateCreationEndValid;
141− bool m_needsRelayout;
142− bool m_delegateValidated;
143− bool m_implicitHeightDirty;
14465};
14566
14667#endif
plugins/DashViews/verticaljournal.cpp+74−417
@@ -27,88 +27,16 @@
2727 */
2828#include "verticaljournal.h"
2929
30−#include <qqmlengine.h>
3130#pragma GCC diagnostic push
3231#pragma GCC diagnostic ignored "-pedantic"
33−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
34−#include <private/qquickvisualdatamodel_p.h>
35−#else
36−#include <private/qqmldelegatemodel_p.h>
37−#include <qqmlinfo.h>
38−#endif
3932#include <private/qquickitem_p.h>
4033#pragma GCC diagnostic pop
4134
4235static const qreal bufferRatio = 0.5;
4336
4437VerticalJournal::VerticalJournal()
45− : m_delegateModel(nullptr)
46− , m_asyncRequestedIndex(-1)
47− , m_columnWidth(0)
48− , m_columnSpacing(0)
49− , m_rowSpacing(0)
50− , m_delegateCreationBegin(0)
51− , m_delegateCreationEnd(0)
52− , m_delegateCreationBeginValid(false)
53− , m_delegateCreationEndValid(false)
54− , m_needsRelayout(false)
55− , m_delegateValidated(false)
56− , m_implicitHeightDirty(false)
57−{
58− connect(this, SIGNAL(widthChanged()), this, SLOT(relayout()));
59− connect(this, SIGNAL(heightChanged()), this, SLOT(onHeightChanged()));
60−}
61−
62−QAbstractItemModel *VerticalJournal::model() const
38+ : m_columnWidth(0)
6339{
64− return m_delegateModel ? m_delegateModel->model().value<QAbstractItemModel *>() : nullptr;
65−}
66−
67−void VerticalJournal::setModel(QAbstractItemModel *model)
68−{
69− if (model != this->model()) {
70− if (!m_delegateModel) {
71− createDelegateModel();
72− } else {
73−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
74− disconnect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
75− }
76− m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
77− connect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
78−#else
79− disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
80− }
81− m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
82− connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
83−#endif
84−
85− cleanupExistingItems();
86−
87− Q_EMIT modelChanged();
88− polish();
89− }
90−}
91−
92−QQmlComponent *VerticalJournal::delegate() const
93−{
94− return m_delegateModel ? m_delegateModel->delegate() : nullptr;
95−}
96−
97−void VerticalJournal::setDelegate(QQmlComponent *delegate)
98−{
99− if (delegate != this->delegate()) {
100− if (!m_delegateModel) {
101− createDelegateModel();
102− }
103−
104− cleanupExistingItems();
105−
106− m_delegateModel->setDelegate(delegate);
107−
108− Q_EMIT delegateChanged();
109− m_delegateValidated = false;
110− polish();
111− }
11240}
11341
11442qreal VerticalJournal::columnWidth() const
@@ -133,133 +61,6 @@ void VerticalJournal::setColumnWidth(qreal columnWidth)
13361 }
13462}
13563
136−qreal VerticalJournal::columnSpacing() const
137−{
138− return m_columnSpacing;
139−}
140−
141−void VerticalJournal::setColumnSpacing(qreal columnSpacing)
142−{
143− if (columnSpacing != m_columnSpacing) {
144− m_columnSpacing = columnSpacing;
145− Q_EMIT columnSpacingChanged();
146−
147− if (isComponentComplete()) {
148− relayout();
149− }
150− }
151−}
152−
153−qreal VerticalJournal::rowSpacing() const
154−{
155− return m_rowSpacing;
156−}
157−
158−void VerticalJournal::setRowSpacing(qreal rowSpacing)
159−{
160− if (rowSpacing != m_rowSpacing) {
161− m_rowSpacing = rowSpacing;
162− Q_EMIT rowSpacingChanged();
163−
164− if (isComponentComplete()) {
165− relayout();
166− }
167− }
168−}
169−
170−qreal VerticalJournal::delegateCreationBegin() const
171−{
172− return m_delegateCreationBegin;
173−}
174−
175−void VerticalJournal::setDelegateCreationBegin(qreal begin)
176−{
177− m_delegateCreationBeginValid = true;
178− if (m_delegateCreationBegin == begin)
179− return;
180− m_delegateCreationBegin = begin;
181− if (isComponentComplete()) {
182− polish();
183− }
184− emit delegateCreationBeginChanged();
185−}
186−
187−void VerticalJournal::resetDelegateCreationBegin()
188−{
189− m_delegateCreationBeginValid = false;
190− if (m_delegateCreationBegin == 0)
191− return;
192− m_delegateCreationBegin = 0;
193− if (isComponentComplete()) {
194− polish();
195− }
196− emit delegateCreationBeginChanged();
197−}
198−
199−qreal VerticalJournal::delegateCreationEnd() const
200−{
201− return m_delegateCreationEnd;
202−}
203−
204−void VerticalJournal::setDelegateCreationEnd(qreal end)
205−{
206− m_delegateCreationEndValid = true;
207− if (m_delegateCreationEnd == end)
208− return;
209− m_delegateCreationEnd = end;
210− if (isComponentComplete()) {
211− polish();
212− }
213− emit delegateCreationEndChanged();
214−}
215−
216−void VerticalJournal::resetDelegateCreationEnd()
217−{
218− m_delegateCreationEndValid = false;
219− if (m_delegateCreationEnd == 0)
220− return;
221− m_delegateCreationEnd = 0;
222− if (isComponentComplete()) {
223− polish();
224− }
225− emit delegateCreationEndChanged();
226−}
227−
228−void VerticalJournal::createDelegateModel()
229−{
230−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
231− m_delegateModel = new QQuickVisualDataModel(qmlContext(this), this);
232− connect(m_delegateModel, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(itemCreated(int,QQuickItem*)));
233−#else
234− m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
235− connect(m_delegateModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(itemCreated(int,QObject*)));
236−#endif
237− if (isComponentComplete())
238− m_delegateModel->componentComplete();
239−}
240−
241−void VerticalJournal::refill()
242−{
243− if (!isComponentComplete()) {
244− return;
245− }
246−
247− const bool delegateRangesValid = m_delegateCreationBeginValid && m_delegateCreationEndValid;
248− const qreal from = delegateRangesValid ? m_delegateCreationBegin : 0;
249− const qreal to = delegateRangesValid ? m_delegateCreationEnd : from + height();
250− const qreal buffer = (to - from) * bufferRatio;
251− const qreal bufferFrom = from - buffer;
252− const qreal bufferTo = to + buffer;
253−
254− bool added = addVisibleItems(from, to, false);
255− bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
256− added |= addVisibleItems(bufferFrom, bufferTo, true);
257−
258− if (added || removed) {
259− m_implicitHeightDirty = true;
260− }
261−}
262−
26364void VerticalJournal::findBottomModelIndexToAdd(int *modelIndex, qreal *yPos)
26465{
26566 *modelIndex = 0;
@@ -268,7 +69,7 @@ void VerticalJournal::findBottomModelIndexToAdd(int *modelIndex, qreal *yPos)
26869 Q_FOREACH(const auto &column, m_columnVisibleItems) {
26970 if (!column.isEmpty()) {
27071 const ViewItem &item = column.last();
271− *yPos = qMin(*yPos, item.y() + item.height() + m_rowSpacing);
72+ *yPos = qMin(*yPos, item.y() + item.height() + rowSpacing());
27273 *modelIndex = qMax(*modelIndex, item.m_modelIndex + 1);
27374 } else {
27475 *yPos = 0;
@@ -287,7 +88,7 @@ void VerticalJournal::findTopModelIndexToAdd(int *modelIndex, qreal *yPos)
28788 const auto &column = m_columnVisibleItems[i];
28889 if (!column.isEmpty()) {
28990 const ViewItem &item = column.first();
290− const auto itemTopPos = item.y() - m_rowSpacing;
91+ const auto itemTopPos = item.y() - rowSpacing();
29192 if (itemTopPos > *yPos) {
29293 *yPos = itemTopPos;
29394 *modelIndex = item.m_modelIndex - 1;
@@ -309,38 +110,6 @@ void VerticalJournal::findTopModelIndexToAdd(int *modelIndex, qreal *yPos)
309110 }
310111}
311112
312−bool VerticalJournal::addVisibleItems(qreal fillFrom, qreal fillTo, bool asynchronous)
313−{
314− if (!delegate())
315− return false;
316−
317− if (m_delegateModel->count() == 0)
318− return false;
319−
320− int modelIndex;
321− qreal yPos;
322− findBottomModelIndexToAdd(&modelIndex, &yPos);
323− bool changed = false;
324− while (modelIndex < m_delegateModel->count() && yPos <= fillTo) {
325− if (!createItem(modelIndex, asynchronous))
326− break;
327−
328− changed = true;
329− findBottomModelIndexToAdd(&modelIndex, &yPos);
330− }
331−
332− findTopModelIndexToAdd(&modelIndex, &yPos);
333− while (modelIndex >= 0 && yPos > fillFrom) {
334− if (!createItem(modelIndex, asynchronous))
335− break;
336−
337− changed = true;
338− findTopModelIndexToAdd(&modelIndex, &yPos);
339− }
340−
341− return changed;
342−}
343−
344113bool VerticalJournal::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
345114{
346115 bool changed = false;
@@ -348,12 +117,12 @@ bool VerticalJournal::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
348117 for (int i = 0; i < m_columnVisibleItems.count(); ++i) {
349118 QList<ViewItem> &column = m_columnVisibleItems[i];
350119 while (!column.isEmpty() && column.first().y() + column.first().height() < bufferFrom) {
351− releaseItem(column.takeFirst());
120+ releaseItem(column.takeFirst().m_item);
352121 changed = true;
353122 }
354123
355124 while (!column.isEmpty() && column.last().y() > bufferTo) {
356− releaseItem(column.takeLast());
125+ releaseItem(column.takeLast().m_item);
357126 changed = true;
358127 }
359128 }
@@ -361,53 +130,20 @@ bool VerticalJournal::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
361130 return changed;
362131}
363132
364−QQuickItem *VerticalJournal::createItem(int modelIndex, bool asynchronous)
133+void VerticalJournal::positionItem(int modelIndex, QQuickItem *item)
365134{
366− if (asynchronous && m_asyncRequestedIndex != -1)
367− return nullptr;
368−
369− m_asyncRequestedIndex = -1;
370−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
371− QQuickItem *item = m_delegateModel->item(modelIndex, asynchronous);
372−#else
373− QObject* object = m_delegateModel->object(modelIndex, asynchronous);
374− QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
375−#endif
376− if (!item) {
377−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
378− m_asyncRequestedIndex = modelIndex;
379−#else
380− if (object) {
381− m_delegateModel->release(object);
382− if (!m_delegateValidated) {
383− m_delegateValidated = true;
384− QObject* delegateObj = delegate();
385− qmlInfo(delegateObj ? delegateObj : this) << "Delegate must be of Item type";
386− }
387− } else {
388− m_asyncRequestedIndex = modelIndex;
389− }
390−#endif
391− return nullptr;
392− } else {
393− if (item->width() != m_columnWidth) {
394− qWarning() << "Item" << modelIndex << "width is not the one that the columnWidth mandates, resetting it";
395− item->setWidth(m_columnWidth);
396− }
397− positionItem(modelIndex, item);
398− return item;
135+ if (item->width() != m_columnWidth) {
136+ qWarning() << "Item" << modelIndex << "width is not the one that the columnWidth mandates, resetting it";
137+ item->setWidth(m_columnWidth);
399138 }
400−}
401139
402−void VerticalJournal::positionItem(int modelIndex, QQuickItem *item)
403−{
404140 // Check if we add it to the bottom of existing column items
405141 const QList<ViewItem> &firstColumn = m_columnVisibleItems[0];
406− qreal columnToAddY = !firstColumn.isEmpty() ? firstColumn.last().y() + firstColumn.last().height() : -m_rowSpacing;
142+ qreal columnToAddY = !firstColumn.isEmpty() ? firstColumn.last().y() + firstColumn.last().height() : -rowSpacing();
407143 int columnToAddTo = 0;
408144 for (int i = 1; i < m_columnVisibleItems.count(); ++i) {
409145 const QList<ViewItem> &column = m_columnVisibleItems[i];
410− const qreal iY = !column.isEmpty() ? column.last().y() + column.last().height() : -m_rowSpacing;
146+ const qreal iY = !column.isEmpty() ? column.last().y() + column.last().height() : -rowSpacing();
411147 if (iY < columnToAddY) {
412148 columnToAddTo = i;
413149 columnToAddY = iY;
@@ -416,8 +152,8 @@ void VerticalJournal::positionItem(int modelIndex, QQuickItem *item)
416152
417153 const QList<ViewItem> &columnToAdd = m_columnVisibleItems[columnToAddTo];
418154 if (columnToAdd.isEmpty() || columnToAdd.last().m_modelIndex < modelIndex) {
419− item->setX(columnToAddTo * (m_columnWidth + m_columnSpacing));
420− item->setY(columnToAddY + m_rowSpacing);
155+ item->setX(columnToAddTo * (m_columnWidth + columnSpacing()));
156+ item->setY(columnToAddY + rowSpacing());
421157
422158 m_columnVisibleItems[columnToAddTo] << ViewItem(item, modelIndex);
423159 m_indexColumnMap[modelIndex] = columnToAddTo;
@@ -426,8 +162,8 @@ void VerticalJournal::positionItem(int modelIndex, QQuickItem *item)
426162 columnToAddTo = m_indexColumnMap[modelIndex];
427163 columnToAddY = m_columnVisibleItems[columnToAddTo].first().y();
428164
429− item->setX(columnToAddTo * (m_columnWidth + m_columnSpacing));
430− item->setY(columnToAddY - m_rowSpacing - item->height());
165+ item->setX(columnToAddTo * (m_columnWidth + columnSpacing()));
166+ item->setY(columnToAddY - rowSpacing() - item->height());
431167
432168 m_columnVisibleItems[columnToAddTo].prepend(ViewItem(item, modelIndex));
433169 }
@@ -439,29 +175,14 @@ void VerticalJournal::cleanupExistingItems()
439175 for (int i = 0; i < m_columnVisibleItems.count(); ++i) {
440176 QList<ViewItem> &column = m_columnVisibleItems[i];
441177 Q_FOREACH(const ViewItem &item, column)
442− releaseItem(item);
178+ releaseItem(item.m_item);
443179 column.clear();
444180 }
445181 m_indexColumnMap.clear();
446182}
447183
448−void VerticalJournal::releaseItem(const ViewItem &item)
449−{
450−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
451− QQuickVisualModel::ReleaseFlags flags = m_delegateModel->release(item.m_item);
452− if (flags & QQuickVisualModel::Destroyed) {
453−#else
454− QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item.m_item);
455− if (flags & QQmlDelegateModel::Destroyed) {
456−#endif
457− item.m_item->setParentItem(nullptr);
458− }
459−}
460−
461184void VerticalJournal::calculateImplicitHeight()
462185{
463− m_implicitHeightDirty = false;
464−
465186 int lastModelIndex = -1;
466187 qreal bottomMostY = 0;
467188 Q_FOREACH(const auto &column, m_columnVisibleItems) {
@@ -479,144 +200,80 @@ void VerticalJournal::calculateImplicitHeight()
479200 }
480201}
481202
482−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
483−void VerticalJournal::itemCreated(int modelIndex, QQuickItem *item)
484−{
485−#else
486−void VerticalJournal::itemCreated(int modelIndex, QObject *object)
203+void VerticalJournal::doRelayout()
487204{
488− QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
489− if (!item) {
490− qWarning() << "VerticalJournal::itemCreated got a non item for index" << modelIndex;
491− return;
205+ QList<ViewItem> allItems;
206+ Q_FOREACH(const auto &column, m_columnVisibleItems)
207+ allItems << column;
208+
209+ qSort(allItems);
210+
211+ const int nColumns = qMax(1., floor((double)(width() + columnSpacing()) / (m_columnWidth + columnSpacing())));
212+ m_columnVisibleItems.resize(nColumns);
213+ m_indexColumnMap.clear();
214+ for (int i = 0; i < nColumns; ++i)
215+ m_columnVisibleItems[i].clear();
216+
217+ // If the first of allItems doesn't contain index 0 we need to drop them
218+ // all since we can't consistently relayout without the first item being there
219+
220+ if (!allItems.isEmpty()) {
221+ if (allItems.first().m_modelIndex == 0) {
222+ Q_FOREACH(const ViewItem &item, allItems)
223+ positionItem(item.m_modelIndex, item.m_item);
224+ } else {
225+ Q_FOREACH(const ViewItem &item, allItems)
226+ releaseItem(item.m_item);
227+ }
492228 }
493−#endif
494− item->setParentItem(this);
495− if (modelIndex == m_asyncRequestedIndex) {
496− createItem(modelIndex, false);
497− m_implicitHeightDirty = true;
498− polish();
229+}
230+
231+void VerticalJournal::updateItemCulling(qreal visibleFrom, qreal visibleTo)
232+{
233+ Q_FOREACH(const auto &column, m_columnVisibleItems) {
234+ Q_FOREACH(const ViewItem &item, column) {
235+ QQuickItemPrivate::get(item.m_item)->setCulled(item.y() + item.height() <= visibleFrom || item.y() >= visibleTo);
236+ }
499237 }
500238}
501239
502240#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
503−void VerticalJournal::onModelUpdated(const QQuickChangeSet &changeSet, bool reset)
241+void VerticalJournal::processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes)
504242#else
505−void VerticalJournal::onModelUpdated(const QQmlChangeSet &changeSet, bool reset)
243+void VerticalJournal::processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes)
506244#endif
507245{
508− if (reset) {
509− cleanupExistingItems();
510− } else {
511246#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
512− Q_FOREACH(const QQuickChangeSet::Remove &remove, changeSet.removes()) {
247+ Q_FOREACH(const QQuickChangeSet::Remove &remove, removes) {
513248#else
514− Q_FOREACH(const QQmlChangeSet::Remove &remove, changeSet.removes()) {
249+ Q_FOREACH(const QQmlChangeSet::Remove &remove, removes) {
515250#endif
516− for (int i = remove.count - 1; i >= 0; --i) {
517− const int indexToRemove = remove.index + i;
518− // Since we only support removing from the end, indexToRemove
519− // must refer to the last item of one of the columns or
520− // be bigger than them (because it's not in the viewport and
521− // thus we have not created a delegate for it)
522− bool found = false;
523− int lastCreatedIndex = INT_MIN;
524− for (int i = 0; !found && i < m_columnVisibleItems.count(); ++i) {
525− QList<ViewItem> &column = m_columnVisibleItems[i];
526− if (!column.isEmpty()) {
527− const int lastColumnIndex = column.last().m_modelIndex;
528− if (lastColumnIndex == indexToRemove) {
529− releaseItem(column.takeLast());
530− found = true;
531− }
532− lastCreatedIndex = qMax(lastCreatedIndex, lastColumnIndex);
533− }
534− }
535− if (!found) {
536− if (indexToRemove < lastCreatedIndex) {
537− qFatal("VerticalJournal only supports removal from the end of the model");
538− } else {
539− m_implicitHeightDirty = true;
251+ for (int i = remove.count - 1; i >= 0; --i) {
252+ const int indexToRemove = remove.index + i;
253+ // Since we only support removing from the end, indexToRemove
254+ // must refer to the last item of one of the columns or
255+ // be bigger than them (because it's not in the viewport and
256+ // thus we have not created a delegate for it)
257+ bool found = false;
258+ int lastCreatedIndex = INT_MIN;
259+ for (int i = 0; !found && i < m_columnVisibleItems.count(); ++i) {
260+ QList<ViewItem> &column = m_columnVisibleItems[i];
261+ if (!column.isEmpty()) {
262+ const int lastColumnIndex = column.last().m_modelIndex;
263+ if (lastColumnIndex == indexToRemove) {
264+ releaseItem(column.takeLast().m_item);
265+ found = true;
540266 }
267+ lastCreatedIndex = qMax(lastCreatedIndex, lastColumnIndex);
541268 }
542269 }
543− }
544− }
545− polish();
546−}
547−
548−
549−void VerticalJournal::relayout()
550−{
551− m_needsRelayout = true;
552− polish();
553−}
554−
555−void VerticalJournal::onHeightChanged()
556−{
557− polish();
558−}
559−
560−void VerticalJournal::updatePolish()
561−{
562− if (!model())
563− return;
564−
565− if (m_needsRelayout) {
566− m_implicitHeightDirty = true;
567−
568− QList<ViewItem> allItems;
569− Q_FOREACH(const auto &column, m_columnVisibleItems)
570− allItems << column;
571−
572− qSort(allItems);
573−
574− const int nColumns = qMax(1., floor((double)(width() + m_columnSpacing) / (m_columnWidth + m_columnSpacing)));
575− m_columnVisibleItems.resize(nColumns);
576− m_indexColumnMap.clear();
577− for (int i = 0; i < nColumns; ++i)
578− m_columnVisibleItems[i].clear();
579−
580− // If the first of allItems doesn't contain index 0 we need to drop them
581− // all since we can't consistently relayout without the first item being there
582−
583− if (!allItems.isEmpty()) {
584− if (allItems.first().m_modelIndex == 0) {
585− Q_FOREACH(const ViewItem &item, allItems)
586− positionItem(item.m_modelIndex, item.m_item);
587− } else {
588− Q_FOREACH(const ViewItem &item, allItems)
589− releaseItem(item);
270+ if (!found) {
271+ if (indexToRemove < lastCreatedIndex) {
272+ qFatal("VerticalJournal only supports removal from the end of the model");
273+ } else {
274+ setImplicitHeightDirty();
275+ }
590276 }
591277 }
592−
593− m_needsRelayout = false;
594− }
595−
596− refill();
597−
598− const bool delegateRangesValid = m_delegateCreationBeginValid && m_delegateCreationEndValid;
599− const qreal from = delegateRangesValid ? m_delegateCreationBegin : 0;
600− const qreal to = delegateRangesValid ? m_delegateCreationEnd : from + height();
601− Q_FOREACH(const auto &column, m_columnVisibleItems) {
602− Q_FOREACH(const ViewItem &item, column) {
603− QQuickItemPrivate::get(item.m_item)->setCulled(item.y() + item.height() <= from || item.y() >= to);
604− }
605278 }
606−
607− if (m_implicitHeightDirty) {
608− calculateImplicitHeight();
609− }
610−}
611−
612−void VerticalJournal::componentComplete()
613−{
614− if (m_delegateModel)
615− m_delegateModel->componentComplete();
616−
617− QQuickItem::componentComplete();
618−
619− m_needsRelayout = true;
620−
621− polish();
622279}
plugins/DashViews/verticaljournal.h+13−91
@@ -17,17 +17,7 @@
1717#ifndef VERTICALJOURNAL_H
1818#define VERTICALJOURNAL_H
1919
20−#include <QQuickItem>
21−
22−class QAbstractItemModel;
23−class QQmlComponent;
24−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
25−class QQuickChangeSet;
26−class QQuickVisualDataModel;
27−#else
28−class QQmlChangeSet;
29−class QQmlDelegateModel;
30−#endif
20+#include "abstractjournal.h"
3121
3222 /** A vertical journal is a view that creates delegates
3323 * based on a model and layouts them in columns following
@@ -60,75 +50,23 @@ class QQmlDelegateModel;
6050 * +-----+
6151 *
6252 */
63− class VerticalJournal : public QQuickItem
53+
54+class VerticalJournal : public AbstractJournal
6455{
6556 Q_OBJECT
6657
67− Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged)
68− Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
6958 Q_PROPERTY(qreal columnWidth READ columnWidth WRITE setColumnWidth NOTIFY columnWidthChanged)
70− Q_PROPERTY(qreal columnSpacing READ columnSpacing WRITE setColumnSpacing NOTIFY columnSpacingChanged)
71− Q_PROPERTY(qreal rowSpacing READ rowSpacing WRITE setRowSpacing NOTIFY rowSpacingChanged)
72− Q_PROPERTY(qreal delegateCreationBegin READ delegateCreationBegin
73− WRITE setDelegateCreationBegin
74− NOTIFY delegateCreationBeginChanged
75− RESET resetDelegateCreationBegin)
76− Q_PROPERTY(qreal delegateCreationEnd READ delegateCreationEnd
77− WRITE setDelegateCreationEnd
78− NOTIFY delegateCreationEndChanged
79− RESET resetDelegateCreationEnd)
8059
8160friend class VerticalJournalTest;
8261
8362public:
8463 VerticalJournal();
8564
86− QAbstractItemModel *model() const;
87− void setModel(QAbstractItemModel *model);
88−
89− QQmlComponent *delegate() const;
90− void setDelegate(QQmlComponent *delegate);
91−
9265 qreal columnWidth() const;
9366 void setColumnWidth(qreal columnWidth);
9467
95− qreal columnSpacing() const;
96− void setColumnSpacing(qreal columnSpacing);
97−
98− qreal rowSpacing() const;
99− void setRowSpacing(qreal rowSpacing);
100−
101− qreal delegateCreationBegin() const;
102− void setDelegateCreationBegin(qreal);
103− void resetDelegateCreationBegin();
104−
105− qreal delegateCreationEnd() const;
106− void setDelegateCreationEnd(qreal);
107− void resetDelegateCreationEnd();
108−
10968Q_SIGNALS:
110− void modelChanged();
111− void delegateChanged();
11269 void columnWidthChanged();
113− void columnSpacingChanged();
114− void rowSpacingChanged();
115− void delegateCreationBeginChanged();
116− void delegateCreationEndChanged();
117−
118−protected:
119− void updatePolish();
120− void componentComplete();
121−
122−private Q_SLOTS:
123−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
124− void itemCreated(int modelIndex, QQuickItem *item);
125− void onModelUpdated(const QQuickChangeSet &changeSet, bool reset);
126−#else
127− void itemCreated(int modelIndex, QObject *object);
128− void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
129−#endif
130− void relayout();
131− void onHeightChanged();
13270
13371private:
13472 class ViewItem
@@ -144,39 +82,23 @@ private:
14482 int m_modelIndex;
14583 };
14684
147− void createDelegateModel();
148− void refill();
149− void findBottomModelIndexToAdd(int *modelIndex, qreal *yPos);
150− void findTopModelIndexToAdd(int *modelIndex, qreal *yPos);
151− bool addVisibleItems(qreal fillFrom, qreal fillTo, bool asynchronous);
152− bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo);
153− QQuickItem *createItem(int modelIndex, bool asynchronous);
154− void positionItem(int modelIndex, QQuickItem *item);
155− void cleanupExistingItems();
156− void releaseItem(const ViewItem &item);
157− void calculateImplicitHeight();
158−
85+ void findBottomModelIndexToAdd(int *modelIndex, qreal *yPos) override;
86+ void findTopModelIndexToAdd(int *modelIndex, qreal *yPos) override;
87+ bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) override;
88+ void positionItem(int modelIndex, QQuickItem *item) override;
89+ void cleanupExistingItems() override;
90+ void calculateImplicitHeight() override;
91+ void doRelayout() override;
92+ void updateItemCulling(qreal visibleFrom, qreal visibleTo) override;
15993#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
160− QQuickVisualDataModel *m_delegateModel;
94+ void processModelRemoves(const QVector<QQuickChangeSet::Remove> &removes) override;
16195#else
162− QQmlDelegateModel *m_delegateModel;
96+ void processModelRemoves(const QVector<QQmlChangeSet::Remove> &removes) override;
16397#endif
16498
165− // Index we are waiting because we requested it asynchronously
166− int m_asyncRequestedIndex;
167−
16899 QVector<QList<ViewItem>> m_columnVisibleItems;
169100 QHash<int, int> m_indexColumnMap;
170101 int m_columnWidth;
171− int m_columnSpacing;
172− int m_rowSpacing;
173− qreal m_delegateCreationBegin;
174− qreal m_delegateCreationEnd;
175− bool m_delegateCreationBeginValid;
176− bool m_delegateCreationEndValid;
177− bool m_needsRelayout;
178− bool m_delegateValidated;
179− bool m_implicitHeightDirty;
180102};
181103
182104#endif
tests/plugins/DashViews/CMakeLists.txt+4−4
@@ -40,22 +40,22 @@ qt5_use_modules(listviewwithpageheadertestsectionexternalmodelExec Test Core Qml
4040target_link_libraries(listviewwithpageheadertestsectionexternalmodelExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
4141add_custom_target(testlistviewwithpageheadersectionexternalmodel ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestsectionexternalmodelExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheadersectionexternalmodel.xml,xunitxml -o -,txt)
4242
43−add_executable(verticaljournaltestExec verticaljournaltest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/verticaljournal.cpp)
43+add_executable(verticaljournaltestExec verticaljournaltest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/verticaljournal.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/abstractjournal.cpp)
4444qt5_use_modules(verticaljournaltestExec Test Core Qml)
4545target_link_libraries(verticaljournaltestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
4646add_custom_target(testVerticalJournal ${CMAKE_CURRENT_BINARY_DIR}/verticaljournaltestExec -o ${CMAKE_BINARY_DIR}/testVerticalJournal.xml,xunitxml -o -,txt)
4747
48−add_executable(verticaljournaltryExec verticaljournaltry.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/verticaljournal.cpp)
48+add_executable(verticaljournaltryExec verticaljournaltry.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/verticaljournal.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/abstractjournal.cpp)
4949qt5_use_modules(verticaljournaltryExec Test Core Qml)
5050target_link_libraries(verticaljournaltryExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
5151add_custom_target(tryVerticalJournal ${CMAKE_CURRENT_BINARY_DIR}/verticaljournaltryExec -o ${CMAKE_BINARY_DIR}/testVerticalJournal.xml,xunitxml -o -,txt)
5252
53−add_executable(horizontaljournaltestExec horizontaljournaltest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/horizontaljournal.cpp)
53+add_executable(horizontaljournaltestExec horizontaljournaltest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/horizontaljournal.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/abstractjournal.cpp)
5454qt5_use_modules(horizontaljournaltestExec Test Core Qml)
5555target_link_libraries(horizontaljournaltestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
5656add_custom_target(testHorizontalJournal ${CMAKE_CURRENT_BINARY_DIR}/horizontaljournaltestExec -o ${CMAKE_BINARY_DIR}/testHorizontalJournal.xml,xunitxml -o -,txt)
5757
58−add_executable(horizontaljournaltryExec horizontaljournaltry.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/horizontaljournal.cpp)
58+add_executable(horizontaljournaltryExec horizontaljournaltry.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/horizontaljournal.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/abstractjournal.cpp)
5959qt5_use_modules(horizontaljournaltryExec Test Core Qml)
6060target_link_libraries(horizontaljournaltryExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
6161add_custom_target(tryHorizontalJournal ${CMAKE_CURRENT_BINARY_DIR}/horizontaljournaltryExec -o ${CMAKE_BINARY_DIR}/testHorizontalJournal.xml,xunitxml -o -,txt)