diff options
Diffstat (limited to 'src/client')
-rw-r--r-- | src/client/addons/addons.cpp | 235 | ||||
-rw-r--r-- | src/client/addons/addons.h | 25 | ||||
-rw-r--r-- | src/client/toolbar/toolbar.cpp | 110 | ||||
-rw-r--r-- | src/client/toolbar/toolbar.h | 11 |
4 files changed, 291 insertions, 90 deletions
diff --git a/src/client/addons/addons.cpp b/src/client/addons/addons.cpp new file mode 100644 index 0000000..9f4a99f --- /dev/null +++ b/src/client/addons/addons.cpp @@ -0,0 +1,235 @@ +#include "addons.h" + +#include <QDir> +#include <QSettings> +#include <QPushButton> +#include <QAction> +#include <QProcess> +#include <QtDebug> +#include <QRegularExpression> + +#define MKSTR(x) static const QString s_ ## x(#x) + +MKSTR(EVENT); +MKSTR(ADDRESS); +MKSTR(ISLOCAL); +MKSTR(CHECKED); +MKSTR(ENABLED); +MKSTR(VISIBLE); +MKSTR(connected); +MKSTR(disconnected); +MKSTR(init); +MKSTR(clicked); +MKSTR(true); +MKSTR(false); + +static const QSize ICON_SIZE(20, 20); + +QList<Addon*> AddonManager::_addons; + +class Addon +{ +public: + Addon() : button(nullptr), menu(nullptr), wantConnectInfo(false) {} + QPushButton *button; + QAction *menu; + QProcess process; + bool wantConnectInfo; + bool wantInit; + bool runAsync; + QList<QPair<QString, QString>> envir; +}; + +static inline bool toBool(const QString &string) +{ + return string.toLower() == s_true; +} + +static void executeAddon(Addon *addon); + +static void setAddonVisible(Addon *addon, bool visible); + +static void handleAddonOutput(Addon *addon, QRegularExpressionMatchIterator &matches); + +void AddonManager::loadFromPath(const QString &path, QList<QPushButton*> &buttons, QList<QAction*> &menuEntries) +{ + QDir configDir(path); + QFileInfoList fileInfoList = configDir.entryInfoList(QDir::Files, QDir::Name); + QRegularExpression paramRegex("^([A-Z]+)=(.*)$", QRegularExpression::MultilineOption); + + for (QFileInfo fileInfo : fileInfoList) { + QString filePath = fileInfo.absoluteFilePath(); + QSettings setting(filePath, QSettings::IniFormat); + QString caption = setting.value("caption").toString(); // TODO: i18n + QString exec = setting.value("exec").toString(); + QString type = setting.value("type").toString(); + QString tooltip = setting.value("tooltip").toString(); + QIcon icon(setting.value("icon").toString()); + bool checkable = setting.value("checkable").toBool(); + if (exec.isEmpty() || (caption.isEmpty() && icon.isNull())) { + qDebug() << "Ignoring" << filePath << "caption+icon or exec empty"; + continue; + } + if (!QFileInfo(exec).isExecutable() || !QFileInfo(exec).isFile()) { + qDebug() << "Ignoring" << filePath << "since target" << exec << "doesn't exist or isn't an executable file"; + continue; + } + + // Alloc addon + Addon *addon = new Addon(); + // Toggle/click callback + auto toggleFun = [=](bool value) { + addon->envir.append(qMakePair(s_EVENT, s_clicked)); + addon->envir.append(qMakePair(s_CHECKED, (value ? s_true : s_false))); + executeAddon(addon); + }; + if (type == "menu") { + addon->menu = new QAction(caption); + if (!icon.isNull()) { + addon->menu->setIcon(icon); + } + addon->menu->setCheckable(checkable); + addon->menu->setToolTip(tooltip); + menuEntries.append(addon->menu); + addon->menu->connect(addon->menu, &QAction::triggered, toggleFun); + } else if (type == "button") { + addon->button = new QPushButton(caption); + if (!icon.isNull()) { + addon->button->setIcon(icon); + addon->button->setIconSize(ICON_SIZE); + } + addon->button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding); + addon->button->setCheckable(checkable); + addon->button->setToolTip(tooltip); + buttons.append(addon->button); + addon->button->connect(addon->button, &QPushButton::clicked, toggleFun); + } else { + qDebug() << "Ignoring unknown addon type" << type; + delete addon; + continue; + } + _addons.append(addon); + + addon->wantConnectInfo = setting.value("connection-events").toBool(); + addon->wantInit = setting.value("init").toBool(); + addon->runAsync = setting.value("async").toBool(); + // Setup process + addon->process.setProgram(exec); + // Stdin for status updates + addon->process.connect(&addon->process, &QProcess::readyReadStandardOutput, [=]() { + auto lines = addon->process.readAllStandardOutput(); + auto matches = paramRegex.globalMatch(lines); + handleAddonOutput(addon, matches); + }); + // Stderr just for debugging + addon->process.connect(&addon->process, &QProcess::readyReadStandardError, [=]() { + qDebug() << exec << "stderr:" << QString::fromLocal8Bit(addon->process.readAllStandardError()); + }); + } +} + +void AddonManager::initControls() +{ + // Call all init functions + for (auto addon : _addons) { + if (addon->wantInit) { + addon->envir.append(qMakePair(s_EVENT, s_init)); + executeAddon(addon); + } else { + setAddonVisible(addon, true); + } + } +} + +void AddonManager::connectEvent(bool isLocal, const QString &address) +{ + for (auto addon : _addons) { + if (!addon->wantConnectInfo) + continue; + addon->envir.append(qMakePair(s_EVENT, s_connected)); + addon->envir.append(qMakePair(s_ADDRESS, address)); + addon->envir.append(qMakePair(s_ISLOCAL, isLocal ? s_true : s_false)); + executeAddon(addon); + } +} + +void AddonManager::disconnectEvent() +{ + for (auto addon : _addons) { + if (!addon->wantConnectInfo) + continue; + addon->envir.append(qMakePair(s_EVENT, s_disconnected)); + executeAddon(addon); + } +} + +static void executeAddon(Addon *addon) +{ + // Set up environment + auto env = QProcessEnvironment::systemEnvironment(); + for (auto e : addon->envir) { + env.insert(e.first, e.second); + } + addon->envir.clear(); + if (!addon->runAsync) { + // Kill remains + if (addon->process.state() != QProcess::NotRunning) { + addon->process.waitForFinished(500); + } + if (addon->process.state() != QProcess::NotRunning) { + addon->process.close(); + } + } + addon->process.setProcessEnvironment(env); + // Run + if (addon->runAsync) { + addon->process.startDetached(addon->process.program(), QStringList()); + } else { + addon->process.start(); + addon->process.closeWriteChannel(); + } +} + +static void setAddonVisible(Addon *addon, bool newValue) +{ + if (addon->button != nullptr) { + QWidget *p = addon->button->parentWidget(); + bool wasVisible = p != nullptr && addon->button->isVisibleTo(p); + qDebug() << "Visibility" << wasVisible << "->" << newValue; + addon->button->setVisible(newValue); + if (p != nullptr && wasVisible != newValue) { + // Visibility changed -- adjust size of toolbar + int size = (addon->button->width() + 2) * (newValue ? 1 : -1); + qDebug() << "Adding" << size; + p->setFixedWidth(p->width() + size); + } + } else { + addon->menu->setVisible(newValue); + } +} + +static void handleAddonOutput(Addon* addon, QRegularExpressionMatchIterator &matches) +{ + while (matches.hasNext()) { + auto m = matches.next(); + qDebug() << "Match:" << m.captured(0); + auto key = m.captured(1); + auto val = m.captured(2); + bool newValue = toBool(val); + if (key == s_VISIBLE) { + setAddonVisible(addon, newValue); + } else if (key == s_CHECKED) { + if (addon->button != nullptr) { + addon->button->setChecked(newValue); + } else { + addon->menu->setChecked(newValue); + } + } else if (key == s_ENABLED) { + if (addon->button != nullptr) { + addon->button->setEnabled(newValue); + } else { + addon->menu->setEnabled(newValue); + } + } + } +} diff --git a/src/client/addons/addons.h b/src/client/addons/addons.h new file mode 100644 index 0000000..185c399 --- /dev/null +++ b/src/client/addons/addons.h @@ -0,0 +1,25 @@ +#ifndef _ADDONS_H_ +#define _ADDONS_H_ + +#include <QString> +#include <QList> + +class Toolbar; +class QPushButton; +class QAction; + +class Addon; + +class AddonManager +{ +public: + static void loadFromPath(const QString &path, QList<QPushButton*> &buttons, QList<QAction*> &menuEntries); + static void initControls(); + static void connectEvent(bool isLocal, const QString &address); + static void disconnectEvent(); + +private: + static QList<Addon*> _addons; +}; + +#endif diff --git a/src/client/toolbar/toolbar.cpp b/src/client/toolbar/toolbar.cpp index 1640c01..bec8586 100644 --- a/src/client/toolbar/toolbar.cpp +++ b/src/client/toolbar/toolbar.cpp @@ -1,12 +1,3 @@ -/* - * toolbar.cpp - * - * Created on: 21.01.2013 - * Author: sr - */ -#include <QtAlgorithms> -#include <QNetworkInterface> -#include <QProcess> #include "../../shared/settings.h" #include "../net/serverconnection.h" #include "../vnc/vncwindow.h" @@ -14,10 +5,15 @@ #include "../util/util.h" #include "../informationdialog/informationdialog.h" #include "../clientapp/clientapp.h" +#include "../addons/addons.h" #include "toolbar.h" #include "ui_toolbar.h" +#include <QtAlgorithms> +#include <QNetworkInterface> +#include <QProcess> + /** * @brief * @@ -107,23 +103,9 @@ void Toolbar::init() connect(clientApp->connectWindow(), SIGNAL(disconnect()), this, SLOT(onDoDisconnect())); connect(clientApp->connectWindow(), SIGNAL(connected(ServerConnection*)), this, SLOT(onConnected(ServerConnection*))); connect(_ui->btnAttention, SIGNAL(toggled(bool)), this, SLOT(onBtnAttention())); - connect(_ui->btnManager, &QPushButton::toggled, [=](bool pressed) { - this->toggleDesktop(pressed ? Desktop::Manager : Desktop::Primary); - }); /* Setup menu */ - initMenu(); - - updateButtonVisibility(); - - /* setup lock desktop button*/ - bool showLock = clientApp->getSettings()->value("showLockDesktopButton").toBool(); - if (showLock) { - connect(_ui->btnLockDesktop, SIGNAL(clicked()), this, SLOT(onBtnLockDesktop())); - } else { - setFixedWidth(width() - _ui->btnLockDesktop->width()); - _ui->btnLockDesktop->setVisible(false); - } + initButtonsAndMenus(); /* hide attention button while disconnected */ _ui->btnAttention->setVisible(false); @@ -160,8 +142,18 @@ void Toolbar::init() * This function should be called once from the main init() function which in * turn should only be called by the constructor. **/ -void Toolbar::initMenu() +void Toolbar::initButtonsAndMenus() { + QList<QPushButton*> buttons; + QList<QAction*> menus; + auto settings = clientApp->getSettings(); + AddonManager::loadFromPath(settings->value("addonConfigDir", "/opt/openslx/pvs2/addons").toString(), buttons, menus); + // Buttons + for (auto i : buttons) { + _ui->buttonContainer->addWidget(i); + i->setVisible(false); + } + // Menu _menu = new QMenu(this); _acnConnect = new QAction(tr("&Connect..."), this); _acnDisconnect = new QAction(tr("&Disconnect"), this); @@ -173,6 +165,10 @@ void Toolbar::initMenu() _menu->addAction(_acnConnect); _menu->addAction(_acnDisconnect); _menu->addSeparator(); + for (auto i : menus) { + _menu->addAction(i); + i->setVisible(false); + } _menu->addAction(_acnInformation); _menu->addAction(_acnAbout); _menu->addSeparator(); @@ -181,7 +177,7 @@ void Toolbar::initMenu() /* only add a "quit"-button when the configuration allows it. */ - bool allow = clientApp->getSettings()->value("allowClientQuit").toBool(); + bool allow = settings->value("allowClientQuit").toBool(); _acnQuit->setVisible(allow); // Connect the signals @@ -191,26 +187,11 @@ void Toolbar::initMenu() connect(_acnInformation, SIGNAL(triggered()), this, SLOT(showInformationDialog())); connect(_acnAbout, SIGNAL(triggered()), this, SLOT(showAboutDialog())); connect(_acnQuit, SIGNAL(triggered()), this, SLOT(exit())); -} -void Toolbar::updateButtonVisibility() -{ - // "Toggle to manager view" (switch between desktop 1 and 2) - bool showManagerToggle = clientApp->isConfiguredAsManager() || clientApp->isConnectedToLocalManager(); - if (showManagerToggle == _ui->btnManager->isHidden()) { - // Visibility should change - if (showManagerToggle) { - _ui->btnManager->blockSignals(false); - setFixedWidth(width() + _ui->btnManager->width()); - } else { - // Hide "toggle manager" -- assume manager was closed, switch to first desktop where the VM should be running - _ui->btnManager->blockSignals(true); - _ui->btnManager->setChecked(false); - setFixedWidth(width() - _ui->btnManager->width()); - toggleDesktop(Desktop::Primary); - } - _ui->btnManager->setVisible(showManagerToggle); - } + // Delay until bar is visible + QTimer::singleShot(10, [=]() { + AddonManager::initControls(); + }); } /** @@ -382,7 +363,7 @@ void Toolbar::onDisconnected(ServerConnection* connection) _ui->btnAttention->setVisible(false); onBtnAttention(); delayedHideBar(); - QTimer::singleShot(1, this, SLOT(updateButtonVisibility())); + AddonManager::disconnectEvent(); } /** @@ -401,7 +382,7 @@ void Toolbar::onConnected(ServerConnection* connection) _ui->lblStatus->setText(tr("Online")); /* connected, show button */ _ui->btnAttention->setVisible(true); - QTimer::singleShot(1, this, SLOT(updateButtonVisibility())); + AddonManager::connectEvent(connection->isLocalConnection(), connection->getPeerAdress()); // connect(connection, SIGNAL(disconnected(ServerConnection*)), this, SLOT(onDisconnected(ServerConnection*))); connect(connection, SIGNAL(openVnc(const QString&, int, const QString&, bool, bool, const QString&, const int, const QByteArray&)), @@ -501,6 +482,8 @@ void Toolbar::showInformationDialog() InformationDialog* d = new InformationDialog(); d->exec(); d->deleteLater(); + auto b = new QPushButton("sdfadsfgadfgadfgadg"); + this->layout()->addWidget(b); } void Toolbar::onBtnAttention() @@ -515,39 +498,6 @@ void Toolbar::onBtnAttention() } } -/** call script to switch to workspace of the manager */ -void Toolbar::toggleDesktop(Desktop d) -{ - QProcess switchP; - if (d == Desktop::Manager) { - switchP.start("/bin/sh", QStringList() << "/opt/openslx/pvs2/switchToManager.sh"); - } else if (d == Desktop::Primary) { - switchP.start("/bin/sh", QStringList() << "/opt/openslx/pvs2/switchBack.sh"); - } else { - qDebug() << "Invalid toggleDesktop call"; - return; - } - switchP.waitForFinished(); -} - -void Toolbar::onBtnLockDesktop() -{ - if (this->lockDesktopP.state() == QProcess::NotRunning) { - _ui->btnLockDesktop->setEnabled(false); - this->lockDesktopP.start("/bin/sh", QStringList() << "/opt/openslx/pvs2/lockDesktop.sh"); - - QTimer::singleShot(2 * 1000, this, SLOT(enableLockBtn())); - - } else { - qDebug() << "trying to use lockDesktop-process while it is still running"; - } -} - -void Toolbar::enableLockBtn() -{ - _ui->btnLockDesktop->setEnabled(true); -} - void Toolbar::setToolbarPosition(const QRect &availableGeometry) { const QRect primaryScreen = QGuiApplication::primaryScreen()->geometry(); diff --git a/src/client/toolbar/toolbar.h b/src/client/toolbar/toolbar.h index 67e9347..48fbf03 100644 --- a/src/client/toolbar/toolbar.h +++ b/src/client/toolbar/toolbar.h @@ -27,11 +27,6 @@ namespace Ui class Toolbar; } -enum class Desktop { - Primary, - Manager, -}; - class Toolbar : public QWidget { Q_OBJECT @@ -69,8 +64,7 @@ private: bool isManagerPc(); QString identifyMgrIP(); void init(); - void initMenu(); - void toggleDesktop(Desktop d); + void initButtonsAndMenus(); QProcess lockDesktopP; @@ -80,7 +74,6 @@ private slots: void onConnected(ServerConnection* connection); void onServerAttentionChanged(const bool on); void onDoDisconnect(); - void onBtnLockDesktop(); void onBtnAttention(); void exit(); void cameraBlink(); @@ -90,8 +83,6 @@ private slots: void delayedHideBar(); void showAboutDialog(); void showInformationDialog(); - void enableLockBtn(); - void updateButtonVisibility(); void setToolbarPosition(const QRect &geometry); }; |