Refactoring generic tree model behavior

This commit is contained in:
Dan Paulat 2022-09-19 23:12:46 -05:00
parent 1ba60f0da1
commit 98f8bab79a
7 changed files with 348 additions and 236 deletions

View file

@ -11,241 +11,30 @@ namespace model
static const std::string logPrefix_ = "scwx::qt::model::radar_product_model";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
class RadarProductModelItem
{
public:
explicit RadarProductModelItem(const std::vector<QVariant>& data,
RadarProductModelItem* parent = nullptr);
~RadarProductModelItem();
void AppendChild(RadarProductModelItem* child);
const RadarProductModelItem* child(int row) const;
int child_count() const;
int column_count() const;
QVariant data(int column) const;
int row() const;
const RadarProductModelItem* parent_item() const;
private:
std::vector<RadarProductModelItem*> childItems_;
std::vector<QVariant> itemData_;
RadarProductModelItem* parentItem_;
};
class RadarProductModelImpl
{
public:
explicit RadarProductModelImpl() :
rootItem_ {std::make_shared<RadarProductModelItem>(
rootItem_ {std::make_shared<TreeItem>(
std::vector<QVariant> {QObject::tr("Name"), QObject::tr("Info")})}
{
rootItem_->AppendChild(new RadarProductModelItem(
rootItem_->AppendChild(new TreeItem(
std::vector<QVariant> {QObject::tr("MyItem"), QObject::tr("Data")}));
}
~RadarProductModelImpl() = default;
std::shared_ptr<RadarProductModelItem> rootItem_;
std::shared_ptr<TreeItem> rootItem_;
};
RadarProductModel::RadarProductModel(QObject* parent) :
QAbstractTableModel(parent), p(std::make_unique<RadarProductModelImpl>())
TreeModel(parent), p(std::make_unique<RadarProductModelImpl>())
{
}
RadarProductModel::~RadarProductModel() = default;
int RadarProductModel::rowCount(const QModelIndex& parent) const
const std::shared_ptr<TreeItem> RadarProductModel::root_item() const
{
const RadarProductModelItem* parentItem;
if (parent.isValid())
{
parentItem = static_cast<const RadarProductModelItem*>(
parent.constInternalPointer());
}
else
{
parentItem = p->rootItem_.get();
}
return parentItem->child_count();
}
int RadarProductModel::columnCount(const QModelIndex& parent) const
{
const RadarProductModelItem* parentItem;
if (parent.isValid())
{
parentItem = static_cast<const RadarProductModelItem*>(
parent.constInternalPointer());
}
else
{
parentItem = p->rootItem_.get();
}
return parentItem->column_count();
}
QVariant RadarProductModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid() || role != Qt::DisplayRole)
{
return QVariant();
}
const RadarProductModelItem* item =
static_cast<const RadarProductModelItem*>(index.internalPointer());
return item->data(index.column());
}
Qt::ItemFlags RadarProductModel::flags(const QModelIndex& index) const
{
Qt::ItemFlags flags;
if (!index.isValid())
{
flags = Qt::NoItemFlags;
}
else
{
flags = QAbstractItemModel::flags(index);
}
return flags;
}
QVariant RadarProductModel::headerData(int section,
Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
return p->rootItem_->data(section);
}
return QVariant();
}
QModelIndex
RadarProductModel::index(int row, int column, const QModelIndex& parent) const
{
if (!hasIndex(row, column, parent))
{
return QModelIndex();
}
const RadarProductModelItem* parentItem;
if (!parent.isValid())
{
parentItem = p->rootItem_.get();
}
else
{
parentItem = static_cast<const RadarProductModelItem*>(
parent.constInternalPointer());
}
const RadarProductModelItem* childItem = parentItem->child(row);
if (childItem)
{
return createIndex(row, column, childItem);
}
return QModelIndex();
}
QModelIndex RadarProductModel::parent(const QModelIndex& index) const
{
if (!index.isValid())
{
return QModelIndex();
}
const RadarProductModelItem* childItem =
static_cast<const RadarProductModelItem*>(index.constInternalPointer());
const RadarProductModelItem* parentItem = childItem->parent_item();
if (parentItem == p->rootItem_.get())
{
return QModelIndex();
}
return createIndex(parentItem->row(), 0, parentItem);
}
RadarProductModelItem::RadarProductModelItem(const std::vector<QVariant>& data,
RadarProductModelItem* parent) :
childItems_ {}, itemData_ {data}, parentItem_ {parent}
{
}
RadarProductModelItem::~RadarProductModelItem()
{
qDeleteAll(childItems_);
}
void RadarProductModelItem::AppendChild(RadarProductModelItem* item)
{
item->parentItem_ = this;
childItems_.push_back(item);
}
const RadarProductModelItem* RadarProductModelItem::child(int row) const
{
const RadarProductModelItem* item = nullptr;
if (0 <= row && row < childItems_.size())
{
item = childItems_[row];
}
return item;
}
int RadarProductModelItem::child_count() const
{
return static_cast<int>(childItems_.size());
}
int RadarProductModelItem::column_count() const
{
return static_cast<int>(itemData_.size());
}
QVariant RadarProductModelItem::data(int column) const
{
if (0 <= column && column < itemData_.size())
{
return itemData_[column];
}
else
{
return QVariant("Hello world");
}
}
int RadarProductModelItem::row() const
{
int row = 0;
if (parentItem_ != nullptr)
{
const auto& childItems = parentItem_->childItems_;
row =
std::distance(childItems.cbegin(),
std::find(childItems.cbegin(), childItems.cend(), this));
}
return row;
}
const RadarProductModelItem* RadarProductModelItem::parent_item() const
{
return parentItem_;
return p->rootItem_;
}
} // namespace model

