2018-04-29 23:25:49 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <QAbstractTableModel>
|
|
|
|
#include <QStandardItem>
|
|
|
|
#include <util/signalvector2.hpp>
|
|
|
|
|
|
|
|
#include <pajlada/signals/signalholder.hpp>
|
|
|
|
|
|
|
|
namespace chatterino {
|
|
|
|
namespace util {
|
|
|
|
|
|
|
|
template <typename TVectorItem>
|
|
|
|
class SignalVectorModel : public QAbstractTableModel, pajlada::Signals::SignalHolder
|
|
|
|
{
|
|
|
|
public:
|
2018-04-30 00:41:58 +02:00
|
|
|
SignalVectorModel(int columnCount, QObject *parent = nullptr)
|
2018-04-29 23:25:49 +02:00
|
|
|
: QAbstractTableModel(parent)
|
|
|
|
, _columnCount(columnCount)
|
|
|
|
{
|
2018-04-30 00:41:58 +02:00
|
|
|
for (int i = 0; i < columnCount; i++) {
|
|
|
|
this->_headerData.emplace_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void init(util::BaseSignalVector<TVectorItem> *vec)
|
|
|
|
{
|
|
|
|
this->vector = vec;
|
|
|
|
|
2018-04-30 20:35:01 +02:00
|
|
|
auto insert = [this](const typename BaseSignalVector<TVectorItem>::ItemArgs &args) {
|
2018-04-29 23:25:49 +02:00
|
|
|
std::vector<QStandardItem *> items;
|
|
|
|
for (int i = 0; i < this->_columnCount; i++) {
|
|
|
|
items.push_back(new QStandardItem());
|
|
|
|
}
|
|
|
|
|
2018-04-30 00:41:58 +02:00
|
|
|
int row = this->prepareVectorInserted(args.item, args.index, items);
|
2018-04-29 23:25:49 +02:00
|
|
|
assert(row >= 0 && row <= this->rows.size());
|
|
|
|
|
|
|
|
// insert row
|
|
|
|
this->beginInsertRows(QModelIndex(), row, row);
|
|
|
|
this->rows.insert(this->rows.begin() + row, Row(items));
|
|
|
|
this->endInsertRows();
|
2018-04-30 00:41:58 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
for (const TVectorItem &item : vec->getVector()) {
|
2018-04-30 20:35:01 +02:00
|
|
|
typename BaseSignalVector<TVectorItem>::ItemArgs args{item, i++, 0};
|
2018-04-30 00:41:58 +02:00
|
|
|
|
|
|
|
insert(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
this->managedConnect(vec->itemInserted, insert);
|
|
|
|
|
2018-04-29 23:25:49 +02:00
|
|
|
this->managedConnect(vec->itemRemoved, [this](auto args) {
|
2018-04-30 00:41:58 +02:00
|
|
|
int row = this->prepareVectorRemoved(args.item, args.index);
|
2018-04-29 23:25:49 +02:00
|
|
|
assert(row >= 0 && row <= this->rows.size());
|
|
|
|
|
|
|
|
// remove row
|
|
|
|
this->beginRemoveRows(QModelIndex(), row, row);
|
|
|
|
for (QStandardItem *item : this->rows[row].items) {
|
|
|
|
delete item;
|
|
|
|
}
|
|
|
|
this->rows.erase(this->rows.begin() + row);
|
|
|
|
this->endRemoveRows();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~SignalVectorModel()
|
|
|
|
{
|
|
|
|
for (Row &row : this->rows) {
|
|
|
|
for (QStandardItem *item : row.items) {
|
|
|
|
delete item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-30 00:41:58 +02:00
|
|
|
virtual int rowCount(const QModelIndex &parent) const
|
2018-04-29 23:25:49 +02:00
|
|
|
{
|
|
|
|
return this->rows.size();
|
|
|
|
}
|
|
|
|
|
2018-04-30 00:41:58 +02:00
|
|
|
virtual int columnCount(const QModelIndex &parent) const
|
2018-04-29 23:25:49 +02:00
|
|
|
{
|
|
|
|
return this->_columnCount;
|
|
|
|
}
|
|
|
|
|
2018-04-30 00:41:58 +02:00
|
|
|
virtual QVariant data(const QModelIndex &index, int role) const
|
2018-04-29 23:25:49 +02:00
|
|
|
{
|
|
|
|
int row = index.row(), column = index.column();
|
|
|
|
assert(row >= 0 && row < this->rows.size() && column >= 0 && column < this->_columnCount);
|
|
|
|
|
|
|
|
return rows[row].items[column]->data(role);
|
|
|
|
}
|
|
|
|
|
2018-04-30 00:41:58 +02:00
|
|
|
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
|
2018-04-29 23:25:49 +02:00
|
|
|
{
|
|
|
|
this->rows[index.row()].items[index.column()]->setData(value, role);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-04-30 00:41:58 +02:00
|
|
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const
|
|
|
|
{
|
|
|
|
if (orientation != Qt::Horizontal) {
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto it = this->_headerData[section].find(role);
|
|
|
|
if (it == this->_headerData[section].end()) {
|
|
|
|
return QVariant();
|
|
|
|
} else {
|
|
|
|
return it.value();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value,
|
|
|
|
int role = Qt::DisplayRole)
|
|
|
|
{
|
|
|
|
if (orientation != Qt::Horizontal) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->_headerData[section][role] = value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QStandardItem *getItem(int row, int column)
|
2018-04-29 23:25:49 +02:00
|
|
|
{
|
|
|
|
assert(row >= 0 && row < this->rows.size() && column >= 0 && column < this->_columnCount);
|
|
|
|
|
2018-04-30 00:41:58 +02:00
|
|
|
return rows[row].items[column];
|
|
|
|
}
|
|
|
|
|
|
|
|
void removeRow(int row)
|
|
|
|
{
|
|
|
|
assert(row >= 0 && row <= this->rows.size());
|
|
|
|
|
|
|
|
int signalVectorRow = this->prepareModelItemRemoved(row);
|
|
|
|
this->vector->removeItem(signalVectorRow);
|
2018-04-29 23:25:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2018-04-30 00:41:58 +02:00
|
|
|
// gets called when an item gets inserted into the SignalVector
|
|
|
|
//
|
|
|
|
// returns the index of that the row should be inserted into and edits the rowToAdd elements
|
|
|
|
// based on the item
|
|
|
|
virtual int prepareVectorInserted(const TVectorItem &item, int index,
|
|
|
|
std::vector<QStandardItem *> &rowToAdd) = 0;
|
|
|
|
// gets called when an item gets removed from a SignalVector
|
|
|
|
//
|
|
|
|
// returns the index of the row in the model that should be removed
|
|
|
|
virtual int prepareVectorRemoved(const TVectorItem &item, int index) = 0;
|
|
|
|
|
|
|
|
// gets called when an item gets removed from the model
|
|
|
|
//
|
|
|
|
// returns the related index of the SignalVector
|
|
|
|
virtual int prepareModelItemRemoved(int index) = 0;
|
2018-04-29 23:25:49 +02:00
|
|
|
|
|
|
|
private:
|
|
|
|
struct Row {
|
|
|
|
std::vector<QStandardItem *> items;
|
|
|
|
bool isCustomRow;
|
|
|
|
|
|
|
|
Row(const std::vector<QStandardItem *> _items, bool _isCustomRow = false)
|
|
|
|
: items(_items)
|
|
|
|
, isCustomRow(_isCustomRow)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<Row> rows;
|
2018-04-30 00:41:58 +02:00
|
|
|
std::vector<QMap<int, QVariant>> _headerData;
|
|
|
|
BaseSignalVector<TVectorItem> *vector;
|
|
|
|
|
2018-04-29 23:25:49 +02:00
|
|
|
int _columnCount;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace util
|
|
|
|
} // namespace chatterino
|