Merge "Merge remote-tracking branch 'origin/4.3'"

This commit is contained in:
Orgad Shaneh
2017-06-26 07:43:23 +00:00
committed by The Qt Project
34 changed files with 283 additions and 95 deletions

View File

@@ -58,12 +58,28 @@ Controls.ComboBox {
Layout.fillWidth: true Layout.fillWidth: true
onCurrentTextChanged: { onAccepted: {
if (backendValue === undefined) if (backendValue === undefined)
return; return;
if (backendValue.value !== currentText) if (editText === "")
backendValue.value = currentText; return
if (backendValue.value !== editText)
backendValue.value = editText;
}
onActivated: {
if (backendValue === undefined)
return;
if (editText === "")
return
var indexText = comboBox.textAt(index)
if (backendValue.value !== indexText)
backendValue.value = indexText;
} }
ExtendedFunctionButton { ExtendedFunctionButton {
@@ -73,6 +89,13 @@ Controls.ComboBox {
visible: comboBox.enabled visible: comboBox.enabled
} }
Connections {
target: modelNodeBackend
onSelectionChanged: {
comboBox.editText = backendValue.value
}
}
Component.onCompleted: { Component.onCompleted: {
//Hack to style the text input //Hack to style the text input
for (var i = 0; i < comboBox.children.length; i++) { for (var i = 0; i < comboBox.children.length; i++) {

View File

@@ -53,16 +53,22 @@ public:
: m_accumulating(false), m_aborted(false), m_lockDepth(0) : m_accumulating(false), m_aborted(false), m_lockDepth(0)
{} {}
bool resolveMacro(const QString &name, QString *ret) bool resolveMacro(const QString &name, QString *ret, QSet<AbstractMacroExpander *> &seen)
{ {
// Prevent loops:
const int count = seen.count();
seen.insert(this);
if (seen.count() == count)
return false;
bool found; bool found;
*ret = value(name.toUtf8(), &found); *ret = value(name.toUtf8(), &found);
if (found) if (found)
return true; return true;
found = Utils::anyOf(m_subProviders, [name, ret] (const MacroExpanderProvider &p) -> bool { found = Utils::anyOf(m_subProviders, [name, ret, &seen] (const MacroExpanderProvider &p) -> bool {
MacroExpander *expander = p ? p() : 0; MacroExpander *expander = p ? p() : 0;
return expander && expander->resolveMacro(name, ret); return expander && expander->d->resolveMacro(name, ret, seen);
}); });
if (found) if (found)
@@ -75,7 +81,7 @@ public:
if (found) if (found)
return true; return true;
return this == globalMacroExpander()->d ? false : globalMacroExpander()->d->resolveMacro(name, ret); return this == globalMacroExpander()->d ? false : globalMacroExpander()->d->resolveMacro(name, ret, seen);
} }
QString value(const QByteArray &variable, bool *found) QString value(const QByteArray &variable, bool *found)
@@ -243,7 +249,8 @@ MacroExpander::~MacroExpander()
*/ */
bool MacroExpander::resolveMacro(const QString &name, QString *ret) const bool MacroExpander::resolveMacro(const QString &name, QString *ret) const
{ {
return d->resolveMacro(name, ret); QSet<AbstractMacroExpander*> seen;
return d->resolveMacro(name, ret, seen);
} }
/*! /*!

View File

@@ -68,8 +68,6 @@ QPlainTextEdit *OutputFormatter::plainTextEdit() const
void OutputFormatter::setPlainTextEdit(QPlainTextEdit *plainText) void OutputFormatter::setPlainTextEdit(QPlainTextEdit *plainText)
{ {
plainText->setReadOnly(true);
plainText->setTextInteractionFlags(plainText->textInteractionFlags() | Qt::TextSelectableByKeyboard);
d->plainTextEdit = plainText; d->plainTextEdit = plainText;
d->cursor = plainText ? plainText->textCursor() : QTextCursor(); d->cursor = plainText ? plainText->textCursor() : QTextCursor();
initFormats(); initFormats();

View File

@@ -31,6 +31,7 @@
#include <QDir> #include <QDir>
#include <QRegularExpression> #include <QRegularExpression>
#include <QSet>
#include <limits.h> #include <limits.h>
@@ -153,7 +154,8 @@ bool AbstractMacroExpander::expandNestedMacros(const QString &str, int *pos, QSt
*pos = i; *pos = i;
return true; return true;
} }
if (resolveMacro(varName, ret)) { QSet<AbstractMacroExpander*> seen;
if (resolveMacro(varName, ret, seen)) {
*pos = i; *pos = i;
if (!pattern.isEmpty() && currArg == &replace) { if (!pattern.isEmpty() && currArg == &replace) {
const QRegularExpression regexp(pattern); const QRegularExpression regexp(pattern);

View File

@@ -65,7 +65,7 @@ public:
//! \param name The name of the expando //! \param name The name of the expando
//! \param ret Replacement string on output //! \param ret Replacement string on output
//! \return True if the expando was found //! \return True if the expando was found
virtual bool resolveMacro(const QString &name, QString *ret) = 0; virtual bool resolveMacro(const QString &name, QString *ret, QSet<AbstractMacroExpander *> &seen) = 0;
private: private:
bool expandNestedMacros(const QString &str, int *pos, QString *ret); bool expandNestedMacros(const QString &str, int *pos, QString *ret);
}; };

View File

@@ -277,10 +277,6 @@ void BuildDirManager::generateProjectTree(CMakeProjectNode *root, const QList<co
const Utils::FileName projectFile = m_buildConfiguration->target()->project()->projectFilePath(); const Utils::FileName projectFile = m_buildConfiguration->target()->project()->projectFilePath();
m_reader->generateProjectTree(root, allFiles); m_reader->generateProjectTree(root, allFiles);
// Make sure the top level CMakeLists.txt is always visible:
if (root->isEmpty())
root->addNode(new FileNode(projectFile, FileType::Project, false));
} }
void BuildDirManager::updateCodeModel(CppTools::RawProjectParts &rpps) void BuildDirManager::updateCodeModel(CppTools::RawProjectParts &rpps)
@@ -336,7 +332,12 @@ QList<CMakeBuildTarget> BuildDirManager::buildTargets() const
m_buildTargets.append(utilityTarget(CMakeBuildStep::installTarget(), this)); m_buildTargets.append(utilityTarget(CMakeBuildStep::installTarget(), this));
m_buildTargets.append(utilityTarget(CMakeBuildStep::testTarget(), this)); m_buildTargets.append(utilityTarget(CMakeBuildStep::testTarget(), this));
m_buildTargets.append(m_reader->buildTargets()); m_buildTargets.append(Utils::filtered(m_reader->buildTargets(), [](const CMakeBuildTarget &bt) {
return bt.title != CMakeBuildStep::allTarget()
&& bt.title != CMakeBuildStep::cleanTarget()
&& bt.title != CMakeBuildStep::installTarget()
&& bt.title != CMakeBuildStep::testTarget();
}));
} }
return m_buildTargets; return m_buildTargets;
} }

View File

@@ -221,6 +221,10 @@ CMakeBuildConfiguration::generateProjectTree(const QList<const FileNode*> &allFi
auto root = new CMakeProjectNode(target()->project()->projectDirectory()); auto root = new CMakeProjectNode(target()->project()->projectDirectory());
m_buildDirManager->generateProjectTree(root, allFiles); m_buildDirManager->generateProjectTree(root, allFiles);
if (root->isEmpty()) {
delete root;
return nullptr;
}
return root; return root;
} }
@@ -280,7 +284,9 @@ QList<ConfigModel::DataItem> CMakeBuildConfiguration::completeCMakeConfiguration
j.values = i.values; j.values = i.values;
j.inCMakeCache = i.inCMakeCache; j.inCMakeCache = i.inCMakeCache;
j.isAdvanced = i.isAdvanced || i.type == CMakeConfigItem::INTERNAL; j.isAdvanced = i.isAdvanced;
j.isHidden = i.type == CMakeConfigItem::INTERNAL || i.type == CMakeConfigItem::STATIC;
switch (i.type) { switch (i.type) {
case CMakeConfigItem::FILEPATH: case CMakeConfigItem::FILEPATH:
j.type = ConfigModel::DataItem::FILE; j.type = ConfigModel::DataItem::FILE;

View File

@@ -267,7 +267,7 @@ void CMakeBuildStep::run(QFutureInterface<bool> &fi)
m_runTrigger = connect(bc, &CMakeBuildConfiguration::dataAvailable, m_runTrigger = connect(bc, &CMakeBuildConfiguration::dataAvailable,
this, [this, &fi]() { runImpl(fi); }); this, [this, &fi]() { runImpl(fi); });
m_errorTrigger = connect(bc, &CMakeBuildConfiguration::errorOccured, m_errorTrigger = connect(bc, &CMakeBuildConfiguration::errorOccured,
this, [this, &fi]() { reportRunResult(fi, false); }); this, [this, &fi](const QString& em) { handleCMakeError(fi, em); });
} else { } else {
runImpl(fi); runImpl(fi);
} }
@@ -276,10 +276,21 @@ void CMakeBuildStep::run(QFutureInterface<bool> &fi)
void CMakeBuildStep::runImpl(QFutureInterface<bool> &fi) void CMakeBuildStep::runImpl(QFutureInterface<bool> &fi)
{ {
// Do the actual build: // Do the actual build:
disconnectTriggers();
AbstractProcessStep::run(fi);
}
void CMakeBuildStep::handleCMakeError(QFutureInterface<bool> &fi, const QString& errorMessage)
{
disconnectTriggers();
AbstractProcessStep::stdError(tr("Error parsing CMake: %1\n").arg(errorMessage));
reportRunResult(fi, false);
}
void CMakeBuildStep::disconnectTriggers()
{
disconnect(m_runTrigger); disconnect(m_runTrigger);
disconnect(m_errorTrigger); disconnect(m_errorTrigger);
AbstractProcessStep::run(fi);
} }
BuildStepConfigWidget *CMakeBuildStep::createConfigWidget() BuildStepConfigWidget *CMakeBuildStep::createConfigWidget()

View File

@@ -104,6 +104,8 @@ private:
void ctor(ProjectExplorer::BuildStepList *bsl); void ctor(ProjectExplorer::BuildStepList *bsl);
void runImpl(QFutureInterface<bool> &fi); void runImpl(QFutureInterface<bool> &fi);
void handleCMakeError(QFutureInterface<bool> &fi, const QString& errorMessage);
void disconnectTriggers();
void handleBuildTargetChanges(); void handleBuildTargetChanges();
CMakeRunConfiguration *targetsActiveRunConfiguration() const; CMakeRunConfiguration *targetsActiveRunConfiguration() const;

View File

@@ -170,15 +170,20 @@ std::function<bool (const CMakeConfigItem &a, const CMakeConfigItem &b)> CMakeCo
CMakeConfigItem CMakeConfigItem::fromString(const QString &s) CMakeConfigItem CMakeConfigItem::fromString(const QString &s)
{ {
// Strip comments: // Strip comments (only at start of line!):
int commentStart = s.count(); int commentStart = s.count();
int pos = s.indexOf(QLatin1Char('#')); for (int i = 0; i < s.count(); ++i) {
if (pos >= 0) const QChar c = s.at(i);
commentStart = pos; if (c == ' ' || c == '\t')
pos = s.indexOf(QLatin1String("//")); continue;
if (pos >= 0 && pos < commentStart) else if ((c == '#')
commentStart = pos; || (c == '/' && i < s.count() - 1 && s.at(i + 1) == '/')) {
commentStart = i;
break;
} else {
break;
}
}
const QString line = s.mid(0, commentStart); const QString line = s.mid(0, commentStart);
// Split up line: // Split up line:

View File

@@ -32,7 +32,7 @@
using namespace CMakeProjectManager; using namespace CMakeProjectManager;
using namespace ProjectExplorer; using namespace ProjectExplorer;
const char COMMON_ERROR_PATTERN[] = "^CMake Error at (.*):([0-9]*) \\((.*)\\):"; const char COMMON_ERROR_PATTERN[] = "^CMake Error at (.*):([0-9]*)( \\((.*)\\))?:";
const char NEXT_SUBERROR_PATTERN[] = "^CMake Error in (.*):"; const char NEXT_SUBERROR_PATTERN[] = "^CMake Error in (.*):";
const char LOCATION_LINE_PATTERN[] = ":(\\d+):(?:(\\d+))?$"; const char LOCATION_LINE_PATTERN[] = ":(\\d+):(?:(\\d+))?$";
@@ -250,6 +250,20 @@ void Internal::CMakeProjectPlugin::testCMakeParser_data()
Utils::FileName(), -1, categoryBuild)) Utils::FileName(), -1, categoryBuild))
<< QString(); << QString();
QTest::newRow("cmake error at")
<< QString::fromLatin1("CMake Error at CMakeLists.txt:4:\n"
" Parse error. Expected \"(\", got newline with text \"\n"
"\n"
" \".\n")
<< OutputParserTester::STDERR
<< QString() << QString()
<< (QList<ProjectExplorer::Task>()
<< Task(Task::Error,
QLatin1String("Parse error. Expected \"(\", got newline with text \" \"."),
Utils::FileName::fromUserInput(QLatin1String("CMakeLists.txt")), 4,
categoryBuild))
<< QString();
QTest::newRow("cmake warning") QTest::newRow("cmake warning")
<< QString::fromLatin1("Syntax Warning in cmake code at\n" << QString::fromLatin1("Syntax Warning in cmake code at\n"
"/test/path/CMakeLists.txt:9:15\n" "/test/path/CMakeLists.txt:9:15\n"

View File

@@ -147,8 +147,8 @@ void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc)
auto newRoot = bc->generateProjectTree(m_allFiles); auto newRoot = bc->generateProjectTree(m_allFiles);
if (newRoot) { if (newRoot) {
setRootProjectNode(newRoot);
setDisplayName(newRoot->displayName()); setDisplayName(newRoot->displayName());
setRootProjectNode(newRoot);
} }
updateApplicationAndDeploymentTargets(); updateApplicationAndDeploymentTargets();
@@ -495,8 +495,13 @@ void CMakeProject::updateApplicationAndDeploymentTargets()
if (ct.targetType == UtilityType) if (ct.targetType == UtilityType)
continue; continue;
if (ct.targetType == ExecutableType || ct.targetType == DynamicLibraryType) if (ct.targetType == ExecutableType || ct.targetType == DynamicLibraryType) {
deploymentData.addFile(ct.executable.toString(), deploymentPrefix + buildDir.relativeFilePath(ct.executable.toFileInfo().dir().path()), DeployableFile::TypeExecutable); if (!ct.executable.isEmpty()) {
deploymentData.addFile(ct.executable.toString(),
deploymentPrefix + buildDir.relativeFilePath(ct.executable.toFileInfo().dir().path()),
DeployableFile::TypeExecutable);
}
}
if (ct.targetType == ExecutableType) { if (ct.targetType == ExecutableType) {
FileName srcWithTrailingSlash = FileName::fromString(ct.sourceDirectory.toString()); FileName srcWithTrailingSlash = FileName::fromString(ct.sourceDirectory.toString());
srcWithTrailingSlash.appendString('/'); srcWithTrailingSlash.appendString('/');

View File

@@ -257,7 +257,9 @@ void ConfigModel::setConfiguration(const QList<ConfigModel::DataItem> &config)
QList<InternalDataItem> result; QList<InternalDataItem> result;
while (newIt != newEndIt && oldIt != oldEndIt) { while (newIt != newEndIt && oldIt != oldEndIt) {
if (newIt->key < oldIt->key) { if (newIt->isHidden) {
++newIt;
} else if (newIt->key < oldIt->key) {
// Add new entry: // Add new entry:
result << InternalDataItem(*newIt); result << InternalDataItem(*newIt);
++newIt; ++newIt;
@@ -279,8 +281,11 @@ void ConfigModel::setConfiguration(const QList<ConfigModel::DataItem> &config)
} }
// Add remaining new entries: // Add remaining new entries:
for (; newIt != newEndIt; ++newIt) for (; newIt != newEndIt; ++newIt) {
if (newIt->isHidden)
continue;
result << InternalDataItem(*newIt); result << InternalDataItem(*newIt);
}
beginResetModel(); beginResetModel();
m_configuration = result; m_configuration = result;

View File

@@ -45,6 +45,7 @@ public:
QString key; QString key;
Type type = STRING; Type type = STRING;
bool isHidden = false;
bool isAdvanced = false; bool isAdvanced = false;
bool inCMakeCache = false; bool inCMakeCache = false;
QString value; QString value;

View File

@@ -73,6 +73,17 @@ ServerModeReader::ServerModeReader()
if (m_cmakeFiles.contains(document->filePath())) if (m_cmakeFiles.contains(document->filePath()))
emit dirty(); emit dirty();
}); });
connect(&m_parser, &CMakeParser::addOutput,
this, [](const QString &m) { Core::MessageManager::write(m); });
connect(&m_parser, &CMakeParser::addTask, this, [this](const Task &t) {
Task editable(t);
if (!editable.file.isEmpty()) {
QDir srcDir(m_parameters.sourceDirectory.toString());
editable.file = FileName::fromString(srcDir.absoluteFilePath(editable.file.toString()));
}
TaskHub::addTask(editable);
});
} }
ServerModeReader::~ServerModeReader() ServerModeReader::~ServerModeReader()
@@ -98,8 +109,13 @@ void ServerModeReader::setParameters(const BuildDirReader::Parameters &p)
this, &ServerModeReader::handleProgress); this, &ServerModeReader::handleProgress);
connect(m_cmakeServer.get(), &ServerMode::cmakeSignal, connect(m_cmakeServer.get(), &ServerMode::cmakeSignal,
this, &ServerModeReader::handleSignal); this, &ServerModeReader::handleSignal);
connect(m_cmakeServer.get(), &ServerMode::cmakeMessage, connect(m_cmakeServer.get(), &ServerMode::cmakeMessage, [this](const QString &m) {
this, [this](const QString &m) { Core::MessageManager::write(m); }); const QStringList lines = m.split('\n');
for (const QString &l : lines) {
m_parser.stdError(l);
Core::MessageManager::write(l);
}
});
connect(m_cmakeServer.get(), &ServerMode::message, connect(m_cmakeServer.get(), &ServerMode::message,
this, [](const QString &m) { Core::MessageManager::write(m); }); this, [](const QString &m) { Core::MessageManager::write(m); });
connect(m_cmakeServer.get(), &ServerMode::connected, connect(m_cmakeServer.get(), &ServerMode::connected,
@@ -170,6 +186,7 @@ void ServerModeReader::stop()
m_future->reportFinished(); m_future->reportFinished();
m_future.reset(); m_future.reset();
} }
m_parser.flush();
} }
bool ServerModeReader::isReady() const bool ServerModeReader::isReady() const
@@ -732,6 +749,9 @@ void ServerModeReader::addFileGroups(ProjectNode *targetRoot,
void ServerModeReader::addHeaderNodes(ProjectNode *root, const QList<FileNode *> knownHeaders, void ServerModeReader::addHeaderNodes(ProjectNode *root, const QList<FileNode *> knownHeaders,
const QList<const FileNode *> &allFiles) const QList<const FileNode *> &allFiles)
{ {
if (root->isEmpty())
return;
auto headerNode = new VirtualFolderNode(root->filePath(), Node::DefaultPriority - 5); auto headerNode = new VirtualFolderNode(root->filePath(), Node::DefaultPriority - 5);
headerNode->setDisplayName(tr("<Headers>")); headerNode->setDisplayName(tr("<Headers>"));

View File

@@ -27,6 +27,7 @@
#include "builddirreader.h" #include "builddirreader.h"
#include "servermode.h" #include "servermode.h"
#include "cmakeparser.h"
#include <memory> #include <memory>
@@ -148,6 +149,8 @@ private:
QList<Project *> m_projects; QList<Project *> m_projects;
mutable QList<Target *> m_targets; mutable QList<Target *> m_targets;
QList<FileGroup *> m_fileGroups; QList<FileGroup *> m_fileGroups;
CMakeParser m_parser;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -243,6 +243,10 @@ CMakeConfig TeaLeafReader::takeParsedConfiguration()
{ {
FileName cacheFile = m_parameters.buildDirectory; FileName cacheFile = m_parameters.buildDirectory;
cacheFile.appendPath(QLatin1String("CMakeCache.txt")); cacheFile.appendPath(QLatin1String("CMakeCache.txt"));
if (!cacheFile.exists())
return { };
QString errorMessage; QString errorMessage;
CMakeConfig result = BuildDirManager::parseConfiguration(cacheFile, &errorMessage); CMakeConfig result = BuildDirManager::parseConfiguration(cacheFile, &errorMessage);
@@ -266,6 +270,9 @@ CMakeConfig TeaLeafReader::takeParsedConfiguration()
void TeaLeafReader::generateProjectTree(CMakeProjectNode *root, const QList<const FileNode *> &allFiles) void TeaLeafReader::generateProjectTree(CMakeProjectNode *root, const QList<const FileNode *> &allFiles)
{ {
if (m_files.isEmpty())
return;
root->setDisplayName(m_projectName); root->setDisplayName(m_projectName);
// Delete no longer necessary file watcher based on m_cmakeFiles: // Delete no longer necessary file watcher based on m_cmakeFiles:

View File

@@ -25,6 +25,8 @@
#include "treescanner.h" #include "treescanner.h"
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <cpptools/cpptoolsconstants.h> #include <cpptools/cpptoolsconstants.h>
@@ -67,7 +69,10 @@ bool TreeScanner::asyncScanForFiles(const Utils::FileName &directory)
m_scanFuture = fi->future(); m_scanFuture = fi->future();
m_futureWatcher.setFuture(m_scanFuture); m_futureWatcher.setFuture(m_scanFuture);
Utils::runAsync([this, fi, directory]() { TreeScanner::scanForFiles(fi, directory, m_filter, m_factory); }); if (m_versionControls.isEmpty())
m_versionControls = Core::VcsManager::versionControls();
Utils::runAsync([this, fi, directory]() { TreeScanner::scanForFiles(fi, directory, m_filter, m_factory, m_versionControls); });
return true; return true;
} }
@@ -144,13 +149,17 @@ FileType TreeScanner::genericFileType(const Utils::MimeType &mimeType, const Uti
return Node::fileTypeForMimeType(mimeType); return Node::fileTypeForMimeType(mimeType);
} }
void TreeScanner::scanForFiles(FutureInterface *fi, const Utils::FileName& directory, const FileFilter &filter, const FileTypeFactory &factory) void TreeScanner::scanForFiles(FutureInterface *fi, const Utils::FileName& directory,
const FileFilter &filter, const FileTypeFactory &factory,
QList<Core::IVersionControl *> &versionControls)
{ {
std::unique_ptr<FutureInterface> fip(fi); std::unique_ptr<FutureInterface> fip(fi);
fip->reportStarted(); fip->reportStarted();
Result nodes = FileNode::scanForFiles(directory, Result nodes
[&filter, &factory](const Utils::FileName &fn) -> FileNode * { = FileNode::scanForFilesWithVersionControls(
directory,
[&filter, &factory](const Utils::FileName &fn) -> FileNode * {
const Utils::MimeType mimeType = Utils::mimeTypeForFile(fn.toString()); const Utils::MimeType mimeType = Utils::mimeTypeForFile(fn.toString());
// Skip some files during scan. // Skip some files during scan.
@@ -163,8 +172,7 @@ void TreeScanner::scanForFiles(FutureInterface *fi, const Utils::FileName& direc
type = factory(mimeType, fn); type = factory(mimeType, fn);
return new FileNode(fn, type, false); return new FileNode(fn, type, false);
}, }, versionControls, fip.get());
fip.get());
Utils::sort(nodes, ProjectExplorer::Node::sortByPath); Utils::sort(nodes, ProjectExplorer::Node::sortByPath);

View File

@@ -36,6 +36,8 @@
#include <functional> #include <functional>
namespace Core { class IVersionControl; }
namespace CMakeProjectManager { namespace CMakeProjectManager {
namespace Internal { namespace Internal {
@@ -86,7 +88,8 @@ signals:
private: private:
static void scanForFiles(FutureInterface *fi, const Utils::FileName &directory, static void scanForFiles(FutureInterface *fi, const Utils::FileName &directory,
const FileFilter &filter, const FileTypeFactory &factory); const FileFilter &filter, const FileTypeFactory &factory,
QList<Core::IVersionControl *> &versionControls);
private: private:
FileFilter m_filter; FileFilter m_filter;
@@ -94,6 +97,7 @@ private:
FutureWatcher m_futureWatcher; FutureWatcher m_futureWatcher;
Future m_scanFuture; Future m_scanFuture;
QList<Core::IVersionControl *> m_versionControls;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -100,6 +100,8 @@ public:
* *
* It will return true only for exact matches of the name, not for e.g. files in a * It will return true only for exact matches of the name, not for e.g. files in a
* directory owned by the version control system (e.g. .git/control). * directory owned by the version control system (e.g. .git/control).
*
* This method needs to be thread safe!
*/ */
virtual bool isVcsFileOrDirectory(const Utils::FileName &fileName) const = 0; virtual bool isVcsFileOrDirectory(const Utils::FileName &fileName) const = 0;

View File

@@ -300,6 +300,7 @@ void CompilerOptionsBuilder::addDefineToAvoidIncludingGccOrMinGwIntrinsics()
if (type == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID if (type == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID
|| type == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID) { || type == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID) {
addDefine("#define _X86INTRIN_H_INCLUDED"); addDefine("#define _X86INTRIN_H_INCLUDED");
addDefine("#define BOOST_UUID_NO_SIMD");
} }
} }

View File

@@ -2303,26 +2303,32 @@ void DebuggerPluginPrivate::requestContextMenu(TextEditorWidget *widget,
} }
// Run to, jump to line below in stopped state. // Run to, jump to line below in stopped state.
if (currentEngine()->state() == InferiorStopOk && args.isValid()) { DebuggerEngine *engine = currentEngine();
QTC_ASSERT(engine, return);
if (engine->state() == InferiorStopOk && args.isValid()) {
menu->addSeparator(); menu->addSeparator();
if (currentEngine()->hasCapability(RunToLineCapability)) { if (engine->hasCapability(RunToLineCapability)) {
auto act = menu->addAction(args.address auto act = menu->addAction(args.address
? DebuggerEngine::tr("Run to Address 0x%1").arg(args.address, 0, 16) ? DebuggerEngine::tr("Run to Address 0x%1").arg(args.address, 0, 16)
: DebuggerEngine::tr("Run to Line %1").arg(args.lineNumber)); : DebuggerEngine::tr("Run to Line %1").arg(args.lineNumber));
connect(act, &QAction::triggered, [this, args] { connect(act, &QAction::triggered, [this, args] {
currentEngine()->executeRunToLine(args); DebuggerEngine *engine = currentEngine();
QTC_ASSERT(engine, return);
engine->executeRunToLine(args);
}); });
} }
if (currentEngine()->hasCapability(JumpToLineCapability)) { if (engine->hasCapability(JumpToLineCapability)) {
auto act = menu->addAction(args.address auto act = menu->addAction(args.address
? DebuggerEngine::tr("Jump to Address 0x%1").arg(args.address, 0, 16) ? DebuggerEngine::tr("Jump to Address 0x%1").arg(args.address, 0, 16)
: DebuggerEngine::tr("Jump to Line %1").arg(args.lineNumber)); : DebuggerEngine::tr("Jump to Line %1").arg(args.lineNumber));
connect(act, &QAction::triggered, [this, args] { connect(act, &QAction::triggered, [this, args] {
currentEngine()->executeJumpToLine(args); DebuggerEngine *engine = currentEngine();
QTC_ASSERT(engine, return);
engine->executeJumpToLine(args);
}); });
} }
// Disassemble current function in stopped state. // Disassemble current function in stopped state.
if (currentEngine()->hasCapability(DisassemblerCapability)) { if (engine->hasCapability(DisassemblerCapability)) {
StackFrame frame; StackFrame frame;
frame.function = cppFunctionAt(args.fileName, lineNumber, 1); frame.function = cppFunctionAt(args.fileName, lineNumber, 1);
frame.line = 42; // trick gdb into mixed mode. frame.line = 42; // trick gdb into mixed mode.
@@ -2331,7 +2337,9 @@ void DebuggerPluginPrivate::requestContextMenu(TextEditorWidget *widget,
.arg(frame.function); .arg(frame.function);
auto act = new QAction(text, menu); auto act = new QAction(text, menu);
connect(act, &QAction::triggered, [this, frame] { connect(act, &QAction::triggered, [this, frame] {
currentEngine()->openDisassemblerView(Location(frame)); DebuggerEngine *engine = currentEngine();
QTC_ASSERT(engine, return);
engine->openDisassemblerView(Location(frame));
}); });
menu->addAction(act); menu->addAction(act);
} }

View File

@@ -31,6 +31,8 @@
#include "../nimconstants.h" #include "../nimconstants.h"
#include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
#include <projectexplorer/buildconfiguration.h> #include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/kit.h> #include <projectexplorer/kit.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
@@ -113,8 +115,11 @@ void NimProject::collectProjectFiles()
m_lastProjectScan.start(); m_lastProjectScan.start();
QTC_ASSERT(!m_futureWatcher.future().isRunning(), return); QTC_ASSERT(!m_futureWatcher.future().isRunning(), return);
FileName prjDir = projectDirectory(); FileName prjDir = projectDirectory();
QFuture<QList<ProjectExplorer::FileNode *>> future = Utils::runAsync([prjDir] { const QList<Core::IVersionControl *> versionControls = Core::VcsManager::versionControls();
return FileNode::scanForFiles(prjDir, [](const FileName &fn) { return new FileNode(fn, FileType::Source, false); }); QFuture<QList<ProjectExplorer::FileNode *>> future = Utils::runAsync([prjDir, versionControls] {
return FileNode::scanForFilesWithVersionControls(
prjDir, [](const FileName &fn) { return new FileNode(fn, FileType::Source, false); },
versionControls);
}); });
m_futureWatcher.setFuture(future); m_futureWatcher.setFuture(future);
Core::ProgressManager::addTask(future, tr("Scanning for Nim files"), "Nim.Project.Scan"); Core::ProgressManager::addTask(future, tr("Scanning for Nim files"), "Nim.Project.Scan");

View File

@@ -149,7 +149,10 @@ void TabWidget::slotContextMenuRequested(const QPoint &pos)
AppOutputPane::RunControlTab::RunControlTab(RunControl *rc, Core::OutputWindow *w) : AppOutputPane::RunControlTab::RunControlTab(RunControl *rc, Core::OutputWindow *w) :
runControl(rc), window(w) runControl(rc), window(w)
{ } {
if (rc && w)
w->setFormatter(rc->outputFormatter());
}
AppOutputPane::AppOutputPane() : AppOutputPane::AppOutputPane() :
m_mainWidget(new QWidget), m_mainWidget(new QWidget),
@@ -262,7 +265,7 @@ AppOutputPane::~AppOutputPane()
qDebug() << "OutputPane::~OutputPane: Entries left" << m_runControlTabs.size(); qDebug() << "OutputPane::~OutputPane: Entries left" << m_runControlTabs.size();
foreach (const RunControlTab &rt, m_runControlTabs) { foreach (const RunControlTab &rt, m_runControlTabs) {
rt.window->setFormatter(nullptr); delete rt.window;
delete rt.runControl; delete rt.runControl;
} }
delete m_mainWidget; delete m_mainWidget;
@@ -416,13 +419,14 @@ void AppOutputPane::createNewOutputWindow(RunControl *rc)
RunControlTab &tab = m_runControlTabs[tabIndex]; RunControlTab &tab = m_runControlTabs[tabIndex];
// Reuse this tab // Reuse this tab
delete tab.runControl; delete tab.runControl;
handleOldOutput(tab.window);
tab.runControl = rc; tab.runControl = rc;
tab.window->setFormatter(rc ? rc->outputFormatter() : nullptr);
handleOldOutput(tab.window);
// Update the title. // Update the title.
m_tabWidget->setTabText(tabIndex, rc->displayName()); m_tabWidget->setTabText(tabIndex, rc->displayName());
tab.window->setFormatter(nullptr);
tab.window->scrollToBottom(); tab.window->scrollToBottom();
if (debug) if (debug)
qDebug() << "OutputPane::createNewOutputWindow: Reusing tab" << tabIndex << " for " << rc; qDebug() << "OutputPane::createNewOutputWindow: Reusing tab" << tabIndex << " for " << rc;
@@ -435,7 +439,6 @@ void AppOutputPane::createNewOutputWindow(RunControl *rc)
Core::OutputWindow *ow = new Core::OutputWindow(context, m_tabWidget); Core::OutputWindow *ow = new Core::OutputWindow(context, m_tabWidget);
ow->setWindowTitle(tr("Application Output Window")); ow->setWindowTitle(tr("Application Output Window"));
ow->setWindowIcon(Icons::WINDOW.icon()); ow->setWindowIcon(Icons::WINDOW.icon());
ow->setFormatter(nullptr);
ow->setWordWrapEnabled(ProjectExplorerPlugin::projectExplorerSettings().wrapAppOutput); ow->setWordWrapEnabled(ProjectExplorerPlugin::projectExplorerSettings().wrapAppOutput);
ow->setMaxLineCount(ProjectExplorerPlugin::projectExplorerSettings().maxAppOutputLines); ow->setMaxLineCount(ProjectExplorerPlugin::projectExplorerSettings().maxAppOutputLines);
ow->setWheelZoomEnabled(TextEditor::TextEditorSettings::behaviorSettings().m_scrollWheelZooming); ow->setWheelZoomEnabled(TextEditor::TextEditorSettings::behaviorSettings().m_scrollWheelZooming);
@@ -590,9 +593,8 @@ bool AppOutputPane::closeTab(int tabIndex, CloseTabMode closeTabMode)
} }
m_tabWidget->removeTab(tabIndex); m_tabWidget->removeTab(tabIndex);
m_runControlTabs[index].window->setFormatter(nullptr);
delete m_runControlTabs[index].runControl;
delete m_runControlTabs[index].window; delete m_runControlTabs[index].window;
delete m_runControlTabs[index].runControl;
m_runControlTabs.removeAt(index); m_runControlTabs.removeAt(index);
updateCloseActions(); updateCloseActions();
@@ -706,10 +708,6 @@ void AppOutputPane::contextMenuRequested(const QPoint &pos, int index)
void AppOutputPane::slotRunControlStarted() void AppOutputPane::slotRunControlStarted()
{ {
RunControl *current = currentRunControl(); RunControl *current = currentRunControl();
const int rcIndex = indexOf(current);
if (rcIndex >= 0 && m_runControlTabs.at(rcIndex).window)
m_runControlTabs.at(rcIndex).window->setFormatter(current->outputFormatter());
if (current && current == sender()) if (current && current == sender())
enableButtons(current, true); // RunControl::isRunning() cannot be trusted in signal handler. enableButtons(current, true); // RunControl::isRunning() cannot be trusted in signal handler.
} }
@@ -740,8 +738,6 @@ void AppOutputPane::slotRunControlFinished2(RunControl *sender)
if (current && current == sender) if (current && current == sender)
enableButtons(current, false); // RunControl::isRunning() cannot be trusted in signal handler. enableButtons(current, false); // RunControl::isRunning() cannot be trusted in signal handler.
m_runControlTabs.at(senderIndex).window->setFormatter(nullptr); // Reset formater for this RC
ProjectExplorerPlugin::instance()->updateRunActions(); ProjectExplorerPlugin::instance()->updateRunActions();
if (!isRunning()) if (!isRunning())

View File

@@ -339,7 +339,8 @@ FileType FileNode::fileType() const
static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &directory, static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &directory,
const std::function<FileNode *(const Utils::FileName &)> factory, const std::function<FileNode *(const Utils::FileName &)> factory,
QSet<QString> &visited, QFutureInterface<QList<FileNode*>> *future, QSet<QString> &visited, QFutureInterface<QList<FileNode*>> *future,
double progressStart, double progressRange) double progressStart, double progressRange,
const QList<Core::IVersionControl*> &versionControls)
{ {
QList<FileNode *> result; QList<FileNode *> result;
@@ -351,8 +352,6 @@ static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &director
if (visitedCount == visited.count()) if (visitedCount == visited.count())
return result; return result;
const Core::IVersionControl *vcsControl
= Core::VcsManager::findVersionControlForDirectory(baseDir.absolutePath(), nullptr);
const QList<QFileInfo> entries = baseDir.entryInfoList(QStringList(), QDir::AllEntries|QDir::NoDotAndDotDot); const QList<QFileInfo> entries = baseDir.entryInfoList(QStringList(), QDir::AllEntries|QDir::NoDotAndDotDot);
double progress = 0; double progress = 0;
const double progressIncrement = progressRange / static_cast<double>(entries.count()); const double progressIncrement = progressRange / static_cast<double>(entries.count());
@@ -362,9 +361,11 @@ static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &director
return result; return result;
const Utils::FileName entryName = Utils::FileName::fromString(entry.absoluteFilePath()); const Utils::FileName entryName = Utils::FileName::fromString(entry.absoluteFilePath());
if (!vcsControl || !vcsControl->isVcsFileOrDirectory(entryName)) { if (!Utils::contains(versionControls, [&entryName](const Core::IVersionControl *vc) {
return vc->isVcsFileOrDirectory(entryName);
})) {
if (entry.isDir()) if (entry.isDir())
result.append(scanForFilesRecursively(entryName, factory, visited, future, progress, progressIncrement)); result.append(scanForFilesRecursively(entryName, factory, visited, future, progress, progressIncrement, versionControls));
else if (FileNode *node = factory(entryName)) else if (FileNode *node = factory(entryName))
result.append(node); result.append(node);
} }
@@ -382,14 +383,24 @@ static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &director
return result; return result;
} }
QList<FileNode *> FileNode::scanForFiles(const Utils::FileName &directory, QList<FileNode *> FileNode::scanForFiles(const Utils::FileName &directory,
const std::function<FileNode *(const Utils::FileName &)> factory, const std::function<FileNode *(const Utils::FileName &)> factory,
QFutureInterface<QList<FileNode *>> *future) QFutureInterface<QList<FileNode *> > *future)
{
return FileNode::scanForFilesWithVersionControls(directory, factory, QList<Core::IVersionControl *>(), future);
}
QList<FileNode *>
FileNode::scanForFilesWithVersionControls(const Utils::FileName &directory,
const std::function<FileNode *(const Utils::FileName &)> factory,
const QList<Core::IVersionControl *> &versionControls,
QFutureInterface<QList<FileNode *>> *future)
{ {
QSet<QString> visited; QSet<QString> visited;
if (future) if (future)
future->setProgressRange(0, 1000000); future->setProgressRange(0, 1000000);
return scanForFilesRecursively(directory, factory, visited, future, 0.0, 1000000.0); return scanForFilesRecursively(directory, factory, visited, future, 0.0, 1000000.0, versionControls);
} }
bool FileNode::supportsAction(ProjectAction action, Node *node) const bool FileNode::supportsAction(ProjectAction action, Node *node) const

View File

@@ -37,6 +37,7 @@
#include <functional> #include <functional>
namespace Utils { class MimeType; } namespace Utils { class MimeType; }
namespace Core { class IVersionControl; }
namespace ProjectExplorer { namespace ProjectExplorer {
@@ -188,9 +189,16 @@ public:
FileNode *asFileNode() final { return this; } FileNode *asFileNode() final { return this; }
const FileNode *asFileNode() const final { return this; } const FileNode *asFileNode() const final { return this; }
// For ABI compatibility, remove in QtC 4.4:
static QList<FileNode *> scanForFiles(const Utils::FileName &directory, static QList<FileNode *> scanForFiles(const Utils::FileName &directory,
const std::function<FileNode *(const Utils::FileName &fileName)> factory, const std::function<FileNode *(const Utils::FileName &fileName)> factory,
QFutureInterface<QList<FileNode *>> *future = nullptr); QFutureInterface<QList<FileNode *>> *future = nullptr);
static QList<FileNode *>
scanForFilesWithVersionControls(const Utils::FileName &directory,
const std::function<FileNode *(const Utils::FileName &fileName)> factory,
const QList<Core::IVersionControl *> &versionControls,
QFutureInterface<QList<FileNode *>> *future = nullptr);
bool supportsAction(ProjectAction action, Node *node) const override; bool supportsAction(ProjectAction action, Node *node) const override;
private: private:

View File

@@ -330,7 +330,7 @@ void QmakeProjectManagerPlugin::updateContextActions()
Project *project = ProjectTree::currentProject(); Project *project = ProjectTree::currentProject();
ContainerNode *containerNode = node ? node->asContainerNode() : nullptr; ContainerNode *containerNode = node ? node->asContainerNode() : nullptr;
ProjectNode *proFileNode = containerNode ? containerNode->rootProjectNode() : dynamic_cast<QmakeProFileNode *>(node); QmakeProFileNode *proFileNode = dynamic_cast<QmakeProFileNode *>(containerNode ? containerNode->rootProjectNode() : node);
m_addLibraryActionContextMenu->setEnabled(proFileNode); m_addLibraryActionContextMenu->setEnabled(proFileNode);
QmakeProject *qmakeProject = qobject_cast<QmakeProject *>(QmakeManager::contextProject()); QmakeProject *qmakeProject = qobject_cast<QmakeProject *>(QmakeManager::contextProject());

View File

@@ -26,6 +26,7 @@
#include "gradientmodel.h" #include "gradientmodel.h"
#include "qmlanchorbindingproxy.h" #include "qmlanchorbindingproxy.h"
#include "propertyeditorview.h"
#include <nodeproperty.h> #include <nodeproperty.h>
#include <nodelistproperty.h> #include <nodelistproperty.h>
@@ -35,7 +36,7 @@
#include <rewritertransaction.h> #include <rewritertransaction.h>
GradientModel::GradientModel(QObject *parent) : GradientModel::GradientModel(QObject *parent) :
QAbstractListModel(parent), m_lock(false) QAbstractListModel(parent), m_locked(false)
{ {
} }
@@ -93,7 +94,7 @@ QVariant GradientModel::data(const QModelIndex &index, int role) const
int GradientModel::addStop(qreal position, const QColor &color) int GradientModel::addStop(qreal position, const QColor &color)
{ {
if (m_lock) if (m_locked)
return -1; return -1;
if (!m_itemNode.isValid() || gradientPropertyName().isEmpty()) if (!m_itemNode.isValid() || gradientPropertyName().isEmpty())
@@ -131,7 +132,7 @@ int GradientModel::addStop(qreal position, const QColor &color)
void GradientModel::addGradient() void GradientModel::addGradient()
{ {
if (m_lock) if (m_locked)
return; return;
if (!m_itemNode.isValid() || gradientPropertyName().isEmpty()) if (!m_itemNode.isValid() || gradientPropertyName().isEmpty())
@@ -174,7 +175,7 @@ void GradientModel::addGradient()
void GradientModel::setColor(int index, const QColor &color) void GradientModel::setColor(int index, const QColor &color)
{ {
if (m_lock) if (locked())
return; return;
if (!m_itemNode.modelNode().isSelected()) if (!m_itemNode.modelNode().isSelected())
@@ -191,7 +192,7 @@ void GradientModel::setColor(int index, const QColor &color)
void GradientModel::setPosition(int index, qreal positition) void GradientModel::setPosition(int index, qreal positition)
{ {
if (m_lock) if (locked())
return; return;
if (index < rowCount()) { if (index < rowCount()) {
@@ -266,12 +267,12 @@ void GradientModel::deleteGradient()
void GradientModel::lock() void GradientModel::lock()
{ {
m_lock = true; m_locked = true;
} }
void GradientModel::unlock() void GradientModel::unlock()
{ {
m_lock = false; m_locked = false;
} }
void GradientModel::registerDeclarativeType() void GradientModel::registerDeclarativeType()
@@ -281,11 +282,11 @@ void GradientModel::registerDeclarativeType()
void GradientModel::setupModel() void GradientModel::setupModel()
{ {
m_lock = true; m_locked = true;
beginResetModel(); beginResetModel();
endResetModel(); endResetModel();
m_lock = false; m_locked = false;
} }
void GradientModel::setAnchorBackend(const QVariant &anchorBackend) void GradientModel::setAnchorBackend(const QVariant &anchorBackend)
@@ -300,12 +301,12 @@ void GradientModel::setAnchorBackend(const QVariant &anchorBackend)
setupModel(); setupModel();
m_lock = true; m_locked = true;
emit anchorBackendChanged(); emit anchorBackendChanged();
emit hasGradientChanged(); emit hasGradientChanged();
m_lock = false; m_locked = false;
} }
QString GradientModel::gradientPropertyName() const QString GradientModel::gradientPropertyName() const
@@ -323,3 +324,16 @@ bool GradientModel::hasGradient() const
return m_itemNode.isValid() return m_itemNode.isValid()
&& m_itemNode.modelNode().hasProperty(gradientPropertyName().toUtf8()); && m_itemNode.modelNode().hasProperty(gradientPropertyName().toUtf8());
} }
bool GradientModel::locked() const
{
if (m_locked)
return true;
QmlDesigner::PropertyEditorView *view = qobject_cast<QmlDesigner::PropertyEditorView*>(m_itemNode.view());
if (view && view->locked())
return true;
return false;
}

View File

@@ -76,11 +76,12 @@ private:
QString gradientPropertyName() const; QString gradientPropertyName() const;
void setGradientPropertyName(const QString &name); void setGradientPropertyName(const QString &name);
bool hasGradient() const; bool hasGradient() const;
bool locked() const;
private: private:
QmlDesigner::QmlItemNode m_itemNode; QmlDesigner::QmlItemNode m_itemNode;
QString m_gradientPropertyName; QString m_gradientPropertyName;
bool m_lock; bool m_locked;
}; };

View File

@@ -135,7 +135,7 @@ void PropertyEditorView::changeValue(const QString &name)
if (propertyName.isNull()) if (propertyName.isNull())
return; return;
if (m_locked) if (locked())
return; return;
if (propertyName == "className") if (propertyName == "className")
@@ -231,7 +231,7 @@ void PropertyEditorView::changeExpression(const QString &propertyName)
if (name.isNull()) if (name.isNull())
return; return;
if (m_locked) if (locked())
return; return;
if (!m_selectedNode.isValid()) if (!m_selectedNode.isValid())
@@ -306,7 +306,7 @@ void PropertyEditorView::exportPopertyAsAlias(const QString &name)
if (name.isNull()) if (name.isNull())
return; return;
if (m_locked) if (locked())
return; return;
if (!m_selectedNode.isValid()) if (!m_selectedNode.isValid())
@@ -340,7 +340,7 @@ void PropertyEditorView::removeAliasExport(const QString &name)
if (name.isNull()) if (name.isNull())
return; return;
if (m_locked) if (locked())
return; return;
if (!m_selectedNode.isValid()) if (!m_selectedNode.isValid())
@@ -362,6 +362,11 @@ void PropertyEditorView::removeAliasExport(const QString &name)
} }
} }
bool PropertyEditorView::locked() const
{
return m_locked;
}
void PropertyEditorView::updateSize() void PropertyEditorView::updateSize()
{ {
if (!m_qmlBackEndForCurrentType) if (!m_qmlBackEndForCurrentType)
@@ -523,7 +528,6 @@ void PropertyEditorView::modelAttached(Model *model)
m_locked = true; m_locked = true;
resetView();
if (!m_setupCompleted) { if (!m_setupCompleted) {
m_singleShotTimer->setSingleShot(true); m_singleShotTimer->setSingleShot(true);
m_singleShotTimer->setInterval(100); m_singleShotTimer->setInterval(100);
@@ -532,6 +536,8 @@ void PropertyEditorView::modelAttached(Model *model)
} }
m_locked = false; m_locked = false;
resetView();
} }
void PropertyEditorView::modelAboutToBeDetached(Model *model) void PropertyEditorView::modelAboutToBeDetached(Model *model)

View File

@@ -92,6 +92,8 @@ public:
void exportPopertyAsAlias(const QString &name); void exportPopertyAsAlias(const QString &name);
void removeAliasExport(const QString &name); void removeAliasExport(const QString &name);
bool locked() const;
protected: protected:
void timerEvent(QTimerEvent *event) override; void timerEvent(QTimerEvent *event) override;
void setupPane(const TypeName &typeName); void setupPane(const TypeName &typeName);

View File

@@ -344,7 +344,7 @@ QString NodeInstanceServerProxy::qrcMappingString() const
foreach (const StringPair &pair, rewriterView->qrcMapping()) { foreach (const StringPair &pair, rewriterView->qrcMapping()) {
if (!mappingString.isEmpty()) if (!mappingString.isEmpty())
mappingString.append(QLatin1String(",")); mappingString.append(QLatin1String(";"));
mappingString.append(pair.first); mappingString.append(pair.first);
mappingString.append(QLatin1String("=")); mappingString.append(QLatin1String("="));
mappingString.append(pair.second); mappingString.append(pair.second);

View File

@@ -34,8 +34,14 @@ using namespace Utils;
class MacroMapExpander : public AbstractMacroExpander { class MacroMapExpander : public AbstractMacroExpander {
public: public:
virtual bool resolveMacro(const QString &name, QString *ret) virtual bool resolveMacro(const QString &name, QString *ret, QSet<AbstractMacroExpander*> &seen)
{ {
// loop prevention
const int count = seen.count();
seen.insert(this);
if (seen.count() == count)
return false;
QHash<QString, QString>::const_iterator it = m_map.constFind(name); QHash<QString, QString>::const_iterator it = m_map.constFind(name);
if (it != m_map.constEnd()) { if (it != m_map.constEnd()) {
*ret = it.value(); *ret = it.value();

View File

@@ -32,8 +32,14 @@
class TestMacroExpander : public Utils::AbstractMacroExpander class TestMacroExpander : public Utils::AbstractMacroExpander
{ {
public: public:
virtual bool resolveMacro(const QString &name, QString *ret) virtual bool resolveMacro(const QString &name, QString *ret, QSet<AbstractMacroExpander*> &seen)
{ {
// loop prevention
const int count = seen.count();
seen.insert(this);
if (seen.count() == count)
return false;
if (name == QLatin1String("foo")) { if (name == QLatin1String("foo")) {
*ret = QLatin1String("a"); *ret = QLatin1String("a");
return true; return true;