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 <volker.hilsheimer@qt.io>
This commit is contained in:
Carl Schwan 2023-05-26 16:51:49 +02:00 committed by Volker Hilsheimer
parent be1b589cb9
commit 25027444a9
5 changed files with 61 additions and 63 deletions

View File

@ -104,16 +104,14 @@
\snippet itemviews/simpletreemodel/treeitem.cpp 0 \snippet itemviews/simpletreemodel/treeitem.cpp 0
A pointer to each of the child items belonging to this item will be 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 stored in the \c childItems private member variable as an std::unique_ptr.
destructor is called, it must delete each of these to ensure that When the class's destructor is called, the child items will be automatically
their memory is reused: deleted to ensure that their memory is reused:
\snippet itemviews/simpletreemodel/treeitem.cpp 1
Since each of the child items are constructed when the model is initially Since each of the child items are constructed when the model is initially
populated with data, the function to add child items is straightforward: 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 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}, 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 \c child() function returns the child that corresponds to
the specified row number in the item's list of child items: 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(): 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 The \c TreeModel uses this function to determine the number of rows that
exist for a given parent item. exist for a given parent item.
@ -136,7 +134,7 @@
The \c row() function reports the item's location within its parent's The \c row() function reports the item's location within its parent's
list of items: 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 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. 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 The number of columns of data in the item is trivially returned by the
\c columnCount() function. \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 Column data is returned by the \c data() function. The bounds are checked
before accessing the container with the data: 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(): 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 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 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 item only contains vertical header data for convenience. We also use it
to reference the internal data structure that contains the model data, 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 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 The model's internal data structure is populated with items by the
\c setupModelData() function. We will examine this function separately \c setupModelData() function. We will examine this function separately
at the end of this document. at the end of this document.
The destructor ensures that the root item and all of its descendants 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 \snippet itemviews/simpletreemodel/treemodel.cpp 1

View File

