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
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

View File

@ -10,70 +10,70 @@
#include "treeitem.h"
//! [0]
TreeItem::TreeItem(const QList<QVariant> &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<TreeItem> &&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<TreeItem*>(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> &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
{
public:
explicit TreeItem(const QList<QVariant> &data, TreeItem *parentItem = nullptr);
~TreeItem();
explicit TreeItem(const QVariantList &data, TreeItem *parentItem = nullptr);
void appendChild(TreeItem *child);
void appendChild(std::unique_ptr<TreeItem> &&child);
TreeItem *child(int row);
int childCount() const;
@ -24,8 +23,8 @@ public:
TreeItem *parentItem();
private:
QList<TreeItem *> m_childItems;
QList<QVariant> m_itemData;
std::vector<std::unique_ptr<TreeItem>> m_childItems;
QVariantList m_itemData;
TreeItem *m_parentItem;
};
//! [0]

View File

@ -13,20 +13,19 @@
#include <QStringList>
using namespace Qt::StringLiterals;
//! [0]
TreeModel::TreeModel(const QString &data, QObject *parent)
: QAbstractItemModel(parent)
, rootItem(std::make_unique<TreeItem>(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<TreeItem*>(index.internalPointer());
auto item = static_cast<TreeItem*>(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<TreeItem*>(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<TreeItem*>(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<TreeItem*>(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<QVariant> 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<TreeItem>(columnData, parents.last()));
}
++number;
}

View File

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