View file

@ -1,8 +1,6 @@
#pragma once
#include <memory>
#include <QAbstractTableModel>
#include <scwx/qt/model/tree_model.hpp>
namespace scwx
{
@ -13,25 +11,14 @@ namespace model
class RadarProductModelImpl;
class RadarProductModel : public QAbstractTableModel
class RadarProductModel : public TreeModel
{
public:
explicit RadarProductModel(QObject* parent = nullptr);
~RadarProductModel();
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index,
int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
QVariant headerData(int section,
Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
QModelIndex index(int row,
int column,
const QModelIndex& parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex& index) const override;
protected:
const std::shared_ptr<TreeItem> root_item() const override;
private:
std::unique_ptr<RadarProductModelImpl> p;

View file

@ -0,0 +1,98 @@
#include <scwx/qt/model/tree_item.hpp>
namespace scwx
{
namespace qt
{
namespace model
{
static const std::string logPrefix_ = "scwx::qt::model::tree_item";
class TreeItem::Impl
{
public:
explicit Impl(const std::vector<QVariant>& data, TreeItem* parent) :
childItems_ {}, itemData_ {data}, parentItem_ {parent}
{
}
~Impl() { qDeleteAll(childItems_); }
std::vector<TreeItem*> childItems_;
std::vector<QVariant> itemData_;
TreeItem* parentItem_;
};
TreeItem::TreeItem(const std::vector<QVariant>& data, TreeItem* parent) :
p {std::make_unique<Impl>(data, parent)}
{
}
TreeItem::~TreeItem() {}
TreeItem::TreeItem(TreeItem&&) noexcept = default;
TreeItem& TreeItem::operator=(TreeItem&&) noexcept = default;
void TreeItem::AppendChild(TreeItem* item)
{
item->p->parentItem_ = this;
p->childItems_.push_back(item);
}
const TreeItem* TreeItem::child(int row) const
{
const TreeItem* item = nullptr;
if (0 <= row && row < p->childItems_.size())
{
item = p->childItems_[row];
}
return item;
}
int TreeItem::child_count() const
{
return static_cast<int>(p->childItems_.size());
}
int TreeItem::column_count() const
{
return static_cast<int>(p->itemData_.size());
}
QVariant TreeItem::data(int column) const
{
if (0 <= column && column < p->itemData_.size())
{
return p->itemData_[column];
}
else
{
return QVariant();
}
}
int TreeItem::row() const
{
int row = 0;
if (p->parentItem_ != nullptr)
{
const auto& childItems = p->parentItem_->p->childItems_;
row =
std::distance(childItems.cbegin(),
std::find(childItems.cbegin(), childItems.cend(), this));
}
return row;
}
const TreeItem* TreeItem::parent_item() const
{
return p->parentItem_;
}
} // namespace model
} // namespace qt
} // namespace scwx

View file

@ -0,0 +1,44 @@
#pragma once
#include <memory>
#include <vector>
#include <QVariant>
namespace scwx
{
namespace qt
{
namespace model
{
class TreeItem
{
public:
explicit TreeItem(const std::vector<QVariant>& data,
TreeItem* parent = nullptr);
virtual ~TreeItem();
TreeItem(const TreeItem&) = delete;
TreeItem& operator=(const TreeItem&) = delete;
TreeItem(TreeItem&&) noexcept;
TreeItem& operator=(TreeItem&&) noexcept;
void AppendChild(TreeItem* child);
const TreeItem* child(int row) const;
int child_count() const;
int column_count() const;
QVariant data(int column) const;
int row() const;
const TreeItem* parent_item() const;
private:
class Impl;
std::unique_ptr<Impl> p;
};
} // namespace model
} // namespace qt
} // namespace scwx

View file

@ -0,0 +1,145 @@
#include <scwx/qt/model/tree_model.hpp>
namespace scwx
{
namespace qt
{
namespace model
{
static const std::string logPrefix_ = "scwx::qt::model::tree_model";
class TreeModelImpl
{
public:
explicit TreeModelImpl() = default;
~TreeModelImpl() = default;
};
TreeModel::TreeModel(QObject* parent) :
QAbstractTableModel(parent), p(std::make_unique<TreeModelImpl>())
{
}
TreeModel::~TreeModel() = default;
int TreeModel::rowCount(const QModelIndex& parent) const
{
const TreeItem* parentItem;
if (parent.isValid())
{
parentItem = static_cast<const TreeItem*>(parent.constInternalPointer());
}
else
{
parentItem = root_item().get();
}
return parentItem->child_count();
}
int TreeModel::columnCount(const QModelIndex& parent) const
{
const TreeItem* parentItem;
if (parent.isValid())
{
parentItem = static_cast<const TreeItem*>(parent.constInternalPointer());
}
else
{
parentItem = root_item().get();
}
return parentItem->column_count();
}
QVariant TreeModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid() || role != Qt::DisplayRole)
{
return QVariant();
}
const TreeItem* item = static_cast<const TreeItem*>(index.internalPointer());
return item->data(index.column());
}
Qt::ItemFlags TreeModel::flags(const QModelIndex& index) const
{
Qt::ItemFlags flags;
if (!index.isValid())
{
flags = Qt::NoItemFlags;
}
else
{
flags = QAbstractItemModel::flags(index);
}
return flags;
}
QVariant
TreeModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
return root_item()->data(section);
}
return QVariant();
}
QModelIndex
TreeModel::index(int row, int column, const QModelIndex& parent) const
{
if (!hasIndex(row, column, parent))
{
return QModelIndex();
}
const TreeItem* parentItem;
if (!parent.isValid())
{
parentItem = root_item().get();
}
else
{
parentItem = static_cast<const TreeItem*>(parent.constInternalPointer());
}
const TreeItem* childItem = parentItem->child(row);
if (childItem)
{
return createIndex(row, column, childItem);
}
return QModelIndex();
}
QModelIndex TreeModel::parent(const QModelIndex& index) const
{
if (!index.isValid())
{
return QModelIndex();
}
const TreeItem* childItem =
static_cast<const TreeItem*>(index.constInternalPointer());
const TreeItem* parentItem = childItem->parent_item();
if (parentItem == root_item().get())
{
return QModelIndex();
}
return createIndex(parentItem->row(), 0, parentItem);
}
} // namespace model
} // namespace qt
} // namespace scwx

View file

@ -0,0 +1,45 @@
#pragma once
#include <scwx/qt/model/tree_item.hpp>
#include <QAbstractTableModel>
namespace scwx
{
namespace qt
{
namespace model
{
class TreeModelImpl;
class TreeModel : public QAbstractTableModel
{
public:
explicit TreeModel(QObject* parent = nullptr);
virtual ~TreeModel();
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index,
int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
QVariant headerData(int section,
Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
QModelIndex index(int row,
int column,
const QModelIndex& parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex& index) const override;
protected:
virtual const std::shared_ptr<TreeItem> root_item() const = 0;
private:
std::unique_ptr<TreeModelImpl> p;
};
} // namespace model
} // namespace qt
} // namespace scwx