mirror-chatterino2/src/common/SignalVectorModel.hpp
Vilgot Fredenberg de04ff82a7
Clean up compiler warnings (#2027)
Fix the following compiler warning
../src/common/NetworkResult.hpp: In constructor ‘chatterino::NetworkResult::NetworkResult(const QByteArray&, int)’:
../src/common/NetworkResult.hpp:28:16: warning: ‘chatterino::NetworkResult::data_’ will be initialized after [-Wreorder]
   28 |     QByteArray data_;
      |                ^~~~~
../src/common/NetworkResult.hpp:27:9: warning:   ‘int chatterino::NetworkResult::status_’ [-Wreorder]
   27 |     int status_;
      |         ^~~~~~~
../src/common/NetworkResult.cpp:9:1: warning:   when initialized here [-Wreorder]
    9 | NetworkResult::NetworkResult(const QByteArray &data, int status)

* Clang compiler warnings

Fixes every instance of the following error:

In file included from ../src/widgets/settingspages/CommandPage.cpp:12:
In file included from ../src/controllers/commands/CommandModel.hpp:5:
../src/common/SignalVectorModel.hpp:242:10: warning: 'moveRows' overrides a member function but is not marked 'override' [-Winconsistent-missing-override]
    bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
         ^
../src/controllers/commands/CommandModel.hpp:12:29: note: in instantiation of template class 'chatterino::SignalVectorModel<chatterino::Command>' requested here
class CommandModel : public SignalVectorModel<Command>
2020-10-04 12:47:23 +02:00

486 lines
13 KiB
C++

#pragma once
#include "common/SignalVector.hpp"
#include <QAbstractTableModel>
#include <QStandardItem>
#include <boost/optional.hpp>
#include <pajlada/signals/signalholder.hpp>
namespace chatterino {
template <typename TVectorItem>
class SignalVectorModel : public QAbstractTableModel,
pajlada::Signals::SignalHolder
{
public:
SignalVectorModel(int columnCount, QObject *parent = nullptr)
: QAbstractTableModel(parent)
, columnCount_(columnCount)
{
for (int i = 0; i < columnCount; i++)
{
this->headerData_.emplace_back();
}
}
void initialize(SignalVector<TVectorItem> *vec)
{
this->vector_ = vec;
auto insert = [this](const SignalVectorItemEvent<TVectorItem> &args) {
if (args.caller == this)
{
return;
}
// get row index
int index = this->getModelIndexFromVectorIndex(args.index);
assert(index >= 0 && index <= this->rows_.size());
// get row items
std::vector<QStandardItem *> row = this->createRow();
this->getRowFromItem(args.item, row);
// insert row
index = this->beforeInsert(args.item, row, index);
this->beginInsertRows(QModelIndex(), index, index);
this->rows_.insert(this->rows_.begin() + index,
Row(row, args.item));
this->endInsertRows();
};
int i = 0;
for (const TVectorItem &item : vec->raw())
{
SignalVectorItemEvent<TVectorItem> args{item, i++, 0};
insert(args);
}
this->managedConnect(vec->itemInserted, insert);
this->managedConnect(vec->itemRemoved, [this](auto args) {
if (args.caller == this)
{
return;
}
int row = this->getModelIndexFromVectorIndex(args.index);
assert(row >= 0 && row <= this->rows_.size());
// remove row
std::vector<QStandardItem *> items = this->rows_[row].items;
this->beginRemoveRows(QModelIndex(), row, row);
this->rows_.erase(this->rows_.begin() + row);
this->endRemoveRows();
this->afterRemoved(args.item, items, row);
for (QStandardItem *item : items)
{
delete item;
}
});
this->afterInit();
}
SignalVectorModel<TVectorItem> *initialized(SignalVector<TVectorItem> *vec)
{
this->initialize(vec);
return this;
}
virtual ~SignalVectorModel()
{
for (Row &row : this->rows_)
{
for (QStandardItem *item : row.items)
{
delete item;
}
}
}
int rowCount(const QModelIndex &parent) const override
{
(void)parent;
return this->rows_.size();
}
int columnCount(const QModelIndex &parent) const override
{
(void)parent;
return this->columnCount_;
}
QVariant data(const QModelIndex &index, int role) const override
{
int row = index.row(), column = index.column();
if (row < 0 || column < 0 || row >= this->rows_.size() ||
column >= this->columnCount_)
{
return QVariant();
}
return rows_[row].items[column]->data(role);
}
bool setData(const QModelIndex &index, const QVariant &value,
int role) override
{
int row = index.row(), column = index.column();
if (row < 0 || column < 0 || row >= this->rows_.size() ||
column >= this->columnCount_)
{
return false;
}
Row &rowItem = this->rows_[row];
assert(this->columnCount_ == rowItem.items.size());
auto &cell = rowItem.items[column];
cell->setData(value, role);
if (rowItem.isCustomRow)
{
this->customRowSetData(rowItem.items, column, value, role, row);
}
else
{
int vecRow = this->getVectorIndexFromModelIndex(row);
this->vector_->removeAt(vecRow, this);
assert(this->rows_[row].original);
TVectorItem item = this->getItemFromRow(
this->rows_[row].items, this->rows_[row].original.get());
this->vector_->insert(item, vecRow, this);
}
return true;
}
QVariant headerData(int section, Qt::Orientation orientation,
int role) const override
{
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) override
{
if (orientation != Qt::Horizontal)
{
return false;
}
this->headerData_[section][role] = value;
emit this->headerDataChanged(Qt::Horizontal, section, section);
return true;
}
Qt::ItemFlags flags(const QModelIndex &index) const override
{
int row = index.row(), column = index.column();
if (row < 0 || column < 0 || row >= this->rows_.size() ||
column >= this->columnCount_)
{
return Qt::NoItemFlags;
}
assert(row >= 0 && row < this->rows_.size() && column >= 0 &&
column < this->columnCount_);
const auto &rowItem = this->rows_[row];
assert(this->columnCount_ == rowItem.items.size());
return rowItem.items[column]->flags();
}
QStandardItem *getItem(int row, int column)
{
assert(row >= 0 && row < this->rows_.size() && column >= 0 &&
column < this->columnCount_);
const auto &rowItem = this->rows_[row];
assert(this->columnCount_ == rowItem.items.size());
return rowItem.items[column];
}
void deleteRow(int row)
{
int signalVectorRow = this->getVectorIndexFromModelIndex(row);
this->vector_->removeAt(signalVectorRow);
}
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
const QModelIndex &destinationParent,
int destinationChild) override
{
if (count != 1)
{
return false;
}
assert(sourceRow >= 0 && sourceRow < this->rows_.size());
int signalVectorRow = this->getVectorIndexFromModelIndex(sourceRow);
this->beginMoveRows(sourceParent, sourceRow, sourceRow,
destinationParent, destinationChild);
TVectorItem item =
this->getItemFromRow(this->rows_[sourceRow].items,
this->rows_[sourceRow].original.get());
this->vector_->removeAt(signalVectorRow);
this->vector_->insert(
item, this->getVectorIndexFromModelIndex(destinationChild));
this->endMoveRows();
return true;
}
bool removeRows(int row, int count, const QModelIndex &parent) override
{
(void)parent;
if (count != 1)
{
return false;
}
assert(row >= 0 && row < this->rows_.size());
int signalVectorRow = this->getVectorIndexFromModelIndex(row);
this->vector_->removeAt(signalVectorRow);
return true;
}
QStringList mimeTypes() const override
{
return {"chatterino_row_id"};
}
QMimeData *mimeData(const QModelIndexList &list) const override
{
if (list.length() == 1)
{
return nullptr;
}
// Check if all indices are in the same row -> single row selected
for (auto &&x : list)
{
if (x.row() != list.first().row())
return nullptr;
}
auto data = new QMimeData;
data->setData("chatterino_row_id", QByteArray::number(list[0].row()));
return data;
}
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int /*row*/,
int /*column*/, const QModelIndex &parent) override
{
if (data->hasFormat("chatterino_row_id") &&
action & (Qt::DropAction::MoveAction | Qt::DropAction::CopyAction))
{
int from = data->data("chatterino_row_id").toInt();
int to = parent.row();
int vectorFrom = this->getVectorIndexFromModelIndex(from);
int vectorTo = this->getVectorIndexFromModelIndex(to);
if (vectorFrom < 0 || vectorFrom > this->vector_->raw().size() ||
vectorTo < 0 || vectorTo > this->vector_->raw().size())
{
return false;
}
if (from != to)
{
this->moveRow(this->index(from, to), from, parent, to);
}
// We return false since we remove items ourselves.
return false;
}
return false;
}
Qt::DropActions supportedDropActions() const override
{
return this->vector_->isSorted()
? Qt::DropActions()
: Qt::DropAction::CopyAction | Qt::DropAction::MoveAction;
}
protected:
virtual void afterInit()
{
}
// turn a vector item into a model row
virtual TVectorItem getItemFromRow(std::vector<QStandardItem *> &row,
const TVectorItem &original) = 0;
// turns a row in the model into a vector item
virtual void getRowFromItem(const TVectorItem &item,
std::vector<QStandardItem *> &row) = 0;
virtual int beforeInsert(const TVectorItem &item,
std::vector<QStandardItem *> &row,
int proposedIndex)
{
(void)item, (void)row;
return proposedIndex;
}
virtual void afterRemoved(const TVectorItem &item,
std::vector<QStandardItem *> &row, int index)
{
(void)item, (void)row, (void)index;
}
virtual void customRowSetData(const std::vector<QStandardItem *> &row,
int column, const QVariant &value, int role,
int rowIndex)
{
(void)row, (void)column, (void)value, (void)role, (void)rowIndex;
}
void insertCustomRow(std::vector<QStandardItem *> row, int index)
{
assert(index >= 0 && index <= this->rows_.size());
this->beginInsertRows(QModelIndex(), index, index);
this->rows_.insert(this->rows_.begin() + index,
Row(std::move(row), true));
this->endInsertRows();
}
void removeCustomRow(int index)
{
assert(index >= 0 && index <= this->rows_.size());
assert(this->rows_[index].isCustomRow);
this->beginRemoveRows(QModelIndex(), index, index);
this->rows_.erase(this->rows_.begin() + index);
this->endRemoveRows();
}
std::vector<QStandardItem *> createRow()
{
std::vector<QStandardItem *> row;
for (int i = 0; i < this->columnCount_; i++)
{
row.push_back(new QStandardItem());
}
return row;
}
struct Row {
std::vector<QStandardItem *> items;
boost::optional<TVectorItem> original;
bool isCustomRow;
Row(std::vector<QStandardItem *> _items, bool _isCustomRow = false)
: items(std::move(_items))
, isCustomRow(_isCustomRow)
{
}
Row(std::vector<QStandardItem *> _items, const TVectorItem &_original,
bool _isCustomRow = false)
: items(std::move(_items))
, original(_original)
, isCustomRow(_isCustomRow)
{
}
};
private:
std::vector<QMap<int, QVariant>> headerData_;
SignalVector<TVectorItem> *vector_;
std::vector<Row> rows_;
const int columnCount_;
// returns the related index of the SignalVector
int getVectorIndexFromModelIndex(int index)
{
int i = 0;
for (auto &row : this->rows_)
{
if (row.isCustomRow)
{
index--;
continue;
}
if (i == index)
{
return i;
}
i++;
}
return i;
}
// returns the related index of the model
int getModelIndexFromVectorIndex(int index)
{
int i = 0;
for (auto &row : this->rows_)
{
if (row.isCustomRow)
{
index++;
}
if (i == index)
{
return i;
}
i++;
}
return i;
}
};
} // namespace chatterino