on 6321533 help sign in
unity8/plugins/ListViewWithPageHeader/listviewwithpageheader.h
212 lines 7.5 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 */
17#ifndef LISTVIEWWITHPAGEHEADER_H
18#define LISTVIEWWITHPAGEHEADER_H
20#pragma GCC diagnostic push
21#pragma GCC diagnostic ignored "-pedantic"
22#include <private/qquickitemchangelistener_p.h>
23#include <private/qquickflickable_p.h>
24#pragma GCC diagnostic pop
26class QAbstractItemModel;
27class QQuickNumberAnimation;
28#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
29class QQuickChangeSet;
30class QQuickVisualDataModel;
31#else
32class QQmlChangeSet;
33class QQmlDelegateModel;
34#endif
37/**
38 Note for users of this class
40 ListViewWithPageHeader already loads delegates async when appropiate so if
41 your delegate uses a Loader you should not enable the asynchronous feature since
42 that will need to introduce sizing problems
44 With the double async it may happen what while we are scrolling down
45 we reach to a point where given the size of the just created delegate with loader not yet loaded (which will be very close to 0)
46 we are already "at the end" of the list, but then a few milliseconds later the loader finishes loading and we could
47 have kept scrolling. This is specially visible at the end of the list where you realize
48 that scrolling ended a bit before the end of the list but the speed of the flicking was good
49 to reach the end
51 By not having the second async we get a better sizing when the delegate is created and things work better
52*/
54class ListViewWithPageHeader : public QQuickFlickable, public QQuickItemChangeListener
56 Q_OBJECT
57 Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged)
58 Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
59 Q_PROPERTY(QQuickItem *pageHeader READ header WRITE setHeader NOTIFY headerChanged)
60 Q_PROPERTY(QQmlComponent *sectionDelegate READ sectionDelegate WRITE setSectionDelegate NOTIFY sectionDelegateChanged)
61 Q_PROPERTY(QString sectionProperty READ sectionProperty WRITE setSectionProperty NOTIFY sectionPropertyChanged)
62 Q_PROPERTY(bool forceNoClip READ forceNoClip WRITE setForceNoClip NOTIFY forceNoClipChanged)
64 friend class ListViewWithPageHeaderTest;
65 friend class ListViewWithPageHeaderTestSection;
66 friend class ListViewWithPageHeaderTestExternalModel;
68public:
69 ListViewWithPageHeader();
70 ~ListViewWithPageHeader();
72 QAbstractItemModel *model() const;
73 void setModel(QAbstractItemModel *model);
75 QQmlComponent *delegate() const;
76 void setDelegate(QQmlComponent *delegate);
78 QQuickItem *header() const;
79 void setHeader(QQuickItem *header);
81 QQmlComponent *sectionDelegate() const;
82 void setSectionDelegate(QQmlComponent *delegate);
84 QString sectionProperty() const;
85 void setSectionProperty(const QString &property);
87 bool forceNoClip() const;
88 void setForceNoClip(bool noClip);
90 Q_INVOKABLE void positionAtBeginning();
91 Q_INVOKABLE void showHeader();
92 Q_INVOKABLE QQuickItem *item(int modelIndex) const;
94 // The index has to be created for this to try to do something
95 // Created items are those visible and the precached ones
96 // Returns if the item existed or not
97 Q_INVOKABLE bool maximizeVisibleArea(int modelIndex);
98 Q_INVOKABLE bool maximizeVisibleArea(int modelIndex, int itemHeight);
100Q_SIGNALS:
101 void modelChanged();
102 void delegateChanged();
103 void headerChanged();
104 void sectionDelegateChanged();
105 void sectionPropertyChanged();
106 void forceNoClipChanged();
108protected:
109 void componentComplete();
110 void viewportMoved(Qt::Orientations orient);
111 qreal minYExtent() const;
112 void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
113 void updatePolish();
115private Q_SLOTS:
116#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
117 void itemCreated(int modelIndex, QQuickItem *item);
118#else
119 void itemCreated(int modelIndex, QObject *object);
120#endif
121 void onContentHeightChanged();
122 void onContentWidthChanged();
123 void onHeightChanged();
124#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
125 void onModelUpdated(const QQuickChangeSet &changeSet, bool reset);
126#else
127 void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
128#endif
129 void onShowHeaderAnimationFinished();
131private:
132 class ListItem
133 {
134 public:
135 qreal height() const;
137 qreal y() const;
138 void setY(qreal newY);
140 bool culled() const;
141 void setCulled(bool culled);
143 QQuickItem *m_item;
144 QQuickItem *m_sectionItem;
145 };
147 bool maximizeVisibleArea(ListItem *listItem, int listItemHeight);
149 void createDelegateModel();
151 void layout();
152 void refill();
153 bool addVisibleItems(qreal fillFrom, qreal fillTo, bool asynchronous);
154 bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo);
155 ListItem *createItem(int modelIndex, bool asynchronous);
157 void adjustMinYExtent();
158 void updateClipItem();
159 void headerHeightChanged(qreal newHeaderHeight, qreal oldHeaderHeight, qreal oldHeaderY);
160 ListItem *itemAtIndex(int modelIndex) const; // Returns the item at modelIndex if has been created
161 void releaseItem(ListItem *item);
162 void reallyReleaseItem(ListItem *item);
163 void updateWatchedRoles();
164 QQuickItem *getSectionItem(int modelIndex, bool alreadyInserted);
165 QQuickItem *getSectionItem(const QString &sectionText);
167#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
168 QQuickVisualDataModel *m_delegateModel;
169#else
170 QQmlDelegateModel *m_delegateModel;
171#endif
173 // Index we are waiting because we requested it asynchronously
174 int m_asyncRequestedIndex;
176 // Used to only give a warning once if the delegate does not return objects
177 bool m_delegateValidated;
179 // Visible indexes, [0] is m_firstValidIndex, [0+1] is m_firstValidIndex +1, ...
180 QList<ListItem *> m_visibleItems;
181 int m_firstVisibleIndex;
183 qreal m_minYExtent;
185 QQuickItem *m_clipItem;
187 // If any of the heights has changed
188 // or new items have been added/removed
189 bool m_contentHeightDirty;
191 QQuickItem *m_headerItem;
192 qreal m_previousContentY;
193 qreal m_headerItemShownHeight; // The height of header shown when the header is shown outside its topmost position
194 // i.e. it's being shown after dragging down in the middle of the list
195 enum ContentYAnimationType { ContentYAnimationShowHeader, ContentYAnimationMaximizeVisibleArea };
196 ContentYAnimationType contentYAnimationType;
197 QQuickNumberAnimation *m_contentYAnimation;
199 QQmlComponent *m_sectionDelegate;
200 QString m_sectionProperty;
201 QQuickItem *m_topSectionItem;
203 bool m_forceNoClip;
204 bool m_inLayout;
206 // Qt 5.0 doesn't like releasing the items just after itemCreated
207 // so we delay the releasing until the next updatePolish
208 QList<ListItem *> m_itemsToRelease;
209};
212#endif