diff --git a/src/plugins/squish/squishplugin.cpp b/src/plugins/squish/squishplugin.cpp index 5bc03a3248e..82330d9c365 100644 --- a/src/plugins/squish/squishplugin.cpp +++ b/src/plugins/squish/squishplugin.cpp @@ -32,12 +32,15 @@ #include "squishtesttreemodel.h" #include "squishtools.h" +#include +#include #include #include #include +#include #include using namespace Squish::Internal; @@ -68,7 +71,23 @@ SquishSettings *SquishPlugin::squishSettings() return &m_squishSettings; } -void SquishPlugin::initializeMenuEntries() {} +void SquishPlugin::initializeMenuEntries() +{ + ActionContainer *menu = ActionManager::createMenu("Squish.Menu"); + menu->menu()->setTitle(tr("&Squish")); + menu->setOnAllDisabledBehavior(ActionContainer::Show); + + QAction *action = new QAction(tr("&Server Settings..."), this); + Command *command = ActionManager::registerAction(action, "Squish.ServerSettings"); + menu->addAction(command); + connect(action, &QAction::triggered, this, [this] { + SquishServerSettingsDialog dialog; + dialog.exec(); + }); + + ActionContainer *toolsMenu = ActionManager::actionContainer(Core::Constants::M_TOOLS); + toolsMenu->addMenu(menu); +} bool SquishPlugin::initialize(const QStringList &arguments, QString *errorString) { diff --git a/src/plugins/squish/squishsettings.cpp b/src/plugins/squish/squishsettings.cpp index 0d6f1e0d70d..10f47898dca 100644 --- a/src/plugins/squish/squishsettings.cpp +++ b/src/plugins/squish/squishsettings.cpp @@ -26,11 +26,22 @@ #include "squishsettings.h" #include "squishconstants.h" +#include "squishtools.h" +#include #include #include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include using namespace Utils; @@ -74,7 +85,6 @@ SquishSettings::SquishSettings() serverPort.setDefaultValue(9999); serverPort.setEnabled(false); - registerAspect(&verbose); verbose.setSettingsKey("Verbose"); verbose.setLabel(tr("Verbose log")); @@ -114,5 +124,271 @@ SquishSettingsPage::SquishSettingsPage(SquishSettings *settings) }); } +class SquishServerSettings : public AspectContainer +{ + Q_DECLARE_TR_FUNCTIONS(Squish::Internal::SquishSettings) +public: + SquishServerSettings(); + + void setFromXmlOutput(const QByteArray &output); + + QMap mappedAuts; // name, path + QMap attachableAuts; // name, host:port + QStringList autPaths; // absolute path + IntegerAspect autTimeout; + IntegerAspect responseTimeout; + IntegerAspect postMortemWaitTime; + BoolAspect animatedCursor; +}; + +SquishServerSettings::SquishServerSettings() +{ + setAutoApply(false); + + registerAspect(&autTimeout); + autTimeout.setLabel(tr("Maximum startup time:")); + autTimeout.setToolTip(tr("Specifies how many seconds Squish should wait for a reply from the " + "AUT directly after starting it.")); + autTimeout.setRange(1, 65535); + autTimeout.setSuffix("s"); + autTimeout.setDefaultValue(20); + + registerAspect(&responseTimeout); + responseTimeout.setLabel(tr("Maximum response time:")); + responseTimeout.setToolTip(tr("Specifies how many seconds Squish should wait for a reply from " + "the hooked up AUT before raising a timeout error.")); + responseTimeout.setRange(1, 65535); + responseTimeout.setDefaultValue(300); + responseTimeout.setSuffix("s"); + + registerAspect(&postMortemWaitTime); + postMortemWaitTime.setLabel(tr("Maximum post-mortem wait time:")); + postMortemWaitTime.setToolTip(tr("Specifies how many seconds Squish should wait after the the " + "first AUT process has exited.")); + postMortemWaitTime.setRange(1, 65535); + postMortemWaitTime.setDefaultValue(1500); + postMortemWaitTime.setSuffix("ms"); + + registerAspect(&animatedCursor); + animatedCursor.setLabel(tr("Animate mouse cursor:")); + animatedCursor.setDefaultValue(true); +} + +enum InfoMode {None, Applications, AutPaths, AttachableAuts, AutTimeout, AutPMTimeout, + AutResponseTimeout, AnimatedCursor}; + +InfoMode infoModeFromType(const QString &type) +{ + if (type == "applications") + return Applications; + if (type == "autPaths") + return AutPaths; + if (type == "attachableApplications") + return AttachableAuts; + if (type == "AUTTimeout") + return AutTimeout; + if (type == "AUTPMTimeout") + return AutPMTimeout; + if (type == "responseTimeout") + return AutResponseTimeout; + if (type == "cursorAnimation") + return AnimatedCursor; + return None; +} + +void SquishServerSettings::setFromXmlOutput(const QByteArray &output) +{ + SquishServerSettings newSettings; + InfoMode infoMode = None; + QXmlStreamReader reader(output); + while (!reader.atEnd()) { + QXmlStreamReader::TokenType type = reader.readNext(); + if (type == QXmlStreamReader::Invalid) { + // MessageBox? + return; + } else if (type == QXmlStreamReader::StartElement) { + const QString tagName = reader.name().toString(); + if (tagName == "info") { + const QString typeString = reader.attributes().value("type").toString(); + QTC_ASSERT(!typeString.isEmpty(), infoMode = None; continue); + infoMode = infoModeFromType(typeString); + } else if (tagName == "item") { + const QXmlStreamAttributes attributes = reader.attributes(); + switch (infoMode) { + case Applications: + if (attributes.value("mappedOrViaAUTPaths").toString() == "path") + continue; // ignore applications provided by autPaths + newSettings.mappedAuts.insert(attributes.value("executableName").toString(), + attributes.value("executablePath").toString()); + break; + case AutPaths: + newSettings.autPaths.append(attributes.value("value").toString()); + break; + case AttachableAuts: + newSettings.attachableAuts.insert(attributes.value("name").toString(), + attributes.value("hostAndPort").toString()); + break; + case AutTimeout: + newSettings.autTimeout.setValue(attributes.value("value").toInt()); + break; + case AutPMTimeout: + newSettings.postMortemWaitTime.setValue(attributes.value("value").toInt()); + break; + case AutResponseTimeout: + newSettings.responseTimeout.setValue(attributes.value("value").toInt()); + break; + case AnimatedCursor: + newSettings.animatedCursor.setValue(attributes.value("value").toString() == "on"); + break; + default: + break; + } + } + } + } + // if we end here, we update the settings with the read settings + mappedAuts = newSettings.mappedAuts; + autPaths = newSettings.autPaths; + attachableAuts = newSettings.attachableAuts; + autTimeout.setValue(newSettings.autTimeout.value()); + postMortemWaitTime.setValue(newSettings.postMortemWaitTime.value()); + responseTimeout.setValue(newSettings.responseTimeout.value()); + animatedCursor.setValue(newSettings.animatedCursor.value()); +} + +class SquishServerItem : public TreeItem +{ +public: + explicit SquishServerItem(const QString &col1 = {}, const QString &col2 = {}); + QVariant data(int column, int role) const override; +private: + QString m_first; + QString m_second; +}; + +SquishServerItem::SquishServerItem(const QString &col1, const QString &col2) + : m_first(col1) + , m_second(col2) +{ +} + +QVariant SquishServerItem::data(int column, int role) const +{ + if (role == Qt::DisplayRole) { + switch (column) { + case 0: return m_first; + case 1: return m_second; + default: return QVariant(); + } + } + return QVariant(); +} + +class SquishServerSettingsWidget : public QWidget +{ + Q_DECLARE_TR_FUNCTIONS(Squish::Internal::SquishSettings) +public: + explicit SquishServerSettingsWidget(QWidget *parent = nullptr); +private: + void repopulateApplicationView(); + + SquishServerSettings m_serverSettings; + BaseTreeView m_applicationsView; +}; + +SquishServerSettingsWidget::SquishServerSettingsWidget(QWidget *parent) + : QWidget(parent) +{ + m_applicationsView.setHeaderHidden(true); + m_applicationsView.setAttribute(Qt::WA_MacShowFocusRect, false); + m_applicationsView.setFrameStyle(QFrame::NoFrame); + m_applicationsView.setRootIsDecorated(true); + m_applicationsView.setSelectionMode(QAbstractItemView::SingleSelection); + m_applicationsView.header()->setStretchLastSection(false); + m_applicationsView.header()->setSectionResizeMode(QHeaderView::ResizeToContents); + m_applicationsView.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + m_applicationsView.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + + using namespace Layouting; + Form grid { + &m_applicationsView, Break(), + &m_serverSettings.autTimeout, + &m_serverSettings.responseTimeout, + &m_serverSettings.postMortemWaitTime, + &m_serverSettings.animatedCursor, + }; + // TODO buttons for add, edit, remove + Column { Row { grid }, Stretch() }.attachTo(this); + + repopulateApplicationView(); // initial + + auto progress = new ProgressIndicator(ProgressIndicatorSize::Large, this); + progress->attachToWidget(this); + setEnabled(false); + progress->show(); + + // query settings + SquishTools *squishTools = SquishTools::instance(); + connect(squishTools, &SquishTools::queryFinished, this, + [this, progress] (const QByteArray &out) { + m_serverSettings.setFromXmlOutput(out); + repopulateApplicationView(); + progress->hide(); + setEnabled(true); + }); + squishTools->queryServerSettings(); +} + +void SquishServerSettingsWidget::repopulateApplicationView() +{ + TreeModel *model = new TreeModel; + model->setHeader({QString(), QString()}); // enforce 2 columns + + SquishServerItem *mapped = new SquishServerItem(tr("Mapped AUTs")); + model->rootItem()->appendChild(mapped); + for (auto it = m_serverSettings.mappedAuts.begin(), + end = m_serverSettings.mappedAuts.end(); it != end; ++it) { + mapped->appendChild(new SquishServerItem(it.key(), it.value())); + } + + SquishServerItem *autPaths = new SquishServerItem(tr("AUT Paths")); + model->rootItem()->appendChild(autPaths); + for (const QString &path : qAsConst(m_serverSettings.autPaths)) + autPaths->appendChild(new SquishServerItem(path, "")); + + SquishServerItem *attachable = new SquishServerItem(tr("Attachable AUTs")); + model->rootItem()->appendChild(attachable); + for (auto it = m_serverSettings.attachableAuts.begin(), + end = m_serverSettings.attachableAuts.end(); it != end; ++it) { + attachable->appendChild(new SquishServerItem(it.key(), it.value())); + } + + auto oldModel = m_applicationsView.model(); + m_applicationsView.setModel(model); + delete oldModel; +} + +SquishServerSettingsDialog::SquishServerSettingsDialog(QWidget *parent) + : QDialog(parent) +{ + setWindowTitle(tr("Squish Server Settings")); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(new SquishServerSettingsWidget); + auto buttonBox = new QDialogButtonBox(/*QDialogButtonBox::Apply|*/QDialogButtonBox::Cancel, this); + mainLayout->addWidget(buttonBox); + setLayout(mainLayout); +// connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, +// this, &SquishServerSettingsDialog::onApply); + connect(buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, + this, &QDialog::reject); +} + +void SquishServerSettingsDialog::onApply() +{ + // TODO write settings to server + accept(); +} + } // namespace Internal } // namespace Squish diff --git a/src/plugins/squish/squishsettings.h b/src/plugins/squish/squishsettings.h index 9cdb9f7634d..99861eb6c7e 100644 --- a/src/plugins/squish/squishsettings.h +++ b/src/plugins/squish/squishsettings.h @@ -29,6 +29,8 @@ #include +#include + QT_BEGIN_NAMESPACE class QSettings; QT_END_NAMESPACE @@ -57,5 +59,14 @@ public: SquishSettingsPage(SquishSettings *settings); }; +class SquishServerSettingsDialog : public QDialog +{ + Q_DECLARE_TR_FUNCTIONS(Squish::Internal::SquishSettings) +public: + explicit SquishServerSettingsDialog(QWidget *parent = nullptr); +private: + void onApply(); +}; + } // namespace Internal } // namespace Squish