Merge remote-tracking branch 'origin/4.14' into master

Change-Id: I4ea98cc1c14808afe44030a057f9ff289a57ccfe
This commit is contained in:
Eike Ziller
2020-10-06 10:05:47 +02:00
31 changed files with 760 additions and 163 deletions

View File

@@ -4,6 +4,14 @@ Qt Creator is a cross-platform, integrated development environment (IDE) for
application developers to create applications for multiple desktop, embedded,
and mobile device platforms.
The Qt Creator Manual is available at:
https://doc.qt.io/qtcreator/index.html
For an overview of the Qt Creator IDE, see:
https://doc.qt.io/qtcreator/creator-overview.html
## Supported Platforms
The standalone binary packages support the following platforms:

View File

@@ -39,7 +39,7 @@
However, you can use some of the components in \uicontrol Library to draw
basic shapes, such as rectangles. In addition, \QDS comes with a set of
more powerful and flexible graphical primitives, that allow creating more
complex shapes, such as lines, triangles, arcs, and pies in
complex shapes, such as borders, triangles, arcs, and pies in
\uicontrol {Form Editor}.
\image studio-shapes.png "Shapes in Form Editor"
@@ -98,11 +98,15 @@
\if defined(qtdesignstudio)
\section2 Studio Rectangle
If you want to draw asymmetric shapes or use a dashed border, for example,
select the Rectangle type in the \uicontrol {Studio Components} tab of
\uicontrol Library instead of the basic rectangle type. By setting the
values of properties in the \uicontrol {Corner Radiuses} and
\uicontrol {Corner Bevel} groups, you can create shapes with cut corners.
If you want to modify each corner of the rectangle independently
or use a dashed border, select the Rectangle type in the
\uicontrol {Studio Components} tab of \uicontrol Library instead
of the basic rectangle type.
By setting the values of properties in the \uicontrol {Corner Radiuses}
group, you can draw each corner independently. By using radius values
in combination with the values in the \uicontrol {Corner Bevel} group,
you can create shapes with cut corners.
\image studio-shapes-rectangle.png "A studio rectangle with cut corners"

View File

@@ -27,6 +27,7 @@ add_subdirectory(resourceeditor)
add_subdirectory(tasklist)
add_subdirectory(nim)
add_subdirectory(incredibuild)
add_subdirectory(conan)
# Level 4: (only depends on Level 3 and below)
add_subdirectory(clangpchmanager)

View File

