Squish: Allow modification of server settings

Implements ui interaction for mapped AUTs, AUT paths
and attachable AUTs.
Modified data is not yet written back to the server config.

Change-Id: Id6661efd990f1744b61b763c5654d1bee7145b5e
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Stenger
2022-07-08 15:04:15 +02:00
parent b6d7d9803e
commit adb10e907e

View File

@@ -30,6 +30,7 @@
#include "squishtr.h"
#include <utils/basetreeview.h>
#include <utils/fileutils.h>
#include <utils/icon.h>
#include <utils/layoutbuilder.h>
#include <utils/progressindicator.h>
@@ -141,8 +142,6 @@ public:
SquishServerSettings::SquishServerSettings()
{
setAutoApply(false);
registerAspect(&autTimeout);
autTimeout.setLabel(Tr::tr("Maximum startup time:"));
autTimeout.setToolTip(Tr::tr("Specifies how many seconds Squish should wait for a reply from the "
@@ -259,6 +258,7 @@ class SquishServerItem : public TreeItem
public:
explicit SquishServerItem(const QString &col1 = {}, const QString &col2 = {});
QVariant data(int column, int role) const override;
bool setData(int column, const QVariant &value, int role) override;
private:
QString m_first;
QString m_second;
@@ -282,6 +282,55 @@ QVariant SquishServerItem::data(int column, int role) const
return QVariant();
}
bool SquishServerItem::setData(int column, const QVariant &value, int role)
{
if (column != 1 || role != Qt::EditRole)
return TreeItem::setData(column, value, role);
m_second = value.toString();
return true;
}
class AttachableAutDialog : public QDialog
{
public:
AttachableAutDialog()
{
executable.setLabelText(Tr::tr("Name:"));
executable.setDisplayStyle(StringAspect::LineEditDisplay);
host.setLabelText(Tr::tr("Host:"));
host.setDisplayStyle(StringAspect::LineEditDisplay);
host.setDefaultValue("localhost");
port.setLabelText(Tr::tr("Port:"));
port.setRange(1, 65535);
port.setDefaultValue(12345);
QWidget *widget = new QWidget(this);
auto buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, this);
using namespace Layouting;
Form {
executable,
host,
port,
st
}.attachTo(widget);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(widget);
layout->addWidget(buttons);
setLayout(layout);
connect(buttons->button(QDialogButtonBox::Ok), &QPushButton::clicked,
this, &QDialog::accept);
connect(buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked,
this, &QDialog::reject);
setWindowTitle(Tr::tr("Add Attachable AUT"));
}
StringAspect executable;
StringAspect host;
IntegerAspect port;
};
class SquishServerSettingsWidget : public QWidget
{
public:
@@ -289,14 +338,22 @@ public:
private:
void repopulateApplicationView();
void addApplicationOrPath();
void addMappedAut(TreeItem *categoryItem, SquishServerItem *original);
void addAutPath(TreeItem *categoryItem, SquishServerItem *original);
void addAttachableAut(TreeItem *categoryItem, SquishServerItem *original);
void editApplicationOrPath();
void removeApplicationOrPath();
SquishServerSettings m_serverSettings;
BaseTreeView m_applicationsView;
TreeModel<SquishServerItem> m_model;
};
SquishServerSettingsWidget::SquishServerSettingsWidget(QWidget *parent)
: QWidget(parent)
{
m_model.setHeader({QString(), QString()}); // enforce 2 columns
m_applicationsView.setModel(&m_model);
m_applicationsView.setHeaderHidden(true);
m_applicationsView.setAttribute(Qt::WA_MacShowFocusRect, false);
m_applicationsView.setFrameStyle(QFrame::NoFrame);
@@ -307,6 +364,18 @@ SquishServerSettingsWidget::SquishServerSettingsWidget(QWidget *parent)
m_applicationsView.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_applicationsView.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
auto add = new QPushButton(Tr::tr("Add"), this);
auto edit = new QPushButton(Tr::tr("Edit"), this);
auto remove = new QPushButton(Tr::tr("Remove"), this);
auto updateButtons = [add, edit, remove] (const QModelIndex &idx) {
add->setEnabled(idx.isValid());
bool enabled = idx.isValid() && idx.parent() != QModelIndex();
edit->setEnabled(enabled);
remove->setEnabled(enabled);
};
updateButtons(QModelIndex());
using namespace Layouting;
Form grid {
&m_applicationsView, br,
@@ -315,11 +384,26 @@ SquishServerSettingsWidget::SquishServerSettingsWidget(QWidget *parent)
&m_serverSettings.postMortemWaitTime,
&m_serverSettings.animatedCursor,
};
// TODO buttons for add, edit, remove
Column { Row { grid }, st }.attachTo(this);
Column buttonCol {
add,
edit,
remove,
st
};
Column { Row { grid, buttonCol }, st }.attachTo(this);
repopulateApplicationView(); // initial
connect(&m_applicationsView, &QAbstractItemView::clicked,
this, updateButtons);
connect(add, &QPushButton::clicked,
this, &SquishServerSettingsWidget::addApplicationOrPath);
connect(edit, &QPushButton::clicked,
this, &SquishServerSettingsWidget::editApplicationOrPath);
connect(remove, &QPushButton::clicked,
this, &SquishServerSettingsWidget::removeApplicationOrPath);
auto progress = new ProgressIndicator(ProgressIndicatorSize::Large, this);
progress->attachToWidget(this);
setEnabled(false);
@@ -339,31 +423,179 @@ SquishServerSettingsWidget::SquishServerSettingsWidget(QWidget *parent)
void SquishServerSettingsWidget::repopulateApplicationView()
{
TreeModel<SquishServerItem> *model = new TreeModel<SquishServerItem>;
model->setHeader({QString(), QString()}); // enforce 2 columns
m_model.clear();
SquishServerItem *mapped = new SquishServerItem(Tr::tr("Mapped AUTs"));
model->rootItem()->appendChild(mapped);
m_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::tr("AUT Paths"));
model->rootItem()->appendChild(autPaths);
m_model.rootItem()->appendChild(autPaths);
for (const QString &path : qAsConst(m_serverSettings.autPaths))
autPaths->appendChild(new SquishServerItem(path, ""));
SquishServerItem *attachable = new SquishServerItem(Tr::tr("Attachable AUTs"));
model->rootItem()->appendChild(attachable);
m_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;
enum Category { MappedAutCategory, AutPathCategory, AttachableAutCategory };
void SquishServerSettingsWidget::addApplicationOrPath()
{
const QModelIndex &idx = m_applicationsView.currentIndex();
QTC_ASSERT(idx.isValid(), return);
const SquishServerItem *item = m_model.itemForIndex(idx);
QTC_ASSERT(item, return);
const int category = (item->level() == 2) ? idx.parent().row() : idx.row();
QTC_ASSERT(category >= 0 && category <= 2, return);
TreeItem *categoryItem = m_model.rootItem()->childAt(category);
switch (category) {
case MappedAutCategory:
addMappedAut(categoryItem, nullptr);
break;
case AutPathCategory:
addAutPath(categoryItem, nullptr);
break;
case AttachableAutCategory:
addAttachableAut(categoryItem, nullptr);
break;
}
}
void SquishServerSettingsWidget::addMappedAut(TreeItem *categoryItem, SquishServerItem *original)
{
FilePath entry = original ? FilePath::fromString(original->data(1, Qt::DisplayRole).toString())
: FilePath();
const FilePath aut = FileUtils::getOpenFilePath(nullptr, Tr::tr("Select Application to test"),
entry);
if (aut.isEmpty())
return;
const QString fileName = aut.completeBaseName();
if (original) {
const QString originalFileName = original->data(0, Qt::DisplayRole).toString();
if (originalFileName != fileName) {
m_serverSettings.mappedAuts.remove(originalFileName);
m_model.destroyItem(original);
}
}
m_serverSettings.mappedAuts.insert(fileName, aut.parentDir().path());
TreeItem *found = categoryItem->findAnyChild([&fileName](TreeItem *it) {
return it->data(0, Qt::DisplayRole).toString() == fileName;
});
if (found)
found->setData(1, aut.path(), Qt::EditRole);
else
categoryItem->appendChild(new SquishServerItem(fileName, aut.parentDir().path()));
}
void SquishServerSettingsWidget::addAutPath(TreeItem *categoryItem, SquishServerItem *original)
{
const QString originalPathStr = original ? original->data(0, Qt::DisplayRole).toString()
: QString();
FilePath entry = FilePath::fromString(originalPathStr);
const FilePath path = FileUtils::getExistingDirectory(nullptr,
Tr::tr("Select Application Path"), entry);
if (path.isEmpty() || path == entry)
return;
const QString pathStr = path.toString();
if (original) {
m_serverSettings.autPaths.removeOne(originalPathStr);
m_model.destroyItem(original);
}
int index = m_serverSettings.autPaths.indexOf(pathStr);
if (index != -1)
return;
m_serverSettings.autPaths.append(pathStr);
categoryItem->appendChild(new SquishServerItem(pathStr));
}
void SquishServerSettingsWidget::addAttachableAut(TreeItem *categoryItem, SquishServerItem *original)
{
AttachableAutDialog dialog;
const QString originalExecutable = original ? original->data(0, Qt::DisplayRole).toString()
: QString();
const QString originalHostAndPort = original ? original->data(1, Qt::DisplayRole).toString()
: QString();
if (original) {
dialog.executable.setValue(originalExecutable);
QStringList hostAndPortList = originalHostAndPort.split(':');
QTC_ASSERT(hostAndPortList.size() == 2, return);
dialog.host.setValue(hostAndPortList.first());
dialog.port.setValue(hostAndPortList.last().toInt());
}
if (dialog.exec() != QDialog::Accepted)
return;
const QString executableStr = dialog.executable.value();
const QString hostStr = dialog.host.value();
if (executableStr.isEmpty() || hostStr.isEmpty())
return;
if (original && executableStr != originalExecutable) {
m_serverSettings.attachableAuts.remove(originalExecutable);
m_model.destroyItem(original);
}
const QString hostAndPort = hostStr + ':' + QString::number(dialog.port.value());
m_serverSettings.attachableAuts.insert(executableStr, hostAndPort);
TreeItem *found = categoryItem->findAnyChild([&executableStr](TreeItem *it) {
return it->data(0, Qt::DisplayRole).toString() == executableStr;
});
if (found)
found->setData(1, hostAndPort, Qt::EditRole);
else
categoryItem->appendChild(new SquishServerItem(executableStr, hostAndPort));
}
void SquishServerSettingsWidget::removeApplicationOrPath()
{
const QModelIndex &idx = m_applicationsView.currentIndex();
QTC_ASSERT(idx.isValid(), return);
SquishServerItem *item = m_model.itemForIndex(idx);
QTC_ASSERT(item, return);
QTC_ASSERT(item->level() == 2, return);
int row = idx.parent().row();
QTC_ASSERT(row >= 0 && row <= 2, return);
switch (row) {
case MappedAutCategory:
m_serverSettings.mappedAuts.remove(item->data(0, Qt::DisplayRole).toString());
break;
case AutPathCategory:
m_serverSettings.autPaths.removeOne(item->data(0, Qt::DisplayRole).toString());
break;
case AttachableAutCategory:
m_serverSettings.attachableAuts.remove(item->data(0, Qt::DisplayRole).toString());
break;
}
m_model.destroyItem(item);
}
void SquishServerSettingsWidget::editApplicationOrPath()
{
const QModelIndex &idx = m_applicationsView.currentIndex();
QTC_ASSERT(idx.isValid(), return);
SquishServerItem *item = m_model.itemForIndex(idx);
QTC_ASSERT(item && item->level() == 2, return);
const int category = idx.parent().row();
QTC_ASSERT(category >= 0 && category <= 2, return);
TreeItem *categoryItem = m_model.rootItem()->childAt(category);
switch (category) {
case MappedAutCategory:
addMappedAut(categoryItem, item);
break;
case AutPathCategory:
addAutPath(categoryItem, item);
break;
case AttachableAutCategory:
addAttachableAut(categoryItem, item);
break;
}
}
SquishServerSettingsDialog::SquishServerSettingsDialog(QWidget *parent)