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:
parent
be1b589cb9
commit
25027444a9
@ -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
|
||||||
|
|
||||||
|
@ -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]
|
||||||
|
@ -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]
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user