aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquicktableview_p_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquicktableview_p_p.h')
-rw-r--r--src/quick/items/qquicktableview_p_p.h388
1 files changed, 388 insertions, 0 deletions
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
new file mode 100644
index 0000000000..2ed04f8d29
--- /dev/null
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -0,0 +1,388 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTABLEVIEW_P_P_H
+#define QQUICKTABLEVIEW_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquicktableview_p.h"
+
+#include <QtCore/qtimer.h>
+#include <QtQml/private/qqmltableinstancemodel_p.h>
+#include <QtQml/private/qqmlincubator_p.h>
+#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQml/qqmlinfo.h>
+
+#include <QtQuick/private/qquickflickable_p_p.h>
+#include <QtQuick/private/qquickitemviewfxitem_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcTableViewDelegateLifecycle)
+
+static const qreal kDefaultRowHeight = 50;
+static const qreal kDefaultColumnWidth = 50;
+
+class FxTableItem;
+
+class Q_QML_AUTOTEST_EXPORT QQuickTableViewPrivate : public QQuickFlickablePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickTableView)
+
+public:
+ class TableEdgeLoadRequest
+ {
+ // Whenever we need to load new rows or columns in the
+ // table, we fill out a TableEdgeLoadRequest.
+ // TableEdgeLoadRequest is just a struct that keeps track
+ // of which cells that needs to be loaded, and which cell
+ // the table is currently loading. The loading itself is
+ // done by QQuickTableView.
+
+ public:
+ void begin(const QPoint &cell, const QPointF &pos, QQmlIncubator::IncubationMode incubationMode)
+ {
+ Q_ASSERT(!active);
+ active = true;
+ tableEdge = Qt::Edge(0);
+ tableCells = QLine(cell, cell);
+ mode = incubationMode;
+ cellCount = 1;
+ currentIndex = 0;
+ startPos = pos;
+ qCDebug(lcTableViewDelegateLifecycle()) << "begin top-left:" << toString();
+ }
+
+ void begin(const QLine cellsToLoad, Qt::Edge edgeToLoad, QQmlIncubator::IncubationMode incubationMode)
+ {
+ Q_ASSERT(!active);
+ active = true;
+ tableEdge = edgeToLoad;
+ tableCells = cellsToLoad;
+ mode = incubationMode;
+ cellCount = tableCells.x2() - tableCells.x1() + tableCells.y2() - tableCells.y1() + 1;
+ currentIndex = 0;
+ qCDebug(lcTableViewDelegateLifecycle()) << "begin:" << toString();
+ }
+
+ inline void markAsDone() { active = false; }
+ inline bool isActive() { return active; }
+
+ inline QPoint firstCell() { return tableCells.p1(); }
+ inline QPoint lastCell() { return tableCells.p2(); }
+ inline QPoint currentCell() { return cellAt(currentIndex); }
+ inline QPoint previousCell() { return cellAt(currentIndex - 1); }
+
+ inline bool atBeginning() { return currentIndex == 0; }
+ inline bool hasCurrentCell() { return currentIndex < cellCount; }
+ inline void moveToNextCell() { ++currentIndex; }
+
+ inline Qt::Edge edge() { return tableEdge; }
+ inline QQmlIncubator::IncubationMode incubationMode() { return mode; }
+
+ inline QPointF startPosition() { return startPos; }
+
+ QString toString()
+ {
+ QString str;
+ QDebug dbg(&str);
+ dbg.nospace() << "TableSectionLoadRequest(" << "edge:"
+ << tableEdge << " cells:" << tableCells << " incubation:";
+
+ switch (mode) {
+ case QQmlIncubator::Asynchronous:
+ dbg << "Asynchronous";
+ break;
+ case QQmlIncubator::AsynchronousIfNested:
+ dbg << "AsynchronousIfNested";
+ break;
+ case QQmlIncubator::Synchronous:
+ dbg << "Synchronous";
+ break;
+ }
+
+ return str;
+ }
+
+ private:
+ Qt::Edge tableEdge = Qt::Edge(0);
+ QLine tableCells;
+ int currentIndex = 0;
+ int cellCount = 0;
+ bool active = false;
+ QQmlIncubator::IncubationMode mode = QQmlIncubator::AsynchronousIfNested;
+ QPointF startPos;
+
+ QPoint cellAt(int index)
+ {
+ int x = tableCells.p1().x() + (tableCells.dx() ? index : 0);
+ int y = tableCells.p1().y() + (tableCells.dy() ? index : 0);
+ return QPoint(x, y);
+ }
+ };
+
+ enum class RebuildState {
+ Begin = 0,
+ LoadInitalTable,
+ VerifyTable,
+ LayoutTable,
+ LoadAndUnloadAfterLayout,
+ PreloadColumns,
+ PreloadRows,
+ MovePreloadedItemsToPool,
+ Done
+ };
+
+ enum class RebuildOption {
+ None = 0,
+ ViewportOnly = 0x1,
+ CalculateNewTopLeftRow = 0x2,
+ CalculateNewTopLeftColumn = 0x4,
+ All = 0x8,
+ };
+ Q_DECLARE_FLAGS(RebuildOptions, RebuildOption)
+
+public:
+ QQuickTableViewPrivate();
+ ~QQuickTableViewPrivate() override;
+
+ static inline QQuickTableViewPrivate *get(QQuickTableView *q) { return q->d_func(); }
+
+ void updatePolish() override;
+ void fixup(AxisData &data, qreal minExtent, qreal maxExtent) override;
+
+public:
+ QHash<int, FxTableItem *> loadedItems;
+
+ // model, tableModel and modelVariant all point to the same model. modelVariant
+ // is the model assigned by the user. And tableModel is the wrapper model we create
+ // around it. But if the model is an instance model directly, we cannot wrap it, so
+ // we need a pointer for that case as well.
+ QQmlInstanceModel* model = nullptr;
+ QPointer<QQmlTableInstanceModel> tableModel = nullptr;
+ QVariant modelVariant;
+
+ // When the applications assignes a new model or delegate to the view, we keep them
+ // around until we're ready to take them into use (syncWithPendingChanges).
+ QVariant assignedModel = QVariant(int(0));
+ QQmlComponent *assignedDelegate = nullptr;
+
+ // loadedTable describes the table cells that are currently loaded (from top left
+ // row/column to bottom right row/column). loadedTableOuterRect describes the actual
+ // pixels that those cells cover, and is matched agains the viewport to determine when
+ // we need to fill up with more rows/columns. loadedTableInnerRect describes the pixels
+ // that the loaded table covers if you remove one row/column on each side of the table, and
+ // is used to determine rows/columns that are no longer visible and can be unloaded.
+ QRect loadedTable;
+ QRectF loadedTableOuterRect;
+ QRectF loadedTableInnerRect;
+
+ QRectF viewportRect = QRectF(0, 0, -1, -1);
+
+ QSize tableSize;
+
+ RebuildState rebuildState = RebuildState::Done;
+ RebuildOptions rebuildOptions = RebuildOption::All;
+ RebuildOptions scheduledRebuildOptions = RebuildOption::All;
+
+ TableEdgeLoadRequest loadRequest;
+
+ QPoint contentSizeBenchMarkPoint = QPoint(-1, -1);
+ QSizeF cellSpacing = QSizeF(0, 0);
+
+ QQmlTableInstanceModel::ReusableFlag reusableFlag = QQmlTableInstanceModel::Reusable;
+
+ bool blockItemCreatedCallback = false;
+ bool columnRowPositionsInvalid = false;
+ bool layoutWarningIssued = false;
+ bool polishing = false;
+ bool rebuildScheduled = true;
+
+ QJSValue rowHeightProvider;
+ QJSValue columnWidthProvider;
+
+ // TableView uses contentWidth/height to report the size of the table (this
+ // will e.g make scrollbars written for Flickable work out of the box). This
+ // value is continuously calculated, and will change/improve as more columns
+ // are loaded into view. At the same time, we want to open up for the
+ // possibility that the application can set the content width explicitly, in
+ // case it knows what the exact width should be from the start. We therefore
+ // override the contentWidth/height properties from QQuickFlickable, to be able
+ // to implement this combined behavior. This also lets us lazy build the table
+ // if the application needs to know the content size early on.
+ QQmlNullableValue<qreal> explicitContentWidth;
+ QQmlNullableValue<qreal> explicitContentHeight;
+
+ QSizeF averageEdgeSize;
+
+ const static QPoint kLeft;
+ const static QPoint kRight;
+ const static QPoint kUp;
+ const static QPoint kDown;
+
+#ifdef QT_DEBUG
+ QString forcedIncubationMode = qEnvironmentVariable("QT_TABLEVIEW_INCUBATION_MODE");
+#endif
+
+public:
+ QQuickTableViewAttached *getAttachedObject(const QObject *object) const;
+
+ int modelIndexAtCell(const QPoint &cell) const;
+ QPoint cellAtModelIndex(int modelIndex) const;
+
+ qreal sizeHintForColumn(int column);
+ qreal sizeHintForRow(int row);
+ void calculateTableSize();
+
+ qreal resolveColumnWidth(int column);
+ qreal resolveRowHeight(int row);
+
+ void relayoutTable();
+ void relayoutTableItems();
+
+ void layoutVerticalEdge(Qt::Edge tableEdge);
+ void layoutHorizontalEdge(Qt::Edge tableEdge);
+ void layoutTopLeftItem();
+ void layoutTableEdgeFromLoadRequest();
+
+ void updateContentWidth();
+ void updateContentHeight();
+ void updateAverageEdgeSize();
+
+ void enforceTableAtOrigin();
+ void syncLoadedTableRectFromLoadedTable();
+ void syncLoadedTableFromLoadRequest();
+
+ bool canLoadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const;
+ bool canUnloadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const;
+ Qt::Edge nextEdgeToLoad(const QRectF rect);
+ Qt::Edge nextEdgeToUnload(const QRectF rect);
+
+ qreal cellWidth(const QPoint &cell);
+ qreal cellHeight(const QPoint &cell);
+
+ FxTableItem *loadedTableItem(const QPoint &cell) const;
+ FxTableItem *itemNextTo(const FxTableItem *fxTableItem, const QPoint &direction) const;
+ FxTableItem *createFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode);
+ FxTableItem *loadFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode);
+
+ void releaseItem(FxTableItem *fxTableItem, QQmlTableInstanceModel::ReusableFlag reusableFlag);
+ void releaseLoadedItems(QQmlTableInstanceModel::ReusableFlag reusableFlag);
+
+ void unloadItem(const QPoint &cell);
+ void unloadItems(const QLine &items);
+
+ void loadInitialTopLeftItem(const QPoint &cell, const QPointF &pos);
+ void loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode);
+ void unloadEdge(Qt::Edge edge);
+ void loadAndUnloadVisibleEdges();
+ void drainReusePoolAfterLoadRequest();
+ void cancelLoadRequest();
+ void processLoadRequest();
+
+ void processRebuildTable();
+ bool moveToNextRebuildState();
+ void beginRebuildTable();
+ void layoutAfterLoadingInitialTable();
+
+ void scheduleRebuildTable(QQuickTableViewPrivate::RebuildOptions options);
+ void invalidateColumnRowPositions();
+
+ void createWrapperModel();
+
+ void initItemCallback(int modelIndex, QObject *item);
+ void itemCreatedCallback(int modelIndex, QObject *object);
+ void itemPooledCallback(int modelIndex, QObject *object);
+ void itemReusedCallback(int modelIndex, QObject *object);
+ void modelUpdated(const QQmlChangeSet &changeSet, bool reset);
+
+ inline void syncWithPendingChanges();
+ inline void syncDelegate();
+ inline void syncModel();
+ inline void syncRebuildOptions();
+
+ void connectToModel();
+ void disconnectFromModel();
+
+ void rowsMovedCallback(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row);
+ void columnsMovedCallback(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column);
+ void rowsInsertedCallback(const QModelIndex &parent, int begin, int end);
+ void rowsRemovedCallback(const QModelIndex &parent, int begin, int end);
+ void columnsInsertedCallback(const QModelIndex &parent, int begin, int end);
+ void columnsRemovedCallback(const QModelIndex &parent, int begin, int end);
+ void layoutChangedCallback(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
+ void modelResetCallback();
+
+ void _q_componentFinalized();
+ void registerCallbackWhenBindingsAreEvaluated();
+
+ inline QString tableLayoutToString() const;
+ void dumpTable() const;
+};
+
+class FxTableItem : public QQuickItemViewFxItem
+{
+public:
+ FxTableItem(QQuickItem *item, QQuickTableView *table, bool own)
+ : QQuickItemViewFxItem(item, own, QQuickTableViewPrivate::get(table))
+ {
+ }
+
+ qreal position() const override { return 0; }
+ qreal endPosition() const override { return 0; }
+ qreal size() const override { return 0; }
+ qreal sectionSize() const override { return 0; }
+ bool contains(qreal, qreal) const override { return false; }
+
+ QPoint cell;
+};
+
+QT_END_NAMESPACE
+
+#endif