mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
changed CommandManager to CommandController
This commit is contained in:
parent
b907bf5639
commit
4c3f0921e2
17 changed files with 524 additions and 398 deletions
|
@ -186,7 +186,9 @@ SOURCES += \
|
||||||
src/widgets/settingspages/externaltoolspage.cpp \
|
src/widgets/settingspages/externaltoolspage.cpp \
|
||||||
src/widgets/helper/comboboxitemdelegate.cpp \
|
src/widgets/helper/comboboxitemdelegate.cpp \
|
||||||
src/util/signalvectormodel.cpp \
|
src/util/signalvectormodel.cpp \
|
||||||
src/managers/commands/command.cpp
|
src/controllers/commands/command.cpp \
|
||||||
|
src/controllers/commands/commandmodel.cpp \
|
||||||
|
src/controllers/commands/commandcontroller.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
src/precompiled_header.hpp \
|
src/precompiled_header.hpp \
|
||||||
|
@ -320,7 +322,9 @@ HEADERS += \
|
||||||
src/util/assertinguithread.hpp \
|
src/util/assertinguithread.hpp \
|
||||||
src/util/signalvector2.hpp \
|
src/util/signalvector2.hpp \
|
||||||
src/util/signalvectormodel.hpp \
|
src/util/signalvectormodel.hpp \
|
||||||
src/managers/commands/command.hpp
|
src/controllers/commands/command.hpp \
|
||||||
|
src/controllers/commands/commandmodel.hpp \
|
||||||
|
src/controllers/commands/commandcontroller.hpp
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
resources/resources.qrc
|
resources/resources.qrc
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#include "application.hpp"
|
#include "application.hpp"
|
||||||
|
|
||||||
|
#include "controllers/commands/commandcontroller.hpp"
|
||||||
#include "providers/twitch/pubsub.hpp"
|
#include "providers/twitch/pubsub.hpp"
|
||||||
#include "providers/twitch/twitchserver.hpp"
|
#include "providers/twitch/twitchserver.hpp"
|
||||||
#include "singletons/accountmanager.hpp"
|
#include "singletons/accountmanager.hpp"
|
||||||
#include "singletons/commandmanager.hpp"
|
|
||||||
#include "singletons/emotemanager.hpp"
|
#include "singletons/emotemanager.hpp"
|
||||||
#include "singletons/fontmanager.hpp"
|
#include "singletons/fontmanager.hpp"
|
||||||
#include "singletons/loggingmanager.hpp"
|
#include "singletons/loggingmanager.hpp"
|
||||||
|
@ -63,7 +63,7 @@ void Application::construct()
|
||||||
this->themes = new singletons::ThemeManager;
|
this->themes = new singletons::ThemeManager;
|
||||||
this->windows = new singletons::WindowManager;
|
this->windows = new singletons::WindowManager;
|
||||||
this->logging = new singletons::LoggingManager;
|
this->logging = new singletons::LoggingManager;
|
||||||
this->commands = new singletons::CommandManager;
|
this->commands = new controllers::commands::CommandController;
|
||||||
this->accounts = new singletons::AccountManager;
|
this->accounts = new singletons::AccountManager;
|
||||||
this->emotes = new singletons::EmoteManager;
|
this->emotes = new singletons::EmoteManager;
|
||||||
this->settings = new singletons::SettingManager;
|
this->settings = new singletons::SettingManager;
|
||||||
|
|
|
@ -16,13 +16,18 @@ class PubSub;
|
||||||
} // namespace twitch
|
} // namespace twitch
|
||||||
} // namespace providers
|
} // namespace providers
|
||||||
|
|
||||||
|
namespace controllers {
|
||||||
|
namespace commands {
|
||||||
|
class CommandController;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace singletons {
|
namespace singletons {
|
||||||
|
|
||||||
class ThemeManager;
|
class ThemeManager;
|
||||||
class WindowManager;
|
class WindowManager;
|
||||||
class LoggingManager;
|
class LoggingManager;
|
||||||
class PathManager;
|
class PathManager;
|
||||||
class CommandManager;
|
|
||||||
class AccountManager;
|
class AccountManager;
|
||||||
class EmoteManager;
|
class EmoteManager;
|
||||||
class NativeMessagingManager;
|
class NativeMessagingManager;
|
||||||
|
@ -53,7 +58,7 @@ public:
|
||||||
singletons::ThemeManager *themes = nullptr;
|
singletons::ThemeManager *themes = nullptr;
|
||||||
singletons::WindowManager *windows = nullptr;
|
singletons::WindowManager *windows = nullptr;
|
||||||
singletons::LoggingManager *logging = nullptr;
|
singletons::LoggingManager *logging = nullptr;
|
||||||
singletons::CommandManager *commands = nullptr;
|
controllers::commands::CommandController *commands = nullptr;
|
||||||
singletons::AccountManager *accounts = nullptr;
|
singletons::AccountManager *accounts = nullptr;
|
||||||
singletons::EmoteManager *emotes = nullptr;
|
singletons::EmoteManager *emotes = nullptr;
|
||||||
singletons::NativeMessagingManager *nativeMessaging = nullptr;
|
singletons::NativeMessagingManager *nativeMessaging = nullptr;
|
||||||
|
|
34
src/controllers/commands/command.cpp
Normal file
34
src/controllers/commands/command.cpp
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#include "command.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace controllers {
|
||||||
|
namespace commands {
|
||||||
|
|
||||||
|
// command
|
||||||
|
Command::Command(const QString &_text)
|
||||||
|
{
|
||||||
|
int index = _text.indexOf(' ');
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
this->name = _text;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->name = _text.mid(0, index);
|
||||||
|
this->func = _text.mid(index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Command::Command(const QString &_name, const QString &_func)
|
||||||
|
: name(_name)
|
||||||
|
, func(_func)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Command::toString() const
|
||||||
|
{
|
||||||
|
return this->name + " " + this->func;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace commands
|
||||||
|
} // namespace controllers
|
||||||
|
} // namespace chatterino
|
22
src/controllers/commands/command.hpp
Normal file
22
src/controllers/commands/command.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace controllers {
|
||||||
|
namespace commands {
|
||||||
|
|
||||||
|
struct Command {
|
||||||
|
QString name;
|
||||||
|
QString func;
|
||||||
|
|
||||||
|
Command() = default;
|
||||||
|
explicit Command(const QString &text);
|
||||||
|
Command(const QString &name, const QString &func);
|
||||||
|
|
||||||
|
QString toString() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace commands
|
||||||
|
} // namespace controllers
|
||||||
|
} // namespace chatterino
|
245
src/controllers/commands/commandcontroller.cpp
Normal file
245
src/controllers/commands/commandcontroller.cpp
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
#include "commandcontroller.hpp"
|
||||||
|
|
||||||
|
#include "application.hpp"
|
||||||
|
#include "controllers/commands/command.hpp"
|
||||||
|
#include "controllers/commands/commandmodel.hpp"
|
||||||
|
#include "messages/messagebuilder.hpp"
|
||||||
|
#include "providers/twitch/twitchchannel.hpp"
|
||||||
|
#include "providers/twitch/twitchserver.hpp"
|
||||||
|
#include "singletons/accountmanager.hpp"
|
||||||
|
#include "singletons/pathmanager.hpp"
|
||||||
|
#include "util/signalvector2.hpp"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
using namespace chatterino::providers::twitch;
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace controllers {
|
||||||
|
namespace commands {
|
||||||
|
|
||||||
|
CommandController::CommandController()
|
||||||
|
{
|
||||||
|
auto addFirstMatchToMap = [this](auto args) {
|
||||||
|
this->commandsMap.remove(args.item.name);
|
||||||
|
|
||||||
|
for (const Command &cmd : this->items.getVector()) {
|
||||||
|
if (cmd.name == args.item.name) {
|
||||||
|
this->commandsMap[cmd.name] = cmd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this->items.itemInserted.connect(addFirstMatchToMap);
|
||||||
|
this->items.itemRemoved.connect(addFirstMatchToMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandController::load()
|
||||||
|
{
|
||||||
|
auto app = getApp();
|
||||||
|
this->filePath = app->paths->customFolderPath + "/Commands.txt";
|
||||||
|
|
||||||
|
QFile textFile(this->filePath);
|
||||||
|
if (!textFile.open(QIODevice::ReadOnly)) {
|
||||||
|
// No commands file created yet
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QByteArray> test = textFile.readAll().split('\n');
|
||||||
|
|
||||||
|
for (const auto &command : test) {
|
||||||
|
if (command.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->items.appendItem(Command(command));
|
||||||
|
}
|
||||||
|
|
||||||
|
textFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandController::save()
|
||||||
|
{
|
||||||
|
QFile textFile(this->filePath);
|
||||||
|
if (!textFile.open(QIODevice::WriteOnly)) {
|
||||||
|
debug::Log("[CommandController::saveCommands] Unable to open {} for writing",
|
||||||
|
this->filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const Command &cmd : this->items.getVector()) {
|
||||||
|
textFile.write((cmd.toString() + "\n").toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
textFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandModel *CommandController::createModel(QObject *parent)
|
||||||
|
{
|
||||||
|
CommandModel *model = new CommandModel(parent);
|
||||||
|
model->init(&this->items);
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CommandController::execCommand(const QString &text, ChannelPtr channel, bool dryRun)
|
||||||
|
{
|
||||||
|
QStringList words = text.split(' ', QString::SkipEmptyParts);
|
||||||
|
Command command;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(this->mutex);
|
||||||
|
|
||||||
|
if (words.length() == 0) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString commandName = words[0];
|
||||||
|
|
||||||
|
// check if default command exists
|
||||||
|
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
||||||
|
|
||||||
|
if (!dryRun && twitchChannel != nullptr) {
|
||||||
|
if (commandName == "/debug-args") {
|
||||||
|
QString msg = QApplication::instance()->arguments().join(' ');
|
||||||
|
|
||||||
|
channel->addMessage(messages::Message::createSystemMessage(msg));
|
||||||
|
|
||||||
|
return "";
|
||||||
|
} else if (commandName == "/uptime") {
|
||||||
|
const auto &streamStatus = twitchChannel->GetStreamStatus();
|
||||||
|
|
||||||
|
QString messageText =
|
||||||
|
streamStatus.live ? streamStatus.uptime : "Channel is not live.";
|
||||||
|
|
||||||
|
channel->addMessage(messages::Message::createSystemMessage(messageText));
|
||||||
|
|
||||||
|
return "";
|
||||||
|
} else if (commandName == "/ignore" && words.size() >= 2) {
|
||||||
|
// fourtf: ignore user
|
||||||
|
// QString messageText;
|
||||||
|
|
||||||
|
// if (IrcManager::getInstance().tryAddIgnoredUser(words.at(1),
|
||||||
|
// messageText)) {
|
||||||
|
// messageText = "Ignored user \"" + words.at(1) + "\".";
|
||||||
|
// }
|
||||||
|
|
||||||
|
// channel->addMessage(messages::Message::createSystemMessage(messageText));
|
||||||
|
return "";
|
||||||
|
} else if (commandName == "/unignore") {
|
||||||
|
// fourtf: ignore user
|
||||||
|
// QString messageText;
|
||||||
|
|
||||||
|
// if (IrcManager::getInstance().tryRemoveIgnoredUser(words.at(1),
|
||||||
|
// messageText)) {
|
||||||
|
// messageText = "Ignored user \"" + words.at(1) + "\".";
|
||||||
|
// }
|
||||||
|
|
||||||
|
// channel->addMessage(messages::Message::createSystemMessage(messageText));
|
||||||
|
return "";
|
||||||
|
} else if (commandName == "/w") {
|
||||||
|
if (words.length() <= 2) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto app = getApp();
|
||||||
|
|
||||||
|
messages::MessageBuilder b;
|
||||||
|
|
||||||
|
b.emplace<messages::TextElement>(app->accounts->Twitch.getCurrent()->getUserName(),
|
||||||
|
messages::MessageElement::Text);
|
||||||
|
b.emplace<messages::TextElement>("->", messages::MessageElement::Text);
|
||||||
|
b.emplace<messages::TextElement>(words[1], messages::MessageElement::Text);
|
||||||
|
|
||||||
|
QString rest = "";
|
||||||
|
|
||||||
|
for (int i = 2; i < words.length(); i++) {
|
||||||
|
rest += words[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
b.emplace<messages::TextElement>(rest, messages::MessageElement::Text);
|
||||||
|
|
||||||
|
app->twitch.server->whispersChannel->addMessage(b.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if custom command exists
|
||||||
|
auto it = this->commandsMap.find(commandName);
|
||||||
|
if (it == this->commandsMap.end()) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
command = it.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->execCustomCommand(words, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CommandController::execCustomCommand(const QStringList &words, const Command &command)
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
|
||||||
|
static QRegularExpression parseCommand("(^|[^{])({{)*{(\\d+\\+?)}");
|
||||||
|
|
||||||
|
int lastCaptureEnd = 0;
|
||||||
|
|
||||||
|
auto globalMatch = parseCommand.globalMatch(command.func);
|
||||||
|
int matchOffset = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
QRegularExpressionMatch match = parseCommand.match(command.func, matchOffset);
|
||||||
|
|
||||||
|
if (!match.hasMatch()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result += command.func.mid(lastCaptureEnd, match.capturedStart() - lastCaptureEnd + 1);
|
||||||
|
|
||||||
|
lastCaptureEnd = match.capturedEnd();
|
||||||
|
matchOffset = lastCaptureEnd - 1;
|
||||||
|
|
||||||
|
QString wordIndexMatch = match.captured(3);
|
||||||
|
|
||||||
|
bool plus = wordIndexMatch.at(wordIndexMatch.size() - 1) == '+';
|
||||||
|
wordIndexMatch = wordIndexMatch.replace("+", "");
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
int wordIndex = wordIndexMatch.replace("=", "").toInt(&ok);
|
||||||
|
if (!ok || wordIndex == 0) {
|
||||||
|
result += "{" + match.captured(3) + "}";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (words.length() <= wordIndex) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plus) {
|
||||||
|
bool first = true;
|
||||||
|
for (int i = wordIndex; i < words.length(); i++) {
|
||||||
|
if (!first) {
|
||||||
|
result += " ";
|
||||||
|
}
|
||||||
|
result += words[i];
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result += words[wordIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result += command.func.mid(lastCaptureEnd);
|
||||||
|
|
||||||
|
if (result.size() > 0 && result.at(0) == '{') {
|
||||||
|
result = result.mid(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.replace("{{", "{");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace commands
|
||||||
|
} // namespace controllers
|
||||||
|
} // namespace chatterino
|
42
src/controllers/commands/commandcontroller.hpp
Normal file
42
src/controllers/commands/commandcontroller.hpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QMap>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "controllers/commands/command.hpp"
|
||||||
|
#include "util/signalvector2.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
class Channel;
|
||||||
|
|
||||||
|
namespace controllers {
|
||||||
|
namespace commands {
|
||||||
|
|
||||||
|
class CommandModel;
|
||||||
|
|
||||||
|
class CommandController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CommandController();
|
||||||
|
|
||||||
|
QString execCommand(const QString &text, std::shared_ptr<Channel> channel, bool dryRun);
|
||||||
|
|
||||||
|
void load();
|
||||||
|
void save();
|
||||||
|
|
||||||
|
CommandModel *createModel(QObject *parent);
|
||||||
|
|
||||||
|
util::UnsortedSignalVector<Command> items;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMap<QString, Command> commandsMap;
|
||||||
|
|
||||||
|
std::mutex mutex;
|
||||||
|
QString filePath;
|
||||||
|
|
||||||
|
QString execCustomCommand(const QStringList &words, const Command &command);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace commands
|
||||||
|
} // namespace controllers
|
||||||
|
} // namespace chatterino
|
42
src/controllers/commands/commandmodel.cpp
Normal file
42
src/controllers/commands/commandmodel.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include "commandmodel.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace controllers {
|
||||||
|
namespace commands {
|
||||||
|
|
||||||
|
// commandmodel
|
||||||
|
CommandModel::CommandModel(QObject *parent)
|
||||||
|
: util::SignalVectorModel<Command>(2, parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn a vector item into a model row
|
||||||
|
Command CommandModel::getItemFromRow(std::vector<QStandardItem *> &row)
|
||||||
|
{
|
||||||
|
return Command(row[0]->data(Qt::EditRole).toString(), row[1]->data(Qt::EditRole).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// turns a row in the model into a vector item
|
||||||
|
void CommandModel::getRowFromItem(const Command &item, std::vector<QStandardItem *> &row)
|
||||||
|
{
|
||||||
|
row[0]->setData(item.name, Qt::DisplayRole);
|
||||||
|
row[0]->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
|
||||||
|
row[1]->setData(item.func, Qt::DisplayRole);
|
||||||
|
row[1]->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the related index of the SignalVector
|
||||||
|
int CommandModel::getVectorIndexFromModelIndex(int index)
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the related index of the model
|
||||||
|
int CommandModel::getModelIndexFromVectorIndex(int index)
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace commands
|
||||||
|
} // namespace controllers
|
||||||
|
} // namespace chatterino
|
36
src/controllers/commands/commandmodel.hpp
Normal file
36
src/controllers/commands/commandmodel.hpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "controllers/commands/command.hpp"
|
||||||
|
#include "util/signalvectormodel.hpp"
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
namespace controllers {
|
||||||
|
namespace commands {
|
||||||
|
|
||||||
|
class CommandController;
|
||||||
|
|
||||||
|
class CommandModel : public util::SignalVectorModel<Command>
|
||||||
|
{
|
||||||
|
explicit CommandModel(QObject *parent);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// turn a vector item into a model row
|
||||||
|
virtual Command getItemFromRow(std::vector<QStandardItem *> &row) override;
|
||||||
|
|
||||||
|
// turns a row in the model into a vector item
|
||||||
|
virtual void getRowFromItem(const Command &item, std::vector<QStandardItem *> &row) override;
|
||||||
|
|
||||||
|
// returns the related index of the SignalVector
|
||||||
|
virtual int getVectorIndexFromModelIndex(int index) override;
|
||||||
|
|
||||||
|
// returns the related index of the model
|
||||||
|
virtual int getModelIndexFromVectorIndex(int index) override;
|
||||||
|
|
||||||
|
friend class CommandController;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace commands
|
||||||
|
} // namespace controllers
|
||||||
|
} // namespace chatterino
|
|
@ -1,9 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace chatterino {
|
|
||||||
namespace managers {
|
|
||||||
namespace commands {
|
|
||||||
// code
|
|
||||||
}
|
|
||||||
} // namespace managers
|
|
||||||
} // namespace chatterino
|
|
|
@ -1,294 +1,12 @@
|
||||||
#include "singletons/commandmanager.hpp"
|
//#include "singletons/commandmanager.hpp"
|
||||||
|
|
||||||
#include "application.hpp"
|
//#include "application.hpp"
|
||||||
#include "debug/log.hpp"
|
//#include "debug/log.hpp"
|
||||||
#include "messages/messagebuilder.hpp"
|
|
||||||
#include "providers/twitch/twitchserver.hpp"
|
|
||||||
#include "singletons/accountmanager.hpp"
|
|
||||||
#include "singletons/pathmanager.hpp"
|
|
||||||
|
|
||||||
#include <QApplication>
|
//#include "channel.hpp"
|
||||||
#include <QFile>
|
|
||||||
#include <QRegularExpression>
|
|
||||||
|
|
||||||
#include "channel.hpp"
|
// namespace chatterino {
|
||||||
#include "providers/twitch/twitchchannel.hpp"
|
// namespace singletons {
|
||||||
|
|
||||||
using namespace chatterino::providers::twitch;
|
//} // namespace singletons
|
||||||
|
//} // namespace chatterino
|
||||||
namespace chatterino {
|
|
||||||
namespace singletons {
|
|
||||||
|
|
||||||
CommandManager::CommandManager()
|
|
||||||
{
|
|
||||||
auto addFirstMatchToMap = [this](auto args) {
|
|
||||||
this->commandsMap.remove(args.item.name);
|
|
||||||
|
|
||||||
for (const Command &cmd : this->items.getVector()) {
|
|
||||||
if (cmd.name == args.item.name) {
|
|
||||||
this->commandsMap[cmd.name] = cmd;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this->items.itemInserted.connect(addFirstMatchToMap);
|
|
||||||
this->items.itemRemoved.connect(addFirstMatchToMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommandManager::load()
|
|
||||||
{
|
|
||||||
auto app = getApp();
|
|
||||||
this->filePath = app->paths->customFolderPath + "/Commands.txt";
|
|
||||||
|
|
||||||
QFile textFile(this->filePath);
|
|
||||||
if (!textFile.open(QIODevice::ReadOnly)) {
|
|
||||||
// No commands file created yet
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QByteArray> test = textFile.readAll().split('\n');
|
|
||||||
|
|
||||||
for (const auto &command : test) {
|
|
||||||
if (command.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->items.appendItem(Command(command));
|
|
||||||
}
|
|
||||||
|
|
||||||
textFile.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommandManager::save()
|
|
||||||
{
|
|
||||||
QFile textFile(this->filePath);
|
|
||||||
if (!textFile.open(QIODevice::WriteOnly)) {
|
|
||||||
debug::Log("[CommandManager::saveCommands] Unable to open {} for writing", this->filePath);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const Command &cmd : this->items.getVector()) {
|
|
||||||
textFile.write((cmd.toString() + "\n").toUtf8());
|
|
||||||
}
|
|
||||||
|
|
||||||
textFile.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
CommandModel *CommandManager::createModel(QObject *parent)
|
|
||||||
{
|
|
||||||
CommandModel *model = new CommandModel(parent);
|
|
||||||
model->init(&this->items);
|
|
||||||
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString CommandManager::execCommand(const QString &text, ChannelPtr channel, bool dryRun)
|
|
||||||
{
|
|
||||||
QStringList words = text.split(' ', QString::SkipEmptyParts);
|
|
||||||
Command command;
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(this->mutex);
|
|
||||||
|
|
||||||
if (words.length() == 0) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString commandName = words[0];
|
|
||||||
|
|
||||||
// check if default command exists
|
|
||||||
auto *twitchChannel = dynamic_cast<TwitchChannel *>(channel.get());
|
|
||||||
|
|
||||||
if (!dryRun && twitchChannel != nullptr) {
|
|
||||||
if (commandName == "/debug-args") {
|
|
||||||
QString msg = QApplication::instance()->arguments().join(' ');
|
|
||||||
|
|
||||||
channel->addMessage(messages::Message::createSystemMessage(msg));
|
|
||||||
|
|
||||||
return "";
|
|
||||||
} else if (commandName == "/uptime") {
|
|
||||||
const auto &streamStatus = twitchChannel->GetStreamStatus();
|
|
||||||
|
|
||||||
QString messageText =
|
|
||||||
streamStatus.live ? streamStatus.uptime : "Channel is not live.";
|
|
||||||
|
|
||||||
channel->addMessage(messages::Message::createSystemMessage(messageText));
|
|
||||||
|
|
||||||
return "";
|
|
||||||
} else if (commandName == "/ignore" && words.size() >= 2) {
|
|
||||||
// fourtf: ignore user
|
|
||||||
// QString messageText;
|
|
||||||
|
|
||||||
// if (IrcManager::getInstance().tryAddIgnoredUser(words.at(1),
|
|
||||||
// messageText)) {
|
|
||||||
// messageText = "Ignored user \"" + words.at(1) + "\".";
|
|
||||||
// }
|
|
||||||
|
|
||||||
// channel->addMessage(messages::Message::createSystemMessage(messageText));
|
|
||||||
return "";
|
|
||||||
} else if (commandName == "/unignore") {
|
|
||||||
// fourtf: ignore user
|
|
||||||
// QString messageText;
|
|
||||||
|
|
||||||
// if (IrcManager::getInstance().tryRemoveIgnoredUser(words.at(1),
|
|
||||||
// messageText)) {
|
|
||||||
// messageText = "Ignored user \"" + words.at(1) + "\".";
|
|
||||||
// }
|
|
||||||
|
|
||||||
// channel->addMessage(messages::Message::createSystemMessage(messageText));
|
|
||||||
return "";
|
|
||||||
} else if (commandName == "/w") {
|
|
||||||
if (words.length() <= 2) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto app = getApp();
|
|
||||||
|
|
||||||
messages::MessageBuilder b;
|
|
||||||
|
|
||||||
b.emplace<messages::TextElement>(app->accounts->Twitch.getCurrent()->getUserName(),
|
|
||||||
messages::MessageElement::Text);
|
|
||||||
b.emplace<messages::TextElement>("->", messages::MessageElement::Text);
|
|
||||||
b.emplace<messages::TextElement>(words[1], messages::MessageElement::Text);
|
|
||||||
|
|
||||||
QString rest = "";
|
|
||||||
|
|
||||||
for (int i = 2; i < words.length(); i++) {
|
|
||||||
rest += words[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
b.emplace<messages::TextElement>(rest, messages::MessageElement::Text);
|
|
||||||
|
|
||||||
app->twitch.server->whispersChannel->addMessage(b.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if custom command exists
|
|
||||||
auto it = this->commandsMap.find(commandName);
|
|
||||||
if (it == this->commandsMap.end()) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
command = it.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->execCustomCommand(words, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString CommandManager::execCustomCommand(const QStringList &words, const Command &command)
|
|
||||||
{
|
|
||||||
QString result;
|
|
||||||
|
|
||||||
static QRegularExpression parseCommand("(^|[^{])({{)*{(\\d+\\+?)}");
|
|
||||||
|
|
||||||
int lastCaptureEnd = 0;
|
|
||||||
|
|
||||||
auto globalMatch = parseCommand.globalMatch(command.func);
|
|
||||||
int matchOffset = 0;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
QRegularExpressionMatch match = parseCommand.match(command.func, matchOffset);
|
|
||||||
|
|
||||||
if (!match.hasMatch()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
result += command.func.mid(lastCaptureEnd, match.capturedStart() - lastCaptureEnd + 1);
|
|
||||||
|
|
||||||
lastCaptureEnd = match.capturedEnd();
|
|
||||||
matchOffset = lastCaptureEnd - 1;
|
|
||||||
|
|
||||||
QString wordIndexMatch = match.captured(3);
|
|
||||||
|
|
||||||
bool plus = wordIndexMatch.at(wordIndexMatch.size() - 1) == '+';
|
|
||||||
wordIndexMatch = wordIndexMatch.replace("+", "");
|
|
||||||
|
|
||||||
bool ok;
|
|
||||||
int wordIndex = wordIndexMatch.replace("=", "").toInt(&ok);
|
|
||||||
if (!ok || wordIndex == 0) {
|
|
||||||
result += "{" + match.captured(3) + "}";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (words.length() <= wordIndex) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plus) {
|
|
||||||
bool first = true;
|
|
||||||
for (int i = wordIndex; i < words.length(); i++) {
|
|
||||||
if (!first) {
|
|
||||||
result += " ";
|
|
||||||
}
|
|
||||||
result += words[i];
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result += words[wordIndex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result += command.func.mid(lastCaptureEnd);
|
|
||||||
|
|
||||||
if (result.size() > 0 && result.at(0) == '{') {
|
|
||||||
result = result.mid(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.replace("{{", "{");
|
|
||||||
}
|
|
||||||
|
|
||||||
// commandmodel
|
|
||||||
CommandModel::CommandModel(QObject *parent)
|
|
||||||
: util::SignalVectorModel<Command>(2, parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int CommandModel::prepareVectorInserted(const Command &item, int index,
|
|
||||||
std::vector<QStandardItem *> &rowToAdd)
|
|
||||||
{
|
|
||||||
rowToAdd[0]->setData(item.name, Qt::EditRole);
|
|
||||||
rowToAdd[1]->setData(item.func, Qt::EditRole);
|
|
||||||
|
|
||||||
return 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)
|
|
||||||
{
|
|
||||||
int index = _text.indexOf(' ');
|
|
||||||
|
|
||||||
if (index == -1) {
|
|
||||||
this->name = _text;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->name = _text.mid(0, index);
|
|
||||||
this->func = _text.mid(index + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Command::Command(const QString &_name, const QString &_func)
|
|
||||||
: name(_name)
|
|
||||||
, func(_func)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Command::toString() const
|
|
||||||
{
|
|
||||||
return this->name + " " + this->func;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace singletons
|
|
||||||
} // namespace chatterino
|
|
||||||
|
|
|
@ -1,70 +1,25 @@
|
||||||
#pragma once
|
//#pragma once
|
||||||
|
|
||||||
#include <QMap>
|
//#include <QMap>
|
||||||
#include <QString>
|
//#include <QString>
|
||||||
|
|
||||||
#include <memory>
|
//#include <memory>
|
||||||
#include <mutex>
|
//#include <mutex>
|
||||||
|
|
||||||
#include <util/signalvector2.hpp>
|
//#include <util/signalvector2.hpp>
|
||||||
#include <util/signalvectormodel.hpp>
|
//#include <util/signalvectormodel.hpp>
|
||||||
|
|
||||||
namespace chatterino {
|
// namespace chatterino {
|
||||||
class Channel;
|
// class Channel;
|
||||||
|
|
||||||
namespace singletons {
|
// namespace singletons {
|
||||||
|
|
||||||
class CommandManager;
|
////
|
||||||
|
//// this class managed the custom /commands
|
||||||
|
////
|
||||||
|
// class CommandManager
|
||||||
|
//{
|
||||||
|
//};
|
||||||
|
|
||||||
struct Command {
|
//} // namespace singletons
|
||||||
QString name;
|
//} // namespace chatterino
|
||||||
QString func;
|
|
||||||
|
|
||||||
Command() = default;
|
|
||||||
explicit Command(const QString &text);
|
|
||||||
Command(const QString &name, const QString &func);
|
|
||||||
|
|
||||||
QString toString() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CommandModel : public util::SignalVectorModel<Command>
|
|
||||||
{
|
|
||||||
explicit CommandModel(QObject *parent);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual int prepareVectorInserted(const Command &item, int index,
|
|
||||||
std::vector<QStandardItem *> &rowToAdd) override;
|
|
||||||
virtual int prepareVectorRemoved(const Command &item, int index) override;
|
|
||||||
virtual int prepareModelItemRemoved(int index) override;
|
|
||||||
|
|
||||||
friend class CommandManager;
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// this class managed the custom /commands
|
|
||||||
//
|
|
||||||
class CommandManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CommandManager();
|
|
||||||
|
|
||||||
QString execCommand(const QString &text, std::shared_ptr<Channel> channel, bool dryRun);
|
|
||||||
|
|
||||||
void load();
|
|
||||||
void save();
|
|
||||||
|
|
||||||
CommandModel *createModel(QObject *parent);
|
|
||||||
|
|
||||||
util::UnsortedSignalVector<Command> items;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QMap<QString, Command> commandsMap;
|
|
||||||
|
|
||||||
std::mutex mutex;
|
|
||||||
QString filePath;
|
|
||||||
|
|
||||||
QString execCustomCommand(const QStringList &words, const Command &command);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace singletons
|
|
||||||
} // namespace chatterino
|
|
||||||
|
|
|
@ -57,7 +57,8 @@ template <typename TVectorItem>
|
||||||
class BaseSignalVector : public ReadOnlySignalVector<TVectorItem>
|
class BaseSignalVector : public ReadOnlySignalVector<TVectorItem>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void appendItem(const TVectorItem &item, void *caller = 0) = 0;
|
// returns the actual index of the inserted item
|
||||||
|
virtual int insertItem(const TVectorItem &item, int proposedIndex = -1, void *caller = 0) = 0;
|
||||||
|
|
||||||
void removeItem(int index, void *caller = 0)
|
void removeItem(int index, void *caller = 0)
|
||||||
{
|
{
|
||||||
|
@ -69,26 +70,31 @@ public:
|
||||||
typename ReadOnlySignalVector<TVectorItem>::ItemArgs args{item, index, caller};
|
typename ReadOnlySignalVector<TVectorItem>::ItemArgs args{item, index, caller};
|
||||||
this->itemRemoved.invoke(args);
|
this->itemRemoved.invoke(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int appendItem(const TVectorItem &item, void *caller = 0)
|
||||||
|
{
|
||||||
|
return this->insertItem(item, -1, caller);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TVectorItem>
|
template <typename TVectorItem>
|
||||||
class UnsortedSignalVector : public BaseSignalVector<TVectorItem>
|
class UnsortedSignalVector : public BaseSignalVector<TVectorItem>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void insertItem(const TVectorItem &item, int index, void *caller = 0)
|
virtual int insertItem(const TVectorItem &item, int index = -1, void *caller = 0) override
|
||||||
{
|
{
|
||||||
util::assertInGuiThread();
|
util::assertInGuiThread();
|
||||||
assert(index >= 0 && index <= this->vector.size());
|
if (index == -1) {
|
||||||
|
index = this->vector.size();
|
||||||
|
} else {
|
||||||
|
assert(index >= 0 && index <= this->vector.size());
|
||||||
|
}
|
||||||
|
|
||||||
this->vector.insert(this->vector.begin() + index, item);
|
this->vector.insert(this->vector.begin() + index, item);
|
||||||
|
|
||||||
typename ReadOnlySignalVector<TVectorItem>::ItemArgs args{item, index, caller};
|
typename ReadOnlySignalVector<TVectorItem>::ItemArgs args{item, index, caller};
|
||||||
this->itemInserted.invoke(args);
|
this->itemInserted.invoke(args);
|
||||||
}
|
return index;
|
||||||
|
|
||||||
virtual void appendItem(const TVectorItem &item, void *caller = 0) override
|
|
||||||
{
|
|
||||||
this->insertItem(item, this->vector.size(), caller);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -96,7 +102,7 @@ template <typename TVectorItem>
|
||||||
class SortedSignalVector : public BaseSignalVector<TVectorItem>
|
class SortedSignalVector : public BaseSignalVector<TVectorItem>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void appendItem(const TVectorItem &item, void *caller = 0) override
|
virtual int insertItem(const TVectorItem &item, int index = -1, void *caller = 0) override
|
||||||
{
|
{
|
||||||
util::assertInGuiThread();
|
util::assertInGuiThread();
|
||||||
|
|
||||||
|
@ -105,6 +111,7 @@ public:
|
||||||
this->vector.begin();
|
this->vector.begin();
|
||||||
typename ReadOnlySignalVector<TVectorItem>::ItemArgs args{item, index, caller};
|
typename ReadOnlySignalVector<TVectorItem>::ItemArgs args{item, index, caller};
|
||||||
this->itemInserted.invoke(args);
|
this->itemInserted.invoke(args);
|
||||||
|
return index;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,21 @@ public:
|
||||||
this->vector = vec;
|
this->vector = vec;
|
||||||
|
|
||||||
auto insert = [this](const typename BaseSignalVector<TVectorItem>::ItemArgs &args) {
|
auto insert = [this](const typename BaseSignalVector<TVectorItem>::ItemArgs &args) {
|
||||||
|
if (args.caller == this) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get row index
|
||||||
|
int row = this->getModelIndexFromVectorIndex(args.index);
|
||||||
|
assert(row >= 0 && row <= this->rows.size());
|
||||||
|
|
||||||
|
// get row items
|
||||||
std::vector<QStandardItem *> items;
|
std::vector<QStandardItem *> items;
|
||||||
for (int i = 0; i < this->_columnCount; i++) {
|
for (int i = 0; i < this->_columnCount; i++) {
|
||||||
items.push_back(new QStandardItem());
|
items.push_back(new QStandardItem());
|
||||||
}
|
}
|
||||||
|
|
||||||
int row = this->prepareVectorInserted(args.item, args.index, items);
|
this->getRowFromItem(args.item, items);
|
||||||
assert(row >= 0 && row <= this->rows.size());
|
|
||||||
|
|
||||||
// insert row
|
// insert row
|
||||||
this->beginInsertRows(QModelIndex(), row, row);
|
this->beginInsertRows(QModelIndex(), row, row);
|
||||||
|
@ -51,7 +59,11 @@ public:
|
||||||
this->managedConnect(vec->itemInserted, insert);
|
this->managedConnect(vec->itemInserted, insert);
|
||||||
|
|
||||||
this->managedConnect(vec->itemRemoved, [this](auto args) {
|
this->managedConnect(vec->itemRemoved, [this](auto args) {
|
||||||
int row = this->prepareVectorRemoved(args.item, args.index);
|
if (args.caller == this) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int row = this->getModelIndexFromVectorIndex(args.index);
|
||||||
assert(row >= 0 && row <= this->rows.size());
|
assert(row >= 0 && row <= this->rows.size());
|
||||||
|
|
||||||
// remove row
|
// remove row
|
||||||
|
@ -93,7 +105,15 @@ public:
|
||||||
|
|
||||||
virtual 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);
|
int row = index.row(), column = index.column();
|
||||||
|
assert(row >= 0 && row < this->rows.size() && column >= 0 && column < this->_columnCount);
|
||||||
|
|
||||||
|
this->rows[row].items[column]->setData(value, role);
|
||||||
|
|
||||||
|
int vecRow = this->getVectorIndexFromModelIndex(row);
|
||||||
|
this->vector->removeItem(vecRow, this);
|
||||||
|
TVectorItem item = this->getItemFromRow(this->rows[row].items);
|
||||||
|
this->vector->insertItem(item, vecRow, this);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -123,6 +143,14 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags flags(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
int row = index.row(), column = index.column();
|
||||||
|
assert(row >= 0 && row < this->rows.size() && column >= 0 && column < this->_columnCount);
|
||||||
|
|
||||||
|
return this->rows[index.row()].items[index.column()]->flags();
|
||||||
|
}
|
||||||
|
|
||||||
virtual QStandardItem *getItem(int row, int column)
|
virtual QStandardItem *getItem(int row, int column)
|
||||||
{
|
{
|
||||||
assert(row >= 0 && row < this->rows.size() && column >= 0 && column < this->_columnCount);
|
assert(row >= 0 && row < this->rows.size() && column >= 0 && column < this->_columnCount);
|
||||||
|
@ -134,26 +162,22 @@ public:
|
||||||
{
|
{
|
||||||
assert(row >= 0 && row <= this->rows.size());
|
assert(row >= 0 && row <= this->rows.size());
|
||||||
|
|
||||||
int signalVectorRow = this->prepareModelItemRemoved(row);
|
int signalVectorRow = this->getVectorIndexFromModelIndex(row);
|
||||||
this->vector->removeItem(signalVectorRow);
|
this->vector->removeItem(signalVectorRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// gets called when an item gets inserted into the SignalVector
|
// turn a vector item into a model row
|
||||||
//
|
virtual TVectorItem getItemFromRow(std::vector<QStandardItem *> &row) = 0;
|
||||||
// returns the index of that the row should be inserted into and edits the rowToAdd elements
|
|
||||||
// based on the item
|
// turns a row in the model into a vector item
|
||||||
virtual int prepareVectorInserted(const TVectorItem &item, int index,
|
virtual void getRowFromItem(const TVectorItem &item, std::vector<QStandardItem *> &row) = 0;
|
||||||
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
|
// returns the related index of the SignalVector
|
||||||
virtual int prepareModelItemRemoved(int index) = 0;
|
virtual int getVectorIndexFromModelIndex(int index) = 0;
|
||||||
|
|
||||||
|
// returns the related index of the model
|
||||||
|
virtual int getModelIndexFromVectorIndex(int index) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Row {
|
struct Row {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "widgets/helper/splitinput.hpp"
|
#include "widgets/helper/splitinput.hpp"
|
||||||
|
|
||||||
#include "application.hpp"
|
#include "application.hpp"
|
||||||
#include "singletons/commandmanager.hpp"
|
#include "controllers/commands/commandcontroller.hpp"
|
||||||
#include "singletons/ircmanager.hpp"
|
#include "singletons/ircmanager.hpp"
|
||||||
#include "singletons/settingsmanager.hpp"
|
#include "singletons/settingsmanager.hpp"
|
||||||
#include "singletons/thememanager.hpp"
|
#include "singletons/thememanager.hpp"
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
|
|
||||||
#include "application.hpp"
|
#include "application.hpp"
|
||||||
#include "singletons/commandmanager.hpp"
|
#include "controllers/commands/commandcontroller.hpp"
|
||||||
|
#include "controllers/commands/commandmodel.hpp"
|
||||||
#include "util/layoutcreator.hpp"
|
#include "util/layoutcreator.hpp"
|
||||||
#include "util/standarditemhelper.hpp"
|
#include "util/standarditemhelper.hpp"
|
||||||
//#include "widgets/helper/comboboxitemdelegate.hpp"
|
//#include "widgets/helper/comboboxitemdelegate.hpp"
|
||||||
|
@ -49,7 +50,7 @@ CommandPage::CommandPage()
|
||||||
auto add = buttons.emplace<QPushButton>("Add");
|
auto add = buttons.emplace<QPushButton>("Add");
|
||||||
QObject::connect(*add, &QPushButton::clicked, [model, view] {
|
QObject::connect(*add, &QPushButton::clicked, [model, view] {
|
||||||
getApp()->commands->items.appendItem(
|
getApp()->commands->items.appendItem(
|
||||||
singletons::Command{"/command", "I made a new command HeyGuys"});
|
controllers::commands::Command{"/command", "I made a new command HeyGuys"});
|
||||||
view->scrollToBottom();
|
view->scrollToBottom();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue