2014-10-07 15:51:02 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-22 10:37:55 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2014-10-07 15:51:02 +02:00
|
|
|
**
|
2016-01-22 10:37:55 +01:00
|
|
|
** This file is part of Qt Creator.
|
2014-10-07 15:51:02 +02:00
|
|
|
**
|
2016-01-22 10:37:55 +01:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
2014-10-07 15:51:02 +02:00
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-22 10:37:55 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2014-10-07 15:51:02 +02:00
|
|
|
**
|
2016-01-22 10:37:55 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2014-10-07 15:51:02 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2014-12-04 14:05:19 +01:00
|
|
|
#include "autotestplugin.h"
|
2015-11-24 15:46:51 +01:00
|
|
|
#include "autotesticons.h"
|
2014-10-07 15:51:02 +02:00
|
|
|
#include "testresultspane.h"
|
|
|
|
|
#include "testresultmodel.h"
|
|
|
|
|
#include "testresultdelegate.h"
|
|
|
|
|
#include "testrunner.h"
|
2014-12-04 14:05:19 +01:00
|
|
|
#include "testsettings.h"
|
2014-10-07 15:51:02 +02:00
|
|
|
#include "testtreemodel.h"
|
2016-03-14 15:36:03 +01:00
|
|
|
#include "testcodeparser.h"
|
2014-10-07 15:51:02 +02:00
|
|
|
|
2017-05-05 13:01:06 +02:00
|
|
|
#include <aggregation/aggregate.h>
|
2017-06-15 10:43:44 +02:00
|
|
|
#include <coreplugin/actionmanager/actionmanager.h>
|
2014-10-21 13:10:37 +02:00
|
|
|
#include <coreplugin/coreconstants.h>
|
2015-02-26 16:50:39 +01:00
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2017-05-05 13:01:06 +02:00
|
|
|
#include <coreplugin/find/basetextfind.h>
|
2016-02-29 09:56:30 +01:00
|
|
|
#include <coreplugin/find/itemviewfind.h>
|
2014-10-07 15:51:02 +02:00
|
|
|
#include <coreplugin/icontext.h>
|
2015-08-19 13:19:28 +02:00
|
|
|
#include <coreplugin/icore.h>
|
2017-06-15 10:43:44 +02:00
|
|
|
#include <projectexplorer/buildmanager.h>
|
2016-03-10 13:10:35 +01:00
|
|
|
#include <projectexplorer/projectexplorer.h>
|
2014-10-07 15:51:02 +02:00
|
|
|
#include <texteditor/texteditor.h>
|
2014-11-05 15:27:49 +01:00
|
|
|
#include <utils/theme/theme.h>
|
2016-08-03 17:55:54 +02:00
|
|
|
#include <utils/utilsicons.h>
|
2014-10-07 15:51:02 +02:00
|
|
|
|
2015-08-19 13:19:28 +02:00
|
|
|
#include <QApplication>
|
|
|
|
|
#include <QClipboard>
|
2014-10-21 13:10:37 +02:00
|
|
|
#include <QDebug>
|
2015-08-19 13:19:28 +02:00
|
|
|
#include <QFileDialog>
|
2014-11-05 15:27:49 +01:00
|
|
|
#include <QHBoxLayout>
|
2015-02-26 16:50:39 +01:00
|
|
|
#include <QMenu>
|
2015-08-19 13:19:28 +02:00
|
|
|
#include <QMessageBox>
|
2015-04-16 08:54:41 +02:00
|
|
|
#include <QScrollBar>
|
2017-05-05 13:01:06 +02:00
|
|
|
#include <QStackedWidget>
|
2014-10-07 15:51:02 +02:00
|
|
|
#include <QToolButton>
|
2014-11-05 15:27:49 +01:00
|
|
|
#include <QVBoxLayout>
|
2014-10-07 15:51:02 +02:00
|
|
|
|
|
|
|
|
namespace Autotest {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2015-08-19 13:19:28 +02:00
|
|
|
ResultsTreeView::ResultsTreeView(QWidget *parent)
|
|
|
|
|
: Utils::TreeView(parent)
|
2016-01-19 11:58:47 +01:00
|
|
|
{
|
|
|
|
|
setAttribute(Qt::WA_MacShowFocusRect, false);
|
|
|
|
|
}
|
2015-08-19 13:19:28 +02:00
|
|
|
|
|
|
|
|
void ResultsTreeView::keyPressEvent(QKeyEvent *event)
|
|
|
|
|
{
|
|
|
|
|
if (event->matches(QKeySequence::Copy)) {
|
|
|
|
|
emit copyShortcutTriggered();
|
|
|
|
|
event->accept();
|
|
|
|
|
}
|
2015-10-01 09:10:49 +02:00
|
|
|
TreeView::keyPressEvent(event);
|
2015-08-19 13:19:28 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-07 15:51:02 +02:00
|
|
|
TestResultsPane::TestResultsPane(QObject *parent) :
|
|
|
|
|
Core::IOutputPane(parent),
|
2016-09-29 12:15:43 +02:00
|
|
|
m_context(new Core::IContext(this))
|
2014-10-07 15:51:02 +02:00
|
|
|
{
|
2017-05-05 13:01:06 +02:00
|
|
|
m_outputWidget = new QStackedWidget;
|
|
|
|
|
QWidget *visualOutputWidget = new QWidget;
|
|
|
|
|
m_outputWidget->addWidget(visualOutputWidget);
|
2014-11-05 15:27:49 +01:00
|
|
|
QVBoxLayout *outputLayout = new QVBoxLayout;
|
|
|
|
|
outputLayout->setMargin(0);
|
|
|
|
|
outputLayout->setSpacing(0);
|
2017-05-05 13:01:06 +02:00
|
|
|
visualOutputWidget->setLayout(outputLayout);
|
2014-11-05 15:27:49 +01:00
|
|
|
|
|
|
|
|
QPalette pal;
|
|
|
|
|
pal.setColor(QPalette::Window,
|
2014-11-13 12:31:58 +01:00
|
|
|
Utils::creatorTheme()->color(Utils::Theme::InfoBarBackground));
|
2014-11-05 15:27:49 +01:00
|
|
|
pal.setColor(QPalette::WindowText,
|
2014-11-13 12:31:58 +01:00
|
|
|
Utils::creatorTheme()->color(Utils::Theme::InfoBarText));
|
2014-11-05 15:27:49 +01:00
|
|
|
m_summaryWidget = new QFrame;
|
|
|
|
|
m_summaryWidget->setPalette(pal);
|
|
|
|
|
m_summaryWidget->setAutoFillBackground(true);
|
|
|
|
|
QHBoxLayout *layout = new QHBoxLayout;
|
|
|
|
|
layout->setMargin(6);
|
|
|
|
|
m_summaryWidget->setLayout(layout);
|
|
|
|
|
m_summaryLabel = new QLabel;
|
|
|
|
|
m_summaryLabel->setPalette(pal);
|
|
|
|
|
layout->addWidget(m_summaryLabel);
|
|
|
|
|
m_summaryWidget->setVisible(false);
|
|
|
|
|
|
|
|
|
|
outputLayout->addWidget(m_summaryWidget);
|
|
|
|
|
|
2017-05-05 13:01:06 +02:00
|
|
|
m_treeView = new ResultsTreeView(visualOutputWidget);
|
2015-04-21 07:41:06 +02:00
|
|
|
m_treeView->setHeaderHidden(true);
|
|
|
|
|
m_treeView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
2015-08-19 13:19:28 +02:00
|
|
|
m_treeView->setContextMenuPolicy(Qt::CustomContextMenu);
|
2017-02-06 12:02:24 +01:00
|
|
|
pal = m_treeView->palette();
|
|
|
|
|
pal.setColor(QPalette::Base, pal.window().color());
|
|
|
|
|
m_treeView->setPalette(pal);
|
2014-10-07 15:51:02 +02:00
|
|
|
m_model = new TestResultModel(this);
|
2014-10-21 13:10:37 +02:00
|
|
|
m_filterModel = new TestResultFilterModel(m_model, this);
|
|
|
|
|
m_filterModel->setDynamicSortFilter(true);
|
2015-04-21 07:41:06 +02:00
|
|
|
m_treeView->setModel(m_filterModel);
|
2014-10-07 15:51:02 +02:00
|
|
|
TestResultDelegate *trd = new TestResultDelegate(this);
|
2015-04-21 07:41:06 +02:00
|
|
|
m_treeView->setItemDelegate(trd);
|
2014-10-07 15:51:02 +02:00
|
|
|
|
2016-02-29 09:56:30 +01:00
|
|
|
outputLayout->addWidget(Core::ItemViewFind::createSearchableWrapper(m_treeView));
|
2014-11-05 15:27:49 +01:00
|
|
|
|
2017-05-05 13:01:06 +02:00
|
|
|
m_textOutput = new QPlainTextEdit;
|
|
|
|
|
m_textOutput->setPalette(pal);
|
|
|
|
|
QFont font("monospace");
|
|
|
|
|
font.setStyleHint(QFont::TypeWriter);
|
|
|
|
|
m_textOutput->setFont(font);
|
|
|
|
|
m_textOutput->setWordWrapMode(QTextOption::WordWrap);
|
|
|
|
|
m_textOutput->setReadOnly(true);
|
|
|
|
|
m_outputWidget->addWidget(m_textOutput);
|
|
|
|
|
|
|
|
|
|
auto agg = new Aggregation::Aggregate;
|
|
|
|
|
agg->add(m_textOutput);
|
|
|
|
|
agg->add(new Core::BaseTextFind(m_textOutput));
|
|
|
|
|
|
2014-10-07 15:51:02 +02:00
|
|
|
createToolButtons();
|
|
|
|
|
|
2015-04-21 07:41:06 +02:00
|
|
|
connect(m_treeView, &Utils::TreeView::activated, this, &TestResultsPane::onItemActivated);
|
|
|
|
|
connect(m_treeView->selectionModel(), &QItemSelectionModel::currentChanged,
|
2014-10-07 15:51:02 +02:00
|
|
|
trd, &TestResultDelegate::currentChanged);
|
2015-08-19 13:19:28 +02:00
|
|
|
connect(m_treeView, &Utils::TreeView::customContextMenuRequested,
|
|
|
|
|
this, &TestResultsPane::onCustomContextMenuRequested);
|
|
|
|
|
connect(m_treeView, &ResultsTreeView::copyShortcutTriggered, [this] () {
|
2017-09-09 16:46:43 +02:00
|
|
|
onCopyItemTriggered(getTestResult(m_treeView->currentIndex()));
|
2015-08-19 13:19:28 +02:00
|
|
|
});
|
2015-08-20 15:59:15 +02:00
|
|
|
connect(m_model, &TestResultModel::requestExpansion, [this] (QModelIndex idx) {
|
|
|
|
|
m_treeView->expand(m_filterModel->mapFromSource(idx));
|
|
|
|
|
});
|
2014-11-03 08:30:22 +01:00
|
|
|
connect(TestRunner::instance(), &TestRunner::testRunStarted,
|
|
|
|
|
this, &TestResultsPane::onTestRunStarted);
|
|
|
|
|
connect(TestRunner::instance(), &TestRunner::testRunFinished,
|
|
|
|
|
this, &TestResultsPane::onTestRunFinished);
|
2016-01-19 14:24:09 +01:00
|
|
|
connect(TestRunner::instance(), &TestRunner::testResultReady,
|
|
|
|
|
this, &TestResultsPane::addTestResult);
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultsPane::createToolButtons()
|
|
|
|
|
{
|
2015-08-20 15:59:15 +02:00
|
|
|
m_expandCollapse = new QToolButton(m_treeView);
|
2016-08-03 17:55:54 +02:00
|
|
|
m_expandCollapse->setIcon(Utils::Icons::EXPAND_ALL_TOOLBAR.icon());
|
2015-08-20 15:59:15 +02:00
|
|
|
m_expandCollapse->setToolTip(tr("Expand All"));
|
|
|
|
|
m_expandCollapse->setCheckable(true);
|
|
|
|
|
m_expandCollapse->setChecked(false);
|
|
|
|
|
connect(m_expandCollapse, &QToolButton::clicked, [this] (bool checked) {
|
|
|
|
|
if (checked)
|
|
|
|
|
m_treeView->expandAll();
|
|
|
|
|
else
|
|
|
|
|
m_treeView->collapseAll();
|
|
|
|
|
});
|
|
|
|
|
|
2015-04-21 07:41:06 +02:00
|
|
|
m_runAll = new QToolButton(m_treeView);
|
2017-12-04 10:11:19 +01:00
|
|
|
m_runAll->setDefaultAction(Core::ActionManager::command(Constants::ACTION_RUN_ALL_ID)->action());
|
2014-10-07 15:51:02 +02:00
|
|
|
|
2015-04-21 07:41:06 +02:00
|
|
|
m_runSelected = new QToolButton(m_treeView);
|
2017-12-04 10:11:19 +01:00
|
|
|
m_runSelected->setDefaultAction(Core::ActionManager::command(Constants::ACTION_RUN_SELECTED_ID)->action());
|
2014-10-21 13:10:37 +02:00
|
|
|
|
2015-04-21 07:41:06 +02:00
|
|
|
m_stopTestRun = new QToolButton(m_treeView);
|
2016-08-03 17:55:54 +02:00
|
|
|
m_stopTestRun->setIcon(Utils::Icons::STOP_SMALL_TOOLBAR.icon());
|
2014-11-03 08:30:22 +01:00
|
|
|
m_stopTestRun->setToolTip(tr("Stop Test Run"));
|
|
|
|
|
m_stopTestRun->setEnabled(false);
|
2015-01-13 11:24:41 +01:00
|
|
|
connect(m_stopTestRun, &QToolButton::clicked, TestRunner::instance(), &TestRunner::requestStopTestRun);
|
2014-11-03 08:30:22 +01:00
|
|
|
|
2015-04-21 07:41:06 +02:00
|
|
|
m_filterButton = new QToolButton(m_treeView);
|
2016-08-03 17:55:54 +02:00
|
|
|
m_filterButton->setIcon(Utils::Icons::FILTER.icon());
|
2014-10-21 13:10:37 +02:00
|
|
|
m_filterButton->setToolTip(tr("Filter Test Results"));
|
|
|
|
|
m_filterButton->setProperty("noArrow", true);
|
|
|
|
|
m_filterButton->setAutoRaise(true);
|
|
|
|
|
m_filterButton->setPopupMode(QToolButton::InstantPopup);
|
|
|
|
|
m_filterMenu = new QMenu(m_filterButton);
|
|
|
|
|
initializeFilterMenu();
|
|
|
|
|
connect(m_filterMenu, &QMenu::triggered, this, &TestResultsPane::filterMenuTriggered);
|
|
|
|
|
m_filterButton->setMenu(m_filterMenu);
|
2017-05-05 13:01:06 +02:00
|
|
|
m_outputToggleButton = new QToolButton(m_treeView);
|
|
|
|
|
m_outputToggleButton->setIcon(Icons::TEXT_DISPLAY.icon());
|
|
|
|
|
m_outputToggleButton->setToolTip(tr("Switch Between Visual and Text Display"));
|
|
|
|
|
m_outputToggleButton->setEnabled(true);
|
|
|
|
|
connect(m_outputToggleButton, &QToolButton::clicked, this, &TestResultsPane::toggleOutputStyle);
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
2017-02-13 10:05:06 +01:00
|
|
|
static TestResultsPane *s_instance = nullptr;
|
2014-10-07 15:51:02 +02:00
|
|
|
|
|
|
|
|
TestResultsPane *TestResultsPane::instance()
|
|
|
|
|
{
|
2017-02-13 10:05:06 +01:00
|
|
|
if (!s_instance)
|
|
|
|
|
s_instance = new TestResultsPane;
|
|
|
|
|
return s_instance;
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestResultsPane::~TestResultsPane()
|
|
|
|
|
{
|
2015-04-21 07:41:06 +02:00
|
|
|
delete m_treeView;
|
2017-05-05 13:01:06 +02:00
|
|
|
if (!m_outputWidget->parent())
|
|
|
|
|
delete m_outputWidget;
|
2017-02-13 10:05:06 +01:00
|
|
|
s_instance = nullptr;
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
2016-02-25 13:02:31 +01:00
|
|
|
void TestResultsPane::addTestResult(const TestResultPtr &result)
|
2014-10-07 15:51:02 +02:00
|
|
|
{
|
2015-04-16 08:54:41 +02:00
|
|
|
const QScrollBar *scrollBar = m_treeView->verticalScrollBar();
|
|
|
|
|
m_atEnd = scrollBar ? scrollBar->value() == scrollBar->maximum() : true;
|
|
|
|
|
|
2015-08-20 15:59:15 +02:00
|
|
|
m_model->addTestResult(result, m_expandCollapse->isChecked());
|
2016-03-04 11:57:24 +01:00
|
|
|
setIconBadgeNumber(m_model->resultTypeCount(Result::Fail)
|
|
|
|
|
+ m_model->resultTypeCount(Result::UnexpectedPass));
|
2014-10-07 15:51:02 +02:00
|
|
|
flash();
|
|
|
|
|
navigateStateChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-05 13:01:06 +02:00
|
|
|
void TestResultsPane::addOutput(const QByteArray &output)
|
|
|
|
|
{
|
|
|
|
|
m_textOutput->appendPlainText(QString::fromLatin1(output));
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-07 15:51:02 +02:00
|
|
|
QWidget *TestResultsPane::outputWidget(QWidget *parent)
|
|
|
|
|
{
|
2014-11-05 15:27:49 +01:00
|
|
|
if (m_outputWidget) {
|
|
|
|
|
m_outputWidget->setParent(parent);
|
2014-10-07 15:51:02 +02:00
|
|
|
} else {
|
2014-11-05 15:27:49 +01:00
|
|
|
qDebug() << "This should not happen...";
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
2014-11-05 15:27:49 +01:00
|
|
|
return m_outputWidget;
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<QWidget *> TestResultsPane::toolBarWidgets() const
|
|
|
|
|
{
|
2017-05-05 13:01:06 +02:00
|
|
|
return {m_expandCollapse, m_runAll, m_runSelected, m_stopTestRun, m_outputToggleButton,
|
|
|
|
|
m_filterButton};
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString TestResultsPane::displayName() const
|
|
|
|
|
{
|
|
|
|
|
return tr("Test Results");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int TestResultsPane::priorityInStatusBar() const
|
|
|
|
|
{
|
|
|
|
|
return -666;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultsPane::clearContents()
|
|
|
|
|
{
|
2014-10-21 13:10:37 +02:00
|
|
|
m_filterModel->clearTestResults();
|
2017-10-12 14:56:21 +02:00
|
|
|
if (auto delegate = qobject_cast<TestResultDelegate *>(m_treeView->itemDelegate()))
|
|
|
|
|
delegate->clearCache();
|
2016-03-04 11:57:24 +01:00
|
|
|
setIconBadgeNumber(0);
|
2014-10-07 15:51:02 +02:00
|
|
|
navigateStateChanged();
|
2014-11-05 15:27:49 +01:00
|
|
|
m_summaryWidget->setVisible(false);
|
2015-04-16 08:54:41 +02:00
|
|
|
m_autoScroll = AutotestPlugin::instance()->settings()->autoScroll;
|
|
|
|
|
connect(m_treeView->verticalScrollBar(), &QScrollBar::rangeChanged,
|
|
|
|
|
this, &TestResultsPane::onScrollBarRangeChanged, Qt::UniqueConnection);
|
2017-05-05 13:01:06 +02:00
|
|
|
m_textOutput->clear();
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
2017-12-04 10:11:19 +01:00
|
|
|
void TestResultsPane::visibilityChanged(bool /*visible*/)
|
2014-10-07 15:51:02 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultsPane::setFocus()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestResultsPane::hasFocus() const
|
|
|
|
|
{
|
2015-04-21 07:41:06 +02:00
|
|
|
return m_treeView->hasFocus();
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestResultsPane::canFocus() const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestResultsPane::canNavigate() const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestResultsPane::canNext() const
|
|
|
|
|
{
|
2014-10-21 13:10:37 +02:00
|
|
|
return m_filterModel->hasResults();
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestResultsPane::canPrevious() const
|
|
|
|
|
{
|
2014-10-21 13:10:37 +02:00
|
|
|
return m_filterModel->hasResults();
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultsPane::goToNext()
|
|
|
|
|
{
|
|
|
|
|
if (!canNext())
|
|
|
|
|
return;
|
|
|
|
|
|
2015-08-20 15:59:15 +02:00
|
|
|
const QModelIndex currentIndex = m_treeView->currentIndex();
|
|
|
|
|
QModelIndex nextCurrentIndex;
|
|
|
|
|
|
2014-10-07 15:51:02 +02:00
|
|
|
if (currentIndex.isValid()) {
|
2015-08-20 15:59:15 +02:00
|
|
|
// try to set next to first child or next sibling
|
|
|
|
|
if (m_filterModel->rowCount(currentIndex)) {
|
|
|
|
|
nextCurrentIndex = currentIndex.child(0, 0);
|
|
|
|
|
} else {
|
|
|
|
|
nextCurrentIndex = currentIndex.sibling(currentIndex.row() + 1, 0);
|
|
|
|
|
// if it had no sibling check siblings of parent (and grandparents if necessary)
|
|
|
|
|
if (!nextCurrentIndex.isValid()) {
|
|
|
|
|
|
|
|
|
|
QModelIndex parent = currentIndex.parent();
|
|
|
|
|
do {
|
|
|
|
|
if (!parent.isValid())
|
|
|
|
|
break;
|
|
|
|
|
nextCurrentIndex = parent.sibling(parent.row() + 1, 0);
|
|
|
|
|
parent = parent.parent();
|
|
|
|
|
} while (!nextCurrentIndex.isValid());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if we have no current or could not find a next one, use the first item of the whole tree
|
|
|
|
|
if (!nextCurrentIndex.isValid()) {
|
|
|
|
|
Utils::TreeItem *rootItem = m_model->itemForIndex(QModelIndex());
|
|
|
|
|
// if the tree does not contain any item - don't do anything
|
|
|
|
|
if (!rootItem || !rootItem->childCount())
|
|
|
|
|
return;
|
|
|
|
|
|
2016-07-06 13:38:00 +02:00
|
|
|
nextCurrentIndex = m_filterModel->mapFromSource(m_model->indexForItem(rootItem->childAt(0)));
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
2015-08-20 15:59:15 +02:00
|
|
|
|
|
|
|
|
m_treeView->setCurrentIndex(nextCurrentIndex);
|
|
|
|
|
onItemActivated(nextCurrentIndex);
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultsPane::goToPrev()
|
|
|
|
|
{
|
|
|
|
|
if (!canPrevious())
|
|
|
|
|
return;
|
|
|
|
|
|
2015-08-20 15:59:15 +02:00
|
|
|
const QModelIndex currentIndex = m_treeView->currentIndex();
|
|
|
|
|
QModelIndex nextCurrentIndex;
|
|
|
|
|
|
2014-10-07 15:51:02 +02:00
|
|
|
if (currentIndex.isValid()) {
|
2015-08-20 15:59:15 +02:00
|
|
|
// try to set next to prior sibling or parent
|
|
|
|
|
if (currentIndex.row() > 0) {
|
|
|
|
|
nextCurrentIndex = currentIndex.sibling(currentIndex.row() - 1, 0);
|
|
|
|
|
// if the sibling has children, use the last one
|
|
|
|
|
while (int rowCount = m_filterModel->rowCount(nextCurrentIndex))
|
|
|
|
|
nextCurrentIndex = nextCurrentIndex.child(rowCount - 1, 0);
|
|
|
|
|
} else {
|
|
|
|
|
nextCurrentIndex = currentIndex.parent();
|
|
|
|
|
}
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
2015-08-20 15:59:15 +02:00
|
|
|
|
|
|
|
|
// if we have no current or didn't find a sibling/parent use the last item of the whole tree
|
|
|
|
|
if (!nextCurrentIndex.isValid()) {
|
|
|
|
|
const QModelIndex rootIdx = m_filterModel->index(0, 0);
|
|
|
|
|
// if the tree does not contain any item - don't do anything
|
|
|
|
|
if (!rootIdx.isValid())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// get the last (visible) top level index
|
|
|
|
|
nextCurrentIndex = m_filterModel->index(m_filterModel->rowCount(QModelIndex()) - 1, 0);
|
|
|
|
|
// step through until end
|
|
|
|
|
while (int rowCount = m_filterModel->rowCount(nextCurrentIndex))
|
|
|
|
|
nextCurrentIndex = nextCurrentIndex.child(rowCount - 1, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_treeView->setCurrentIndex(nextCurrentIndex);
|
|
|
|
|
onItemActivated(nextCurrentIndex);
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultsPane::onItemActivated(const QModelIndex &index)
|
|
|
|
|
{
|
|
|
|
|
if (!index.isValid())
|
|
|
|
|
return;
|
|
|
|
|
|
2016-04-13 10:20:17 +02:00
|
|
|
const TestResult *testResult = m_filterModel->testResult(index);
|
|
|
|
|
if (testResult && !testResult->fileName().isEmpty())
|
|
|
|
|
Core::EditorManager::openEditorAt(testResult->fileName(), testResult->line(), 0);
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultsPane::onRunAllTriggered()
|
|
|
|
|
{
|
|
|
|
|
TestRunner *runner = TestRunner::instance();
|
|
|
|
|
runner->setSelectedTests(TestTreeModel::instance()->getAllTestCases());
|
2017-09-05 13:57:22 +02:00
|
|
|
runner->prepareToRunTests(TestRunMode::Run);
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultsPane::onRunSelectedTriggered()
|
|
|
|
|
{
|
|
|
|
|
TestRunner *runner = TestRunner::instance();
|
|
|
|
|
runner->setSelectedTests(TestTreeModel::instance()->getSelectedTests());
|
2017-09-05 13:57:22 +02:00
|
|
|
runner->prepareToRunTests(TestRunMode::Run);
|
2014-10-21 13:10:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultsPane::initializeFilterMenu()
|
|
|
|
|
{
|
2014-12-04 14:05:19 +01:00
|
|
|
const bool omitIntern = AutotestPlugin::instance()->settings()->omitInternalMssg;
|
|
|
|
|
// FilterModel has all messages enabled by default
|
|
|
|
|
if (omitIntern)
|
2015-12-07 08:26:54 +01:00
|
|
|
m_filterModel->toggleTestResultType(Result::MessageInternal);
|
2015-01-08 13:46:28 +01:00
|
|
|
|
|
|
|
|
QMap<Result::Type, QString> textAndType;
|
2015-12-07 08:26:54 +01:00
|
|
|
textAndType.insert(Result::Pass, tr("Pass"));
|
|
|
|
|
textAndType.insert(Result::Fail, tr("Fail"));
|
|
|
|
|
textAndType.insert(Result::ExpectedFail, tr("Expected Fail"));
|
|
|
|
|
textAndType.insert(Result::UnexpectedPass, tr("Unexpected Pass"));
|
|
|
|
|
textAndType.insert(Result::Skip, tr("Skip"));
|
|
|
|
|
textAndType.insert(Result::Benchmark, tr("Benchmarks"));
|
|
|
|
|
textAndType.insert(Result::MessageDebug, tr("Debug Messages"));
|
|
|
|
|
textAndType.insert(Result::MessageWarn, tr("Warning Messages"));
|
|
|
|
|
textAndType.insert(Result::MessageInternal, tr("Internal Messages"));
|
2017-02-13 10:05:06 +01:00
|
|
|
for (Result::Type result : textAndType.keys()) {
|
2014-10-21 13:10:37 +02:00
|
|
|
QAction *action = new QAction(m_filterMenu);
|
|
|
|
|
action->setText(textAndType.value(result));
|
|
|
|
|
action->setCheckable(true);
|
2015-12-07 08:26:54 +01:00
|
|
|
action->setChecked(result != Result::MessageInternal || !omitIntern);
|
2014-10-21 13:10:37 +02:00
|
|
|
action->setData(result);
|
|
|
|
|
m_filterMenu->addAction(action);
|
|
|
|
|
}
|
2014-11-05 15:40:37 +01:00
|
|
|
m_filterMenu->addSeparator();
|
|
|
|
|
QAction *action = new QAction(m_filterMenu);
|
|
|
|
|
action->setText(tr("Check All Filters"));
|
|
|
|
|
action->setCheckable(false);
|
|
|
|
|
m_filterMenu->addAction(action);
|
|
|
|
|
connect(action, &QAction::triggered, this, &TestResultsPane::enableAllFilter);
|
2014-10-21 13:10:37 +02:00
|
|
|
}
|
2014-10-07 15:51:02 +02:00
|
|
|
|
2014-11-05 15:27:49 +01:00
|
|
|
void TestResultsPane::updateSummaryLabel()
|
|
|
|
|
{
|
2016-09-29 12:15:43 +02:00
|
|
|
QString labelText = QString("<p>Test summary: %1 %2, %3 %4")
|
2015-12-07 08:26:54 +01:00
|
|
|
.arg(QString::number(m_model->resultTypeCount(Result::Pass)), tr("passes"),
|
|
|
|
|
QString::number(m_model->resultTypeCount(Result::Fail)), tr("fails"));
|
|
|
|
|
int count = m_model->resultTypeCount(Result::UnexpectedPass);
|
2014-11-05 15:27:49 +01:00
|
|
|
if (count)
|
2016-09-29 12:15:43 +02:00
|
|
|
labelText.append(QString(", %1 %2").arg(QString::number(count), tr("unexpected passes")));
|
2015-12-07 08:26:54 +01:00
|
|
|
count = m_model->resultTypeCount(Result::ExpectedFail);
|
2014-11-05 15:27:49 +01:00
|
|
|
if (count)
|
2016-09-29 12:15:43 +02:00
|
|
|
labelText.append(QString(", %1 %2").arg(QString::number(count), tr("expected fails")));
|
2015-12-07 08:26:54 +01:00
|
|
|
count = m_model->resultTypeCount(Result::MessageFatal);
|
2014-11-05 15:52:34 +01:00
|
|
|
if (count)
|
2016-09-29 12:15:43 +02:00
|
|
|
labelText.append(QString(", %1 %2").arg(QString::number(count), tr("fatals")));
|
2015-12-07 08:26:54 +01:00
|
|
|
count = m_model->resultTypeCount(Result::BlacklistedFail)
|
|
|
|
|
+ m_model->resultTypeCount(Result::BlacklistedPass);
|
2014-12-01 11:42:28 +01:00
|
|
|
if (count)
|
2016-09-29 12:15:43 +02:00
|
|
|
labelText.append(QString(", %1 %2").arg(QString::number(count), tr("blacklisted")));
|
2014-12-01 11:42:28 +01:00
|
|
|
|
2015-12-14 12:48:58 +01:00
|
|
|
count = m_model->disabledTests();
|
|
|
|
|
if (count)
|
|
|
|
|
labelText.append(tr(", %1 disabled").arg(count));
|
|
|
|
|
|
2016-09-29 12:15:43 +02:00
|
|
|
labelText.append(".</p>");
|
2014-11-05 15:27:49 +01:00
|
|
|
m_summaryLabel->setText(labelText);
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-05 15:40:37 +01:00
|
|
|
void TestResultsPane::enableAllFilter()
|
|
|
|
|
{
|
2017-02-13 10:05:06 +01:00
|
|
|
for (QAction *action : m_filterMenu->actions()) {
|
2014-11-05 15:40:37 +01:00
|
|
|
if (action->isCheckable())
|
|
|
|
|
action->setChecked(true);
|
|
|
|
|
}
|
|
|
|
|
m_filterModel->enableAllResultTypes();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-21 13:10:37 +02:00
|
|
|
void TestResultsPane::filterMenuTriggered(QAction *action)
|
|
|
|
|
{
|
2014-11-11 17:30:34 +01:00
|
|
|
m_filterModel->toggleTestResultType(TestResult::toResultType(action->data().value<int>()));
|
2014-10-21 13:10:37 +02:00
|
|
|
navigateStateChanged();
|
2014-10-07 15:51:02 +02:00
|
|
|
}
|
|
|
|
|
|
2014-11-03 08:30:22 +01:00
|
|
|
void TestResultsPane::onTestRunStarted()
|
|
|
|
|
{
|
2015-08-19 13:19:28 +02:00
|
|
|
m_testRunning = true;
|
2014-11-03 08:30:22 +01:00
|
|
|
m_stopTestRun->setEnabled(true);
|
2017-12-04 10:11:19 +01:00
|
|
|
AutotestPlugin::instance()->updateMenuItemsEnabledState();
|
2014-11-05 15:27:49 +01:00
|
|
|
m_summaryWidget->setVisible(false);
|
2014-11-03 08:30:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultsPane::onTestRunFinished()
|
|
|
|
|
{
|
2015-08-19 13:19:28 +02:00
|
|
|
m_testRunning = false;
|
2014-11-03 08:30:22 +01:00
|
|
|
m_stopTestRun->setEnabled(false);
|
2017-06-15 10:43:44 +02:00
|
|
|
|
2017-12-04 10:11:19 +01:00
|
|
|
AutotestPlugin::instance()->updateMenuItemsEnabledState();
|
2014-11-05 15:27:49 +01:00
|
|
|
updateSummaryLabel();
|
|
|
|
|
m_summaryWidget->setVisible(true);
|
2014-12-05 14:01:16 +01:00
|
|
|
m_model->removeCurrentTestMessage();
|
2015-04-16 08:54:41 +02:00
|
|
|
disconnect(m_treeView->verticalScrollBar(), &QScrollBar::rangeChanged,
|
|
|
|
|
this, &TestResultsPane::onScrollBarRangeChanged);
|
2016-10-24 09:17:27 +02:00
|
|
|
if (!m_treeView->isVisible())
|
|
|
|
|
popup(Core::IOutputPane::NoModeSwitch);
|
2015-04-16 08:54:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultsPane::onScrollBarRangeChanged(int, int max)
|
|
|
|
|
{
|
|
|
|
|
if (m_autoScroll && m_atEnd)
|
|
|
|
|
m_treeView->verticalScrollBar()->setValue(max);
|
2014-11-03 08:30:22 +01:00
|
|
|
}
|
|
|
|
|
|
2015-08-19 13:19:28 +02:00
|
|
|
void TestResultsPane::onCustomContextMenuRequested(const QPoint &pos)
|
|
|
|
|
{
|
|
|
|
|
const bool resultsAvailable = m_filterModel->hasResults();
|
|
|
|
|
const bool enabled = !m_testRunning && resultsAvailable;
|
2017-09-09 16:46:43 +02:00
|
|
|
const TestResult *clicked = getTestResult(m_treeView->indexAt(pos));
|
2015-08-19 13:19:28 +02:00
|
|
|
QMenu menu;
|
2017-09-09 16:46:43 +02:00
|
|
|
|
2015-08-19 13:19:28 +02:00
|
|
|
QAction *action = new QAction(tr("Copy"), &menu);
|
|
|
|
|
action->setShortcut(QKeySequence(QKeySequence::Copy));
|
2017-09-09 16:46:43 +02:00
|
|
|
action->setEnabled(resultsAvailable && clicked);
|
2015-08-19 13:19:28 +02:00
|
|
|
connect(action, &QAction::triggered, [this, clicked] () {
|
|
|
|
|
onCopyItemTriggered(clicked);
|
|
|
|
|
});
|
|
|
|
|
menu.addAction(action);
|
|
|
|
|
|
|
|
|
|
action = new QAction(tr("Copy All"), &menu);
|
|
|
|
|
action->setEnabled(enabled);
|
|
|
|
|
connect(action, &QAction::triggered, this, &TestResultsPane::onCopyWholeTriggered);
|
|
|
|
|
menu.addAction(action);
|
|
|
|
|
|
|
|
|
|
action = new QAction(tr("Save Output to File..."), &menu);
|
|
|
|
|
action->setEnabled(enabled);
|
|
|
|
|
connect(action, &QAction::triggered, this, &TestResultsPane::onSaveWholeTriggered);
|
|
|
|
|
menu.addAction(action);
|
|
|
|
|
|
2017-09-29 12:36:26 +02:00
|
|
|
const auto correlatingItem = clicked ? clicked->findTestTreeItem() : nullptr;
|
2017-09-09 16:46:43 +02:00
|
|
|
action = new QAction(tr("Run This Test"), &menu);
|
2017-09-29 12:36:26 +02:00
|
|
|
action->setEnabled(correlatingItem && correlatingItem->canProvideTestConfiguration());
|
2017-09-09 16:46:43 +02:00
|
|
|
connect(action, &QAction::triggered, this, [this, clicked] {
|
|
|
|
|
onRunThisTestTriggered(TestRunMode::Run, clicked);
|
|
|
|
|
});
|
|
|
|
|
menu.addAction(action);
|
|
|
|
|
|
|
|
|
|
action = new QAction(tr("Debug This Test"), &menu);
|
2017-09-29 12:36:26 +02:00
|
|
|
action->setEnabled(correlatingItem && correlatingItem->canProvideDebugConfiguration());
|
2017-09-09 16:46:43 +02:00
|
|
|
connect(action, &QAction::triggered, this, [this, clicked] {
|
|
|
|
|
onRunThisTestTriggered(TestRunMode::Debug, clicked);
|
|
|
|
|
});
|
|
|
|
|
menu.addAction(action);
|
|
|
|
|
|
2015-08-19 13:19:28 +02:00
|
|
|
menu.exec(m_treeView->mapToGlobal(pos));
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-09 16:46:43 +02:00
|
|
|
const TestResult *TestResultsPane::getTestResult(const QModelIndex &idx)
|
2015-08-19 13:19:28 +02:00
|
|
|
{
|
2016-12-14 15:29:24 +01:00
|
|
|
if (!idx.isValid())
|
2017-09-09 16:46:43 +02:00
|
|
|
return nullptr;
|
|
|
|
|
|
2016-04-13 10:20:17 +02:00
|
|
|
const TestResult *result = m_filterModel->testResult(idx);
|
2017-09-09 16:46:43 +02:00
|
|
|
QTC_CHECK(result);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultsPane::onCopyItemTriggered(const TestResult *result)
|
|
|
|
|
{
|
2016-04-13 10:20:17 +02:00
|
|
|
QTC_ASSERT(result, return);
|
|
|
|
|
QApplication::clipboard()->setText(result->outputString(true));
|
2015-08-19 13:19:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultsPane::onCopyWholeTriggered()
|
|
|
|
|
{
|
|
|
|
|
QApplication::clipboard()->setText(getWholeOutput());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestResultsPane::onSaveWholeTriggered()
|
|
|
|
|
{
|
|
|
|
|
const QString fileName = QFileDialog::getSaveFileName(Core::ICore::dialogParent(),
|
2017-01-18 14:36:12 +01:00
|
|
|
tr("Save Output To"));
|
2016-04-14 16:46:48 +02:00
|
|
|
if (fileName.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
2015-08-19 13:19:28 +02:00
|
|
|
Utils::FileSaver saver(fileName, QIODevice::Text);
|
|
|
|
|
if (!saver.write(getWholeOutput().toUtf8()) || !saver.finalize()) {
|
|
|
|
|
QMessageBox::critical(Core::ICore::dialogParent(), tr("Error"),
|
|
|
|
|
tr("Failed to write \"%1\".\n\n%2").arg(fileName)
|
|
|
|
|
.arg(saver.errorString()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-09 16:46:43 +02:00
|
|
|
void TestResultsPane::onRunThisTestTriggered(TestRunMode runMode, const TestResult *result)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(result, return);
|
|
|
|
|
|
|
|
|
|
const TestTreeItem *item = result->findTestTreeItem();
|
|
|
|
|
|
|
|
|
|
if (item)
|
|
|
|
|
TestRunner::instance()->runTest(runMode, item);
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-05 13:01:06 +02:00
|
|
|
void TestResultsPane::toggleOutputStyle()
|
|
|
|
|
{
|
|
|
|
|
const bool displayText = m_outputWidget->currentIndex() == 0;
|
|
|
|
|
m_outputWidget->setCurrentIndex(displayText ? 1 : 0);
|
|
|
|
|
m_outputToggleButton->setIcon(displayText ? Icons::VISUAL_DISPLAY.icon()
|
|
|
|
|
: Icons::TEXT_DISPLAY.icon());
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-19 13:19:28 +02:00
|
|
|
// helper for onCopyWholeTriggered() and onSaveWholeTriggered()
|
2015-08-20 15:59:15 +02:00
|
|
|
QString TestResultsPane::getWholeOutput(const QModelIndex &parent)
|
2015-08-19 13:19:28 +02:00
|
|
|
{
|
|
|
|
|
QString output;
|
2015-08-20 15:59:15 +02:00
|
|
|
for (int row = 0, count = m_model->rowCount(parent); row < count; ++row) {
|
|
|
|
|
QModelIndex current = m_model->index(row, 0, parent);
|
2016-04-13 10:20:17 +02:00
|
|
|
const TestResult *result = m_model->testResult(current);
|
|
|
|
|
QTC_ASSERT(result, continue);
|
2016-09-29 12:15:43 +02:00
|
|
|
output.append(TestResult::resultToString(result->result())).append('\t');
|
|
|
|
|
output.append(result->outputString(true)).append('\n');
|
2015-08-20 15:59:15 +02:00
|
|
|
output.append(getWholeOutput(current));
|
2015-08-19 13:19:28 +02:00
|
|
|
}
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-07 15:51:02 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Autotest
|