@ -10,70 +10,70 @@
#include "treeitem.h" #include "treeitem.h"
//! [0] //! [0]
TreeItem::TreeItem(const QList<QVariant> &data, TreeItem *parent) TreeItem::TreeItem(const QVariantList &data, TreeItem *parent)
: m_itemData(data), m_parentItem(parent) : m_itemData(data), m_parentItem(parent)
{} {}
//! [0] //! [0]
//! [1] //! [1]
TreeItem::~TreeItem() void TreeItem::appendChild(std::unique_ptr<TreeItem> &&child)
{ {
qDeleteAll(m_childItems); m_childItems.push_back(std::move(child));
} }
//! [1] //! [1]
//! [2] //! [2]
void TreeItem::appendChild(TreeItem *item)
{
m_childItems.append(item);
}
//! [2]
//! [3]
TreeItem *TreeItem::child(int row) TreeItem *TreeItem::child(int row)
{ {
if (row < 0 || row >= m_childItems.size()) if (row < 0 || row >= m_childItems.size())
return nullptr; return nullptr;
return m_childItems.at(row); return m_childItems.at(row).get();
}
//! [2]
//! [3]
int TreeItem::childCount() const
{
return m_childItems.size();
} }
//! [3] //! [3]
//! [4] //! [4]
int TreeItem::childCount() const
{
return m_childItems.count();
}
//! [4]
//! [5]
int TreeItem::columnCount() const int TreeItem::columnCount() const
{ {
return m_itemData.count(); return m_itemData.count();
} }
//! [5] //! [4]
//! [6] //! [5]
QVariant TreeItem::data(int column) const QVariant TreeItem::data(int column) const
{ {
if (column < 0 || column >= m_itemData.size()) if (column < 0 || column >= m_itemData.size())
return QVariant(); return QVariant();
return m_itemData.at(column); return m_itemData.at(column);
} }
//! [6] //! [5]
//! [7] //! [6]
TreeItem *TreeItem::parentItem() TreeItem *TreeItem::parentItem()
{ {
return m_parentItem; return m_parentItem;
} }
//! [7] //! [6]
//! [8] //! [7]
int TreeItem::row() const int TreeItem::row() const
{ {
if (m_parentItem) if (!m_parentItem)
return m_parentItem->m_childItems.indexOf(const_cast<TreeItem*>(this)); return 0;
const auto it = std::find_if(m_parentItem->m_childItems.cbegin(), m_parentItem->m_childItems.cend(),
[this](const std::unique_ptr<TreeItem> &treeItem) {
return treeItem.get() == const_cast<TreeItem *>(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]

View File

@ -11,10 +11,9 @@
class TreeItem class TreeItem
{ {
public: public:
explicit TreeItem(const QList<QVariant> &data, TreeItem *parentItem = nullptr); explicit TreeItem(const QVariantList &data, TreeItem *parentItem = nullptr);
~TreeItem();
void appendChild(TreeItem *child); void appendChild(std::unique_ptr<TreeItem> &&child);
TreeItem *child(int row); TreeItem *child(int row);
int childCount() const; int childCount() const;
@ -24,8 +23,8 @@ public:
TreeItem *parentItem(); TreeItem *parentItem();
private: private:
QList<TreeItem *> m_childItems; std::vector<std::unique_ptr<TreeItem>> m_childItems;
QList<QVariant> m_itemData; QVariantList m_itemData;
TreeItem *m_parentItem; TreeItem *m_parentItem;
}; };
//! [0] //! [0]

View File

@ -13,20 +13,19 @@
#include <QStringList> #include <QStringList>
using namespace Qt::StringLiterals;
//! [0] //! [0]
TreeModel::TreeModel(const QString &data, QObject *parent) TreeModel::TreeModel(const QString &data, QObject *parent)
: QAbstractItemModel(parent) : QAbstractItemModel(parent)
, rootItem(std::make_unique<TreeItem>(QVariantList{tr("Title"), tr("Summary")}))
{ {
rootItem = new TreeItem({tr("Title"), tr("Summary")}); setupModelData(data.split('\n'_L1), rootItem.get());
setupModelData(data.split('\n'), rootItem);
} }
//! [0] //! [0]
//! [1] //! [1]
TreeModel::~TreeModel() TreeModel::~TreeModel() = default;
{
delete rootItem;
}
//! [1] //! [1]
//! [2] //! [2]
@ -47,7 +46,7 @@ QVariant TreeModel::data(const QModelIndex &index, int role) const
if (role != Qt::DisplayRole) if (role != Qt::DisplayRole)
return QVariant(); return QVariant();
TreeItem *item = static_cast<TreeItem*>(index.internalPointer()); auto item = static_cast<TreeItem*>(index.internalPointer());
return item->data(index.column()); return item->data(index.column());
} }
@ -83,11 +82,11 @@ QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) con
TreeItem *parentItem; TreeItem *parentItem;
if (!parent.isValid()) if (!parent.isValid())
parentItem = rootItem; parentItem = rootItem.get();
else else
parentItem = static_cast<TreeItem*>(parent.internalPointer()); parentItem = static_cast<TreeItem*>(parent.internalPointer());
TreeItem *childItem = parentItem->child(row); auto childItem = parentItem->child(row);
if (childItem) if (childItem)
return createIndex(row, column, childItem); return createIndex(row, column, childItem);
return QModelIndex(); return QModelIndex();
@ -103,7 +102,7 @@ QModelIndex TreeModel::parent(const QModelIndex &index) const
TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer()); TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
TreeItem *parentItem = childItem->parentItem(); TreeItem *parentItem = childItem->parentItem();
if (parentItem == rootItem) if (parentItem == rootItem.get())
return QModelIndex(); return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem); return createIndex(parentItem->row(), 0, parentItem);
@ -118,7 +117,7 @@ int TreeModel::rowCount(const QModelIndex &parent) const
return 0; return 0;
if (!parent.isValid()) if (!parent.isValid())
parentItem = rootItem; parentItem = rootItem.get();
else else
parentItem = static_cast<TreeItem*>(parent.internalPointer()); parentItem = static_cast<TreeItem*>(parent.internalPointer());
@ -138,7 +137,7 @@ void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent)
while (number < lines.count()) { while (number < lines.count()) {
int position = 0; int position = 0;
while (position < lines[number].length()) { while (position < lines[number].length()) {
if (lines[number].at(position) != ' ') if (lines[number].at(position) != ' '_L1)
break; break;
position++; position++;
} }
@ -148,8 +147,8 @@ void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent)
if (!lineData.isEmpty()) { if (!lineData.isEmpty()) {
// Read the column data from the rest of the line. // Read the column data from the rest of the line.
const QStringList columnStrings = const QStringList columnStrings =
lineData.split(QLatin1Char('\t'), Qt::SkipEmptyParts); lineData.split('\t'_L1, Qt::SkipEmptyParts);
QList<QVariant> columnData; QVariantList columnData;
columnData.reserve(columnStrings.count()); columnData.reserve(columnStrings.count());
for (const QString &columnString : columnStrings) for (const QString &columnString : columnStrings)
columnData << columnString; 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. // 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<TreeItem>(columnData, parents.last()));
} }
++number; ++number;
} }

View File

@ -32,7 +32,7 @@ public:
private: private:
void setupModelData(const QStringList &lines, TreeItem *parent); void setupModelData(const QStringList &lines, TreeItem *parent);
TreeItem *rootItem; std::unique_ptr<TreeItem> rootItem;
}; };
//! [0] //! [0]