9 #include <QRegularExpression>
11 #define MKSTR(x) static const QString s_ ## x(#x)
39 QList<QPair<QString, QString>>
envir;
42 static inline bool toBool(
const QString &
string)
44 return string.toLower() == s_true;
56 QFileInfoList fileInfoList = configDir.entryInfoList(QDir::Files, QDir::Name);
57 QRegularExpression paramRegex(
"^([A-Z]+)=(.*)$", QRegularExpression::MultilineOption);
59 for (
const auto& fileInfo : fileInfoList) {
60 QString filePath = fileInfo.absoluteFilePath();
61 QSettings setting(filePath, QSettings::IniFormat);
62 setting.setIniCodec(
"UTF-8");
63 QString caption = setting.value(
"caption").toString();
64 QString exec = setting.value(
"exec").toString();
65 QString type = setting.value(
"type").toString();
66 QString tooltip = setting.value(
"tooltip").toString();
67 QIcon icon(setting.value(
"icon").toString());
68 bool checkable = setting.value(
"checkable").toBool();
69 if (exec.isEmpty() || (caption.isEmpty() && icon.isNull())) {
70 qDebug() <<
"Ignoring" << filePath <<
"caption+icon or exec empty";
73 if (!QFileInfo(exec).isExecutable() || !QFileInfo(exec).isFile()) {
74 qDebug() <<
"Ignoring" << filePath <<
"since target" << exec <<
"doesn't exist or isn't an executable file";
79 auto *addon =
new Addon();
81 auto toggleFun = [=](
bool value) {
82 addon->envir.append(qMakePair(s_EVENT, s_clicked));
83 addon->envir.append(qMakePair(s_CHECKED, (value ? s_true : s_false)));
87 addon->menu =
new QAction(caption);
89 addon->menu->setIcon(icon);
91 addon->menu->setCheckable(checkable);
92 addon->menu->setToolTip(tooltip);
93 menuEntries.append(addon->menu);
94 QObject::connect(addon->menu, &QAction::triggered, toggleFun);
95 }
else if (type ==
"button") {
96 addon->button =
new QPushButton(caption);
98 addon->button->setIcon(icon);
101 addon->button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);
102 addon->button->setCheckable(checkable);
103 addon->button->setToolTip(tooltip);
104 buttons.append(addon->button);
105 QObject::connect(addon->button, &QPushButton::clicked, toggleFun);
107 qDebug() <<
"Ignoring unknown addon type" << type;
113 addon->wantConnectInfo = setting.value(
"connection-events").toBool();
114 addon->wantInit = setting.value(
"init").toBool();
115 addon->runAsync = setting.value(
"async").toBool();
117 addon->process.setProgram(exec);
119 QObject::connect(&addon->process, &QProcess::readyReadStandardOutput, [=]() {
120 auto lines = addon->process.readAllStandardOutput();
121 auto matches = paramRegex.globalMatch(lines);
122 handleAddonOutput(addon, matches);
125 QObject::connect(&addon->process, &QProcess::readyReadStandardError, [=]() {
126 qDebug() << exec <<
"stderr:" << QString::fromLocal8Bit(addon->process.readAllStandardError());
135 if (addon->wantInit) {
136 addon->envir.append(qMakePair(s_EVENT, s_init));
147 if (!addon->wantConnectInfo)
149 addon->envir.append(qMakePair(s_EVENT, s_connected));
150 addon->envir.append(qMakePair(s_ADDRESS, address));
151 addon->envir.append(qMakePair(s_ISLOCAL, isLocal ? s_true : s_false));
159 if (!addon->wantConnectInfo)
161 addon->envir.append(qMakePair(s_EVENT, s_disconnected));
169 auto env = QProcessEnvironment::systemEnvironment();
170 for (
const auto& e : addon->
envir) {
171 env.insert(e.first, e.second);
173 addon->
envir.clear();
176 if (addon->
process.state() != QProcess::NotRunning) {
177 addon->
process.waitForFinished(500);
179 if (addon->
process.state() != QProcess::NotRunning) {
183 addon->
process.setProcessEnvironment(env);
186 QProcess::startDetached(addon->
process.program(), QStringList());
189 addon->
process.closeWriteChannel();
195 if (addon->
button !=
nullptr) {
197 bool wasVisible = p !=
nullptr && addon->
button->isVisibleTo(p);
198 addon->
button->setVisible(visible);
199 if (p !=
nullptr && wasVisible != visible) {
201 int size = (addon->
button->width() + 2) * (visible ? 1 : -1);
202 p->setFixedWidth(p->width() + size);
205 addon->
menu->setVisible(visible);
211 while (matches.hasNext()) {
212 auto m = matches.next();
213 auto key = m.captured(1);
214 auto val = m.captured(2);
215 bool newValue =
toBool(val);
216 if (key == s_VISIBLE) {
218 }
else if (key == s_CHECKED) {
219 if (addon->
button !=
nullptr) {
220 addon->
button->setChecked(newValue);
222 addon->
menu->setChecked(newValue);
224 }
else if (key == s_ENABLED) {
225 if (addon->
button !=
nullptr) {
226 addon->
button->setEnabled(newValue);
228 addon->
menu->setEnabled(newValue);
static void initControls()
QList< QPair< QString, QString > > envir
static const QSize ICON_SIZE(20, 20)
static void connectEvent(bool isLocal, const QString &address)
static void disconnectEvent()
static void handleAddonOutput(Addon *addon, QRegularExpressionMatchIterator &matches)
static bool toBool(const QString &string)
static void loadFromPath(const QString &path, QList< QPushButton * > &buttons, QList< QAction * > &menuEntries)
static void setAddonVisible(Addon *addon, bool visible)
static void executeAddon(Addon *addon)
static QList< Addon * > _addons