forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/master' into 4.4
Change-Id: I5d3d689e7bd8d51094b8416761caed15b7df7bd8
This commit is contained in:
@@ -280,11 +280,10 @@ bool PathsAndLanguages::maybeInsert(const PathAndLanguage &pathAndLanguage) {
|
|||||||
if (currentElement.path() == pathAndLanguage.path()) {
|
if (currentElement.path() == pathAndLanguage.path()) {
|
||||||
int j = i;
|
int j = i;
|
||||||
do {
|
do {
|
||||||
if (pathAndLanguage.language() < currentElement.language()) {
|
if (pathAndLanguage.language() < currentElement.language())
|
||||||
|
break;
|
||||||
if (currentElement.language() == pathAndLanguage.language())
|
if (currentElement.language() == pathAndLanguage.language())
|
||||||
return false;
|
return false;
|
||||||
break;
|
|
||||||
}
|
|
||||||
++j;
|
++j;
|
||||||
if (j == m_list.length())
|
if (j == m_list.length())
|
||||||
break;
|
break;
|
||||||
|
@@ -841,6 +841,18 @@ TreeItem *TreeItem::findAnyChild(const std::function<bool(TreeItem *)> &pred) co
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TreeItem *TreeItem::reverseFindAnyChild(const std::function<bool (TreeItem *)> &pred) const
|
||||||
|
{
|
||||||
|
auto end = m_children.rend();
|
||||||
|
for (auto it = m_children.rbegin(); it != end; ++it) {
|
||||||
|
if (pred(*it))
|
||||||
|
return *it;
|
||||||
|
if (TreeItem *found = (*it)->reverseFindAnyChild(pred))
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void TreeItem::clear()
|
void TreeItem::clear()
|
||||||
{
|
{
|
||||||
while (childCount() != 0) {
|
while (childCount() != 0) {
|
||||||
|
@@ -78,6 +78,8 @@ public:
|
|||||||
void forSelectedChildren(const std::function<bool(TreeItem *)> &pred) const;
|
void forSelectedChildren(const std::function<bool(TreeItem *)> &pred) const;
|
||||||
void forAllChildren(const std::function<void(TreeItem *)> &pred) const;
|
void forAllChildren(const std::function<void(TreeItem *)> &pred) const;
|
||||||
TreeItem *findAnyChild(const std::function<bool(TreeItem *)> &pred) const;
|
TreeItem *findAnyChild(const std::function<bool(TreeItem *)> &pred) const;
|
||||||
|
// like findAnyChild() but processes children from bottom to top
|
||||||
|
TreeItem *reverseFindAnyChild(const std::function<bool(TreeItem *)> &pred) const;
|
||||||
|
|
||||||
// Levels are 1-based: Child at Level 1 is an immediate child.
|
// Levels are 1-based: Child at Level 1 is an immediate child.
|
||||||
void forChildrenAtLevel(int level, const std::function<void(TreeItem *)> &pred) const;
|
void forChildrenAtLevel(int level, const std::function<void(TreeItem *)> &pred) const;
|
||||||
|
200
src/plugins/android/adbcommandswidget.cpp
Normal file
200
src/plugins/android/adbcommandswidget.cpp
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2017 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
#include "adbcommandswidget.h"
|
||||||
|
#include "ui_adbcommandswidget.h"
|
||||||
|
|
||||||
|
#include "utils/utilsicons.h"
|
||||||
|
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QItemSelectionModel>
|
||||||
|
#include <QShortcut>
|
||||||
|
#include <QStringListModel>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace Android {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
using namespace std::placeholders;
|
||||||
|
|
||||||
|
const char defaultCommand[] = "echo \"shell command\"";
|
||||||
|
|
||||||
|
static void swapData(QStringListModel *model, const QModelIndex &srcIndex,
|
||||||
|
const QModelIndex &destIndex)
|
||||||
|
{
|
||||||
|
if (model) {
|
||||||
|
QVariant data = model->data(destIndex, Qt::EditRole); // QTBUG-55078
|
||||||
|
model->setData(destIndex, model->data(srcIndex, Qt::EditRole));
|
||||||
|
model->setData(srcIndex, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AdbCommandsWidgetPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AdbCommandsWidgetPrivate(const AdbCommandsWidget &parent, QWidget *parentWidget);
|
||||||
|
~AdbCommandsWidgetPrivate();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addString(const QString &str);
|
||||||
|
void onAddButton();
|
||||||
|
void onMoveUpButton();
|
||||||
|
void onMoveDownButton();
|
||||||
|
void onRemove();
|
||||||
|
void onCurrentIndexChanged(const QModelIndex &newIndex, const QModelIndex &prevIndex);
|
||||||
|
|
||||||
|
const AdbCommandsWidget &m_parent;
|
||||||
|
QGroupBox *m_rootWidget = nullptr;
|
||||||
|
Ui::AdbCommandsWidget *m_ui = nullptr;
|
||||||
|
QStringListModel *m_stringModel = nullptr;
|
||||||
|
friend class AdbCommandsWidget;
|
||||||
|
};
|
||||||
|
|
||||||
|
AdbCommandsWidget::AdbCommandsWidget(QWidget *parent) :
|
||||||
|
QObject(parent),
|
||||||
|
d(new AdbCommandsWidgetPrivate(*this, parent))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AdbCommandsWidget::~AdbCommandsWidget()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList AdbCommandsWidget::commandsList() const
|
||||||
|
{
|
||||||
|
return d->m_stringModel->stringList();
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *AdbCommandsWidget::widget() const
|
||||||
|
{
|
||||||
|
return d->m_rootWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdbCommandsWidget::setTitleText(const QString &title)
|
||||||
|
{
|
||||||
|
d->m_rootWidget->setTitle(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdbCommandsWidget::setCommandList(const QStringList &commands)
|
||||||
|
{
|
||||||
|
d->m_stringModel->setStringList(commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdbCommandsWidgetPrivate::AdbCommandsWidgetPrivate(const AdbCommandsWidget &parent,
|
||||||
|
QWidget *parentWidget):
|
||||||
|
m_parent(parent),
|
||||||
|
m_rootWidget(new QGroupBox(parentWidget)),
|
||||||
|
m_ui(new Ui::AdbCommandsWidget),
|
||||||
|
m_stringModel(new QStringListModel)
|
||||||
|
{
|
||||||
|
m_ui->setupUi(m_rootWidget);
|
||||||
|
m_ui->addButton->setIcon(Utils::Icons::PLUS.icon());
|
||||||
|
m_ui->removeButton->setIcon(Utils::Icons::MINUS.icon());
|
||||||
|
m_ui->moveUpButton->setIcon(Utils::Icons::ARROW_UP.icon());
|
||||||
|
m_ui->moveDownButton->setIcon(Utils::Icons::ARROW_DOWN.icon());
|
||||||
|
|
||||||
|
auto deleteShortcut = new QShortcut(QKeySequence(QKeySequence::Delete), m_ui->commandsView);
|
||||||
|
deleteShortcut->setContext(Qt::WidgetShortcut);
|
||||||
|
QObject::connect(deleteShortcut, &QShortcut::activated,
|
||||||
|
std::bind(&AdbCommandsWidgetPrivate::onRemove, this));
|
||||||
|
|
||||||
|
QObject::connect(m_ui->addButton, &QToolButton::clicked,
|
||||||
|
std::bind(&AdbCommandsWidgetPrivate::onAddButton, this));
|
||||||
|
QObject::connect(m_ui->removeButton, &QToolButton::clicked,
|
||||||
|
std::bind(&AdbCommandsWidgetPrivate::onRemove, this));
|
||||||
|
QObject::connect(m_ui->moveUpButton, &QToolButton::clicked,
|
||||||
|
std::bind(&AdbCommandsWidgetPrivate::onMoveUpButton, this));
|
||||||
|
QObject::connect(m_ui->moveDownButton, &QToolButton::clicked,
|
||||||
|
std::bind(&AdbCommandsWidgetPrivate::onMoveDownButton, this));
|
||||||
|
|
||||||
|
m_ui->commandsView->setModel(m_stringModel);
|
||||||
|
QObject::connect(m_stringModel, &QStringListModel::dataChanged,
|
||||||
|
&m_parent, &AdbCommandsWidget::commandsChanged);
|
||||||
|
QObject::connect(m_stringModel, &QStringListModel::rowsRemoved,
|
||||||
|
&m_parent, &AdbCommandsWidget::commandsChanged);
|
||||||
|
QObject::connect(m_ui->commandsView->selectionModel(), &QItemSelectionModel::currentChanged,
|
||||||
|
std::bind(&AdbCommandsWidgetPrivate::onCurrentIndexChanged, this, _1, _2));
|
||||||
|
}
|
||||||
|
|
||||||
|
AdbCommandsWidgetPrivate::~AdbCommandsWidgetPrivate()
|
||||||
|
{
|
||||||
|
delete m_ui;
|
||||||
|
delete m_stringModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdbCommandsWidgetPrivate::addString(const QString &str)
|
||||||
|
{
|
||||||
|
if (!str.isEmpty()) {
|
||||||
|
m_stringModel->insertRows(m_stringModel->rowCount(), 1);
|
||||||
|
const QModelIndex lastItemIndex = m_stringModel->index(m_stringModel->rowCount() - 1);
|
||||||
|
m_stringModel->setData(lastItemIndex, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdbCommandsWidgetPrivate::onAddButton()
|
||||||
|
{
|
||||||
|
addString(defaultCommand);
|
||||||
|
const QModelIndex index = m_stringModel->index(m_stringModel->rowCount() - 1);
|
||||||
|
m_ui->commandsView->setCurrentIndex(index);
|
||||||
|
m_ui->commandsView->edit(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdbCommandsWidgetPrivate::onMoveUpButton()
|
||||||
|
{
|
||||||
|
QModelIndex index = m_ui->commandsView->currentIndex();
|
||||||
|
if (index.row() > 0) {
|
||||||
|
const QModelIndex newIndex = m_stringModel->index(index.row() - 1, 0);
|
||||||
|
swapData(m_stringModel, index, newIndex);
|
||||||
|
m_ui->commandsView->setCurrentIndex(newIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdbCommandsWidgetPrivate::onMoveDownButton()
|
||||||
|
{
|
||||||
|
QModelIndex index = m_ui->commandsView->currentIndex();
|
||||||
|
if (index.row() < m_stringModel->rowCount() - 1) {
|
||||||
|
const QModelIndex newIndex = m_stringModel->index(index.row() + 1, 0);
|
||||||
|
swapData(m_stringModel, index, newIndex);
|
||||||
|
m_ui->commandsView->setCurrentIndex(newIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdbCommandsWidgetPrivate::onRemove()
|
||||||
|
{
|
||||||
|
const QModelIndex &index = m_ui->commandsView->currentIndex();
|
||||||
|
if (index.isValid())
|
||||||
|
m_stringModel->removeRow(index.row());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdbCommandsWidgetPrivate::onCurrentIndexChanged(const QModelIndex &newIndex, const QModelIndex &prevIndex)
|
||||||
|
{
|
||||||
|
Q_UNUSED(prevIndex)
|
||||||
|
m_ui->moveUpButton->setEnabled(newIndex.row() != 0);
|
||||||
|
m_ui->moveDownButton->setEnabled(newIndex.row() < m_stringModel->rowCount() - 1);
|
||||||
|
m_ui->removeButton->setEnabled(newIndex.isValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Internal
|
||||||
|
} // Android
|
64
src/plugins/android/adbcommandswidget.h
Normal file
64
src/plugins/android/adbcommandswidget.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2017 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QWidget;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
namespace Android {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class AdbCommandsWidgetPrivate;
|
||||||
|
|
||||||
|
class AdbCommandsWidget : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit AdbCommandsWidget(QWidget *parent);
|
||||||
|
~AdbCommandsWidget();
|
||||||
|
|
||||||
|
QStringList commandsList() const;
|
||||||
|
void setCommandList(const QStringList &commands);
|
||||||
|
|
||||||
|
QWidget *widget() const;
|
||||||
|
|
||||||
|
void setTitleText(const QString &title);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void commandsChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<AdbCommandsWidgetPrivate> d;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // Internal
|
||||||
|
} // Android
|
117
src/plugins/android/adbcommandswidget.ui
Normal file
117
src/plugins/android/adbcommandswidget.ui
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>AdbCommandsWidget</class>
|
||||||
|
<widget class="QGroupBox" name="AdbCommandsWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>682</width>
|
||||||
|
<height>391</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Widget</string>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="2" column="1">
|
||||||
|
<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>
|
||||||
|
<item row="0" column="0" rowspan="6">
|
||||||
|
<widget class="QListView" name="commandsView">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="defaultDropAction">
|
||||||
|
<enum>Qt::MoveAction</enum>
|
||||||
|
</property>
|
||||||
|
<property name="movement">
|
||||||
|
<enum>QListView::Snap</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QToolButton" name="moveUpButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="arrowType">
|
||||||
|
<enum>Qt::NoArrow</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QToolButton" name="addButton">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QToolButton" name="moveDownButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="arrowType">
|
||||||
|
<enum>Qt::NoArrow</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QToolButton" name="removeButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>commandsView</tabstop>
|
||||||
|
<tabstop>addButton</tabstop>
|
||||||
|
<tabstop>removeButton</tabstop>
|
||||||
|
<tabstop>moveUpButton</tabstop>
|
||||||
|
<tabstop>moveDownButton</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
@@ -50,7 +50,8 @@ HEADERS += \
|
|||||||
androidtoolmanager.h \
|
androidtoolmanager.h \
|
||||||
androidsdkmanager.h \
|
androidsdkmanager.h \
|
||||||
androidavdmanager.h \
|
androidavdmanager.h \
|
||||||
androidrunconfigurationwidget.h
|
androidrunconfigurationwidget.h \
|
||||||
|
adbcommandswidget.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
androidconfigurations.cpp \
|
androidconfigurations.cpp \
|
||||||
@@ -94,7 +95,8 @@ SOURCES += \
|
|||||||
androidtoolmanager.cpp \
|
androidtoolmanager.cpp \
|
||||||
androidsdkmanager.cpp \
|
androidsdkmanager.cpp \
|
||||||
androidavdmanager.cpp \
|
androidavdmanager.cpp \
|
||||||
androidrunconfigurationwidget.cpp
|
androidrunconfigurationwidget.cpp \
|
||||||
|
adbcommandswidget.cpp
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
androidsettingswidget.ui \
|
androidsettingswidget.ui \
|
||||||
@@ -103,7 +105,8 @@ FORMS += \
|
|||||||
androiddevicedialog.ui \
|
androiddevicedialog.ui \
|
||||||
androiddeployqtwidget.ui \
|
androiddeployqtwidget.ui \
|
||||||
androidbuildapkwidget.ui \
|
androidbuildapkwidget.ui \
|
||||||
androidrunconfigurationwidget.ui
|
androidrunconfigurationwidget.ui \
|
||||||
|
adbcommandswidget.ui
|
||||||
|
|
||||||
RESOURCES = android.qrc
|
RESOURCES = android.qrc
|
||||||
|
|
||||||
|
@@ -18,8 +18,11 @@ Project {
|
|||||||
|
|
||||||
files: [
|
files: [
|
||||||
"android_global.h",
|
"android_global.h",
|
||||||
"addnewavddialog.ui",
|
|
||||||
"android.qrc",
|
"android.qrc",
|
||||||
|
"adbcommandswidget.cpp",
|
||||||
|
"adbcommandswidget.h",
|
||||||
|
"adbcommandswidget.ui",
|
||||||
|
"addnewavddialog.ui",
|
||||||
"androidanalyzesupport.cpp",
|
"androidanalyzesupport.cpp",
|
||||||
"androidanalyzesupport.h",
|
"androidanalyzesupport.h",
|
||||||
"androidavdmanager.cpp",
|
"androidavdmanager.cpp",
|
||||||
|
@@ -40,7 +40,10 @@ using namespace ProjectExplorer;
|
|||||||
|
|
||||||
namespace Android {
|
namespace Android {
|
||||||
using namespace Internal;
|
using namespace Internal;
|
||||||
|
|
||||||
const char amStartArgsKey[] = "Android.AmStartArgsKey";
|
const char amStartArgsKey[] = "Android.AmStartArgsKey";
|
||||||
|
const char preStartShellCmdsKey[] = "Android.PreStartShellCmdListKey";
|
||||||
|
const char postFinishShellCmdsKey[] = "Android.PostFinishShellCmdListKey";
|
||||||
|
|
||||||
AndroidRunConfiguration::AndroidRunConfiguration(Target *parent, Core::Id id)
|
AndroidRunConfiguration::AndroidRunConfiguration(Target *parent, Core::Id id)
|
||||||
: RunConfiguration(parent, id)
|
: RunConfiguration(parent, id)
|
||||||
@@ -52,6 +55,16 @@ AndroidRunConfiguration::AndroidRunConfiguration(Target *parent, AndroidRunConfi
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AndroidRunConfiguration::setPreStartShellCommands(const QStringList &cmdList)
|
||||||
|
{
|
||||||
|
m_preStartShellCommands = cmdList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidRunConfiguration::setPostFinishShellCommands(const QStringList &cmdList)
|
||||||
|
{
|
||||||
|
m_postFinishShellCommands = cmdList;
|
||||||
|
}
|
||||||
|
|
||||||
void AndroidRunConfiguration::setAmStartExtraArgs(const QStringList &args)
|
void AndroidRunConfiguration::setAmStartExtraArgs(const QStringList &args)
|
||||||
{
|
{
|
||||||
m_amStartExtraArgs = args;
|
m_amStartExtraArgs = args;
|
||||||
@@ -61,8 +74,14 @@ QWidget *AndroidRunConfiguration::createConfigurationWidget()
|
|||||||
{
|
{
|
||||||
auto configWidget = new AndroidRunConfigurationWidget();
|
auto configWidget = new AndroidRunConfigurationWidget();
|
||||||
configWidget->setAmStartArgs(m_amStartExtraArgs);
|
configWidget->setAmStartArgs(m_amStartExtraArgs);
|
||||||
|
configWidget->setPreStartShellCommands(m_preStartShellCommands);
|
||||||
|
configWidget->setPostFinishShellCommands(m_postFinishShellCommands);
|
||||||
connect(configWidget, &AndroidRunConfigurationWidget::amStartArgsChanged,
|
connect(configWidget, &AndroidRunConfigurationWidget::amStartArgsChanged,
|
||||||
this, &AndroidRunConfiguration::setAmStartExtraArgs);
|
this, &AndroidRunConfiguration::setAmStartExtraArgs);
|
||||||
|
connect(configWidget, &AndroidRunConfigurationWidget::preStartCmdsChanged,
|
||||||
|
this, &AndroidRunConfiguration::setPreStartShellCommands);
|
||||||
|
connect(configWidget, &AndroidRunConfigurationWidget::postFinishCmdsChanged,
|
||||||
|
this, &AndroidRunConfiguration::setPostFinishShellCommands);
|
||||||
return configWidget;
|
return configWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +92,8 @@ Utils::OutputFormatter *AndroidRunConfiguration::createOutputFormatter() const
|
|||||||
|
|
||||||
bool AndroidRunConfiguration::fromMap(const QVariantMap &map)
|
bool AndroidRunConfiguration::fromMap(const QVariantMap &map)
|
||||||
{
|
{
|
||||||
|
m_preStartShellCommands = map.value(preStartShellCmdsKey).toStringList();
|
||||||
|
m_postFinishShellCommands = map.value(postFinishShellCmdsKey).toStringList();
|
||||||
m_amStartExtraArgs = map.value(amStartArgsKey).toStringList();
|
m_amStartExtraArgs = map.value(amStartArgsKey).toStringList();
|
||||||
return RunConfiguration::fromMap(map);
|
return RunConfiguration::fromMap(map);
|
||||||
}
|
}
|
||||||
@@ -80,6 +101,8 @@ bool AndroidRunConfiguration::fromMap(const QVariantMap &map)
|
|||||||
QVariantMap AndroidRunConfiguration::toMap() const
|
QVariantMap AndroidRunConfiguration::toMap() const
|
||||||
{
|
{
|
||||||
QVariantMap res = RunConfiguration::toMap();
|
QVariantMap res = RunConfiguration::toMap();
|
||||||
|
res[preStartShellCmdsKey] = m_preStartShellCommands;
|
||||||
|
res[postFinishShellCmdsKey] = m_postFinishShellCommands;
|
||||||
res[amStartArgsKey] = m_amStartExtraArgs;
|
res[amStartArgsKey] = m_amStartExtraArgs;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -88,4 +111,15 @@ const QStringList &AndroidRunConfiguration::amStartExtraArgs() const
|
|||||||
{
|
{
|
||||||
return m_amStartExtraArgs;
|
return m_amStartExtraArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QStringList &AndroidRunConfiguration::preStartShellCommands() const
|
||||||
|
{
|
||||||
|
return m_preStartShellCommands;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QStringList &AndroidRunConfiguration::postFinishShellCommands() const
|
||||||
|
{
|
||||||
|
return m_postFinishShellCommands;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Android
|
} // namespace Android
|
||||||
|
@@ -48,15 +48,21 @@ public:
|
|||||||
QVariantMap toMap() const override;
|
QVariantMap toMap() const override;
|
||||||
|
|
||||||
const QStringList &amStartExtraArgs() const;
|
const QStringList &amStartExtraArgs() const;
|
||||||
|
const QStringList &preStartShellCommands() const;
|
||||||
|
const QStringList &postFinishShellCommands() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AndroidRunConfiguration(ProjectExplorer::Target *parent, AndroidRunConfiguration *source);
|
AndroidRunConfiguration(ProjectExplorer::Target *parent, AndroidRunConfiguration *source);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void setPreStartShellCommands(const QStringList &cmdList);
|
||||||
|
void setPostFinishShellCommands(const QStringList &cmdList);
|
||||||
void setAmStartExtraArgs(const QStringList &args);
|
void setAmStartExtraArgs(const QStringList &args);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStringList m_amStartExtraArgs;
|
QStringList m_amStartExtraArgs;
|
||||||
|
QStringList m_preStartShellCommands;
|
||||||
|
QStringList m_postFinishShellCommands;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Android
|
} // namespace Android
|
||||||
|
@@ -23,6 +23,7 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include "androidrunconfigurationwidget.h"
|
#include "androidrunconfigurationwidget.h"
|
||||||
|
#include "adbcommandswidget.h"
|
||||||
#include "ui_androidrunconfigurationwidget.h"
|
#include "ui_androidrunconfigurationwidget.h"
|
||||||
|
|
||||||
#include "utils/utilsicons.h"
|
#include "utils/utilsicons.h"
|
||||||
@@ -39,6 +40,26 @@ AndroidRunConfigurationWidget::AndroidRunConfigurationWidget(QWidget *parent):
|
|||||||
m_ui->setupUi(detailsWidget);
|
m_ui->setupUi(detailsWidget);
|
||||||
m_ui->m_warningIconLabel->setPixmap(Utils::Icons::WARNING.pixmap());
|
m_ui->m_warningIconLabel->setPixmap(Utils::Icons::WARNING.pixmap());
|
||||||
|
|
||||||
|
m_preStartCmdsWidget = new AdbCommandsWidget(detailsWidget);
|
||||||
|
connect(m_preStartCmdsWidget, &AdbCommandsWidget::commandsChanged, [this]() {
|
||||||
|
emit preStartCmdsChanged(m_preStartCmdsWidget->commandsList());
|
||||||
|
});
|
||||||
|
m_preStartCmdsWidget->setTitleText(tr("Shell commands to run on Android device before"
|
||||||
|
" application launch."));
|
||||||
|
|
||||||
|
m_postEndCmdsWidget = new AdbCommandsWidget(detailsWidget);
|
||||||
|
connect(m_postEndCmdsWidget, &AdbCommandsWidget::commandsChanged, [this]() {
|
||||||
|
emit postFinishCmdsChanged(m_postEndCmdsWidget->commandsList());
|
||||||
|
});
|
||||||
|
m_postEndCmdsWidget->setTitleText(tr("Shell commands to run on Android device after application"
|
||||||
|
" quits."));
|
||||||
|
|
||||||
|
auto mainLayout = static_cast<QGridLayout*>(detailsWidget->layout());
|
||||||
|
mainLayout->addWidget(m_preStartCmdsWidget->widget(), mainLayout->rowCount(),
|
||||||
|
0, mainLayout->columnCount() - 1, 0);
|
||||||
|
mainLayout->addWidget(m_postEndCmdsWidget->widget(), mainLayout->rowCount(),
|
||||||
|
0, mainLayout->columnCount() - 1, 0);
|
||||||
|
|
||||||
setWidget(detailsWidget);
|
setWidget(detailsWidget);
|
||||||
setSummaryText(tr("Android run settings"));
|
setSummaryText(tr("Android run settings"));
|
||||||
|
|
||||||
@@ -54,10 +75,19 @@ AndroidRunConfigurationWidget::~AndroidRunConfigurationWidget()
|
|||||||
|
|
||||||
void AndroidRunConfigurationWidget::setAmStartArgs(const QStringList &args)
|
void AndroidRunConfigurationWidget::setAmStartArgs(const QStringList &args)
|
||||||
{
|
{
|
||||||
if (m_ui->m_amStartArgsEdit && !args.isEmpty())
|
|
||||||
m_ui->m_amStartArgsEdit->setText(Utils::QtcProcess::joinArgs(args, Utils::OsTypeLinux));
|
m_ui->m_amStartArgsEdit->setText(Utils::QtcProcess::joinArgs(args, Utils::OsTypeLinux));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AndroidRunConfigurationWidget::setPreStartShellCommands(const QStringList &cmdList)
|
||||||
|
{
|
||||||
|
m_preStartCmdsWidget->setCommandList(cmdList);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidRunConfigurationWidget::setPostFinishShellCommands(const QStringList &cmdList)
|
||||||
|
{
|
||||||
|
m_postEndCmdsWidget->setCommandList(cmdList);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Android
|
} // namespace Android
|
||||||
|
|
||||||
|
@@ -29,10 +29,14 @@
|
|||||||
#include "projectexplorer/runconfiguration.h"
|
#include "projectexplorer/runconfiguration.h"
|
||||||
#include "utils/detailswidget.h"
|
#include "utils/detailswidget.h"
|
||||||
|
|
||||||
|
#include <QStringListModel>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace Android {
|
namespace Android {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class AdbCommandsWidget;
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class AndroidRunConfigurationWidget;
|
class AndroidRunConfigurationWidget;
|
||||||
}
|
}
|
||||||
@@ -45,12 +49,22 @@ public:
|
|||||||
~AndroidRunConfigurationWidget();
|
~AndroidRunConfigurationWidget();
|
||||||
|
|
||||||
void setAmStartArgs(const QStringList &args);
|
void setAmStartArgs(const QStringList &args);
|
||||||
|
void setPreStartShellCommands(const QStringList &cmdList);
|
||||||
|
void setPostFinishShellCommands(const QStringList &cmdList);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void amStartArgsChanged(QStringList args);
|
void amStartArgsChanged(QStringList args);
|
||||||
|
void preStartCmdsChanged(const QStringList &cmdList);
|
||||||
|
void postFinishCmdsChanged(const QStringList &cmdList);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addPreStartCommand(const QString &command);
|
||||||
|
void addPostFinishCommand(const QString &command);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::AndroidRunConfigurationWidget> m_ui;
|
std::unique_ptr<Ui::AndroidRunConfigurationWidget> m_ui;
|
||||||
|
AdbCommandsWidget *m_preStartCmdsWidget = nullptr;
|
||||||
|
AdbCommandsWidget *m_postEndCmdsWidget = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -6,25 +6,31 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>625</width>
|
<width>731</width>
|
||||||
<height>73</height>
|
<height>119</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Form</string>
|
<string>Form</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="2">
|
<property name="spacing">
|
||||||
<widget class="QLineEdit" name="m_amStartArgsEdit"/>
|
<number>-1</number>
|
||||||
</item>
|
</property>
|
||||||
<item row="1" column="2">
|
<item row="1" column="0" colspan="2">
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Conflicting "am start" options might result in the app startup failure.</string>
|
<string>Activity manager start options:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QLabel" name="m_warningIconLabel">
|
<widget class="QLabel" name="m_warningIconLabel">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||||
@@ -37,7 +43,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="2" column="0">
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
@@ -53,13 +59,32 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0" colspan="2">
|
<item row="3" column="0" colspan="3">
|
||||||
<widget class="QLabel" name="label">
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>12</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Activity manager start options:</string>
|
<string>Conflicting "am start" options might result in the app startup failure.</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QLineEdit" name="m_amStartArgsEdit"/>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
@@ -37,8 +37,8 @@ struct ANDROID_EXPORT AndroidRunnable
|
|||||||
QString intentName;
|
QString intentName;
|
||||||
QStringList amStartExtraArgs;
|
QStringList amStartExtraArgs;
|
||||||
Utils::Environment environment;
|
Utils::Environment environment;
|
||||||
QVector<QStringList> beforeStartADBCommands;
|
QStringList beforeStartAdbCommands;
|
||||||
QVector<QStringList> afterFinishADBCommands;
|
QStringList afterFinishAdbCommands;
|
||||||
QString deviceSerialNumber;
|
QString deviceSerialNumber;
|
||||||
|
|
||||||
QString displayName() const { return packageName; }
|
QString displayName() const { return packageName; }
|
||||||
@@ -51,8 +51,8 @@ inline bool operator==(const AndroidRunnable &r1, const AndroidRunnable &r2)
|
|||||||
&& r1.intentName == r2.intentName
|
&& r1.intentName == r2.intentName
|
||||||
&& r1.amStartExtraArgs == r2.amStartExtraArgs
|
&& r1.amStartExtraArgs == r2.amStartExtraArgs
|
||||||
&& r1.environment == r2.environment
|
&& r1.environment == r2.environment
|
||||||
&& r1.beforeStartADBCommands == r2.beforeStartADBCommands
|
&& r1.beforeStartAdbCommands == r2.beforeStartAdbCommands
|
||||||
&& r1.afterFinishADBCommands == r2.afterFinishADBCommands
|
&& r1.afterFinishAdbCommands == r2.afterFinishAdbCommands
|
||||||
&& r1.deviceSerialNumber == r2.deviceSerialNumber;
|
&& r1.deviceSerialNumber == r2.deviceSerialNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -214,14 +214,13 @@ class AndroidRunnerWorker : public QObject
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AndroidRunnerWorker(RunControl *runControl, const QString &packageName,
|
AndroidRunnerWorker(RunControl *runControl, const AndroidRunnable &runnable);
|
||||||
const QStringList &selector);
|
|
||||||
~AndroidRunnerWorker();
|
~AndroidRunnerWorker();
|
||||||
|
|
||||||
void asyncStart(const AndroidRunnable &runnable);
|
void asyncStart();
|
||||||
void asyncStop(const AndroidRunnable &runnable);
|
void asyncStop();
|
||||||
|
|
||||||
void setAdbParameters(const QString &packageName, const QStringList &selector);
|
void setAndroidRunnable(const AndroidRunnable &runnable);
|
||||||
void handleRemoteDebuggerRunning();
|
void handleRemoteDebuggerRunning();
|
||||||
|
|
||||||
Utils::Port localGdbServerPort() const { return m_localGdbServerPort; }
|
Utils::Port localGdbServerPort() const { return m_localGdbServerPort; }
|
||||||
@@ -238,7 +237,7 @@ private:
|
|||||||
void logcatReadStandardError();
|
void logcatReadStandardError();
|
||||||
void logcatReadStandardOutput();
|
void logcatReadStandardOutput();
|
||||||
void adbKill(qint64 pid);
|
void adbKill(qint64 pid);
|
||||||
QStringList selector() const { return m_selector; }
|
QStringList selector() const;
|
||||||
void forceStop();
|
void forceStop();
|
||||||
void findPs();
|
void findPs();
|
||||||
void logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError);
|
void logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError);
|
||||||
@@ -264,22 +263,19 @@ private:
|
|||||||
QString m_gdbserverPath;
|
QString m_gdbserverPath;
|
||||||
QString m_gdbserverSocket;
|
QString m_gdbserverSocket;
|
||||||
QString m_adb;
|
QString m_adb;
|
||||||
QStringList m_selector;
|
|
||||||
QRegExp m_logCatRegExp;
|
QRegExp m_logCatRegExp;
|
||||||
DebugHandShakeType m_handShakeMethod = SocketHandShake;
|
DebugHandShakeType m_handShakeMethod = SocketHandShake;
|
||||||
bool m_customPort = false;
|
bool m_customPort = false;
|
||||||
|
|
||||||
QString m_packageName;
|
AndroidRunnable m_androidRunnable;
|
||||||
int m_socketHandShakePort = MIN_SOCKET_HANDSHAKE_PORT;
|
int m_socketHandShakePort = MIN_SOCKET_HANDSHAKE_PORT;
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidRunnerWorker::AndroidRunnerWorker(RunControl *runControl, const QString &packageName,
|
AndroidRunnerWorker::AndroidRunnerWorker(RunControl *runControl, const AndroidRunnable &runnable)
|
||||||
const QStringList &selector)
|
|
||||||
: m_adbLogcatProcess(nullptr, deleter)
|
: m_adbLogcatProcess(nullptr, deleter)
|
||||||
, m_psIsAlive(nullptr, deleter)
|
, m_psIsAlive(nullptr, deleter)
|
||||||
, m_selector(selector)
|
|
||||||
, m_logCatRegExp(regExpLogcat)
|
, m_logCatRegExp(regExpLogcat)
|
||||||
, m_packageName(packageName)
|
, m_androidRunnable(runnable)
|
||||||
{
|
{
|
||||||
auto runConfig = runControl->runConfiguration();
|
auto runConfig = runControl->runConfiguration();
|
||||||
auto aspect = runConfig->extraAspect<Debugger::DebuggerRunConfigurationAspect>();
|
auto aspect = runConfig->extraAspect<Debugger::DebuggerRunConfigurationAspect>();
|
||||||
@@ -307,9 +303,9 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunControl *runControl, const QString &
|
|||||||
}
|
}
|
||||||
m_adb = AndroidConfigurations::currentConfig().adbToolPath().toString();
|
m_adb = AndroidConfigurations::currentConfig().adbToolPath().toString();
|
||||||
|
|
||||||
QString packageDir = "/data/data/" + m_packageName;
|
QString packageDir = "/data/data/" + m_androidRunnable.packageName;
|
||||||
m_pingFile = packageDir + "/debug-ping";
|
m_pingFile = packageDir + "/debug-ping";
|
||||||
m_pongFile = "/data/local/tmp/qt/debug-pong-" + m_packageName;
|
m_pongFile = "/data/local/tmp/qt/debug-pong-" + m_androidRunnable.packageName;
|
||||||
m_gdbserverSocket = packageDir + "/debug-socket";
|
m_gdbserverSocket = packageDir + "/debug-socket";
|
||||||
const QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(
|
const QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(
|
||||||
runConfig->target()->kit());
|
runConfig->target()->kit());
|
||||||
@@ -347,20 +343,20 @@ AndroidRunnerWorker::~AndroidRunnerWorker()
|
|||||||
|
|
||||||
void AndroidRunnerWorker::forceStop()
|
void AndroidRunnerWorker::forceStop()
|
||||||
{
|
{
|
||||||
runAdb({"shell", "am", "force-stop", m_packageName}, nullptr, 30);
|
runAdb({"shell", "am", "force-stop", m_androidRunnable.packageName}, nullptr, 30);
|
||||||
|
|
||||||
// try killing it via kill -9
|
// try killing it via kill -9
|
||||||
const QByteArray out = Utils::SynchronousProcess()
|
const QByteArray out = Utils::SynchronousProcess()
|
||||||
.runBlocking(m_adb, selector() << QStringLiteral("shell") << pidScript)
|
.runBlocking(m_adb, selector() << QStringLiteral("shell") << pidScript)
|
||||||
.allRawOutput();
|
.allRawOutput();
|
||||||
|
|
||||||
qint64 pid = extractPID(out.simplified(), m_packageName);
|
qint64 pid = extractPID(out.simplified(), m_androidRunnable.packageName);
|
||||||
if (pid != -1) {
|
if (pid != -1) {
|
||||||
adbKill(pid);
|
adbKill(pid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidRunnerWorker::asyncStart(const AndroidRunnable &runnable)
|
void AndroidRunnerWorker::asyncStart()
|
||||||
{
|
{
|
||||||
forceStop();
|
forceStop();
|
||||||
|
|
||||||
@@ -378,12 +374,12 @@ void AndroidRunnerWorker::asyncStart(const AndroidRunnable &runnable)
|
|||||||
if (m_useCppDebugger)
|
if (m_useCppDebugger)
|
||||||
runAdb({"shell", "rm", m_pongFile}); // Remove pong file.
|
runAdb({"shell", "rm", m_pongFile}); // Remove pong file.
|
||||||
|
|
||||||
for (const QStringList &entry: runnable.beforeStartADBCommands)
|
for (const QString &entry: m_androidRunnable.beforeStartAdbCommands)
|
||||||
runAdb(entry);
|
runAdb(entry.split(' ', QString::SkipEmptyParts));
|
||||||
|
|
||||||
QStringList args({"shell", "am", "start"});
|
QStringList args({"shell", "am", "start"});
|
||||||
args << runnable.amStartExtraArgs;
|
args << m_androidRunnable.amStartExtraArgs;
|
||||||
args << "-n" << runnable.intentName;
|
args << "-n" << m_androidRunnable.intentName;
|
||||||
|
|
||||||
if (m_useCppDebugger) {
|
if (m_useCppDebugger) {
|
||||||
if (!runAdb({"forward", "--remove", "tcp:" + m_localGdbServerPort.toString()})){
|
if (!runAdb({"forward", "--remove", "tcp:" + m_localGdbServerPort.toString()})){
|
||||||
@@ -395,7 +391,7 @@ void AndroidRunnerWorker::asyncStart(const AndroidRunnable &runnable)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString pingPongSocket(m_packageName + ".ping_pong_socket");
|
const QString pingPongSocket(m_androidRunnable.packageName + ".ping_pong_socket");
|
||||||
args << "-e" << "debug_ping" << "true";
|
args << "-e" << "debug_ping" << "true";
|
||||||
if (m_handShakeMethod == SocketHandShake) {
|
if (m_handShakeMethod == SocketHandShake) {
|
||||||
args << "-e" << "ping_socket" << pingPongSocket;
|
args << "-e" << "ping_socket" << pingPongSocket;
|
||||||
@@ -499,7 +495,8 @@ void AndroidRunnerWorker::asyncStart(const AndroidRunnable &runnable)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if (i == 20) {
|
if (i == 20) {
|
||||||
emit remoteProcessFinished(tr("Unable to start \"%1\".").arg(m_packageName));
|
emit remoteProcessFinished(tr("Unable to start \"%1\".")
|
||||||
|
.arg(m_androidRunnable.packageName));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
qDebug() << "WAITING FOR " << tmp.fileName();
|
qDebug() << "WAITING FOR " << tmp.fileName();
|
||||||
@@ -512,7 +509,7 @@ void AndroidRunnerWorker::asyncStart(const AndroidRunnable &runnable)
|
|||||||
QTC_ASSERT(!m_adbLogcatProcess, /**/);
|
QTC_ASSERT(!m_adbLogcatProcess, /**/);
|
||||||
m_adbLogcatProcess = std::move(logcatProcess);
|
m_adbLogcatProcess = std::move(logcatProcess);
|
||||||
m_pidFinder = Utils::onResultReady(Utils::runAsync(&findProcessPID, m_adb, selector(),
|
m_pidFinder = Utils::onResultReady(Utils::runAsync(&findProcessPID, m_adb, selector(),
|
||||||
m_packageName),
|
m_androidRunnable.packageName),
|
||||||
bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1));
|
bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1));
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -543,7 +540,7 @@ bool AndroidRunnerWorker::runAdb(const QStringList &args, QString *exitMessage,
|
|||||||
{
|
{
|
||||||
Utils::SynchronousProcess adb;
|
Utils::SynchronousProcess adb;
|
||||||
adb.setTimeoutS(timeoutS);
|
adb.setTimeoutS(timeoutS);
|
||||||
Utils::SynchronousProcessResponse response = adb.run(m_adb, m_selector + args);
|
Utils::SynchronousProcessResponse response = adb.run(m_adb, selector() + args);
|
||||||
if (exitMessage)
|
if (exitMessage)
|
||||||
*exitMessage = response.exitMessage(m_adb, timeoutS);
|
*exitMessage = response.exitMessage(m_adb, timeoutS);
|
||||||
return response.result == Utils::SynchronousProcessResponse::Finished;
|
return response.result == Utils::SynchronousProcessResponse::Finished;
|
||||||
@@ -567,7 +564,7 @@ void AndroidRunnerWorker::handleRemoteDebuggerRunning()
|
|||||||
// emit remoteProcessStarted(m_localGdbServerPort, m_qmlPort);
|
// emit remoteProcessStarted(m_localGdbServerPort, m_qmlPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidRunnerWorker::asyncStop(const AndroidRunnable &runnable)
|
void AndroidRunnerWorker::asyncStop()
|
||||||
{
|
{
|
||||||
if (!m_pidFinder.isFinished())
|
if (!m_pidFinder.isFinished())
|
||||||
m_pidFinder.cancel();
|
m_pidFinder.cancel();
|
||||||
@@ -575,14 +572,11 @@ void AndroidRunnerWorker::asyncStop(const AndroidRunnable &runnable)
|
|||||||
if (m_processPID != -1) {
|
if (m_processPID != -1) {
|
||||||
forceStop();
|
forceStop();
|
||||||
}
|
}
|
||||||
for (const QStringList &entry: runnable.afterFinishADBCommands)
|
|
||||||
runAdb(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidRunnerWorker::setAdbParameters(const QString &packageName, const QStringList &selector)
|
void AndroidRunnerWorker::setAndroidRunnable(const AndroidRunnable &runnable)
|
||||||
{
|
{
|
||||||
m_packageName = packageName;
|
m_androidRunnable = runnable;
|
||||||
m_selector = selector;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidRunnerWorker::logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError)
|
void AndroidRunnerWorker::logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError)
|
||||||
@@ -635,10 +629,14 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
|
|||||||
m_processPID = pid;
|
m_processPID = pid;
|
||||||
if (pid == -1) {
|
if (pid == -1) {
|
||||||
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.")
|
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.")
|
||||||
.arg(m_packageName));
|
.arg(m_androidRunnable.packageName));
|
||||||
// App died/killed. Reset log and monitor processes.
|
// App died/killed. Reset log and monitor processes.
|
||||||
m_adbLogcatProcess.reset();
|
m_adbLogcatProcess.reset();
|
||||||
m_psIsAlive.reset();
|
m_psIsAlive.reset();
|
||||||
|
|
||||||
|
// Run adb commands after application quit.
|
||||||
|
for (const QString &entry: m_androidRunnable.afterFinishAdbCommands)
|
||||||
|
runAdb(entry.split(' ', QString::SkipEmptyParts));
|
||||||
} else {
|
} else {
|
||||||
// In debugging cases this will be funneled to the engine to actually start
|
// In debugging cases this will be funneled to the engine to actually start
|
||||||
// and attach gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
|
// and attach gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
|
||||||
@@ -671,7 +669,12 @@ void AndroidRunnerWorker::logcatReadStandardOutput()
|
|||||||
void AndroidRunnerWorker::adbKill(qint64 pid)
|
void AndroidRunnerWorker::adbKill(qint64 pid)
|
||||||
{
|
{
|
||||||
runAdb({"shell", "kill", "-9", QString::number(pid)});
|
runAdb({"shell", "kill", "-9", QString::number(pid)});
|
||||||
runAdb({"shell", "run-as", m_packageName, "kill", "-9", QString::number(pid)});
|
runAdb({"shell", "run-as", m_androidRunnable.packageName, "kill", "-9", QString::number(pid)});
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList AndroidRunnerWorker::selector() const
|
||||||
|
{
|
||||||
|
return AndroidDeviceInfo::adbSelector(m_androidRunnable.deviceSerialNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidRunner::AndroidRunner(RunControl *runControl)
|
AndroidRunner::AndroidRunner(RunControl *runControl)
|
||||||
@@ -694,15 +697,19 @@ AndroidRunner::AndroidRunner(RunControl *runControl)
|
|||||||
|
|
||||||
auto androidRunConfig = qobject_cast<AndroidRunConfiguration *>(runControl->runConfiguration());
|
auto androidRunConfig = qobject_cast<AndroidRunConfiguration *>(runControl->runConfiguration());
|
||||||
m_androidRunnable.amStartExtraArgs = androidRunConfig->amStartExtraArgs();
|
m_androidRunnable.amStartExtraArgs = androidRunConfig->amStartExtraArgs();
|
||||||
|
for (QString shellCmd: androidRunConfig->preStartShellCommands())
|
||||||
|
m_androidRunnable.beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||||
|
|
||||||
m_worker.reset(new AndroidRunnerWorker(runControl, m_androidRunnable.packageName,
|
for (QString shellCmd: androidRunConfig->postFinishShellCommands())
|
||||||
AndroidDeviceInfo::adbSelector(m_androidRunnable.deviceSerialNumber)));
|
m_androidRunnable.afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd));
|
||||||
|
|
||||||
|
m_worker.reset(new AndroidRunnerWorker(runControl, m_androidRunnable));
|
||||||
m_worker->moveToThread(&m_thread);
|
m_worker->moveToThread(&m_thread);
|
||||||
|
|
||||||
connect(this, &AndroidRunner::asyncStart, m_worker.data(), &AndroidRunnerWorker::asyncStart);
|
connect(this, &AndroidRunner::asyncStart, m_worker.data(), &AndroidRunnerWorker::asyncStart);
|
||||||
connect(this, &AndroidRunner::asyncStop, m_worker.data(), &AndroidRunnerWorker::asyncStop);
|
connect(this, &AndroidRunner::asyncStop, m_worker.data(), &AndroidRunnerWorker::asyncStop);
|
||||||
connect(this, &AndroidRunner::adbParametersChanged,
|
connect(this, &AndroidRunner::androidRunnableChanged,
|
||||||
m_worker.data(), &AndroidRunnerWorker::setAdbParameters);
|
m_worker.data(), &AndroidRunnerWorker::setAndroidRunnable);
|
||||||
connect(this, &AndroidRunner::remoteDebuggerRunning,
|
connect(this, &AndroidRunner::remoteDebuggerRunning,
|
||||||
m_worker.data(), &AndroidRunnerWorker::handleRemoteDebuggerRunning);
|
m_worker.data(), &AndroidRunnerWorker::handleRemoteDebuggerRunning);
|
||||||
|
|
||||||
@@ -738,7 +745,7 @@ void AndroidRunner::start()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emit asyncStart(m_androidRunnable);
|
emit asyncStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidRunner::stop()
|
void AndroidRunner::stop()
|
||||||
@@ -750,7 +757,7 @@ void AndroidRunner::stop()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit asyncStop(m_androidRunnable);
|
emit asyncStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidRunner::qmlServerPortReady(Port port)
|
void AndroidRunner::qmlServerPortReady(Port port)
|
||||||
@@ -797,8 +804,7 @@ void AndroidRunner::setRunnable(const AndroidRunnable &runnable)
|
|||||||
{
|
{
|
||||||
if (runnable != m_androidRunnable) {
|
if (runnable != m_androidRunnable) {
|
||||||
m_androidRunnable = runnable;
|
m_androidRunnable = runnable;
|
||||||
emit adbParametersChanged(runnable.packageName,
|
emit androidRunnableChanged(m_androidRunnable);
|
||||||
AndroidDeviceInfo::adbSelector(runnable.deviceSerialNumber));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -816,8 +822,7 @@ void AndroidRunner::launchAVD()
|
|||||||
AndroidConfigurations::None);
|
AndroidConfigurations::None);
|
||||||
AndroidManager::setDeviceSerialNumber(m_target, info.serialNumber);
|
AndroidManager::setDeviceSerialNumber(m_target, info.serialNumber);
|
||||||
m_androidRunnable.deviceSerialNumber = info.serialNumber;
|
m_androidRunnable.deviceSerialNumber = info.serialNumber;
|
||||||
emit adbParametersChanged(m_androidRunnable.packageName,
|
emit androidRunnableChanged(m_androidRunnable);
|
||||||
AndroidDeviceInfo::adbSelector(info.serialNumber));
|
|
||||||
if (info.isValid()) {
|
if (info.isValid()) {
|
||||||
AndroidAvdManager avdManager;
|
AndroidAvdManager avdManager;
|
||||||
if (avdManager.findAvd(info.avdname).isEmpty()) {
|
if (avdManager.findAvd(info.avdname).isEmpty()) {
|
||||||
@@ -840,7 +845,7 @@ void AndroidRunner::checkAVD()
|
|||||||
if (avdManager.isAvdBooted(serialNumber)) {
|
if (avdManager.isAvdBooted(serialNumber)) {
|
||||||
m_checkAVDTimer.stop();
|
m_checkAVDTimer.stop();
|
||||||
AndroidManager::setDeviceSerialNumber(m_target, serialNumber);
|
AndroidManager::setDeviceSerialNumber(m_target, serialNumber);
|
||||||
emit asyncStart(m_androidRunnable);
|
emit asyncStart();
|
||||||
} else if (!config.isConnected(serialNumber)) {
|
} else if (!config.isConnected(serialNumber)) {
|
||||||
// device was disconnected
|
// device was disconnected
|
||||||
m_checkAVDTimer.stop();
|
m_checkAVDTimer.stop();
|
||||||
|
@@ -64,12 +64,11 @@ public:
|
|||||||
void stop() override;
|
void stop() override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void asyncStart(const AndroidRunnable &runnable);
|
void asyncStart();
|
||||||
void asyncStop(const AndroidRunnable &runnable);
|
void asyncStop();
|
||||||
void remoteDebuggerRunning();
|
void remoteDebuggerRunning();
|
||||||
void qmlServerReady(const QUrl &serverUrl);
|
void qmlServerReady(const QUrl &serverUrl);
|
||||||
|
void androidRunnableChanged(const AndroidRunnable &runnable);
|
||||||
void adbParametersChanged(const QString &packageName, const QStringList &selector);
|
|
||||||
void avdDetected();
|
void avdDetected();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -35,7 +35,17 @@ namespace Internal {
|
|||||||
TestOutputReader *QtTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
|
TestOutputReader *QtTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
|
||||||
QProcess *app) const
|
QProcess *app) const
|
||||||
{
|
{
|
||||||
return new QtTestOutputReader(fi, app, buildDirectory());
|
static const Core::Id id
|
||||||
|
= Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QtTest::Constants::FRAMEWORK_NAME);
|
||||||
|
TestFrameworkManager *manager = TestFrameworkManager::instance();
|
||||||
|
auto qtSettings = qSharedPointerCast<QtTestSettings>(manager->settingsForTestFramework(id));
|
||||||
|
if (qtSettings.isNull())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (qtSettings->useXMLOutput)
|
||||||
|
return new QtTestOutputReader(fi, app, buildDirectory(), QtTestOutputReader::XML);
|
||||||
|
else
|
||||||
|
return new QtTestOutputReader(fi, app, buildDirectory(), QtTestOutputReader::PlainText);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList QtTestConfiguration::argumentsForTestRunner() const
|
QStringList QtTestConfiguration::argumentsForTestRunner() const
|
||||||
@@ -43,14 +53,15 @@ QStringList QtTestConfiguration::argumentsForTestRunner() const
|
|||||||
static const Core::Id id
|
static const Core::Id id
|
||||||
= Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QtTest::Constants::FRAMEWORK_NAME);
|
= Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QtTest::Constants::FRAMEWORK_NAME);
|
||||||
|
|
||||||
QStringList arguments("-xml");
|
QStringList arguments;
|
||||||
if (testCases().count())
|
|
||||||
arguments << testCases();
|
|
||||||
|
|
||||||
TestFrameworkManager *manager = TestFrameworkManager::instance();
|
TestFrameworkManager *manager = TestFrameworkManager::instance();
|
||||||
auto qtSettings = qSharedPointerCast<QtTestSettings>(manager->settingsForTestFramework(id));
|
auto qtSettings = qSharedPointerCast<QtTestSettings>(manager->settingsForTestFramework(id));
|
||||||
if (qtSettings.isNull())
|
if (qtSettings.isNull())
|
||||||
return arguments;
|
return arguments;
|
||||||
|
if (qtSettings->useXMLOutput)
|
||||||
|
arguments << "-xml";
|
||||||
|
if (testCases().count())
|
||||||
|
arguments << testCases();
|
||||||
|
|
||||||
const QString &metricsOption = QtTestSettings::metricsTypeToOption(qtSettings->metrics);
|
const QString &metricsOption = QtTestSettings::metricsTypeToOption(qtSettings->metrics);
|
||||||
if (!metricsOption.isEmpty())
|
if (!metricsOption.isEmpty())
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QRegExp>
|
#include <QRegExp>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
namespace Autotest {
|
namespace Autotest {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -128,12 +129,26 @@ static QString constructSourceFilePath(const QString &path, const QString &fileP
|
|||||||
}
|
}
|
||||||
|
|
||||||
QtTestOutputReader::QtTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
|
QtTestOutputReader::QtTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
|
||||||
QProcess *testApplication, const QString &buildDirectory)
|
QProcess *testApplication, const QString &buildDirectory,
|
||||||
|
OutputMode mode)
|
||||||
: TestOutputReader(futureInterface, testApplication, buildDirectory)
|
: TestOutputReader(futureInterface, testApplication, buildDirectory)
|
||||||
|
, m_mode(mode)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtTestOutputReader::processOutput(const QByteArray &outputLine)
|
void QtTestOutputReader::processOutput(const QByteArray &outputLine)
|
||||||
|
{
|
||||||
|
switch (m_mode) {
|
||||||
|
case PlainText:
|
||||||
|
processPlainTextOutput(outputLine);
|
||||||
|
break;
|
||||||
|
case XML:
|
||||||
|
processXMLOutput(outputLine);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtTestOutputReader::processXMLOutput(const QByteArray &outputLine)
|
||||||
{
|
{
|
||||||
static QStringList validEndTags = {QStringLiteral("Incident"),
|
static QStringList validEndTags = {QStringLiteral("Incident"),
|
||||||
QStringLiteral("Message"),
|
QStringLiteral("Message"),
|
||||||
@@ -162,24 +177,14 @@ void QtTestOutputReader::processOutput(const QByteArray &outputLine)
|
|||||||
if (currentTag == QStringLiteral("TestCase")) {
|
if (currentTag == QStringLiteral("TestCase")) {
|
||||||
m_className = m_xmlReader.attributes().value(QStringLiteral("name")).toString();
|
m_className = m_xmlReader.attributes().value(QStringLiteral("name")).toString();
|
||||||
QTC_ASSERT(!m_className.isEmpty(), continue);
|
QTC_ASSERT(!m_className.isEmpty(), continue);
|
||||||
TestResultPtr testResult = TestResultPtr(createDefaultResult());
|
sendStartMessage(false);
|
||||||
testResult->setResult(Result::MessageTestCaseStart);
|
|
||||||
testResult->setDescription(tr("Executing test case %1").arg(m_className));
|
|
||||||
m_futureInterface.reportResult(testResult);
|
|
||||||
} else if (currentTag == QStringLiteral("TestFunction")) {
|
} else if (currentTag == QStringLiteral("TestFunction")) {
|
||||||
m_testCase = m_xmlReader.attributes().value(QStringLiteral("name")).toString();
|
m_testCase = m_xmlReader.attributes().value(QStringLiteral("name")).toString();
|
||||||
QTC_ASSERT(!m_testCase.isEmpty(), continue);
|
QTC_ASSERT(!m_testCase.isEmpty(), continue);
|
||||||
if (m_testCase == m_formerTestCase) // don't report "Executing..." more than once
|
if (m_testCase == m_formerTestCase) // don't report "Executing..." more than once
|
||||||
continue;
|
continue;
|
||||||
TestResultPtr testResult = TestResultPtr(createDefaultResult());
|
sendStartMessage(true);
|
||||||
testResult->setResult(Result::MessageTestCaseStart);
|
sendMessageCurrentTest();
|
||||||
testResult->setDescription(tr("Executing test function %1").arg(m_testCase));
|
|
||||||
m_futureInterface.reportResult(testResult);
|
|
||||||
testResult = TestResultPtr(new QtTestResult);
|
|
||||||
testResult->setResult(Result::MessageCurrentTest);
|
|
||||||
testResult->setDescription(tr("Entering test function %1::%2").arg(m_className,
|
|
||||||
m_testCase));
|
|
||||||
m_futureInterface.reportResult(testResult);
|
|
||||||
} else if (currentTag == QStringLiteral("Duration")) {
|
} else if (currentTag == QStringLiteral("Duration")) {
|
||||||
m_duration = m_xmlReader.attributes().value(QStringLiteral("msecs")).toString();
|
m_duration = m_xmlReader.attributes().value(QStringLiteral("msecs")).toString();
|
||||||
QTC_ASSERT(!m_duration.isEmpty(), continue);
|
QTC_ASSERT(!m_duration.isEmpty(), continue);
|
||||||
@@ -255,23 +260,13 @@ void QtTestOutputReader::processOutput(const QByteArray &outputLine)
|
|||||||
m_cdataMode = None;
|
m_cdataMode = None;
|
||||||
const QStringRef currentTag = m_xmlReader.name();
|
const QStringRef currentTag = m_xmlReader.name();
|
||||||
if (currentTag == QStringLiteral("TestFunction")) {
|
if (currentTag == QStringLiteral("TestFunction")) {
|
||||||
QtTestResult *testResult = createDefaultResult();
|
sendFinishMessage(true);
|
||||||
testResult->setResult(Result::MessageTestCaseEnd);
|
|
||||||
testResult->setDescription(
|
|
||||||
m_duration.isEmpty() ? tr("Test function finished.")
|
|
||||||
: tr("Execution took %1 ms.").arg(m_duration));
|
|
||||||
m_futureInterface.reportResult(TestResultPtr(testResult));
|
|
||||||
m_futureInterface.setProgressValue(m_futureInterface.progressValue() + 1);
|
m_futureInterface.setProgressValue(m_futureInterface.progressValue() + 1);
|
||||||
m_dataTag.clear();
|
m_dataTag.clear();
|
||||||
m_formerTestCase = m_testCase;
|
m_formerTestCase = m_testCase;
|
||||||
m_testCase.clear();
|
m_testCase.clear();
|
||||||
} else if (currentTag == QStringLiteral("TestCase")) {
|
} else if (currentTag == QStringLiteral("TestCase")) {
|
||||||
QtTestResult *testResult = createDefaultResult();
|
sendFinishMessage(false);
|
||||||
testResult->setResult(Result::MessageTestCaseEnd);
|
|
||||||
testResult->setDescription(
|
|
||||||
m_duration.isEmpty() ? tr("Test finished.")
|
|
||||||
: tr("Test execution took %1 ms.").arg(m_duration));
|
|
||||||
m_futureInterface.reportResult(TestResultPtr(testResult));
|
|
||||||
} else if (validEndTags.contains(currentTag.toString())) {
|
} else if (validEndTags.contains(currentTag.toString())) {
|
||||||
QtTestResult *testResult = createDefaultResult();
|
QtTestResult *testResult = createDefaultResult();
|
||||||
testResult->setResult(m_result);
|
testResult->setResult(m_result);
|
||||||
@@ -290,6 +285,138 @@ void QtTestOutputReader::processOutput(const QByteArray &outputLine)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QStringList extractFunctionInformation(const QString &testClassName,
|
||||||
|
const QString &lineWithoutResultType,
|
||||||
|
Result::Type resultType)
|
||||||
|
{
|
||||||
|
static QRegularExpression classInformation("^(.+?)\\((.*?)\\)(.*)$");
|
||||||
|
QStringList result;
|
||||||
|
const QRegularExpressionMatch match = classInformation.match(lineWithoutResultType);
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
QString fullQualifiedFunc = match.captured(1);
|
||||||
|
QTC_ASSERT(fullQualifiedFunc.startsWith(testClassName + "::"), return result);
|
||||||
|
fullQualifiedFunc = fullQualifiedFunc.mid(testClassName.length() + 2);
|
||||||
|
result.append(fullQualifiedFunc);
|
||||||
|
if (resultType == Result::Benchmark) { // tag is displayed differently
|
||||||
|
QString possiblyTag = match.captured(3);
|
||||||
|
if (!possiblyTag.isEmpty())
|
||||||
|
possiblyTag = possiblyTag.mid(2, possiblyTag.length() - 4);
|
||||||
|
result.append(possiblyTag);
|
||||||
|
result.append(QString());
|
||||||
|
} else {
|
||||||
|
result.append(match.captured(2));
|
||||||
|
result.append(match.captured(3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtTestOutputReader::processPlainTextOutput(const QByteArray &outputLine)
|
||||||
|
{
|
||||||
|
static QRegExp start("^[*]{9} Start testing of (.*) [*]{9}$");
|
||||||
|
static QRegExp config("^Config: Using QtTest library (.*), (Qt (\\d+(\\.\\d+){2}) \\(.*\\))$");
|
||||||
|
static QRegExp summary("^Totals: \\d+ passed, \\d+ failed, \\d+ skipped(, \\d+ blacklisted)?$");
|
||||||
|
static QRegExp finish("^[*]{9} Finished testing of (.*) [*]{9}$");
|
||||||
|
|
||||||
|
static QRegExp result("^(PASS |FAIL! |XFAIL |XPASS |SKIP |BPASS |BFAIL |RESULT "
|
||||||
|
"|INFO |QWARN |WARNING|QDEBUG ): (.*)$");
|
||||||
|
|
||||||
|
static QRegExp benchDetails("^\\s+([\\d,.]+ .* per iteration \\(total: [\\d,.]+, iterations: \\d+\\))$");
|
||||||
|
static QRegExp locationUnix("^ Loc: \\[(.*)\\]$");
|
||||||
|
static QRegExp locationWin("^(.*\\(\\d+\\)) : failure location$");
|
||||||
|
|
||||||
|
if (m_futureInterface.isCanceled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QString &line = QString::fromLatin1(outputLine);
|
||||||
|
|
||||||
|
if (result.exactMatch(line)) {
|
||||||
|
processResultOutput(result.cap(1).toLower().trimmed(), result.cap(2));
|
||||||
|
} else if (locationUnix.exactMatch(line)) {
|
||||||
|
processLocationOutput(locationUnix.cap(1));
|
||||||
|
} else if (locationWin.exactMatch(line)) {
|
||||||
|
processLocationOutput(locationWin.cap(1));
|
||||||
|
} else if (benchDetails.exactMatch(line)) {
|
||||||
|
m_description = benchDetails.cap(1);
|
||||||
|
} else if (config.exactMatch(line)) {
|
||||||
|
handleAndSendConfigMessage(config);
|
||||||
|
} else if (start.exactMatch(line)) {
|
||||||
|
m_className = start.cap(1);
|
||||||
|
QTC_CHECK(!m_className.isEmpty());
|
||||||
|
sendStartMessage(false);
|
||||||
|
} else if (summary.exactMatch(line) || finish.exactMatch(line)) {
|
||||||
|
processSummaryFinishOutput();
|
||||||
|
} else { // we have some plain output, but we cannot say where for sure it belongs to..
|
||||||
|
if (!m_description.isEmpty())
|
||||||
|
m_description.append('\n');
|
||||||
|
m_description.append(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtTestOutputReader::processResultOutput(const QString &result, const QString &message)
|
||||||
|
{
|
||||||
|
if (!m_testCase.isEmpty()) { // report the former result if there is any
|
||||||
|
sendCompleteInformation();
|
||||||
|
m_dataTag.clear();
|
||||||
|
m_description.clear();
|
||||||
|
m_file.clear();
|
||||||
|
m_lineNumber = 0;
|
||||||
|
}
|
||||||
|
m_result = TestResult::resultFromString(result);
|
||||||
|
const QStringList funcWithTag = extractFunctionInformation(m_className, message, m_result);
|
||||||
|
QTC_ASSERT(funcWithTag.size() == 3, return);
|
||||||
|
m_testCase = funcWithTag.at(0);
|
||||||
|
if (m_testCase != m_formerTestCase) { // new test function executed
|
||||||
|
if (!m_formerTestCase.isEmpty()) {
|
||||||
|
using namespace std;
|
||||||
|
swap(m_testCase, m_formerTestCase); // we want formerTestCase to be reported
|
||||||
|
sendFinishMessage(true);
|
||||||
|
swap(m_testCase, m_formerTestCase);
|
||||||
|
}
|
||||||
|
sendStartMessage(true);
|
||||||
|
sendMessageCurrentTest();
|
||||||
|
}
|
||||||
|
m_dataTag = funcWithTag.at(1);
|
||||||
|
const QString description = funcWithTag.at(2);
|
||||||
|
if (!description.isEmpty()) {
|
||||||
|
if (!m_description.isEmpty())
|
||||||
|
m_description.append('\n');
|
||||||
|
m_description.append(description.mid(1)); // cut the first whitespace
|
||||||
|
}
|
||||||
|
m_formerTestCase = m_testCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtTestOutputReader::processLocationOutput(const QString &fileWithLine)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(fileWithLine.endsWith(')'), return);
|
||||||
|
int openBrace = fileWithLine.lastIndexOf('(');
|
||||||
|
QTC_ASSERT(openBrace != -1, return);
|
||||||
|
m_file = constructSourceFilePath(m_buildDir, fileWithLine.left(openBrace));
|
||||||
|
QString numberStr = fileWithLine.mid(openBrace + 1);
|
||||||
|
numberStr.chop(1);
|
||||||
|
m_lineNumber = numberStr.toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtTestOutputReader::processSummaryFinishOutput()
|
||||||
|
{
|
||||||
|
if (m_className.isEmpty()) // we have reported already
|
||||||
|
return;
|
||||||
|
// we still have something to report
|
||||||
|
sendCompleteInformation();
|
||||||
|
m_dataTag.clear();
|
||||||
|
// report finished function
|
||||||
|
sendFinishMessage(true);
|
||||||
|
m_testCase.clear();
|
||||||
|
m_formerTestCase.clear();
|
||||||
|
// create and report the finish message for this test class
|
||||||
|
sendFinishMessage(false);
|
||||||
|
m_className.clear();
|
||||||
|
m_description.clear();
|
||||||
|
m_result = Result::Invalid;
|
||||||
|
m_file.clear();
|
||||||
|
m_lineNumber = 0;
|
||||||
|
}
|
||||||
|
|
||||||
QtTestResult *QtTestOutputReader::createDefaultResult() const
|
QtTestResult *QtTestOutputReader::createDefaultResult() const
|
||||||
{
|
{
|
||||||
QtTestResult *result = new QtTestResult(m_className);
|
QtTestResult *result = new QtTestResult(m_className);
|
||||||
@@ -298,5 +425,63 @@ QtTestResult *QtTestOutputReader::createDefaultResult() const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QtTestOutputReader::sendCompleteInformation()
|
||||||
|
{
|
||||||
|
TestResultPtr testResult = TestResultPtr(createDefaultResult());
|
||||||
|
testResult->setResult(m_result);
|
||||||
|
testResult->setFileName(m_file);
|
||||||
|
testResult->setLine(m_lineNumber);
|
||||||
|
testResult->setDescription(m_description);
|
||||||
|
m_futureInterface.reportResult(testResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtTestOutputReader::sendMessageCurrentTest()
|
||||||
|
{
|
||||||
|
TestResultPtr testResult = TestResultPtr(new QtTestResult);
|
||||||
|
testResult->setResult(Result::MessageCurrentTest);
|
||||||
|
testResult->setDescription(tr("Entering test function %1::%2").arg(m_className, m_testCase));
|
||||||
|
m_futureInterface.reportResult(testResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtTestOutputReader::sendStartMessage(bool isFunction)
|
||||||
|
{
|
||||||
|
TestResultPtr testResult = TestResultPtr(createDefaultResult());
|
||||||
|
testResult->setResult(Result::MessageTestCaseStart);
|
||||||
|
testResult->setDescription(isFunction ? tr("Executing test function %1").arg(m_testCase)
|
||||||
|
: tr("Executing test case %1").arg(m_className));
|
||||||
|
m_futureInterface.reportResult(testResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtTestOutputReader::sendFinishMessage(bool isFunction)
|
||||||
|
{
|
||||||
|
TestResultPtr testResult = TestResultPtr(createDefaultResult());
|
||||||
|
testResult->setResult(Result::MessageTestCaseEnd);
|
||||||
|
if (m_duration.isEmpty()) {
|
||||||
|
testResult->setDescription(isFunction ? tr("Execution took %1 ms.").arg(m_duration)
|
||||||
|
: tr("Test execution took %1 ms.").arg(m_duration));
|
||||||
|
} else {
|
||||||
|
testResult->setDescription(isFunction ? tr("Test function finished.")
|
||||||
|
: tr("Test finished."));
|
||||||
|
}
|
||||||
|
m_futureInterface.reportResult(testResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO factor out tr() strings to avoid duplication (see XML processing of Characters)
|
||||||
|
void QtTestOutputReader::handleAndSendConfigMessage(const QRegExp &config)
|
||||||
|
{
|
||||||
|
QtTestResult *testResult = createDefaultResult();
|
||||||
|
testResult->setResult(Result::MessageInternal);
|
||||||
|
testResult->setDescription(tr("Qt version: %1").arg(config.cap(3)));
|
||||||
|
m_futureInterface.reportResult(TestResultPtr(testResult));
|
||||||
|
testResult = createDefaultResult();
|
||||||
|
testResult->setResult(Result::MessageInternal);
|
||||||
|
testResult->setDescription(tr("Qt build: %1").arg(config.cap(2)));
|
||||||
|
m_futureInterface.reportResult(TestResultPtr(testResult));
|
||||||
|
testResult = createDefaultResult();
|
||||||
|
testResult->setResult(Result::MessageInternal);
|
||||||
|
testResult->setDescription(tr("QTest version: %1").arg(config.cap(1)));
|
||||||
|
m_futureInterface.reportResult(TestResultPtr(testResult));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Autotest
|
} // namespace Autotest
|
||||||
|
@@ -40,14 +40,32 @@ class QtTestOutputReader : public TestOutputReader
|
|||||||
Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::QtTestOutputReader)
|
Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::QtTestOutputReader)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum OutputMode
|
||||||
|
{
|
||||||
|
XML,
|
||||||
|
PlainText
|
||||||
|
};
|
||||||
|
|
||||||
QtTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
|
QtTestOutputReader(const QFutureInterface<TestResultPtr> &futureInterface,
|
||||||
QProcess *testApplication, const QString &buildDirectory);
|
QProcess *testApplication, const QString &buildDirectory,
|
||||||
|
OutputMode mode);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void processOutput(const QByteArray &outputLine) override;
|
void processOutput(const QByteArray &outputLine) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void processXMLOutput(const QByteArray &outputLine);
|
||||||
|
void processPlainTextOutput(const QByteArray &outputLine);
|
||||||
|
void processResultOutput(const QString &result, const QString &message);
|
||||||
|
void processLocationOutput(const QString &fileWithLine);
|
||||||
|
void processSummaryFinishOutput();
|
||||||
|
// helper functions
|
||||||
QtTestResult *createDefaultResult() const;
|
QtTestResult *createDefaultResult() const;
|
||||||
|
void sendCompleteInformation();
|
||||||
|
void sendMessageCurrentTest();
|
||||||
|
void sendStartMessage(bool isFunction);
|
||||||
|
void sendFinishMessage(bool isFunction);
|
||||||
|
void handleAndSendConfigMessage(const QRegExp &config);
|
||||||
|
|
||||||
enum CDATAMode
|
enum CDATAMode
|
||||||
{
|
{
|
||||||
@@ -70,6 +88,8 @@ private:
|
|||||||
int m_lineNumber = 0;
|
int m_lineNumber = 0;
|
||||||
QString m_duration;
|
QString m_duration;
|
||||||
QXmlStreamReader m_xmlReader;
|
QXmlStreamReader m_xmlReader;
|
||||||
|
OutputMode m_mode = XML;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -30,6 +30,7 @@ namespace Internal {
|
|||||||
|
|
||||||
static const char metricsKey[] = "Metrics";
|
static const char metricsKey[] = "Metrics";
|
||||||
static const char noCrashhandlerKey[] = "NoCrashhandlerOnDebug";
|
static const char noCrashhandlerKey[] = "NoCrashhandlerOnDebug";
|
||||||
|
static const char useXMLOutputKey[] = "UseXMLOutput";
|
||||||
|
|
||||||
static MetricsType intToMetrics(int value)
|
static MetricsType intToMetrics(int value)
|
||||||
{
|
{
|
||||||
@@ -58,12 +59,14 @@ void QtTestSettings::fromFrameworkSettings(const QSettings *s)
|
|||||||
{
|
{
|
||||||
metrics = intToMetrics(s->value(metricsKey, Walltime).toInt());
|
metrics = intToMetrics(s->value(metricsKey, Walltime).toInt());
|
||||||
noCrashHandler = s->value(noCrashhandlerKey, true).toBool();
|
noCrashHandler = s->value(noCrashhandlerKey, true).toBool();
|
||||||
|
useXMLOutput = s->value(useXMLOutputKey, true).toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtTestSettings::toFrameworkSettings(QSettings *s) const
|
void QtTestSettings::toFrameworkSettings(QSettings *s) const
|
||||||
{
|
{
|
||||||
s->setValue(metricsKey, metrics);
|
s->setValue(metricsKey, metrics);
|
||||||
s->setValue(noCrashhandlerKey, noCrashHandler);
|
s->setValue(noCrashhandlerKey, noCrashHandler);
|
||||||
|
s->setValue(useXMLOutputKey, useXMLOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QtTestSettings::metricsTypeToOption(const MetricsType type)
|
QString QtTestSettings::metricsTypeToOption(const MetricsType type)
|
||||||
|
@@ -48,6 +48,7 @@ public:
|
|||||||
|
|
||||||
MetricsType metrics = Walltime;
|
MetricsType metrics = Walltime;
|
||||||
bool noCrashHandler = true;
|
bool noCrashHandler = true;
|
||||||
|
bool useXMLOutput = true;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void fromFrameworkSettings(const QSettings *s) override;
|
void fromFrameworkSettings(const QSettings *s) override;
|
||||||
|
@@ -46,6 +46,7 @@ QtTestSettingsWidget::QtTestSettingsWidget(QWidget *parent)
|
|||||||
void QtTestSettingsWidget::setSettings(const QtTestSettings &settings)
|
void QtTestSettingsWidget::setSettings(const QtTestSettings &settings)
|
||||||
{
|
{
|
||||||
m_ui.disableCrashhandlerCB->setChecked(settings.noCrashHandler);
|
m_ui.disableCrashhandlerCB->setChecked(settings.noCrashHandler);
|
||||||
|
m_ui.useXMLOutputCB->setChecked(settings.useXMLOutput);
|
||||||
switch (settings.metrics) {
|
switch (settings.metrics) {
|
||||||
case MetricsType::Walltime:
|
case MetricsType::Walltime:
|
||||||
m_ui.walltimeRB->setChecked(true);
|
m_ui.walltimeRB->setChecked(true);
|
||||||
@@ -72,6 +73,7 @@ QtTestSettings QtTestSettingsWidget::settings() const
|
|||||||
QtTestSettings result;
|
QtTestSettings result;
|
||||||
|
|
||||||
result.noCrashHandler = m_ui.disableCrashhandlerCB->isChecked();
|
result.noCrashHandler = m_ui.disableCrashhandlerCB->isChecked();
|
||||||
|
result.useXMLOutput = m_ui.useXMLOutputCB->isChecked();
|
||||||
if (m_ui.walltimeRB->isChecked())
|
if (m_ui.walltimeRB->isChecked())
|
||||||
result.metrics = MetricsType::Walltime;
|
result.metrics = MetricsType::Walltime;
|
||||||
else if (m_ui.tickcounterRB->isChecked())
|
else if (m_ui.tickcounterRB->isChecked())
|
||||||
|
@@ -31,6 +31,21 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="useXMLOutputCB">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>XML output recommended as it avoids parsing issues, while plain text is more human readable.
|
||||||
|
|
||||||
|
Warning: Plain text output is missing some information (e.g. duration)</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Use XML output</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
|
@@ -35,7 +35,16 @@ namespace Internal {
|
|||||||
TestOutputReader *QuickTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
|
TestOutputReader *QuickTestConfiguration::outputReader(const QFutureInterface<TestResultPtr> &fi,
|
||||||
QProcess *app) const
|
QProcess *app) const
|
||||||
{
|
{
|
||||||
return new QtTestOutputReader(fi, app, buildDirectory());
|
static const Core::Id id
|
||||||
|
= Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QtTest::Constants::FRAMEWORK_NAME);
|
||||||
|
TestFrameworkManager *manager = TestFrameworkManager::instance();
|
||||||
|
auto qtSettings = qSharedPointerCast<QtTestSettings>(manager->settingsForTestFramework(id));
|
||||||
|
if (qtSettings.isNull())
|
||||||
|
return nullptr;
|
||||||
|
if (qtSettings->useXMLOutput)
|
||||||
|
return new QtTestOutputReader(fi, app, buildDirectory(), QtTestOutputReader::XML);
|
||||||
|
else
|
||||||
|
return new QtTestOutputReader(fi, app, buildDirectory(), QtTestOutputReader::PlainText);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList QuickTestConfiguration::argumentsForTestRunner() const
|
QStringList QuickTestConfiguration::argumentsForTestRunner() const
|
||||||
@@ -43,14 +52,15 @@ QStringList QuickTestConfiguration::argumentsForTestRunner() const
|
|||||||
static const Core::Id id
|
static const Core::Id id
|
||||||
= Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QtTest::Constants::FRAMEWORK_NAME);
|
= Core::Id(Constants::FRAMEWORK_PREFIX).withSuffix(QtTest::Constants::FRAMEWORK_NAME);
|
||||||
|
|
||||||
QStringList arguments("-xml");
|
QStringList arguments;
|
||||||
if (testCases().count())
|
|
||||||
arguments << testCases();
|
|
||||||
|
|
||||||
TestFrameworkManager *manager = TestFrameworkManager::instance();
|
TestFrameworkManager *manager = TestFrameworkManager::instance();
|
||||||
auto qtSettings = qSharedPointerCast<QtTestSettings>(manager->settingsForTestFramework(id));
|
auto qtSettings = qSharedPointerCast<QtTestSettings>(manager->settingsForTestFramework(id));
|
||||||
if (qtSettings.isNull())
|
if (qtSettings.isNull())
|
||||||
return arguments;
|
return arguments;
|
||||||
|
if (qtSettings->useXMLOutput)
|
||||||
|
arguments << "-xml";
|
||||||
|
if (testCases().count())
|
||||||
|
arguments << testCases();
|
||||||
|
|
||||||
const QString &metricsOption = QtTestSettings::metricsTypeToOption(qtSettings->metrics);
|
const QString &metricsOption = QtTestSettings::metricsTypeToOption(qtSettings->metrics);
|
||||||
if (!metricsOption.isEmpty())
|
if (!metricsOption.isEmpty())
|
||||||
|
@@ -56,7 +56,7 @@ Result::Type TestResult::resultFromString(const QString &resultString)
|
|||||||
{
|
{
|
||||||
if (resultString == "pass")
|
if (resultString == "pass")
|
||||||
return Result::Pass;
|
return Result::Pass;
|
||||||
if (resultString == "fail")
|
if (resultString == "fail" || resultString == "fail!")
|
||||||
return Result::Fail;
|
return Result::Fail;
|
||||||
if (resultString == "xfail")
|
if (resultString == "xfail")
|
||||||
return Result::ExpectedFail;
|
return Result::ExpectedFail;
|
||||||
@@ -64,11 +64,13 @@ Result::Type TestResult::resultFromString(const QString &resultString)
|
|||||||
return Result::UnexpectedPass;
|
return Result::UnexpectedPass;
|
||||||
if (resultString == "skip")
|
if (resultString == "skip")
|
||||||
return Result::Skip;
|
return Result::Skip;
|
||||||
|
if (resultString == "result")
|
||||||
|
return Result::Benchmark;
|
||||||
if (resultString == "qdebug")
|
if (resultString == "qdebug")
|
||||||
return Result::MessageDebug;
|
return Result::MessageDebug;
|
||||||
if (resultString == "qinfo")
|
if (resultString == "qinfo" || resultString == "info")
|
||||||
return Result::MessageInfo;
|
return Result::MessageInfo;
|
||||||
if (resultString == "warn" || resultString == "qwarn")
|
if (resultString == "warn" || resultString == "qwarn" || resultString == "warning")
|
||||||
return Result::MessageWarn;
|
return Result::MessageWarn;
|
||||||
if (resultString == "qfatal")
|
if (resultString == "qfatal")
|
||||||
return Result::MessageFatal;
|
return Result::MessageFatal;
|
||||||
|
@@ -313,7 +313,7 @@ TestResultItem *TestResultModel::findParentItemFor(const TestResultItem *item,
|
|||||||
TestResultItem *currentItem = static_cast<TestResultItem *>(it);
|
TestResultItem *currentItem = static_cast<TestResultItem *>(it);
|
||||||
return currentItem->testResult()->isDirectParentOf(result, &needsIntermediate);
|
return currentItem->testResult()->isDirectParentOf(result, &needsIntermediate);
|
||||||
};
|
};
|
||||||
TestResultItem *parent = static_cast<TestResultItem *>(root->findAnyChild(predicate));
|
TestResultItem *parent = static_cast<TestResultItem *>(root->reverseFindAnyChild(predicate));
|
||||||
if (parent) {
|
if (parent) {
|
||||||
if (needsIntermediate) {
|
if (needsIntermediate) {
|
||||||
// check if the intermediate is present already
|
// check if the intermediate is present already
|
||||||
|
@@ -378,7 +378,8 @@ void TestRunner::debugTests()
|
|||||||
outputreader, &QObject::deleteLater);
|
outputreader, &QObject::deleteLater);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(this, &TestRunner::requestStopTestRun, runControl, &ProjectExplorer::RunControl::stop);
|
connect(this, &TestRunner::requestStopTestRun, runControl,
|
||||||
|
&ProjectExplorer::RunControl::initiateStop);
|
||||||
connect(runControl, &ProjectExplorer::RunControl::finished, this, &TestRunner::onFinished);
|
connect(runControl, &ProjectExplorer::RunControl::finished, this, &TestRunner::onFinished);
|
||||||
ProjectExplorer::ProjectExplorerPlugin::startRunControl(runControl);
|
ProjectExplorer::ProjectExplorerPlugin::startRunControl(runControl);
|
||||||
}
|
}
|
||||||
|
@@ -79,7 +79,7 @@ ClangStaticAnalyzerToolRunner::ClangStaticAnalyzerToolRunner(RunControl *runCont
|
|||||||
|
|
||||||
RunConfiguration *runConfiguration = runControl->runConfiguration();
|
RunConfiguration *runConfiguration = runControl->runConfiguration();
|
||||||
auto tool = ClangStaticAnalyzerTool::instance();
|
auto tool = ClangStaticAnalyzerTool::instance();
|
||||||
connect(tool->stopAction(), &QAction::triggered, runControl, &RunControl::stop);
|
connect(tool->stopAction(), &QAction::triggered, runControl, &RunControl::initiateStop);
|
||||||
|
|
||||||
ProjectInfo projectInfoBeforeBuild = tool->projectInfoBeforeBuild();
|
ProjectInfo projectInfoBeforeBuild = tool->projectInfoBeforeBuild();
|
||||||
QTC_ASSERT(projectInfoBeforeBuild.isValid(), return);
|
QTC_ASSERT(projectInfoBeforeBuild.isValid(), return);
|
||||||
|
@@ -28,9 +28,14 @@
|
|||||||
#include "editorarea.h"
|
#include "editorarea.h"
|
||||||
#include "editormanager_p.h"
|
#include "editormanager_p.h"
|
||||||
|
|
||||||
|
#include <aggregation/aggregate.h>
|
||||||
#include <coreplugin/icontext.h>
|
#include <coreplugin/icontext.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
#include <coreplugin/locator/locator.h>
|
||||||
|
#include <coreplugin/locator/locatorwidget.h>
|
||||||
|
#include <coreplugin/statusbarmanager.h>
|
||||||
|
|
||||||
|
#include <QStatusBar>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@@ -46,6 +51,14 @@ EditorWindow::EditorWindow(QWidget *parent) :
|
|||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
layout->addWidget(m_area);
|
layout->addWidget(m_area);
|
||||||
setFocusProxy(m_area);
|
setFocusProxy(m_area);
|
||||||
|
auto statusBar = new QStatusBar;
|
||||||
|
layout->addWidget(statusBar);
|
||||||
|
auto splitter = new NonResizingSplitter(statusBar);
|
||||||
|
splitter->setChildrenCollapsible(false);
|
||||||
|
statusBar->addPermanentWidget(splitter, 10);
|
||||||
|
auto locatorWidget = createStaticLocatorWidget(Locator::instance());
|
||||||
|
splitter->addWidget(locatorWidget);
|
||||||
|
splitter->addWidget(new QWidget);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
setAttribute(Qt::WA_QuitOnClose, false); // don't prevent Qt Creator from closing
|
setAttribute(Qt::WA_QuitOnClose, false); // don't prevent Qt Creator from closing
|
||||||
resize(QSize(800, 600));
|
resize(QSize(800, 600));
|
||||||
@@ -61,6 +74,11 @@ EditorWindow::EditorWindow(QWidget *parent) :
|
|||||||
deleteLater();
|
deleteLater();
|
||||||
});
|
});
|
||||||
updateWindowTitle();
|
updateWindowTitle();
|
||||||
|
|
||||||
|
// register locator widget for this window
|
||||||
|
auto agg = new Aggregation::Aggregate;
|
||||||
|
agg->add(this);
|
||||||
|
agg->add(locatorWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorWindow::~EditorWindow()
|
EditorWindow::~EditorWindow()
|
||||||
|
@@ -86,6 +86,11 @@ Locator::~Locator()
|
|||||||
qDeleteAll(m_customFilters);
|
qDeleteAll(m_customFilters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Locator *Locator::instance()
|
||||||
|
{
|
||||||
|
return m_instance;
|
||||||
|
}
|
||||||
|
|
||||||
void Locator::initialize(CorePlugin *corePlugin, const QStringList &, QString *)
|
void Locator::initialize(CorePlugin *corePlugin, const QStringList &, QString *)
|
||||||
{
|
{
|
||||||
m_corePlugin = corePlugin;
|
m_corePlugin = corePlugin;
|
||||||
@@ -103,15 +108,14 @@ void Locator::initialize(CorePlugin *corePlugin, const QStringList &, QString *)
|
|||||||
ActionContainer *mtools = ActionManager::actionContainer(Constants::M_TOOLS);
|
ActionContainer *mtools = ActionManager::actionContainer(Constants::M_TOOLS);
|
||||||
mtools->addAction(cmd);
|
mtools->addAction(cmd);
|
||||||
|
|
||||||
auto locatorWidget = new LocatorWidget(this);
|
m_locatorWidget = createStaticLocatorWidget(this);
|
||||||
new LocatorPopup(locatorWidget, locatorWidget); // child of locatorWidget
|
|
||||||
StatusBarWidget *view = new StatusBarWidget;
|
StatusBarWidget *view = new StatusBarWidget;
|
||||||
view->setWidget(locatorWidget);
|
view->setWidget(m_locatorWidget);
|
||||||
view->setContext(Context("LocatorWidget"));
|
view->setContext(Context("LocatorWidget"));
|
||||||
view->setPosition(StatusBarWidget::First);
|
view->setPosition(StatusBarWidget::First);
|
||||||
m_corePlugin->addAutoReleasedObject(view);
|
m_corePlugin->addAutoReleasedObject(view);
|
||||||
|
|
||||||
new LocatorManager(locatorWidget);
|
new LocatorManager(this);
|
||||||
|
|
||||||
m_openDocumentsFilter = new OpenDocumentsFilter;
|
m_openDocumentsFilter = new OpenDocumentsFilter;
|
||||||
m_corePlugin->addObject(m_openDocumentsFilter);
|
m_corePlugin->addObject(m_openDocumentsFilter);
|
||||||
@@ -135,6 +139,11 @@ void Locator::initialize(CorePlugin *corePlugin, const QStringList &, QString *)
|
|||||||
|
|
||||||
void Locator::extensionsInitialized()
|
void Locator::extensionsInitialized()
|
||||||
{
|
{
|
||||||
|
// register locator widget for main window
|
||||||
|
auto agg = new Aggregation::Aggregate;
|
||||||
|
agg->add(ICore::mainWindow());
|
||||||
|
agg->add(m_locatorWidget);
|
||||||
|
|
||||||
m_filters = ExtensionSystem::PluginManager::getObjects<ILocatorFilter>();
|
m_filters = ExtensionSystem::PluginManager::getObjects<ILocatorFilter>();
|
||||||
Utils::sort(m_filters, [](const ILocatorFilter *first, const ILocatorFilter *second) -> bool {
|
Utils::sort(m_filters, [](const ILocatorFilter *first, const ILocatorFilter *second) -> bool {
|
||||||
if (first->priority() != second->priority())
|
if (first->priority() != second->priority())
|
||||||
@@ -341,6 +350,11 @@ void Locator::setRefreshInterval(int interval)
|
|||||||
m_refreshTimer.start();
|
m_refreshTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocatorWidget *Locator::mainLocatorWidget()
|
||||||
|
{
|
||||||
|
return m_instance->m_locatorWidget;
|
||||||
|
}
|
||||||
|
|
||||||
void Locator::refresh(QList<ILocatorFilter *> filters)
|
void Locator::refresh(QList<ILocatorFilter *> filters)
|
||||||
{
|
{
|
||||||
if (filters.isEmpty())
|
if (filters.isEmpty())
|
||||||
|
@@ -43,6 +43,7 @@ class CorePlugin;
|
|||||||
class OpenDocumentsFilter;
|
class OpenDocumentsFilter;
|
||||||
class FileSystemFilter;
|
class FileSystemFilter;
|
||||||
class LocatorSettingsPage;
|
class LocatorSettingsPage;
|
||||||
|
class LocatorWidget;
|
||||||
class ExternalToolsFilter;
|
class ExternalToolsFilter;
|
||||||
|
|
||||||
class Locator : public QObject
|
class Locator : public QObject
|
||||||
@@ -53,6 +54,8 @@ public:
|
|||||||
Locator();
|
Locator();
|
||||||
~Locator();
|
~Locator();
|
||||||
|
|
||||||
|
static Locator *instance();
|
||||||
|
|
||||||
void initialize(CorePlugin *corePlugin, const QStringList &arguments, QString *errorMessage);
|
void initialize(CorePlugin *corePlugin, const QStringList &arguments, QString *errorMessage);
|
||||||
void extensionsInitialized();
|
void extensionsInitialized();
|
||||||
bool delayedInitialize();
|
bool delayedInitialize();
|
||||||
@@ -63,6 +66,7 @@ public:
|
|||||||
void setCustomFilters(QList<ILocatorFilter *> f);
|
void setCustomFilters(QList<ILocatorFilter *> f);
|
||||||
int refreshInterval();
|
int refreshInterval();
|
||||||
void setRefreshInterval(int interval);
|
void setRefreshInterval(int interval);
|
||||||
|
static LocatorWidget *mainLocatorWidget();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void filtersChanged();
|
void filtersChanged();
|
||||||
@@ -89,6 +93,7 @@ private:
|
|||||||
ExecuteFilter *m_executeFilter;
|
ExecuteFilter *m_executeFilter;
|
||||||
CorePlugin *m_corePlugin = nullptr;
|
CorePlugin *m_corePlugin = nullptr;
|
||||||
ExternalToolsFilter *m_externalToolsFilter;
|
ExternalToolsFilter *m_externalToolsFilter;
|
||||||
|
LocatorWidget *m_locatorWidget;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -29,29 +29,45 @@
|
|||||||
#include "locator.h"
|
#include "locator.h"
|
||||||
#include "locatorwidget.h"
|
#include "locatorwidget.h"
|
||||||
|
|
||||||
|
#include <aggregation/aggregate.h>
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
using namespace Core::Internal;
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
static Internal::LocatorWidget *m_locatorWidget = 0;
|
LocatorManager::LocatorManager(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
LocatorManager::LocatorManager(Internal::LocatorWidget *locatorWidget)
|
|
||||||
: QObject(locatorWidget)
|
|
||||||
{
|
{
|
||||||
m_locatorWidget = locatorWidget;
|
}
|
||||||
|
|
||||||
|
static LocatorWidget *locatorWidget()
|
||||||
|
{
|
||||||
|
static QPointer<LocatorPopup> popup;
|
||||||
|
QWidget *window = ICore::dialogParent()->window();
|
||||||
|
if (auto *widget = Aggregation::query<LocatorWidget>(window)) {
|
||||||
|
if (popup)
|
||||||
|
popup->close();
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
if (!popup) {
|
||||||
|
popup = createLocatorPopup(Locator::instance(), window);
|
||||||
|
popup->show();
|
||||||
|
}
|
||||||
|
return popup->inputWidget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocatorManager::showFilter(ILocatorFilter *filter)
|
void LocatorManager::showFilter(ILocatorFilter *filter)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(filter, return);
|
QTC_ASSERT(filter, return);
|
||||||
QTC_ASSERT(m_locatorWidget, return);
|
|
||||||
QString searchText = tr("<type here>");
|
QString searchText = tr("<type here>");
|
||||||
const QString currentText = m_locatorWidget->currentText().trimmed();
|
const QString currentText = locatorWidget()->currentText().trimmed();
|
||||||
// add shortcut string at front or replace existing shortcut string
|
// add shortcut string at front or replace existing shortcut string
|
||||||
if (!currentText.isEmpty()) {
|
if (!currentText.isEmpty()) {
|
||||||
searchText = currentText;
|
searchText = currentText;
|
||||||
foreach (ILocatorFilter *otherfilter, Internal::Locator::filters()) {
|
foreach (ILocatorFilter *otherfilter, Locator::filters()) {
|
||||||
if (currentText.startsWith(otherfilter->shortcutString() + QLatin1Char(' '))) {
|
if (currentText.startsWith(otherfilter->shortcutString() + QLatin1Char(' '))) {
|
||||||
searchText = currentText.mid(otherfilter->shortcutString().length() + 1);
|
searchText = currentText.mid(otherfilter->shortcutString().length() + 1);
|
||||||
break;
|
break;
|
||||||
@@ -66,8 +82,7 @@ void LocatorManager::showFilter(ILocatorFilter *filter)
|
|||||||
void LocatorManager::show(const QString &text,
|
void LocatorManager::show(const QString &text,
|
||||||
int selectionStart, int selectionLength)
|
int selectionStart, int selectionLength)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(m_locatorWidget, return);
|
locatorWidget()->showText(text, selectionStart, selectionLength);
|
||||||
m_locatorWidget->showText(text, selectionStart, selectionLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Core
|
||||||
|
@@ -40,7 +40,7 @@ class CORE_EXPORT LocatorManager : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LocatorManager(Internal::LocatorWidget *locatorWidget);
|
LocatorManager(QObject *parent = 0);
|
||||||
|
|
||||||
static void showFilter(ILocatorFilter *filter);
|
static void showFilter(ILocatorFilter *filter);
|
||||||
static void show(const QString &text, int selectionStart = -1, int selectionLength = 0);
|
static void show(const QString &text, int selectionStart = -1, int selectionLength = 0);
|
||||||
|
@@ -49,7 +49,9 @@
|
|||||||
#include <utils/stylehelper.h>
|
#include <utils/stylehelper.h>
|
||||||
#include <utils/utilsicons.h>
|
#include <utils/utilsicons.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
#include <QDesktopWidget>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
@@ -112,6 +114,28 @@ public:
|
|||||||
void showCurrentItemToolTip();
|
void showCurrentItemToolTip();
|
||||||
|
|
||||||
void keyPressEvent(QKeyEvent *event);
|
void keyPressEvent(QKeyEvent *event);
|
||||||
|
bool eventFilter(QObject *watched, QEvent *event);
|
||||||
|
};
|
||||||
|
|
||||||
|
class TopLeftLocatorPopup : public LocatorPopup
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TopLeftLocatorPopup(LocatorWidget *locatorWidget)
|
||||||
|
: LocatorPopup(locatorWidget, locatorWidget) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void updateGeometry() override;
|
||||||
|
void inputLostFocus() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CenteredLocatorPopup : public LocatorPopup
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CenteredLocatorPopup(LocatorWidget *locatorWidget, QWidget *parent)
|
||||||
|
: LocatorPopup(locatorWidget, parent) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void updateGeometry() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// =========== LocatorModel ===========
|
// =========== LocatorModel ===========
|
||||||
@@ -226,6 +250,8 @@ CompletionList::CompletionList(QWidget *parent)
|
|||||||
const QStyleOptionViewItem &option = viewOptions();
|
const QStyleOptionViewItem &option = viewOptions();
|
||||||
const QSize shint = itemDelegate()->sizeHint(option, QModelIndex());
|
const QSize shint = itemDelegate()->sizeHint(option, QModelIndex());
|
||||||
setFixedHeight(shint.height() * 17 + frameWidth() * 2);
|
setFixedHeight(shint.height() * 17 + frameWidth() * 2);
|
||||||
|
|
||||||
|
installEventFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompletionList::setModel(QAbstractItemModel *newModel)
|
void CompletionList::setModel(QAbstractItemModel *newModel)
|
||||||
@@ -241,20 +267,41 @@ void CompletionList::setModel(QAbstractItemModel *newModel)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocatorPopup::resize()
|
void LocatorPopup::updateGeometry()
|
||||||
{
|
{
|
||||||
static const int MIN_WIDTH = 730;
|
|
||||||
const QSize windowSize = m_window ? m_window->size() : QSize(MIN_WIDTH, 0);
|
|
||||||
|
|
||||||
const int width = qMax(MIN_WIDTH, windowSize.width() * 2 / 3);
|
|
||||||
m_preferredSize = QSize(width, sizeHint().height());
|
|
||||||
QWidget::resize(m_preferredSize);
|
|
||||||
m_tree->resizeHeaders();
|
m_tree->resizeHeaders();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize LocatorPopup::preferredSize() const
|
void TopLeftLocatorPopup::updateGeometry()
|
||||||
{
|
{
|
||||||
return m_preferredSize;
|
QTC_ASSERT(parentWidget(), return);
|
||||||
|
const QSize size = preferredSize();
|
||||||
|
const QRect rect(parentWidget()->mapToGlobal(QPoint(0, -size.height())), size);
|
||||||
|
setGeometry(rect);
|
||||||
|
LocatorPopup::updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CenteredLocatorPopup::updateGeometry()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(parentWidget(), return);
|
||||||
|
const QSize size = preferredSize();
|
||||||
|
const QSize parentSize = parentWidget()->size();
|
||||||
|
const QPoint pos = parentWidget()->mapToGlobal({(parentSize.width() - size.width()) / 2,
|
||||||
|
parentSize.height() / 2 - size.height()});
|
||||||
|
QRect rect(pos, size);
|
||||||
|
// invisible widget doesn't have the right screen set yet, so use the parent widget to
|
||||||
|
// check for available geometry
|
||||||
|
const QRect available = QApplication::desktop()->availableGeometry(parentWidget());
|
||||||
|
if (rect.right() > available.right())
|
||||||
|
rect.moveRight(available.right());
|
||||||
|
if (rect.bottom() > available.bottom())
|
||||||
|
rect.moveBottom(available.bottom());
|
||||||
|
if (rect.top() < available.top())
|
||||||
|
rect.moveTop(available.top());
|
||||||
|
if (rect.left() < available.left())
|
||||||
|
rect.moveLeft(available.left());
|
||||||
|
setGeometry(rect);
|
||||||
|
LocatorPopup::updateGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocatorPopup::updateWindow()
|
void LocatorPopup::updateWindow()
|
||||||
@@ -271,25 +318,36 @@ void LocatorPopup::updateWindow()
|
|||||||
|
|
||||||
bool LocatorPopup::event(QEvent *event)
|
bool LocatorPopup::event(QEvent *event)
|
||||||
{
|
{
|
||||||
if (event->type() == QEvent::ParentChange)
|
if (event->type() == QEvent::ParentChange) {
|
||||||
updateWindow();
|
updateWindow();
|
||||||
|
} else if (event->type() == QEvent::Show)
|
||||||
|
updateGeometry();
|
||||||
return QWidget::event(event);
|
return QWidget::event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LocatorPopup::eventFilter(QObject *watched, QEvent *event)
|
bool LocatorPopup::eventFilter(QObject *watched, QEvent *event)
|
||||||
{
|
{
|
||||||
if (watched == m_window && event->type() == QEvent::Resize)
|
if (watched == m_window && event->type() == QEvent::Resize)
|
||||||
resize();
|
updateGeometry();
|
||||||
return QWidget::eventFilter(watched, event);
|
return QWidget::eventFilter(watched, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocatorPopup::showPopup()
|
QSize LocatorPopup::preferredSize()
|
||||||
|
{
|
||||||
|
static const int MIN_WIDTH = 730;
|
||||||
|
const QSize windowSize = m_window ? m_window->size() : QSize(MIN_WIDTH, 0);
|
||||||
|
|
||||||
|
const int width = qMax(MIN_WIDTH, windowSize.width() * 2 / 3);
|
||||||
|
return QSize(width, sizeHint().height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TopLeftLocatorPopup::inputLostFocus()
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocatorPopup::inputLostFocus()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(parentWidget(), return);
|
|
||||||
const QSize size = preferredSize();
|
|
||||||
const QRect rect(parentWidget()->mapToGlobal(QPoint(0, -size.height())), size);
|
|
||||||
setGeometry(rect);
|
|
||||||
show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompletionList::resizeHeaders()
|
void CompletionList::resizeHeaders()
|
||||||
@@ -300,10 +358,9 @@ void CompletionList::resizeHeaders()
|
|||||||
|
|
||||||
LocatorPopup::LocatorPopup(LocatorWidget *locatorWidget, QWidget *parent)
|
LocatorPopup::LocatorPopup(LocatorWidget *locatorWidget, QWidget *parent)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
m_tree(new CompletionList(this))
|
m_tree(new CompletionList(this)),
|
||||||
|
m_inputWidget(locatorWidget)
|
||||||
{
|
{
|
||||||
setWindowFlags(Qt::ToolTip);
|
|
||||||
|
|
||||||
m_tree->setFrameStyle(QFrame::NoFrame);
|
m_tree->setFrameStyle(QFrame::NoFrame);
|
||||||
m_tree->setModel(locatorWidget->model());
|
m_tree->setModel(locatorWidget->model());
|
||||||
|
|
||||||
@@ -315,8 +372,9 @@ LocatorPopup::LocatorPopup(LocatorWidget *locatorWidget, QWidget *parent)
|
|||||||
layout->addWidget(m_tree);
|
layout->addWidget(m_tree);
|
||||||
|
|
||||||
connect(locatorWidget, &LocatorWidget::parentChanged, this, &LocatorPopup::updateWindow);
|
connect(locatorWidget, &LocatorWidget::parentChanged, this, &LocatorPopup::updateWindow);
|
||||||
connect(locatorWidget, &LocatorWidget::showPopup, this, &LocatorPopup::showPopup);
|
connect(locatorWidget, &LocatorWidget::showPopup, this, &LocatorPopup::show);
|
||||||
connect(locatorWidget, &LocatorWidget::hidePopup, this, &LocatorPopup::hide);
|
connect(locatorWidget, &LocatorWidget::hidePopup, this, &LocatorPopup::close);
|
||||||
|
connect(locatorWidget, &LocatorWidget::lostFocus, this, &LocatorPopup::inputLostFocus);
|
||||||
connect(locatorWidget, &LocatorWidget::selectRow, m_tree, [this](int row) {
|
connect(locatorWidget, &LocatorWidget::selectRow, m_tree, [this](int row) {
|
||||||
m_tree->setCurrentIndex(m_tree->model()->index(row, 0));
|
m_tree->setCurrentIndex(m_tree->model()->index(row, 0));
|
||||||
});
|
});
|
||||||
@@ -331,7 +389,7 @@ LocatorPopup::LocatorPopup(LocatorWidget *locatorWidget, QWidget *parent)
|
|||||||
locatorWidget->scheduleAcceptEntry(index);
|
locatorWidget->scheduleAcceptEntry(index);
|
||||||
});
|
});
|
||||||
|
|
||||||
resize();
|
updateGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
CompletionList *LocatorPopup::completionList() const
|
CompletionList *LocatorPopup::completionList() const
|
||||||
@@ -339,6 +397,11 @@ CompletionList *LocatorPopup::completionList() const
|
|||||||
return m_tree;
|
return m_tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocatorWidget *LocatorPopup::inputWidget() const
|
||||||
|
{
|
||||||
|
return m_inputWidget;
|
||||||
|
}
|
||||||
|
|
||||||
void LocatorPopup::focusOutEvent(QFocusEvent *event) {
|
void LocatorPopup::focusOutEvent(QFocusEvent *event) {
|
||||||
if (event->reason() == Qt::ActiveWindowFocusReason)
|
if (event->reason() == Qt::ActiveWindowFocusReason)
|
||||||
hide();
|
hide();
|
||||||
@@ -402,6 +465,22 @@ void CompletionList::keyPressEvent(QKeyEvent *event)
|
|||||||
Utils::TreeView::keyPressEvent(event);
|
Utils::TreeView::keyPressEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CompletionList::eventFilter(QObject *watched, QEvent *event)
|
||||||
|
{
|
||||||
|
if (watched == this && event->type() == QEvent::ShortcutOverride) {
|
||||||
|
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
|
||||||
|
switch (ke->key()) {
|
||||||
|
case Qt::Key_Escape:
|
||||||
|
if (!ke->modifiers()) {
|
||||||
|
event->accept();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Utils::TreeView::eventFilter(watched, event);
|
||||||
|
}
|
||||||
|
|
||||||
// =========== LocatorWidget ===========
|
// =========== LocatorWidget ===========
|
||||||
|
|
||||||
LocatorWidget::LocatorWidget(Locator *locator) :
|
LocatorWidget::LocatorWidget(Locator *locator) :
|
||||||
@@ -576,7 +655,7 @@ bool LocatorWidget::eventFilter(QObject *obj, QEvent *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (obj == m_fileLineEdit && event->type() == QEvent::FocusOut) {
|
} else if (obj == m_fileLineEdit && event->type() == QEvent::FocusOut) {
|
||||||
emit hidePopup();
|
emit lostFocus();
|
||||||
} else if (obj == m_fileLineEdit && event->type() == QEvent::FocusIn) {
|
} else if (obj == m_fileLineEdit && event->type() == QEvent::FocusIn) {
|
||||||
QFocusEvent *fev = static_cast<QFocusEvent *>(event);
|
QFocusEvent *fev = static_cast<QFocusEvent *>(event);
|
||||||
if (fev->reason() != Qt::ActiveWindowFocusReason)
|
if (fev->reason() != Qt::ActiveWindowFocusReason)
|
||||||
@@ -796,5 +875,23 @@ void LocatorWidget::addSearchResults(int firstIndex, int endIndex)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocatorWidget *createStaticLocatorWidget(Locator *locator)
|
||||||
|
{
|
||||||
|
auto widget = new LocatorWidget(locator);
|
||||||
|
auto popup = new TopLeftLocatorPopup(widget); // owned by widget
|
||||||
|
popup->setWindowFlags(Qt::ToolTip);
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocatorPopup *createLocatorPopup(Locator *locator, QWidget *parent)
|
||||||
|
{
|
||||||
|
auto widget = new LocatorWidget(locator);
|
||||||
|
auto popup = new CenteredLocatorPopup(widget, parent);
|
||||||
|
popup->layout()->addWidget(widget);
|
||||||
|
popup->setWindowFlags(Qt::Popup);
|
||||||
|
popup->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@@ -64,6 +64,7 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void showCurrentItemToolTip();
|
void showCurrentItemToolTip();
|
||||||
|
void lostFocus();
|
||||||
void hidePopup();
|
void hidePopup();
|
||||||
void selectRow(int row);
|
void selectRow(int row);
|
||||||
void handleKey(QKeyEvent *keyEvent); // only use with DirectConnection, event is deleted
|
void handleKey(QKeyEvent *keyEvent); // only use with DirectConnection, event is deleted
|
||||||
@@ -109,21 +110,28 @@ public:
|
|||||||
LocatorPopup(LocatorWidget *locatorWidget, QWidget *parent = 0);
|
LocatorPopup(LocatorWidget *locatorWidget, QWidget *parent = 0);
|
||||||
|
|
||||||
CompletionList *completionList() const;
|
CompletionList *completionList() const;
|
||||||
|
LocatorWidget *inputWidget() const;
|
||||||
|
|
||||||
void focusOutEvent (QFocusEvent *event) override;
|
void focusOutEvent (QFocusEvent *event) override;
|
||||||
void resize();
|
|
||||||
QSize preferredSize() const;
|
|
||||||
bool event(QEvent *event) override;
|
bool event(QEvent *event) override;
|
||||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QSize preferredSize();
|
||||||
|
virtual void updateGeometry();
|
||||||
|
virtual void inputLostFocus();
|
||||||
|
|
||||||
|
QPointer<QWidget> m_window;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void showPopup();
|
void updateWindow();
|
||||||
|
|
||||||
CompletionList *m_tree;
|
CompletionList *m_tree;
|
||||||
QSize m_preferredSize;
|
LocatorWidget *m_inputWidget;
|
||||||
QPointer<QWidget> m_window;
|
|
||||||
void updateWindow();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LocatorWidget *createStaticLocatorWidget(Locator *locator);
|
||||||
|
LocatorPopup *createLocatorPopup(Locator *locator, QWidget *parent);
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@@ -475,7 +475,7 @@ void GdbEngine::handleResponse(const QString &buff)
|
|||||||
|
|
||||||
case '@': {
|
case '@': {
|
||||||
QString data = GdbMi::parseCString(from, to);
|
QString data = GdbMi::parseCString(from, to);
|
||||||
QString msg = data.mid(2, data.size() - 4);
|
QString msg = data.left(data.size() - 1);
|
||||||
showMessage(msg, AppOutput);
|
showMessage(msg, AppOutput);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -726,20 +726,10 @@ RunControl::~RunControl()
|
|||||||
void RunControl::initiateStart()
|
void RunControl::initiateStart()
|
||||||
{
|
{
|
||||||
emit aboutToStart();
|
emit aboutToStart();
|
||||||
start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunControl::start()
|
|
||||||
{
|
|
||||||
d->initiateStart();
|
d->initiateStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunControl::initiateStop()
|
void RunControl::initiateStop()
|
||||||
{
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunControl::stop()
|
|
||||||
{
|
{
|
||||||
d->initiateStop();
|
d->initiateStop();
|
||||||
}
|
}
|
||||||
|
@@ -429,8 +429,8 @@ public:
|
|||||||
RunControl(RunConfiguration *runConfiguration, Core::Id mode);
|
RunControl(RunConfiguration *runConfiguration, Core::Id mode);
|
||||||
~RunControl() override;
|
~RunControl() override;
|
||||||
|
|
||||||
void initiateStart(); // Calls start() asynchronously.
|
void initiateStart();
|
||||||
void initiateStop(); // Calls stop() asynchronously.
|
void initiateStop();
|
||||||
|
|
||||||
bool promptToStop(bool *optionalPrompt = nullptr) const;
|
bool promptToStop(bool *optionalPrompt = nullptr) const;
|
||||||
void setPromptToStop(const std::function<bool(bool *)> &promptToStop);
|
void setPromptToStop(const std::function<bool(bool *)> &promptToStop);
|
||||||
@@ -478,9 +478,6 @@ public:
|
|||||||
const QString &cancelButtonText = QString(),
|
const QString &cancelButtonText = QString(),
|
||||||
bool *prompt = nullptr);
|
bool *prompt = nullptr);
|
||||||
|
|
||||||
virtual void start();
|
|
||||||
virtual void stop();
|
|
||||||
|
|
||||||
using WorkerCreator = std::function<RunWorker *(RunControl *)>;
|
using WorkerCreator = std::function<RunWorker *(RunControl *)>;
|
||||||
static void registerWorkerCreator(Core::Id id, const WorkerCreator &workerCreator);
|
static void registerWorkerCreator(Core::Id id, const WorkerCreator &workerCreator);
|
||||||
RunWorker *workerById(Core::Id id) const;
|
RunWorker *workerById(Core::Id id) const;
|
||||||
|
@@ -102,7 +102,7 @@ QmlProfilerRunner::QmlProfilerRunner(RunControl *runControl)
|
|||||||
QmlProfilerRunner::~QmlProfilerRunner()
|
QmlProfilerRunner::~QmlProfilerRunner()
|
||||||
{
|
{
|
||||||
if (runControl()->isRunning() && d->m_profilerState)
|
if (runControl()->isRunning() && d->m_profilerState)
|
||||||
runControl()->stop();
|
runControl()->initiateStop();
|
||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -342,10 +342,10 @@ void QmlProfilerTool::finalizeRunControl(QmlProfilerRunner *runWorker)
|
|||||||
connect(runControl, &RunControl::finished, this, [this, runControl] {
|
connect(runControl, &RunControl::finished, this, [this, runControl] {
|
||||||
d->m_toolBusy = false;
|
d->m_toolBusy = false;
|
||||||
updateRunActions();
|
updateRunActions();
|
||||||
disconnect(d->m_stopAction, &QAction::triggered, runControl, &RunControl::stop);
|
disconnect(d->m_stopAction, &QAction::triggered, runControl, &RunControl::initiateStop);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(d->m_stopAction, &QAction::triggered, runControl, &RunControl::stop);
|
connect(d->m_stopAction, &QAction::triggered, runControl, &RunControl::initiateStop);
|
||||||
|
|
||||||
updateRunActions();
|
updateRunActions();
|
||||||
runWorker->registerProfilerStateManager(d->m_profilerState);
|
runWorker->registerProfilerStateManager(d->m_profilerState);
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#include "basehoverhandler.h"
|
#include "basehoverhandler.h"
|
||||||
#include "texteditor.h"
|
#include "texteditor.h"
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/tooltip/tooltip.h>
|
#include <utils/tooltip/tooltip.h>
|
||||||
|
|
||||||
namespace TextEditor {
|
namespace TextEditor {
|
||||||
@@ -33,6 +34,11 @@ namespace TextEditor {
|
|||||||
BaseHoverHandler::~BaseHoverHandler()
|
BaseHoverHandler::~BaseHoverHandler()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
bool BaseHoverHandler::isAsyncHandler() const
|
||||||
|
{
|
||||||
|
return m_isAsyncHandler;
|
||||||
|
}
|
||||||
|
|
||||||
void BaseHoverHandler::showToolTip(TextEditorWidget *widget, const QPoint &point, bool decorate)
|
void BaseHoverHandler::showToolTip(TextEditorWidget *widget, const QPoint &point, bool decorate)
|
||||||
{
|
{
|
||||||
if (decorate)
|
if (decorate)
|
||||||
@@ -40,13 +46,18 @@ void BaseHoverHandler::showToolTip(TextEditorWidget *widget, const QPoint &point
|
|||||||
operateTooltip(widget, point);
|
operateTooltip(widget, point);
|
||||||
}
|
}
|
||||||
|
|
||||||
int BaseHoverHandler::checkToolTip(TextEditorWidget *widget, int pos)
|
void BaseHoverHandler::checkPriority(TextEditorWidget *widget,
|
||||||
|
int pos,
|
||||||
|
ReportPriority report)
|
||||||
{
|
{
|
||||||
widget->setContextHelpId(QString());
|
widget->setContextHelpId(QString());
|
||||||
|
|
||||||
process(widget, pos);
|
process(widget, pos, report);
|
||||||
|
}
|
||||||
|
|
||||||
return priority();
|
void BaseHoverHandler::cancelAsyncCheck()
|
||||||
|
{
|
||||||
|
QTC_CHECK(false && "BaseHoverHandler: Implement cancelCheck() in derived class!");
|
||||||
}
|
}
|
||||||
|
|
||||||
int BaseHoverHandler::priority() const
|
int BaseHoverHandler::priority() const
|
||||||
@@ -73,7 +84,7 @@ QString BaseHoverHandler::contextHelpId(TextEditorWidget *widget, int pos)
|
|||||||
// If the tooltip is visible and there is a help match, this match is used to update
|
// If the tooltip is visible and there is a help match, this match is used to update
|
||||||
// the help id. Otherwise, let the identification process happen.
|
// the help id. Otherwise, let the identification process happen.
|
||||||
if (!Utils::ToolTip::isVisible() || !lastHelpItemIdentified().isValid())
|
if (!Utils::ToolTip::isVisible() || !lastHelpItemIdentified().isValid())
|
||||||
process(widget, pos);
|
process(widget, pos, ReportPriority()); // TODO
|
||||||
|
|
||||||
if (lastHelpItemIdentified().isValid())
|
if (lastHelpItemIdentified().isValid())
|
||||||
return lastHelpItemIdentified().helpId();
|
return lastHelpItemIdentified().helpId();
|
||||||
@@ -100,13 +111,23 @@ const HelpItem &BaseHoverHandler::lastHelpItemIdentified() const
|
|||||||
return m_lastHelpItemIdentified;
|
return m_lastHelpItemIdentified;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseHoverHandler::process(TextEditorWidget *widget, int pos)
|
void BaseHoverHandler::process(TextEditorWidget *widget, int pos, ReportPriority report)
|
||||||
{
|
{
|
||||||
m_toolTip.clear();
|
m_toolTip.clear();
|
||||||
m_priority = -1;
|
m_priority = -1;
|
||||||
m_lastHelpItemIdentified = HelpItem();
|
m_lastHelpItemIdentified = HelpItem();
|
||||||
|
|
||||||
|
if (m_isAsyncHandler) {
|
||||||
|
identifyMatchAsync(widget, pos, report);
|
||||||
|
} else {
|
||||||
identifyMatch(widget, pos);
|
identifyMatch(widget, pos);
|
||||||
|
report(priority());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseHoverHandler::setIsAsyncHandler(bool isAsyncHandler)
|
||||||
|
{
|
||||||
|
m_isAsyncHandler = isAsyncHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos)
|
void BaseHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos)
|
||||||
@@ -116,6 +137,11 @@ void BaseHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos)
|
|||||||
setToolTip(tooltip);
|
setToolTip(tooltip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseHoverHandler::identifyMatchAsync(TextEditorWidget *, int, BaseHoverHandler::ReportPriority)
|
||||||
|
{
|
||||||
|
QTC_CHECK(false && "BaseHoverHandler: Implement identifyMatchAsync() in derived class!");
|
||||||
|
}
|
||||||
|
|
||||||
void BaseHoverHandler::decorateToolTip()
|
void BaseHoverHandler::decorateToolTip()
|
||||||
{
|
{
|
||||||
if (Qt::mightBeRichText(toolTip()))
|
if (Qt::mightBeRichText(toolTip()))
|
||||||
|
@@ -28,6 +28,8 @@
|
|||||||
#include "texteditor_global.h"
|
#include "texteditor_global.h"
|
||||||
#include "helpitem.h"
|
#include "helpitem.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QPoint;
|
class QPoint;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
@@ -41,9 +43,15 @@ class TEXTEDITOR_EXPORT BaseHoverHandler
|
|||||||
public:
|
public:
|
||||||
virtual ~BaseHoverHandler();
|
virtual ~BaseHoverHandler();
|
||||||
|
|
||||||
|
bool isAsyncHandler() const;
|
||||||
|
void setIsAsyncHandler(bool isAsyncHandler);
|
||||||
|
|
||||||
QString contextHelpId(TextEditorWidget *widget, int pos);
|
QString contextHelpId(TextEditorWidget *widget, int pos);
|
||||||
|
|
||||||
int checkToolTip(TextEditorWidget *widget, int pos);
|
using ReportPriority = std::function<void(int priority)>;
|
||||||
|
void checkPriority(TextEditorWidget *widget, int pos, ReportPriority report);
|
||||||
|
virtual void cancelAsyncCheck();
|
||||||
|
|
||||||
void showToolTip(TextEditorWidget *widget, const QPoint &point, bool decorate = true);
|
void showToolTip(TextEditorWidget *widget, const QPoint &point, bool decorate = true);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -63,11 +71,14 @@ protected:
|
|||||||
const HelpItem &lastHelpItemIdentified() const;
|
const HelpItem &lastHelpItemIdentified() const;
|
||||||
|
|
||||||
virtual void identifyMatch(TextEditorWidget *editorWidget, int pos);
|
virtual void identifyMatch(TextEditorWidget *editorWidget, int pos);
|
||||||
|
virtual void identifyMatchAsync(TextEditorWidget *editorWidget, int pos, ReportPriority report);
|
||||||
virtual void decorateToolTip();
|
virtual void decorateToolTip();
|
||||||
virtual void operateTooltip(TextEditorWidget *editorWidget, const QPoint &point);
|
virtual void operateTooltip(TextEditorWidget *editorWidget, const QPoint &point);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void process(TextEditorWidget *widget, int pos);
|
void process(TextEditorWidget *widget, int pos, ReportPriority report);
|
||||||
|
|
||||||
|
bool m_isAsyncHandler = false;
|
||||||
|
|
||||||
QString m_toolTip;
|
QString m_toolTip;
|
||||||
HelpItem m_lastHelpItemIdentified;
|
HelpItem m_lastHelpItemIdentified;
|
||||||
|
@@ -248,6 +248,119 @@ public:
|
|||||||
TextEditorFactoryPrivate *m_origin;
|
TextEditorFactoryPrivate *m_origin;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class HoverHandlerRunner
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HoverHandlerRunner(TextEditorWidget *widget, QList<BaseHoverHandler *> &handlers)
|
||||||
|
: m_widget(widget)
|
||||||
|
, m_handlers(handlers)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void startChecking(const QTextCursor &textCursor, const QPoint &point)
|
||||||
|
{
|
||||||
|
if (m_handlers.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Does the last handler still applies?
|
||||||
|
const int documentRevision = textCursor.document()->revision();
|
||||||
|
const int position = Convenience::wordStartCursor(textCursor).position();
|
||||||
|
if (m_lastHandlerInfo.applies(documentRevision, position)) {
|
||||||
|
m_lastHandlerInfo.handler->showToolTip(m_widget, point, /*decorate=*/ false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel currently running checks
|
||||||
|
for (BaseHoverHandler *handler : m_handlers) {
|
||||||
|
if (handler->isAsyncHandler())
|
||||||
|
handler->cancelAsyncCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update invocation data
|
||||||
|
m_documentRevision = documentRevision;
|
||||||
|
m_position = position;
|
||||||
|
m_point = point;
|
||||||
|
|
||||||
|
// Re-initialize process data
|
||||||
|
m_currentHandlerIndex = 0;
|
||||||
|
m_bestHandler = nullptr;
|
||||||
|
m_highestHandlerPriority = -1;
|
||||||
|
|
||||||
|
// Start checking
|
||||||
|
checkNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkNext()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_currentHandlerIndex < m_handlers.size(), return);
|
||||||
|
BaseHoverHandler *currentHandler = m_handlers[m_currentHandlerIndex];
|
||||||
|
|
||||||
|
currentHandler->checkPriority(m_widget, m_position, [this](int priority) {
|
||||||
|
onHandlerFinished(m_documentRevision, m_position, priority);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void onHandlerFinished(int documentRevision, int position, int priority)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_currentHandlerIndex < m_handlers.size(), return);
|
||||||
|
QTC_ASSERT(documentRevision == m_documentRevision, return);
|
||||||
|
QTC_ASSERT(position == m_position, return);
|
||||||
|
|
||||||
|
BaseHoverHandler *currentHandler = m_handlers[m_currentHandlerIndex];
|
||||||
|
if (priority > m_highestHandlerPriority) {
|
||||||
|
m_highestHandlerPriority = priority;
|
||||||
|
m_bestHandler = currentHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There are more, check next
|
||||||
|
++m_currentHandlerIndex;
|
||||||
|
if (m_currentHandlerIndex < m_handlers.size()) {
|
||||||
|
checkNext();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All were queried, run the best
|
||||||
|
if (m_bestHandler) {
|
||||||
|
m_lastHandlerInfo = LastHandlerInfo(m_bestHandler, m_documentRevision, m_position);
|
||||||
|
m_bestHandler->showToolTip(m_widget, m_point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TextEditorWidget *m_widget = nullptr;
|
||||||
|
const QList<BaseHoverHandler *> &m_handlers;
|
||||||
|
|
||||||
|
struct LastHandlerInfo {
|
||||||
|
LastHandlerInfo() = default;
|
||||||
|
LastHandlerInfo(BaseHoverHandler *handler, int documentRevision, int cursorPosition)
|
||||||
|
: handler(handler)
|
||||||
|
, documentRevision(documentRevision)
|
||||||
|
, cursorPosition(cursorPosition)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool applies(int documentRevision, int cursorPosition) const
|
||||||
|
{
|
||||||
|
return handler
|
||||||
|
&& documentRevision == this->documentRevision
|
||||||
|
&& cursorPosition == this->cursorPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseHoverHandler *handler = nullptr;
|
||||||
|
int documentRevision = -1;
|
||||||
|
int cursorPosition = -1;
|
||||||
|
} m_lastHandlerInfo;
|
||||||
|
|
||||||
|
// invocation data
|
||||||
|
QPoint m_point;
|
||||||
|
int m_position = -1;
|
||||||
|
int m_documentRevision = -1;
|
||||||
|
|
||||||
|
// processing data
|
||||||
|
int m_currentHandlerIndex = -1;
|
||||||
|
int m_highestHandlerPriority = -1;
|
||||||
|
BaseHoverHandler *m_bestHandler = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
class TextEditorWidgetPrivate : public QObject
|
class TextEditorWidgetPrivate : public QObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -469,26 +582,8 @@ public:
|
|||||||
CodeAssistant m_codeAssistant;
|
CodeAssistant m_codeAssistant;
|
||||||
bool m_assistRelevantContentAdded = false;
|
bool m_assistRelevantContentAdded = false;
|
||||||
|
|
||||||
struct LastHoverHandlerInfo {
|
|
||||||
LastHoverHandlerInfo() = default;
|
|
||||||
LastHoverHandlerInfo(BaseHoverHandler *handler, int documentRevision, int cursorPosition)
|
|
||||||
: handler(handler)
|
|
||||||
, documentRevision(documentRevision)
|
|
||||||
, cursorPosition(cursorPosition)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool applies(int documentRevision, int cursorPosition) const
|
|
||||||
{
|
|
||||||
return handler
|
|
||||||
&& documentRevision == this->documentRevision
|
|
||||||
&& cursorPosition == this->cursorPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseHoverHandler *handler = nullptr;
|
|
||||||
int documentRevision = -1;
|
|
||||||
int cursorPosition = -1;
|
|
||||||
} m_lastHoverHandlerInfo;
|
|
||||||
QList<BaseHoverHandler *> m_hoverHandlers; // Not owned
|
QList<BaseHoverHandler *> m_hoverHandlers; // Not owned
|
||||||
|
HoverHandlerRunner m_hoverHandlerRunner;
|
||||||
|
|
||||||
QPointer<QSequentialAnimationGroup> m_navigationAnimation;
|
QPointer<QSequentialAnimationGroup> m_navigationAnimation;
|
||||||
|
|
||||||
@@ -535,6 +630,7 @@ TextEditorWidgetPrivate::TextEditorWidgetPrivate(TextEditorWidget *parent)
|
|||||||
m_requestMarkEnabled(true),
|
m_requestMarkEnabled(true),
|
||||||
m_lineSeparatorsAllowed(false),
|
m_lineSeparatorsAllowed(false),
|
||||||
m_maybeFakeTooltipEvent(false),
|
m_maybeFakeTooltipEvent(false),
|
||||||
|
m_hoverHandlerRunner(parent, m_hoverHandlers),
|
||||||
m_clipboardAssistProvider(new ClipboardAssistProvider),
|
m_clipboardAssistProvider(new ClipboardAssistProvider),
|
||||||
m_autoCompleter(new AutoCompleter)
|
m_autoCompleter(new AutoCompleter)
|
||||||
{
|
{
|
||||||
@@ -978,7 +1074,7 @@ int TextEditorWidgetPrivate::visualIndent(const QTextBlock &block) const
|
|||||||
void TextEditorWidgetPrivate::updateAutoCompleteHighlight()
|
void TextEditorWidgetPrivate::updateAutoCompleteHighlight()
|
||||||
{
|
{
|
||||||
const QTextCharFormat &matchFormat
|
const QTextCharFormat &matchFormat
|
||||||
= q->textDocument()->fontSettings().toTextCharFormat(C_PARENTHESES);
|
= q->textDocument()->fontSettings().toTextCharFormat(C_AUTOCOMPLETE);
|
||||||
|
|
||||||
QList<QTextEdit::ExtraSelection> extraSelections;
|
QList<QTextEdit::ExtraSelection> extraSelections;
|
||||||
for (QTextCursor cursor : Utils::asConst(m_autoCompleteHighlightPos)) {
|
for (QTextCursor cursor : Utils::asConst(m_autoCompleteHighlightPos)) {
|
||||||
@@ -3181,30 +3277,7 @@ void TextEditorWidgetPrivate::processTooltipRequest(const QTextCursor &c)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does the last handler still applies?
|
m_hoverHandlerRunner.startChecking(c, toolTipPoint);
|
||||||
const int documentRevision = m_document->document()->revision();
|
|
||||||
const int cursorPosition = Convenience::wordStartCursor(c).position();
|
|
||||||
if (m_lastHoverHandlerInfo.applies(documentRevision, cursorPosition)) {
|
|
||||||
m_lastHoverHandlerInfo.handler->showToolTip(q, toolTipPoint, /*decorate=*/ false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine best handler
|
|
||||||
int highestPriority = -1;
|
|
||||||
BaseHoverHandler *highest = 0;
|
|
||||||
foreach (BaseHoverHandler *handler, m_hoverHandlers) {
|
|
||||||
int priority = handler->checkToolTip(q, c.position());
|
|
||||||
if (priority > highestPriority) {
|
|
||||||
highestPriority = priority;
|
|
||||||
highest = handler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let the best handler show the tooltip
|
|
||||||
if (highest) {
|
|
||||||
m_lastHoverHandlerInfo = LastHoverHandlerInfo{highest, documentRevision, cursorPosition};
|
|
||||||
highest->showToolTip(q, toolTipPoint);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextEditorWidgetPrivate::processAnnotaionTooltipRequest(const QTextBlock &block,
|
bool TextEditorWidgetPrivate::processAnnotaionTooltipRequest(const QTextBlock &block,
|
||||||
|
@@ -752,7 +752,7 @@ ValgrindToolRunner *CallgrindTool::createRunTool(RunControl *runControl)
|
|||||||
connect(this, &CallgrindTool::resetRequested, toolRunner, &CallgrindToolRunner::reset);
|
connect(this, &CallgrindTool::resetRequested, toolRunner, &CallgrindToolRunner::reset);
|
||||||
connect(this, &CallgrindTool::pauseToggled, toolRunner, &CallgrindToolRunner::setPaused);
|
connect(this, &CallgrindTool::pauseToggled, toolRunner, &CallgrindToolRunner::setPaused);
|
||||||
|
|
||||||
connect(m_stopAction, &QAction::triggered, toolRunner, [runControl] { runControl->stop(); });
|
connect(m_stopAction, &QAction::triggered, toolRunner, [runControl] { runControl->initiateStop(); });
|
||||||
|
|
||||||
// initialize run control
|
// initialize run control
|
||||||
toolRunner->setPaused(m_pauseAction->isChecked());
|
toolRunner->setPaused(m_pauseAction->isChecked());
|
||||||
|
@@ -567,7 +567,7 @@ RunWorker *MemcheckTool::createRunWorker(RunControl *runControl)
|
|||||||
connect(runTool, &MemcheckToolRunner::internalParserError, this, &MemcheckTool::internalParserError);
|
connect(runTool, &MemcheckToolRunner::internalParserError, this, &MemcheckTool::internalParserError);
|
||||||
connect(runTool, &MemcheckToolRunner::stopped, this, &MemcheckTool::engineFinished);
|
connect(runTool, &MemcheckToolRunner::stopped, this, &MemcheckTool::engineFinished);
|
||||||
|
|
||||||
connect(m_stopAction, &QAction::triggered, runControl, &RunControl::stop);
|
connect(m_stopAction, &QAction::triggered, runControl, &RunControl::initiateStop);
|
||||||
|
|
||||||
m_toolBusy = true;
|
m_toolBusy = true;
|
||||||
updateRunActions();
|
updateRunActions();
|
||||||
|
Reference in New Issue
Block a user