diff options
35 files changed, 1409 insertions, 29 deletions
diff --git a/plugins/autotest/autotest.pro b/plugins/autotest/autotest.pro index 4d3c6643f2..b60a83f656 100644 --- a/plugins/autotest/autotest.pro +++ b/plugins/autotest/autotest.pro @@ -9,6 +9,8 @@ include(autotest_dependencies.pri) DEFINES += AUTOTEST_LIBRARY SOURCES += \ + squishsettings.cpp \ + squishsettingspage.cpp \ testtreeview.cpp \ testtreemodel.cpp \ testtreeitem.cpp \ @@ -26,9 +28,14 @@ SOURCES += \ testsettings.cpp \ testsettingspage.cpp \ testnavigationwidget.cpp \ - testxmloutputreader.cpp + testxmloutputreader.cpp \ + testsquishfilehandler.cpp \ + opensquishsuitesdialog.cpp \ + testsquishutils.cpp HEADERS += \ + squishsettings.h \ + squishsettingspage.h \ testtreeview.h \ testtreemodel.h \ testtreeitem.h \ @@ -48,13 +55,18 @@ HEADERS += \ testsettings.h \ testsettingspage.h \ testnavigationwidget.h \ - testxmloutputreader.h + testxmloutputreader.h \ + testsquishfilehandler.h \ + opensquishsuitesdialog.h \ + testsquishutils.h RESOURCES += \ autotest.qrc FORMS += \ - testsettingspage.ui + squishsettingspage.ui \ + testsettingspage.ui \ + opensquishsuitesdialog.ui equals(TEST, 1) { HEADERS += autotestunittests.h diff --git a/plugins/autotest/autotest.qbs b/plugins/autotest/autotest.qbs index 93505bce3b..09581cfdee 100644 --- a/plugins/autotest/autotest.qbs +++ b/plugins/autotest/autotest.qbs @@ -31,6 +31,11 @@ QtcPlugin { "autotestconstants.h", "autotestplugin.cpp", "autotestplugin.h", + "squishsettings.cpp", + "squishsettings.h", + "squishsettingspage.cpp", + "squishsettingspage.h", + "squishsettingspage.ui", "testcodeparser.cpp", "testcodeparser.h", "testconfiguration.cpp", @@ -66,6 +71,13 @@ QtcPlugin { "testvisitor.h", "testxmloutputreader.cpp", "testxmloutputreader.h", + "testsquishfilehandler.cpp", + "testsquishfilehandler.h", + "opensquishsuitesdialog.cpp", + "opensquishsuitesdialog.h", + "opensquishsuitesdialog.ui", + "testsquishutils.cpp", + "testsquishutils.h" ] Group { diff --git a/plugins/autotest/autotest.qrc b/plugins/autotest/autotest.qrc index 2770aff5fe..49404c3083 100644 --- a/plugins/autotest/autotest.qrc +++ b/plugins/autotest/autotest.qrc @@ -21,5 +21,8 @@ <file>images/run.png</file> <file>images/runselected.png</file> <file>images/stop.png</file> + <file>images/objectsmap.png</file> + <file>images/play.png</file> + <file>images/record.png</file> </qresource> </RCC> diff --git a/plugins/autotest/autotestplugin.cpp b/plugins/autotest/autotestplugin.cpp index a2ab783418..6992166c6b 100644 --- a/plugins/autotest/autotestplugin.cpp +++ b/plugins/autotest/autotestplugin.cpp @@ -19,6 +19,8 @@ #include "autotestplugin.h" #include "autotestconstants.h" +#include "squishsettings.h" +#include "squishsettingspage.h" #include "testcodeparser.h" #include "testrunner.h" #include "testsettings.h" @@ -57,7 +59,7 @@ using namespace Core; static AutotestPlugin *m_instance = 0; AutotestPlugin::AutotestPlugin() - : m_settings(new TestSettings) + : m_qtestSettings(new TestSettings), m_squishSettings(new SquishSettings) { // needed to be used in QueuedConnection connects qRegisterMetaType<TestResult>(); @@ -82,9 +84,14 @@ AutotestPlugin *AutotestPlugin::instance() return m_instance; } -QSharedPointer<TestSettings> AutotestPlugin::settings() const +QSharedPointer<TestSettings> AutotestPlugin::qtestSettings() const { - return m_settings; + return m_qtestSettings; +} + +QSharedPointer<SquishSettings> AutotestPlugin::squishSettings() const +{ + return m_squishSettings; } bool AutotestPlugin::checkLicense() @@ -142,8 +149,10 @@ bool AutotestPlugin::initialize(const QStringList &arguments, QString *errorStri initializeMenuEntries(); - m_settings->fromSettings(ICore::settings()); - addAutoReleasedObject(new TestSettingsPage(m_settings)); + m_qtestSettings->fromSettings(ICore::settings()); + m_squishSettings->fromSettings(ICore::settings()); + addAutoReleasedObject(new TestSettingsPage(m_qtestSettings)); + addAutoReleasedObject(new SquishSettingsPage(m_squishSettings)); addAutoReleasedObject(new TestNavigationWidgetFactory); addAutoReleasedObject(TestResultsPane::instance()); diff --git a/plugins/autotest/autotestplugin.h b/plugins/autotest/autotestplugin.h index b7a02d89e7..ad6a2b9a2a 100644 --- a/plugins/autotest/autotestplugin.h +++ b/plugins/autotest/autotestplugin.h @@ -28,6 +28,7 @@ namespace Autotest { namespace Internal { struct TestSettings; +struct SquishSettings; class AutotestPlugin : public ExtensionSystem::IPlugin { @@ -40,7 +41,8 @@ public: static AutotestPlugin *instance(); - QSharedPointer<TestSettings> settings() const; + QSharedPointer<TestSettings> qtestSettings() const; + QSharedPointer<SquishSettings> squishSettings() const; bool initialize(const QStringList &arguments, QString *errorString); void extensionsInitialized(); @@ -53,7 +55,8 @@ private: void onRunSelectedTriggered(); void updateMenuItemsEnabledState(); QList<QObject *> createTestObjects() const; - const QSharedPointer<TestSettings> m_settings; + const QSharedPointer<TestSettings> m_qtestSettings; + const QSharedPointer<SquishSettings> m_squishSettings; }; } // namespace Internal diff --git a/plugins/autotest/images/objectsmap.png b/plugins/autotest/images/objectsmap.png Binary files differnew file mode 100644 index 0000000000..39a2a07eae --- /dev/null +++ b/plugins/autotest/images/objectsmap.png diff --git a/plugins/autotest/images/play.png b/plugins/autotest/images/play.png Binary files differnew file mode 100644 index 0000000000..893c7b40e3 --- /dev/null +++ b/plugins/autotest/images/play.png diff --git a/plugins/autotest/images/record.png b/plugins/autotest/images/record.png Binary files differnew file mode 100644 index 0000000000..45ba1ab712 --- /dev/null +++ b/plugins/autotest/images/record.png diff --git a/plugins/autotest/opensquishsuitesdialog.cpp b/plugins/autotest/opensquishsuitesdialog.cpp new file mode 100644 index 0000000000..14d1ad2bf3 --- /dev/null +++ b/plugins/autotest/opensquishsuitesdialog.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at +** http://www.qt.io/contact-us +** +** This file is part of the Qt Creator Enterprise Auto Test Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include "opensquishsuitesdialog.h" +#include "testsquishutils.h" +#include "ui_opensquishsuitesdialog.h" + +#include <QDir> +#include <QPushButton> +#include <QListWidgetItem> + +namespace Autotest { +namespace Internal { + +static QString previousPath; + +OpenSquishSuitesDialog::OpenSquishSuitesDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::OpenSquishSuitesDialog) +{ + ui->setupUi(this); + ui->buttonBox->button(QDialogButtonBox::Open)->setEnabled(false); + + connect(ui->directoryLineEdit, &Utils::PathChooser::pathChanged, + this, &OpenSquishSuitesDialog::onDirectoryChanged); + connect(ui->selectAllPushButton, &QPushButton::clicked, + this, &OpenSquishSuitesDialog::selectAll); + connect(ui->deselectAllPushButton, &QPushButton::clicked, + this, &OpenSquishSuitesDialog::deselectAll); + connect(this, &OpenSquishSuitesDialog::accepted, + this, &OpenSquishSuitesDialog::setChosenSuites); + + ui->directoryLineEdit->setPath(previousPath); +} + +OpenSquishSuitesDialog::~OpenSquishSuitesDialog() +{ + delete ui; +} + +void OpenSquishSuitesDialog::onDirectoryChanged() +{ + ui->suitesListWidget->clear(); + ui->buttonBox->button(QDialogButtonBox::Open)->setEnabled(false); + QDir baseDir(ui->directoryLineEdit->path()); + if (!baseDir.exists()) { + return; + } + + foreach (const QFileInfo &subDir, baseDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { + if (!subDir.baseName().startsWith(QLatin1String("suite_"))) + continue; + + if (TestSquishUtils::validTestCases(subDir.absoluteFilePath()).size()) { + QListWidgetItem *item = new QListWidgetItem(subDir.baseName(), + ui->suitesListWidget); + item->setCheckState(Qt::Checked); + connect(ui->suitesListWidget, &QListWidget::itemChanged, + this, &OpenSquishSuitesDialog::onListItemChanged); + } + } + ui->buttonBox->button(QDialogButtonBox::Open)->setEnabled(ui->suitesListWidget->count()); +} + +void OpenSquishSuitesDialog::onListItemChanged(QListWidgetItem *) +{ + const int count = ui->suitesListWidget->count(); + for (int row = 0; row < count; ++row) { + if (ui->suitesListWidget->item(row)->checkState() == Qt::Checked) { + ui->buttonBox->button(QDialogButtonBox::Open)->setEnabled(true); + return; + } + } + ui->buttonBox->button(QDialogButtonBox::Open)->setEnabled(false); +} + +void OpenSquishSuitesDialog::selectAll() +{ + const int count = ui->suitesListWidget->count(); + for (int row = 0; row < count; ++row) + ui->suitesListWidget->item(row)->setCheckState(Qt::Checked); +} + +void OpenSquishSuitesDialog::deselectAll() +{ + const int count = ui->suitesListWidget->count(); + for (int row = 0; row < count; ++row) + ui->suitesListWidget->item(row)->setCheckState(Qt::Unchecked); +} + +void OpenSquishSuitesDialog::setChosenSuites() +{ + const int count = ui->suitesListWidget->count(); + previousPath = ui->directoryLineEdit->path(); + const QDir baseDir(previousPath); + for (int row = 0; row < count; ++row) { + QListWidgetItem *item = ui->suitesListWidget->item(row); + if (item->checkState() == Qt::Checked) + m_chosenSuites.append(QFileInfo(baseDir, item->text()).absoluteFilePath()); + } +} + +} // namespace Internal +} // namespace Autotest diff --git a/plugins/autotest/opensquishsuitesdialog.h b/plugins/autotest/opensquishsuitesdialog.h new file mode 100644 index 0000000000..62b87e00a1 --- /dev/null +++ b/plugins/autotest/opensquishsuitesdialog.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at +** http://www.qt.io/contact-us +** +** This file is part of the Qt Creator Enterprise Auto Test Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#ifndef OPENSQUISHSUITESDIALOG_H +#define OPENSQUISHSUITESDIALOG_H + +#include <QDialog> + +class QListWidgetItem; + +namespace Ui { +class OpenSquishSuitesDialog; +} + +namespace Autotest { +namespace Internal { + +class OpenSquishSuitesDialog : public QDialog +{ + Q_OBJECT + +public: + explicit OpenSquishSuitesDialog(QWidget *parent = 0); + ~OpenSquishSuitesDialog(); + QStringList chosenSuites() const { return m_chosenSuites; } + +private: + void onDirectoryChanged(); + void onListItemChanged(QListWidgetItem *); + void selectAll(); + void deselectAll(); + void setChosenSuites(); + + Ui::OpenSquishSuitesDialog *ui; + QStringList m_chosenSuites; +}; + +} // namespace Internal +} // namespace Autotest + +#endif // OPENSQUISHSUITESDIALOG_H diff --git a/plugins/autotest/opensquishsuitesdialog.ui b/plugins/autotest/opensquishsuitesdialog.ui new file mode 100644 index 0000000000..c1fe45de6c --- /dev/null +++ b/plugins/autotest/opensquishsuitesdialog.ui @@ -0,0 +1,135 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>OpenSquishSuitesDialog</class> + <widget class="QDialog" name="OpenSquishSuitesDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>303</width> + <height>340</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string>Open Squish Test Suites</string> + </property> + <property name="modal"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Base directory:</string> + </property> + </widget> + </item> + <item> + <widget class="Utils::PathChooser" name="directoryLineEdit"/> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Test suites:</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QListWidget" name="suitesListWidget"/> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QPushButton" name="selectAllPushButton"> + <property name="text"> + <string>Select All</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="deselectAllPushButton"> + <property name="text"> + <string>Deselect All</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Open</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>Utils::PathChooser</class> + <extends>QLineEdit</extends> + <header location="global">utils/pathchooser.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>OpenSquishSuitesDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>OpenSquishSuitesDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/plugins/autotest/squishsettings.cpp b/plugins/autotest/squishsettings.cpp new file mode 100644 index 0000000000..db981ce34a --- /dev/null +++ b/plugins/autotest/squishsettings.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at +** http://www.qt.io/contact-us +** +** This file is part of the Qt Creator Enterprise Auto Test Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include "squishsettings.h" + +#include <QSettings> + +namespace Autotest { +namespace Internal { + +static const char group[] = "Squish"; +static const char squishPathKey[] = "SquishPath"; +static const char licensePathKey[] = "LicensePath"; +static const char localKey[] = "Local"; +static const char serverHostKey[] = "ServerHost"; +static const char serverPortKey[] = "ServerPort"; +static const char verboseKey[] = "Verbose"; + +void SquishSettings::toSettings(QSettings *s) const +{ + s->beginGroup(QLatin1String(group)); + s->setValue(QLatin1String(squishPathKey), squishPath.toString()); + s->setValue(QLatin1String(licensePathKey), licensePath.toString()); + s->setValue(QLatin1String(localKey), local); + s->setValue(QLatin1String(serverHostKey), serverHost); + s->setValue(QLatin1String(serverPortKey), serverPort); + s->setValue(QLatin1String(verboseKey), verbose); + s->endGroup(); +} + +void SquishSettings::fromSettings(const QSettings *s) +{ + const QString root = QLatin1String(group) + QLatin1Char('/'); + squishPath = Utils::FileName::fromString(s->value(root + QLatin1String(squishPathKey)).toString()); + licensePath = Utils::FileName::fromString(s->value(root + QLatin1String(licensePathKey)).toString()); + local = s->value(root + QLatin1String(localKey), true).toBool(); + serverHost = s->value(root + QLatin1String(serverHostKey), QStringLiteral("localhost")).toString(); + serverPort = s->value(root + QLatin1String(serverPortKey), 9999).toUInt(); + verbose = s->value(root + QLatin1String(verboseKey), false).toBool(); +} + +bool SquishSettings::operator==(const SquishSettings &other) const +{ + return local == other.local + && verbose == other.verbose + && serverPort == other.serverPort + && squishPath == other.squishPath + && licensePath == other.licensePath + && serverHost == other.serverHost; +} + +bool SquishSettings::operator!=(const SquishSettings &other) const +{ + return !(*this == other); +} + +} // namespace Internal +} // namespace Autotest diff --git a/plugins/autotest/squishsettings.h b/plugins/autotest/squishsettings.h new file mode 100644 index 0000000000..5c11e1793c --- /dev/null +++ b/plugins/autotest/squishsettings.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at +** http://www.qt.io/contact-us +** +** This file is part of the Qt Creator Enterprise Auto Test Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#ifndef SQUISHSETTINGS_H +#define SQUISHSETTINGS_H + +#include <utils/fileutils.h> + +#include <QtGlobal> +#include <QString> + +QT_BEGIN_NAMESPACE +class QSettings; +QT_END_NAMESPACE + +namespace Autotest { +namespace Internal { + +struct SquishSettings +{ + void toSettings(QSettings *s) const; + void fromSettings(const QSettings *s); + + bool operator==(const SquishSettings &other) const; + bool operator!=(const SquishSettings &other) const; + + Utils::FileName squishPath; + Utils::FileName licensePath; + QString serverHost; + quint16 serverPort; + bool local; + bool verbose; +}; + + +} // namespace Internal +} // namespace Autotest + +#endif // SQUISHSETTINGS_H diff --git a/plugins/autotest/squishsettingspage.cpp b/plugins/autotest/squishsettingspage.cpp new file mode 100644 index 0000000000..9325e928e6 --- /dev/null +++ b/plugins/autotest/squishsettingspage.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at +** http://www.qt.io/contact-us +** +** This file is part of the Qt Creator Enterprise Auto Test Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include "autotestconstants.h" +#include "squishsettingspage.h" +#include "squishsettings.h" + +#include <coreplugin/icore.h> +#include <utils/hostosinfo.h> + +namespace Autotest { +namespace Internal { + +SquishSettingsWidget::SquishSettingsWidget(QWidget *parent) + : QWidget(parent) +{ + m_ui.setupUi(this); + + connect(m_ui.localCheckBox, &QCheckBox::toggled, + this, &SquishSettingsWidget::onLocalToggled); +} + +void SquishSettingsWidget::setSettings(const SquishSettings &settings) +{ + m_ui.squishPathChooser->setFileName(settings.squishPath); + m_ui.licensePathChooser->setFileName(settings.licensePath); + m_ui.localCheckBox->setChecked(settings.local); + m_ui.serverHostLineEdit->setText(settings.serverHost); + m_ui.serverPortSpinBox->setValue(settings.serverPort); + m_ui.verboseCheckBox->setChecked(settings.verbose); +} + +SquishSettings SquishSettingsWidget::settings() const +{ + SquishSettings result; + result.squishPath = m_ui.squishPathChooser->fileName(); + result.licensePath = m_ui.licensePathChooser->fileName(); + result.local = m_ui.localCheckBox->checkState() == Qt::Checked; + result.serverHost = m_ui.serverHostLineEdit->text(); + result.serverPort = m_ui.serverPortSpinBox->value(); + result.verbose = m_ui.verboseCheckBox->checkState() == Qt::Checked; + return result; +} + +void SquishSettingsWidget::onLocalToggled(bool checked) +{ + m_ui.serverHostLineEdit->setEnabled(!checked); + m_ui.serverPortSpinBox->setEnabled(!checked); +} + +SquishSettingsPage::SquishSettingsPage(const QSharedPointer<SquishSettings> &settings) + : m_settings(settings), m_widget(0) +{ + setId("B.Squish"); + setDisplayName(tr("Squish")); + setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); +} + +QWidget *SquishSettingsPage::widget() +{ + if (!m_widget) { + m_widget = new SquishSettingsWidget; + m_widget->setSettings(*m_settings); + } + return m_widget; +} + +void SquishSettingsPage::apply() +{ + if (!m_widget) // page was not shown at all + return; + const SquishSettings newSettings = m_widget->settings(); + if (newSettings != *m_settings) { + *m_settings = newSettings; + m_settings->toSettings(Core::ICore::settings()); + } +} + +} // namespace Internal +} // namespace Autotest diff --git a/plugins/autotest/squishsettingspage.h b/plugins/autotest/squishsettingspage.h new file mode 100644 index 0000000000..2685012485 --- /dev/null +++ b/plugins/autotest/squishsettingspage.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at +** http://www.qt.io/contact-us +** +** This file is part of the Qt Creator Enterprise Auto Test Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#ifndef SQUISHSETTINGSPAGE_H +#define SQUISHSETTINGSPAGE_H + +#include "ui_squishsettingspage.h" + +#include <coreplugin/dialogs/ioptionspage.h> + +#include <QPointer> +#include <QSharedPointer> +#include <QWidget> + +namespace Autotest { +namespace Internal { + +struct SquishSettings; + +class SquishSettingsWidget : public QWidget +{ + Q_OBJECT +public: + explicit SquishSettingsWidget(QWidget *parent = 0); + + void setSettings(const SquishSettings &settings); + SquishSettings settings() const; + +private: + void onLocalToggled(bool checked); + + Ui::SquishSettingsPage m_ui; + +}; + +class SquishSettingsPage : public Core::IOptionsPage +{ + Q_OBJECT +public: + explicit SquishSettingsPage(const QSharedPointer<SquishSettings> &settings); + + QWidget *widget(); + void apply(); + void finish() { } + +private: + QSharedPointer<SquishSettings> m_settings; + QPointer<SquishSettingsWidget> m_widget; +}; + +} // namespace Internal +} // namespace Autotest + +#endif // SQUISHSETTINGSPAGE_H diff --git a/plugins/autotest/squishsettingspage.ui b/plugins/autotest/squishsettingspage.ui new file mode 100644 index 0000000000..08fbe72ee5 --- /dev/null +++ b/plugins/autotest/squishsettingspage.ui @@ -0,0 +1,127 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Autotest::Internal::SquishSettingsPage</class> + <widget class="QWidget" name="Autotest::Internal::SquishSettingsPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>463</width> + <height>338</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="squishPathLabel"> + <property name="text"> + <string>Squish path:</string> + </property> + </widget> + </item> + <item row="0" column="2" colspan="5"> + <widget class="Utils::PathChooser" name="squishPathChooser"> + <property name="toolTip"> + <string>Path to Squish installation directory.</string> + </property> + </widget> + </item> + <item row="1" column="0" colspan="2"> + <widget class="QLabel" name="licensePathLabel"> + <property name="text"> + <string>License path:</string> + </property> + </widget> + </item> + <item row="1" column="2" colspan="5"> + <widget class="Utils::PathChooser" name="licensePathChooser"> + <property name="toolTip"> + <string>Path to directory containing Squish license file. You will only need this in special configurations like if you did not run the Squish setup tool.</string> + </property> + </widget> + </item> + <item row="2" column="0" colspan="3"> + <widget class="QCheckBox" name="localCheckBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Local server</string> + </property> + </widget> + </item> + <item row="2" column="3"> + <widget class="QLabel" name="serverHostLabel"> + <property name="text"> + <string>Server host:</string> + </property> + </widget> + </item> + <item row="2" column="4"> + <widget class="QLineEdit" name="serverHostLineEdit"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="2" column="5"> + <widget class="QLabel" name="portLabel"> + <property name="text"> + <string>Port:</string> + </property> + </widget> + </item> + <item row="2" column="6"> + <widget class="QSpinBox" name="serverPortSpinBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximum"> + <number>65535</number> + </property> + </widget> + </item> + <item row="3" column="0" colspan="3"> + <widget class="QCheckBox" name="verboseCheckBox"> + <property name="text"> + <string>Verbose log</string> + </property> + </widget> + </item> + <item row="4" column="0" colspan="3"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>289</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>Utils::PathChooser</class> + <extends>QLineEdit</extends> + <header location="global">utils/pathchooser.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/plugins/autotest/testnavigationwidget.cpp b/plugins/autotest/testnavigationwidget.cpp index f9847a5782..33c5f4342b 100644 --- a/plugins/autotest/testnavigationwidget.cpp +++ b/plugins/autotest/testnavigationwidget.cpp @@ -18,6 +18,7 @@ ****************************************************************************/ #include "testnavigationwidget.h" +#include "testsquishfilehandler.h" #include "testtreemodel.h" #include "testtreeview.h" #include "testtreeitemdelegate.h" @@ -35,7 +36,9 @@ #include <coreplugin/actionmanager/actionmanager.h> #include <QAction> +#include <QHeaderView> #include <QMenu> +#include <QMessageBox> #include <QTimer> #include <QToolButton> #include <QVBoxLayout> @@ -43,6 +46,8 @@ namespace Autotest { namespace Internal { +const int defaultSectionSize = 18; + TestNavigationWidget::TestNavigationWidget(QWidget *parent) : QWidget(parent) { @@ -54,6 +59,14 @@ TestNavigationWidget::TestNavigationWidget(QWidget *parent) : m_view->setModel(m_sortFilterModel); m_view->setSortingEnabled(true); m_view->setItemDelegate(new TestTreeItemDelegate(this)); + QHeaderView *header = new QHeaderView(Qt::Horizontal, m_view); + header->setModel(m_model); + header->setDefaultSectionSize(0); + header->setSectionResizeMode(0, QHeaderView::Stretch); + header->setSectionResizeMode(1, QHeaderView::Fixed); + header->setSectionResizeMode(2, QHeaderView::Fixed); + m_view->setHeader(header); + m_view->setHeaderHidden(true); QVBoxLayout *layout = new QVBoxLayout; layout->setMargin(0); @@ -77,6 +90,11 @@ TestNavigationWidget::TestNavigationWidget(QWidget *parent) : this, &TestNavigationWidget::onParsingFinished); connect(m_progressTimer, &QTimer::timeout, m_progressIndicator, &Utils::ProgressIndicator::show); + + connect(m_view, &QTreeView::expanded, this, &TestNavigationWidget::onExpanded); + connect(m_view, &QTreeView::collapsed, this, &TestNavigationWidget::onCollapsed); + connect(m_model, &QAbstractItemModel::rowsInserted, this, &TestNavigationWidget::onRowsInserted); + connect(m_model, &QAbstractItemModel::rowsRemoved, this, &TestNavigationWidget::onRowsRemoved); } TestNavigationWidget::~TestNavigationWidget() @@ -84,11 +102,101 @@ TestNavigationWidget::~TestNavigationWidget() m_model->disableParsing(); } +bool TestNavigationWidget::handleSquishContextMenuEvent(QContextMenuEvent *event, bool enabled) +{ + bool isSquishMenu = false; + QMenu menu; + + // item specific menu entries + const QModelIndexList list = m_view->selectionModel()->selectedIndexes(); + // 3 columns - but we only need the data of the first column as the others contain only an icon + if (list.size() == 3) { + QRect rect(m_view->visualRect(list.first())); + rect.adjust(0, 0, defaultSectionSize * 2, 0); + if (rect.contains(event->pos())) { + TestTreeItem::Type type = TestTreeItem::toTestType(list.first().data(TypeRole).toInt()); + + if (type == TestTreeItem::SQUISH_TESTCASE) { + isSquishMenu = true; + QAction *runThisTestCase = new QAction(tr("Run This Test Case"), &menu); + menu.addAction(runThisTestCase); + runThisTestCase->setEnabled(enabled); + QAction *deleteTestCase = new QAction(tr("Delete Test Case"), &menu); + menu.addAction(deleteTestCase); + deleteTestCase->setEnabled(enabled); + menu.addSeparator(); + } else if (type == TestTreeItem::SQUISH_SUITE) { + const QString suiteName = list.first().data().toString(); + isSquishMenu = true; + QAction *runThisTestSuite = new QAction(tr("Run This Test Suite"), &menu); + menu.addAction(runThisTestSuite); + runThisTestSuite->setEnabled(enabled); + menu.addSeparator(); + QAction *addNewTestCase = new QAction(tr("Add New Test Case..."), &menu); + menu.addAction(addNewTestCase); + addNewTestCase->setEnabled(enabled); + QAction *closeTestSuite = new QAction(tr("Close Test Suite"), &menu); + menu.addAction(closeTestSuite); + closeTestSuite->setEnabled(enabled); + QAction *deleteTestSuite = new QAction(tr("Delete Test Suite"), &menu); + menu.addAction(deleteTestSuite); + deleteTestSuite->setEnabled(enabled); + menu.addSeparator(); + + connect(closeTestSuite, &QAction::triggered, + [suiteName] () { + TestSquishFileHandler::instance()->closeTestSuite(suiteName); + }); + } + } + } + // ROOT items aren't selectable - so, check for them different way + QModelIndex squishIndex = m_view->model()->index(2, 0); + QRect squishRootRect(m_view->visualRect(squishIndex)); + if (squishRootRect.contains(event->pos())) + isSquishMenu = true; + + if (isSquishMenu) { + // general squish related menu entries + QAction *openSquishSuites = new QAction(tr("Open Squish Suites..."), &menu); + menu.addAction(openSquishSuites); + openSquishSuites->setEnabled(enabled); + QAction *createNewTestSuite = new QAction(tr("Create New Test Suite..."), &menu); + menu.addAction(createNewTestSuite); + createNewTestSuite->setEnabled(enabled); + + connect(openSquishSuites, &QAction::triggered, + TestSquishFileHandler::instance(), &TestSquishFileHandler::openTestSuites); + + if (m_view->model()->rowCount(squishIndex) > 0) { + menu.addSeparator(); + QAction *closeAllSuites = new QAction(tr("Close All Test Suites"), &menu); + menu.addAction(closeAllSuites); + closeAllSuites->setEnabled(enabled); + + connect(closeAllSuites, &QAction::triggered, [this] () { + if (QMessageBox::question(this, tr("Close All Test Suites"), + tr("Are you sure you want to close all test suites?" + /*"\nThis will close all related files as well."*/)) + == QMessageBox::Yes) + TestSquishFileHandler::instance()->closeAllTestSuites(); + }); + } + + menu.exec(mapToGlobal(event->pos())); + } + return isSquishMenu; +} + void TestNavigationWidget::contextMenuEvent(QContextMenuEvent *event) { const bool enabled = !TestRunner::instance()->isTestRunning() && m_model->parser()->state() == TestCodeParser::Idle; const bool hasTests = m_model->hasTests(); + + if (handleSquishContextMenuEvent(event, enabled)) + return; + QMenu menu; QAction *runAll = Core::ActionManager::command(Constants::ACTION_RUN_ALL_ID)->action(); QAction *runSelected = Core::ActionManager::command(Constants::ACTION_RUN_SELECTED_ID)->action(); @@ -194,6 +302,32 @@ void TestNavigationWidget::onParsingFinished() m_progressIndicator->hide(); } +void TestNavigationWidget::onExpanded(const QModelIndex &index) +{ + if (index.data().toString().startsWith(QLatin1String("Squish"))) + m_view->header()->setDefaultSectionSize(defaultSectionSize); +} + +void TestNavigationWidget::onCollapsed(const QModelIndex &index) +{ + if (index.data().toString().startsWith(QLatin1String("Squish"))) + m_view->header()->setDefaultSectionSize(0); +} + +void TestNavigationWidget::onRowsInserted(const QModelIndex &parent, int, int) +{ + if (parent.isValid() && parent.data().toString().startsWith(QLatin1String("Squish"))) + if (m_view->isExpanded(parent) && m_model->rowCount(parent)) + m_view->header()->setDefaultSectionSize(defaultSectionSize); +} + +void TestNavigationWidget::onRowsRemoved(const QModelIndex &parent, int, int) +{ + if (parent.isValid() && parent.data().toString().startsWith(QLatin1String("Squish"))) + if (m_model->rowCount(parent) == 0) + m_view->header()->setDefaultSectionSize(0); +} + void TestNavigationWidget::initializeFilterMenu() { QAction *action = new QAction(m_filterMenu); diff --git a/plugins/autotest/testnavigationwidget.h b/plugins/autotest/testnavigationwidget.h index a4b4c6f061..8704595564 100644 --- a/plugins/autotest/testnavigationwidget.h +++ b/plugins/autotest/testnavigationwidget.h @@ -66,8 +66,13 @@ private slots: void onFilterMenuTriggered(QAction *action); void onParsingStarted(); void onParsingFinished(); + void onExpanded(const QModelIndex &index); + void onCollapsed(const QModelIndex &index); + void onRowsInserted(const QModelIndex &parent, int, int); + void onRowsRemoved(const QModelIndex &parent, int, int); private: + bool handleSquishContextMenuEvent(QContextMenuEvent *event, bool enabled); void initializeFilterMenu(); TestTreeModel *m_model; diff --git a/plugins/autotest/testresultdelegate.cpp b/plugins/autotest/testresultdelegate.cpp index c20ce11200..0eedd68eef 100644 --- a/plugins/autotest/testresultdelegate.cpp +++ b/plugins/autotest/testresultdelegate.cpp @@ -131,7 +131,7 @@ void TestResultDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op int fontHeight = fm.height(); output.replace(QLatin1Char('\n'), QChar::LineSeparator); - if (AutotestPlugin::instance()->settings()->limitResultOutput + if (AutotestPlugin::instance()->qtestSettings()->limitResultOutput && output.length() > outputLimit) output = output.left(outputLimit).append(QLatin1String("...")); @@ -237,7 +237,7 @@ QSize TestResultDelegate::sizeHint(const QStyleOptionViewItem &option, const QMo int height = 0; int leading = fm.leading(); - if (AutotestPlugin::instance()->settings()->limitResultOutput + if (AutotestPlugin::instance()->qtestSettings()->limitResultOutput && output.length() > outputLimit) output = output.left(outputLimit).append(QLatin1String("...")); diff --git a/plugins/autotest/testresultspane.cpp b/plugins/autotest/testresultspane.cpp index c2a2b5851f..e5d9bd6084 100644 --- a/plugins/autotest/testresultspane.cpp +++ b/plugins/autotest/testresultspane.cpp @@ -293,7 +293,7 @@ void TestResultsPane::onRunSelectedTriggered() void TestResultsPane::initializeFilterMenu() { - const bool omitIntern = AutotestPlugin::instance()->settings()->omitInternalMssg; + const bool omitIntern = AutotestPlugin::instance()->qtestSettings()->omitInternalMssg; // FilterModel has all messages enabled by default if (omitIntern) m_filterModel->toggleTestResultType(Result::MESSAGE_INTERNAL); diff --git a/plugins/autotest/testrunner.cpp b/plugins/autotest/testrunner.cpp index 07f90a56ad..368897a929 100644 --- a/plugins/autotest/testrunner.cpp +++ b/plugins/autotest/testrunner.cpp @@ -186,7 +186,7 @@ void performTestRun(QFutureInterface<void> &futureInterface, void TestRunner::runTests() { - const QSharedPointer<TestSettings> settings = AutotestPlugin::instance()->settings(); + const QSharedPointer<TestSettings> settings = AutotestPlugin::instance()->qtestSettings(); const int timeout = settings->timeout; const QString metricsOption = TestSettings::metricsTypeToOption(settings->metrics); const bool displayRunConfigWarnings = !settings->omitRunConfigWarn; diff --git a/plugins/autotest/testsettings.cpp b/plugins/autotest/testsettings.cpp index 3a11b8c66b..276c2c9a79 100644 --- a/plugins/autotest/testsettings.cpp +++ b/plugins/autotest/testsettings.cpp @@ -24,7 +24,7 @@ namespace Autotest { namespace Internal { -static const char group[] = "Autotest"; +static const char group[] = "QTest"; static const char timeoutKey[] = "Timeout"; static const char metricsKey[] = "Metrics"; static const char omitInternalKey[] = "OmitInternal"; diff --git a/plugins/autotest/testsettingspage.cpp b/plugins/autotest/testsettingspage.cpp index e65bff754a..a0b218cb27 100644 --- a/plugins/autotest/testsettingspage.cpp +++ b/plugins/autotest/testsettingspage.cpp @@ -89,8 +89,8 @@ TestSettings TestSettingsWidget::settings() const TestSettingsPage::TestSettingsPage(const QSharedPointer<TestSettings> &settings) : m_settings(settings), m_widget(0) { - setId("A.General"); - setDisplayName(tr("General")); + setId("A.QTest"); + setDisplayName(tr("QTest")); setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY); setDisplayCategory(tr("Test Settings")); setCategoryIcon(QLatin1String(":/images/autotest.png")); diff --git a/plugins/autotest/testsettingspage.h b/plugins/autotest/testsettingspage.h index 3e98c8413d..61a8ea678a 100644 --- a/plugins/autotest/testsettingspage.h +++ b/plugins/autotest/testsettingspage.h @@ -25,6 +25,7 @@ #include <coreplugin/dialogs/ioptionspage.h> #include <QPointer> +#include <QSharedPointer> namespace Autotest { namespace Internal { diff --git a/plugins/autotest/testsquishfilehandler.cpp b/plugins/autotest/testsquishfilehandler.cpp new file mode 100644 index 0000000000..26a2f718b0 --- /dev/null +++ b/plugins/autotest/testsquishfilehandler.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at +** http://www.qt.io/contact-us +** +** This file is part of the Qt Creator Enterprise Auto Test Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include "opensquishsuitesdialog.h" +#include "testsquishfilehandler.h" +#include "testsquishutils.h" + +#include <QDir> +#include <QFileInfo> +#include <QMessageBox> + +namespace Autotest { +namespace Internal { + +static TestSquishFileHandler *m_instance = 0; + +TestSquishFileHandler::TestSquishFileHandler(QObject *parent) : QObject(parent) +{ + m_instance = this; +} + +TestSquishFileHandler *TestSquishFileHandler::instance() +{ + if (!m_instance) + m_instance = new TestSquishFileHandler; + + return m_instance; +} + +TestTreeItem createTestTreeItem(const QString &name, const QString &filePath, + const QStringList &cases) +{ + TestTreeItem item(name, filePath, TestTreeItem::SQUISH_SUITE); + foreach (const QString &testCase, cases) { + TestTreeItem *child = new TestTreeItem(QFileInfo(testCase).dir().dirName(), testCase, + TestTreeItem::SQUISH_TESTCASE, &item); + item.appendChild(child); + } + return item; +} + +void TestSquishFileHandler::openTestSuites() +{ + OpenSquishSuitesDialog dialog; + dialog.exec(); + foreach (const QString &suite, dialog.chosenSuites()) { + const QDir suiteDir(suite); + const QStringList cases = TestSquishUtils::validTestCases(suite); + const QFileInfo suiteConf(suiteDir, QLatin1String("suite.conf")); + if (m_suites.contains(suiteDir.dirName())) { + if (QMessageBox::question(0, tr("Suite Already Open"), + tr("A test suite with the name \"%1\" is already open. " + "The opened test suite will be closed and replaced " + "with the new one.").arg(suiteDir.dirName()), + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel) + == QMessageBox::Cancel) { + continue; + } else { + TestTreeItem item = createTestTreeItem(suiteDir.dirName(), + suiteConf.absoluteFilePath(), cases); + // TODO update file watcher + m_suites.insert(suiteDir.dirName(), suiteConf.absoluteFilePath()); + emit testTreeItemModified(item, TestTreeModel::SquishTest, + m_suites.value(suiteDir.dirName())); + } + } else { + TestTreeItem item = createTestTreeItem(suiteDir.dirName(), + suiteConf.absoluteFilePath(), cases); + // TODO add file watcher + m_suites.insert(suiteDir.dirName(), suiteConf.absoluteFilePath()); + emit testTreeItemCreated(item, TestTreeModel::SquishTest); + } + } +} + +void TestSquishFileHandler::closeTestSuite(const QString &suite) +{ + const QString suiteConf = m_suites.value(suite); + if (suiteConf.isEmpty()) + return; + + // TODO close respective editors if there are any + // TODO remove file watcher + emit testTreeItemsRemoved(suiteConf, TestTreeModel::SquishTest); + m_suites.remove(suite); +} + +void TestSquishFileHandler::closeAllTestSuites() +{ + // TODO close respective editors if there are any + // TODO remove file watcher + foreach (const QString &suiteConf, m_suites.values()) + emit testTreeItemsRemoved(suiteConf, TestTreeModel::SquishTest); + m_suites.clear(); +} + +} // namespace Internal +} // namespace Autotest diff --git a/plugins/autotest/testsquishfilehandler.h b/plugins/autotest/testsquishfilehandler.h new file mode 100644 index 0000000000..a63d435929 --- /dev/null +++ b/plugins/autotest/testsquishfilehandler.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at +** http://www.qt.io/contact-us +** +** This file is part of the Qt Creator Enterprise Auto Test Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#ifndef TESTSQUISHFILEHANDLER_H +#define TESTSQUISHFILEHANDLER_H + +#include "testtreeitem.h" +#include "testtreemodel.h" + +#include <QObject> +#include <QString> +#include <QMap> + +namespace Autotest { +namespace Internal { + +class TestSquishFileHandler : public QObject +{ + Q_OBJECT +public: + explicit TestSquishFileHandler(QObject *parent = 0); + static TestSquishFileHandler *instance(); + + void openTestSuites(); + void closeTestSuite(const QString &suite); + void closeAllTestSuites(); + +signals: + void testTreeItemCreated(const TestTreeItem &item, TestTreeModel::Type type); + void testTreeItemModified(const TestTreeItem &item, TestTreeModel::Type type, const QString &file); + void testTreeItemsRemoved(const QString &filePath, TestTreeModel::Type type); + +private: + QMap<QString, QString> m_suites; + +}; + +} // namespace Internal +} // namespace Autotest + +#endif // TESTSQUISHFILEHANDLER_H diff --git a/plugins/autotest/testsquishutils.cpp b/plugins/autotest/testsquishutils.cpp new file mode 100644 index 0000000000..cafe9cb5ce --- /dev/null +++ b/plugins/autotest/testsquishutils.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at +** http://www.qt.io/contact-us +** +** This file is part of the Qt Creator Enterprise Auto Test Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include "testsquishutils.h" + +#include <QDir> +#include <QFileInfo> +#include <QString> +#include <QSettings> + +namespace Autotest { +namespace Internal { + +const static QString squishLanguageKey = QLatin1String("LANGUAGE"); +const static QString squishTestCasesKey = QLatin1String("TEST_CASES"); + +QStringList TestSquishUtils::validTestCases(QString baseDirectory) +{ + QStringList validCases; + QDir subDir(baseDirectory); + QFileInfo suiteConf(subDir, QLatin1String("suite.conf")); + if (suiteConf.exists()) { + QVariantMap conf = readSuiteConf(suiteConf.absoluteFilePath()); + QString extension = extensionForLanguage(conf.value(squishLanguageKey).toString()); + QStringList cases = conf.value(squishTestCasesKey).toString().split( + QRegExp(QLatin1String("\\s+"))); + + foreach (const QString &testCase, cases) { + QFileInfo testCaseDirInfo(subDir, testCase); + if (testCaseDirInfo.isDir()) { + QFileInfo testCaseTestInfo(testCaseDirInfo.filePath(), + QLatin1String("test") + extension); + if (testCaseTestInfo.isFile()) + validCases.append(testCaseTestInfo.absoluteFilePath()); + } + } + } + + return validCases; +} + +QVariantMap TestSquishUtils::readSuiteConf(QString suiteConfPath) +{ + const QSettings suiteConf(suiteConfPath, QSettings::IniFormat); + QVariantMap result; + // TODO get all information - actually only the information needed now is fetched + result.insert(squishLanguageKey, suiteConf.value(squishLanguageKey)); + result.insert(squishTestCasesKey, suiteConf.value(squishTestCasesKey)); + return result; +} + +QString TestSquishUtils::extensionForLanguage(QString language) +{ + if (language == QLatin1String("Python")) + return QLatin1String(".py"); + else if (language == QLatin1String("Perl")) + return QLatin1String(".pl"); + else if (language == QLatin1String("JavaScript")) + return QLatin1String(".js"); + else if (language == QLatin1String("Ruby")) + return QLatin1String(".rb"); + else if (language == QLatin1String("Tcl")) + return QLatin1String(".tcl"); + else + return QString(); // better return an invalid extension? +} + +} // namespace Internal +} // namespace Autotest diff --git a/plugins/autotest/testsquishutils.h b/plugins/autotest/testsquishutils.h new file mode 100644 index 0000000000..6936f95837 --- /dev/null +++ b/plugins/autotest/testsquishutils.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at +** http://www.qt.io/contact-us +** +** This file is part of the Qt Creator Enterprise Auto Test Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#ifndef TESTSQUISHUTILS_H +#define TESTSQUISHUTILS_H + +#include <QString> +#include <QVariantMap> + +namespace Autotest { +namespace Internal { + +class TestSquishUtils +{ +public: + static QStringList validTestCases(QString baseDirectory); + static QVariantMap readSuiteConf(QString suiteConfPath); + static QString extensionForLanguage(QString language); + +private: + TestSquishUtils() {} +}; + +} // namespace Internal +} // namespace Autotest + +#endif // TESTSQUISHUTILS_H diff --git a/plugins/autotest/testtreeitem.cpp b/plugins/autotest/testtreeitem.cpp index 721c605473..4c430db177 100644 --- a/plugins/autotest/testtreeitem.cpp +++ b/plugins/autotest/testtreeitem.cpp @@ -35,6 +35,8 @@ TestTreeItem::TestTreeItem(const QString &name, const QString &filePath, Type ty break; case TEST_CLASS: case TEST_FUNCTION: + case SQUISH_SUITE: + case SQUISH_TESTCASE: m_checked = Qt::Checked; break; case TEST_DATAFUNCTION: @@ -144,12 +146,14 @@ bool TestTreeItem::modifyContent(const TestTreeItem *modified) void TestTreeItem::setChecked(const Qt::CheckState checkState) { switch (m_type) { - case TEST_FUNCTION: { + case TEST_FUNCTION: + case SQUISH_TESTCASE: { m_checked = (checkState == Qt::Unchecked ? Qt::Unchecked : Qt::Checked); m_parent->revalidateCheckState(); break; } - case TEST_CLASS: { + case TEST_CLASS: + case SQUISH_SUITE: { Qt::CheckState usedState = (checkState == Qt::Unchecked ? Qt::Unchecked : Qt::Checked); foreach (TestTreeItem *child, m_children) { child->setChecked(usedState); @@ -166,6 +170,8 @@ Qt::CheckState TestTreeItem::checked() const switch (m_type) { case TEST_CLASS: case TEST_FUNCTION: + case SQUISH_SUITE: + case SQUISH_TESTCASE: return m_checked; case TEST_DATAFUNCTION: case TEST_SPECIALFUNCTION: @@ -185,6 +191,29 @@ QList<QString> TestTreeItem::getChildNames() const return names; } +TestTreeItem::Type TestTreeItem::toTestType(int testType) +{ + switch (testType) { + case ROOT: + return ROOT; + case TEST_CLASS: + return TEST_CLASS; + case TEST_FUNCTION: + return TEST_FUNCTION; + case TEST_DATAFUNCTION: + return TEST_DATAFUNCTION; + case TEST_SPECIALFUNCTION: + return TEST_SPECIALFUNCTION; + case SQUISH_SUITE: + return SQUISH_SUITE; + case SQUISH_TESTCASE: + return SQUISH_TESTCASE; + default: + qWarning("This should not happen: Unknown test type %d", testType); + return ROOT; // should cause the least trouble + } +} + void TestTreeItem::revalidateCheckState() { if (m_children.size() == 0) diff --git a/plugins/autotest/testtreeitem.h b/plugins/autotest/testtreeitem.h index 0cfa1aead1..825e53f0ca 100644 --- a/plugins/autotest/testtreeitem.h +++ b/plugins/autotest/testtreeitem.h @@ -36,7 +36,9 @@ public: TEST_CLASS, TEST_FUNCTION, TEST_DATAFUNCTION, - TEST_SPECIALFUNCTION + TEST_SPECIALFUNCTION, + SQUISH_SUITE, + SQUISH_TESTCASE }; TestTreeItem(const QString &name = QString(), const QString &filePath = QString(), @@ -69,6 +71,8 @@ public: void setParent(TestTreeItem *parent) { m_parent = parent; } QList<QString> getChildNames() const; + static Type toTestType(int testType); + private: void revalidateCheckState(); diff --git a/plugins/autotest/testtreeitemdelegate.cpp b/plugins/autotest/testtreeitemdelegate.cpp index 1e5952c7a0..6b58e3adc2 100644 --- a/plugins/autotest/testtreeitemdelegate.cpp +++ b/plugins/autotest/testtreeitemdelegate.cpp @@ -63,6 +63,9 @@ void TestTreeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & } } + if (index.flags() == Qt::NoItemFlags) + opt.palette.setColor(QPalette::Text, opt.palette.color(QPalette::Active, QPalette::Text)); + QStyledItemDelegate::paint(painter, opt, index); } diff --git a/plugins/autotest/testtreemodel.cpp b/plugins/autotest/testtreemodel.cpp index 134a9dc214..1e40493c02 100644 --- a/plugins/autotest/testtreemodel.cpp +++ b/plugins/autotest/testtreemodel.cpp @@ -19,9 +19,12 @@ #include "autotestconstants.h" #include "testcodeparser.h" +#include "testsquishfilehandler.h" #include "testtreeitem.h" #include "testtreemodel.h" +#include <coreplugin/coreconstants.h> // remove if placeholder icon is removed as well + #include <cpptools/cppmodelmanager.h> #include <projectexplorer/buildtargetinfo.h> @@ -50,11 +53,14 @@ TestTreeModel::TestTreeModel(QObject *parent) : m_rootItem(new TestTreeItem(QString(), QString(), TestTreeItem::ROOT)), m_autoTestRootItem(new TestTreeItem(tr("Auto Tests"), QString(), TestTreeItem::ROOT, m_rootItem)), m_quickTestRootItem(new TestTreeItem(tr("Qt Quick Tests"), QString(), TestTreeItem::ROOT, m_rootItem)), + m_squishTestRootItem(new TestTreeItem(tr("Squish Tests"), QString(), TestTreeItem::ROOT, m_rootItem)), m_parser(new TestCodeParser(this)), + m_squishFileHandler(new TestSquishFileHandler(this)), m_connectionsInitialized(false) { m_rootItem->appendChild(m_autoTestRootItem); m_rootItem->appendChild(m_quickTestRootItem); + m_rootItem->appendChild(m_squishTestRootItem); connect(m_parser, &TestCodeParser::cacheCleared, this, &TestTreeModel::removeAllTestItems, Qt::QueuedConnection); @@ -71,6 +77,13 @@ TestTreeModel::TestTreeModel(QObject *parent) : connect(m_parser, &TestCodeParser::unnamedQuickTestsRemoved, this, &TestTreeModel::removeUnnamedQuickTests, Qt::QueuedConnection); + connect(m_squishFileHandler, &TestSquishFileHandler::testTreeItemCreated, + this, &TestTreeModel::addTestTreeItem, Qt::QueuedConnection); + connect(m_squishFileHandler, &TestSquishFileHandler::testTreeItemModified, + this, &TestTreeModel::modifyTestTreeItem, Qt::QueuedConnection); + connect(m_squishFileHandler, &TestSquishFileHandler::testTreeItemsRemoved, + this, &TestTreeModel::removeTestTreeItems, Qt::QueuedConnection); + // CppTools::CppModelManagerInterface *cppMM = CppTools::CppModelManagerInterface::instance(); // if (cppMM) { // // replace later on by @@ -178,18 +191,26 @@ int TestTreeModel::rowCount(const QModelIndex &parent) const int TestTreeModel::columnCount(const QModelIndex &) const { - return 1; + return 3; } static QIcon testTreeIcon(TestTreeItem::Type type) { - static QIcon icons[3] = { + static QIcon icons[5] = { QIcon(), QIcon(QLatin1String(":/images/class.png")), - QIcon(QLatin1String(":/images/func.png")) + QIcon(QLatin1String(":/images/func.png")), + // TODO these icons are actually only placeholder + QIcon(QLatin1String(Core::Constants::ICON_DIR)), + QIcon(QLatin1String(":/fancyactionbar/images/mode_Edit.png")) }; - if (type >= 3) + if (type >= 3) { + if (type == TestTreeItem::SQUISH_SUITE) + return icons[3]; + if (type == TestTreeItem::SQUISH_TESTCASE) + return icons[4]; return icons[2]; + } return icons[type]; } @@ -202,9 +223,39 @@ QVariant TestTreeModel::data(const QModelIndex &index, int role) const if (!item) return QVariant(); + if (index.column() != 0) { + TestTreeItem::Type type = item->type(); + switch (role) { + case Qt::DecorationRole: + if (type == TestTreeItem::SQUISH_SUITE) + return index.column() == 1 ? QIcon(QLatin1String(":/images/play.png")) + : QIcon(QLatin1String(":/images/objectsmap.png")); + else if (type == TestTreeItem::SQUISH_TESTCASE) + return index.column() == 1 ? QIcon(QLatin1String(":/images/play.png")) + : QIcon(QLatin1String(":/images/record.png")); + case TypeRole: + return item->type(); + case Qt::DisplayRole: + if (type == TestTreeItem::SQUISH_SUITE || type == TestTreeItem::SQUISH_TESTCASE) + return item->name(); + case Qt::ToolTipRole: + if (type == TestTreeItem::SQUISH_SUITE || type == TestTreeItem::SQUISH_TESTCASE) { + if (index.column() == 1) + return tr("Run %1").arg(item->name()); + else + return type == TestTreeItem::SQUISH_SUITE ? tr("Open objects.map") + : tr("Record %1").arg(item->name()); + } + default: + return QVariant(); + } + return QVariant(); + } + if (role == Qt::DisplayRole) { if ((item == m_autoTestRootItem && m_autoTestRootItem->childCount() == 0) - || (item == m_quickTestRootItem && m_quickTestRootItem->childCount() == 0)) { + || (item == m_quickTestRootItem && m_quickTestRootItem->childCount() == 0) + || (item == m_squishTestRootItem && m_squishTestRootItem->childCount() == 0)) { return QString(item->name() + tr(" (none)")); } else { if (item->name().isEmpty()) @@ -238,6 +289,8 @@ QVariant TestTreeModel::data(const QModelIndex &index, int role) const return parent->name().isEmpty() ? QVariant() : item->checked(); else return item->checked(); + case TestTreeItem::SQUISH_SUITE: + case TestTreeItem::SQUISH_TESTCASE: default: return item->checked(); } @@ -262,6 +315,8 @@ QVariant TestTreeModel::data(const QModelIndex &index, int role) const default: return false; } + case TypeRole: + return item->type(); } // TODO ? @@ -280,12 +335,14 @@ bool TestTreeModel::setData(const QModelIndex &index, const QVariant &value, int if (item->checked() != old) { switch(item->type()) { case TestTreeItem::TEST_CLASS: + case TestTreeItem::SQUISH_SUITE: emit dataChanged(index, index); if (item->childCount() > 0) { emit dataChanged(index.child(0, 0), index.child(item->childCount() - 1, 0)); } break; case TestTreeItem::TEST_FUNCTION: + case TestTreeItem::SQUISH_TESTCASE: emit dataChanged(index, index); emit dataChanged(index.parent(), index.parent()); break; @@ -304,17 +361,25 @@ Qt::ItemFlags TestTreeModel::flags(const QModelIndex &index) const return Qt::ItemIsEnabled | Qt::ItemIsSelectable; TestTreeItem *item = static_cast<TestTreeItem *>(index.internalPointer()); - switch(item->type()) { + TestTreeItem::Type type = item->type(); + if (index.column() != 0 && type != TestTreeItem::SQUISH_SUITE + && type != TestTreeItem::SQUISH_TESTCASE) + return type == TestTreeItem::ROOT ? Qt::NoItemFlags + : Qt::ItemIsEnabled | Qt::ItemIsSelectable; + + switch (type) { case TestTreeItem::TEST_CLASS: + case TestTreeItem::SQUISH_SUITE: if (item->name().isEmpty()) return Qt::ItemIsEnabled | Qt::ItemIsSelectable; return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsTristate | Qt::ItemIsUserCheckable; case TestTreeItem::TEST_FUNCTION: + case TestTreeItem::SQUISH_TESTCASE: if (item->parent()->name().isEmpty()) return Qt::ItemIsEnabled | Qt::ItemIsSelectable; return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; case TestTreeItem::ROOT: - return Qt::ItemIsEnabled; + return Qt::NoItemFlags; case TestTreeItem::TEST_DATAFUNCTION: case TestTreeItem::TEST_SPECIALFUNCTION: default: @@ -781,6 +846,8 @@ TestTreeItem *TestTreeModel::rootItemForType(TestTreeModel::Type type) return m_autoTestRootItem; case QuickTest: return m_quickTestRootItem; + case SquishTest: + return m_squishTestRootItem; } QTC_ASSERT(false, return 0); } @@ -792,6 +859,8 @@ QModelIndex TestTreeModel::rootIndexForType(TestTreeModel::Type type) return index(0, 0); case QuickTest: return index(1, 0); + case SquishTest: + return index(2, 0); } QTC_ASSERT(false, return QModelIndex()); } diff --git a/plugins/autotest/testtreemodel.h b/plugins/autotest/testtreemodel.h index 15a00ecb38..8fa854f443 100644 --- a/plugins/autotest/testtreemodel.h +++ b/plugins/autotest/testtreemodel.h @@ -31,7 +31,8 @@ namespace { enum ItemRole { // AnnotationRole = Qt::UserRole + 1, LinkRole = Qt::UserRole + 2, // can be removed if AnnotationRole comes back - ItalicRole // used only inside the delegate + ItalicRole, // used only inside the delegate + TypeRole }; } @@ -41,6 +42,7 @@ namespace Internal { struct TestCodeLocationAndType; class TestCodeParser; class TestInfo; +class TestSquishFileHandler; class TestTreeItem; class TestTreeModel : public QAbstractItemModel @@ -49,7 +51,8 @@ class TestTreeModel : public QAbstractItemModel public: enum Type { AutoTest, - QuickTest + QuickTest, + SquishTest }; static TestTreeModel* instance(); @@ -110,7 +113,9 @@ private: TestTreeItem *m_rootItem; TestTreeItem *m_autoTestRootItem; TestTreeItem *m_quickTestRootItem; + TestTreeItem *m_squishTestRootItem; TestCodeParser *m_parser; + TestSquishFileHandler *m_squishFileHandler; bool m_connectionsInitialized; QAtomicInt m_refCounter; }; diff --git a/plugins/autotest/testtreeview.cpp b/plugins/autotest/testtreeview.cpp index 5675e9266f..62630efe26 100644 --- a/plugins/autotest/testtreeview.cpp +++ b/plugins/autotest/testtreeview.cpp @@ -97,5 +97,51 @@ void TestTreeView::changeCheckStateAll(const Qt::CheckState checkState) } } +void TestTreeView::resizeEvent(QResizeEvent *event) +{ + // override derived behavior of Utils::NavigationTreeView as we might have more than 1 column + TreeView::resizeEvent(event); +} + +void TestTreeView::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + QModelIndex index = indexAt(event->pos()); + if (index.isValid() && index.column() != 0) { + auto type = TestTreeItem::toTestType(index.data(TypeRole).toInt()); + if (index.column() > 2) + qWarning() << "Unexpected column:" << index.column(); + else if (type == TestTreeItem::SQUISH_SUITE || type == TestTreeItem::SQUISH_TESTCASE) + m_lastMousePressedIndex = index; + } + } + QTreeView::mousePressEvent(event); +} + +void TestTreeView::mouseReleaseEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + QModelIndex index = indexAt(event->pos()); + if (index.isValid() && m_lastMousePressedIndex == index) { + auto type = TestTreeItem::toTestType(index.data(TypeRole).toInt()); + if (type == TestTreeItem::SQUISH_SUITE) { + if (index.column() == 1) + emit runTestSuite(index.data().toString()); + else if (index.column() == 2) + emit openObjectsMap(index.data().toString()); + } else { + const QModelIndex &parent = index.parent(); + if (parent.isValid()) { + if (index.column() == 1) + emit runTestCase(parent.data().toString(), index.data().toString()); + else if (index.column() == 2) + emit recordTestCase(parent.data().toString(), index.data().toString()); + } + } + } + } + QTreeView::mouseReleaseEvent(event); +} + } // namespace Internal } // namespace Autotest diff --git a/plugins/autotest/testtreeview.h b/plugins/autotest/testtreeview.h index c9a4d9f9ff..cb6fc714e0 100644 --- a/plugins/autotest/testtreeview.h +++ b/plugins/autotest/testtreeview.h @@ -22,6 +22,8 @@ #include <utils/navigationtreeview.h> +#include <QModelIndex> + namespace Core { class IContext; } @@ -38,10 +40,20 @@ public: void selectAll(); void deselectAll(); + void resizeEvent(QResizeEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + +signals: + void runTestSuite(const QString &suiteName); + void runTestCase(const QString &suiteName, const QString &testCaseName); + void openObjectsMap(const QString &suiteName); + void recordTestCase(const QString &suiteName, const QString &testCaseName); private: void changeCheckStateAll(const Qt::CheckState checkState); Core::IContext *m_context; + QModelIndex m_lastMousePressedIndex; }; } // namespace Internal |