diff options
-rw-r--r-- | examples/quick/controls/filesystembrowser/main.cpp | 1 | ||||
-rw-r--r-- | examples/quick/controls/filesystembrowser/main.qml | 6 | ||||
-rw-r--r-- | src/controls/Private/qquicktreemodeladaptor.cpp | 52 | ||||
-rw-r--r-- | src/controls/Private/qquicktreemodeladaptor_p.h | 6 | ||||
-rw-r--r-- | src/controls/TreeView.qml | 1 | ||||
-rw-r--r-- | src/controls/doc/src/qtquickcontrols-treeview.qdoc | 13 | ||||
-rw-r--r-- | src/controls/plugin.cpp | 3 | ||||
-rw-r--r-- | tests/auto/qquicktreemodeladaptor/tst_qquicktreemodeladaptor.cpp | 47 |
8 files changed, 107 insertions, 22 deletions
diff --git a/examples/quick/controls/filesystembrowser/main.cpp b/examples/quick/controls/filesystembrowser/main.cpp index 176d334c..1322bc49 100644 --- a/examples/quick/controls/filesystembrowser/main.cpp +++ b/examples/quick/controls/filesystembrowser/main.cpp @@ -137,6 +137,7 @@ int main(int argc, char *argv[]) fsm->setRootPath(QDir::homePath()); fsm->setResolveSymlinks(true); engine.rootContext()->setContextProperty("fileSystemModel", fsm); + engine.rootContext()->setContextProperty("rootPathIndex", fsm->index(fsm->rootPath())); engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); return app.exec(); diff --git a/examples/quick/controls/filesystembrowser/main.qml b/examples/quick/controls/filesystembrowser/main.qml index abc3c20c..b85002d5 100644 --- a/examples/quick/controls/filesystembrowser/main.qml +++ b/examples/quick/controls/filesystembrowser/main.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.2 -import QtQuick.Controls 1.4 +import QtQuick.Controls 1.5 import QtQml.Models 2.2 ApplicationWindow { @@ -90,6 +90,7 @@ ApplicationWindow { anchors.fill: parent anchors.margins: 2 * 12 + row.height model: fileSystemModel + rootIndex: rootPathIndex selection: sel TableViewColumn { @@ -103,12 +104,14 @@ ApplicationWindow { role: "size" resizable: true horizontalAlignment : Text.AlignRight + width: 70 } TableViewColumn { title: "Permissions" role: "displayableFilePermissions" resizable: true + width: 100 } TableViewColumn { @@ -117,7 +120,6 @@ ApplicationWindow { resizable: true } - onDoubleClicked: isExpanded(index) ? collapse(index) : expand(index) onActivated : Qt.openUrlExternally(fileSystemModel.data(index, 263)) } } diff --git a/src/controls/Private/qquicktreemodeladaptor.cpp b/src/controls/Private/qquicktreemodeladaptor.cpp index dddcdd01..0fda5704 100644 --- a/src/controls/Private/qquicktreemodeladaptor.cpp +++ b/src/controls/Private/qquicktreemodeladaptor.cpp @@ -120,6 +120,29 @@ void QQuickTreeModelAdaptor::clearModelData() endResetModel(); } +const QModelIndex &QQuickTreeModelAdaptor::rootIndex() const +{ + return m_rootIndex; +} + +void QQuickTreeModelAdaptor::setRootIndex(const QModelIndex &idx) +{ + if (m_rootIndex == idx) + return; + + if (m_model) + clearModelData(); + m_rootIndex = idx; + if (m_model) + showModelTopLevelItems(); + emit rootIndexChanged(); +} + +void QQuickTreeModelAdaptor::resetRootIndex() +{ + setRootIndex(QModelIndex()); +} + QHash<int, QByteArray> QQuickTreeModelAdaptor::roleNames() const { if (!m_model) @@ -180,7 +203,7 @@ bool QQuickTreeModelAdaptor::setData(const QModelIndex &index, const QVariant &v int QQuickTreeModelAdaptor::itemIndex(const QModelIndex &index) const { // This is basically a plagiarism of QTreeViewPrivate::viewIndex() - if (!index.isValid() || m_items.isEmpty()) + if (!index.isValid() || index == m_rootIndex || m_items.isEmpty()) return -1; const int totalCount = m_items.count(); @@ -226,7 +249,7 @@ bool QQuickTreeModelAdaptor::isVisible(const QModelIndex &index) bool QQuickTreeModelAdaptor::childrenVisible(const QModelIndex &index) { - return (!index.isValid() && !m_items.isEmpty()) + return (index == m_rootIndex && !m_items.isEmpty()) || (m_expandedItems.contains(index) && isVisible(index)); } @@ -302,21 +325,21 @@ void QQuickTreeModelAdaptor::showModelTopLevelItems(bool doInsertRows) if (!m_model) return; - if (m_model->hasChildren(QModelIndex()) && m_model->canFetchMore(QModelIndex())) - m_model->fetchMore(QModelIndex()); - const long topLevelRowCount = m_model->rowCount(); + if (m_model->hasChildren(m_rootIndex) && m_model->canFetchMore(m_rootIndex)) + m_model->fetchMore(m_rootIndex); + const long topLevelRowCount = m_model->rowCount(m_rootIndex); if (topLevelRowCount == 0) return; - showModelChildItems(TreeItem(), 0, topLevelRowCount - 1, doInsertRows); + showModelChildItems(TreeItem(m_rootIndex), 0, topLevelRowCount - 1, doInsertRows); } void QQuickTreeModelAdaptor::showModelChildItems(const TreeItem &parentItem, int start, int end, bool doInsertRows, bool doExpandPendingRows) { const QModelIndex &parentIndex = parentItem.index; - int rowIdx = parentIndex.isValid() ? itemIndex(parentIndex) + 1 : 0; + int rowIdx = parentIndex.isValid() && parentIndex != m_rootIndex ? itemIndex(parentIndex) + 1 : 0; Q_ASSERT(rowIdx == 0 || parentItem.expanded); - if (parentIndex.isValid() && (rowIdx == 0 || !parentItem.expanded)) + if (parentIndex.isValid() && parentIndex != m_rootIndex && (rowIdx == 0 || !parentItem.expanded)) return; if (m_model->rowCount(parentIndex) == 0) { @@ -603,8 +626,11 @@ void QQuickTreeModelAdaptor::modelRowsInserted(const QModelIndex & parent, int s ASSERT_CONSISTENCY(); return; } - } else if (parent.isValid()) { + } else if (parent == m_rootIndex) { item = TreeItem(parent); + } else { + ASSERT_CONSISTENCY(); + return; } showModelChildItems(item, start, end); ASSERT_CONSISTENCY(); @@ -612,10 +638,8 @@ void QQuickTreeModelAdaptor::modelRowsInserted(const QModelIndex & parent, int s void QQuickTreeModelAdaptor::modelRowsAboutToBeRemoved(const QModelIndex & parent, int start, int end) { - Q_UNUSED(start); - Q_UNUSED(end); ASSERT_CONSISTENCY(); - if (!parent.isValid() || childrenVisible(parent)) { + if (parent == m_rootIndex || childrenVisible(parent)) { const QModelIndex &smi = m_model->index(start, 0, parent); int startIndex = itemIndex(smi); const QModelIndex &emi = m_model->index(end, 0, parent); @@ -756,9 +780,9 @@ bool QQuickTreeModelAdaptor::testConsistency(bool dumpOnFail) const } return true; } - QModelIndex parent; + QModelIndex parent = m_rootIndex; QStack<QModelIndex> ancestors; - QModelIndex idx = m_model->index(0, 0); + QModelIndex idx = m_model->index(0, 0, parent); for (int i = 0; i < m_items.count(); i++) { bool isConsistent = true; const TreeItem &item = m_items.at(i); diff --git a/src/controls/Private/qquicktreemodeladaptor_p.h b/src/controls/Private/qquicktreemodeladaptor_p.h index 2297c365..3eefbe77 100644 --- a/src/controls/Private/qquicktreemodeladaptor_p.h +++ b/src/controls/Private/qquicktreemodeladaptor_p.h @@ -61,6 +61,7 @@ class QQuickTreeModelAdaptor : public QAbstractListModel { Q_OBJECT Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged) + Q_PROPERTY(QModelIndex rootIndex READ rootIndex WRITE setRootIndex RESET resetRootIndex NOTIFY rootIndexChanged) struct TreeItem; @@ -68,6 +69,9 @@ public: explicit QQuickTreeModelAdaptor(QObject *parent = 0); QAbstractItemModel *model() const; + const QModelIndex &rootIndex() const; + void setRootIndex(const QModelIndex &idx); + void resetRootIndex(); enum { DepthRole = Qt::UserRole - 4, @@ -110,6 +114,7 @@ public: signals: void modelChanged(QAbstractItemModel *model); + void rootIndexChanged(); void expanded(const QModelIndex &index); void collapsed(const QModelIndex &index); @@ -149,6 +154,7 @@ private: }; QPointer<QAbstractItemModel> m_model; + QPersistentModelIndex m_rootIndex; QList<TreeItem> m_items; QSet<QPersistentModelIndex> m_expandedItems; QList<TreeItem *> m_itemsToExpand; diff --git a/src/controls/TreeView.qml b/src/controls/TreeView.qml index c97930f3..637c46c3 100644 --- a/src/controls/TreeView.qml +++ b/src/controls/TreeView.qml @@ -44,6 +44,7 @@ BasicTableView { id: root property var model: null + property alias rootIndex: modelAdaptor.rootIndex readonly property var currentIndex: modelAdaptor.mapRowToModelIndex(__currentRow) property ItemSelectionModel selection: null diff --git a/src/controls/doc/src/qtquickcontrols-treeview.qdoc b/src/controls/doc/src/qtquickcontrols-treeview.qdoc index fb186059..a9d41b70 100644 --- a/src/controls/doc/src/qtquickcontrols-treeview.qdoc +++ b/src/controls/doc/src/qtquickcontrols-treeview.qdoc @@ -142,6 +142,19 @@ */ /*! + \qmlproperty QModelIndex TreeView::rootIndex + The model index of the root item in the tree view. The root item is the + parent item to the view's top-level items. Only items descending from the + root item will be visible in the view. + + Its default value is an invalid QModelIndex, which means the whole + model data is shown by the tree view (assigning \c undefined to this + proprety resets it to its default value.) + + \since QtQuick.Controls 1.5 +*/ + +/*! \qmlproperty QModelIndex TreeView::currentIndex The model index of the current row in the tree view. */ diff --git a/src/controls/plugin.cpp b/src/controls/plugin.cpp index f20cada1..802dacb0 100644 --- a/src/controls/plugin.cpp +++ b/src/controls/plugin.cpp @@ -113,7 +113,8 @@ static const struct { { "TreeView", 1, 4 }, - { "TextArea", 1, 5 } + { "TextArea", 1, 5 }, + { "TreeView", 1, 5 } }; void QtQuickControlsPlugin::registerTypes(const char *uri) diff --git a/tests/auto/qquicktreemodeladaptor/tst_qquicktreemodeladaptor.cpp b/tests/auto/qquicktreemodeladaptor/tst_qquicktreemodeladaptor.cpp index b484665d..13a92ea7 100644 --- a/tests/auto/qquicktreemodeladaptor/tst_qquicktreemodeladaptor.cpp +++ b/tests/auto/qquicktreemodeladaptor/tst_qquicktreemodeladaptor.cpp @@ -57,6 +57,8 @@ private slots: void modelDestroyed(); void modelReset(); + void rootIndex(); + void dataAccess(); void dataChange(); void groupedDataChange(); @@ -96,9 +98,10 @@ void tst_QQuickTreeModelAdaptor::cleanup() void tst_QQuickTreeModelAdaptor::compareData(int row, QQuickTreeModelAdaptor &tma, const QModelIndex &modelIdx, TestModel &model, bool expanded) { const QModelIndex &tmaIdx = tma.index(row); + const int indexDepth = model.level(modelIdx) - model.level(tma.rootIndex()) - 1; QCOMPARE(tma.mapToModel(tmaIdx), modelIdx); QCOMPARE(tma.data(tmaIdx, Qt::DisplayRole).toString(), model.displayData(modelIdx)); - QCOMPARE(tma.data(tmaIdx, QQuickTreeModelAdaptor::DepthRole).toInt(), model.level(modelIdx)); + QCOMPARE(tma.data(tmaIdx, QQuickTreeModelAdaptor::DepthRole).toInt(), indexDepth); QCOMPARE(tma.data(tmaIdx, QQuickTreeModelAdaptor::ExpandedRole).toBool(), expanded); QCOMPARE(tma.data(tmaIdx, QQuickTreeModelAdaptor::HasChildrenRole).toBool(), model.hasChildren(modelIdx)); } @@ -117,7 +120,7 @@ void tst_QQuickTreeModelAdaptor::expandAndTest(const QModelIndex &idx, QQuickTre const QModelIndex &tmaIdx = tma.index(tma.itemIndex(idx)); QCOMPARE(tma.data(tmaIdx, QQuickTreeModelAdaptor::ExpandedRole).toBool(), expandable); - if (expandable) { + if (expandable && expectedRowCountDifference != 0) { // Rows were added below the parent QCOMPARE(tma.rowCount(), oldRowCount + expectedRowCountDifference); QCOMPARE(rowsAboutToBeInsertedSpy.count(), rowsInsertedSpy.count()); @@ -160,7 +163,7 @@ void tst_QQuickTreeModelAdaptor::collapseAndTest(const QModelIndex &idx, QQuickT if (tmaIdx.isValid()) QCOMPARE(tma.data(tmaIdx, QQuickTreeModelAdaptor::ExpandedRole).toBool(), false); - if (expandable) { + if (expandable && expectedRowCountDifference != 0) { // Rows were removed below the parent QCOMPARE(tma.rowCount(), oldRowCount - expectedRowCountDifference); QCOMPARE(rowsAboutToBeRemovedSpy.count(), 1); @@ -188,9 +191,9 @@ void tst_QQuickTreeModelAdaptor::collapseAndTest(const QModelIndex &idx, QQuickT void tst_QQuickTreeModelAdaptor::compareModels(QQuickTreeModelAdaptor &tma, TestModel &model) { - QModelIndex parent; + QModelIndex parent = tma.rootIndex(); QStack<QModelIndex> parents; - QModelIndex idx = model.index(0, 0); + QModelIndex idx = model.index(0, 0, parent); int modelVisibleRows = model.rowCount(parent); for (int i = 0; i < tma.rowCount(); i++) { bool expanded = tma.isExpanded(i); @@ -283,6 +286,40 @@ void tst_QQuickTreeModelAdaptor::modelReset() compareModels(tma, model); } +void tst_QQuickTreeModelAdaptor::rootIndex() +{ + TestModel model(5, 1); + + QQuickTreeModelAdaptor tma; + tma.setModel(&model); + + QVERIFY(!tma.rootIndex().isValid()); + compareModels(tma, model); + + QSignalSpy rootIndexSpy(&tma, SIGNAL(rootIndexChanged())); + QModelIndex rootIndex = model.index(0, 0); + tma.setRootIndex(rootIndex); + QCOMPARE(tma.rootIndex(), rootIndex); + QCOMPARE(rootIndexSpy.count(), 1); + compareModels(tma, model); + + rootIndexSpy.clear(); + rootIndex = model.index(2, 2, tma.rootIndex()); + tma.setRootIndex(rootIndex); + QCOMPARE(tma.rootIndex(), rootIndex); + QCOMPARE(rootIndexSpy.count(), 1); + compareModels(tma, model); + + // Expand 1st visible item, business as usual + expandAndTest(model.index(0, 0, rootIndex), tma, true /*expandable*/, 5); + // Expand non root item descendant item, nothing should happen + expandAndTest(model.index(0, 0), tma, true /*expandable*/, 0); + // Collapse 1st visible item, business as usual + collapseAndTest(model.index(0, 0, rootIndex), tma, true /*expandable*/, 5); + // Collapse non root item descendant item, nothing should happen + collapseAndTest(model.index(0, 0), tma, true /*expandable*/, 0); +} + void tst_QQuickTreeModelAdaptor::dataAccess() { TestModel model(5, 1); |