@@ -0,0 +1,251 @@
2+ * Copyright (C) 2013 Canonical, Ltd.
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.
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.
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/>.
17+#include "listviewwithpageheader.h"
19+#include <QAbstractItemModel>
23+#include <QSortFilterProxyModel>
25+#pragma GCC diagnostic push
26+#pragma GCC diagnostic ignored "-pedantic"
27+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
28+#include <private/qquicklistmodel_p.h>
30+#include <private/qqmllistmodel_p.h>
32+#include <private/qquickanimation_p.h>
33+#include <private/qquickitem_p.h>
34+#pragma GCC diagnostic pop
36+class StringListModel : public QAbstractListModel
41+ list << "A" << "B" << "C" << "D" << "E" << "F" << "G" << "H";
44+ int rowCount(const QModelIndex &parent) const
46+ if (parent.isValid())
52+ QVariant data(const QModelIndex &index, int role) const
54+ if (role == Qt::SizeHintRole) return 50;
55+ else if (role == Qt::DisplayRole) return list[index.row()];
59+ QHash<int, QByteArray> roleNames() const
61+ QHash<int, QByteArray> hash;
62+ hash.insert(Qt::DisplayRole, "type");
63+ hash.insert(Qt::SizeHintRole, "size");
67+ void moveLastToFirst()
69+ const int last = list.count() - 1;
70+ beginMoveRows(QModelIndex(), last, last, QModelIndex(), 0);
78+class ListViewWithPageHeaderTestSection : public QObject
83+ void verifyItem(int visibleIndex, qreal pos, qreal height, bool culled, const QString §ionHeader, bool sectionHeaderCulled)
85+ QTRY_VERIFY(visibleIndex < lvwph->m_visibleItems.count());
86+ QTRY_COMPARE(lvwph->m_visibleItems[visibleIndex]->y(), pos);
87+ QTRY_COMPARE(lvwph->m_visibleItems[visibleIndex]->height(), height);
88+ QCOMPARE(QQuickItemPrivate::get(lvwph->m_visibleItems[visibleIndex]->m_item)->culled, culled);
89+ QCOMPARE(section(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), sectionHeader);
90+ if (!sectionHeader.isNull()) {
91+ QCOMPARE(QQuickItemPrivate::get(lvwph->m_visibleItems[visibleIndex]->m_sectionItem)->culled, sectionHeaderCulled);
92+ QCOMPARE(sectionDelegateIndex(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), lvwph->m_firstVisibleIndex + visibleIndex);
96+ void changeContentY(qreal change)
98+ const qreal dest = lvwph->contentY() + change;
99+ if (dest > lvwph->contentY()) {
100+ const qreal jump = 25;
101+ while (lvwph->contentY() + jump < dest) {
102+ lvwph->setContentY(lvwph->contentY() + jump);
106+ const qreal jump = -25;
107+ while (lvwph->contentY() + jump > dest) {
108+ lvwph->setContentY(lvwph->contentY() + jump);
112+ lvwph->setContentY(dest);
118+ const qreal jump = -25;
119+ while (!lvwph->isAtYBeginning()) {
120+ if (lvwph->contentY() + jump > -lvwph->minYExtent()) {
121+ lvwph->setContentY(lvwph->contentY() + jump);
123+ lvwph->setContentY(lvwph->contentY() - 1);
129+ void scrollToBottom()
131+ const qreal jump = 25;
132+ while (!lvwph->isAtYEnd()) {
133+ if (lvwph->contentY() + lvwph->height() + jump < lvwph->contentHeight()) {
134+ lvwph->setContentY(lvwph->contentY() + jump);
136+ lvwph->setContentY(lvwph->contentY() + 1);
142+ void verifyInitialTopPosition()
144+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
145+ QCOMPARE(lvwph->m_firstVisibleIndex, -1);
146+ QCOMPARE(lvwph->m_minYExtent, 0.);
147+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
148+ QCOMPARE(lvwph->m_clipItem->clip(), false);
149+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
150+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
151+ QCOMPARE(lvwph->contentY(), 0.);
152+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
153+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
156+ QString section(QQuickItem *item)
158+ return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("section")).toString() : QString();
161+ int sectionDelegateIndex(QQuickItem *item)
163+ return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("delegateIndex")).toInt() : -1;
174+ view = new QQuickView();
175+ view->engine()->addImportPath(BUILT_PLUGINS_DIR);
176+ view->setSource(QUrl::fromLocalFile(LISTVIEWWITHPAGEHEADER_FOLDER "/test_sectionexternalmodel.qml"));
177+ lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
180+ QTest::qWaitForWindowExposed(view);
182+ verifyInitialTopPosition();
190+ void testCreationDeletion()
192+ // Nothing, init/cleanup already tests this
195+ void testMoveWithProxy()
198+ QSortFilterProxyModel proxy;
199+ proxy.setSourceModel(&m);
201+ lvwph->setModel(&proxy);
203+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 8);
204+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
205+ verifyItem(0, 50., 90., false, "A", false);
206+ verifyItem(1, 140., 90., false, "B", false);
207+ verifyItem(2, 230., 90., false, "C", false);
208+ verifyItem(3, 320., 90., false, "D", false);
209+ verifyItem(4, 410., 90., false, "E", false);
210+ verifyItem(5, 500., 90., false, "F", false);
211+ verifyItem(6, 590., 90., true, "G", true);
212+ verifyItem(7, 680., 90., true, "H", true);
213+ QCOMPARE(lvwph->m_minYExtent, 0.);
214+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
215+ QCOMPARE(lvwph->m_clipItem->clip(), false);
216+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
217+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
218+ QCOMPARE(lvwph->contentY(), 0.);
219+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
220+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
222+ m.moveLastToFirst();
224+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 8);
225+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
226+ verifyItem(0, 50., 90., false, "H", false);
227+ verifyItem(1, 140., 90., false, "A", false);
228+ verifyItem(2, 230., 90., false, "B", false);
229+ verifyItem(3, 320., 90., false, "C", false);
230+ verifyItem(4, 410., 90., false, "D", false);
231+ verifyItem(5, 500., 90., false, "E", false);
232+ verifyItem(6, 590., 90., true, "F", true);
233+ verifyItem(7, 680., 90., true, "G", true);
234+ QCOMPARE(lvwph->m_minYExtent, 0.);
235+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
236+ QCOMPARE(lvwph->m_clipItem->clip(), false);
237+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
238+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
239+ QCOMPARE(lvwph->contentY(), 0.);
240+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
241+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
246+ ListViewWithPageHeader *lvwph;
249+QTEST_MAIN(ListViewWithPageHeaderTestSection)
251+#include "listviewwithpageheadertestsectionexternalmodel.moc"