From 25027444a9b53d61a6257dc5f5ce0ffdb3b06f98 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Fri, 26 May 2023 16:51:49 +0200 Subject: [PATCH] Modernize SimpleTreeModel example Use std::unique_ptr to manage items tree memory allocations. This also use the new string literals operator. Change-Id: Iab002b5dc612b75cef0be10862e263c6c6c013c1 Reviewed-by: Volker Hilsheimer --- examples/widgets/doc/src/simpletreemodel.qdoc | 28 +++++----- .../itemviews/simpletreemodel/treeitem.cpp | 56 +++++++++---------- .../itemviews/simpletreemodel/treeitem.h | 9 ++- .../itemviews/simpletreemodel/treemodel.cpp | 29 +++++----- .../itemviews/simpletreemodel/treemodel.h | 2 +- 5 files changed, 61 insertions(+), 63 deletions(-) diff --git a/examples/widgets/doc/src/simpletreemodel.qdoc b/examples/widgets/doc/src/simpletreemodel.qdoc index 5892d05244..3ab5a70151 100644 --- a/examples/widgets/doc/src/simpletreemodel.qdoc +++ b/examples/widgets/doc/src/simpletreemodel.qdoc @@ -104,16 +104,14 @@ \snippet itemviews/simpletreemodel/treeitem.cpp 0 A pointer to each of the child items belonging to this item will be - stored in the \c childItems private member variable. When the class's - destructor is called, it must delete each of these to ensure that - their memory is reused: - - \snippet itemviews/simpletreemodel/treeitem.cpp 1 + stored in the \c childItems private member variable as an std::unique_ptr. + When the class's destructor is called, the child items will be automatically + deleted to ensure that their memory is reused: Since each of the child items are constructed when the model is initially populated with data, the function to add child items is straightforward: - \snippet itemviews/simpletreemodel/treeitem.cpp 2 + \snippet itemviews/simpletreemodel/treeitem.cpp 1 Each item is able to return any of its child items when given a suitable row number. For example, in the \l{#SimpleTreeModelStructure}{above diagram}, @@ -124,11 +122,11 @@ The \c child() function returns the child that corresponds to the specified row number in the item's list of child items: - \snippet itemviews/simpletreemodel/treeitem.cpp 3 + \snippet itemviews/simpletreemodel/treeitem.cpp 2 The number of child items held can be found with \c childCount(): - \snippet itemviews/simpletreemodel/treeitem.cpp 4 + \snippet itemviews/simpletreemodel/treeitem.cpp 3 The \c TreeModel uses this function to determine the number of rows that exist for a given parent item. @@ -136,7 +134,7 @@ The \c row() function reports the item's location within its parent's list of items: - \snippet itemviews/simpletreemodel/treeitem.cpp 8 + \snippet itemviews/simpletreemodel/treeitem.cpp 7 Note that, although the root item (with no parent item) is automatically assigned a row number of 0, this information is never used by the model. @@ -144,16 +142,16 @@ The number of columns of data in the item is trivially returned by the \c columnCount() function. - \snippet itemviews/simpletreemodel/treeitem.cpp 5 + \snippet itemviews/simpletreemodel/treeitem.cpp 4 Column data is returned by the \c data() function. The bounds are checked before accessing the container with the data: - \snippet itemviews/simpletreemodel/treeitem.cpp 6 + \snippet itemviews/simpletreemodel/treeitem.cpp 5 The item's parent is found with \c parent(): - \snippet itemviews/simpletreemodel/treeitem.cpp 7 + \snippet itemviews/simpletreemodel/treeitem.cpp 6 Note that, since the root item in the model will not have a parent, this function will return zero in that case. We need to ensure that the model @@ -183,14 +181,16 @@ item only contains vertical header data for convenience. We also use it to reference the internal data structure that contains the model data, and it is used to represent an imaginary parent of top-level items in - the model. + the model. The root item is managed with a std::unique_ptr to ensure the + entire tree of item is deleted when the model is deleted. The model's internal data structure is populated with items by the \c setupModelData() function. We will examine this function separately at the end of this document. The destructor ensures that the root item and all of its descendants - are deleted when the model is destroyed: + are deleted when the model is destroyed. This is done automatically + since the root item is stored in a unique_ptr. \snippet itemviews/simpletreemodel/treemodel.cpp 1 diff --git a/examples/widgets/itemviews/simpletreemodel/treeitem.cpp b/examples/widgets/itemviews/simpletreemodel/treeitem.cpp index 59292bbbca..611a6a0976 100644 --- a/examples/widgets/itemviews/simpletreemodel/treeitem.cpp +++ b/examples/widgets/itemviews/simpletreemodel/treeitem.cpp @@ -10,70 +10,70 @@ #include "treeitem.h" //! [0] -TreeItem::TreeItem(const QList &data, TreeItem *parent) +TreeItem::TreeItem(const QVariantList &data, TreeItem *parent) : m_itemData(data), m_parentItem(parent) {} //! [0] //! [1] -TreeItem::~TreeItem() +void TreeItem::appendChild(std::unique_ptr &&child) { - qDeleteAll(m_childItems); + m_childItems.push_back(std::move(child)); } //! [1] //! [2] -void TreeItem::appendChild(TreeItem *item) -{ - m_childItems.append(item); -} -//! [2] - -//! [3] TreeItem *TreeItem::child(int row) { if (row < 0 || row >= m_childItems.size()) return nullptr; - return m_childItems.at(row); + return m_childItems.at(row).get(); +} +//! [2] + +//! [3] +int TreeItem::childCount() const +{ + return m_childItems.size(); } //! [3] //! [4] -int TreeItem::childCount() const -{ - return m_childItems.count(); -} -//! [4] - -//! [5] int TreeItem::columnCount() const { return m_itemData.count(); } -//! [5] +//! [4] -//! [6] +//! [5] QVariant TreeItem::data(int column) const { if (column < 0 || column >= m_itemData.size()) return QVariant(); return m_itemData.at(column); } -//! [6] +//! [5] -//! [7] +//! [6] TreeItem *TreeItem::parentItem() { return m_parentItem; } -//! [7] +//! [6] -//! [8] +//! [7] int TreeItem::row() const { - if (m_parentItem) - return m_parentItem->m_childItems.indexOf(const_cast(this)); + if (!m_parentItem) + return 0; + const auto it = std::find_if(m_parentItem->m_childItems.cbegin(), m_parentItem->m_childItems.cend(), + [this](const std::unique_ptr &treeItem) { + return treeItem.get() == const_cast(this); + }); - return 0; + if (it != m_parentItem->m_childItems.cend()) + return std::distance(m_parentItem->m_childItems.cbegin(), it); + Q_ASSERT(false); // should not happen + return -1; } -//! [8] +//! [7] diff --git a/examples/widgets/itemviews/simpletreemodel/treeitem.h b/examples/widgets/itemviews/simpletreemodel/treeitem.h index b2508b9058..8edebcc34b 100644 --- a/examples/widgets/itemviews/simpletreemodel/treeitem.h +++ b/examples/widgets/itemviews/simpletreemodel/treeitem.h @@ -11,10 +11,9 @@ class TreeItem { public: - explicit TreeItem(const QList &data, TreeItem *parentItem = nullptr); - ~TreeItem(); + explicit TreeItem(const QVariantList &data, TreeItem *parentItem = nullptr); - void appendChild(TreeItem *child); + void appendChild(std::unique_ptr &&child); TreeItem *child(int row); int childCount() const; @@ -24,8 +23,8 @@ public: TreeItem *parentItem(); private: - QList m_childItems; - QList m_itemData; + std::vector> m_childItems; + QVariantList m_itemData; TreeItem *m_parentItem; }; //! [0] diff --git a/examples/widgets/itemviews/simpletreemodel/treemodel.cpp b/examples/widgets/itemviews/simpletreemodel/treemodel.cpp index 1665f18ebe..93cd6709a9 100644 --- a/examples/widgets/itemviews/simpletreemodel/treemodel.cpp +++ b/examples/widgets/itemviews/simpletreemodel/treemodel.cpp @@ -13,20 +13,19 @@ #include +using namespace Qt::StringLiterals; + //! [0] TreeModel::TreeModel(const QString &data, QObject *parent) : QAbstractItemModel(parent) + , rootItem(std::make_unique(QVariantList{tr("Title"), tr("Summary")})) { - rootItem = new TreeItem({tr("Title"), tr("Summary")}); - setupModelData(data.split('\n'), rootItem); + setupModelData(data.split('\n'_L1), rootItem.get()); } //! [0] //! [1] -TreeModel::~TreeModel() -{ - delete rootItem; -} +TreeModel::~TreeModel() = default; //! [1] //! [2] @@ -47,7 +46,7 @@ QVariant TreeModel::data(const QModelIndex &index, int role) const if (role != Qt::DisplayRole) return QVariant(); - TreeItem *item = static_cast(index.internalPointer()); + auto item = static_cast(index.internalPointer()); return item->data(index.column()); } @@ -83,11 +82,11 @@ QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) con TreeItem *parentItem; if (!parent.isValid()) - parentItem = rootItem; + parentItem = rootItem.get(); else parentItem = static_cast(parent.internalPointer()); - TreeItem *childItem = parentItem->child(row); + auto childItem = parentItem->child(row); if (childItem) return createIndex(row, column, childItem); return QModelIndex(); @@ -103,7 +102,7 @@ QModelIndex TreeModel::parent(const QModelIndex &index) const TreeItem *childItem = static_cast(index.internalPointer()); TreeItem *parentItem = childItem->parentItem(); - if (parentItem == rootItem) + if (parentItem == rootItem.get()) return QModelIndex(); return createIndex(parentItem->row(), 0, parentItem); @@ -118,7 +117,7 @@ int TreeModel::rowCount(const QModelIndex &parent) const return 0; if (!parent.isValid()) - parentItem = rootItem; + parentItem = rootItem.get(); else parentItem = static_cast(parent.internalPointer()); @@ -138,7 +137,7 @@ void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent) while (number < lines.count()) { int position = 0; while (position < lines[number].length()) { - if (lines[number].at(position) != ' ') + if (lines[number].at(position) != ' '_L1) break; position++; } @@ -148,8 +147,8 @@ void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent) if (!lineData.isEmpty()) { // Read the column data from the rest of the line. const QStringList columnStrings = - lineData.split(QLatin1Char('\t'), Qt::SkipEmptyParts); - QList columnData; + lineData.split('\t'_L1, Qt::SkipEmptyParts); + QVariantList columnData; columnData.reserve(columnStrings.count()); for (const QString &columnString : columnStrings) columnData << columnString; @@ -170,7 +169,7 @@ void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent) } // Append a new item to the current parent's list of children. - parents.last()->appendChild(new TreeItem(columnData, parents.last())); + parents.last()->appendChild(std::make_unique(columnData, parents.last())); } ++number; } diff --git a/examples/widgets/itemviews/simpletreemodel/treemodel.h b/examples/widgets/itemviews/simpletreemodel/treemodel.h index aa93c33494..0a771088ed 100644 --- a/examples/widgets/itemviews/simpletreemodel/treemodel.h +++ b/examples/widgets/itemviews/simpletreemodel/treemodel.h @@ -32,7 +32,7 @@ public: private: void setupModelData(const QStringList &lines, TreeItem *parent); - TreeItem *rootItem; + std::unique_ptr rootItem; }; //! [0]