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