@@ -57,36 +57,34 @@ namespace Internal {
* It is possible for the user to specify custom arguments.
*/
class AutogenStep : public AbstractProcessStep
class AutogenStep final : public AbstractProcessStep
{
Q_DECLARE_TR_FUNCTIONS(AutotoolsProjectManager::Internal::AutogenStep)
public:
AutogenStep(BuildStepList *bsl, Utils::Id id);
AutogenStep(BuildStepList *bsl, Id id);
private:
void doRun() override;
void doRun() final;
StringAspect *m_additionalArgumentsAspect = nullptr;
bool m_runAutogen = false;
};
AutogenStep::AutogenStep(BuildStepList *bsl, Utils::Id id) : AbstractProcessStep(bsl, id)
AutogenStep::AutogenStep(BuildStepList *bsl, Id id) : AbstractProcessStep(bsl, id)
{
m_additionalArgumentsAspect = addAspect<StringAspect>();
m_additionalArgumentsAspect->setSettingsKey(
"AutotoolsProjectManager.AutogenStep.AdditionalArguments");
m_additionalArgumentsAspect->setLabelText(tr("Arguments:"));
m_additionalArgumentsAspect->setDisplayStyle(StringAspect::LineEditDisplay);
m_additionalArgumentsAspect->setHistoryCompleter("AutotoolsPM.History.AutogenStepArgs");
auto arguments = addAspect<StringAspect>();
arguments->setSettingsKey("AutotoolsProjectManager.AutogenStep.AdditionalArguments");
arguments->setLabelText(tr("Arguments:"));
arguments->setDisplayStyle(StringAspect::LineEditDisplay);
arguments->setHistoryCompleter("AutotoolsPM.History.AutogenStepArgs");
connect(m_additionalArgumentsAspect, &BaseAspect::changed, this, [this] {
connect(arguments, &BaseAspect::changed, this, [this] {
m_runAutogen = true;
});
setCommandLineProvider([this] {
setCommandLineProvider([arguments] {
return CommandLine(FilePath::fromString("./autogen.sh"),
m_additionalArgumentsAspect->value(),
arguments->value(),
CommandLine::Raw);
});

View File

@@ -55,38 +55,37 @@ namespace Internal {
* It is possible for the user to specify custom arguments.
*/
class AutoreconfStep : public AbstractProcessStep
class AutoreconfStep final : public AbstractProcessStep
{
Q_DECLARE_TR_FUNCTIONS(AutotoolsProjectManager::Internal::AutoreconfStep)
public:
AutoreconfStep(BuildStepList *bsl, Utils::Id id);
AutoreconfStep(BuildStepList *bsl, Id id);
void doRun() override;
private:
StringAspect *m_additionalArgumentsAspect = nullptr;
bool m_runAutoreconf = false;
};
AutoreconfStep::AutoreconfStep(BuildStepList *bsl, Utils::Id id)
AutoreconfStep::AutoreconfStep(BuildStepList *bsl, Id id)
: AbstractProcessStep(bsl, id)
{
m_additionalArgumentsAspect = addAspect<StringAspect>();
m_additionalArgumentsAspect->setSettingsKey("AutotoolsProjectManager.AutoreconfStep.AdditionalArguments");
m_additionalArgumentsAspect->setLabelText(tr("Arguments:"));
m_additionalArgumentsAspect->setValue("--force --install");
m_additionalArgumentsAspect->setDisplayStyle(StringAspect::LineEditDisplay);
m_additionalArgumentsAspect->setHistoryCompleter("AutotoolsPM.History.AutoreconfStepArgs");
auto arguments = addAspect<StringAspect>();
arguments->setSettingsKey("AutotoolsProjectManager.AutoreconfStep.AdditionalArguments");
arguments->setLabelText(tr("Arguments:"));
arguments->setValue("--force --install");
arguments->setDisplayStyle(StringAspect::LineEditDisplay);
arguments->setHistoryCompleter("AutotoolsPM.History.AutoreconfStepArgs");
connect(m_additionalArgumentsAspect, &BaseAspect::changed, this, [this] {
connect(arguments, &BaseAspect::changed, this, [this] {
m_runAutoreconf = true;
});
setCommandLineProvider([this] {
return Utils::CommandLine(Utils::FilePath::fromString("autoreconf"),
m_additionalArgumentsAspect->value(),
Utils::CommandLine::Raw);
setCommandLineProvider([arguments] {
return CommandLine(FilePath::fromString("autoreconf"),
arguments->value(),
CommandLine::Raw);
});
setWorkingDirectoryProvider([this] { return project()->projectDirectory(); });
@@ -107,7 +106,7 @@ void AutoreconfStep::doRun()
m_runAutoreconf = true;
if (!m_runAutoreconf) {
emit addOutput(tr("Configuration unchanged, skipping autoreconf step."), BuildStep::OutputFormat::NormalMessage);
emit addOutput(tr("Configuration unchanged, skipping autoreconf step."), OutputFormat::NormalMessage);
emit finished(true);
return;
}

View File

@@ -74,43 +74,41 @@ static QString projectDirRelativeToBuildDir(BuildConfiguration *bc)
// * represented by an instance of the class MakeStepConfigWidget.
// */
class ConfigureStep : public ProjectExplorer::AbstractProcessStep
class ConfigureStep final : public AbstractProcessStep
{
Q_DECLARE_TR_FUNCTIONS(AutotoolsProjectManager::Internal::ConfigureStep)
public:
ConfigureStep(BuildStepList *bsl, Utils::Id id);
ConfigureStep(BuildStepList *bsl, Id id);
void setAdditionalArguments(const QString &list);
private:
void doRun() override;
void doRun() final;
StringAspect *m_additionalArgumentsAspect = nullptr;
bool m_runConfigure = false;
};
ConfigureStep::ConfigureStep(BuildStepList *bsl, Utils::Id id)
ConfigureStep::ConfigureStep(BuildStepList *bsl, Id id)
: AbstractProcessStep(bsl, id)
{
m_additionalArgumentsAspect = addAspect<StringAspect>();
m_additionalArgumentsAspect->setDisplayStyle(StringAspect::LineEditDisplay);
m_additionalArgumentsAspect->setSettingsKey(
"AutotoolsProjectManager.ConfigureStep.AdditionalArguments");
m_additionalArgumentsAspect->setLabelText(tr("Arguments:"));
m_additionalArgumentsAspect->setHistoryCompleter("AutotoolsPM.History.ConfigureArgs");
auto arguments = addAspect<StringAspect>();
arguments->setDisplayStyle(StringAspect::LineEditDisplay);
arguments->setSettingsKey("AutotoolsProjectManager.ConfigureStep.AdditionalArguments");
arguments->setLabelText(tr("Arguments:"));
arguments->setHistoryCompleter("AutotoolsPM.History.ConfigureArgs");
connect(m_additionalArgumentsAspect, &BaseAspect::changed, this, [this] {
connect(arguments, &BaseAspect::changed, this, [this] {
m_runConfigure = true;
});
setWorkingDirectoryProvider([this] { return project()->projectDirectory(); });
setCommandLineProvider([this] {
setCommandLineProvider([this, arguments] {
BuildConfiguration *bc = buildConfiguration();
return CommandLine({FilePath::fromString(projectDirRelativeToBuildDir(bc) + "configure"),
m_additionalArgumentsAspect->value(),
arguments->value(),
CommandLine::Raw});
});
@@ -135,7 +133,7 @@ void ConfigureStep::doRun()
}
if (!m_runConfigure) {
emit addOutput(tr("Configuration unchanged, skipping configure step."), BuildStep::OutputFormat::NormalMessage);
emit addOutput(tr("Configuration unchanged, skipping configure step."), OutputFormat::NormalMessage);
emit finished(true);
return;
}

View File

@@ -0,0 +1,6 @@
add_qtc_plugin(Conan
PLUGIN_DEPENDS Core ProjectExplorer
SOURCES
conaninstallstep.cpp conaninstallstep.h
conanplugin.cpp conanplugin.h
)

View File

@@ -0,0 +1,20 @@
{
\"Name\" : \"Conan\",
\"Version\" : \"$$QTCREATOR_VERSION\",
\"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
\"Vendor\" : \"Jochen Seemann\",
\"Copyright\" : \"(C) 2018 Jochen Seemann, (C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\",
\"License\" : [ \"Commercial Usage\",
\"\",
\"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.\",
\"\",
\"GNU General Public License Usage\",
\"\",
\"Alternatively, this plugin 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 plugin. 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.\"
],
\"Category\" : \"Utilities\",
\"Experimental\" : true,
\"Description\" : \"Conan integration.\",
\"Url\" : \"http://www.qt.io\",
$$dependencyList
}

View File

@@ -0,0 +1,8 @@
include(../../qtcreatorplugin.pri)
SOURCES += \
conaninstallstep.cpp \
conanplugin.cpp
HEADERS += \
conaninstallstep.h \
conanplugin.h

View File

@@ -0,0 +1,19 @@
import qbs 1.0
QtcPlugin {
name: "Conan"
Depends { name: "Qt.widgets" }
Depends { name: "Utils" }
Depends { name: "Core" }
Depends { name: "ProjectExplorer" }
files: [
"conanplugin.h",
"conanplugin.cpp",
"conaninstallstep.h",
"conaninstallstep.cpp"
]
}

View File

@@ -0,0 +1,6 @@
QTC_PLUGIN_NAME = Conan
QTC_LIB_DEPENDS += \
utils
QTC_PLUGIN_DEPENDS += \
coreplugin \
projectexplorer

View File

@@ -0,0 +1,131 @@
/****************************************************************************
**
** Copyright (C) 2018 Jochen Seemann
** 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 "conaninstallstep.h"
#include <projectexplorer/abstractprocessstep.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/gnumakeparser.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/processparameters.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
#include <projectexplorer/task.h>
#include <projectexplorer/toolchain.h>
using namespace ProjectExplorer;
using namespace Utils;
namespace ConanPackageManager {
namespace Internal {
// ConanInstallStep
class ConanInstallStep final : public AbstractProcessStep
{
Q_DECLARE_TR_FUNCTIONS(ConanPackageManager::Internal::ConanInstallStep)
public:
ConanInstallStep(BuildStepList *bsl, Id id);
private:
bool init() final;
void setupOutputFormatter(OutputFormatter *formatter) final;
};
ConanInstallStep::ConanInstallStep(BuildStepList *bsl, Id id)
: AbstractProcessStep(bsl, id)
{
setUseEnglishOutput();
setDisplayName(ConanInstallStep::tr("Conan install"));
auto conanFile = addAspect<StringAspect>();
conanFile->setSettingsKey("ConanPackageManager.InstallStep.ConanFile");
conanFile->setFilePath(project()->projectDirectory() / "conanfile.txt");
conanFile->setLabelText(tr("Conan file:"));
conanFile->setToolTip(tr("Enter location of conanfile.txt or conanfile.py"));
conanFile->setDisplayStyle(StringAspect::PathChooserDisplay);
conanFile->setExpectedKind(PathChooser::File);
auto additionalArguments = addAspect<StringAspect>();
additionalArguments->setSettingsKey("ConanPackageManager.InstallStep.AdditionalArguments");
additionalArguments->setLabelText(tr("Additional arguments:"));
additionalArguments->setDisplayStyle(StringAspect::LineEditDisplay);
setCommandLineProvider([this, conanFile, additionalArguments] {
BuildConfiguration::BuildType bt = buildConfiguration()->buildType();
const QString buildType = bt == BuildConfiguration::Release ? QString("Release")
: QString("Debug");
CommandLine cmd("conan");
cmd.addArgs({"install", "-s", "build_type=" + buildType, conanFile->value()});
cmd.addArgs(additionalArguments->value(), CommandLine::Raw);
return cmd;
});
setSummaryUpdater([this]() -> QString {
QList<ToolChain *> tcList = ToolChainKitAspect::toolChains(target()->kit());
if (tcList.isEmpty())
return "<b>" + ToolChainKitAspect::msgNoToolChainInTarget() + "</b>";
ProcessParameters param;
setupProcessParameters(&param);
return param.summary(displayName());
});
}
bool ConanInstallStep::init()
{
if (!AbstractProcessStep::init())
return false;
const QList<ToolChain *> tcList = ToolChainKitAspect::toolChains(target()->kit());
if (tcList.isEmpty()) {
emit addTask(Task::compilerMissingTask());
emitFaultyConfigurationMessage();
return false;
}
return true;
}
void ConanInstallStep::setupOutputFormatter(OutputFormatter *formatter)
{
formatter->addLineParser(new GnuMakeParser());
formatter->addLineParsers(kit()->createOutputParsers());
formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
AbstractProcessStep::setupOutputFormatter(formatter);
}
// ConanInstallStepFactory
ConanInstallStepFactory::ConanInstallStepFactory()
{
registerStep<ConanInstallStep>("ConanPackageManager.InstallStep");
setDisplayName(ConanInstallStep::tr("Run conan install"));
}
} // Internal
} // ConanPackageManager

View File

@@ -0,0 +1,40 @@
/****************************************************************************
**
** Copyright (C) 2018 Jochen Seemann
** 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 <projectexplorer/buildstep.h>
namespace ConanPackageManager {
namespace Internal {
class ConanInstallStepFactory final : public ProjectExplorer::BuildStepFactory
{
public:
ConanInstallStepFactory();
};
} // namespace Internal
} // namespace ConanPackageManager

View File

@@ -0,0 +1,60 @@
/****************************************************************************
**
** Copyright (C) 2018 Jochen Seemann
** 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 "conanplugin.h"
#include "conaninstallstep.h"
#include <projectexplorer/projectmanager.h>
#include <projectexplorer/buildmanager.h>
namespace ConanPackageManager {
namespace Internal {
class ConanPluginRunData
{
public:
ConanInstallStepFactory installStepFactory;
};
ConanPlugin::~ConanPlugin()
{
delete m_runData;
}
void ConanPlugin::extensionsInitialized()
{ }
bool ConanPlugin::initialize(const QStringList &arguments, QString *errorString)
{
Q_UNUSED(arguments)
Q_UNUSED(errorString)
m_runData = new ConanPluginRunData;
return true;
}
} // namespace Internal
} // namespace ConanPackageManager

View File

@@ -0,0 +1,49 @@
/****************************************************************************
**
** Copyright (C) 2018 Jochen Seemann
** 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 <extensionsystem/iplugin.h>
namespace ConanPackageManager {
namespace Internal {
class ConanPluginRunData;
class ConanPlugin final : public ExtensionSystem::IPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Conan.json")
~ConanPlugin() final;
void extensionsInitialized() final;
bool initialize(const QStringList &arguments, QString *errorString) final;
ConanPluginRunData *m_runData = nullptr;
};
} // namespace Internal
} // namespace ConanPackageManager

View File

@@ -89,104 +89,111 @@ void GdbMi::parseResultOrValue(const QChar *&from, const QChar *to)
}
}
// Reads one \ooo entity.
static bool parseOctalEscapedHelper(const QChar *&from, const QChar *to, QByteArray &buffer)
{
if (to - from < 4)
return false;
if (*from != '\\')
return false;
const char c1 = from[1].unicode();
const char c2 = from[2].unicode();
const char c3 = from[3].unicode();
if (!isdigit(c1) || !isdigit(c2) || !isdigit(c3))
return false;
buffer += char((c1 - '0') * 64 + (c2 - '0') * 8 + (c3 - '0'));
from += 4;
return true;
}
static bool parseHexEscapedHelper(const QChar *&from, const QChar *to, QByteArray &buffer)
{
if (to - from < 4)
return false;
if (from[0]!= '\\')
return false;
if (from[1] != 'x')
return false;
const char c1 = from[2].unicode();
const char c2 = from[3].unicode();
if (!isxdigit(c1) || !isxdigit(c2))
return false;
buffer += char(16 * fromhex(c1) + fromhex(c2));
from += 4;
return true;
}
static void parseSimpleEscape(const QChar *&from, const QChar *to, QString &result)
{
if (from == to) {
qDebug() << "MI Parse Error, unterminated backslash escape";
return;
}
QChar c = *from++;
switch (c.unicode()) {
case 'a': result += '\a'; break;
case 'b': result += '\b'; break;
case 'f': result += '\f'; break;
case 'n': result += '\n'; break;
case 'r': result += '\r'; break;
case 't': result += '\t'; break;
case 'v': result += '\v'; break;
case '"': result += '"'; break;
case '\'': result += '\''; break;
case '\\': result += '\\'; break;
default:
qDebug() << "MI Parse Error, unrecognized backslash escape";
}
}
// Reads subsequent \123 or \x12 entities and converts to Utf8,
// *or* one escaped char, *or* one unescaped char.
static void parseCharOrEscape(const QChar *&from, const QChar *to, QString &result)
{
QByteArray buffer;
while (parseOctalEscapedHelper(from, to, buffer))
;
while (parseHexEscapedHelper(from, to, buffer))
;
if (!buffer.isEmpty())
result.append(QString::fromUtf8(buffer));
else if (*from == '\\')
parseSimpleEscape(++from, to, result);
else
result += *from++;
}
QString GdbMi::parseCString(const QChar *&from, const QChar *to)
{
QString result;
if (to == from)
return QString();
//qDebug() << "parseCString: " << QString(from, to - from);
if (*from != '"') {
qDebug() << "MI Parse Error, double quote expected";
++from; // So we don't hang
return QString();
}
const QChar *ptr = from;
++ptr;
while (ptr < to) {
if (*ptr == '"') {
++ptr;
result = QString(from + 1, ptr - from - 2);
break;
}
if (*ptr == '\\') {
++ptr;
if (ptr == to) {
qDebug() << "MI Parse Error, unterminated backslash escape";
from = ptr; // So we don't hang
return QString();
}
}
++ptr;
}
from = ptr;
int idx = result.indexOf('\\');
if (idx >= 0) {
QChar *dst = result.data() + idx;
const QChar *src = dst + 1, *end = result.data() + result.length();
do {
QChar c = *src++;
switch (c.unicode()) {
case 'a': *dst++ = '\a'; break;
case 'b': *dst++ = '\b'; break;
case 'f': *dst++ = '\f'; break;
case 'n': *dst++ = '\n'; break;
case 'r': *dst++ = '\r'; break;
case 't': *dst++ = '\t'; break;
case 'v': *dst++ = '\v'; break;
case '"': *dst++ = '"'; break;
case '\\': *dst++ = '\\'; break;
case 'x': {
c = *src++;
int chars = 0;
uchar prod = 0;
while (true) {
uchar val = fromhex(c.unicode());
if (val == UCHAR_MAX)
break;
prod = prod * 16 + val;
if (++chars == 3 || src == end)
break;
c = *src++;
}
if (!chars) {
qDebug() << "MI Parse Error, unrecognized hex escape";
return QString();
}
*dst++ = prod;
break;
}
default:
{
int chars = 0;
uchar prod = 0;
forever {
if (c < '0' || c > '7') {
--src;
break;
}
prod = prod * 8 + c.unicode() - '0';
if (++chars == 3 || src == end)
break;
c = *src++;
}
if (!chars) {
qDebug() << "MI Parse Error, unrecognized backslash escape";
return QString();
}
*dst++ = prod;
}
}
while (src != end) {
QChar c = *src++;
if (c == '\\')
break;
*dst++ = c;
}
} while (src != end);
*dst = 0;
result.truncate(dst - result.data());
++from; // Skip initial quote.
QString result;
result.reserve(to - from);
while (from < to) {
if (*from == '"') {
++from;
return result;
}
parseCharOrEscape(from, to, result);
}
return result;
qDebug() << "MI Parse Error, unfinished string";
return QString();
}
void GdbMi::parseValue(const QChar *&from, const QChar *to)

View File

@@ -195,7 +195,7 @@ public:
const auto cppDocumentParser = BuiltinEditorDocumentParser::get(cppFile);
QVERIFY(cppDocumentParser);
const Document::Ptr cppDocument = cppDocumentParser->document();
QCOMPARE(cppDocument->editorRevision(), 2);
QVERIFY(cppDocument->editorRevision() >= 2);
QVERIFY(checkDiagsnosticMessages(cppDocument));
const auto hDocumentParser = BuiltinEditorDocumentParser::get(hFile);

View File

@@ -170,13 +170,9 @@ bool IosBuildStep::init()
if (!AbstractProcessStep::init())
return false;
BuildConfiguration *bc = buildConfiguration();
ToolChain *tc = ToolChainKitAspect::cxxToolChain(kit());
if (!tc)
if (!tc) {
emit addTask(Task::compilerMissingTask());
if (!bc || !tc) {
emitFaultyConfigurationMessage();
return false;
}

View File

@@ -66,7 +66,8 @@ SUBDIRS = \
webassembly \
mcusupport \
marketplace \
incredibuild
incredibuild \
conan
qtHaveModule(serialport) {
SUBDIRS += serialterminal

View File

@@ -23,6 +23,7 @@ Project {
"cmakeprojectmanager/cmakeprojectmanager.qbs",
"mesonprojectmanager/mesonprojectmanager.qbs",
"compilationdatabaseprojectmanager/compilationdatabaseprojectmanager.qbs",
"conan/conan.qbs",
"coreplugin/coreplugin.qbs",
"coreplugin/images/logo/logo.qbs",
"cpaster/cpaster.qbs",

View File

@@ -55,18 +55,18 @@ const int PANEL_LEFT_MARGIN = 70;
// PanelsWidget
///
PanelsWidget::PanelsWidget(QWidget *parent) : QWidget(parent)
PanelsWidget::PanelsWidget(QWidget *parent)
: QWidget(parent), m_splitter(new Core::MiniSplitter(this))
{
const auto splitter = new Core::MiniSplitter(this);
m_root = new QWidget(nullptr);
m_root->setFocusPolicy(Qt::NoFocus);
m_root->setContentsMargins(0, 0, 40, 0);
splitter->addWidget(m_root);
splitter->addWidget(new QWidget);
splitter->setStretchFactor(1, 100); // Force root widget to its minimum size initially
m_splitter->addWidget(m_root);
m_splitter->addWidget(new QWidget);
m_splitter->setStretchFactor(1, 100); // Force root widget to its minimum size initially
const auto scroller = new QScrollArea(this);
scroller->setWidget(splitter);
scroller->setWidget(m_splitter);
scroller->setFrameStyle(QFrame::NoFrame);
scroller->setWidgetResizable(true);
scroller->setFocusPolicy(Qt::NoFocus);
@@ -153,4 +153,14 @@ void PanelsWidget::addPropertiesPanel(const QString &displayName, const QIcon &i
m_layout->addWidget(widget, widgetRow, 0, 1, 2);
}
QByteArray PanelsWidget::saveSplitterState() const
{
return m_splitter->saveState().toHex();
}
void PanelsWidget::loadSplitterState(const QByteArray &state)
{
m_splitter->restoreState(QByteArray::fromHex(state));
}
} // ProjectExplorer

View File

@@ -34,6 +34,8 @@ class QGridLayout;
class QIcon;
QT_END_NAMESPACE
namespace Core { class MiniSplitter; }
namespace ProjectExplorer {
class PROJECTEXPLORER_EXPORT PanelsWidget : public QWidget
@@ -49,8 +51,12 @@ public:
void addPropertiesPanel(const QString &displayName, const QIcon &icon,
QWidget *widget);
QByteArray saveSplitterState() const;
void loadSplitterState(const QByteArray &state);
private:
QGridLayout *m_layout;
Core::MiniSplitter * const m_splitter;
QWidget *m_root;
};

View File

@@ -613,13 +613,32 @@ public:
QWidget *panel() const
{
if (!m_panel) {
m_panel = (m_subIndex == RunPage)
? new PanelsWidget(RunSettingsWidget::tr("Run Settings"),
QIcon(":/projectexplorer/images/RunSettings.png"),
new RunSettingsWidget(target()))
: new PanelsWidget(QCoreApplication::translate("BuildSettingsPanel", "Build Settings"),
QIcon(":/projectexplorer/images/BuildSettings.png"),
new BuildSettingsWidget(target()));
QString splitterStateKey = "PanelSplitterState:"
+ m_project->projectFilePath().toString() + ':';
if (m_subIndex == RunPage) {
splitterStateKey += "Run";
m_panel = new PanelsWidget(RunSettingsWidget::tr("Run Settings"),
QIcon(":/projectexplorer/images/RunSettings.png"),
new RunSettingsWidget(target()));
} else {
splitterStateKey += "Build";
m_panel = new PanelsWidget(QCoreApplication::translate("BuildSettingsPanel", "Build Settings"),
QIcon(":/projectexplorer/images/BuildSettings.png"),
new BuildSettingsWidget(target()));
}
const auto panel = qobject_cast<PanelsWidget *>(m_panel.data());
const auto loadSplitterValue = [panel, splitterStateKey] {
const QByteArray splitterState = SessionManager::value(splitterStateKey).toByteArray();
if (!splitterState.isEmpty())
panel->loadSplitterState(splitterState);
};
loadSplitterValue();
QObject::connect(SessionManager::instance(), &SessionManager::aboutToSaveSession,
panel, [panel, splitterStateKey] {
SessionManager::setValue(splitterStateKey, panel->saveSplitterState());
});
QObject::connect(SessionManager::instance(), &SessionManager::sessionLoaded,
panel, loadSplitterValue);
}
return m_panel;
}

View File

@@ -163,6 +163,8 @@ enum { NExtraSelectionKinds = 12 };
using TransformationMethod = QString(const QString &);
using ListTransformationMethod = void(QStringList &);
static constexpr char dropProperty[] = "dropProp";
class LineColumnLabel : public FixedSizeClickLabel
{
Q_OBJECT
@@ -714,7 +716,7 @@ public:
// block selection mode
bool m_inBlockSelectionMode = false;
QString copyBlockSelection();
void insertIntoBlockSelection(const QString &text = QString());
void insertIntoBlockSelection(const QString &text = QString(), const bool selectText = false);
void setCursorToColumn(QTextCursor &cursor, int column,
QTextCursor::MoveMode moveMode = QTextCursor::MoveAnchor);
void removeBlockSelection();
@@ -3802,7 +3804,7 @@ void TextEditorWidgetPrivate::setCursorToColumn(QTextCursor &cursor, int column,
cursor.block().text(), column), moveMode);
}
void TextEditorWidgetPrivate::insertIntoBlockSelection(const QString &text)
void TextEditorWidgetPrivate::insertIntoBlockSelection(const QString &text, const bool selectText)
{
// TODO: add autocompleter support
QTextCursor cursor = q->textCursor();
@@ -3828,6 +3830,7 @@ void TextEditorWidgetPrivate::insertIntoBlockSelection(const QString &text)
int positionBlock = m_blockSelection.positionBlock;
int anchorBlock = m_blockSelection.anchorBlock;
int column = m_blockSelection.positionColumn;
const int anchorColumn = m_blockSelection.anchorColumn;
const QTextBlock &firstBlock =
m_document->document()->findBlockByNumber(m_blockSelection.firstBlockNumber());
@@ -3880,7 +3883,10 @@ void TextEditorWidgetPrivate::insertIntoBlockSelection(const QString &text)
cursor.endEditBlock();
column += textLength;
m_blockSelection.fromPostition(positionBlock, column, anchorBlock, column);
m_blockSelection.fromPostition(positionBlock,
column,
anchorBlock,
selectText ? anchorColumn : column);
q->doSetTextCursor(m_blockSelection.selection(m_document.data()), true);
}
@@ -7722,8 +7728,9 @@ void TextEditorWidget::insertFromMimeData(const QMimeData *source)
if (d->m_codeAssistant.hasContext())
d->m_codeAssistant.destroyContext();
const bool selectInsertedText = source->property(dropProperty).toBool();
if (d->m_inBlockSelectionMode) {
d->insertIntoBlockSelection(text);
d->insertIntoBlockSelection(text, selectInsertedText);
return;
}
@@ -7738,7 +7745,16 @@ void TextEditorWidget::insertFromMimeData(const QMimeData *source)
QTextCursor cursor = textCursor();
if (!tps.m_autoIndent) {
cursor.beginEditBlock();
cursor.insertText(text);
if (selectInsertedText) {
const int anchor = cursor.position();
cursor.insertText(text);
const int pos = cursor.position();
cursor.endEditBlock();
cursor.setPosition(anchor);
cursor.setPosition(pos, QTextCursor::KeepAnchor);
} else {
cursor.insertText(text);
}
cursor.endEditBlock();
setTextCursor(cursor);
return;
@@ -7768,6 +7784,9 @@ void TextEditorWidget::insertFromMimeData(const QMimeData *source)
int cursorPosition = cursor.position();
cursor.insertText(text);
const QTextCursor endCursor = cursor;
QTextCursor startCursor = endCursor;
startCursor.setPosition(cursorPosition);
int reindentBlockEnd = cursor.blockNumber() - (hasFinalNewline?1:0);
@@ -7788,9 +7807,33 @@ void TextEditorWidget::insertFromMimeData(const QMimeData *source)
}
cursor.endEditBlock();
if (selectInsertedText) {
cursor.setPosition(startCursor.position());
cursor.setPosition(endCursor.position(), QTextCursor::KeepAnchor);
}
setTextCursor(cursor);
}
void TextEditorWidget::dropEvent(QDropEvent *e)
{
const QMimeData *mime = e->mimeData();
if (mime && (mime->hasText() || mime->hasHtml())) {
QMimeData *mimeOverwrite = duplicateMimeData(mime);
mimeOverwrite->setProperty(dropProperty, true);
auto dropOverwrite = new QDropEvent(e->pos(),
e->possibleActions(),
mimeOverwrite,
e->mouseButtons(),
e->keyboardModifiers());
QPlainTextEdit::dropEvent(dropOverwrite);
e->setAccepted(dropOverwrite->isAccepted());
delete dropOverwrite;
delete mimeOverwrite;
} else {
QPlainTextEdit::dropEvent(e);
}
}
QMimeData *TextEditorWidget::duplicateMimeData(const QMimeData *source)
{
Q_ASSERT(source);

View File

@@ -530,6 +530,7 @@ protected:
QMimeData *createMimeDataFromSelection() const override;
bool canInsertFromMimeData(const QMimeData *source) const override;
void insertFromMimeData(const QMimeData *source) override;
void dropEvent(QDropEvent *e) override;
virtual QString plainTextFromSelection(const QTextCursor &cursor) const;
static QString convertToPlainText(const QString &txt);

View File

@@ -32,6 +32,15 @@ add_qtc_test(tst_debugger_gdb
"${DEBUGGERDIR}/debuggerprotocol.cpp" "${DEBUGGERDIR}/debuggerprotocol.h"
)
add_qtc_test(tst_debugger_protocol
DEPENDS Qt5::Network Utils
INCLUDES
"${DEBUGGERDIR}"
SOURCES
"${DEBUGGERDIR}/debuggerprotocol.cpp" "${DEBUGGERDIR}/debuggerprotocol.h"
tst_protocol.cpp
)
add_qtc_test(tst_debugger_offsets
DEPENDS Qt5::CorePrivate
INCLUDES "${DEBUGGERDIR}"

View File

@@ -12,3 +12,4 @@ SUBDIRS += simplifytypes.pro
SUBDIRS += dumpers.pro
SUBDIRS += disassembler.pro
SUBDIRS += offsets.pro
SUBDIRS += protocol.pro

View File

@@ -7,6 +7,7 @@ Project {
"disassembler.qbs",
"dumpers.qbs",
"gdb.qbs",
"protocol.qbs",
"offsets.qbs",
"simplifytypes.qbs",
]

View File

@@ -0,0 +1,46 @@
QT = core network
msvc: QTC_LIB_DEPENDS += utils
include(../qttest.pri)
DEBUGGERDIR = $$IDE_SOURCE_TREE/src/plugins/debugger
UTILSDIR = $$IDE_SOURCE_TREE/src/libs/utils
INCLUDEPATH += $$DEBUGGERDIR
SOURCES += \
tst_protocol.cpp \
$$DEBUGGERDIR/debuggerprotocol.cpp
HEADERS += \
$$DEBUGGERDIR/debuggerprotocol.h
!msvc {
SOURCES += \
$$UTILSDIR/environment.cpp \
$$UTILSDIR/fileutils.cpp \
$$UTILSDIR/hostosinfo.cpp \
$$UTILSDIR/namevaluedictionary.cpp \
$$UTILSDIR/namevalueitem.cpp \
$$UTILSDIR/qtcassert.cpp \
$$UTILSDIR/qtcprocess.cpp \
$$UTILSDIR/processhandle.cpp \
$$UTILSDIR/savefile.cpp \
HEADERS += \
$$UTILSDIR/environment.h \
$$UTILSDIR/fileutils.h \
$$UTILSDIR/hostosinfo.h \
$$UTILSDIR/namevaluedictionary.h \
$$UTILSDIR/namevalueitem.h \
$$UTILSDIR/qtcassert.h \
$$UTILSDIR/qtcprocess.h \
$$UTILSDIR/processhandle.h \
$$UTILSDIR/savefile.h \
macos: {
HEADERS += $$UTILSDIR/fileutils_mac.h
OBJECTIVE_SOURCES += $$UTILSDIR/fileutils_mac.mm
LIBS += -framework Foundation
}
}

View File

@@ -0,0 +1,17 @@
import qbs
QtcAutotest {
name: "debugger protocol autotest"
Depends { name: "Utils" }
Depends { name: "Qt.network" } // For QHostAddress
Group {
name: "Sources from Debugger plugin"
prefix: project.debuggerDir
files: "debuggerprotocol.cpp"
}
Group {
name: "Test sources"
files: "tst_protocol.cpp"
}
cpp.includePaths: base.concat([project.debuggerDir])
}

View File

@@ -0,0 +1,92 @@
/****************************************************************************
**
** Copyright (C) 2020 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 <debuggerprotocol.h>
#include <QtTest>
//TESTED_COMPONENT=src/plugins/debugger
class tst_protocol : public QObject
{
Q_OBJECT
public:
tst_protocol() {}
private slots:
void parseCString();
void parseCString_data();
};
void tst_protocol::parseCString()
{
QFETCH(QString, input);
QFETCH(QString, expected);
const QChar *from = input.begin();
const QChar *to = input.end();
QString parsed = Debugger::Internal::GdbMi::parseCString(from, to);
QCOMPARE(parsed, expected);
}
void tst_protocol::parseCString_data()
{
QTest::addColumn<QString>("input");
QTest::addColumn<QString>("expected");
QTest::newRow("empty")
<< ""
<< "";
QTest::newRow("unquoted")
<< "irgendwas"
<< "";
QTest::newRow("plain")
<< R"("plain")"
<< "plain";
// This is expected to throw several warnings
// "MI Parse Error, unrecognized backslash escape"
QChar escapes[] = {'\a', '\b', '\f', '\n', '\r', '\t', '\v', '"', '\'', '\\'};
QTest::newRow("escaped")
<< R"("\a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\y\z\"\'\\")"
<< QString(escapes, sizeof(escapes)/sizeof(escapes[0]));
QTest::newRow("octal")
<< R"("abc\303\244\303\251def\303\261")"
<< R"(abcäédefñ)";
QTest::newRow("hex")
<< R"("abc\xc3\xa4\xc3\xa9def\xc3\xb1")"
<< R"(abcäédefñ)";
}
QTEST_APPLESS_MAIN(tst_protocol);
#include "tst_protocol.moc"