diff --git a/src/application.cpp b/src/application.cpp index d9632f68a..e59a22c1e 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -100,6 +100,7 @@ void Application::initialize() this->accounts->load(); this->twitch.server->initialize(); + this->logging->initialize(); // XXX this->settings->updateWordTypeMask(); diff --git a/src/singletons/commandmanager.cpp b/src/singletons/commandmanager.cpp index 29d82645f..0ed1dcc02 100644 --- a/src/singletons/commandmanager.cpp +++ b/src/singletons/commandmanager.cpp @@ -24,7 +24,7 @@ CommandManager::CommandManager() auto addFirstMatchToMap = [this](auto args) { this->commandsMap.remove(args.item.name); - for (const Command &cmd : this->commands.getVector()) { + for (const Command &cmd : this->items.getVector()) { if (cmd.name == args.item.name) { this->commandsMap[cmd.name] = cmd; break; @@ -32,8 +32,8 @@ CommandManager::CommandManager() } }; - this->commands.itemInserted.connect(addFirstMatchToMap); - this->commands.itemRemoved.connect(addFirstMatchToMap); + this->items.itemInserted.connect(addFirstMatchToMap); + this->items.itemRemoved.connect(addFirstMatchToMap); } void CommandManager::load() @@ -50,7 +50,11 @@ void CommandManager::load() QList test = textFile.readAll().split('\n'); for (const auto &command : test) { - this->commands.appendItem(Command(command)); + if (command.isEmpty()) { + continue; + } + + this->items.appendItem(Command(command)); } textFile.close(); @@ -64,7 +68,7 @@ void CommandManager::save() return; } - for (const Command &cmd : this->commands.getVector()) { + for (const Command &cmd : this->items.getVector()) { textFile.write((cmd.toString() + "\n").toUtf8()); } @@ -73,7 +77,10 @@ void CommandManager::save() CommandModel *CommandManager::createModel(QObject *parent) { - return new CommandModel(&this->commands, parent); + CommandModel *model = new CommandModel(parent); + model->init(&this->items); + + return model; } QString CommandManager::execCommand(const QString &text, ChannelPtr channel, bool dryRun) @@ -232,13 +239,13 @@ QString CommandManager::execCustomCommand(const QStringList &words, const Comman } // commandmodel -CommandModel::CommandModel(util::BaseSignalVector *vec, QObject *parent) - : util::SignalVectorModel(vec, 2, parent) +CommandModel::CommandModel(QObject *parent) + : util::SignalVectorModel(2, parent) { } -int CommandModel::prepareInsert(const Command &item, int index, - std::vector &rowToAdd) +int CommandModel::prepareVectorInserted(const Command &item, int index, + std::vector &rowToAdd) { rowToAdd[0]->setData(item.name, Qt::EditRole); rowToAdd[1]->setData(item.func, Qt::EditRole); @@ -246,13 +253,18 @@ int CommandModel::prepareInsert(const Command &item, int index, return index; } -int CommandModel::prepareRemove(const Command &item, int index) +int CommandModel::prepareVectorRemoved(const Command &item, int index) { UNUSED(item); return index; } +int CommandModel::prepareModelItemRemoved(int index) +{ + return index; +} + // command Command::Command(const QString &_text) { diff --git a/src/singletons/commandmanager.hpp b/src/singletons/commandmanager.hpp index 2026d483a..2fc33b1b4 100644 --- a/src/singletons/commandmanager.hpp +++ b/src/singletons/commandmanager.hpp @@ -29,12 +29,13 @@ struct Command { class CommandModel : public util::SignalVectorModel { - explicit CommandModel(util::BaseSignalVector *vec, QObject *parent); + explicit CommandModel(QObject *parent); protected: - virtual int prepareInsert(const Command &item, int index, - std::vector &rowToAdd) override; - virtual int prepareRemove(const Command &item, int index) override; + virtual int prepareVectorInserted(const Command &item, int index, + std::vector &rowToAdd) override; + virtual int prepareVectorRemoved(const Command &item, int index) override; + virtual int prepareModelItemRemoved(int index) override; friend class CommandManager; }; @@ -54,7 +55,7 @@ public: CommandModel *createModel(QObject *parent); - util::UnsortedSignalVector commands; + util::UnsortedSignalVector items; private: QMap commandsMap; diff --git a/src/util/signalvector2.hpp b/src/util/signalvector2.hpp index f0d9e7217..054d2780c 100644 --- a/src/util/signalvector2.hpp +++ b/src/util/signalvector2.hpp @@ -66,7 +66,7 @@ public: TVectorItem item = this->vector[index]; this->vector.erase(this->vector.begin() + index); - ItemArgs args{item, args, caller}; + ItemArgs args{item, index, caller}; this->itemRemoved.invoke(args); } }; diff --git a/src/util/signalvectormodel.hpp b/src/util/signalvectormodel.hpp index 82870cbd6..cf1e3b1c2 100644 --- a/src/util/signalvectormodel.hpp +++ b/src/util/signalvectormodel.hpp @@ -13,27 +13,45 @@ template class SignalVectorModel : public QAbstractTableModel, pajlada::Signals::SignalHolder { public: - SignalVectorModel(util::BaseSignalVector *vec, int columnCount, - QObject *parent = nullptr) + SignalVectorModel(int columnCount, QObject *parent = nullptr) : QAbstractTableModel(parent) , _columnCount(columnCount) { - this->managedConnect(vec->itemInserted, [this](auto args) { + for (int i = 0; i < columnCount; i++) { + this->_headerData.emplace_back(); + } + } + + void init(util::BaseSignalVector *vec) + { + this->vector = vec; + + auto insert = [this](const BaseSignalVector::ItemArgs &args) { std::vector items; for (int i = 0; i < this->_columnCount; i++) { items.push_back(new QStandardItem()); } - int row = this->prepareInsert(args.item, args.index, items); + int row = this->prepareVectorInserted(args.item, args.index, items); 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(); - }); + }; + + int i = 0; + for (const TVectorItem &item : vec->getVector()) { + BaseSignalVector::ItemArgs args{item, i++, 0}; + + insert(args); + } + + this->managedConnect(vec->itemInserted, insert); + this->managedConnect(vec->itemRemoved, [this](auto args) { - int row = this->prepareRemove(args.item, args.index); + int row = this->prepareVectorRemoved(args.item, args.index); assert(row >= 0 && row <= this->rows.size()); // remove row @@ -55,17 +73,17 @@ public: } } - int rowCount(const QModelIndex &parent) const + virtual int rowCount(const QModelIndex &parent) const { return this->rows.size(); } - int columnCount(const QModelIndex &parent) const + virtual int columnCount(const QModelIndex &parent) const { return this->_columnCount; } - QVariant data(const QModelIndex &index, int role) const + virtual QVariant data(const QModelIndex &index, int role) const { int row = index.row(), column = index.column(); assert(row >= 0 && row < this->rows.size() && column >= 0 && column < this->_columnCount); @@ -73,24 +91,69 @@ public: return rows[row].items[column]->data(role); } - bool setData(const QModelIndex &index, const QVariant &value, int role) + virtual bool setData(const QModelIndex &index, const QVariant &value, int role) { this->rows[index.row()].items[index.column()]->setData(value, role); return true; } - QStandardItem *getItem(int row, int column) + 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) { assert(row >= 0 && row < this->rows.size() && column >= 0 && column < this->_columnCount); - return rows[row][column]; + 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); } protected: - virtual int prepareInsert(const TVectorItem &item, int index, - std::vector &rowToAdd) = 0; - virtual int prepareRemove(const TVectorItem &item, int index) = 0; + // 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 &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; private: struct Row { @@ -105,6 +168,9 @@ private: }; std::vector rows; + std::vector> _headerData; + BaseSignalVector *vector; + int _columnCount; }; diff --git a/src/widgets/settingspages/commandpage.cpp b/src/widgets/settingspages/commandpage.cpp index deb91584e..beb7012b5 100644 --- a/src/widgets/settingspages/commandpage.cpp +++ b/src/widgets/settingspages/commandpage.cpp @@ -35,7 +35,40 @@ CommandPage::CommandPage() QTableView *view = *layout.emplace(); - auto *model = app->commands->createModel(this); + auto *model = app->commands->createModel(view); + view->setModel(model); + model->setHeaderData(0, Qt::Horizontal, "Trigger"); + model->setHeaderData(1, Qt::Horizontal, "Command"); + view->setSelectionMode(QAbstractItemView::ExtendedSelection); + view->setSelectionBehavior(QAbstractItemView::SelectRows); + view->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); + view->verticalHeader()->hide(); + + auto buttons = layout.emplace().withoutMargin(); + { + auto add = buttons.emplace("Add"); + QObject::connect(*add, &QPushButton::clicked, [model, view] { + getApp()->commands->items.appendItem( + singletons::Command{"/command", "I made a new command HeyGuys"}); + view->scrollToBottom(); + }); + + auto remove = buttons.emplace("Remove"); + QObject::connect(*remove, &QPushButton::clicked, [view, model] { + std::vector indices; + + for (const QModelIndex &index : view->selectionModel()->selectedRows(0)) { + indices.push_back(index.row()); + } + + std::sort(indices.begin(), indices.end()); + + for (int i = indices.size() - 1; i >= 0; i--) { + model->removeRow(indices[i]); + } + }); + buttons->addStretch(1); + } // QTableView *view = *layout.emplace(); // QStandardItemModel *model = new QStandardItemModel(0, 2, view);