Squish: Allow querying and displaying server settings

Change-Id: I6158aa11fa314ca7c42f175ccd03330059eef910
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Christian Stenger
2022-07-06 12:27:00 +02:00
parent 79f0fe4819
commit 191626e2ea
3 changed files with 308 additions and 2 deletions

View File

@@ -26,11 +26,22 @@
#include "squishsettings.h"
#include "squishconstants.h"
#include "squishtools.h"
#include <utils/basetreeview.h>
#include <utils/icon.h>
#include <utils/layoutbuilder.h>
#include <utils/progressindicator.h>
#include <utils/qtcassert.h>
#include <utils/treemodel.h>
#include <QDialogButtonBox>
#include <QFrame>
#include <QHeaderView>
#include <QPushButton>
#include <QSettings>
#include <QVBoxLayout>
#include <QXmlStreamReader>
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<QString, QString> mappedAuts; // name, path
QMap<QString, QString> 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<SquishServerItem> *model = new TreeModel<SquishServerItem>;
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