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
|
||||
|
||||
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
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ public:
|
||||
private:
|
||||
void setupModelData(const QStringList &lines, TreeItem *parent);
|
||||
|
||||
TreeItem *rootItem;
|
||||
std::unique_ptr<TreeItem> rootItem;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user