From 4dc3ef8034d026e968146fd47e4c7dc0d4a29d34 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 20 Jun 2017 11:15:38 +0200 Subject: [PATCH 01/23] Qmake: Only offer Add Library wizard for qmake projects Task-number: QTCREATORBUG-18415 Change-Id: Icd8535a6d7d599457c23f92958fa969661076ade Reviewed-by: Tim Jenssen Reviewed-by: Eike Ziller --- src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp index 6022602f517..817676bfeea 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp @@ -330,7 +330,7 @@ void QmakeProjectManagerPlugin::updateContextActions() Project *project = ProjectTree::currentProject(); ContainerNode *containerNode = node ? node->asContainerNode() : nullptr; - ProjectNode *proFileNode = containerNode ? containerNode->rootProjectNode() : dynamic_cast(node); + QmakeProFileNode *proFileNode = dynamic_cast(containerNode ? containerNode->rootProjectNode() : node); m_addLibraryActionContextMenu->setEnabled(proFileNode); QmakeProject *qmakeProject = qobject_cast(QmakeManager::contextProject()); From 7e81d330d9c6346f8dc485666709b787f6482d3f Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 20 Jun 2017 12:07:07 +0200 Subject: [PATCH 02/23] CMake: Hide INTERNAL and STATIC configuration entries in Project UI Task-number: QTCREATORBUG-18403 Change-Id: I6b69305ff0dc337da1d8b20e0321be5ce1b1f595 Reviewed-by: Tim Jenssen Reviewed-by: Eike Ziller --- .../cmakeprojectmanager/cmakebuildconfiguration.cpp | 4 +++- src/plugins/cmakeprojectmanager/configmodel.cpp | 9 +++++++-- src/plugins/cmakeprojectmanager/configmodel.h | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 8ae17f13d72..8bba67e359c 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -280,7 +280,9 @@ QList CMakeBuildConfiguration::completeCMakeConfiguration j.values = i.values; 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) { case CMakeConfigItem::FILEPATH: j.type = ConfigModel::DataItem::FILE; diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index 98d9cf05b7a..7336a2a7a2b 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -257,7 +257,9 @@ void ConfigModel::setConfiguration(const QList &config) QList result; while (newIt != newEndIt && oldIt != oldEndIt) { - if (newIt->key < oldIt->key) { + if (newIt->isHidden) { + ++newIt; + } else if (newIt->key < oldIt->key) { // Add new entry: result << InternalDataItem(*newIt); ++newIt; @@ -279,8 +281,11 @@ void ConfigModel::setConfiguration(const QList &config) } // Add remaining new entries: - for (; newIt != newEndIt; ++newIt) + for (; newIt != newEndIt; ++newIt) { + if (newIt->isHidden) + continue; result << InternalDataItem(*newIt); + } beginResetModel(); m_configuration = result; diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h index 94fef0b6648..f9629f702fa 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.h +++ b/src/plugins/cmakeprojectmanager/configmodel.h @@ -45,6 +45,7 @@ public: QString key; Type type = STRING; + bool isHidden = false; bool isAdvanced = false; bool inCMakeCache = false; QString value; From ba8e7d11562f7d2c811fd3a211fc7c429cddf3c3 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Thu, 15 Jun 2017 10:48:16 +0200 Subject: [PATCH 03/23] CMake: Report more cmake errors in server mode Handle more kinds of errors in CMake server-mode. Task-number: QTCREATORBUG-18318 Change-Id: I43fff7f3cfbd86d01ff05a0936261b8d91aa5d70 Reviewed-by: Eike Ziller Reviewed-by: Tim Jenssen --- .../cmakeprojectmanager/servermodereader.cpp | 21 +++++++++++++++++-- .../cmakeprojectmanager/servermodereader.h | 3 +++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/servermodereader.cpp b/src/plugins/cmakeprojectmanager/servermodereader.cpp index a99b6cc77cb..e17843c02d9 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.cpp +++ b/src/plugins/cmakeprojectmanager/servermodereader.cpp @@ -73,6 +73,17 @@ ServerModeReader::ServerModeReader() if (m_cmakeFiles.contains(document->filePath())) 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() @@ -98,8 +109,13 @@ void ServerModeReader::setParameters(const BuildDirReader::Parameters &p) this, &ServerModeReader::handleProgress); connect(m_cmakeServer.get(), &ServerMode::cmakeSignal, this, &ServerModeReader::handleSignal); - connect(m_cmakeServer.get(), &ServerMode::cmakeMessage, - this, [this](const QString &m) { Core::MessageManager::write(m); }); + connect(m_cmakeServer.get(), &ServerMode::cmakeMessage, [this](const QString &m) { + const QStringList lines = m.split('\n'); + for (const QString &l : lines) { + m_parser.stdError(l); + Core::MessageManager::write(l + "\n"); + } + }); connect(m_cmakeServer.get(), &ServerMode::message, this, [](const QString &m) { Core::MessageManager::write(m); }); connect(m_cmakeServer.get(), &ServerMode::connected, @@ -168,6 +184,7 @@ void ServerModeReader::stop() m_future->reportFinished(); m_future.reset(); } + m_parser.flush(); } bool ServerModeReader::isReady() const diff --git a/src/plugins/cmakeprojectmanager/servermodereader.h b/src/plugins/cmakeprojectmanager/servermodereader.h index 0c3a3c2fd8c..4265d9627c3 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.h +++ b/src/plugins/cmakeprojectmanager/servermodereader.h @@ -27,6 +27,7 @@ #include "builddirreader.h" #include "servermode.h" +#include "cmakeparser.h" #include @@ -148,6 +149,8 @@ private: QList m_projects; mutable QList m_targets; QList m_fileGroups; + + CMakeParser m_parser; }; } // namespace Internal From 4e96f2ce22e1a01b08b196e9b940034d50b87460 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Wed, 7 Jun 2017 16:50:04 +0200 Subject: [PATCH 04/23] MacroExpander: Prevent loop with subproviders Prevent a loop where a subprovider of a macroexpander creates the macroexpander itself. Change-Id: Id2f3e29651aeb22c818091d8c785a6ea01545463 Reviewed-by: Tim Jenssen --- src/libs/utils/macroexpander.cpp | 17 ++++++++++++----- src/libs/utils/stringutils.cpp | 4 +++- src/libs/utils/stringutils.h | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/libs/utils/macroexpander.cpp b/src/libs/utils/macroexpander.cpp index 6aa965a942c..755f2e0a89c 100644 --- a/src/libs/utils/macroexpander.cpp +++ b/src/libs/utils/macroexpander.cpp @@ -53,16 +53,22 @@ public: : m_accumulating(false), m_aborted(false), m_lockDepth(0) {} - bool resolveMacro(const QString &name, QString *ret) + bool resolveMacro(const QString &name, QString *ret, QSet &seen) { + // Prevent loops: + const int count = seen.count(); + seen.insert(this); + if (seen.count() == count) + return false; + bool found; *ret = value(name.toUtf8(), &found); if (found) 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; - return expander && expander->resolveMacro(name, ret); + return expander && expander->d->resolveMacro(name, ret, seen); }); if (found) @@ -75,7 +81,7 @@ public: if (found) 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) @@ -243,7 +249,8 @@ MacroExpander::~MacroExpander() */ bool MacroExpander::resolveMacro(const QString &name, QString *ret) const { - return d->resolveMacro(name, ret); + QSet seen; + return d->resolveMacro(name, ret, seen); } /*! diff --git a/src/libs/utils/stringutils.cpp b/src/libs/utils/stringutils.cpp index 85813004dec..04df87fb5f2 100644 --- a/src/libs/utils/stringutils.cpp +++ b/src/libs/utils/stringutils.cpp @@ -31,6 +31,7 @@ #include #include +#include #include @@ -153,7 +154,8 @@ bool AbstractMacroExpander::expandNestedMacros(const QString &str, int *pos, QSt *pos = i; return true; } - if (resolveMacro(varName, ret)) { + QSet seen; + if (resolveMacro(varName, ret, seen)) { *pos = i; if (!pattern.isEmpty() && currArg == &replace) { const QRegularExpression regexp(pattern); diff --git a/src/libs/utils/stringutils.h b/src/libs/utils/stringutils.h index 8e0c78f028f..20f6063710c 100644 --- a/src/libs/utils/stringutils.h +++ b/src/libs/utils/stringutils.h @@ -65,7 +65,7 @@ public: //! \param name The name of the expando //! \param ret Replacement string on output //! \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 &seen) = 0; private: bool expandNestedMacros(const QString &str, int *pos, QString *ret); }; From 0652297f5adaacee924d3d4fbaaf1db205432f54 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 20 Jun 2017 14:28:45 +0200 Subject: [PATCH 05/23] AppOutputPane: Do not reset the formatter after the RC has finished Otherwise, clicking on links will have no effect. This feature was broken with commit 113134b3b6. Task-number: QTCREATORBUG-18134 Task-number: QTCREATORBUG-18334 Change-Id: I3cf5d8a9b3957a3f06cb3dbba40bb2dd16a9f8a9 Reviewed-by: Orgad Shaneh Reviewed-by: Tobias Hunger Reviewed-by: Eike Ziller --- src/plugins/projectexplorer/appoutputpane.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp index b43f3f3804b..b7189bbb1ca 100644 --- a/src/plugins/projectexplorer/appoutputpane.cpp +++ b/src/plugins/projectexplorer/appoutputpane.cpp @@ -743,8 +743,6 @@ void AppOutputPane::slotRunControlFinished2(RunControl *sender) if (current && current == sender) enableButtons(current, false); // RunControl::isRunning() cannot be trusted in signal handler. - m_runControlTabs.at(senderIndex).window->setFormatter(nullptr); // Reset formater for this RC - // Check for asynchronous close. Close the tab. if (m_runControlTabs.at(senderIndex).asyncClosing) closeTab(tabWidgetIndexOf(senderIndex), CloseTabNoPrompt); From 523439d71b768874b2ac9613c151483f9961417f Mon Sep 17 00:00:00 2001 From: Claus Steuer Date: Mon, 19 Jun 2017 17:21:38 +0200 Subject: [PATCH 06/23] CMake: The first build of a cmake project always fails in tealeaf mode The TeaLeafReader tries to parse the CMakeCache.txt before cmake is executed for the first time. The error is signaled to the CMakeBuildStep which reports the build as a failure. Make TeaLeafReader::takeParsedConfiguration return an empty CMakeConfig object if the CMakeCache.txt file does not exist instead, but do not report an error. Task-number: QTCREATORBUG-18290 Change-Id: Ibfc43858938477ae7479029e8fe6786c77823014 Reviewed-by: Tim Jenssen --- src/plugins/cmakeprojectmanager/tealeafreader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.cpp b/src/plugins/cmakeprojectmanager/tealeafreader.cpp index 8c37220f262..c05b0bf9c11 100644 --- a/src/plugins/cmakeprojectmanager/tealeafreader.cpp +++ b/src/plugins/cmakeprojectmanager/tealeafreader.cpp @@ -243,6 +243,10 @@ CMakeConfig TeaLeafReader::takeParsedConfiguration() { FileName cacheFile = m_parameters.buildDirectory; cacheFile.appendPath(QLatin1String("CMakeCache.txt")); + + if (!cacheFile.exists()) + return { }; + QString errorMessage; CMakeConfig result = BuildDirManager::parseConfiguration(cacheFile, &errorMessage); From 8542ebcd5dd312aa3038d0b70c861dc05c71333a Mon Sep 17 00:00:00 2001 From: Claus Steuer Date: Mon, 19 Jun 2017 17:29:35 +0200 Subject: [PATCH 07/23] CMake: Do not react to builds in the background If an error occurs while persisting or updating the cmake state, the build might continue for a while in the background. CMakeBuildStep does not disconnect the Error/Run-Trigger when an error is signaled by the CMakeBuildConfiguration. Instead it reports the build as finished (with error). The BuildManager then disconnects the output and runs the next item in the build queue (if any). However the cmake step might still be alive and emits the dataAvailable signal which then triggers the build process. Task-number: QTCREATORBUG-18382 Change-Id: I956133fe8c6f7de58b9f842b231c70d24778b1e0 Reviewed-by: Tim Jenssen --- .../cmakeprojectmanager/cmakebuildstep.cpp | 17 ++++++++++++++--- .../cmakeprojectmanager/cmakebuildstep.h | 2 ++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index d87a538f98b..4bc51dd42ec 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -267,7 +267,7 @@ void CMakeBuildStep::run(QFutureInterface &fi) m_runTrigger = connect(bc, &CMakeBuildConfiguration::dataAvailable, this, [this, &fi]() { runImpl(fi); }); m_errorTrigger = connect(bc, &CMakeBuildConfiguration::errorOccured, - this, [this, &fi]() { reportRunResult(fi, false); }); + this, [this, &fi](const QString& em) { handleCMakeError(fi, em); }); } else { runImpl(fi); } @@ -276,10 +276,21 @@ void CMakeBuildStep::run(QFutureInterface &fi) void CMakeBuildStep::runImpl(QFutureInterface &fi) { // Do the actual build: + disconnectTriggers(); + AbstractProcessStep::run(fi); +} + +void CMakeBuildStep::handleCMakeError(QFutureInterface &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_errorTrigger); - - AbstractProcessStep::run(fi); } BuildStepConfigWidget *CMakeBuildStep::createConfigWidget() diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.h b/src/plugins/cmakeprojectmanager/cmakebuildstep.h index 70d89c87830..08cee9a01cb 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.h @@ -104,6 +104,8 @@ private: void ctor(ProjectExplorer::BuildStepList *bsl); void runImpl(QFutureInterface &fi); + void handleCMakeError(QFutureInterface &fi, const QString& errorMessage); + void disconnectTriggers(); void handleBuildTargetChanges(); CMakeRunConfiguration *targetsActiveRunConfiguration() const; From a027f1cfcede0c404991416f831c57dd5cd9bed3 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 20 Jun 2017 11:47:36 +0200 Subject: [PATCH 08/23] CMake: Only handle strings at start of line Allow comments at the start of line only (or after only space characters) in CMakeCache.txt-style lines. Task-number: QTCREATORBUG-18385 Change-Id: I8b69144ea4f6a667ae1df382c8c4c1e88eca799b Reviewed-by: Eike Ziller Reviewed-by: Tim Jenssen --- .../cmakeprojectmanager/cmakeconfigitem.cpp | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp index 2b09a3769c7..258803d45e7 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp @@ -170,15 +170,20 @@ std::function CMakeCo CMakeConfigItem CMakeConfigItem::fromString(const QString &s) { - // Strip comments: + // Strip comments (only at start of line!): int commentStart = s.count(); - int pos = s.indexOf(QLatin1Char('#')); - if (pos >= 0) - commentStart = pos; - pos = s.indexOf(QLatin1String("//")); - if (pos >= 0 && pos < commentStart) - commentStart = pos; - + for (int i = 0; i < s.count(); ++i) { + const QChar c = s.at(i); + if (c == ' ' || c == '\t') + continue; + else if ((c == '#') + || (c == '/' && i < s.count() - 1 && s.at(i + 1) == '/')) { + commentStart = i; + break; + } else { + break; + } + } const QString line = s.mid(0, commentStart); // Split up line: From dac2a188ded0dd2c07cd354fc00331c9603793d8 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 20 Jun 2017 12:13:25 +0200 Subject: [PATCH 09/23] CMake: Make sure no empty strings end up in deployment data Task-number: QTCREATORBUG-18406 Change-Id: I0b9f8ca76cee8ad2e9ae2ee1f124f16f473033d5 Reviewed-by: Eike Ziller Reviewed-by: Tim Jenssen --- src/plugins/cmakeprojectmanager/cmakeproject.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 101649702cf..9ae83d71ad6 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -495,8 +495,13 @@ void CMakeProject::updateApplicationAndDeploymentTargets() if (ct.targetType == UtilityType) continue; - if (ct.targetType == ExecutableType || ct.targetType == DynamicLibraryType) - deploymentData.addFile(ct.executable.toString(), deploymentPrefix + buildDir.relativeFilePath(ct.executable.toFileInfo().dir().path()), DeployableFile::TypeExecutable); + if (ct.targetType == ExecutableType || ct.targetType == DynamicLibraryType) { + if (!ct.executable.isEmpty()) { + deploymentData.addFile(ct.executable.toString(), + deploymentPrefix + buildDir.relativeFilePath(ct.executable.toFileInfo().dir().path()), + DeployableFile::TypeExecutable); + } + } if (ct.targetType == ExecutableType) { FileName srcWithTrailingSlash = FileName::fromString(ct.sourceDirectory.toString()); srcWithTrailingSlash.appendString('/'); From e42f3db9f0ab1ec28bf9ba414add84d3b552118f Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 20 Jun 2017 12:21:24 +0200 Subject: [PATCH 10/23] CMake: Avoid duplicate build targets Make sure that build targets that get added explicitly are never reported by any of the readers, too. This makes sure entries will not show up twice in the UI. Task-number: QTCREATORBUG-18409 Change-Id: Id5039add262211fd87cd5c2884df2af0fcf24577 Reviewed-by: Tim Jenssen --- src/plugins/cmakeprojectmanager/builddirmanager.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index ca2fd4bd6a9..d474c95cabb 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -336,7 +336,12 @@ QList BuildDirManager::buildTargets() const m_buildTargets.append(utilityTarget(CMakeBuildStep::installTarget(), 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; } From bc22de5f0ae7795561673bf91e9bd5f532e7f4b0 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Mon, 19 Jun 2017 16:07:25 +0200 Subject: [PATCH 11/23] ProjectExplorer: Do not use version manager cache in threads Do not use VcsManager's cache of version control systems from different threads. Iterate over all IVersionControls instead of getting the specific version control for a directory. This is less exact, but will probably not hurt users. Task-number: QTCREATORBUG-18258 Change-Id: Iae2be5735a0d7ecc8d774904f6681963fca1d114 Reviewed-by: Eike Ziller --- .../cmakeprojectmanager/treescanner.cpp | 20 +++++++++----- src/plugins/cmakeprojectmanager/treescanner.h | 6 ++++- src/plugins/coreplugin/iversioncontrol.h | 2 ++ src/plugins/nim/project/nimproject.cpp | 9 +++++-- src/plugins/projectexplorer/projectnodes.cpp | 27 +++++++++++++------ src/plugins/projectexplorer/projectnodes.h | 8 ++++++ 6 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/treescanner.cpp b/src/plugins/cmakeprojectmanager/treescanner.cpp index 6951221dd89..83fae4070eb 100644 --- a/src/plugins/cmakeprojectmanager/treescanner.cpp +++ b/src/plugins/cmakeprojectmanager/treescanner.cpp @@ -25,6 +25,8 @@ #include "treescanner.h" +#include +#include #include #include @@ -67,7 +69,10 @@ bool TreeScanner::asyncScanForFiles(const Utils::FileName &directory) m_scanFuture = fi->future(); 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; } @@ -144,13 +149,17 @@ FileType TreeScanner::genericFileType(const Utils::MimeType &mimeType, const Uti 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 &versionControls) { std::unique_ptr fip(fi); fip->reportStarted(); - Result nodes = FileNode::scanForFiles(directory, - [&filter, &factory](const Utils::FileName &fn) -> FileNode * { + Result nodes + = FileNode::scanForFilesWithVersionControls( + directory, + [&filter, &factory](const Utils::FileName &fn) -> FileNode * { QTC_ASSERT(!fn.isEmpty(), return nullptr); const Utils::MimeType mimeType = Utils::mimeTypeForFile(fn.toString()); @@ -166,8 +175,7 @@ void TreeScanner::scanForFiles(FutureInterface *fi, const Utils::FileName& direc type = factory(mimeType, fn); return new FileNode(fn, type, false); - }, - fip.get()); + }, versionControls, fip.get()); // Clean up nodes and keep it sorted Result tmp = Utils::filtered(nodes, [](const FileNode *fn) -> bool { diff --git a/src/plugins/cmakeprojectmanager/treescanner.h b/src/plugins/cmakeprojectmanager/treescanner.h index 33b4522a204..146076f1f2a 100644 --- a/src/plugins/cmakeprojectmanager/treescanner.h +++ b/src/plugins/cmakeprojectmanager/treescanner.h @@ -36,6 +36,8 @@ #include +namespace Core { class IVersionControl; } + namespace CMakeProjectManager { namespace Internal { @@ -86,7 +88,8 @@ signals: private: static void scanForFiles(FutureInterface *fi, const Utils::FileName &directory, - const FileFilter &filter, const FileTypeFactory &factory); + const FileFilter &filter, const FileTypeFactory &factory, + QList &versionControls); private: FileFilter m_filter; @@ -94,6 +97,7 @@ private: FutureWatcher m_futureWatcher; Future m_scanFuture; + QList m_versionControls; }; } // namespace Internal diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h index eb880e7c70f..eddcee4ff37 100644 --- a/src/plugins/coreplugin/iversioncontrol.h +++ b/src/plugins/coreplugin/iversioncontrol.h @@ -100,6 +100,8 @@ public: * * 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). + * + * This method needs to be thread safe! */ virtual bool isVcsFileOrDirectory(const Utils::FileName &fileName) const = 0; diff --git a/src/plugins/nim/project/nimproject.cpp b/src/plugins/nim/project/nimproject.cpp index 5db9fd554a3..8910bd42af6 100644 --- a/src/plugins/nim/project/nimproject.cpp +++ b/src/plugins/nim/project/nimproject.cpp @@ -31,6 +31,8 @@ #include "../nimconstants.h" #include +#include +#include #include #include #include @@ -113,8 +115,11 @@ void NimProject::collectProjectFiles() m_lastProjectScan.start(); QTC_ASSERT(!m_futureWatcher.future().isRunning(), return); FileName prjDir = projectDirectory(); - QFuture> future = Utils::runAsync([prjDir] { - return FileNode::scanForFiles(prjDir, [](const FileName &fn) { return new FileNode(fn, FileType::Source, false); }); + const QList versionControls = Core::VcsManager::versionControls(); + QFuture> future = Utils::runAsync([prjDir, versionControls] { + return FileNode::scanForFilesWithVersionControls( + prjDir, [](const FileName &fn) { return new FileNode(fn, FileType::Source, false); }, + versionControls); }); m_futureWatcher.setFuture(future); Core::ProgressManager::addTask(future, tr("Scanning for Nim files"), "Nim.Project.Scan"); diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index aa619aa4263..741dc394e71 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -339,7 +339,8 @@ FileType FileNode::fileType() const static QList scanForFilesRecursively(const Utils::FileName &directory, const std::function factory, QSet &visited, QFutureInterface> *future, - double progressStart, double progressRange) + double progressStart, double progressRange, + const QList &versionControls) { QList result; @@ -351,8 +352,6 @@ static QList scanForFilesRecursively(const Utils::FileName &director if (visitedCount == visited.count()) return result; - const Core::IVersionControl *vcsControl - = Core::VcsManager::findVersionControlForDirectory(baseDir.absolutePath(), nullptr); const QList entries = baseDir.entryInfoList(QStringList(), QDir::AllEntries|QDir::NoDotAndDotDot); double progress = 0; const double progressIncrement = progressRange / static_cast(entries.count()); @@ -362,9 +361,11 @@ static QList scanForFilesRecursively(const Utils::FileName &director return result; 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()) - 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)) result.append(node); } @@ -382,14 +383,24 @@ static QList scanForFilesRecursively(const Utils::FileName &director return result; } + QList FileNode::scanForFiles(const Utils::FileName &directory, - const std::function factory, - QFutureInterface> *future) + const std::function factory, + QFutureInterface > *future) +{ + return FileNode::scanForFilesWithVersionControls(directory, factory, QList(), future); +} + +QList +FileNode::scanForFilesWithVersionControls(const Utils::FileName &directory, + const std::function factory, + const QList &versionControls, + QFutureInterface> *future) { QSet visited; if (future) 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 diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index 7c440b73559..746f7437b44 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -37,6 +37,7 @@ #include namespace Utils { class MimeType; } +namespace Core { class IVersionControl; } namespace ProjectExplorer { @@ -188,9 +189,16 @@ public: FileNode *asFileNode() final { return this; } const FileNode *asFileNode() const final { return this; } + // For ABI compatibility, remove in QtC 4.4: static QList scanForFiles(const Utils::FileName &directory, const std::function factory, QFutureInterface> *future = nullptr); + + static QList + scanForFilesWithVersionControls(const Utils::FileName &directory, + const std::function factory, + const QList &versionControls, + QFutureInterface> *future = nullptr); bool supportsAction(ProjectAction action, Node *node) const override; private: From 228dec629f89c170992dad5d9092a76cff2b4ebf Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 20 Jun 2017 17:08:29 +0200 Subject: [PATCH 12/23] CMake: Remove spurios newlines Change-Id: I6f381d4df8b9174f74d1b44364e0fbea58c1e6b6 Reviewed-by: Cristian Adam Reviewed-by: Tim Jenssen --- src/plugins/cmakeprojectmanager/servermodereader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/servermodereader.cpp b/src/plugins/cmakeprojectmanager/servermodereader.cpp index e17843c02d9..0a3ef883805 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.cpp +++ b/src/plugins/cmakeprojectmanager/servermodereader.cpp @@ -113,7 +113,7 @@ void ServerModeReader::setParameters(const BuildDirReader::Parameters &p) const QStringList lines = m.split('\n'); for (const QString &l : lines) { m_parser.stdError(l); - Core::MessageManager::write(l + "\n"); + Core::MessageManager::write(l); } }); connect(m_cmakeServer.get(), &ServerMode::message, From bee61b0fec2bf945794e2243c05b3857ae6138a5 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 20 Jun 2017 17:19:21 +0200 Subject: [PATCH 13/23] CMake: Improve parsing of "CMake Error at" messages Handle more "CMake error at" messages. This includes the generic "Parsing failed" message from cmake. Change-Id: Ie036c606bd7a8ad9cafbc32a34a77f8b95c3defa Reviewed-by: Tim Jenssen --- src/plugins/cmakeprojectmanager/cmakeparser.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeparser.cpp b/src/plugins/cmakeprojectmanager/cmakeparser.cpp index d31ee71daf2..a06a68f6840 100644 --- a/src/plugins/cmakeprojectmanager/cmakeparser.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeparser.cpp @@ -32,7 +32,7 @@ using namespace CMakeProjectManager; 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 LOCATION_LINE_PATTERN[] = ":(\\d+):(?:(\\d+))?$"; @@ -250,6 +250,20 @@ void Internal::CMakeProjectPlugin::testCMakeParser_data() Utils::FileName(), -1, categoryBuild)) << 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() + << Task(Task::Error, + QLatin1String("Parse error. Expected \"(\", got newline with text \" \"."), + Utils::FileName::fromUserInput(QLatin1String("CMakeLists.txt")), 4, + categoryBuild)) + << QString(); + QTest::newRow("cmake warning") << QString::fromLatin1("Syntax Warning in cmake code at\n" "/test/path/CMakeLists.txt:9:15\n" From 1e68d91cb106d553a188a5b083b30c6d6ded8fea Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Tue, 20 Jun 2017 11:01:13 +0200 Subject: [PATCH 14/23] Clang: fix intrinsic errors with boost Add extra define not to include intrinsic headers from boost headers. Task-number: QTCREATORBUG-16439 Change-Id: I887fe63e2560afebdbe9f3d3587f99f95d408997 Reviewed-by: Marco Bubke Reviewed-by: Orgad Shaneh Reviewed-by: Nikolai Kosjar --- src/plugins/cpptools/compileroptionsbuilder.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index e55832ab86d..6e98537c955 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -300,6 +300,7 @@ void CompilerOptionsBuilder::addDefineToAvoidIncludingGccOrMinGwIntrinsics() if (type == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID || type == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID) { addDefine("#define _X86INTRIN_H_INCLUDED"); + addDefine("#define BOOST_UUID_NO_SIMD"); } } From bd259129b5b50d2a816d2d99a1b45bedb57e7563 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 21 Jun 2017 07:34:46 +0200 Subject: [PATCH 15/23] Tests: Fix compile Broke with 4e96f2ce. Change-Id: I7c467cc92cc8444bd3b1ef41eebff089668a0f31 Reviewed-by: Tobias Hunger --- tests/auto/qtcprocess/tst_qtcprocess.cpp | 8 +++++++- tests/auto/utils/stringutils/tst_stringutils.cpp | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/auto/qtcprocess/tst_qtcprocess.cpp b/tests/auto/qtcprocess/tst_qtcprocess.cpp index e789203fbcc..b4df6694419 100644 --- a/tests/auto/qtcprocess/tst_qtcprocess.cpp +++ b/tests/auto/qtcprocess/tst_qtcprocess.cpp @@ -34,8 +34,14 @@ using namespace Utils; class MacroMapExpander : public AbstractMacroExpander { public: - virtual bool resolveMacro(const QString &name, QString *ret) + virtual bool resolveMacro(const QString &name, QString *ret, QSet &seen) { + // loop prevention + const int count = seen.count(); + seen.insert(this); + if (seen.count() == count) + return false; + QHash::const_iterator it = m_map.constFind(name); if (it != m_map.constEnd()) { *ret = it.value(); diff --git a/tests/auto/utils/stringutils/tst_stringutils.cpp b/tests/auto/utils/stringutils/tst_stringutils.cpp index ae137b13e12..d9d47e18451 100644 --- a/tests/auto/utils/stringutils/tst_stringutils.cpp +++ b/tests/auto/utils/stringutils/tst_stringutils.cpp @@ -32,8 +32,14 @@ class TestMacroExpander : public Utils::AbstractMacroExpander { public: - virtual bool resolveMacro(const QString &name, QString *ret) + virtual bool resolveMacro(const QString &name, QString *ret, QSet &seen) { + // loop prevention + const int count = seen.count(); + seen.insert(this); + if (seen.count() == count) + return false; + if (name == QLatin1String("foo")) { *ret = QLatin1String("a"); return true; From 8ede32677e2dd86e3a7f474d33c1656fe3ea0f9b Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 20 Jun 2017 17:43:44 +0200 Subject: [PATCH 16/23] CMake: Fix logic for target filtering Broken by e42f3db9f0ab1ec28bf9ba414add84d3b552118f from today:-/ Sorry. Change-Id: I4803039939de5aae893a701e2bd6399d3fbfae1f Reviewed-by: Florian Apolloner Reviewed-by: Tim Jenssen --- src/plugins/cmakeprojectmanager/builddirmanager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index d474c95cabb..a6281fd7151 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -337,10 +337,10 @@ QList BuildDirManager::buildTargets() const m_buildTargets.append(utilityTarget(CMakeBuildStep::testTarget(), this)); 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 bt.title != CMakeBuildStep::allTarget() + && bt.title != CMakeBuildStep::cleanTarget() + && bt.title != CMakeBuildStep::installTarget() + && bt.title != CMakeBuildStep::testTarget(); })); } return m_buildTargets; From 4ecb1283fe4ee463e9b550d4575eb33ad9944a17 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 22 Jun 2017 11:21:58 +0200 Subject: [PATCH 17/23] Debugger: Do not crash in (im)possible situations Task-number: QTCREATORBUG-18427 Change-Id: I800c2f8d4ea37b28022d789a2e519e4f5286f08a Reviewed-by: Nikolai Kosjar --- src/plugins/debugger/debuggerplugin.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 16825ffa0c7..4581f5ad5a3 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -2311,26 +2311,32 @@ void DebuggerPluginPrivate::requestContextMenu(TextEditorWidget *widget, } // 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(); - if (currentEngine()->hasCapability(RunToLineCapability)) { + if (engine->hasCapability(RunToLineCapability)) { auto act = menu->addAction(args.address ? DebuggerEngine::tr("Run to Address 0x%1").arg(args.address, 0, 16) : DebuggerEngine::tr("Run to Line %1").arg(args.lineNumber)); 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 ? DebuggerEngine::tr("Jump to Address 0x%1").arg(args.address, 0, 16) : DebuggerEngine::tr("Jump to Line %1").arg(args.lineNumber)); 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. - if (currentEngine()->hasCapability(DisassemblerCapability)) { + if (engine->hasCapability(DisassemblerCapability)) { StackFrame frame; frame.function = cppFunctionAt(args.fileName, lineNumber, 1); frame.line = 42; // trick gdb into mixed mode. @@ -2339,7 +2345,9 @@ void DebuggerPluginPrivate::requestContextMenu(TextEditorWidget *widget, .arg(frame.function); auto act = new QAction(text, menu); connect(act, &QAction::triggered, [this, frame] { - currentEngine()->openDisassemblerView(Location(frame)); + DebuggerEngine *engine = currentEngine(); + QTC_ASSERT(engine, return); + engine->openDisassemblerView(Location(frame)); }); menu->addAction(act); } From b1e23b7121f17b4f981252bca49925b3476bbe91 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 20 Jun 2017 12:20:42 +0200 Subject: [PATCH 18/23] Revert "Make the output window readonly, but still keyboard friendly" This reverts commit 3080d0d9e71ecfe89ee3af4982741beb01ce971e. Having the output pane editable is considered a feature by some as it allows easy modification of the contents before passing into other, less accessible interfaces, like Gerrit comment fields. Task-number: QTCREATORBUG-18418 Change-Id: Ice0c6c5e5787d242c714a7b0f61559a70d25d243 Reviewed-by: J-P Nurmi Reviewed-by: Mitch Curtis Reviewed-by: Christian Kandeler Reviewed-by: Eike Ziller Reviewed-by: Vikas Pachdha --- src/libs/utils/outputformatter.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/utils/outputformatter.cpp b/src/libs/utils/outputformatter.cpp index 64ae5033425..aae6a28d168 100644 --- a/src/libs/utils/outputformatter.cpp +++ b/src/libs/utils/outputformatter.cpp @@ -68,8 +68,6 @@ QPlainTextEdit *OutputFormatter::plainTextEdit() const void OutputFormatter::setPlainTextEdit(QPlainTextEdit *plainText) { - plainText->setReadOnly(true); - plainText->setTextInteractionFlags(plainText->textInteractionFlags() | Qt::TextSelectableByKeyboard); d->plainTextEdit = plainText; d->cursor = plainText ? plainText->textCursor() : QTextCursor(); initFormats(); From 2e128db77fade5ae6efa851e72551b5a5f82d64a Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 22 Jun 2017 13:50:41 +0200 Subject: [PATCH 19/23] QmlDesigner: Use ";" as delimiter for QMLDESIGNER_RC_PATHS This is what is used in the qml2puppet. Change-Id: I5c9ce65863539395d0f2c56e7be89998fd26f341 Reviewed-by: Tim Jenssen --- .../designercore/instances/nodeinstanceserverproxy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp index 9f4d24c03f8..e8fbe3a71cf 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp @@ -344,7 +344,7 @@ QString NodeInstanceServerProxy::qrcMappingString() const foreach (const StringPair &pair, rewriterView->qrcMapping()) { if (!mappingString.isEmpty()) - mappingString.append(QLatin1String(",")); + mappingString.append(QLatin1String(";")); mappingString.append(pair.first); mappingString.append(QLatin1String("=")); mappingString.append(pair.second); From 3944c73c512bf601d4b48552f313765cb3c722c8 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 16 Jun 2017 13:26:32 +0200 Subject: [PATCH 20/23] QmlDesigner: Fix combobox for font family The editable combobox had some serious issues. I changed the signals we react to and the properties we use. We react on activated to change to fonts in the model. For some reason using currentText does not work reliable. We have to retrieve the current etxt manually using textAt(). We also react to accepted to changes in the text edit. Here we simply use editText. We also react to selection changes and change the font. Change-Id: I99abd7609f8b64ef446ce154aed0c2a61dfa00f9 Reviewed-by: Tim Jenssen --- .../HelperWidgets/FontComboBox.qml | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/HelperWidgets/FontComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/HelperWidgets/FontComboBox.qml index ffc774d7cd0..6cca085da75 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/HelperWidgets/FontComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/HelperWidgets/FontComboBox.qml @@ -58,12 +58,28 @@ Controls.ComboBox { Layout.fillWidth: true - onCurrentTextChanged: { + onAccepted: { if (backendValue === undefined) return; - if (backendValue.value !== currentText) - backendValue.value = currentText; + if (editText === "") + 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 { @@ -73,6 +89,13 @@ Controls.ComboBox { visible: comboBox.enabled } + Connections { + target: modelNodeBackend + onSelectionChanged: { + comboBox.editText = backendValue.value + } + } + Component.onCompleted: { //Hack to style the text input for (var i = 0; i < comboBox.children.length; i++) { From 7062fd5138054a7eace18322ac5ae9f086cd1dc3 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 22 Jun 2017 17:10:49 +0200 Subject: [PATCH 21/23] QmlDesigner: Avoid accidentally changing gradients The designer was changing gradient stops if the item "selected" in the edit mode has a gradient. The first gradient stop was set to white. There is still an issue with setting up the gradient editor in this case, but the file is not changed anymore. Task-number: QTCREATORBUG-18421 Change-Id: Ifd6829590a8a7b5217c53f49054f8738bdb71563 Reviewed-by: Tim Jenssen --- .../propertyeditor/gradientmodel.cpp | 36 +++++++++++++------ .../components/propertyeditor/gradientmodel.h | 3 +- .../propertyeditor/propertyeditorview.cpp | 16 ++++++--- .../propertyeditor/propertyeditorview.h | 2 ++ 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp index dbb100d8a18..c1aff9dabd7 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp @@ -26,6 +26,7 @@ #include "gradientmodel.h" #include "qmlanchorbindingproxy.h" +#include "propertyeditorview.h" #include #include @@ -35,7 +36,7 @@ #include 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) { - if (m_lock) + if (m_locked) return -1; if (!m_itemNode.isValid() || gradientPropertyName().isEmpty()) @@ -131,7 +132,7 @@ int GradientModel::addStop(qreal position, const QColor &color) void GradientModel::addGradient() { - if (m_lock) + if (m_locked) return; if (!m_itemNode.isValid() || gradientPropertyName().isEmpty()) @@ -174,7 +175,7 @@ void GradientModel::addGradient() void GradientModel::setColor(int index, const QColor &color) { - if (m_lock) + if (locked()) return; if (!m_itemNode.modelNode().isSelected()) @@ -191,7 +192,7 @@ void GradientModel::setColor(int index, const QColor &color) void GradientModel::setPosition(int index, qreal positition) { - if (m_lock) + if (locked()) return; if (index < rowCount()) { @@ -266,12 +267,12 @@ void GradientModel::deleteGradient() void GradientModel::lock() { - m_lock = true; + m_locked = true; } void GradientModel::unlock() { - m_lock = false; + m_locked = false; } void GradientModel::registerDeclarativeType() @@ -281,11 +282,11 @@ void GradientModel::registerDeclarativeType() void GradientModel::setupModel() { - m_lock = true; + m_locked = true; beginResetModel(); endResetModel(); - m_lock = false; + m_locked = false; } void GradientModel::setAnchorBackend(const QVariant &anchorBackend) @@ -300,12 +301,12 @@ void GradientModel::setAnchorBackend(const QVariant &anchorBackend) setupModel(); - m_lock = true; + m_locked = true; emit anchorBackendChanged(); emit hasGradientChanged(); - m_lock = false; + m_locked = false; } QString GradientModel::gradientPropertyName() const @@ -323,3 +324,16 @@ bool GradientModel::hasGradient() const return m_itemNode.isValid() && m_itemNode.modelNode().hasProperty(gradientPropertyName().toUtf8()); } + +bool GradientModel::locked() const +{ + if (m_locked) + return true; + + QmlDesigner::PropertyEditorView *view = qobject_cast(m_itemNode.view()); + + if (view && view->locked()) + return true; + + return false; +} diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.h b/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.h index 39f1b576984..943d6ae22b3 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.h +++ b/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.h @@ -76,11 +76,12 @@ private: QString gradientPropertyName() const; void setGradientPropertyName(const QString &name); bool hasGradient() const; + bool locked() const; private: QmlDesigner::QmlItemNode m_itemNode; QString m_gradientPropertyName; - bool m_lock; + bool m_locked; }; diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index b28fec7c518..fcdb04d2a25 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -135,7 +135,7 @@ void PropertyEditorView::changeValue(const QString &name) if (propertyName.isNull()) return; - if (m_locked) + if (locked()) return; if (propertyName == "className") @@ -231,7 +231,7 @@ void PropertyEditorView::changeExpression(const QString &propertyName) if (name.isNull()) return; - if (m_locked) + if (locked()) return; if (!m_selectedNode.isValid()) @@ -306,7 +306,7 @@ void PropertyEditorView::exportPopertyAsAlias(const QString &name) if (name.isNull()) return; - if (m_locked) + if (locked()) return; if (!m_selectedNode.isValid()) @@ -340,7 +340,7 @@ void PropertyEditorView::removeAliasExport(const QString &name) if (name.isNull()) return; - if (m_locked) + if (locked()) return; if (!m_selectedNode.isValid()) @@ -362,6 +362,11 @@ void PropertyEditorView::removeAliasExport(const QString &name) } } +bool PropertyEditorView::locked() const +{ + return m_locked; +} + void PropertyEditorView::updateSize() { if (!m_qmlBackEndForCurrentType) @@ -527,7 +532,6 @@ void PropertyEditorView::modelAttached(Model *model) m_locked = true; - resetView(); if (!m_setupCompleted) { m_singleShotTimer->setSingleShot(true); m_singleShotTimer->setInterval(100); @@ -536,6 +540,8 @@ void PropertyEditorView::modelAttached(Model *model) } m_locked = false; + + resetView(); } void PropertyEditorView::modelAboutToBeDetached(Model *model) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h index 07073976234..b9028aad3db 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h @@ -92,6 +92,8 @@ public: void exportPopertyAsAlias(const QString &name); void removeAliasExport(const QString &name); + bool locked() const; + protected: void timerEvent(QTimerEvent *event) override; void setupPane(const TypeName &typeName); From 64c5f960e82f6efb947907041ab6e40860ea4652 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 20 Jun 2017 17:44:39 +0200 Subject: [PATCH 22/23] CMake: Return an empty project tree if parsing failed This triggers the logic in Project to show the top level project file in the project tree. Remove similar logic in CMake. Change-Id: I2bfdd3f5e3d4126910a3feb480cec5ef689954ed Reviewed-by: Tim Jenssen Reviewed-by: Florian Apolloner --- src/plugins/cmakeprojectmanager/builddirmanager.cpp | 4 ---- src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp | 4 ++++ src/plugins/cmakeprojectmanager/cmakeproject.cpp | 2 +- src/plugins/cmakeprojectmanager/servermodereader.cpp | 3 +++ src/plugins/cmakeprojectmanager/tealeafreader.cpp | 3 +++ 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index a6281fd7151..71fccc5df8c 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -277,10 +277,6 @@ void BuildDirManager::generateProjectTree(CMakeProjectNode *root, const QListtarget()->project()->projectFilePath(); 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) diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 8bba67e359c..b4113c53fdc 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -221,6 +221,10 @@ CMakeBuildConfiguration::generateProjectTree(const QList &allFi auto root = new CMakeProjectNode(target()->project()->projectDirectory()); m_buildDirManager->generateProjectTree(root, allFiles); + if (root->isEmpty()) { + delete root; + return nullptr; + } return root; } diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 9ae83d71ad6..91aa189e64c 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -147,8 +147,8 @@ void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc) auto newRoot = bc->generateProjectTree(m_allFiles); if (newRoot) { - setRootProjectNode(newRoot); setDisplayName(newRoot->displayName()); + setRootProjectNode(newRoot); } updateApplicationAndDeploymentTargets(); diff --git a/src/plugins/cmakeprojectmanager/servermodereader.cpp b/src/plugins/cmakeprojectmanager/servermodereader.cpp index 0a3ef883805..e366d4f6ecc 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.cpp +++ b/src/plugins/cmakeprojectmanager/servermodereader.cpp @@ -741,6 +741,9 @@ void ServerModeReader::addFileGroups(ProjectNode *targetRoot, void ServerModeReader::addHeaderNodes(ProjectNode *root, const QList knownHeaders, const QList &allFiles) { + if (root->isEmpty()) + return; + auto headerNode = new VirtualFolderNode(root->filePath(), Node::DefaultPriority - 5); headerNode->setDisplayName(tr("")); diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.cpp b/src/plugins/cmakeprojectmanager/tealeafreader.cpp index c05b0bf9c11..e7ecd026dd4 100644 --- a/src/plugins/cmakeprojectmanager/tealeafreader.cpp +++ b/src/plugins/cmakeprojectmanager/tealeafreader.cpp @@ -270,6 +270,9 @@ CMakeConfig TeaLeafReader::takeParsedConfiguration() void TeaLeafReader::generateProjectTree(CMakeProjectNode *root, const QList &allFiles) { + if (m_files.isEmpty()) + return; + root->setDisplayName(m_projectName); // Delete no longer necessary file watcher based on m_cmakeFiles: From 29cf39bfd6424364eeefd07e65cc0c613848ced2 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Fri, 23 Jun 2017 15:19:00 +0200 Subject: [PATCH 23/23] ProjectExplorer: Fix crash in AppOutputPane The RunControl owns the Formatter set on the OutputWindow. Make sure the OutputWindow is deleted before the RunControl and avoid some useless setting of the Formatter. Task-number: QTCREATORBUG-18428 Change-Id: I40c8f032bb04c484957a35a6bbc0fda7b6491c51 Reviewed-by: Eike Ziller --- src/plugins/projectexplorer/appoutputpane.cpp | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp index b7189bbb1ca..a9a46974bbc 100644 --- a/src/plugins/projectexplorer/appoutputpane.cpp +++ b/src/plugins/projectexplorer/appoutputpane.cpp @@ -149,7 +149,10 @@ void TabWidget::slotContextMenuRequested(const QPoint &pos) AppOutputPane::RunControlTab::RunControlTab(RunControl *rc, Core::OutputWindow *w) : runControl(rc), window(w) -{ } +{ + if (rc && w) + w->setFormatter(rc->outputFormatter()); +} AppOutputPane::AppOutputPane() : m_mainWidget(new QWidget), @@ -262,7 +265,7 @@ AppOutputPane::~AppOutputPane() qDebug() << "OutputPane::~OutputPane: Entries left" << m_runControlTabs.size(); foreach (const RunControlTab &rt, m_runControlTabs) { - rt.window->setFormatter(nullptr); + delete rt.window; delete rt.runControl; } delete m_mainWidget; @@ -416,13 +419,14 @@ void AppOutputPane::createNewOutputWindow(RunControl *rc) RunControlTab &tab = m_runControlTabs[tabIndex]; // Reuse this tab delete tab.runControl; - handleOldOutput(tab.window); tab.runControl = rc; + tab.window->setFormatter(rc ? rc->outputFormatter() : nullptr); + + handleOldOutput(tab.window); // Update the title. m_tabWidget->setTabText(tabIndex, rc->displayName()); - tab.window->setFormatter(nullptr); tab.window->scrollToBottom(); if (debug) 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); ow->setWindowTitle(tr("Application Output Window")); ow->setWindowIcon(Icons::WINDOW.icon()); - ow->setFormatter(nullptr); ow->setWordWrapEnabled(ProjectExplorerPlugin::projectExplorerSettings().wrapAppOutput); ow->setMaxLineCount(ProjectExplorerPlugin::projectExplorerSettings().maxAppOutputLines); ow->setWheelZoomEnabled(TextEditor::TextEditorSettings::behaviorSettings().m_scrollWheelZooming); @@ -592,9 +595,8 @@ bool AppOutputPane::closeTab(int tabIndex, CloseTabMode closeTabMode) } m_tabWidget->removeTab(tabIndex); - m_runControlTabs[index].window->setFormatter(nullptr); - delete m_runControlTabs[index].runControl; delete m_runControlTabs[index].window; + delete m_runControlTabs[index].runControl; m_runControlTabs.removeAt(index); updateCloseActions(); @@ -708,10 +710,6 @@ void AppOutputPane::contextMenuRequested(const QPoint &pos, int index) void AppOutputPane::slotRunControlStarted() { 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()) enableButtons(current, true); // RunControl::isRunning() cannot be trusted in signal handler. emit runControlStarted(current);