From b5942847e2ec7f850dea35189197e0ea54c6bc0e Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 18 Oct 2019 12:04:43 +0200 Subject: [PATCH 01/45] McuSupport: Set ARM debugger in MCU kits ... create one if necessary. Change-Id: I0b89d54429834db7b76be0a76d260152efd1ad03 Reviewed-by: hjk --- src/plugins/mcusupport/CMakeLists.txt | 2 +- src/plugins/mcusupport/mcusupport.qbs | 2 +- .../mcusupport/mcusupport_dependencies.pri | 1 + .../mcusupport/mcusupportoptionspage.cpp | 29 +++++++++++++++++-- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/plugins/mcusupport/CMakeLists.txt b/src/plugins/mcusupport/CMakeLists.txt index deed8605aec..91fa58b6209 100644 --- a/src/plugins/mcusupport/CMakeLists.txt +++ b/src/plugins/mcusupport/CMakeLists.txt @@ -1,6 +1,6 @@ add_qtc_plugin(McuSupport DEPENDS Qt5::Core - PLUGIN_DEPENDS Core ProjectExplorer CMakeProjectManager + PLUGIN_DEPENDS Core ProjectExplorer Debugger CMakeProjectManager SOURCES mcusupport.qrc mcusupport_global.h diff --git a/src/plugins/mcusupport/mcusupport.qbs b/src/plugins/mcusupport/mcusupport.qbs index cb8ef1afcee..732ecf81e4f 100644 --- a/src/plugins/mcusupport/mcusupport.qbs +++ b/src/plugins/mcusupport/mcusupport.qbs @@ -9,8 +9,8 @@ QtcPlugin { Depends { name: "Core" } Depends { name: "ProjectExplorer" } + Depends { name: "Debugger" } Depends { name: "CMakeProjectManager" } - Depends { name: "QtSupport" } files: [ "mcusupport.qrc", diff --git a/src/plugins/mcusupport/mcusupport_dependencies.pri b/src/plugins/mcusupport/mcusupport_dependencies.pri index b6fd4f9e6b6..1f2dd5bc644 100644 --- a/src/plugins/mcusupport/mcusupport_dependencies.pri +++ b/src/plugins/mcusupport/mcusupport_dependencies.pri @@ -7,4 +7,5 @@ QTC_LIB_DEPENDS += \ QTC_PLUGIN_DEPENDS += \ coreplugin \ projectexplorer \ + debugger \ cmakeprojectmanager diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index da1bf9f0d93..f83e015b8e4 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -28,6 +28,9 @@ #include #include +#include +#include +#include #include #include #include @@ -623,6 +626,27 @@ static void setKitToolchains(ProjectExplorer::Kit *k, const QString &armGccPath) ToolChainKitAspect::setToolChain(k, cxxTc); } +static void setKitDebugger(ProjectExplorer::Kit *k, const QString &armGccPath) +{ + using namespace Debugger; + + const Utils::FilePath command = Utils::FilePath::fromUserInput( + Utils::HostOsInfo::withExecutableSuffix(armGccPath + "/bin/arm-none-eabi-gdb-py")); + const DebuggerItem *debugger = DebuggerItemManager::findByCommand(command); + QVariant debuggerId; + if (!debugger) { + DebuggerItem newDebugger; + newDebugger.setCommand(command); + newDebugger.setUnexpandedDisplayName( + McuSupportOptionsPage::tr("Arm GDB at %1").arg(command.toUserOutput())); + debuggerId = DebuggerItemManager::registerDebugger(newDebugger); + } else { + debuggerId = debugger->id(); + } + + DebuggerKitAspect::setDebugger(k, debuggerId); +} + static void setKitDevice(ProjectExplorer::Kit *k) { using namespace ProjectExplorer; @@ -650,7 +674,7 @@ static void setKitEnvironment(ProjectExplorer::Kit *k, const BoardOptions* board EnvironmentKitAspect::setEnvironmentChanges(k, changes); } -static void setCMakeOptions(ProjectExplorer::Kit *k, const BoardOptions* board) +static void setKitCMakeOptions(ProjectExplorer::Kit *k, const BoardOptions* board) { using namespace CMakeProjectManager; @@ -674,9 +698,10 @@ static ProjectExplorer::Kit* boardKit(const BoardOptions* board, const QString & setKitProperties(k, board); setKitToolchains(k, armGccPath); + setKitDebugger(k, armGccPath); setKitDevice(k); setKitEnvironment(k, board); - setCMakeOptions(k, board); + setKitCMakeOptions(k, board); k->setup(); k->fix(); From 482c53d11aeb50116b368cbc4c374b048519cd3f Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 18 Oct 2019 13:08:21 +0200 Subject: [PATCH 02/45] Debugger: Fix display of stack When switching between interrupted and continue while debugging the stack was not updated when the engine states it is running again, but immediately did so when clicking into the stack view. Fix by explicitly updating the stack when the engine reports it is running. Change-Id: Ie8cb445e87fe6e45f9ae86b8ee2eec386be78a5c Reviewed-by: hjk --- src/plugins/debugger/debuggerengine.cpp | 1 + src/plugins/debugger/stackhandler.cpp | 5 +++++ src/plugins/debugger/stackhandler.h | 1 + 3 files changed, 7 insertions(+) diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 8fa02ef988d..a90c569c6dc 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -442,6 +442,7 @@ public: m_lookupRequests.clear(); m_locationTimer.stop(); m_locationMark.reset(); + m_stackHandler.resetLocation(); m_disassemblerAgent.resetLocation(); m_toolTipManager.resetLocation(); } diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index aeafc69fbf8..65c6f092643 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -314,6 +314,11 @@ void StackHandler::scheduleResetLocation() m_contentsValid = false; } +void StackHandler::resetLocation() +{ + emit layoutChanged(); +} + int StackHandler::stackRowCount() const { // Only one "thread" for now. diff --git a/src/plugins/debugger/stackhandler.h b/src/plugins/debugger/stackhandler.h index 22be87b16f6..10ce5a4e85e 100644 --- a/src/plugins/debugger/stackhandler.h +++ b/src/plugins/debugger/stackhandler.h @@ -112,6 +112,7 @@ public: bool isContentsValid() const { return m_contentsValid; } bool operatesByInstruction() const; void scheduleResetLocation(); + void resetLocation(); QIcon iconForRow(int row) const; From 89dbb44fcb49a36a559507ce3be21da875129077 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 18 Oct 2019 13:10:08 +0200 Subject: [PATCH 03/45] Debugger: Prohibit multi selection on debugger presets To avoid confusion regarding context menu items limit the selection mode to single selection. Change-Id: I220d97fee65180a497f21e5921f832076235acb5 Reviewed-by: hjk --- src/plugins/debugger/debuggerplugin.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 0fbb1fb7350..cdbe82a7a57 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -870,6 +870,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) engineManagerView->setSettings(ICore::settings(), "Debugger.SnapshotView"); engineManagerView->setIconSize(QSize(10, 10)); engineManagerView->setModel(m_engineManager.model()); + engineManagerView->setSelectionMode(QAbstractItemView::SingleSelection); auto engineManagerWindow = addSearch(engineManagerView); engineManagerWindow->setWindowTitle(tr("Debugger Perspectives")); From ab355bb15751141475b32dc64169b49d4a068580 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 18 Oct 2019 11:01:08 +0200 Subject: [PATCH 04/45] QbsProjectManager: Fix document filtering This was broken in 929083e7b6. Change-Id: I5341a90bf8067d93485a75827309840b5212d2b4 Reviewed-by: Christian Stenger --- src/plugins/qbsprojectmanager/qbsproject.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 0b426bbca47..37e94751ff1 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -738,9 +738,8 @@ void QbsProject::updateDocuments(const std::set &files) const FilePath buildDir = FilePath::fromString(m_projectData.buildDirectory()); const QVector nonBuildDirFilePaths = filtered(filePaths, [buildDir](const FilePath &p) { - return p.isChildOf(buildDir); + return !p.isChildOf(buildDir); }); - setExtraProjectFiles(nonBuildDirFilePaths); } From 91d785a1236aa749a9807faad62cf828e17dacd3 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 4 Oct 2019 16:01:36 +0200 Subject: [PATCH 05/45] Help: Unregister documentation when unregistering Qt versions While doing we must take care that we do not remove documentation that is used by other, still registered Qt versions (since for example desktop & mobile Qt versions share the same documentation). Fixes: QTCREATORBUG-16631 Change-Id: I77a38c89698cb3050d4a0a6963ab12d3238e2068 Reviewed-by: Jarek Kobus Reviewed-by: David Schulz --- src/plugins/coreplugin/helpmanager.cpp | 6 ++ src/plugins/coreplugin/helpmanager.h | 1 + .../coreplugin/helpmanager_implementation.h | 1 + src/plugins/help/helpmanager.cpp | 16 +++- src/plugins/help/helpmanager.h | 1 + src/plugins/qtsupport/qtversionmanager.cpp | 85 +++++++++++++------ 6 files changed, 81 insertions(+), 29 deletions(-) diff --git a/src/plugins/coreplugin/helpmanager.cpp b/src/plugins/coreplugin/helpmanager.cpp index 357adf13121..3e8e5b40037 100644 --- a/src/plugins/coreplugin/helpmanager.cpp +++ b/src/plugins/coreplugin/helpmanager.cpp @@ -80,6 +80,12 @@ void registerDocumentation(const QStringList &files) m_instance->registerDocumentation(files); } +void unregisterDocumentation(const QStringList &fileNames) +{ + if (checkInstance()) + m_instance->unregisterDocumentation(fileNames); +} + QMap linksForIdentifier(const QString &id) { return checkInstance() ? m_instance->linksForIdentifier(id) : QMap(); diff --git a/src/plugins/coreplugin/helpmanager.h b/src/plugins/coreplugin/helpmanager.h index 12a3ac7b1e7..7b7e4f052e7 100644 --- a/src/plugins/coreplugin/helpmanager.h +++ b/src/plugins/coreplugin/helpmanager.h @@ -61,6 +61,7 @@ enum HelpViewerLocation { CORE_EXPORT QString documentationPath(); CORE_EXPORT void registerDocumentation(const QStringList &fileNames); +CORE_EXPORT void unregisterDocumentation(const QStringList &fileNames); CORE_EXPORT QMap linksForIdentifier(const QString &id); CORE_EXPORT QMap linksForKeyword(const QString &id); diff --git a/src/plugins/coreplugin/helpmanager_implementation.h b/src/plugins/coreplugin/helpmanager_implementation.h index 89296691eed..9af4a499380 100644 --- a/src/plugins/coreplugin/helpmanager_implementation.h +++ b/src/plugins/coreplugin/helpmanager_implementation.h @@ -39,6 +39,7 @@ protected: public: virtual void registerDocumentation(const QStringList &fileNames) = 0; + virtual void unregisterDocumentation(const QStringList &fileNames) = 0; virtual QMap linksForIdentifier(const QString &id) = 0; virtual QMap linksForKeyword(const QString &keyword) = 0; virtual QByteArray fileData(const QUrl &url) = 0; diff --git a/src/plugins/help/helpmanager.cpp b/src/plugins/help/helpmanager.cpp index 6d41b79ff3d..3c40e187020 100644 --- a/src/plugins/help/helpmanager.cpp +++ b/src/plugins/help/helpmanager.cpp @@ -136,8 +136,20 @@ void HelpManager::registerDocumentation(const QStringList &files) emit Core::HelpManager::Signals::instance()->documentationChanged(); } }); - ProgressManager::addTask(future, tr("Update Documentation"), - kUpdateDocumentationTask); + ProgressManager::addTask(future, tr("Update Documentation"), kUpdateDocumentationTask); +} + +void HelpManager::unregisterDocumentation(const QStringList &fileNames) +{ + if (fileNames.isEmpty()) + return; + const auto getNamespaces = [](const QStringList &fileNames) { + QMutexLocker locker(&d->m_helpengineMutex); + return Utils::transform(fileNames, [](const QString &filePath) { + return d->m_helpEngine->namespaceName(filePath); + }); + }; + unregisterNamespaces(getNamespaces(fileNames)); } void HelpManager::registerDocumentationNow(QFutureInterface &futureInterface, diff --git a/src/plugins/help/helpmanager.h b/src/plugins/help/helpmanager.h index 49ca60f4684..bcde6b794cd 100644 --- a/src/plugins/help/helpmanager.h +++ b/src/plugins/help/helpmanager.h @@ -49,6 +49,7 @@ public: static QString collectionFilePath(); void registerDocumentation(const QStringList &fileNames) override; + void unregisterDocumentation(const QStringList &fileNames) override; static void unregisterNamespaces(const QStringList &nameSpaces); diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index cbf44af8eff..50f85b8760a 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -94,8 +94,9 @@ bool qtVersionNumberCompare(BaseQtVersion *a, BaseQtVersion *b) static bool restoreQtVersions(); static void findSystemQt(); static void saveQtVersions(); -static void updateDocumentation(); - +static void updateDocumentation(const QList &added, + const QList &removed = {}, + const QList &allNew = {}); // -------------------------------------------------------------------------- // QtVersionManager @@ -143,7 +144,7 @@ void QtVersionManager::triggerQtVersionRestore() FileSystemWatcher::WatchModifiedDate); } // exists - updateDocumentation(); + updateDocumentation(m_versions.values()); } bool QtVersionManager::isLoaded() @@ -465,20 +466,37 @@ void QtVersionManager::removeVersion(BaseQtVersion *version) delete version; } -static void updateDocumentation() +static QStringList documentationFiles(BaseQtVersion *v) { QStringList files; - foreach (BaseQtVersion *v, m_versions) { - const QStringList docPaths = QStringList( - {v->docsPath().toString() + QChar('/'), v->docsPath().toString() + "/qch/"}); - foreach (const QString &docPath, docPaths) { - const QDir versionHelpDir(docPath); - foreach (const QString &helpFile, - versionHelpDir.entryList(QStringList("*.qch"), QDir::Files)) - files << docPath + helpFile; - } + const QStringList docPaths = QStringList( + {v->docsPath().toString() + QChar('/'), v->docsPath().toString() + "/qch/"}); + for (const QString &docPath : docPaths) { + const QDir versionHelpDir(docPath); + for (const QString &helpFile : versionHelpDir.entryList(QStringList("*.qch"), QDir::Files)) + files.append(docPath + helpFile); } - Core::HelpManager::registerDocumentation(files); + return files; +} + +static QStringList documentationFiles(const QList &vs) +{ + QStringList files; + for (BaseQtVersion *v : vs) + files += documentationFiles(v); + return files; +} +static void updateDocumentation(const QList &added, + const QList &removed, + const QList &allNew) +{ + const QStringList docsOfAll = documentationFiles(allNew); + const QStringList docsToRemove = Utils::filtered(documentationFiles(removed), + [&docsOfAll](const QString &f) { + return !docsOfAll.contains(f); + }); + Core::HelpManager::unregisterDocumentation(docsToRemove); + Core::HelpManager::registerDocumentation(documentationFiles(added)); } int QtVersionManager::getUniqueId() @@ -530,9 +548,9 @@ void QtVersionManager::setNewQtVersions(QList newVersions) QList sortedNewVersions = newVersions; Utils::sort(sortedNewVersions, &BaseQtVersion::uniqueId); - QList addedVersions; - QList removedVersions; - QList changedVersions; + QList addedVersions; + QList removedVersions; + QList> changedVersions; // So we trying to find the minimal set of changed versions, // iterate over both sorted list @@ -548,41 +566,54 @@ void QtVersionManager::setNewQtVersions(QList newVersions) int nid = (*nit)->uniqueId(); int oid = (*oit)->uniqueId(); if (nid < oid) { - addedVersions.push_back(nid); + addedVersions.push_back(*nit); ++nit; } else if (oid < nid) { - removedVersions.push_back(oid); + removedVersions.push_back(*oit); ++oit; } else { if (!equals(*oit, *nit)) - changedVersions.push_back(oid); + changedVersions.push_back({*oit, *nit}); ++oit; ++nit; } } while (nit != nend) { - addedVersions.push_back((*nit)->uniqueId()); + addedVersions.push_back(*nit); ++nit; } while (oit != oend) { - removedVersions.push_back((*oit)->uniqueId()); + removedVersions.push_back(*oit); ++oit; } + if (!changedVersions.isEmpty() || !addedVersions.isEmpty() || !removedVersions.isEmpty()) { + const QList changedOldVersions + = Utils::transform(changedVersions, &std::pair::first); + const QList changedNewVersions + = Utils::transform(changedVersions, + &std::pair::second); + updateDocumentation(addedVersions + changedNewVersions, + removedVersions + changedOldVersions, + sortedNewVersions); + } + const QList addedIds = Utils::transform(addedVersions, &BaseQtVersion::uniqueId); + const QList removedIds = Utils::transform(removedVersions, &BaseQtVersion::uniqueId); + const QList changedIds = Utils::transform(changedVersions, + [](std::pair v) { + return v.first->uniqueId(); + }); + qDeleteAll(m_versions); m_versions.clear(); foreach (BaseQtVersion *v, sortedNewVersions) m_versions.insert(v->uniqueId(), v); - - if (!changedVersions.isEmpty() || !addedVersions.isEmpty() || !removedVersions.isEmpty()) - updateDocumentation(); - saveQtVersions(); if (!changedVersions.isEmpty() || !addedVersions.isEmpty() || !removedVersions.isEmpty()) - emit m_instance->qtVersionsChanged(addedVersions, removedVersions, changedVersions); + emit m_instance->qtVersionsChanged(addedIds, removedIds, changedIds); } } // namespace QtVersion From 9c2568b8e8d4414732fad03c2e805edc19fc40f5 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 7 Oct 2019 14:22:53 +0200 Subject: [PATCH 06/45] QtVersionManager: Small code cleanup No QLatin1String, foreach -> for, a few other things. Change-Id: I80aaff6855e4a38c29d43db917fc37eb975a6de0 Reviewed-by: Jarek Kobus --- src/plugins/qtsupport/qtversionmanager.cpp | 83 +++++++++++----------- src/plugins/qtsupport/qtversionmanager.h | 2 +- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index 50f85b8760a..d3fc9904281 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -65,7 +65,8 @@ const char QTVERSION_TYPE_KEY[] = "QtVersion.Type"; const char QTVERSION_FILE_VERSION_KEY[] = "Version"; const char QTVERSION_FILENAME[] = "/qtversion.xml"; -static QMap m_versions; +using VersionMap = QMap; +static VersionMap m_versions; static int m_idcount = 0; // managed by QtProjectManagerPlugin static QtVersionManager *m_instance = nullptr; @@ -173,24 +174,24 @@ QtVersionManager *QtVersionManager::instance() static bool restoreQtVersions() { QTC_ASSERT(!m_writer, return false); - m_writer = new PersistentSettingsWriter(settingsFileName(QLatin1String(QTVERSION_FILENAME)), - QLatin1String("QtCreatorQtVersions")); + m_writer = new PersistentSettingsWriter(settingsFileName(QTVERSION_FILENAME), + "QtCreatorQtVersions"); const QList factories = QtVersionFactory::allQtVersionFactories(); PersistentSettingsReader reader; - FilePath filename = settingsFileName(QLatin1String(QTVERSION_FILENAME)); + const FilePath filename = settingsFileName(QTVERSION_FILENAME); if (!reader.load(filename)) return false; QVariantMap data = reader.restoreValues(); // Check version: - int version = data.value(QLatin1String(QTVERSION_FILE_VERSION_KEY), 0).toInt(); + const int version = data.value(QTVERSION_FILE_VERSION_KEY, 0).toInt(); if (version < 1) return false; - const QString keyPrefix = QLatin1String(QTVERSION_DATA_KEY); + const QString keyPrefix(QTVERSION_DATA_KEY); const QVariantMap::ConstIterator dcend = data.constEnd(); for (QVariantMap::ConstIterator it = data.constBegin(); it != dcend; ++it) { const QString &key = it.key(); @@ -202,7 +203,7 @@ static bool restoreQtVersions() continue; const QVariantMap qtversionMap = it.value().toMap(); - const QString type = qtversionMap.value(QLatin1String(QTVERSION_TYPE_KEY)).toString(); + const QString type = qtversionMap.value(QTVERSION_TYPE_KEY).toString(); bool restored = false; for (QtVersionFactory *f : factories) { @@ -254,7 +255,7 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) if (debug) { qDebug()<< "======= Existing Qt versions ======="; - foreach (BaseQtVersion *version, m_versions) { + for (BaseQtVersion *version : qAsConst(m_versions)) { qDebug() << version->qmakeCommand().toString() << "id:"<uniqueId(); qDebug() << " autodetection source:"<< version->autodetectionSource(); qDebug() << ""; @@ -264,7 +265,7 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) QStringList sdkVersions; - const QString keyPrefix = QLatin1String(QTVERSION_DATA_KEY); + const QString keyPrefix(QTVERSION_DATA_KEY); const QVariantMap::ConstIterator dcend = data.constEnd(); for (QVariantMap::ConstIterator it = data.constBegin(); it != dcend; ++it) { const QString &key = it.key(); @@ -276,12 +277,12 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) continue; QVariantMap qtversionMap = it.value().toMap(); - const QString type = qtversionMap.value(QLatin1String(QTVERSION_TYPE_KEY)).toString(); - const QString autoDetectionSource = qtversionMap.value(QLatin1String("autodetectionSource")).toString(); + const QString type = qtversionMap.value(QTVERSION_TYPE_KEY).toString(); + const QString autoDetectionSource = qtversionMap.value("autodetectionSource").toString(); sdkVersions << autoDetectionSource; int id = -1; // see BaseQtVersion::fromMap() QtVersionFactory *factory = nullptr; - foreach (QtVersionFactory *f, factories) { + for (QtVersionFactory *f : factories) { if (f->canRestore(type)) factory = f; } @@ -292,14 +293,14 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) } // First try to find a existing Qt version to update bool restored = false; - foreach (BaseQtVersion *v, m_versions) { + for (BaseQtVersion *v : qAsConst(m_versions)) { if (v->autodetectionSource() == autoDetectionSource) { id = v->uniqueId(); if (debug) qDebug() << " Qt version found with same autodetection source" << autoDetectionSource << " => Migrating id:" << id; m_versions.remove(id); - qtversionMap[QLatin1String(Constants::QTVERSIONID)] = id; - qtversionMap[QLatin1String(Constants::QTVERSIONNAME)] = v->unexpandedDisplayName(); + qtversionMap[Constants::QTVERSIONID] = id; + qtversionMap[Constants::QTVERSIONNAME] = v->unexpandedDisplayName(); delete v; if (BaseQtVersion *qtv = factory->restore(type, qtversionMap)) { @@ -332,14 +333,14 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) if (debug) { qDebug() << "======= Before removing outdated sdk versions ======="; - foreach (BaseQtVersion *version, m_versions) { + for (BaseQtVersion *version : qAsConst(m_versions)) { qDebug() << version->qmakeCommand().toString() << "id:"<uniqueId(); qDebug() << " autodetection source:"<< version->autodetectionSource(); qDebug() << ""; } } - foreach (BaseQtVersion *qtVersion, m_versions) { - if (qtVersion->autodetectionSource().startsWith(QLatin1String("SDK."))) { + for (BaseQtVersion *qtVersion : qAsConst(m_versions)) { + if (qtVersion->autodetectionSource().startsWith("SDK.")) { if (!sdkVersions.contains(qtVersion->autodetectionSource())) { if (debug) qDebug() << " removing version"<autodetectionSource(); @@ -351,8 +352,8 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) if (debug) { qDebug()<< "======= End result ======="; - foreach (BaseQtVersion *version, m_versions) { - qDebug() << version->qmakeCommand().toString() << "id:"<uniqueId(); + for (BaseQtVersion *version : qAsConst(m_versions)) { + qDebug() << version->qmakeCommand().toString() << "id:" << version->uniqueId(); qDebug() << " autodetection source:"<< version->autodetectionSource(); qDebug() << ""; } @@ -367,17 +368,16 @@ static void saveQtVersions() return; QVariantMap data; - data.insert(QLatin1String(QTVERSION_FILE_VERSION_KEY), 1); + data.insert(QTVERSION_FILE_VERSION_KEY, 1); int count = 0; - foreach (BaseQtVersion *qtv, m_versions) { + for (BaseQtVersion *qtv : qAsConst(m_versions)) { QVariantMap tmp = qtv->toMap(); if (tmp.isEmpty()) continue; - tmp.insert(QLatin1String(QTVERSION_TYPE_KEY), qtv->type()); + tmp.insert(QTVERSION_TYPE_KEY, qtv->type()); data.insert(QString::fromLatin1(QTVERSION_DATA_KEY) + QString::number(count), tmp); ++count; - } m_writer->save(data, Core::ICore::mainWindow()); } @@ -395,10 +395,10 @@ static QList runQtChooser(const QString &qtchooser, const QStringLis // Asks qtchooser for the qmake path of a given version static QString qmakePath(const QString &qtchooser, const QString &version) { - QList outputs = runQtChooser(qtchooser, QStringList() - << QStringLiteral("-qt=%1").arg(version) - << QStringLiteral("-print-env")); - foreach (const QByteArray &output, outputs) { + const QList outputs = runQtChooser(qtchooser, + {QStringLiteral("-qt=%1").arg(version), + QStringLiteral("-print-env")}); + for (const QByteArray &output : outputs) { if (output.startsWith("QTTOOLDIR=\"")) { QByteArray withoutVarName = output.mid(11); // remove QTTOOLDIR=" withoutVarName.chop(1); // remove trailing quote @@ -415,9 +415,9 @@ static FilePathList gatherQmakePathsFromQtChooser() if (qtchooser.isEmpty()) return FilePathList(); - QList versions = runQtChooser(qtchooser, QStringList("-l")); + const QList versions = runQtChooser(qtchooser, QStringList("-l")); QSet foundQMakes; - foreach (const QByteArray &version, versions) { + for (const QByteArray &version : versions) { FilePath possibleQMake = FilePath::fromString( qmakePath(qtchooser, QString::fromLocal8Bit(version))); if (!possibleQMake.isEmpty()) @@ -433,9 +433,11 @@ static void findSystemQt() systemQMakes.append(gatherQmakePathsFromQtChooser()); - foreach (const FilePath &qmakePath, Utils::filteredUnique(systemQMakes)) { - BaseQtVersion *version - = QtVersionFactory::createQtVersionFromQMakePath(qmakePath, false, QLatin1String("PATH")); + const FilePathList uniqueSystemQmakes = Utils::filteredUnique(systemQMakes); + for (const FilePath &qmakePath : uniqueSystemQmakes) { + BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qmakePath, + false, + "PATH"); if (version) { version->setUnexpandedDisplayName(BaseQtVersion::defaultUnexpandedDisplayName(qmakePath, true)); m_versions.insert(version->uniqueId(), version); @@ -510,8 +512,7 @@ QList QtVersionManager::versions(const BaseQtVersion::Predicate QTC_ASSERT(isLoaded(), return versions); if (predicate) return Utils::filtered(m_versions.values(), predicate); - else - return m_versions.values(); + return m_versions.values(); } QList QtVersionManager::sortVersions(const QList &input) @@ -524,7 +525,7 @@ QList QtVersionManager::sortVersions(const QList::const_iterator it = m_versions.constFind(id); + VersionMap::const_iterator it = m_versions.constFind(id); if (it == m_versions.constEnd()) return nullptr; return it.value(); @@ -541,7 +542,7 @@ static bool equals(BaseQtVersion *a, BaseQtVersion *b) return a->equals(b); } -void QtVersionManager::setNewQtVersions(QList newVersions) +void QtVersionManager::setNewQtVersions(const QList &newVersions) { // We want to preserve the same order as in the settings dialog // so we sort a copy @@ -556,7 +557,7 @@ void QtVersionManager::setNewQtVersions(QList newVersions) // newVersions and oldVersions iterator QList::const_iterator nit, nend; - QMap::const_iterator oit, oend; + VersionMap::const_iterator oit, oend; nit = sortedNewVersions.constBegin(); nend = sortedNewVersions.constEnd(); oit = m_versions.constBegin(); @@ -607,9 +608,9 @@ void QtVersionManager::setNewQtVersions(QList newVersions) }); qDeleteAll(m_versions); - m_versions.clear(); - foreach (BaseQtVersion *v, sortedNewVersions) - m_versions.insert(v->uniqueId(), v); + m_versions = Utils::transform(sortedNewVersions, [](BaseQtVersion *v) { + return std::make_pair(v->uniqueId(), v); + }); saveQtVersions(); if (!changedVersions.isEmpty() || !addedVersions.isEmpty() || !removedVersions.isEmpty()) diff --git a/src/plugins/qtsupport/qtversionmanager.h b/src/plugins/qtsupport/qtversionmanager.h index 65695bfff00..fefe5b42731 100644 --- a/src/plugins/qtsupport/qtversionmanager.h +++ b/src/plugins/qtsupport/qtversionmanager.h @@ -72,7 +72,7 @@ private: void triggerQtVersionRestore(); // Used by QtOptionsPage - static void setNewQtVersions(QList newVersions); + static void setNewQtVersions(const QList &newVersions); // Used by QtVersion static int getUniqueId(); }; From 55acde61c3b2fff3b1cbfacf7c03e254bdd4076e Mon Sep 17 00:00:00 2001 From: Laurent Montel Date: Fri, 18 Oct 2019 09:54:09 +0200 Subject: [PATCH 07/45] Cppcheck: remove unused forward declaration Change-Id: I99f8afd16f98b9d7b2719aa95dfe07d0c5cd0054 Reviewed-by: Orgad Shaneh --- src/plugins/cppcheck/cppchecktool.h | 1 - src/plugins/cppcheck/cppchecktrigger.h | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/plugins/cppcheck/cppchecktool.h b/src/plugins/cppcheck/cppchecktool.h index ff668cf40ea..203dc2edd27 100644 --- a/src/plugins/cppcheck/cppchecktool.h +++ b/src/plugins/cppcheck/cppchecktool.h @@ -49,7 +49,6 @@ class Project; namespace Cppcheck { namespace Internal { -class Diagnostic; class CppcheckRunner; class CppcheckTextMarkManager; class CppcheckOptions; diff --git a/src/plugins/cppcheck/cppchecktrigger.h b/src/plugins/cppcheck/cppchecktrigger.h index 069bfc7b044..a745f232e38 100644 --- a/src/plugins/cppcheck/cppchecktrigger.h +++ b/src/plugins/cppcheck/cppchecktrigger.h @@ -42,10 +42,6 @@ class IDocument; class IEditor; } -namespace CppTools { -class ProjectInfo; -} - namespace Cppcheck { namespace Internal { From 7bbfa2de16b3fa64805bbbe0866fea78e704072a Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 17 Oct 2019 14:34:15 +0200 Subject: [PATCH 08/45] QmakeProjectManager: Do not start parsing without a target This "feature" generated misleading output when opening a project initially. Change-Id: I86c541266ffbf576899004f4e6401feea6f38173 Reviewed-by: Eike Ziller --- src/plugins/qmakeprojectmanager/qmakeproject.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index d8b9744ce86..28658414534 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -197,12 +197,12 @@ Project::RestoreResult QmakeProject::fromMap(const QVariantMap &map, QString *er if (m_activeTarget) { connect(m_activeTarget, &Target::activeBuildConfigurationChanged, this, &QmakeProject::scheduleAsyncUpdateLater); + scheduleAsyncUpdate(QmakeProFile::ParseNow); } connect(this, &Project::activeTargetChanged, this, &QmakeProject::activeTargetWasChanged); - scheduleAsyncUpdate(QmakeProFile::ParseNow); return RestoreResult::Ok; } @@ -707,7 +707,8 @@ QmakeProFileNode *QmakeProject::rootProjectNode() const void QmakeProject::activeTargetWasChanged() { - if (m_activeTarget) { + const bool hadActiveTarget = m_activeTarget; + if (hadActiveTarget) { disconnect(m_activeTarget, &Target::activeBuildConfigurationChanged, this, &QmakeProject::scheduleAsyncUpdateLater); } @@ -721,7 +722,7 @@ void QmakeProject::activeTargetWasChanged() connect(m_activeTarget, &Target::activeBuildConfigurationChanged, this, &QmakeProject::scheduleAsyncUpdateLater); - scheduleAsyncUpdate(); + scheduleAsyncUpdate(hadActiveTarget ? QmakeProFile::ParseLater : QmakeProFile::ParseNow); } static void notifyChangedHelper(const FilePath &fileName, QmakeProFile *file) From b6d071c2461efc49532ee2cff55fd225d4deded2 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 11 Oct 2019 15:02:52 +0200 Subject: [PATCH 09/45] Doc: Describe developing apps for Qt for MCUs Fixes: QTCREATORBUG-22926 Change-Id: I6c494858bcd637e4ae11ab0e8ea2687fb1eb26ef Reviewed-by: Venugopal Shivashankar Reviewed-by: Alessandro Portale --- doc/images/qtcreator-mcu-device.png | Bin 0 -> 8321 bytes doc/images/qtcreator-mcu-kit.png | Bin 0 -> 26040 bytes doc/images/qtcreator-mcu-options.png | Bin 0 -> 19827 bytes doc/src/ios/creator-ios-dev.qdoc | 4 +- doc/src/mcu/creator-mcu-dev.qdoc | 203 ++++++++++++++++++ .../creator-only/creator-mobile-targets.qdoc | 5 + .../creator-target-platforms.qdocinc | 7 + .../creator-projects-creating.qdoc | 7 + doc/src/qnx/creator-developing-qnx.qdoc | 2 +- doc/src/qtcreator-toc.qdoc | 1 + 10 files changed, 226 insertions(+), 3 deletions(-) create mode 100644 doc/images/qtcreator-mcu-device.png create mode 100644 doc/images/qtcreator-mcu-kit.png create mode 100644 doc/images/qtcreator-mcu-options.png create mode 100644 doc/src/mcu/creator-mcu-dev.qdoc diff --git a/doc/images/qtcreator-mcu-device.png b/doc/images/qtcreator-mcu-device.png new file mode 100644 index 0000000000000000000000000000000000000000..4159ec10c6502c3325ddb04be4af12c6ba4820a5 GIT binary patch literal 8321 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 MPgg&ebxsLQ05paz>% literal 0 HcmV?d00001 diff --git a/doc/images/qtcreator-mcu-kit.png b/doc/images/qtcreator-mcu-kit.png new file mode 100644 index 0000000000000000000000000000000000000000..e91f784a39aa02ee292ab1988bbb0cec7ba57ed6 GIT binary patch literal 26040 zcmeAS@N?(olHy`uVBq!ia0y~yU>0LwV2bBpVqjp%{d4^R14C-Pr;B4q#jUq{Pv@(g ztX=W?|KdXa%&sLYF}ru)?7zsPSrWV?LL}bScU!9D2G#k!jNc>Hy?R}p>+pPzZ}!5* z6W`uEF+Rj$RdN=c7Yeu*0PS(}M+gT&5^Uv>J@cVT59%bXzGa}EwKg^#Jmhwb- zlacbit`nzz?LB+;>~jD4^XAN%mz`$@I=~K0mNqc)c|FVu8 zKeJuiwyBAI{k{MH@BgVQCo(4?nW_cXZ+YKyRUm`I!T^mH=2oYL0U8Vp zB3;L32rUfI5MelwBl7B1n#G=-rchfa~3+yd>`YQDHgwwY59vOqNgl#Kgk;PRan{Yu-6b_aCpv@`YSlmFEhx` zFn(`_|H4b#9Kt`kISZ`#)w{$pd#d!d*2u%lZ|{|_E%k1nRjNN_XXf%8?DufM&`;L2`iwQsm?ER6FH#%!adx`t`X7|DN<(cgtpP_*21?;+sUW<~U!R z=p_1E;Eu4f(VTKkvLBzJ_Ub1j|SYIHs$@1M$Bn;+koYIOqVi}L-y@BS8ziQ{j-KK*F-zAwhS z_Wxs+e%V~N{NY#sNuP>WpNsCyDcN-U>lquy%EBopmo$ zc(Z5v`kpDDGOCUXv@$Wwh*`L6;X)_NWbU-5^Xlh(zoqmzt?$8x*4w=y>y~^f`*gt} z?(^*?^*>d6%HQwWYroIQ(%UUxeZ95FT$?KgA_^;XPM%tN>5KU3GwWk0=4+EZgXn&-R+l`d;mILXS( z``?^z_v1lx+TkzwVYw4*PgK18@?aslAKm{X%NS0BcRBuz#79XzC?GM)P7fSr~`t`#P zzmkoY)_^>CS$$c+^5x6TzJ{)BDo=E>F}vy_4trzD*F68x->Q$%aFkLw9P$(eV3mc_O%D-{>{ z3kvPkO9G-gz1odbHRpc|p60U9i22v6^}h0_R9`&)6t+^0tJR#5fnm)Yr=%~*2X??YNeOqPMOiQC!y(#=p{wgvsF!Y>n(!7#t6_@%W zV5Qg1%j&^XJ@&7dp86qJENmet01`!B{rEAXJ*|`rlw2B|7$MZ%otIyK-4VDZ_?74@ zevrC2POU4ye*L<4@7}+Ec8iR?TX%s{;%Bdbg=XgF=4NJP<>mc-eN~{8vGwoQd;u0m z0T#pgf*~4-+1c5-xx7c;@QHLOa5O1Q3s{)&johG7ozqiNlTfepUwuI-=O^?@YtE>YX=CCke z#W|5zE? zl!HK!QrrSZ1=E(y5!PuG3ns;MXDSvx|!J;S?o(!b@+&CHce z-;!VSWNJ>?(J$8bXx(C;wks~vme(nq-#F)03jZ?tJr;7F2#<;gjz z0V~cdI5($oZ<3C_>GD0%uhs@lQ#!l1-+G0U3U;XMAzqzXo z5$LE4S#kODW%lC3SI-uhc(FY_?Kp`?C9|UVYeJ*rLXcTZt*>q^u!#-IoEevz(l>SK zeU-FHGt>LFaD%PtPz_lzdGh4BmWrYaQXZ&x@xA4l6ll2qL}*DwYGq2=#N{!2BC_;m zyjyJAozDK^#hXqqo7a=TPJQOKu;%?q;j@uDoh>yht^&;;6IUY3g3j$=X-$e6hJ3woq?<+@GKIf7knYB(1$%^Yh!@uMNJHCQCnB_(HsM zD`>^5Z?≷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 x`~{M+Hb4tWP;zAe \uicontrol {About Plugins} > + \uicontrol {Device Support} > \uicontrol {Bare Metal} and + \uicontrol {MCU Support} to enable the Bare Metal and MCU + plugins. + \li Restart \QC to be able to use the plugins. + \li Create connections for debugging on the MCU board, as described in + \l{Connecting Bare Metal Devices}. + \endlist + + \section2 Specifying MCU Settings + + To configure a connection between \QC and your MCU board, select + \uicontrol Tools > \uicontrol Options > \uicontrol Devices > + \uicontrol MCU: + + \image qtcreator-mcu-options.png "MCU options" + + \list 1 + \li In the \uicontrol {MCU board} field, select your MCU board. + \li In the \uicontrol {GNU ARM Embedded Toolchain} field, + specify the path to the directory where you installed the + tool chain. + \li For STM32 boards: + \list + \li In the \uicontrol {STM32Cube SDK} field, specify the + path to the directory where you installed the SDK. + \li In the \uicontrol {STM32Cube Programmer} field, + specify the path to the directory where you + installed the tool. + \endlist + \li For NXP boards: + \list + \li In the \uicontrol {NXP EVKB-IMXRT 1050 SDK} field, + specify the path to the directory where you + installed the SDK. + \li In the \uicontrol {SEGGER JLink} field, specify the + path to the directory where you installed the tool. + \endlist + \li In the \uicontrol {Qt MCU SDK} field, specify the path to the + directory where you installed Qt MCU. + \li Select \uicontrol Apply to save the settings and to generate + a MCU device and kit. + \endlist + + \section2 Adding MCU Devices + + \QC automatically adds a default MCU device when you select + \uicontrol Apply in the \uicontrol MCU tab after configuring the + MCU tool chain. + + \image qtcreator-mcu-device.png "MCU devices" + + To add MCU devices, select \uicontrol Tools > \uicontrol Options > + \uicontrol Devices > \uicontrol Add > \uicontrol {MCU Device} > + \uicontrol {Start Wizard}: + + \list 1 + \li In the \uicontrol Name field, give the device a name. + \li In the \uicontrol Type field, select the board type. + \li Select \uicontrol Apply to add the device. + \endlist + + \section2 Adding MCU Kits + + \QC automatically adds kits for building applications and running them + on the specified MCU boards when you select \uicontrol Apply in the + \uicontrol MCU tab after configuring the MCU tool chain. + + \image qtcreator-mcu-kit.png "MCU kits" + + To add kits, select \uicontrol Tools > \uicontrol Options > \uicontrol Kits + > \uicontrol Add: + + \list 1 + \li In the \uicontrol Name field, specify a name for the kit. + \li In the \uicontrol {Device type} field, select + \uicontrol {MCU}. + \li In the \uicontrol Device field, select the MCU board for the kit. + \li In the \uicontrol Compiler field, select the Arm GCC compiler for + the kit. + \li Select \uicontrol Apply to add the kit. + \endlist + + \section1 Running Applications on MCUs + + You can use a wizard to set up a project for developing an application that + you can run on MCUs. The project uses a subset of QML and Qt Quick Controls + that are supported by Qt for MCUs. For more information about developing + applications for MCUs, see the Qt for MCU documentation. + + To create an application and run it on a MCU board: + + \list 1 + \li Select \uicontrol File > \uicontrol {New File or Project} > + \uicontrol Application > \uicontrol {MCU Support Application} > + \uicontrol Choose. + \li Follow the instructions of the wizard to create the project. + \li Select \uicontrol Projects > \uicontrol {Build & Run}, and then + select the kit for building the application and running it on the + MCU board specified in the kit. + \li Select \uicontrol Run to specify run settings. + Usually, you can use the default settings. + \endlist +*/ diff --git a/doc/src/overview/creator-only/creator-mobile-targets.qdoc b/doc/src/overview/creator-only/creator-mobile-targets.qdoc index 37822c534fd..470d5c2360b 100644 --- a/doc/src/overview/creator-only/creator-mobile-targets.qdoc +++ b/doc/src/overview/creator-only/creator-mobile-targets.qdoc @@ -83,6 +83,11 @@ \QC detects the tools and configured devices automatically and uses the tools to build, deploy, and run applications. + \li \l{Connecting MCUs} + + You can connect MCU boards to a development host to deploy, run, and + debug applications on them from \QC. + \li \l{Connecting QNX Devices} You can connect QNX devices to the development PC to deploy, run and diff --git a/doc/src/overview/creator-only/creator-target-platforms.qdocinc b/doc/src/overview/creator-only/creator-target-platforms.qdocinc index c269e61404e..95015bd8051 100644 --- a/doc/src/overview/creator-only/creator-target-platforms.qdocinc +++ b/doc/src/overview/creator-only/creator-target-platforms.qdocinc @@ -42,6 +42,8 @@ \li iOS + \li Microcontroller Units (MCU) + \li QNX \li Universal Windows Platform (UWP) @@ -95,6 +97,11 @@ \li \li \image ok \li + \row + \li MCUs + \li \image ok + \li \image ok + \li \image ok \row \li QNX \li \image ok diff --git a/doc/src/projects/creator-only/creator-projects-creating.qdoc b/doc/src/projects/creator-only/creator-projects-creating.qdoc index 557b2acfcb1..1bca73e5517 100644 --- a/doc/src/projects/creator-only/creator-projects-creating.qdoc +++ b/doc/src/projects/creator-only/creator-projects-creating.qdoc @@ -133,6 +133,13 @@ code for a QApplication or create one that contains an empty window. + \li MCU Support Application + + Creates an application that uses a subset of QML and + Qt Quick Controls (as supported by Qt for MCUs) that + you can deploy, run, and debug on MCU boards. For more + information, see \l {Connecting MCUs}. + \endlist \li Libraries diff --git a/doc/src/qnx/creator-developing-qnx.qdoc b/doc/src/qnx/creator-developing-qnx.qdoc index 77874373038..8dce60438d9 100644 --- a/doc/src/qnx/creator-developing-qnx.qdoc +++ b/doc/src/qnx/creator-developing-qnx.qdoc @@ -30,7 +30,7 @@ /*! \contentspage index.html - \previouspage creator-developing-ios.html + \previouspage creator-developing-mcu.html \page creator-developing-qnx.html \nextpage creator-setup-webassembly.html diff --git a/doc/src/qtcreator-toc.qdoc b/doc/src/qtcreator-toc.qdoc index 7527b8a9650..7774af49512 100644 --- a/doc/src/qtcreator-toc.qdoc +++ b/doc/src/qtcreator-toc.qdoc @@ -175,6 +175,7 @@ \li \l{Connecting Bare Metal Devices} \li \l{Connecting Embedded Linux Devices} \li \l{Connecting iOS Devices} + \li \l{Connecting MCUs} \li \l{Connecting QNX Devices} \li \l{Building Applications for the Web} \endlist From e7b481bdee9759a3dc5efc3d55400394654fc592 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 1 Oct 2019 14:53:03 +0200 Subject: [PATCH 10/45] Qnx: Suppress warnings about missing stat These warnings are only relevant for incremental deployment, which is not used here. Change-Id: I52636b0c3f7ba89131c27fc5e66c23e8a6ea9990 Reviewed-by: hjk --- src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp index 4653d8bad03..4182ca28264 100644 --- a/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp +++ b/src/plugins/qnx/qnxdeployqtlibrariesdialog.cpp @@ -77,7 +77,10 @@ QnxDeployQtLibrariesDialog::QnxDeployQtLibrariesDialog(const IDevice::ConstPtr & connect(m_uploadService, &AbstractRemoteLinuxDeployService::errorMessage, m_ui->deployLogWindow, &QPlainTextEdit::appendPlainText); connect(m_uploadService, &AbstractRemoteLinuxDeployService::warningMessage, - m_ui->deployLogWindow, &QPlainTextEdit::appendPlainText); + this, [this](const QString &message) { + if (!message.contains("stat:")) + m_ui->deployLogWindow->appendPlainText(message); + }); connect(m_uploadService, &AbstractRemoteLinuxDeployService::stdOutData, m_ui->deployLogWindow, &QPlainTextEdit::appendPlainText); connect(m_uploadService, &AbstractRemoteLinuxDeployService::stdErrData, From 640044c8f8d7c290558c63c636be7821f9a8a223 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 17 Oct 2019 13:51:57 +0200 Subject: [PATCH 11/45] QmlDesigner: Implement command for synchronising the selection This patch implements the command and dispatchers for synchronising the selection between Qt Creator and the qml2puppet. Qt5InformationNodeInstanceServer::changeSelection() is called whenever the selection is changed in Qt Creator. Qt5InformationNodeInstanceServer::changeSelection() allows to change the selection from the qml2puppet. Change-Id: I73a64d8dc2a3f330433f966b42a10229cbbff649 Reviewed-by: Alessandro Portale --- .../commands/changeselectioncommand.cpp | 69 +++++++++++++++++++ .../commands/changeselectioncommand.h | 61 ++++++++++++++++ .../qml/qmlpuppet/commands/commands.pri | 2 + .../instances/nodeinstanceclientproxy.cpp | 21 +++++- .../instances/nodeinstanceclientproxy.h | 4 +- .../interfaces/nodeinstanceclientinterface.h | 2 + .../nodeinstanceserverinterface.cpp | 4 ++ .../interfaces/nodeinstanceserverinterface.h | 2 + .../instances/nodeinstanceserver.cpp | 16 +++++ .../qml2puppet/instances/nodeinstanceserver.h | 3 + .../qt5informationnodeinstanceserver.cpp | 13 ++++ .../qt5informationnodeinstanceserver.h | 2 + .../instances/qt5testnodeinstanceserver.cpp | 5 ++ .../instances/qt5testnodeinstanceserver.h | 1 + src/plugins/qmldesigner/CMakeLists.txt | 1 + .../designercore/include/nodeinstanceview.h | 7 ++ .../instances/nodeinstanceserverproxy.cpp | 9 +++ .../instances/nodeinstanceserverproxy.h | 1 + .../instances/nodeinstanceview.cpp | 30 ++++++++ .../qmldesigner/designercore/model/model.cpp | 4 ++ src/plugins/qmldesigner/qmldesignerplugin.qbs | 2 + src/tools/qml2puppet/CMakeLists.txt | 1 + src/tools/qml2puppet/qml2puppet.qbs | 2 + 23 files changed, 258 insertions(+), 4 deletions(-) create mode 100644 share/qtcreator/qml/qmlpuppet/commands/changeselectioncommand.cpp create mode 100644 share/qtcreator/qml/qmlpuppet/commands/changeselectioncommand.h diff --git a/share/qtcreator/qml/qmlpuppet/commands/changeselectioncommand.cpp b/share/qtcreator/qml/qmlpuppet/commands/changeselectioncommand.cpp new file mode 100644 index 00000000000..a634e76b8f9 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/commands/changeselectioncommand.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "changeselectioncommand.h" + +#include +#include + +namespace QmlDesigner { + +ChangeSelectionCommand::ChangeSelectionCommand() = default; + +ChangeSelectionCommand::ChangeSelectionCommand(const QVector &idVector) + : m_instanceIdVector(idVector) +{ +} + +QVector ChangeSelectionCommand::instanceIds() const +{ + return m_instanceIdVector; +} + +QDataStream &operator<<(QDataStream &out, const ChangeSelectionCommand &command) +{ + out << command.instanceIds(); + + return out; +} + +QDataStream &operator>>(QDataStream &in, ChangeSelectionCommand &command) +{ + in >> command.m_instanceIdVector; + + return in; +} + +QDebug operator <<(QDebug debug, const ChangeSelectionCommand &command) +{ + return debug.nospace() << "ChangeSelectionCommand(instanceIdVector: " << command.m_instanceIdVector << ")"; +} + +bool operator ==(const ChangeSelectionCommand &first, const ChangeSelectionCommand &second) +{ + return first.m_instanceIdVector == second.m_instanceIdVector; +} + +} // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/commands/changeselectioncommand.h b/share/qtcreator/qml/qmlpuppet/commands/changeselectioncommand.h new file mode 100644 index 00000000000..a5962c5dcb0 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/commands/changeselectioncommand.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include +#include + +#include "instancecontainer.h" + +namespace QmlDesigner { + +class ChangeSelectionCommand +{ + friend QDataStream &operator>>(QDataStream &in, ChangeSelectionCommand &command); + friend QDebug operator <<(QDebug debug, const ChangeSelectionCommand &command); + friend bool operator ==(const ChangeSelectionCommand &first, + const ChangeSelectionCommand &second); + +public: + ChangeSelectionCommand(); + explicit ChangeSelectionCommand(const QVector &idVector); + + QVector instanceIds() const; + +private: + QVector m_instanceIdVector; +}; + +QDataStream &operator<<(QDataStream &out, const ChangeSelectionCommand &command); +QDataStream &operator>>(QDataStream &in, ChangeSelectionCommand &command); +bool operator ==(const ChangeSelectionCommand &first, const ChangeSelectionCommand &second); + +QDebug operator <<(QDebug debug, const ChangeSelectionCommand &command); + +} // namespace QmlDesigner + +Q_DECLARE_METATYPE(QmlDesigner::ChangeSelectionCommand) diff --git a/share/qtcreator/qml/qmlpuppet/commands/commands.pri b/share/qtcreator/qml/qmlpuppet/commands/commands.pri index 3bf0305103f..78dfcd8eb14 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/commands.pri +++ b/share/qtcreator/qml/qmlpuppet/commands/commands.pri @@ -26,6 +26,7 @@ HEADERS += $$PWD/valueschangedcommand.h HEADERS += $$PWD/changeauxiliarycommand.h HEADERS += $$PWD/removesharedmemorycommand.h HEADERS += $$PWD/puppetalivecommand.h +HEADERS += $$PWD/changeselectioncommand.h SOURCES += $$PWD/synchronizecommand.cpp SOURCES += $$PWD/debugoutputcommand.cpp @@ -53,3 +54,4 @@ SOURCES += $$PWD/pixmapchangedcommand.cpp SOURCES += $$PWD/changeauxiliarycommand.cpp SOURCES += $$PWD/removesharedmemorycommand.cpp SOURCES += $$PWD/puppetalivecommand.cpp +SOURCES += $$PWD/changeselectioncommand.cpp diff --git a/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp b/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp index 5ac0e1057b6..a4b9324699e 100644 --- a/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp +++ b/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp @@ -67,6 +67,7 @@ #include "endpuppetcommand.h" #include "debugoutputcommand.h" #include "puppetalivecommand.h" +#include "changeselectioncommand.h" namespace QmlDesigner { @@ -136,6 +137,7 @@ bool compareCommands(const QVariant &command, const QVariant &controlCommand) static const int synchronizeCommandType = QMetaType::type("SynchronizeCommand"); static const int tokenCommandType = QMetaType::type("TokenCommand"); static const int debugOutputCommandType = QMetaType::type("DebugOutputCommand"); + static const int changeSelectionCommandType = QMetaType::type("ChangeSelectionCommand"); if (command.userType() == controlCommand.userType()) { if (command.userType() == informationChangedCommandType) @@ -156,6 +158,8 @@ bool compareCommands(const QVariant &command, const QVariant &controlCommand) return command.value() == controlCommand.value(); else if (command.userType() == debugOutputCommandType) return command.value() == controlCommand.value(); + else if (command.userType() == changeSelectionCommandType) + return command.value() == controlCommand.value(); } return false; @@ -233,6 +237,11 @@ void NodeInstanceClientProxy::puppetAlive(const PuppetAliveCommand &command) writeCommand(QVariant::fromValue(command)); } +void NodeInstanceClientProxy::selectionChanged(const ChangeSelectionCommand &command) +{ + writeCommand(QVariant::fromValue(command)); +} + void NodeInstanceClientProxy::flush() { } @@ -252,9 +261,6 @@ qint64 NodeInstanceClientProxy::bytesToWrite() const QVariant NodeInstanceClientProxy::readCommandFromIOStream(QIODevice *ioDevice, quint32 *readCommandCounter, quint32 *blockSize) { - - - QDataStream in(ioDevice); in.setVersion(QDataStream::Qt_4_8); @@ -416,6 +422,11 @@ void NodeInstanceClientProxy::redirectToken(const EndPuppetCommand & /*command*/ QCoreApplication::exit(); } +void NodeInstanceClientProxy::changeSelection(const ChangeSelectionCommand &command) +{ + nodeInstanceServer()->changeSelection(command); +} + void NodeInstanceClientProxy::dispatchCommand(const QVariant &command) { static const int createInstancesCommandType = QMetaType::type("CreateInstancesCommand"); @@ -436,6 +447,7 @@ void NodeInstanceClientProxy::dispatchCommand(const QVariant &command) static const int removeSharedMemoryCommandType = QMetaType::type("RemoveSharedMemoryCommand"); static const int tokenCommandType = QMetaType::type("TokenCommand"); static const int endPuppetCommandType = QMetaType::type("EndPuppetCommand"); + static const int changeSelectionCommandType = QMetaType::type("ChangeSelectionCommand"); const int commandType = command.userType(); @@ -476,6 +488,9 @@ void NodeInstanceClientProxy::dispatchCommand(const QVariant &command) else if (commandType == synchronizeCommandType) { SynchronizeCommand synchronizeCommand = command.value(); m_synchronizeId = synchronizeCommand.synchronizeId(); + } else if (commandType == changeSelectionCommandType) { + ChangeSelectionCommand changeSelectionCommand = command.value(); + changeSelection(changeSelectionCommand); } else { Q_ASSERT(false); } diff --git a/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.h b/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.h index 2c53a77c90d..8590a48a957 100644 --- a/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.h +++ b/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.h @@ -56,7 +56,7 @@ class CompleteComponentCommand; class ChangeStateCommand; class ChangeNodeSourceCommand; class EndPuppetCommand; - +class ChangeSelectionCommand; class NodeInstanceClientProxy : public QObject, public NodeInstanceClientInterface { @@ -74,6 +74,7 @@ public: void token(const TokenCommand &command) override; void debugOutput(const DebugOutputCommand &command) override; void puppetAlive(const PuppetAliveCommand &command); + void selectionChanged(const ChangeSelectionCommand &command) override; void flush() override; void synchronizeWithClientProcess() override; @@ -104,6 +105,7 @@ protected: void removeSharedMemory(const RemoveSharedMemoryCommand &command); void redirectToken(const TokenCommand &command); void redirectToken(const EndPuppetCommand &command); + void changeSelection(const ChangeSelectionCommand &command); static QVariant readCommandFromIOStream(QIODevice *ioDevice, quint32 *readCommandCounter, quint32 *blockSize); protected slots: diff --git a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceclientinterface.h b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceclientinterface.h index 43c50b510c5..1f49f277f51 100644 --- a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceclientinterface.h +++ b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceclientinterface.h @@ -39,6 +39,7 @@ class TokenCommand; class RemoveSharedMemoryCommand; class DebugOutputCommand; class PuppetAliveCommand; +class ChangeSelectionCommand; class NodeInstanceClientInterface { @@ -51,6 +52,7 @@ public: virtual void componentCompleted(const ComponentCompletedCommand &command) = 0; virtual void token(const TokenCommand &command) = 0; virtual void debugOutput(const DebugOutputCommand &command) = 0; + virtual void selectionChanged(const ChangeSelectionCommand &command) = 0; virtual void flush() {} virtual void synchronizeWithClientProcess() {} diff --git a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp index 8d1ad20c313..90907b50929 100644 --- a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp +++ b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp @@ -45,6 +45,7 @@ #include "completecomponentcommand.h" #include "addimportcontainer.h" #include "changenodesourcecommand.h" +#include "changeselectioncommand.h" #include "informationchangedcommand.h" #include "pixmapchangedcommand.h" @@ -103,6 +104,9 @@ void NodeInstanceServerInterface::registerCommands() qRegisterMetaType("RemoveInstancesCommand"); qRegisterMetaTypeStreamOperators("RemoveInstancesCommand"); + qRegisterMetaType("ChangeSelectionCommand"); + qRegisterMetaTypeStreamOperators("ChangeSelectionCommand"); + qRegisterMetaType("RemovePropertiesCommand"); qRegisterMetaTypeStreamOperators("RemovePropertiesCommand"); diff --git a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.h b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.h index 0fddbde5c07..b452c802be4 100644 --- a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.h +++ b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.h @@ -49,6 +49,7 @@ class CompleteComponentCommand; class ChangeNodeSourceCommand; class TokenCommand; class RemoveSharedMemoryCommand; +class ChangeSelectionCommand; class NodeInstanceServerInterface : public QObject { @@ -77,6 +78,7 @@ public: virtual void changeNodeSource(const ChangeNodeSourceCommand &command) = 0; virtual void token(const TokenCommand &command) = 0; virtual void removeSharedMemory(const RemoveSharedMemoryCommand &command) = 0; + virtual void changeSelection(const ChangeSelectionCommand &command) = 0; virtual void benchmark(const QString &) {} diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index 60d34c909d9..356d173e09a 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -66,6 +66,7 @@ #include #include #include +#include #include #include @@ -330,6 +331,10 @@ void NodeInstanceServer::clearScene(const ClearSceneCommand &/*command*/) m_fileUrl.clear(); } +void NodeInstanceServer::changeSelection(const ChangeSelectionCommand & /*command*/) +{ +} + void NodeInstanceServer::removeInstances(const RemoveInstancesCommand &command) { ServerNodeInstance oldState = activeStateInstance(); @@ -1157,6 +1162,17 @@ ComponentCompletedCommand NodeInstanceServer::createComponentCompletedCommand(co return ComponentCompletedCommand(idVector); } +ChangeSelectionCommand NodeInstanceServer::createChangeSelectionCommand(const QList &instanceList) +{ + QVector idVector; + for (const ServerNodeInstance &instance : instanceList) { + if (instance.instanceId() >= 0) + idVector.append(instance.instanceId()); + } + + return ChangeSelectionCommand(idVector); +} + ValuesChangedCommand NodeInstanceServer::createValuesChangedCommand(const QVector &propertyList) const { QVector valueVector; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h index fb8b081b45b..65c2bdfac14 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h @@ -68,6 +68,7 @@ class ComponentCompletedCommand; class AddImportContainer; class MockupTypeContainer; class IdContainer; +class ChangeSelectionCommand; namespace Internal { class ChildrenChangeEventFilter; @@ -101,6 +102,7 @@ public: void changeNodeSource(const ChangeNodeSourceCommand &command) override; void token(const TokenCommand &command) override; void removeSharedMemory(const RemoveSharedMemoryCommand &command) override; + void changeSelection(const ChangeSelectionCommand &command) override; ServerNodeInstance instanceForId(qint32 id) const; bool hasInstanceForId(qint32 id) const; @@ -170,6 +172,7 @@ protected: InformationChangedCommand createAllInformationChangedCommand(const QList &instanceList, bool initial = false) const; ChildrenChangedCommand createChildrenChangedCommand(const ServerNodeInstance &parentInstance, const QList &instanceList) const; ComponentCompletedCommand createComponentCompletedCommand(const QList &instanceList); + ChangeSelectionCommand createChangeSelectionCommand(const QList &instanceList); void addChangedProperty(const InstancePropertyPair &property); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 2b644b5959c..4754181a77d 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -55,6 +55,7 @@ #include "createscenecommand.h" #include "tokencommand.h" #include "removesharedmemorycommand.h" +#include "changeselectioncommand.h" #include "dummycontextobject.h" @@ -147,6 +148,12 @@ bool Qt5InformationNodeInstanceServer::isDirtyRecursiveForParentInstances(QQuick return false; } +/* This method allows changing the selection from the puppet */ +void Qt5InformationNodeInstanceServer::selectInstance(const ServerNodeInstance &instance) +{ + nodeInstanceClient()->selectionChanged(createChangeSelectionCommand({instance})); +} + QObject *Qt5InformationNodeInstanceServer::findRootNodeOf3DViewport( const QList &instanceList) const { @@ -358,4 +365,10 @@ void QmlDesigner::Qt5InformationNodeInstanceServer::removeSharedMemory(const Qml ValuesChangedCommand::removeSharedMemorys(command.keyNumbers()); } +void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionCommand &command) +{ + // keep track of selection. + qDebug() << Q_FUNC_INFO << command; +} + } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index 9254cb4157c..962336ccdc4 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -42,6 +42,7 @@ public: void completeComponent(const CompleteComponentCommand &command) override; void token(const TokenCommand &command) override; void removeSharedMemory(const RemoveSharedMemoryCommand &command) override; + void changeSelection(const ChangeSelectionCommand &command) override; protected: void collectItemChangesAndSendChangeCommands() override; @@ -49,6 +50,7 @@ protected: void sendTokenBack(); bool isDirtyRecursiveForNonInstanceItems(QQuickItem *item) const; bool isDirtyRecursiveForParentInstances(QQuickItem *item) const; + void selectInstance(const ServerNodeInstance &instance); private: void setup3DEditView(const QList &instanceList); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.cpp index cb5af3dc800..fed075a4866 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.cpp @@ -151,6 +151,11 @@ void Qt5TestNodeInstanceServer::clearScene(const ClearSceneCommand &command) Qt5NodeInstanceServer::clearScene(command); } +void Qt5TestNodeInstanceServer::changeSelection(const ChangeSelectionCommand &) +{ + +} + void Qt5TestNodeInstanceServer::removeInstances(const RemoveInstancesCommand &command) { ServerNodeInstance oldState = activeStateInstance(); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.h index af30c423d6c..18c20561740 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5testnodeinstanceserver.h @@ -50,6 +50,7 @@ public: void completeComponent(const CompleteComponentCommand &command) override; void changeNodeSource(const ChangeNodeSourceCommand &command) override; void removeSharedMemory(const RemoveSharedMemoryCommand &command) override; + void changeSelection(const ChangeSelectionCommand &command) override; using Qt5NodeInstanceServer::createInstances; diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 9bf5fab1135..c645a96774e 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -138,6 +138,7 @@ extend_qtc_plugin(QmlDesigner synchronizecommand.cpp synchronizecommand.h tokencommand.cpp tokencommand.h valueschangedcommand.cpp valueschangedcommand.h + changeselectioncommand.cpp changeselectioncommand.h ) extend_qtc_plugin(QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index f77ac4645b0..258fc9aa2d0 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -64,6 +64,7 @@ class ChangeValuesCommand; class ChangeBindingsCommand; class ChangeIdsCommand; class RemoveInstancesCommand; +class ChangeSelectionCommand; class RemovePropertiesCommand; class CompleteComponentCommand; class InformationContainer; @@ -134,6 +135,11 @@ public: void sendToken(const QString &token, int number, const QVector &nodeVector); + void selectionChanged(const ChangeSelectionCommand &command) override; + + void selectedNodesChanged(const QList &selectedNodeList, + const QList &lastSelectedNodeList) override; + protected: void timerEvent(QTimerEvent *event) override; @@ -173,6 +179,7 @@ private: // functions ChangeBindingsCommand createChangeBindingCommand(const QList &propertyList) const; ChangeIdsCommand createChangeIdsCommand(const QList &instanceList) const; RemoveInstancesCommand createRemoveInstancesCommand(const QList &nodeList) const; + ChangeSelectionCommand createChangeSelectionCommand(const QList &nodeList) const; RemoveInstancesCommand createRemoveInstancesCommand(const ModelNode &node) const; RemovePropertiesCommand createRemovePropertiesCommand(const QList &propertyList) const; RemoveSharedMemoryCommand createRemoveSharedMemoryCommand(const QString &sharedMemoryTypeName, quint32 keyNumber); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp index e7d60b25d24..c5b98bf3258 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -278,6 +279,7 @@ void NodeInstanceServerProxy::dispatchCommand(const QVariant &command, PuppetStr static const int tokenCommandType = QMetaType::type("TokenCommand"); static const int debugOutputCommandType = QMetaType::type("DebugOutputCommand"); static const int puppetAliveCommandType = QMetaType::type("PuppetAliveCommand"); + static const int changeSelectionCommandType = QMetaType::type("ChangeSelectionCommand"); if (m_destructing) return; @@ -299,6 +301,8 @@ void NodeInstanceServerProxy::dispatchCommand(const QVariant &command, PuppetStr nodeInstanceClient()->token(command.value()); } else if (command.userType() == debugOutputCommandType) { nodeInstanceClient()->debugOutput(command.value()); + } else if (command.userType() == changeSelectionCommandType) { + nodeInstanceClient()->selectionChanged(command.value()); } else if (command.userType() == puppetAliveCommandType) { puppetAlive(puppetStreamType); } else if (command.userType() == synchronizeCommandType) { @@ -645,6 +649,11 @@ void NodeInstanceServerProxy::removeInstances(const RemoveInstancesCommand &comm writeCommand(QVariant::fromValue(command)); } +void NodeInstanceServerProxy::changeSelection(const ChangeSelectionCommand &command) +{ + writeCommand(QVariant::fromValue(command)); +} + void NodeInstanceServerProxy::removeProperties(const RemovePropertiesCommand &command) { writeCommand(QVariant::fromValue(command)); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h index b1525b4408e..a6a7f6ce99b 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h @@ -71,6 +71,7 @@ public: void createScene(const CreateSceneCommand &command) override; void clearScene(const ClearSceneCommand &command) override; void removeInstances(const RemoveInstancesCommand &command) override; + void changeSelection(const ChangeSelectionCommand &command) override; void removeProperties(const RemovePropertiesCommand &command) override; void changePropertyBindings(const ChangeBindingsCommand &command) override; void changePropertyValues(const ChangeValuesCommand &command) override; diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 66d503078b5..5d44e5069c4 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -51,6 +51,7 @@ #include "changeauxiliarycommand.h" #include "changebindingscommand.h" #include "changeidscommand.h" +#include "changeselectioncommand.h" #include "changenodesourcecommand.h" #include "removeinstancescommand.h" #include "removepropertiescommand.h" @@ -1109,6 +1110,21 @@ RemoveInstancesCommand NodeInstanceView::createRemoveInstancesCommand(const QLis return RemoveInstancesCommand(idList); } +ChangeSelectionCommand NodeInstanceView::createChangeSelectionCommand(const QList &nodeList) const +{ + QVector idList; + foreach (const ModelNode &node, nodeList) { + if (node.isValid() && hasInstanceForModelNode(node)) { + NodeInstance instance = instanceForModelNode(node); + + if (instance.instanceId() >= 0) + idList.append(instance.instanceId()); + } + } + + return ChangeSelectionCommand(idList); +} + RemoveInstancesCommand NodeInstanceView::createRemoveInstancesCommand(const ModelNode &node) const { QVector idList; @@ -1364,6 +1380,20 @@ void NodeInstanceView::sendToken(const QString &token, int number, const QVector nodeInstanceServer()->token(TokenCommand(token, number, instanceIdVector)); } +void NodeInstanceView::selectionChanged(const ChangeSelectionCommand &command) +{ + foreach (const qint32 &instanceId, command.instanceIds()) { + if (hasModelNodeForInternalId(instanceId)) + selectModelNode(modelNodeForInternalId(instanceId)); + } +} + +void NodeInstanceView::selectedNodesChanged(const QList &selectedNodeList, + const QList & /*lastSelectedNodeList*/) +{ + nodeInstanceServer()->changeSelection(createChangeSelectionCommand(selectedNodeList)); +} + void NodeInstanceView::timerEvent(QTimerEvent *event) { if (m_restartProcessTimerId == event->timerId()) diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index 8699389182e..e3598b09c03 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -1464,6 +1464,10 @@ void ModelPrivate::changeSelectedNodes(const QList &newSe Q_ASSERT(view != nullptr); view->selectedNodesChanged(toModelNodeList(newSelectedNodeList, view.data()), toModelNodeList(oldSelectedNodeList, view.data())); } + + if (nodeInstanceView()) + nodeInstanceView()->selectedNodesChanged(toModelNodeList(newSelectedNodeList, nodeInstanceView()), + toModelNodeList(oldSelectedNodeList, nodeInstanceView())); } QList ModelPrivate::selectedNodes() const diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index c62c75be984..0d7b54c68ed 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -167,6 +167,8 @@ Project { "commands/tokencommand.h", "commands/valueschangedcommand.cpp", "commands/valueschangedcommand.h", + "commands/changeselectioncommand.cpp", + "commands/changeselectioncommand.h", "container/addimportcontainer.cpp", "container/addimportcontainer.h", "container/idcontainer.cpp", diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt index 3715ae9349e..3db1cb34cd9 100644 --- a/src/tools/qml2puppet/CMakeLists.txt +++ b/src/tools/qml2puppet/CMakeLists.txt @@ -44,6 +44,7 @@ extend_qtc_executable(qml2puppet statepreviewimagechangedcommand.cpp statepreviewimagechangedcommand.h synchronizecommand.cpp synchronizecommand.h tokencommand.cpp tokencommand.h + changeselectioncommand.cpp changeselectioncommand.h valueschangedcommand.cpp ) diff --git a/src/tools/qml2puppet/qml2puppet.qbs b/src/tools/qml2puppet/qml2puppet.qbs index 02a6f6e31f2..bc67e79a1a8 100644 --- a/src/tools/qml2puppet/qml2puppet.qbs +++ b/src/tools/qml2puppet/qml2puppet.qbs @@ -93,6 +93,8 @@ QtcTool { "commands/tokencommand.h", "commands/valueschangedcommand.cpp", "commands/valueschangedcommand.h", + "commands/changeselectioncommand.cpp", + "commands/changeselectioncommand.h", "container/addimportcontainer.cpp", "container/addimportcontainer.h", "container/idcontainer.cpp", From 3ee870a3d8860c23e23661bfda3aee2b4ab4b8b8 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 17 Oct 2019 16:22:00 +0200 Subject: [PATCH 12/45] QmlJS: Fix regression caused by parser update We have to keep the semicolonToken into account. Change-Id: Ie599d141d21f09f1d0036c0382f6a3098fde6ca5 Reviewed-by: Vikas Pachdha Reviewed-by: Fabian Kosmale Reviewed-by: Ulf Hermann --- src/libs/qmljs/parser/qmljsast_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/qmljs/parser/qmljsast_p.h b/src/libs/qmljs/parser/qmljsast_p.h index aa9aea87784..3faddcecb38 100644 --- a/src/libs/qmljs/parser/qmljsast_p.h +++ b/src/libs/qmljs/parser/qmljsast_p.h @@ -1766,7 +1766,7 @@ public: { return expression->firstSourceLocation(); } SourceLocation lastSourceLocation() const override - { return expression->lastSourceLocation(); } + { return semicolonToken.isValid() ? semicolonToken : expression->lastSourceLocation(); } // attributes ExpressionNode *expression; From c2c8b9a5d65236f9103f00dd9b0be605aa812409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pasi=20Kera=CC=88nen?= Date: Tue, 15 Oct 2019 14:54:20 +0300 Subject: [PATCH 13/45] Add edit camera controls for 3D edit view Add edit camera controls and grid helper to 3D edit view. Task-number: QDS-1127 Change-Id: Ice5ea0fcca18d59dc8a2907710e16c6688b90628 Reviewed-by: Thomas Hartmann Reviewed-by: Miikka Heikkinen --- .../qml/qmlpuppet/mockfiles/EditView3D.qml | 121 ++++++++++-------- .../editor3d/cameracontrolhelper.cpp | 59 +++++++++ .../qml2puppet/editor3d/cameracontrolhelper.h | 57 +++++++++ .../qml2puppet/editor3d/editor3d.pri | 2 + .../qt5informationnodeinstanceserver.cpp | 8 +- .../qml/qmlpuppet/qml2puppet/qml2puppet.pri | 1 + src/tools/qml2puppet/CMakeLists.txt | 6 + src/tools/qml2puppet/qml2puppet.qbs | 2 + 8 files changed, 204 insertions(+), 52 deletions(-) create mode 100644 share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.cpp create mode 100644 share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.h create mode 100644 share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index f6ad8b58f22..519dc83569a 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -23,79 +23,98 @@ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQuick 2.12 import QtQuick.Window 2.0 import QtQuick3D 1.0 +import QtQuick3D.Helpers 1.0 import QtQuick.Controls 2.0 +import QtGraphicalEffects 1.0 Window { + id: viewWindow width: 1024 height: 768 visible: true title: "3D" flags: Qt.WindowStaysOnTopHint | Qt.Window | Qt.WindowTitleHint | Qt.WindowCloseButtonHint + property alias scene: editView.scene + property alias showEditLight: editLightCheckbox.checked + property alias usePerspective: usePerspectiveCheckbox.checked + Rectangle { - color: "black" + id: sceneBg + color: "#FFFFFF" anchors.fill: parent - } + focus: true - Column { - y: 32 - Slider { - id: slider + View3D { + id: editView + anchors.fill: parent + enableWireframeMode: true + camera: editCamera - value: -600 - from: -1200 - to: 600 + AxisHelper { + id: axisGrid + enableXZGrid: true + enableAxisLines: false + } + + Light { + id: directionalLight + visible: showEditLight + } + + Camera { + id: editCamera + y: 200 + z: -300 + clipFar: 100000 + projectionMode: usePerspective ? Camera.Perspective : Camera.Orthographic + } + + Component.onCompleted: { + directionalLight.setParentItem(editView.scene); + editCamera.setParentItem(editView.scene); + } } - Slider { - id: slider2 - value: 0 - from: -360 - to: 360 - } - CheckBox { - id: checkBox - text: "Light" - Rectangle { - anchors.fill: parent - z: -1 + WasdController { + id: cameraControl + controlledObject: editView.camera + acceptedButtons: Qt.RightButton + + onInputsNeedProcessingChanged: designStudioNativeCameraControlHelper.enabled + = cameraControl.inputsNeedProcessing + + // Use separate native timer as QML timers don't work inside Qt Design Studio + Connections { + target: designStudioNativeCameraControlHelper + onUpdateInputs: cameraControl.processInputs() } } } - Binding { - target: view.scene - property: "rotation.y" - value: slider2.value + Column { + y: 8 + CheckBox { + id: editLightCheckbox + checked: false + text: qsTr("Use Edit View Light") + onCheckedChanged: cameraControl.forceActiveFocus() + } + + CheckBox { + id: usePerspectiveCheckbox + checked: true + text: qsTr("Use Perspective Projection") + onCheckedChanged: cameraControl.forceActiveFocus() + } } - property alias scene: view.scene - property alias showLight: checkBox.checked - - id: viewWindow - - View3D { - id: view - anchors.fill: parent - enableWireframeMode: true - camera: camera01 - - Light { - id: directionalLight - visible: checkBox.checked - } - - Camera { - id: camera01 - z: slider.value - } - - Component.onCompleted: { - directionalLight.setParentItem(view.scene) - camera01.setParentItem(view.scene) - } + Text { + id: helpText + text: qsTr("Camera: W,A,S,D,R,F,right mouse drag") + anchors.bottom: parent.bottom } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.cpp new file mode 100644 index 00000000000..c05e8230bfa --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#include "cameracontrolhelper.h" + +namespace QmlDesigner { +namespace Internal { + +CameraControlHelper::CameraControlHelper() + : QObject() +{ + m_timer.setInterval(16); + m_timer.setSingleShot(false); + QObject::connect(&m_timer, &QTimer::timeout, + this, &CameraControlHelper::handleUpdateTimer); +} + +bool CameraControlHelper::enabled() +{ + return m_enabled; +} + +void CameraControlHelper::handleUpdateTimer() +{ + emit updateInputs(); +} + +void CameraControlHelper::setEnabled(bool enabled) +{ + if (enabled) + m_timer.start(); + else + m_timer.stop(); + m_enabled = enabled; +} + +} +} diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.h new file mode 100644 index 00000000000..87ef1025ff7 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include + +namespace QmlDesigner { +namespace Internal { +class CameraControlHelper : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) + +public: + CameraControlHelper(); + + bool enabled(); + void setEnabled(bool enabled); + +public slots: + void handleUpdateTimer(); + +signals: + void updateInputs(); + void enabledChanged(bool enabled); + +private: + bool m_enabled = false; + QTimer m_timer; +}; + +} +} diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri new file mode 100644 index 00000000000..7b86f8bc820 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri @@ -0,0 +1,2 @@ +HEADERS += $$PWD/cameracontrolhelper.h +SOURCES += $$PWD/cameracontrolhelper.cpp diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 4754181a77d..d0931da3e04 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -58,12 +58,15 @@ #include "changeselectioncommand.h" #include "dummycontextobject.h" +#include "../editor3d/cameracontrolhelper.h" #include #include #include #include +#include +#include namespace QmlDesigner { @@ -74,8 +77,10 @@ static QVariant objectToVariant(QObject *object) static QObject *createEditView3D(QQmlEngine *engine) { - QQmlComponent component(engine, QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml")); + QmlDesigner::Internal::CameraControlHelper *helper = new QmlDesigner::Internal::CameraControlHelper(); + engine->rootContext()->setContextProperty("designStudioNativeCameraControlHelper", helper); + QQmlComponent component(engine, QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml")); QWindow *window = qobject_cast(component.create()); @@ -84,6 +89,7 @@ static QObject *createEditView3D(QQmlEngine *engine) surfaceFormat.setVersion(4, 1); surfaceFormat.setProfile(QSurfaceFormat::CoreProfile); window->setFormat(surfaceFormat); + helper->setParent(window); return window; } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppet.pri b/share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppet.pri index 39599385a86..d0bab57ca1a 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppet.pri +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/qml2puppet.pri @@ -5,6 +5,7 @@ CONFIG += c++11 DEFINES -= QT_CREATOR +include (editor3d/editor3d.pri) include (../instances/instances.pri) include (instances/instances.pri) include (../commands/commands.pri) diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt index 3db1cb34cd9..060ee7d2c9d 100644 --- a/src/tools/qml2puppet/CMakeLists.txt +++ b/src/tools/qml2puppet/CMakeLists.txt @@ -96,6 +96,12 @@ extend_qtc_executable(qml2puppet nodeinstanceserverinterface.cpp nodeinstanceserverinterface.h ) +extend_qtc_executable(qml2puppet + SOURCES_PREFIX "${SRCDIR}/qml2puppet/editor3d" + SOURCES + cameracontrolhelper.cpp cameracontrolhelper.h +} + extend_qtc_executable(qml2puppet SOURCES_PREFIX "${SRCDIR}/qml2puppet/instances" SOURCES diff --git a/src/tools/qml2puppet/qml2puppet.qbs b/src/tools/qml2puppet/qml2puppet.qbs index bc67e79a1a8..9dd7baa8bd9 100644 --- a/src/tools/qml2puppet/qml2puppet.qbs +++ b/src/tools/qml2puppet/qml2puppet.qbs @@ -193,6 +193,8 @@ QtcTool { "instances/qt5testnodeinstanceserver.h", "instances/servernodeinstance.cpp", "instances/servernodeinstance.h", + "editor3d/cameracontrolhelper.cpp", + "editor3d/cameracontrolhelper.h", "qml2puppetmain.cpp", ] } From f6d2315824b4800fd9fbf08b6d48283e90376d34 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Sat, 19 Oct 2019 15:16:44 +0200 Subject: [PATCH 14/45] WebAssembly: Add registered MinGW path to toolchain environment The build system of Qt for WebAssembly on Windows requires MinGW in the path. If a MinGW toolchain is registeded (e.g. via Sdk installer), append it to the path. Change-Id: I5c33cb5c4df636be99f815e307806efc07e18a11 Reviewed-by: hjk --- .../webassembly/webassemblytoolchain.cpp | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/plugins/webassembly/webassemblytoolchain.cpp b/src/plugins/webassembly/webassemblytoolchain.cpp index ec4726aa6f7..73c407c3617 100644 --- a/src/plugins/webassembly/webassemblytoolchain.cpp +++ b/src/plugins/webassembly/webassemblytoolchain.cpp @@ -91,7 +91,7 @@ static ProjectExplorer::Abi toolChainAbi() }; } -void WebAssemblyToolChain::addToEnvironment(Utils::Environment &env) const +static void addEmscriptenToEnvironment(Utils::Environment &env) { const CompilerConfiguration configuration = compilerConfiguration(); @@ -113,6 +113,25 @@ void WebAssemblyToolChain::addToEnvironment(Utils::Environment &env) const env.set("EMSCRIPTEN", configuration.emScripten.toUserOutput()); } +static void addRegisteredMinGWToEnvironment(Utils::Environment &env) +{ + using namespace ProjectExplorer; + const ToolChain *toolChain = ToolChainManager::toolChain([](const ToolChain *t){ + return t->typeId() == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID; + }); + if (toolChain) { + const QString mingwPath = toolChain->compilerCommand().parentDir().toUserOutput(); + env.appendOrSetPath(mingwPath); + } +} + +void WebAssemblyToolChain::addToEnvironment(Utils::Environment &env) const +{ + addEmscriptenToEnvironment(env); + if (Utils::HostOsInfo::isWindowsHost()) + addRegisteredMinGWToEnvironment(env); +} + WebAssemblyToolChain::WebAssemblyToolChain() : ClangToolChain(Constants::WEBASSEMBLY_TOOLCHAIN_TYPEID) { From 163faba8ff3eac7f0ca431b0e68dee0b7f30312a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 21 Oct 2019 10:44:55 +0200 Subject: [PATCH 15/45] Bump version -> 4.11 beta2 Change-Id: Iea7b87cc19309eb4c3a921fa29d1b40170aaacc8 Reviewed-by: Eike Ziller --- cmake/QtCreatorIDEBranding.cmake | 6 +++--- qbs/modules/qtc/qtc.qbs | 6 +++--- qtcreator_ide_branding.pri | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake index 30a062ecb87..172f2e6dcfa 100644 --- a/cmake/QtCreatorIDEBranding.cmake +++ b/cmake/QtCreatorIDEBranding.cmake @@ -1,9 +1,9 @@ #BINARY_ARTIFACTS_BRANCH = master #PROJECT_USER_FILE_EXTENSION = .user -set(IDE_VERSION "4.10.82") # The IDE version. -set(IDE_VERSION_COMPAT "4.10.82") # The IDE Compatibility version. -set(IDE_VERSION_DISPLAY "4.11.0-beta1") # The IDE display version. +set(IDE_VERSION "4.10.83") # The IDE version. +set(IDE_VERSION_COMPAT "4.10.83") # The IDE Compatibility version. +set(IDE_VERSION_DISPLAY "4.11.0-beta2") # The IDE display version. set(IDE_COPYRIGHT_YEAR "2019") # The IDE current copyright year. set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation. diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index 3269b43f78e..696ccf90c14 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -4,16 +4,16 @@ import qbs.FileInfo import "qtc.js" as HelperFunctions Module { - property string qtcreator_display_version: '4.11.0-beta1' + property string qtcreator_display_version: '4.11.0-beta2' property string ide_version_major: '4' property string ide_version_minor: '10' - property string ide_version_release: '82' + property string ide_version_release: '83' property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' + ide_version_release property string ide_compat_version_major: '4' property string ide_compat_version_minor: '10' - property string ide_compat_version_release: '82' + property string ide_compat_version_release: '83' property string qtcreator_compat_version: ide_compat_version_major + '.' + ide_compat_version_minor + '.' + ide_compat_version_release diff --git a/qtcreator_ide_branding.pri b/qtcreator_ide_branding.pri index f068254edcf..ddd9fd42c7b 100644 --- a/qtcreator_ide_branding.pri +++ b/qtcreator_ide_branding.pri @@ -1,8 +1,8 @@ -QTCREATOR_VERSION = 4.10.82 -QTCREATOR_COMPAT_VERSION = 4.10.82 -QTCREATOR_DISPLAY_VERSION = 4.11.0-beta1 +QTCREATOR_VERSION = 4.10.83 +QTCREATOR_COMPAT_VERSION = 4.10.83 +QTCREATOR_DISPLAY_VERSION = 4.11.0-beta2 QTCREATOR_COPYRIGHT_YEAR = 2019 -BINARY_ARTIFACTS_BRANCH = master +BINARY_ARTIFACTS_BRANCH = 4.11 IDE_DISPLAY_NAME = Qt Creator IDE_ID = qtcreator From 1646c266d672fcbb77121f1c34a919207bce8e8b Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 21 Oct 2019 10:47:55 +0200 Subject: [PATCH 16/45] qml2puppet: Fix CMake build Change-Id: If14e60e5a12526f68561bf9b54c5a181fb7b4534 Reviewed-by: Cristian Adam Reviewed-by: Alessandro Portale --- src/tools/qml2puppet/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt index 060ee7d2c9d..1ff67919318 100644 --- a/src/tools/qml2puppet/CMakeLists.txt +++ b/src/tools/qml2puppet/CMakeLists.txt @@ -100,7 +100,7 @@ extend_qtc_executable(qml2puppet SOURCES_PREFIX "${SRCDIR}/qml2puppet/editor3d" SOURCES cameracontrolhelper.cpp cameracontrolhelper.h -} +) extend_qtc_executable(qml2puppet SOURCES_PREFIX "${SRCDIR}/qml2puppet/instances" From 6fd29da2cb6b7325631163bad1fdc79f0f71de77 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 21 Oct 2019 09:43:21 +0200 Subject: [PATCH 17/45] Target setup page: Un-queue connection to kit manager If we have a project with two enabled targets and we remove both of the associated kits, one of the targets temporarily becomes the active one. If the activeTargetChanged() signal gets queued, then the receiver will be called with an invalid target pointer, as the target has been removed in the meantime. It is unclear why the signal was queued in the first place. Presumably the original reasoning is no longer applicable after various refactorings. This amends (and effectively reverts) commit c13b20f160. Task-number: QTCREATORBUG-23075 Change-Id: I3c63c763319734a4d52b3bb221919b20fd123dbe Reviewed-by: hjk Reviewed-by: Christian Stenger --- src/plugins/projectexplorer/targetsettingspanel.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plugins/projectexplorer/targetsettingspanel.cpp b/src/plugins/projectexplorer/targetsettingspanel.cpp index 3bb35bfe75d..e1345cb50ea 100644 --- a/src/plugins/projectexplorer/targetsettingspanel.cpp +++ b/src/plugins/projectexplorer/targetsettingspanel.cpp @@ -674,7 +674,7 @@ TargetGroupItem::TargetGroupItem(const QString &displayName, Project *project) QObject::connect(project, &Project::removedTarget, d.get(), &TargetGroupItemPrivate::handleTargetRemoved); QObject::connect(project, &Project::activeTargetChanged, - d.get(), &TargetGroupItemPrivate::handleTargetChanged, Qt::QueuedConnection); + d.get(), &TargetGroupItemPrivate::handleTargetChanged); } TargetGroupItem::~TargetGroupItem() = default; @@ -748,8 +748,10 @@ TargetItem *TargetGroupItem::currentTargetItem() const TargetItem *TargetGroupItem::targetItem(Target *target) const { - if (target) - return findFirstLevelChild([target](TargetItem *item) { return item->target() == target; }); + if (target) { + Id needle = target->id(); // Unconfigured project have no active target. + return findFirstLevelChild([needle](TargetItem *item) { return item->m_kitId == needle; }); + } return nullptr; } From cc67ad873643af29d64076c4d66ce41d7243c89a Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 30 Sep 2019 11:13:02 +0200 Subject: [PATCH 18/45] Squish: Adapt handling for project creation Some templates got an additional page for handling translations. Change-Id: I420e4f1bd8be5a30056220abd73b3f9da44d5047 Reviewed-by: Christian Stenger Reviewed-by: Robert Loehning --- tests/system/shared/project.py | 10 ++++++++++ .../suite_general/tst_create_proj_wizard/test.py | 2 ++ 2 files changed, 12 insertions(+) diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index 08398f14fab..193ef324af7 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -116,6 +116,11 @@ def __createProjectSetNameAndPath__(path, projectName = None, checks = True): clickButton(waitForObject(":Next_QPushButton")) return str(projectName) + +def __createProjectHandleTranslationSelection__(): + clickButton(":Next_QPushButton") + + def __handleBuildSystem__(buildSystem): combo = "{name='BuildSystem' type='QComboBox' visible='1'}" try: @@ -230,6 +235,7 @@ def createProject_Qt_GUI(path, projectName, checks = True, addToVersionControl = test.compare(findObject(":formFileLineEdit_Utils::FileNameValidatingLineEdit").text, ui_file) clickButton(waitForObject(":Next_QPushButton")) + __createProjectHandleTranslationSelection__() __selectQtVersionDesktop__(checks, available, True) expectedFiles = [] @@ -253,6 +259,7 @@ def createProject_Qt_Console(path, projectName, checks = True, buildSystem = Non available = __createProjectOrFileSelectType__(" Application", "Qt Console Application") __createProjectSetNameAndPath__(path, projectName, checks) __handleBuildSystem__(buildSystem) + __createProjectHandleTranslationSelection__() __selectQtVersionDesktop__(checks, available) expectedFiles = [] @@ -279,6 +286,7 @@ def createNewQtQuickApplication(workingDir, projectName=None, __handleBuildSystem__(buildSystem) requiredQt = __createProjectHandleQtQuickSelection__(minimumQtVersion) __modifyAvailableTargets__(available, requiredQt) + __createProjectHandleTranslationSelection__() checkedTargets = __chooseTargets__(targets, available) snooze(1) if len(checkedTargets): @@ -368,6 +376,7 @@ def createNewCPPLib(projectDir, projectName, className, target, isStatic): LibType.getStringForLib(libType)) __createProjectHandleModuleSelection__("Core") className = __createProjectHandleClassInformation__(className) + __createProjectHandleTranslationSelection__() __chooseTargets__(target, available) clickButton(waitForObject(":Next_QPushButton")) __createProjectHandleLastPage__() @@ -381,6 +390,7 @@ def createNewQtPlugin(projectDir, projectName, className, target, baseClass="QGe "window=':New_ProjectExplorer::JsonWizard'}"), LibType.getStringForLib(LibType.QT_PLUGIN)) className = __createProjectHandleClassInformation__(className, baseClass) + __createProjectHandleTranslationSelection__() __chooseTargets__(target, available) clickButton(waitForObject(":Next_QPushButton")) __createProjectHandleLastPage__() diff --git a/tests/system/suite_general/tst_create_proj_wizard/test.py b/tests/system/suite_general/tst_create_proj_wizard/test.py index 534317c3d14..69a69ace30a 100644 --- a/tests/system/suite_general/tst_create_proj_wizard/test.py +++ b/tests/system/suite_general/tst_create_proj_wizard/test.py @@ -132,6 +132,8 @@ def handleBuildSystemVerifyKits(category, template, kits, displayedPlatforms, clickButton(waitForObject(":Next_QPushButton")) if specialHandlingFunc: specialHandlingFunc(displayedPlatforms, *args) + if not ('Plain C' in template): + __createProjectHandleTranslationSelection__() verifyKitCheckboxes(kits, displayedPlatforms) safeClickButton("Cancel") if counter < len(availableBuildSystems) - 1: From 35fe01c6e9bad202d9f2f433ca9ac558617199e2 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Fri, 18 Oct 2019 17:30:02 +0200 Subject: [PATCH 19/45] Squish: Update expected label text Change-Id: If17465530ca06f5d4d1ae06db1f8175ecdd92fd1 Reviewed-by: Christian Stenger --- tests/system/objects.map | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/objects.map b/tests/system/objects.map index 1d4fab657ef..27e82838e7e 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -98,7 +98,7 @@ :New_Core::Internal::NewDialog {name='Core__Internal__NewDialog' type='Core::Internal::NewDialog' visible='1' windowTitle?='New*'} :New_ProjectExplorer::JsonWizard {type='ProjectExplorer::JsonWizard' unnamed='1' visible='1'} :Next_QPushButton {text~='(Next.*|Continue)' type='QPushButton' visible='1'} -:No valid kits found._QLabel {text?='*No valid kits found.*' type='QLabel' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} +:No valid kits found._QLabel {text?='*No suitable kits found.*' type='QLabel' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :OpenDocuments_Widget {type='Core::Internal::OpenEditorsWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='Open Documents'} :Options.Cancel_QPushButton {text='Cancel' type='QPushButton' unnamed='1' visible='1' window=':Options_Core::Internal::SettingsDialog'} :Options.OK_QPushButton {text='OK' type='QPushButton' unnamed='1' visible='1' window=':Options_Core::Internal::SettingsDialog'} From b64f5a3fe5c7ecfd8ae985266098d0dbd1bac97a Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 21 Oct 2019 09:38:21 +0200 Subject: [PATCH 20/45] QmlDesigner: Position point light at camera Since the camera is movable the light should follow the camera. Change-Id: Ia9925f98288ff19a81086e52f3a31fe72b32ee99 Reviewed-by: Miikka Heikkinen --- share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index 519dc83569a..d3b693788a3 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -61,8 +61,10 @@ Window { } Light { - id: directionalLight + id: pointLight visible: showEditLight + position: editCamera.position + lightType: Light.Point } Camera { @@ -74,7 +76,7 @@ Window { } Component.onCompleted: { - directionalLight.setParentItem(editView.scene); + pointLight.setParentItem(editView.scene); editCamera.setParentItem(editView.scene); } } From fab360d83d4c9e0ca77ecfb44fccc974f279399c Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 18 Oct 2019 16:05:43 +0200 Subject: [PATCH 21/45] QmlDesigner: Start and end transaction for spin box dragging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using the spin box focus is not safe enough, but using transactions on the dragging works nicely. Change-Id: Iffc15b4ca44cb473b257f58e548ff86ebd56bbf2 Reviewed-by: Henning Gründl Reviewed-by: Thomas Hartmann --- .../imports/HelperWidgets/SpinBox.qml | 28 +++++++++++++++---- .../propertyeditortransaction.cpp | 7 ++++- .../propertyeditortransaction.h | 2 ++ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml index 11c358af2af..bf42b964152 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml @@ -46,11 +46,30 @@ Item { width: 96 implicitHeight: spinBox.height + onFocusChanged: transaction.end(); + StudioControls.RealSpinBox { id: spinBox - onDragStarted: hideCursor(); - onDragEnded: restoreCursor(); + onDragStarted: { + hideCursor(); + transaction.start(); + } + + onDragEnded: { + restoreCursor(); + transaction.end(); + } + + onRealValueModified: { + if (transaction.active()) + commitValue(); + } + + function commitValue() { + if (spinBox.backendValue.value !== spinBox.realValue) + spinBox.backendValue.value = spinBox.realValue; + } property variant backendValue property bool hasSlider: wrapper.sliderIndicatorVisible @@ -77,9 +96,6 @@ Item { labelColor: spinBox.edit ? StudioTheme.Values.themeTextColor : colorLogic.textColor - onCompressedRealValueModified: { - if (spinBox.backendValue.value !== spinBox.realValue) - spinBox.backendValue.value = spinBox.realValue; - } + onCompressedRealValueModified: commitValue() } } diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditortransaction.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditortransaction.cpp index 3e4a20a1b3e..feafd9b1df5 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditortransaction.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditortransaction.cpp @@ -41,7 +41,7 @@ void PropertyEditorTransaction::start() if (m_rewriterTransaction.isValid()) m_rewriterTransaction.commit(); m_rewriterTransaction = m_propertyEditor->beginRewriterTransaction(QByteArrayLiteral("PropertyEditorTransaction::start")); - m_timerId = startTimer(4000); + m_timerId = startTimer(10000); } void PropertyEditorTransaction::end() @@ -52,6 +52,11 @@ void PropertyEditorTransaction::end() } } +bool PropertyEditorTransaction::active() const +{ + return m_rewriterTransaction.isValid(); +} + void PropertyEditorTransaction::timerEvent(QTimerEvent *timerEvent) { if (timerEvent->timerId() != m_timerId) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditortransaction.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditortransaction.h index f3f87e47211..02590bf62e0 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditortransaction.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditortransaction.h @@ -38,6 +38,8 @@ public: Q_INVOKABLE void start(); Q_INVOKABLE void end(); + Q_INVOKABLE bool active() const; + protected: void timerEvent(QTimerEvent *event) override; From b128d498b2da55a9f87cd2eabb802acc0c48e7d4 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Fri, 11 Oct 2019 13:15:11 +0200 Subject: [PATCH 22/45] CMake Buildsystem: Enable visibility settings for binaries This should not matter, but makes the add_qtc_executable targets match up with the PCH, so that they should build a bit faster. Change-Id: Ibecaaf7fd98d5b927d52e4956b1bea4a5775afba Reviewed-by: Cristian Adam Reviewed-by: Tobias Hunger --- cmake/QtCreatorAPI.cmake | 2 ++ src/shared/qtcreator_gui_pch.h | 13 ++----------- src/shared/qtcreator_pch.h | 13 +------------ 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake index f122ef1daf3..300b7cd50a9 100644 --- a/cmake/QtCreatorAPI.cmake +++ b/cmake/QtCreatorAPI.cmake @@ -838,6 +838,8 @@ function(add_qtc_executable name) INSTALL_RPATH "${_RPATH_BASE}/${_RELATIVE_LIB_PATH}" RUNTIME_OUTPUT_DIRECTORY "${_output_binary_dir}/${_DESTINATION}" QT_SKIP_TRANSLATION "${skip_translation}" + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON ${_arg_PROPERTIES} ) append_extra_translations("${name}" "${_arg_EXTRA_TRANSLATIONS}") diff --git a/src/shared/qtcreator_gui_pch.h b/src/shared/qtcreator_gui_pch.h index b25dbf67b70..9ac491898b9 100644 --- a/src/shared/qtcreator_gui_pch.h +++ b/src/shared/qtcreator_gui_pch.h @@ -32,16 +32,7 @@ #if defined __cplusplus -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include #endif diff --git a/src/shared/qtcreator_pch.h b/src/shared/qtcreator_pch.h index 4988f3d9392..8ff33bef080 100644 --- a/src/shared/qtcreator_pch.h +++ b/src/shared/qtcreator_pch.h @@ -37,18 +37,7 @@ # undef _POSIX_ #endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include From ac84f8a45717ce65f11be7e71190edd3425a85c8 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 17 Oct 2019 18:27:57 +0200 Subject: [PATCH 23/45] QmlDesigner: Implement Quick3DNodeInstance wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use Quick3DNodeInstance as a proxy class to wrap QQuick3DNode. The access to private API like QQuick3DNodePrivate::setIsHiddenInEditor() is restriced by such proxy classes. Change-Id: If5191c3b730359000cf983c3af206dcffa07be74 Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri Reviewed-by: Pasi Keränen Reviewed-by: Thomas Hartmann --- .../qml2puppet/instances/instances.pri | 7 ++ .../instances/nodeinstanceserver.cpp | 10 +-- .../instances/objectnodeinstance.cpp | 4 + .../qml2puppet/instances/objectnodeinstance.h | 2 + .../instances/quick3dnodeinstance.cpp | 83 +++++++++++++++++++ .../instances/quick3dnodeinstance.h | 57 +++++++++++++ .../instances/servernodeinstance.cpp | 8 ++ .../qml2puppet/instances/servernodeinstance.h | 2 + src/tools/qml2puppet/CMakeLists.txt | 8 ++ src/tools/qml2puppet/qml2puppet.qbs | 2 + 10 files changed, 177 insertions(+), 6 deletions(-) create mode 100644 share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp create mode 100644 share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri index 300f80d2b3f..50c0bd41bb9 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/instances.pri @@ -1,5 +1,10 @@ INCLUDEPATH += $$PWD/ +qtHaveModule(quick3d) { + QT *= quick3d-private + DEFINES *= QUICK3D_MODULE +} + HEADERS += $$PWD/qt5nodeinstanceserver.h HEADERS += $$PWD/qt5testnodeinstanceserver.h HEADERS += $$PWD/qt5informationnodeinstanceserver.h @@ -23,6 +28,7 @@ HEADERS += $$PWD/anchorchangesnodeinstance.h HEADERS += $$PWD/positionernodeinstance.h HEADERS += $$PWD/layoutnodeinstance.h HEADERS += $$PWD/qt3dpresentationnodeinstance.h +HEADERS += $$PWD/quick3dnodeinstance.h SOURCES += $$PWD/qt5nodeinstanceserver.cpp SOURCES += $$PWD/qt5testnodeinstanceserver.cpp @@ -47,3 +53,4 @@ SOURCES += $$PWD/anchorchangesnodeinstance.cpp SOURCES += $$PWD/positionernodeinstance.cpp SOURCES += $$PWD/layoutnodeinstance.cpp SOURCES += $$PWD/qt3dpresentationnodeinstance.cpp +SOURCES += $$PWD/quick3dnodeinstance.cpp diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index 356d173e09a..bd293488f19 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -985,12 +985,10 @@ void NodeInstanceServer::setInstanceAuxiliaryData(const PropertyValueContainer & } else if (auxiliaryContainer.name() == "invisible") { if (hasInstanceForId(auxiliaryContainer.instanceId())) { ServerNodeInstance instance = instanceForId(auxiliaryContainer.instanceId()); - if (instance.isSubclassOf("QQuick3DNode")) { - if (!auxiliaryContainer.value().isNull()) - instance.setPropertyVariant("visible", !auxiliaryContainer.value().toBool()); - else - instance.resetProperty("visible"); - } + if (!auxiliaryContainer.value().isNull()) + instance.setHideInEditor(auxiliaryContainer.value().toBool()); + else + instance.setHideInEditor(false); } } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp index 7fa0e316b6e..2f0244ddeba 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp @@ -392,6 +392,10 @@ PropertyNameList ObjectNodeInstance::ignoredProperties() const return PropertyNameList(); } +void ObjectNodeInstance::setHideInEditor(bool) +{ +} + QVariant ObjectNodeInstance::convertEnumToValue(const QVariant &value, const PropertyName &name) { Q_ASSERT(value.canConvert()); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h index 55114e872a6..8aa7ce4ad4d 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h @@ -193,6 +193,8 @@ public: virtual PropertyNameList ignoredProperties() const; + void virtual setHideInEditor(bool b); + protected: explicit ObjectNodeInstance(QObject *object); void doResetProperty(const PropertyName &propertyName); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp new file mode 100644 index 00000000000..472d560e099 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "quick3dnodeinstance.h" +#include "qt5nodeinstanceserver.h" + +#include + +#include +#include +#include +#include + +#include + +#ifdef QUICK3D_MODULE +#include +#include +#endif + +namespace QmlDesigner { +namespace Internal { + +Quick3DNodeInstance::Quick3DNodeInstance(QObject *node) + : ObjectNodeInstance(node) +{ +} + +Quick3DNodeInstance::~Quick3DNodeInstance() +{ +} + +Qt5NodeInstanceServer *Quick3DNodeInstance::qt5NodeInstanceServer() const +{ + return qobject_cast(nodeInstanceServer()); +} + +QQuick3DNode *Quick3DNodeInstance::quick3DNode() const +{ + return qobject_cast(object()); +} + +Quick3DNodeInstance::Pointer Quick3DNodeInstance::create(QObject *object) +{ + Pointer instance(new Quick3DNodeInstance(object)); + instance->populateResetHashes(); + return instance; +} + +void Quick3DNodeInstance::setHideInEditor(bool b) +{ +#ifdef QUICK3D_MODULE + QQuick3DNodePrivate *privateNode = QQuick3DNodePrivate::get(quick3DNode()); + if (privateNode) + privateNode->setIsHiddenInEditor(b); +#endif +} + +} // namespace Internal +} // namespace QmlDesigner + diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h new file mode 100644 index 00000000000..6bfc2a02a19 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include "objectnodeinstance.h" + +#include + +QT_FORWARD_DECLARE_CLASS(QQuick3DNode) + +namespace QmlDesigner { +namespace Internal { + +class Quick3DNodeInstance : public ObjectNodeInstance +{ +public: + using Pointer = QSharedPointer; + + ~Quick3DNodeInstance() override; + static Pointer create(QObject *objectToBeWrapped); + void setHideInEditor(bool b) override; + +protected: + explicit Quick3DNodeInstance(QObject *node); + +private: + Qt5NodeInstanceServer *qt5NodeInstanceServer() const; + QQuick3DNode *quick3DNode() const; +}; + +} // namespace Internal +} // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp index 87aea97d8de..376ca29524f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp @@ -39,6 +39,7 @@ #include "qt3dpresentationnodeinstance.h" #include "quickitemnodeinstance.h" +#include "quick3dnodeinstance.h" #include "nodeinstanceserver.h" #include "instancecontainer.h" @@ -170,6 +171,8 @@ Internal::ObjectNodeInstance::Pointer ServerNodeInstance::createInstance(QObject instance = Internal::LayoutNodeInstance::create(objectToBeWrapped); else if (isSubclassOf(objectToBeWrapped, "QQuickItem")) instance = Internal::QuickItemNodeInstance::create(objectToBeWrapped); + else if (isSubclassOf(objectToBeWrapped, "QQuick3DNode")) + instance = Internal::Quick3DNodeInstance::create(objectToBeWrapped); else if (isSubclassOf(objectToBeWrapped, "QQmlComponent")) instance = Internal::ComponentNodeInstance::create(objectToBeWrapped); else if (objectToBeWrapped->inherits("QQmlAnchorChanges")) @@ -312,6 +315,11 @@ void ServerNodeInstance::setPropertyBinding(const PropertyName &name, const QStr m_nodeInstance->setPropertyBinding(name, expression); } +void ServerNodeInstance::setHideInEditor(bool b) +{ + m_nodeInstance->setHideInEditor(b); +} + void ServerNodeInstance::resetProperty(const PropertyName &name) { m_nodeInstance->resetProperty(name); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h index 2bfc5147a72..7e72878dca4 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h @@ -172,6 +172,8 @@ private: // functions void setPropertyBinding(const PropertyName &name, const QString &expression); + void setHideInEditor(bool b); + void resetProperty(const PropertyName &name); void refreshProperty(const PropertyName &name); diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt index 1ff67919318..bbad0967613 100644 --- a/src/tools/qml2puppet/CMakeLists.txt +++ b/src/tools/qml2puppet/CMakeLists.txt @@ -87,6 +87,14 @@ extend_qtc_executable(qml2puppet nodeinstanceclientproxy.cpp nodeinstanceclientproxy.h ) +find_package(Qt5 COMPONENTS Quick3D QUIET) +extend_qtc_executable(qml2puppet + CONDITION TARGET Qt5::Quick3 + FEATURE_INFO "Qt Quick 3D" + DEPENDS Qt5::Quick3D + DEFINES QUICK3D_MODULE +) + extend_qtc_executable(qml2puppet SOURCES_PREFIX "${SRCDIR}/interfaces" SOURCES diff --git a/src/tools/qml2puppet/qml2puppet.qbs b/src/tools/qml2puppet/qml2puppet.qbs index 9dd7baa8bd9..995c29eac04 100644 --- a/src/tools/qml2puppet/qml2puppet.qbs +++ b/src/tools/qml2puppet/qml2puppet.qbs @@ -175,6 +175,8 @@ QtcTool { "instances/qmlpropertychangesnodeinstance.h", "instances/qmlstatenodeinstance.cpp", "instances/qmlstatenodeinstance.h", + "instances/quick3dnodeinstance.cpp", + "instances/quick3dnodeinstance.h", "instances/qmltransitionnodeinstance.cpp", "instances/qmltransitionnodeinstance.h", "instances/qt3dpresentationnodeinstance.cpp", From 5e225f85eb7c3e4493ce741d0bfad25d173b73ca Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 21 Oct 2019 09:00:55 +0200 Subject: [PATCH 24/45] QmlDesigner: Fix Coverity scan defects Change-Id: I07a61fe4498ae0b28baaa969f0decfa5689b4443 Reviewed-by: Eike Ziller Reviewed-by: Alessandro Portale --- .../qmldesigner/designercore/instances/puppetcreator.cpp | 8 ++++---- src/plugins/qmldesigner/documentmanager.cpp | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp index 12a55c25fe1..adf962c2cce 100644 --- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp +++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp @@ -464,14 +464,11 @@ QProcessEnvironment PuppetCreator::processEnvironment() const #ifndef QMLDESIGNER_TEST view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); view->emitCustomNotification("PuppetStatus", {}, {QVariant(m_qrcMapping)}); -#endif - - QStringList importPaths = m_model->importPaths(); QmlDesigner::Import import = QmlDesigner::Import::createLibraryImport("QtQuick3D", "1.0"); bool view3DEnabled = false; - if (view && m_model->hasImport(import, true, true)) { + if (m_model->hasImport(import, true, true)) { if (view->rootModelNode().hasAuxiliaryData("3d-view")) view3DEnabled = view->rootModelNode().auxiliaryData("3d-view").toBool(); else @@ -480,6 +477,9 @@ QProcessEnvironment PuppetCreator::processEnvironment() const if (view3DEnabled) environment.set("QMLDESIGNER_QUICK3D_MODE", "true"); +#endif + + QStringList importPaths = m_model->importPaths(); /* For the fallback puppet we have to remove the path to the original qtbase plugins to avoid conflics */ if (m_availablePuppetType == FallbackPuppet) diff --git a/src/plugins/qmldesigner/documentmanager.cpp b/src/plugins/qmldesigner/documentmanager.cpp index 45fd4957590..2cae7208c5d 100644 --- a/src/plugins/qmldesigner/documentmanager.cpp +++ b/src/plugins/qmldesigner/documentmanager.cpp @@ -424,7 +424,8 @@ void DocumentManager::findPathToIsoProFile(bool *iconResourceFileAlreadyExists, if (!iconQrcFileNode) { // The QRC file that we want doesn't exist or is not listed under RESOURCES in the .pro. - *resourceFilePath = project->projectDirectory().toString() + "/" + isoIconsQrcFile; + if (project) + *resourceFilePath = project->projectDirectory().toString() + "/" + isoIconsQrcFile; // We assume that the .pro containing the QML file is an acceptable place to add the .qrc file. ProjectExplorer::ProjectNode *projectNode = ProjectExplorer::ProjectTree::nodeForFile(qmlFileName)->parentProjectNode(); From 79aedfbb7abbede5f1c55dfc5f8aeb054e1d7908 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 21 Oct 2019 13:50:51 +0200 Subject: [PATCH 25/45] McuSupport: Fix warning about unused variable Change-Id: If0905e2937b02806cf000d9f9d270d87f0a0a370 Reviewed-by: Alessandro Portale --- src/plugins/mcusupport/mcusupportoptionspage.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index f83e015b8e4..64d45bf7b08 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -722,9 +722,8 @@ void McuSupportOptionsPage::apply() using namespace ProjectExplorer; - for (auto board : validBoards) { - Kit *kit = boardKit(board, m_options->toolchainPackage->path()); - } + for (auto board : validBoards) + boardKit(board, m_options->toolchainPackage->path()); } void McuSupportOptionsPage::finish() From 33e24ac83ef5b51540071870ec4ff7fe00bc111a Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 21 Oct 2019 13:51:24 +0200 Subject: [PATCH 26/45] QmlDesigner: Fix warnings about unused variables Change-Id: I659cc1246632b91ace8d025e5d02cf5c20f8d1b9 Reviewed-by: Thomas Hartmann --- .../components/itemlibrary/itemlibraryassetimporter.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index c67b527abb5..ac40e87c791 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -127,6 +127,8 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles, #else Q_UNUSED(inputFiles) Q_UNUSED(importPath) + Q_UNUSED(options) + Q_UNUSED(extToImportOptionsMap) addError(tr("Importing 3D assets requires building against Qt Quick 3D module.")); notifyFinished(); #endif @@ -173,6 +175,7 @@ bool ItemLibraryAssetImporter::isQuick3DAsset(const QString &fileName) const } return quick3DExt.contains(QFileInfo(fileName).suffix()); #else + Q_UNUSED(fileName) return false; #endif } @@ -182,6 +185,7 @@ QVariantMap ItemLibraryAssetImporter::supportedOptions(const QString &modelFile) #ifdef IMPORT_QUICK3D_ASSETS return m_quick3DAssetImporter->getOptionsForFile(modelFile); #else + Q_UNUSED(modelFile) return {}; #endif } From b4bc204a7d3b36f0d40e368ceb9f359622a41e2c Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 21 Oct 2019 12:18:45 +0200 Subject: [PATCH 27/45] CtfVisualizer: Avoid compile warning Column::COUNT should not show up as actual column, but the compiler doesn't know. Change-Id: I68eea5c73a95bd45378f88c505f0cefed62ce8ab Reviewed-by: Christian Kandeler --- src/plugins/ctfvisualizer/ctfstatisticsmodel.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/ctfvisualizer/ctfstatisticsmodel.cpp b/src/plugins/ctfvisualizer/ctfstatisticsmodel.cpp index bdf88eaf5c2..1f1320c4038 100644 --- a/src/plugins/ctfvisualizer/ctfstatisticsmodel.cpp +++ b/src/plugins/ctfvisualizer/ctfstatisticsmodel.cpp @@ -93,6 +93,9 @@ QVariant CtfStatisticsModel::data(const QModelIndex &index, int role) const case Column::AvgDuration: case Column::MaxDuration: return Qt::AlignRight; + default: + Q_UNREACHABLE(); + return QVariant(); } case SortRole: switch (index.column()) { From 49379bfda7324c6ec0222c0f0c5ee6e40d98b222 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 18 Oct 2019 16:55:08 +0200 Subject: [PATCH 28/45] QmlDesigner: Add and dispatch ValuesModifiedCommand We already have valuesChanged() which notifies that a property of the C++ QObject has changed. This patch adds valuesModified() which notifies that values in the data model should be changed. While valuesChanged() only changes the so called instance value, valuesModified() does change the internal data model and as a result the QML code. This is done in NodeInstanceView::valuesModified(). This enabled the qml2puppet to acutally change values, like a property editor would. Change-Id: I2493b9e626c4b194e332a7a096de3dbf2195514a Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri Reviewed-by: Alessandro Portale --- .../commands/valueschangedcommand.cpp | 2 +- .../qmlpuppet/commands/valueschangedcommand.h | 22 ++++++++++++++++++- .../instances/nodeinstanceclientproxy.cpp | 10 ++++++++- .../instances/nodeinstanceclientproxy.h | 1 + .../interfaces/nodeinstanceclientinterface.h | 2 ++ .../nodeinstanceserverinterface.cpp | 3 +++ .../designercore/include/nodeinstanceview.h | 1 + .../instances/nodeinstanceserverproxy.cpp | 9 +++++--- .../instances/nodeinstanceview.cpp | 14 ++++++++++++ 9 files changed, 58 insertions(+), 6 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.cpp b/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.cpp index 73c8138a436..c5468bc999b 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.cpp +++ b/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.cpp @@ -50,7 +50,7 @@ ValuesChangedCommand::ValuesChangedCommand(const QVector { } -QVector ValuesChangedCommand::valueChanges() const +const QVector ValuesChangedCommand::valueChanges() const { return m_valueChangeVector; } diff --git a/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.h b/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.h index 96050aee7fe..bf7fe1e43d4 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.h @@ -42,7 +42,7 @@ public: ValuesChangedCommand(); explicit ValuesChangedCommand(const QVector &valueChangeVector); - QVector valueChanges() const; + const QVector valueChanges() const; quint32 keyNumber() const; static void removeSharedMemorys(const QVector &keyNumberVector); @@ -59,6 +59,26 @@ QDataStream &operator>>(QDataStream &in, ValuesChangedCommand &command); bool operator ==(const ValuesChangedCommand &first, const ValuesChangedCommand &second); QDebug operator <<(QDebug debug, const ValuesChangedCommand &instance); + +/* ValuesChangedCommand is used to notify that the values of a specific instatiated + * QObject changed. + * The ValuesModifiedCommand is used to notify that a user changed a QML property and + * that this property should be changed in the data model. + */ + +class ValuesModifiedCommand : public ValuesChangedCommand +{ +public: + ValuesModifiedCommand() + {} + explicit ValuesModifiedCommand(const QVector &valueChangeVector) + : ValuesChangedCommand(valueChangeVector) + {} + +}; + } // namespace QmlDesigner + +Q_DECLARE_METATYPE(QmlDesigner::ValuesModifiedCommand) Q_DECLARE_METATYPE(QmlDesigner::ValuesChangedCommand) diff --git a/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp b/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp index a4b9324699e..3e57baffd0d 100644 --- a/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp +++ b/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.cpp @@ -130,6 +130,7 @@ bool compareCommands(const QVariant &command, const QVariant &controlCommand) { static const int informationChangedCommandType = QMetaType::type("InformationChangedCommand"); static const int valuesChangedCommandType = QMetaType::type("ValuesChangedCommand"); + static const int valuesModifiedCommandType = QMetaType::type("ValuesModifiedCommand"); static const int pixmapChangedCommandType = QMetaType::type("PixmapChangedCommand"); static const int childrenChangedCommandType = QMetaType::type("ChildrenChangedCommand"); static const int statePreviewImageChangedCommandType = QMetaType::type("StatePreviewImageChangedCommand"); @@ -144,7 +145,9 @@ bool compareCommands(const QVariant &command, const QVariant &controlCommand) return command.value() == controlCommand.value(); else if (command.userType() == valuesChangedCommandType) return command.value() == controlCommand.value(); - else if (command.userType() == pixmapChangedCommandType) + else if (command.userType() == valuesModifiedCommandType) + return command.value() == controlCommand.value(); + else if (command.userType() == pixmapChangedCommandType) return command.value() == controlCommand.value(); else if (command.userType() == childrenChangedCommandType) return command.value() == controlCommand.value(); @@ -202,6 +205,11 @@ void NodeInstanceClientProxy::valuesChanged(const ValuesChangedCommand &command) writeCommand(QVariant::fromValue(command)); } +void NodeInstanceClientProxy::valuesModified(const ValuesModifiedCommand &command) +{ + writeCommand(QVariant::fromValue(command)); +} + void NodeInstanceClientProxy::pixmapChanged(const PixmapChangedCommand &command) { writeCommand(QVariant::fromValue(command)); diff --git a/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.h b/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.h index 8590a48a957..edf290f38a0 100644 --- a/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.h +++ b/share/qtcreator/qml/qmlpuppet/instances/nodeinstanceclientproxy.h @@ -67,6 +67,7 @@ public: void informationChanged(const InformationChangedCommand &command) override; void valuesChanged(const ValuesChangedCommand &command) override; + void valuesModified(const ValuesModifiedCommand &command) override; void pixmapChanged(const PixmapChangedCommand &command) override; void childrenChanged(const ChildrenChangedCommand &command) override; void statePreviewImagesChanged(const StatePreviewImageChangedCommand &command) override; diff --git a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceclientinterface.h b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceclientinterface.h index 1f49f277f51..0b5a5ca334b 100644 --- a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceclientinterface.h +++ b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceclientinterface.h @@ -30,6 +30,7 @@ namespace QmlDesigner { class ValuesChangedCommand; +class ValuesModifiedCommand; class PixmapChangedCommand; class InformationChangedCommand; class ChildrenChangedCommand; @@ -46,6 +47,7 @@ class NodeInstanceClientInterface public: virtual void informationChanged(const InformationChangedCommand &command) = 0; virtual void valuesChanged(const ValuesChangedCommand &command) = 0; + virtual void valuesModified(const ValuesModifiedCommand &command) = 0; virtual void pixmapChanged(const PixmapChangedCommand &command) = 0; virtual void childrenChanged(const ChildrenChangedCommand &command) = 0; virtual void statePreviewImagesChanged(const StatePreviewImageChangedCommand &command) = 0; diff --git a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp index 90907b50929..d2b7cb26207 100644 --- a/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp +++ b/share/qtcreator/qml/qmlpuppet/interfaces/nodeinstanceserverinterface.cpp @@ -125,6 +125,9 @@ void NodeInstanceServerInterface::registerCommands() qRegisterMetaType("ValuesChangedCommand"); qRegisterMetaTypeStreamOperators("ValuesChangedCommand"); + qRegisterMetaType("ValuesModifiedCommand"); + qRegisterMetaTypeStreamOperators("ValuesModifiedCommand"); + qRegisterMetaType("PixmapChangedCommand"); qRegisterMetaTypeStreamOperators("PixmapChangedCommand"); diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index 258fc9aa2d0..1e1032900bf 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -120,6 +120,7 @@ public: void updatePosition(const QList& propertyList); void valuesChanged(const ValuesChangedCommand &command) override; + void valuesModified(const ValuesModifiedCommand &command) override; void pixmapChanged(const PixmapChangedCommand &command) override; void informationChanged(const InformationChangedCommand &command) override; void childrenChanged(const ChildrenChangedCommand &command) override; diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp index c5b98bf3258..3d57b3a16a7 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp @@ -271,6 +271,7 @@ void NodeInstanceServerProxy::dispatchCommand(const QVariant &command, PuppetStr { static const int informationChangedCommandType = QMetaType::type("InformationChangedCommand"); static const int valuesChangedCommandType = QMetaType::type("ValuesChangedCommand"); + static const int valuesModifiedCommandType = QMetaType::type("ValuesModifiedCommand"); static const int pixmapChangedCommandType = QMetaType::type("PixmapChangedCommand"); static const int childrenChangedCommandType = QMetaType::type("ChildrenChangedCommand"); static const int statePreviewImageChangedCommandType = QMetaType::type("StatePreviewImageChangedCommand"); @@ -285,11 +286,13 @@ void NodeInstanceServerProxy::dispatchCommand(const QVariant &command, PuppetStr return; qCInfo(instanceViewBenchmark) << "dispatching command" << command.userType() << command.typeName(); - if (command.userType() == informationChangedCommandType) { + if (command.userType() == informationChangedCommandType) { nodeInstanceClient()->informationChanged(command.value()); - } else if (command.userType() == valuesChangedCommandType) { + } else if (command.userType() == valuesChangedCommandType) { nodeInstanceClient()->valuesChanged(command.value()); - } else if (command.userType() == pixmapChangedCommandType) { + } else if (command.userType() == valuesModifiedCommandType) { + nodeInstanceClient()->valuesModified(command.value()); + } else if (command.userType() == pixmapChangedCommandType) { nodeInstanceClient()->pixmapChanged(command.value()); } else if (command.userType() == childrenChangedCommandType) { nodeInstanceClient()->childrenChanged(command.value()); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 5d44e5069c4..7200231267a 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -1190,6 +1190,20 @@ void NodeInstanceView::valuesChanged(const ValuesChangedCommand &command) emitInstancePropertyChange(valuePropertyChangeList); } +void NodeInstanceView::valuesModified(const ValuesModifiedCommand &command) +{ + if (!model()) + return; + + for (const PropertyValueContainer &container : command.valueChanges()) { + if (hasInstanceForId(container.instanceId())) { + NodeInstance instance = instanceForId(container.instanceId()); + if (instance.isValid()) + instance.modelNode().variantProperty(container.name()).setValue(container.value()); + } + } +} + void NodeInstanceView::pixmapChanged(const PixmapChangedCommand &command) { if (!model()) From 091f0f1a042d31afcd3d18ec89c5fc743de1ac6f Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 21 Oct 2019 14:54:54 +0200 Subject: [PATCH 29/45] QmlDesigner: Fix compile Amends ac84f8a45717ce65f11be7e71190edd3425a85c8. Change-Id: Iccca5a31dd852bc95c9095a2c8b1c6f1f5eab8d8 Reviewed-by: Thomas Hartmann --- .../qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp index 472d560e099..29c3ab3f299 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp @@ -59,7 +59,11 @@ Qt5NodeInstanceServer *Quick3DNodeInstance::qt5NodeInstanceServer() const QQuick3DNode *Quick3DNodeInstance::quick3DNode() const { +#ifdef QUICK3D_MODULE return qobject_cast(object()); +#else + return nullptr; +#endif } Quick3DNodeInstance::Pointer Quick3DNodeInstance::create(QObject *object) From b3b813c13ce20e62f7fbf11ddb6c63d1637455eb Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 21 Oct 2019 15:09:13 +0200 Subject: [PATCH 30/45] QmlDesigner: Fix cmake build Amends ac84f8a45717ce65f11be7e71190edd3425a85c8. Change-Id: I0bac2e5ed5328396bbe75c2b7013d81afdcc1bd3 Reviewed-by: Thomas Hartmann --- src/tools/qml2puppet/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt index bbad0967613..105b0a63f0b 100644 --- a/src/tools/qml2puppet/CMakeLists.txt +++ b/src/tools/qml2puppet/CMakeLists.txt @@ -134,6 +134,7 @@ extend_qtc_executable(qml2puppet qt5previewnodeinstanceserver.cpp qt5previewnodeinstanceserver.h qt5rendernodeinstanceserver.cpp qt5rendernodeinstanceserver.h qt5testnodeinstanceserver.cpp qt5testnodeinstanceserver.h + quick3dnodeinstance.cpp quick3dnodeinstance.h quickitemnodeinstance.cpp quickitemnodeinstance.h servernodeinstance.cpp servernodeinstance.h ) From 78e5a8a80a76d80f380336f80e94c218b5ab937c Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 21 Oct 2019 16:29:28 +0200 Subject: [PATCH 31/45] Fix crash in QtVersionManager Introduced in 9c2568b8e8d4414732fad03c2e805edc19fc40f5 Range-based for loops that modify the original container must work on a copy. Change-Id: Ib917014ab259c20b282cdc85e7ca6583f7844de5 Reviewed-by: Jarek Kobus Reviewed-by: Orgad Shaneh --- src/plugins/qtsupport/qtversionmanager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index d3fc9904281..09c4ef6f6c2 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -293,7 +293,8 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) } // First try to find a existing Qt version to update bool restored = false; - for (BaseQtVersion *v : qAsConst(m_versions)) { + const VersionMap versionsCopy = m_versions; // m_versions is modified in loop + for (BaseQtVersion *v : versionsCopy) { if (v->autodetectionSource() == autoDetectionSource) { id = v->uniqueId(); if (debug) @@ -339,7 +340,8 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) qDebug() << ""; } } - for (BaseQtVersion *qtVersion : qAsConst(m_versions)) { + const VersionMap versionsCopy = m_versions; // m_versions is modified in loop + for (BaseQtVersion *qtVersion : versionsCopy) { if (qtVersion->autodetectionSource().startsWith("SDK.")) { if (!sdkVersions.contains(qtVersion->autodetectionSource())) { if (debug) From 8ee22dd597ea67886f2fd605be3a4c17f551c5ae Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Mon, 21 Oct 2019 15:06:28 +0200 Subject: [PATCH 32/45] CMakeProjectManager: Fix clang code model when CMake PCHs are used CMake gives the path to the cmake_pch.h[xx] file as relative path to build directory. Making it absolute fixes the code model. Fixes: QTCREATORBUG-22888 Change-Id: I2fdc080be779f22b737788be2074254290994aaa Reviewed-by: Nikolai Kosjar --- src/libs/utils/fileutils.cpp | 6 +++++ src/libs/utils/fileutils.h | 1 + .../fileapidataextractor.cpp | 27 +++++++++++++------ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 8608756627d..3e8e2ac3bca 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -925,6 +925,12 @@ bool FilePath::isChildOf(const QDir &dir) const return isChildOf(FilePath::fromString(dir.absolutePath())); } +/// \returns whether FilePath startsWith \a s +bool FilePath::startsWith(const QString &s) const +{ + return m_data.startsWith(s, HostOsInfo::fileNameCaseSensitivity()); +} + /// \returns whether FilePath endsWith \a s bool FilePath::endsWith(const QString &s) const { diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index 2026ad1068a..4d1243cfdf7 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -97,6 +97,7 @@ public: bool isChildOf(const FilePath &s) const; bool isChildOf(const QDir &dir) const; + bool startsWith(const QString &s) const; bool endsWith(const QString &s) const; bool isLocal() const; diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index 53d8a126be6..81316f033bf 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -271,13 +271,15 @@ static QStringList splitFragments(const QStringList &fragments) } RawProjectParts generateRawProjectParts(const PreprocessedData &input, - const FilePath &sourceDirectory) + const FilePath &sourceDirectory, + const FilePath &buildDirectory) { RawProjectParts rpps; int counter = 0; for (const TargetDetails &t : input.targetDetails) { QDir sourceDir(sourceDirectory.toString()); + QDir buildDir(buildDirectory.toString()); bool needPostfix = t.compileGroups.size() > 1; int count = 1; @@ -321,16 +323,25 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input, cxxProjectFlags.commandLineFlags = cProjectFlags.commandLineFlags; rpp.setFlagsForCxx(cxxProjectFlags); - const QString precompiled_header - = findOrDefault(t.sources, [&ending](const SourceInfo &si) { - return si.path.endsWith(ending); - }).path; + FilePath precompiled_header + = FilePath::fromString(findOrDefault(t.sources, [&ending](const SourceInfo &si) { + return si.path.endsWith(ending); + }).path); rpp.setFiles(transform(ci.sources, [&t, &sourceDir](const int si) { return sourceDir.absoluteFilePath(t.sources[static_cast(si)].path); })); - if (!precompiled_header.isEmpty()) - rpp.setPreCompiledHeaders({precompiled_header}); + if (!precompiled_header.isEmpty()) { + if (precompiled_header.toFileInfo().isRelative()) { + const FilePath parentDir = FilePath::fromString(buildDir.absolutePath()); + const QString dirName = buildDir.dirName(); + if (precompiled_header.startsWith(dirName)) + precompiled_header = FilePath::fromString( + precompiled_header.toString().mid(dirName.length() + 1)); + precompiled_header = parentDir.pathAppended(precompiled_header.toString()); + } + rpp.setPreCompiledHeaders({precompiled_header.toString()}); + } const bool isExecutable = t.type == "EXECUTABLE"; rpp.setBuildTargetType(isExecutable ? ProjectExplorer::BuildTargetType::Executable @@ -602,7 +613,7 @@ FileApiQtcData extractData(FileApiData &input, result.buildTargets = generateBuildTargets(data, sourceDirectory, buildDirectory); result.cmakeFiles = std::move(data.cmakeFiles); - result.projectParts = generateRawProjectParts(data, sourceDirectory); + result.projectParts = generateRawProjectParts(data, sourceDirectory, buildDirectory); auto pair = generateRootProjectNode(data, sourceDirectory, buildDirectory); result.rootProjectNode = std::move(pair.first); From 734b6a5fdddbeb1090c316ee6acd291f54c10811 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 21 Oct 2019 21:54:57 +0300 Subject: [PATCH 33/45] QtSupport: Use QLoggingCategory for Qt version manager Change-Id: I27b98ff853d7b5d437cab0df61243146220dadc8 Reviewed-by: Christian Kandeler --- src/plugins/qtsupport/qtversionmanager.cpp | 58 ++++++++++------------ 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index 09c4ef6f6c2..6f888e5401b 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -45,13 +45,13 @@ #include #include -#include #include #include +#include #include #include -#include #include +#include #include using namespace Utils; @@ -74,7 +74,7 @@ static FileSystemWatcher *m_configFileWatcher = nullptr; static QTimer *m_fileWatcherTimer = nullptr; static PersistentSettingsWriter *m_writer = nullptr; -enum { debug = 0 }; +static Q_LOGGING_CATEGORY(log, "qtc.qt.versions", QtWarningMsg); static FilePath globalSettingsFileName() { @@ -253,14 +253,14 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) if (reader.load(path)) data = reader.restoreValues(); - if (debug) { - qDebug()<< "======= Existing Qt versions ======="; + if (log().isDebugEnabled()) { + qCDebug(log) << "======= Existing Qt versions ======="; for (BaseQtVersion *version : qAsConst(m_versions)) { - qDebug() << version->qmakeCommand().toString() << "id:"<uniqueId(); - qDebug() << " autodetection source:"<< version->autodetectionSource(); - qDebug() << ""; + qCDebug(log) << version->qmakeCommand().toString() << "id:"<uniqueId(); + qCDebug(log) << " autodetection source:"<< version->autodetectionSource(); + qCDebug(log) << ""; } - qDebug()<< "======= Adding sdk versions ======="; + qCDebug(log)<< "======= Adding sdk versions ======="; } QStringList sdkVersions; @@ -287,8 +287,7 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) factory = f; } if (!factory) { - if (debug) - qDebug("Warning: Unable to find factory for type '%s'", qPrintable(type)); + qCDebug(log, "Warning: Unable to find factory for type '%s'", qPrintable(type)); continue; } // First try to find a existing Qt version to update @@ -297,8 +296,7 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) for (BaseQtVersion *v : versionsCopy) { if (v->autodetectionSource() == autoDetectionSource) { id = v->uniqueId(); - if (debug) - qDebug() << " Qt version found with same autodetection source" << autoDetectionSource << " => Migrating id:" << id; + qCDebug(log) << " Qt version found with same autodetection source" << autoDetectionSource << " => Migrating id:" << id; m_versions.remove(id); qtversionMap[Constants::QTVERSIONID] = id; qtversionMap[Constants::QTVERSIONNAME] = v->unexpandedDisplayName(); @@ -317,8 +315,7 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) } // Create a new qtversion if (!restored) { // didn't replace any existing versions - if (debug) - qDebug() << " No Qt version found matching" << autoDetectionSource << " => Creating new version"; + qCDebug(log) << " No Qt version found matching" << autoDetectionSource << " => Creating new version"; if (BaseQtVersion *qtv = factory->restore(type, qtversionMap)) { Q_ASSERT(qtv->isAutodetected()); m_versions.insert(qtv->uniqueId(), qtv); @@ -326,38 +323,37 @@ void QtVersionManager::updateFromInstaller(bool emitSignal) restored = true; } } - if (!restored) - if (debug) - qDebug("Warning: Unable to update qtversion '%s' from sdk installer.", - qPrintable(autoDetectionSource)); + if (!restored) { + qCDebug(log, "Warning: Unable to update qtversion '%s' from sdk installer.", + qPrintable(autoDetectionSource)); + } } - if (debug) { - qDebug() << "======= Before removing outdated sdk versions ======="; + if (log().isDebugEnabled()) { + qCDebug(log) << "======= Before removing outdated sdk versions ======="; for (BaseQtVersion *version : qAsConst(m_versions)) { - qDebug() << version->qmakeCommand().toString() << "id:"<uniqueId(); - qDebug() << " autodetection source:"<< version->autodetectionSource(); - qDebug() << ""; + qCDebug(log) << version->qmakeCommand().toString() << "id:"<uniqueId(); + qCDebug(log) << " autodetection source:"<< version->autodetectionSource(); + qCDebug(log) << ""; } } const VersionMap versionsCopy = m_versions; // m_versions is modified in loop for (BaseQtVersion *qtVersion : versionsCopy) { if (qtVersion->autodetectionSource().startsWith("SDK.")) { if (!sdkVersions.contains(qtVersion->autodetectionSource())) { - if (debug) - qDebug() << " removing version"<autodetectionSource(); + qCDebug(log) << " removing version"<autodetectionSource(); m_versions.remove(qtVersion->uniqueId()); removed << qtVersion->uniqueId(); } } } - if (debug) { - qDebug()<< "======= End result ======="; + if (log().isDebugEnabled()) { + qCDebug(log)<< "======= End result ======="; for (BaseQtVersion *version : qAsConst(m_versions)) { - qDebug() << version->qmakeCommand().toString() << "id:" << version->uniqueId(); - qDebug() << " autodetection source:"<< version->autodetectionSource(); - qDebug() << ""; + qCDebug(log) << version->qmakeCommand().toString() << "id:" << version->uniqueId(); + qCDebug(log) << " autodetection source:"<< version->autodetectionSource(); + qCDebug(log) << ""; } } if (emitSignal) From 1a2bac60ed09f3d349b85afddf3504a7417722ac Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 22 Oct 2019 13:21:09 +0200 Subject: [PATCH 34/45] PerfProfilerFlameGraphModel: Make Payload::m_numSamples mutable This is necessary to make the class movable. Change-Id: I85decaa9f5c520aa3272a018ceca3aba642e1565 Reviewed-by: Eike Ziller --- src/plugins/perfprofiler/perfprofilerflamegraphmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/perfprofiler/perfprofilerflamegraphmodel.cpp b/src/plugins/perfprofiler/perfprofilerflamegraphmodel.cpp index d9f4cc30528..14716e4a29e 100644 --- a/src/plugins/perfprofiler/perfprofilerflamegraphmodel.cpp +++ b/src/plugins/perfprofiler/perfprofilerflamegraphmodel.cpp @@ -57,7 +57,7 @@ public: private: const PerfProfilerFlameGraphData *m_parent; PerfProfilerFlameGraphModel::Data *m_data; - const int m_numSamples; + int m_numSamples; }; typedef PerfResourceCounter ThreadResourceCounter; From 6e3de85b337eb8a6a107abcef932ee21deabc3d5 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 21 Oct 2019 09:22:36 +0200 Subject: [PATCH 35/45] Debugger: always hex encode the value of assignments in cdbext Fixes assigning negative values to locals Change-Id: Ief6e7f47e8e6f0a5d38458396164dfcd24e408a5 Fixes: QTCREATORBUG-17269 Reviewed-by: Christian Stenger --- .../qtcreatorcdbext/qtcreatorcdbextension.cpp | 9 +- src/libs/qtcreatorcdbext/stringutils.cpp | 11 ++ src/libs/qtcreatorcdbext/stringutils.h | 2 + src/libs/qtcreatorcdbext/symbolgroup.cpp | 7 +- src/libs/qtcreatorcdbext/symbolgroup.h | 1 - src/libs/qtcreatorcdbext/symbolgroupnode.cpp | 5 +- src/libs/qtcreatorcdbext/symbolgroupvalue.cpp | 151 ++++-------------- src/libs/qtcreatorcdbext/symbolgroupvalue.h | 5 +- src/plugins/debugger/cdb/cdbengine.cpp | 33 +--- 9 files changed, 53 insertions(+), 171 deletions(-) diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp index fad25230a34..6bbd71367c0 100644 --- a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp +++ b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp @@ -820,7 +820,7 @@ extern "C" HRESULT CALLBACK assign(CIDebugClient *client, PCSTR argsIn) std::string errorMessage; bool success = false; - AssignEncoding enc = AssignPlainValue; + bool encoded = false; int token = 0; do { StringList tokens = commandTokens(argsIn, &token); @@ -830,10 +830,7 @@ extern "C" HRESULT CALLBACK assign(CIDebugClient *client, PCSTR argsIn) } if (tokens.front() == "-h") { - enc = AssignHexEncoded; - tokens.pop_front(); - } else if (tokens.front() == "-u") { - enc = AssignHexEncodedUtf16; + encoded = true; tokens.pop_front(); } @@ -864,7 +861,7 @@ extern "C" HRESULT CALLBACK assign(CIDebugClient *client, PCSTR argsIn) SymbolGroup *symGroup = ExtensionContext::instance().symbolGroup(exc.symbols(), exc.threadId(), currentFrame, &errorMessage); if (!symGroup) break; - success = symGroup->assign(iname, enc, value, + success = symGroup->assign(iname, encoded ? stringFromHex(value) : value, SymbolGroupValueContext(exc.dataSpaces(), exc.symbols()), &errorMessage); } while (false); diff --git a/src/libs/qtcreatorcdbext/stringutils.cpp b/src/libs/qtcreatorcdbext/stringutils.cpp index cd4eb683b0f..7a8554f91c5 100644 --- a/src/libs/qtcreatorcdbext/stringutils.cpp +++ b/src/libs/qtcreatorcdbext/stringutils.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include static const char whiteSpace[] = " \t\r\n"; @@ -149,6 +150,11 @@ std::string wStringToString(const std::wstring &w) return rc; } +std::wstring utf8ToUtf16(const std::string &s) +{ + return std::wstring_convert>().from_bytes(s.data()); +} + // Convert an ASCII hex digit to its value 'A'->10 static inline unsigned hexDigit(char c) { @@ -210,6 +216,11 @@ std::string stringFromHex(const char *p, const char *end) return rc; } +std::string stringFromHex(const std::string &hexEncoded) +{ + return stringFromHex(hexEncoded.c_str(), hexEncoded.c_str() + hexEncoded.size()); +} + // Helper for dumping memory std::string dumpMemory(const unsigned char *p, size_t size, bool wantQuotes) diff --git a/src/libs/qtcreatorcdbext/stringutils.h b/src/libs/qtcreatorcdbext/stringutils.h index e8297d44a44..f891cf3ae75 100644 --- a/src/libs/qtcreatorcdbext/stringutils.h +++ b/src/libs/qtcreatorcdbext/stringutils.h @@ -167,6 +167,7 @@ inline std::ostream &operator<<(std::ostream &str, const gdbmiWStringFormat &wsf } std::string wStringToString(const std::wstring &w); +std::wstring utf8ToUtf16(const std::string &s); // Strings from raw data. std::wstring quotedWStringFromCharData(const unsigned char *data, size_t size, bool truncated = false); @@ -177,6 +178,7 @@ std::string dumpMemory(const unsigned char *data, size_t size, bool wantQuotes = // String from hex "414A" -> "AJ". std::string stringFromHex(const char *begin, const char *end); +std::string stringFromHex(const std::string &hexEncoded); // Decode hex to a memory area. void decodeHex(const char *begin, const char *end, unsigned char *target); diff --git a/src/libs/qtcreatorcdbext/symbolgroup.cpp b/src/libs/qtcreatorcdbext/symbolgroup.cpp index 8404f0d77c0..0d55fb6a39b 100644 --- a/src/libs/qtcreatorcdbext/symbolgroup.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroup.cpp @@ -449,7 +449,6 @@ void SymbolGroup::markUninitialized(const std::vector &uniniNodes) } bool SymbolGroup::assign(const std::string &nodeName, - int valueEncoding, const std::string &value, const SymbolGroupValueContext &ctx, std::string *errorMessage) @@ -468,9 +467,9 @@ bool SymbolGroup::assign(const std::string &nodeName, int kt = node->dumperType(); if (kt < 0) kt = knownType(node->type(), KnownTypeAutoStripPointer | KnownTypeHasClassPrefix); - return (kt & KT_Editable) ? // Edit complex types - assignType(node, kt, valueEncoding, value, ctx, errorMessage) : - node->assign(value, errorMessage); + if (kt & KT_Editable) + return assignType(node, kt, value, ctx, errorMessage); + return node->assign(value, errorMessage); } bool SymbolGroup::accept(SymbolGroupNodeVisitor &visitor) const diff --git a/src/libs/qtcreatorcdbext/symbolgroup.h b/src/libs/qtcreatorcdbext/symbolgroup.h index 20281a500bb..92ac15238f7 100644 --- a/src/libs/qtcreatorcdbext/symbolgroup.h +++ b/src/libs/qtcreatorcdbext/symbolgroup.h @@ -96,7 +96,6 @@ public: // Assign a value by iname bool assign(const std::string &node, - int valueEncoding, const std::string &value, const SymbolGroupValueContext &ctx, std::string *errorMessage); diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp index d595a5925b2..9ac8b821bfa 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp @@ -1432,10 +1432,11 @@ std::string SymbolGroupNode::msgAssignError(const std::string &nodeName, } // Simple type -bool SymbolGroupNode::assign(const std::string &value, std::string *errorMessage /* = 0 */) +bool SymbolGroupNode::assign(const std::string &value, + std::string *errorMessage /* = 0 */) { const HRESULT hr = - m_symbolGroup->debugSymbolGroup()->WriteSymbol(m_index, const_cast(value.c_str())); + m_symbolGroup->debugSymbolGroup()->WriteSymbol(m_index, value.c_str()); if (FAILED(hr)) { if (errorMessage) *errorMessage = SymbolGroupNode::msgAssignError(name(), value, msgDebugEngineComFailed("WriteSymbol", hr)); diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp index 14c3732678b..e06cf91fe0c 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp @@ -3309,101 +3309,6 @@ static inline std::vector return rc; } -/* AssignmentStringData: Helper struct used for assigning values - * to string classes. Contains an (allocated) data array with size for use - * with IDebugDataSpaced::FillVirtual() + string length information and - * provides a conversion function decodeString() to create the array - * depending on the argument format (blow up ASCII to UTF16 or vice versa). */ - -struct AssignmentStringData -{ - explicit AssignmentStringData(size_t dataLengthIn, size_t stringLengthIn); - static AssignmentStringData decodeString(const char *begin, const char *end, - int valueEncoding, bool toUtf16); - - static inline AssignmentStringData decodeString(const std::string &value, - int valueEncoding, bool toUtf16) - { return decodeString(value.c_str(), value.c_str() + value.size(), - valueEncoding, toUtf16); } - - unsigned char *data; - size_t dataLength; - size_t stringLength; -}; - -AssignmentStringData::AssignmentStringData(size_t dataLengthIn, size_t stringLengthIn) : - data(new unsigned char[dataLengthIn]), dataLength(dataLengthIn), - stringLength(stringLengthIn) -{ - if (dataLength) - memset(data, 0, dataLength); -} - -AssignmentStringData AssignmentStringData::decodeString(const char *begin, const char *end, - int valueEncoding, bool toUtf16) -{ - if (toUtf16) { // Target is UTF16 consisting of unsigned short characters. - switch (valueEncoding) { - // Hex encoded ASCII/2 digits per char: Decode to plain characters and - // recurse to expand them. - case AssignHexEncoded: { - const AssignmentStringData decoded = decodeString(begin, end, AssignHexEncoded, false); - const char *source = reinterpret_cast(decoded.data); - const AssignmentStringData utf16 = decodeString(source, source + decoded.stringLength, - AssignPlainValue, true); - delete [] decoded.data; - return utf16; - } - // Hex encoded UTF16: 4 hex digits per character: Decode sequence. - case AssignHexEncodedUtf16: { - const size_t stringLength = (end - begin) / 4; - AssignmentStringData result(sizeof(unsigned short) *(stringLength + 1), stringLength); - decodeHex(begin, end, result.data); - return result; - } - default: - break; - } - // Convert plain ASCII data to UTF16 by expanding. - const size_t stringLength = end - begin; - AssignmentStringData result(sizeof(unsigned short) *(stringLength + 1), stringLength); - const unsigned char *source = reinterpret_cast(begin); - unsigned short *target = reinterpret_cast(result.data); - std::copy(source, source + stringLength, target); - - return result; - } // toUtf16 - switch (valueEncoding) { - case AssignHexEncoded: { // '0A5A'..2 digits per character - const size_t stringLength = (end - begin) / 2; - AssignmentStringData result(stringLength + 1, stringLength); - decodeHex(begin, end, result.data); - return result; - } - // Condense UTF16 characters to ASCII: Decode and use only every 2nd character - // (little endian, first byte) - case AssignHexEncodedUtf16: { - const AssignmentStringData decoded = decodeString(begin, end, AssignHexEncoded, false); - const size_t stringLength = decoded.stringLength / 2; - const AssignmentStringData result(stringLength + 1, stringLength); - const unsigned char *sourceEnd = decoded.data + decoded.stringLength; - unsigned char *target = result.data; - for (const unsigned char *source = decoded.data; source < sourceEnd; source += 2) - *target++ = *source; - delete [] decoded.data; - return result; - } - break; - default: - break; - } - // Plain 0-terminated copy - const size_t stringLength = end - begin; - AssignmentStringData result(stringLength + 1, stringLength); - memcpy(result.data, begin, stringLength); - return result; -} - // Assignment helpers static inline std::string msgAssignStringFailed(const std::string &value, int errorCode) { @@ -3417,8 +3322,9 @@ static inline std::string msgAssignStringFailed(const std::string &value, int er * recurse (since 'd' might become invalid). This works for QString with UTF16 * data and for QByteArray with ASCII data due to the similar member * names and both using a terminating '\0' w_char/byte. */ +template static int assignQStringI(SymbolGroupNode *n, const char *className, - const AssignmentStringData &data, + const string &data, const SymbolGroupValueContext &ctx, bool doAlloc = true) { @@ -3431,7 +3337,7 @@ static int assignQStringI(SymbolGroupNode *n, const char *className, const QtStringAddressData addressData = readQtStringAddressData(d, qtInfo); if (!addressData.address) return 9; - const bool needRealloc = addressData.allocated < data.stringLength; + const bool needRealloc = addressData.allocated < data.size(); if (needRealloc) { if (!doAlloc) // Calling re-alloc failed somehow. return 3; @@ -3439,7 +3345,7 @@ static int assignQStringI(SymbolGroupNode *n, const char *className, const std::string funcName = qtInfo.prependQtCoreModule(std::string(className) + "::resize"); callStr << funcName << '(' << std::hex << std::showbase - << v.address() << ',' << data.stringLength << ')'; + << v.address() << ',' << data.size() << ')'; std::wstring wOutput; std::string errorMessage; return ExtensionContext::instance().call(callStr.str(), 0, &wOutput, &errorMessage) ? @@ -3447,8 +3353,8 @@ static int assignQStringI(SymbolGroupNode *n, const char *className, } // Write data. if (!SymbolGroupValue::writeMemory(v.context().dataspaces, - addressData.address, data.data, - ULONG(data.dataLength))) + addressData.address, (const unsigned char *)(data.c_str()), + ULONG(data.empty() ? 0 : sizeof(data.front()) * data.size()))) return 11; // Correct size unless we re-allocated if (!needRealloc) { @@ -3460,7 +3366,7 @@ static int assignQStringI(SymbolGroupNode *n, const char *className, const SymbolGroupValue size = dV["size"]; if (!size) return 16; - if (!size.node()->assign(toString(data.stringLength))) + if (!size.node()->assign(toString(data.size()))) return 17; } return 0; @@ -3468,13 +3374,11 @@ static int assignQStringI(SymbolGroupNode *n, const char *className, // QString assignment static inline bool assignQString(SymbolGroupNode *n, - int valueEncoding, const std::string &value, + const std::string &value, const SymbolGroupValueContext &ctx, std::string *errorMessage) { - const AssignmentStringData utf16 = AssignmentStringData::decodeString(value, valueEncoding, true); - const int errorCode = assignQStringI(n, "QString", utf16, ctx); - delete [] utf16.data; + const int errorCode = assignQStringI(n, "QString", utf8ToUtf16(value), ctx); if (errorCode) { *errorMessage = msgAssignStringFailed(value, errorCode); return false; @@ -3484,13 +3388,11 @@ static inline bool assignQString(SymbolGroupNode *n, // QByteArray assignment static inline bool assignQByteArray(SymbolGroupNode *n, - int valueEncoding, const std::string &value, + const std::string &value, const SymbolGroupValueContext &ctx, std::string *errorMessage) { - const AssignmentStringData data = AssignmentStringData::decodeString(value, valueEncoding, false); - const int errorCode = assignQStringI(n, "QByteArray", data, ctx); - delete [] data.data; + const int errorCode = assignQStringI(n, "QByteArray", value, ctx); if (errorCode) { *errorMessage = msgAssignStringFailed(value, errorCode); return false; @@ -3499,8 +3401,9 @@ static inline bool assignQByteArray(SymbolGroupNode *n, } // Helper to assign character data to std::string or std::wstring. -static inline int assignStdStringI(SymbolGroupNode *n, int type, - const AssignmentStringData &data, +template +static inline int assignStdStringI(SymbolGroupNode *n, int type, + const string &data, const SymbolGroupValueContext &ctx) { /* We do not reallocate and just write to the allocated buffer @@ -3527,7 +3430,7 @@ static inline int assignStdStringI(SymbolGroupNode *n, int type, int reserved = base["_Myres"].intValue(); if (reserved < 0 || !size || !bx) return 42; - if (reserved <= (int)data.stringLength) + if (reserved <= (int)data.size()) return 1; // Insufficient memory. // Copy data: 'Buf' array for small strings, else pointer 'Ptr'. const int bufSize = type == KT_StdString ? 16 : 8; // see basic_string. @@ -3536,25 +3439,25 @@ static inline int assignStdStringI(SymbolGroupNode *n, int type, if (!address) return 3; if (!SymbolGroupValue::writeMemory(v.context().dataspaces, - address, data.data, ULONG(data.dataLength))) + address, + (const unsigned char *)(data.c_str()), + ULONG(data.empty() ? 0 : sizeof(data.front()) * data.size()))) return 7; // Correct size - if (!size.node()->assign(toString(data.stringLength))) + if (!size.node()->assign(toString(data.size()))) return 13; return 0; } // assignment of std::string assign via ASCII, std::wstring via UTF16 static inline bool assignStdString(SymbolGroupNode *n, - int type, int valueEncoding, const std::string &value, + int type, const std::string &value, const SymbolGroupValueContext &ctx, std::string *errorMessage) { - const bool toUtf16 = type == KT_StdWString; - const AssignmentStringData data = AssignmentStringData::decodeString(value, valueEncoding, - toUtf16); - const int errorCode = assignStdStringI(n, type, data, ctx); - delete [] data.data; + const int errorCode = type == KT_StdString + ? assignStdStringI(n, type, value, ctx) + : assignStdStringI(n, type, utf8ToUtf16(value), ctx); if (errorCode) { *errorMessage = msgAssignStringFailed(value, errorCode); return false; @@ -3562,17 +3465,17 @@ static inline bool assignStdString(SymbolGroupNode *n, return true; } -bool assignType(SymbolGroupNode *n, int knownType, int valueEncoding, const std::string &value, +bool assignType(SymbolGroupNode *n, int knownType, const std::string &value, const SymbolGroupValueContext &ctx, std::string *errorMessage) { switch (knownType) { case KT_QString: - return assignQString(n, valueEncoding, value, ctx, errorMessage); + return assignQString(n, value, ctx, errorMessage); case KT_QByteArray: - return assignQByteArray(n, valueEncoding, value, ctx, errorMessage); + return assignQByteArray(n,value, ctx, errorMessage); case KT_StdString: case KT_StdWString: - return assignStdString(n, knownType, valueEncoding, value, ctx, errorMessage); + return assignStdString(n, knownType, value, ctx, errorMessage); default: break; } diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.h b/src/libs/qtcreatorcdbext/symbolgroupvalue.h index b2c89cba47d..bb69794cc0f 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.h +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.h @@ -286,9 +286,8 @@ enum AssignEncoding AssignHexEncodedUtf16 }; -bool assignType(SymbolGroupNode *n, int knownType, int valueEncoding, const std::string &value, - const SymbolGroupValueContext &ctx, - std::string *errorMessage); +bool assignType(SymbolGroupNode *n, int knownType, const std::string &value, + const SymbolGroupValueContext &ctx, std::string *errorMessage); // Non-container complex dumpers (QObjects/QVariants). std::vector diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index a5554a3aa88..4e04a02fc40 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -917,15 +917,6 @@ void CdbEngine::handleJumpToLineAddressResolution(const DebuggerResponse &respon } } -static inline bool isAsciiWord(const QString &s) -{ - for (const QChar &c : s) { - if (!c.isLetterOrNumber() || c.toLatin1() == 0) - return false; - } - return true; -} - void CdbEngine::assignValueInDebugger(WatchItem *w, const QString &expr, const QVariant &value) { if (debug) @@ -935,28 +926,8 @@ void CdbEngine::assignValueInDebugger(WatchItem *w, const QString &expr, const Q qWarning("Internal error: assignValueInDebugger: Invalid state or no stack frame."); return; } - QString cmd; - StringInputStream str(cmd); - switch (value.type()) { - case QVariant::String: { - // Convert qstring to Utf16 data not considering endianness for Windows. - const QString s = value.toString(); - if (isAsciiWord(s)) { - str << m_extensionCommandPrefix << "assign \"" << w->iname << '=' << s << '"'; - } else { - const QByteArray utf16(reinterpret_cast(s.utf16()), 2 * s.size()); - str << m_extensionCommandPrefix << "assign -u " << w->iname << '=' - << QString::fromLatin1(utf16.toHex()); - } - } - break; - default: - str << m_extensionCommandPrefix << "assign " << w->iname << '=' - << value.toString(); - break; - } - - runCommand({cmd, NoFlags}); + runCommand({m_extensionCommandPrefix + "assign -h " + w->iname + '=' + toHex(value.toString()), + NoFlags}); // Update all locals in case we change a union or something pointed to // that affects other variables, too. updateLocals(); From 8f6eb41cad805556779c2bac67bdbead68fffda1 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 11 Oct 2019 15:01:09 +0200 Subject: [PATCH 36/45] Clang: Ensure that platform codegen flags get also filtered Leave the function addExtraCodeModelFlags() around as it's used by ClangPchManager::ProjectUpdater::toolChainArguments(). This allows us to filter out excess target arguments in a follow-up change. Change-Id: I742d713dd1ca6c391ba77c52555dcf4e94cc2ff9 Reviewed-by: Cristian Adam Reviewed-by: Nikolai Kosjar --- src/plugins/cpptools/compileroptionsbuilder.cpp | 5 ++--- tests/unit/unittest/compileroptionsbuilder-test.cpp | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index 7fde0b3a578..f13f0f1a26e 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -140,8 +140,6 @@ QStringList CompilerOptionsBuilder::build(ProjectFile::Kind fileKind, addPrecompiledHeaderOptions(usePrecompiledHeaders); addProjectConfigFileInclude(); - addExtraCodeModelFlags(); - addMsvcCompatibilityVersion(); addProjectMacros(); undefineClangVersionMacrosForMsvc(); @@ -727,7 +725,8 @@ void CompilerOptionsBuilder::evaluateCompilerFlags() const Core::Id &toolChain = m_projectPart.toolchainType; bool containsDriverMode = false; bool skipNext = false; - for (const QString &option : m_projectPart.compilerFlags) { + const QStringList allFlags = m_projectPart.compilerFlags + m_projectPart.extraCodeModelFlags; + for (const QString &option : allFlags) { if (skipNext) { skipNext = false; continue; diff --git a/tests/unit/unittest/compileroptionsbuilder-test.cpp b/tests/unit/unittest/compileroptionsbuilder-test.cpp index 234fc0987cd..df110727071 100644 --- a/tests/unit/unittest/compileroptionsbuilder-test.cpp +++ b/tests/unit/unittest/compileroptionsbuilder-test.cpp @@ -593,14 +593,14 @@ TEST_F(CompilerOptionsBuilder, BuildAllOptions) ASSERT_THAT(compilerOptionsBuilder.options(), ElementsAre("-nostdinc", "-nostdinc++", + "-arch", + "x86_64", "-fsyntax-only", "-m64", "--target=x86_64-apple-darwin10", "-x", "c++", "-std=c++17", - "-arch", - "x86_64", "-DprojectFoo=projectBar", "-I", IsPartOfHeader("wrappedQtHeaders"), "-I", IsPartOfHeader(toNative("wrappedQtHeaders/QtCore").toStdString()), From 90982bf2e2b7e68ec2810288424f036e22e4f278 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 11 Oct 2019 14:56:16 +0200 Subject: [PATCH 37/45] Clang: Remove duplicated targets arguments We always set the target explicitly (in a certain way), so exclude the target arguments coming from the build system and the (possibly manually specified) platform codegen flags of the toolchain. Change-Id: I74bbec67f5960f05b50cf9c5aa11875c71a5161f Reviewed-by: Cristian Adam Reviewed-by: Nikolai Kosjar --- src/plugins/cpptools/compileroptionsbuilder.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index f13f0f1a26e..aafcd35b379 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -751,6 +751,16 @@ void CompilerOptionsBuilder::evaluateCompilerFlags() continue; } + // As we always set the target explicitly, filter out target args. + if (!m_projectPart.toolChainTargetTriple.isEmpty()) { + if (option.startsWith("--target=")) + continue; + if (option == "-target") { + skipNext = true; + continue; + } + } + if (option == includeUserPathOption || option == includeSystemPathOption || option == includeUserPathOptionWindows) { skipNext = true; From 6463a686f6b6530c005fe6b340152b331bca9600 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 22 Oct 2019 10:13:29 +0200 Subject: [PATCH 38/45] Build Fix: Workaround symbols inclusion from PCH headers Broken in b128d498b2da55a9f87cd2eabb802acc0c48e7d4 Tested with MinGW 8.1 Tested with VisualStudio 2017 Change-Id: I8f43efe43016ea95866ee018ac9a47373a37373b Reviewed-by: Tim Jenssen --- src/shared/qtcreator_pch.h | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/shared/qtcreator_pch.h b/src/shared/qtcreator_pch.h index 8ff33bef080..a80eb42e7a6 100644 --- a/src/shared/qtcreator_pch.h +++ b/src/shared/qtcreator_pch.h @@ -29,14 +29,37 @@ */ #if defined __cplusplus -#include +#include -#ifdef Q_WS_WIN -# define _POSIX_ -# include -# undef _POSIX_ +#ifdef Q_OS_WIN +#define WIN32_LEAN_AND_MEAN + +// lib/Utils needs defines for Windows 8 +#ifdef Q_CC_MINGW +#define WINVER _WIN32_WINNT_WIN8 +#define _WIN32_WINNT _WIN32_WINNT_WIN8 +#endif // Q_CC_MINGW +#define NOHELP +#include + +#undef DELETE +#undef IN +#undef OUT +#undef ERROR +#undef ABSOLUTE + +//QT_NO_FLOAT16_OPERATORS is used on Visual Studio 2017 (and earlier): +//when including and in the same translation unit, +//it would cause a compilation error due to a toolchain bug (see [QTBUG-72073]) +#if _MSC_VER <= 1920 +#define QT_NO_FLOAT16_OPERATORS #endif +#define _POSIX_ +#include +#undef _POSIX_ +#endif // Q_OS_WIN + #include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) @@ -48,7 +71,7 @@ using Qt::dec; using Qt::showbase; using Qt::hex; using Qt::noforcesign; -#endif +#endif //QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include -#endif +#endif //defined __cplusplus From 67c74fbe2909fa435b6adea3153f43bcc29885fd Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 21 Oct 2019 09:18:31 +0200 Subject: [PATCH 39/45] ProjectExplorer: Do not return early on parsingFinished assert This is a hack, not a proper solution. In theory, this here should serve as a lock. We currently get start - start - finish - finish sequences when switching qmake targets quickly, keeping the run button disabled. The whole setup here is unfortunate. Parsing inherently depend on more than the project alone, it's roughly per-Target. So keeping track of it in the Project complicates it. Change-Id: I57d361ce21088d8e1ec53ce75f83ff3bd04851e1 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/project.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 0a5a157a93d..97352034274 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -524,7 +524,9 @@ void Project::emitParsingStarted() void Project::emitParsingFinished(bool success) { - QTC_ASSERT(d->m_isParsing, return); + // Intentionally no return, as we currently get start - start - end - end + // sequences when switching qmake targets quickly. + QTC_CHECK(d->m_isParsing); d->m_isParsing = false; d->m_hasParsingData = success; From d73632c6f3df49a57014a9c50e99b171f7b985c2 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 21 Oct 2019 21:55:09 +0300 Subject: [PATCH 40/45] Main: Remove unused include Change-Id: Ifeef80bfc6465c5544118a74e774a5442c4f8374 Reviewed-by: hjk --- src/app/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index c7b5aff49c3..4b74be64dce 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include From 82859399e6059556caed381dac0f7d169f1e2792 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 21 Oct 2019 22:56:09 +0300 Subject: [PATCH 41/45] QtSupport: Simplify detection of qmake executable in PATH on Windows Instead of enumerating the directory, search directly for the executable first, like it is done on UNIX. Change-Id: I6465d85efa20d97622afc227eaadcbc14b3e22f5 Reviewed-by: Christian Kandeler --- src/libs/utils/buildablehelperlibrary.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/utils/buildablehelperlibrary.cpp b/src/libs/utils/buildablehelperlibrary.cpp index 80ddeafa1a5..0e19dba5e95 100644 --- a/src/libs/utils/buildablehelperlibrary.cpp +++ b/src/libs/utils/buildablehelperlibrary.cpp @@ -78,7 +78,7 @@ static FilePath findQmakeInDir(const FilePath &path) if (path.isEmpty()) return FilePath(); - const QString qmake = "qmake"; + const QString qmake = HostOsInfo::withExecutableSuffix("qmake"); QDir dir(path.toString()); if (dir.exists(qmake)) { const QString qmakePath = dir.absoluteFilePath(qmake); From 6bdc6c1584f16271fc54733416e8efe7e8d0252e Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 22 Oct 2019 14:33:31 +0200 Subject: [PATCH 42/45] McuSupport: Split up McuSupportOptionsPage Move the non-OptionsPage code into a new file for comprehensibility. Change-Id: I306ae669ec9fdd941f777426420859ee2eb89e95 Reviewed-by: Alessandro Portale --- src/plugins/mcusupport/CMakeLists.txt | 1 + src/plugins/mcusupport/mcusupport.pro | 2 + src/plugins/mcusupport/mcusupport.qbs | 2 + src/plugins/mcusupport/mcusupportoptions.cpp | 503 ++++++++++++++++ src/plugins/mcusupport/mcusupportoptions.h | 137 +++++ .../mcusupport/mcusupportoptionspage.cpp | 563 +----------------- 6 files changed, 648 insertions(+), 560 deletions(-) create mode 100644 src/plugins/mcusupport/mcusupportoptions.cpp create mode 100644 src/plugins/mcusupport/mcusupportoptions.h diff --git a/src/plugins/mcusupport/CMakeLists.txt b/src/plugins/mcusupport/CMakeLists.txt index 91fa58b6209..ef25f4f45c9 100644 --- a/src/plugins/mcusupport/CMakeLists.txt +++ b/src/plugins/mcusupport/CMakeLists.txt @@ -6,6 +6,7 @@ add_qtc_plugin(McuSupport mcusupport_global.h mcusupportconstants.h mcusupportdevice.cpp mcusupportdevice.h + mcusupportoptions.cpp mcusupportoptions.h mcusupportoptionspage.cpp mcusupportoptionspage.h mcusupportplugin.cpp mcusupportplugin.h mcusupportrunconfiguration.cpp mcusupportrunconfiguration.h diff --git a/src/plugins/mcusupport/mcusupport.pro b/src/plugins/mcusupport/mcusupport.pro index 9bb79364f86..3f6d598f598 100644 --- a/src/plugins/mcusupport/mcusupport.pro +++ b/src/plugins/mcusupport/mcusupport.pro @@ -8,12 +8,14 @@ HEADERS += \ mcusupport_global.h \ mcusupportconstants.h \ mcusupportdevice.h \ + mcusupportoptions.h \ mcusupportoptionspage.h \ mcusupportplugin.h \ mcusupportrunconfiguration.h SOURCES += \ mcusupportdevice.cpp \ + mcusupportoptions.cpp \ mcusupportoptionspage.cpp \ mcusupportplugin.cpp \ mcusupportrunconfiguration.cpp diff --git a/src/plugins/mcusupport/mcusupport.qbs b/src/plugins/mcusupport/mcusupport.qbs index 732ecf81e4f..35e3e9a4719 100644 --- a/src/plugins/mcusupport/mcusupport.qbs +++ b/src/plugins/mcusupport/mcusupport.qbs @@ -18,6 +18,8 @@ QtcPlugin { "mcusupportconstants.h", "mcusupportdevice.cpp", "mcusupportdevice.h", + "mcusupportoptions.cpp", + "mcusupportoptions.h", "mcusupportoptionspage.cpp", "mcusupportoptionspage.h", "mcusupportplugin.cpp", diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp new file mode 100644 index 00000000000..c61a3b6f6d1 --- /dev/null +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -0,0 +1,503 @@ +/**************************************************************************** +** +** Copyright (C) 2016 BlackBerry Limited. All rights reserved. +** Contact: BlackBerry (qt@blackberry.com) +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "mcusupportconstants.h" +#include "mcusupportoptions.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace McuSupport { +namespace Internal { + +PackageOptions::PackageOptions(const QString &label, const QString &defaultPath, + const QString &detectionPath, const QString &settingsKey) + : m_label(label) + , m_defaultPath(defaultPath) + , m_detectionPath(detectionPath) + , m_settingsKey(settingsKey) +{ + QSettings *s = Core::ICore::settings(); + s->beginGroup(Constants::SETTINGS_GROUP); + m_path = s->value(QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + m_settingsKey, + m_defaultPath).toString(); + s->endGroup(); +} + +QString PackageOptions::path() const +{ + return QFileInfo(m_fileChooser->path() + m_relativePathModifier).absoluteFilePath(); +} + +QString PackageOptions::label() const +{ + return m_label; +} + +QString PackageOptions::detectionPath() const +{ + return m_detectionPath; +} + +QWidget *PackageOptions::widget() +{ + if (m_widget) + return m_widget; + + m_widget = new QWidget; + m_fileChooser = new Utils::PathChooser; + QObject::connect(m_fileChooser, &Utils::PathChooser::pathChanged, + [this](){ + updateStatus(); + emit changed(); + }); + + auto layout = new QGridLayout(m_widget); + layout->setContentsMargins(0, 0, 0, 0); + m_statusIcon = new QLabel; + m_statusIcon->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding); + m_statusIcon->setAlignment(Qt::AlignTop); + m_statusLabel = new QLabel; + m_statusLabel->setWordWrap(true); + m_statusLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft); + + if (!m_downloadUrl.isEmpty()) { + auto downLoadButton = new QToolButton; + downLoadButton->setIcon(Utils::Icons::DOWNLOAD.icon()); + downLoadButton->setToolTip(tr("Download from \"%1\"").arg(m_downloadUrl)); + QObject::connect(downLoadButton, &QToolButton::pressed, [this]{ + QDesktopServices::openUrl(m_downloadUrl); + }); + layout->addWidget(downLoadButton, 0, 2); + } + + layout->addWidget(m_fileChooser, 0, 0, 1, 2); + layout->addWidget(m_statusIcon, 1, 0); + layout->addWidget(m_statusLabel, 1, 1, 1, -1); + + m_fileChooser->setPath(m_path); // Triggers updateStatus() call + return m_widget; +} + +PackageOptions::Status PackageOptions::status() const +{ + return m_status; +} + +void PackageOptions::setDownloadUrl(const QString &url) +{ + m_downloadUrl = url; +} + +void PackageOptions::setEnvironmentVariableName(const QString &name) +{ + m_environmentVariableName = name; +} + +QString PackageOptions::environmentVariableName() const +{ + return m_environmentVariableName; +} + +void PackageOptions::setAddToPath(bool addToPath) +{ + m_addToPath = addToPath; +} + +bool PackageOptions::addToPath() const +{ + return m_addToPath; +} + +void PackageOptions::writeToSettings() const +{ + if (m_path.compare(m_defaultPath) == 0) + return; + QSettings *s = Core::ICore::settings(); + s->beginGroup(Constants::SETTINGS_GROUP); + s->setValue(QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + m_settingsKey, m_path); + s->endGroup(); +} + +void PackageOptions::setRelativePathModifier(const QString &path) +{ + m_relativePathModifier = path; +} + +void PackageOptions::updateStatus() +{ + m_path = m_fileChooser->rawPath(); + const bool validPath = m_fileChooser->isValid(); + const Utils::FilePath detectionPath = Utils::FilePath::fromString( + m_fileChooser->path() + "/" + m_detectionPath); + const QString displayDetectionPath = Utils::FilePath::fromString(m_detectionPath).toUserOutput(); + const bool validPackage = detectionPath.exists(); + + m_status = validPath ? (validPackage ? ValidPackage : ValidPathInvalidPackage) : InvalidPath; + + static const QPixmap okIcon = Utils::Icons::OK.pixmap(); + static const QPixmap notOkIcon = Utils::Icons::BROKEN.pixmap(); + m_statusIcon->setPixmap(m_status == ValidPackage ? okIcon : notOkIcon); + + QString statusText; + switch (m_status) { + case ValidPackage: + statusText = tr("Path is valid, \"%1\" was found.").arg(displayDetectionPath); + break; + case ValidPathInvalidPackage: + statusText = tr("Path exists, but does not contain \"%1\".").arg(displayDetectionPath); + break; + case InvalidPath: + statusText = tr("Path does not exist."); + break; + } + m_statusLabel->setText(statusText); +} + +BoardOptions::BoardOptions(const QString &model, const QString &toolChainFileName, + const QVector &packages) + : m_model(model) + , m_toolChainFile(toolChainFileName) + , m_packages(packages) +{ +} + +QString BoardOptions::model() const +{ + return m_model; +} + +QString BoardOptions::toolChainFile() const +{ + return m_toolChainFile; +} + +QVector BoardOptions::packages() const +{ + return m_packages; +} + +static PackageOptions *createQulPackage() +{ + auto result = new PackageOptions( + PackageOptions::tr("Qt MCU SDK"), + QDir::homePath(), + Utils::HostOsInfo::withExecutableSuffix("bin/qmltocpp"), + "qulSdk"); + result->setEnvironmentVariableName("Qul_DIR"); + return result; +} + +static PackageOptions *createArmGccPackage() +{ + const QString defaultPath = + Utils::HostOsInfo::isWindowsHost() ? + QDir::fromNativeSeparators(qEnvironmentVariable("ProgramFiles(x86)")) + + "/GNU Tools ARM Embedded/" + : QString("%{Env:ARMGCC_DIR}"); + auto result = new PackageOptions( + PackageOptions::tr("GNU Arm Embedded Toolchain"), + defaultPath, + Utils::HostOsInfo::withExecutableSuffix("bin/arm-none-eabi-g++"), + Constants::SETTINGS_KEY_PACKAGE_ARMGCC); + result->setDownloadUrl( + "https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads"); + result->setEnvironmentVariableName("ARMGCC_DIR"); + return result; +} + +static PackageOptions *createStm32CubeFwF7SdkPackage() +{ + auto result = new PackageOptions( + PackageOptions::tr("STM32Cube SDK"), + "%{Env:STM32Cube_FW_F7_SDK_PATH}", + "Drivers/STM32F7xx_HAL_Driver", + "stm32CubeFwF7Sdk"); + result->setDownloadUrl( + "https://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-mcu-packages/stm32cubef7.html"); + result->setEnvironmentVariableName("STM32Cube_FW_F7_SDK_PATH"); + return result; +} + +static PackageOptions *createStm32CubeProgrammerPackage() +{ + const QString defaultPath = + Utils::HostOsInfo::isWindowsHost() ? + QDir::fromNativeSeparators(qEnvironmentVariable("ProgramFiles")) + + "/STMicroelectronics/STM32Cube/STM32CubeProgrammer/" + : QDir::homePath(); + auto result = new PackageOptions( + PackageOptions::tr("STM32CubeProgrammer"), + defaultPath, + QLatin1String(Utils::HostOsInfo::isWindowsHost() ? "/bin/STM32_Programmer_CLI.exe" + : "/bin/STM32_Programmer.sh"), + "stm32CubeProgrammer"); + result->setRelativePathModifier("/bin"); + result->setDownloadUrl( + "https://www.st.com/en/development-tools/stm32cubeprog.html"); + result->setAddToPath(true); + return result; +} + +static PackageOptions *createEvkbImxrt1050SdkPackage() +{ + auto result = new PackageOptions( + PackageOptions::tr("NXP EVKB-IMXRT1050 SDK"), + "%{Env:EVKB_IMXRT1050_SDK_PATH}", + "EVKB-IMXRT1050_manifest_v3_5.xml", + "evkbImxrt1050Sdk"); + result->setDownloadUrl("https://mcuxpresso.nxp.com/en/welcome"); + return result; +} + +static PackageOptions *createSeggerJLinkPackage() +{ + const QString defaultPath = + Utils::HostOsInfo::isWindowsHost() ? + QDir::fromNativeSeparators(qEnvironmentVariable("ProgramFiles")) + "/SEGGER/JLink" + : QString("%{Env:SEGGER_JLINK_SOFTWARE_AND_DOCUMENTATION_PATH}"); + auto result = new PackageOptions( + PackageOptions::tr("SEGGER JLink"), + defaultPath, + Utils::HostOsInfo::withExecutableSuffix("JLink"), + "seggerJLink"); + result->setDownloadUrl("https://www.segger.com/downloads/jlink"); + return result; +} + +McuSupportOptions::McuSupportOptions(QObject *parent) + : QObject(parent) +{ + PackageOptions* qulPackage = createQulPackage(); + PackageOptions* armGccPackage = createArmGccPackage(); + PackageOptions* stm32CubeFwF7SdkPackage = createStm32CubeFwF7SdkPackage(); + PackageOptions* stm32CubeProgrammerPackage = createStm32CubeProgrammerPackage(); + PackageOptions* evkbImxrt1050SdkPackage = createEvkbImxrt1050SdkPackage(); + PackageOptions* seggerJLinkPackage = createSeggerJLinkPackage(); + + toolchainPackage = armGccPackage; + + + auto stmPackages = {armGccPackage, stm32CubeFwF7SdkPackage, stm32CubeProgrammerPackage, + qulPackage}; + auto nxpPackages = {armGccPackage, evkbImxrt1050SdkPackage, seggerJLinkPackage, + qulPackage}; + packages = {armGccPackage, stm32CubeFwF7SdkPackage, stm32CubeProgrammerPackage, + evkbImxrt1050SdkPackage, seggerJLinkPackage, qulPackage}; + + boards.append(new BoardOptions( + "stm32f7508", "CMake/stm32f7508-discovery.cmake", stmPackages)); + boards.append(new BoardOptions( + "stm32f769i", "CMake/stm32f769i-discovery.cmake", stmPackages)); + boards.append(new BoardOptions( + "evkbimxrt1050", "CMake/evkbimxrt1050-toolchain.cmake", nxpPackages)); + + for (auto package : packages) + connect(package, &PackageOptions::changed, [this](){ + emit changed(); + }); +} + +McuSupportOptions::~McuSupportOptions() +{ + qDeleteAll(packages); + packages.clear(); + qDeleteAll(boards); + boards.clear(); +} + +QVector McuSupportOptions::validBoards() const +{ + return Utils::filtered(boards, [](BoardOptions *board){ + return !Utils::anyOf(board->packages(), [](PackageOptions *package){ + return package->status() != PackageOptions::ValidPackage;}); + }); +} + +static ProjectExplorer::ToolChain* armGccToolchain(const Utils::FilePath &path, Core::Id language) +{ + using namespace ProjectExplorer; + + ToolChain *toolChain = ToolChainManager::toolChain([&path, language](const ToolChain *t){ + return t->compilerCommand() == path && t->language() == language; + }); + if (!toolChain) { + ToolChainFactory *gccFactory = + Utils::findOrDefault(ToolChainFactory::allToolChainFactories(), [](ToolChainFactory *f){ + return f->supportedToolChainType() == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID; + }); + if (gccFactory) { + const QList detected = gccFactory->detectForImport({path, language}); + if (!detected.isEmpty()) { + toolChain = detected.first(); + toolChain->setDetection(ToolChain::ManualDetection); + toolChain->setDisplayName("Arm GCC"); + ToolChainManager::registerToolChain(toolChain); + } + } + } + + return toolChain; +} + +static void setKitProperties(ProjectExplorer::Kit *k, const BoardOptions* board) +{ + using namespace ProjectExplorer; + + k->setUnexpandedDisplayName("Qt MCU - " + board->model()); + k->setValue(Constants::KIT_BOARD_MODEL_KEY, board->model()); + k->setAutoDetected(false); + k->setIrrelevantAspects({ + SysRootKitAspect::id(), + "QtSupport.QtInformation" // QtKitAspect::id() + }); +} + +static void setKitToolchains(ProjectExplorer::Kit *k, const QString &armGccPath) +{ + using namespace ProjectExplorer; + + const QString compileNameScheme = Utils::HostOsInfo::withExecutableSuffix( + armGccPath + "/bin/arm-none-eabi-%1"); + ToolChain *cTc = armGccToolchain( + Utils::FilePath::fromUserInput(compileNameScheme.arg("gcc")), + ProjectExplorer::Constants::C_LANGUAGE_ID); + ToolChain *cxxTc = armGccToolchain( + Utils::FilePath::fromUserInput(compileNameScheme.arg("g++")), + ProjectExplorer::Constants::CXX_LANGUAGE_ID); + ToolChainKitAspect::setToolChain(k, cTc); + ToolChainKitAspect::setToolChain(k, cxxTc); +} + +static void setKitDebugger(ProjectExplorer::Kit *k, const QString &armGccPath) +{ + using namespace Debugger; + + const Utils::FilePath command = Utils::FilePath::fromUserInput( + Utils::HostOsInfo::withExecutableSuffix(armGccPath + "/bin/arm-none-eabi-gdb-py")); + const DebuggerItem *debugger = DebuggerItemManager::findByCommand(command); + QVariant debuggerId; + if (!debugger) { + DebuggerItem newDebugger; + newDebugger.setCommand(command); + newDebugger.setUnexpandedDisplayName( + PackageOptions::tr("Arm GDB at %1").arg(command.toUserOutput())); + debuggerId = DebuggerItemManager::registerDebugger(newDebugger); + } else { + debuggerId = debugger->id(); + } + + DebuggerKitAspect::setDebugger(k, debuggerId); +} + +static void setKitDevice(ProjectExplorer::Kit *k) +{ + using namespace ProjectExplorer; + + DeviceTypeKitAspect::setDeviceTypeId(k, Constants::DEVICE_TYPE); +} + +static void setKitEnvironment(ProjectExplorer::Kit *k, const BoardOptions* board) +{ + using namespace ProjectExplorer; + + Utils::EnvironmentItems changes; + QStringList pathAdditions; + for (auto package : board->packages()) { + if (package->addToPath()) + pathAdditions.append(QDir::toNativeSeparators(package->path())); + if (!package->environmentVariableName().isEmpty()) + changes.append({package->environmentVariableName(), + QDir::toNativeSeparators(package->path())}); + } + if (!pathAdditions.isEmpty()) { + pathAdditions.append("${Path}"); + changes.append({"Path", pathAdditions.join(Utils::HostOsInfo::pathListSeparator())}); + } + EnvironmentKitAspect::setEnvironmentChanges(k, changes); +} + +static void setKitCMakeOptions(ProjectExplorer::Kit *k, const BoardOptions* board) +{ + using namespace CMakeProjectManager; + + CMakeConfig config = CMakeConfigurationKitAspect::configuration(k); + config.append(CMakeConfigItem("CMAKE_TOOLCHAIN_FILE", + ("%{CurrentBuild:Env:Qul_DIR}/" + + board->toolChainFile()).toUtf8())); + CMakeConfigurationKitAspect::setConfiguration(k, config); +} + +ProjectExplorer::Kit *McuSupportOptions::kit(const BoardOptions* board) +{ + using namespace ProjectExplorer; + + Kit *kit = KitManager::kit([board](const Kit *k){ + return board->model() == k->value(Constants::KIT_BOARD_MODEL_KEY).toString(); + }); + if (!kit) { + const QString armGccPath = toolchainPackage->path(); + const auto init = [board, &armGccPath](Kit *k) { + KitGuard kitGuard(k); + + setKitProperties(k, board); + setKitToolchains(k, armGccPath); + setKitDebugger(k, armGccPath); + setKitDevice(k); + setKitEnvironment(k, board); + setKitCMakeOptions(k, board); + + k->setup(); + k->fix(); + }; + kit = KitManager::registerKit(init); + } + return kit; +} + +} // Internal +} // McuSupport diff --git a/src/plugins/mcusupport/mcusupportoptions.h b/src/plugins/mcusupport/mcusupportoptions.h new file mode 100644 index 00000000000..0cfdd2a4ff8 --- /dev/null +++ b/src/plugins/mcusupport/mcusupportoptions.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2016 BlackBerry Limited. All rights reserved. +** Contact: BlackBerry (qt@blackberry.com) +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +QT_FORWARD_DECLARE_CLASS(QWidget) +QT_FORWARD_DECLARE_CLASS(QLabel) + +namespace Utils { +class PathChooser; +} + +namespace ProjectExplorer { +class Kit; +} + +namespace McuSupport { +namespace Internal { + +class PackageOptions : public QObject +{ + Q_OBJECT + +public: + enum Status { + InvalidPath, + ValidPathInvalidPackage, + ValidPackage + }; + + PackageOptions(const QString &label, const QString &defaultPath, const QString &detectionPath, + const QString &settingsKey); + + QString path() const; + QString label() const; + QString detectionPath() const; + Status status() const; + void setDownloadUrl(const QString &url); + void setEnvironmentVariableName(const QString &name); + void setAddToPath(bool addToPath); + bool addToPath() const; + void writeToSettings() const; + void setRelativePathModifier(const QString &path); + + QWidget *widget(); + + QString environmentVariableName() const; + +signals: + void changed(); + +private: + void updateStatus(); + + QWidget *m_widget = nullptr; + Utils::PathChooser *m_fileChooser = nullptr; + QLabel *m_statusIcon = nullptr; + QLabel *m_statusLabel = nullptr; + + const QString m_label; + const QString m_defaultPath; + const QString m_detectionPath; + const QString m_settingsKey; + + QString m_path; + QString m_relativePathModifier; // relative path to m_path to be returned by path() + QString m_downloadUrl; + QString m_environmentVariableName; + bool m_addToPath = false; + + Status m_status = InvalidPath; +}; + +class BoardOptions : public QObject +{ + Q_OBJECT + +public: + BoardOptions(const QString &model, const QString &toolChainFile, + const QVector &packages); + + QString model() const; + QString toolChainFile() const; + QVector packages() const; + +private: + const QString m_model; + const QString m_toolChainFile; + const QVector m_packages; +}; + +class McuSupportOptions : public QObject +{ + Q_OBJECT + +public: + McuSupportOptions(QObject *parent = nullptr); + ~McuSupportOptions() override; + + QVector validBoards() const; + + QVector packages; + QVector boards; + PackageOptions *toolchainPackage = nullptr; + + ProjectExplorer::Kit *kit(const BoardOptions* board); + +signals: + void changed(); +}; + +} // namespace Internal +} // namespace McuSupport diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index 64d45bf7b08..d22f213be58 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -25,441 +25,24 @@ #include "mcusupportconstants.h" #include "mcusupportoptionspage.h" +#include "mcusupportoptions.h" #include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include #include -#include -#include #include #include -#include #include -#include -#include #include -#include #include #include #include -#include -#include #include -#include namespace McuSupport { namespace Internal { -class PackageOptions : public QObject -{ - Q_OBJECT - -public: - enum Status { - InvalidPath, - ValidPathInvalidPackage, - ValidPackage - }; - - PackageOptions(const QString &label, const QString &defaultPath, const QString &detectionPath, - const QString &settingsKey); - - QString path() const; - QString label() const; - QString detectionPath() const; - Status status() const; - void setDownloadUrl(const QUrl &url); - void setEnvironmentVariableName(const QString &name); - void setAddToPath(bool addToPath); - bool addToPath() const; - void writeToSettings() const; - void setRelativePathModifier(const QString &path); - - QWidget *widget(); - - - QString environmentVariableName() const; - -signals: - void changed(); - -private: - void updateStatus(); - - QWidget *m_widget = nullptr; - Utils::PathChooser *m_fileChooser = nullptr; - QLabel *m_statusIcon = nullptr; - QLabel *m_statusLabel = nullptr; - - const QString m_label; - const QString m_defaultPath; - const QString m_detectionPath; - const QString m_settingsKey; - - QString m_path; - QString m_relativePathModifier; // relative path to m_path to be returned by path() - QUrl m_downloadUrl; - QString m_environmentVariableName; - bool m_addToPath = false; - - Status m_status = InvalidPath; -}; - -PackageOptions::PackageOptions(const QString &label, const QString &defaultPath, - const QString &detectionPath, const QString &settingsKey) - : m_label(label) - , m_defaultPath(defaultPath) - , m_detectionPath(detectionPath) - , m_settingsKey(settingsKey) -{ - QSettings *s = Core::ICore::settings(); - s->beginGroup(Constants::SETTINGS_GROUP); - m_path = s->value(QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + m_settingsKey, - m_defaultPath).toString(); - s->endGroup(); -} - -QString PackageOptions::path() const -{ - return QFileInfo(m_fileChooser->path() + m_relativePathModifier).absoluteFilePath(); -} - -QString PackageOptions::label() const -{ - return m_label; -} - -QString PackageOptions::detectionPath() const -{ - return m_detectionPath; -} - -QWidget *PackageOptions::widget() -{ - if (m_widget) - return m_widget; - - m_widget = new QWidget; - m_fileChooser = new Utils::PathChooser; - QObject::connect(m_fileChooser, &Utils::PathChooser::pathChanged, - [this](){ - updateStatus(); - emit changed(); - }); - - auto layout = new QGridLayout(m_widget); - layout->setContentsMargins(0, 0, 0, 0); - m_statusIcon = new QLabel; - m_statusIcon->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding); - m_statusIcon->setAlignment(Qt::AlignTop); - m_statusLabel = new QLabel; - m_statusLabel->setWordWrap(true); - m_statusLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft); - - if (!m_downloadUrl.isEmpty()) { - auto downLoadButton = new QToolButton; - downLoadButton->setIcon(Utils::Icons::DOWNLOAD.icon()); - downLoadButton->setToolTip(McuSupportOptionsPage::tr("Download from \"%1\"") - .arg(m_downloadUrl.toString())); - QObject::connect(downLoadButton, &QToolButton::pressed, [this]{ - QDesktopServices::openUrl(m_downloadUrl); - }); - layout->addWidget(downLoadButton, 0, 2); - } - - layout->addWidget(m_fileChooser, 0, 0, 1, 2); - layout->addWidget(m_statusIcon, 1, 0); - layout->addWidget(m_statusLabel, 1, 1, 1, -1); - - m_fileChooser->setPath(m_path); // Triggers updateStatus() call - return m_widget; -} - -PackageOptions::Status PackageOptions::status() const -{ - return m_status; -} - -void PackageOptions::setDownloadUrl(const QUrl &url) -{ - m_downloadUrl = url; -} - -void PackageOptions::setEnvironmentVariableName(const QString &name) -{ - m_environmentVariableName = name; -} - -QString PackageOptions::environmentVariableName() const -{ - return m_environmentVariableName; -} - -void PackageOptions::setAddToPath(bool addToPath) -{ - m_addToPath = addToPath; -} - -bool PackageOptions::addToPath() const -{ - return m_addToPath; -} - -void PackageOptions::writeToSettings() const -{ - if (m_path.compare(m_defaultPath) == 0) - return; - QSettings *s = Core::ICore::settings(); - s->beginGroup(Constants::SETTINGS_GROUP); - s->setValue(QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + m_settingsKey, m_path); - s->endGroup(); -} - -void PackageOptions::setRelativePathModifier(const QString &path) -{ - m_relativePathModifier = path; -} - -void PackageOptions::updateStatus() -{ - m_path = m_fileChooser->rawPath(); - const bool validPath = m_fileChooser->isValid(); - const Utils::FilePath detectionPath = Utils::FilePath::fromString( - m_fileChooser->path() + "/" + m_detectionPath); - const QString displayDetectionPath = Utils::FilePath::fromString(m_detectionPath).toUserOutput(); - const bool validPackage = detectionPath.exists(); - - m_status = validPath ? (validPackage ? ValidPackage : ValidPathInvalidPackage) : InvalidPath; - - static const QPixmap okIcon = Utils::Icons::OK.pixmap(); - static const QPixmap notOkIcon = Utils::Icons::BROKEN.pixmap(); - m_statusIcon->setPixmap(m_status == ValidPackage ? okIcon : notOkIcon); - - QString statusText; - switch (m_status) { - case ValidPackage: - statusText = McuSupportOptionsPage::tr( - "Path is valid, \"%1\" was found.").arg(displayDetectionPath); - break; - case ValidPathInvalidPackage: - statusText = McuSupportOptionsPage::tr( - "Path exists, but does not contain \"%1\".").arg(displayDetectionPath); - break; - case InvalidPath: - statusText = McuSupportOptionsPage::tr("Path does not exist."); - break; - } - m_statusLabel->setText(statusText); -} - -class BoardOptions : public QObject -{ - Q_OBJECT - -public: - BoardOptions(const QString &model, const QString &toolChainFile, - const QVector &packages); - - QString model() const; - QString toolChainFile() const; - QVector packages() const; - -private: - const QString m_model; - const QString m_toolChainFile; - const QVector m_packages; -}; - -BoardOptions::BoardOptions(const QString &model, const QString &toolChainFileName, - const QVector &packages) - : m_model(model) - , m_toolChainFile(toolChainFileName) - , m_packages(packages) -{ -} - -QString BoardOptions::model() const -{ - return m_model; -} - -QString BoardOptions::toolChainFile() const -{ - return m_toolChainFile; -} - -QVector BoardOptions::packages() const -{ - return m_packages; -} - -class McuSupportOptions : public QObject -{ - Q_OBJECT - -public: - McuSupportOptions(QObject *parent = nullptr); - ~McuSupportOptions() override; - - QVector validBoards() const; - - QVector packages; - QVector boards; - PackageOptions* toolchainPackage = nullptr; - -signals: - void changed(); -}; - -static PackageOptions* createQulPackage() -{ - auto result = new PackageOptions( - McuSupportOptionsPage::tr("Qt MCU SDK"), - QDir::homePath(), - Utils::HostOsInfo::withExecutableSuffix("bin/qmltocpp"), - "qulSdk"); - result->setEnvironmentVariableName("Qul_DIR"); - return result; -} - -static PackageOptions* createArmGccPackage() -{ - const QString defaultPath = - Utils::HostOsInfo::isWindowsHost() ? - QDir::fromNativeSeparators(qEnvironmentVariable("ProgramFiles(x86)")) - + "/GNU Tools ARM Embedded/" - : QString("%{Env:ARMGCC_DIR}"); - auto result = new PackageOptions( - McuSupportOptionsPage::tr("GNU Arm Embedded Toolchain"), - defaultPath, - Utils::HostOsInfo::withExecutableSuffix("bin/arm-none-eabi-g++"), - Constants::SETTINGS_KEY_PACKAGE_ARMGCC); - result->setDownloadUrl( - QUrl::fromUserInput("https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads")); - result->setEnvironmentVariableName("ARMGCC_DIR"); - return result; -} - -static PackageOptions* createStm32CubeFwF7SdkPackage() -{ - auto result = new PackageOptions( - McuSupportOptionsPage::tr("STM32Cube SDK"), - "%{Env:STM32Cube_FW_F7_SDK_PATH}", - "Drivers/STM32F7xx_HAL_Driver", - "stm32CubeFwF7Sdk"); - result->setDownloadUrl( - QUrl::fromUserInput("https://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-mcu-packages/stm32cubef7.html")); - result->setEnvironmentVariableName("STM32Cube_FW_F7_SDK_PATH"); - return result; -} - -static PackageOptions* createStm32CubeProgrammerPackage() -{ - const QString defaultPath = - Utils::HostOsInfo::isWindowsHost() ? - QDir::fromNativeSeparators(qEnvironmentVariable("ProgramFiles")) - + "/STMicroelectronics/STM32Cube/STM32CubeProgrammer/" - : QDir::homePath(); - auto result = new PackageOptions( - McuSupportOptionsPage::tr("STM32CubeProgrammer"), - defaultPath, - QLatin1String(Utils::HostOsInfo::isWindowsHost() ? "/bin/STM32_Programmer_CLI.exe" - : "/bin/STM32_Programmer.sh"), - "stm32CubeProgrammer"); - result->setRelativePathModifier("/bin"); - result->setDownloadUrl( - QUrl::fromUserInput("https://www.st.com/en/development-tools/stm32cubeprog.html")); - result->setAddToPath(true); - return result; -} - -static PackageOptions* createEvkbImxrt1050SdkPackage() -{ - auto result = new PackageOptions( - McuSupportOptionsPage::tr("NXP EVKB-IMXRT1050 SDK"), - "%{Env:EVKB_IMXRT1050_SDK_PATH}", - "EVKB-IMXRT1050_manifest_v3_5.xml", - "evkbImxrt1050Sdk"); - result->setDownloadUrl( - QUrl::fromUserInput("https://mcuxpresso.nxp.com/en/welcome")); - return result; -} - -static PackageOptions* createSeggerJLinkPackage() -{ - const QString defaultPath = - Utils::HostOsInfo::isWindowsHost() ? - QDir::fromNativeSeparators(qEnvironmentVariable("ProgramFiles")) + "/SEGGER/JLink" - : QString("%{Env:SEGGER_JLINK_SOFTWARE_AND_DOCUMENTATION_PATH}"); - auto result = new PackageOptions( - McuSupportOptionsPage::tr("SEGGER JLink"), - defaultPath, - Utils::HostOsInfo::withExecutableSuffix("JLink"), - "seggerJLink"); - result->setDownloadUrl( - QUrl::fromUserInput("https://www.segger.com/downloads/jlink")); - return result; -} - -McuSupportOptions::McuSupportOptions(QObject *parent) - : QObject(parent) -{ - PackageOptions* qulPackage = createQulPackage(); - PackageOptions* armGccPackage = createArmGccPackage(); - PackageOptions* stm32CubeFwF7SdkPackage = createStm32CubeFwF7SdkPackage(); - PackageOptions* stm32CubeProgrammerPackage = createStm32CubeProgrammerPackage(); - PackageOptions* evkbImxrt1050SdkPackage = createEvkbImxrt1050SdkPackage(); - PackageOptions* seggerJLinkPackage = createSeggerJLinkPackage(); - - toolchainPackage = armGccPackage; - - - auto stmPackages = {armGccPackage, stm32CubeFwF7SdkPackage, stm32CubeProgrammerPackage, - qulPackage}; - auto nxpPackages = {armGccPackage, evkbImxrt1050SdkPackage, seggerJLinkPackage, - qulPackage}; - packages = {armGccPackage, stm32CubeFwF7SdkPackage, stm32CubeProgrammerPackage, - evkbImxrt1050SdkPackage, seggerJLinkPackage, qulPackage}; - - boards.append(new BoardOptions( - "stm32f7508", "CMake/stm32f7508-discovery.cmake", stmPackages)); - boards.append(new BoardOptions( - "stm32f769i", "CMake/stm32f769i-discovery.cmake", stmPackages)); - boards.append(new BoardOptions( - "evkbimxrt1050", "CMake/evkbimxrt1050-toolchain.cmake", nxpPackages)); - - for (auto package : packages) - connect(package, &PackageOptions::changed, [this](){ - emit changed(); - }); -} - -McuSupportOptions::~McuSupportOptions() -{ - qDeleteAll(packages); - packages.clear(); - qDeleteAll(boards); - boards.clear(); -} - -QVector McuSupportOptions::validBoards() const -{ - return Utils::filtered(boards, [](BoardOptions *board){ - return !Utils::anyOf(board->packages(), [](PackageOptions *package){ - return package->status() != PackageOptions::ValidPackage;}); - }); -} - class McuSupportOptionsWidget : public QWidget { public: @@ -562,7 +145,7 @@ McuSupportOptionsPage::McuSupportOptionsPage(QObject* parent) setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY); } -QWidget* McuSupportOptionsPage::widget() +QWidget *McuSupportOptionsPage::widget() { if (!m_options) m_options = new McuSupportOptions(this); @@ -571,146 +154,6 @@ QWidget* McuSupportOptionsPage::widget() return m_widget; } -static ProjectExplorer::ToolChain* armGccToolchain(const Utils::FilePath &path, Core::Id language) -{ - using namespace ProjectExplorer; - - ToolChain *toolChain = ToolChainManager::toolChain([&path, language](const ToolChain *t){ - return t->compilerCommand() == path && t->language() == language; - }); - if (!toolChain) { - ToolChainFactory *gccFactory = - Utils::findOrDefault(ToolChainFactory::allToolChainFactories(), [](ToolChainFactory *f){ - return f->supportedToolChainType() == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID; - }); - if (gccFactory) { - const QList detected = gccFactory->detectForImport({path, language}); - if (!detected.isEmpty()) { - toolChain = detected.first(); - toolChain->setDetection(ToolChain::ManualDetection); - toolChain->setDisplayName("Arm GCC"); - ToolChainManager::registerToolChain(toolChain); - } - } - } - - return toolChain; -} - -static void setKitProperties(ProjectExplorer::Kit *k, const BoardOptions* board) -{ - using namespace ProjectExplorer; - - k->setUnexpandedDisplayName("Qt MCU - " + board->model()); - k->setValue(Constants::KIT_BOARD_MODEL_KEY, board->model()); - k->setAutoDetected(false); - k->setIrrelevantAspects({ - SysRootKitAspect::id(), - "QtSupport.QtInformation" // QtKitAspect::id() - }); -} - -static void setKitToolchains(ProjectExplorer::Kit *k, const QString &armGccPath) -{ - using namespace ProjectExplorer; - - const QString compileNameScheme = Utils::HostOsInfo::withExecutableSuffix( - armGccPath + "/bin/arm-none-eabi-%1"); - ToolChain *cTc = armGccToolchain( - Utils::FilePath::fromUserInput(compileNameScheme.arg("gcc")), - ProjectExplorer::Constants::C_LANGUAGE_ID); - ToolChain *cxxTc = armGccToolchain( - Utils::FilePath::fromUserInput(compileNameScheme.arg("g++")), - ProjectExplorer::Constants::CXX_LANGUAGE_ID); - ToolChainKitAspect::setToolChain(k, cTc); - ToolChainKitAspect::setToolChain(k, cxxTc); -} - -static void setKitDebugger(ProjectExplorer::Kit *k, const QString &armGccPath) -{ - using namespace Debugger; - - const Utils::FilePath command = Utils::FilePath::fromUserInput( - Utils::HostOsInfo::withExecutableSuffix(armGccPath + "/bin/arm-none-eabi-gdb-py")); - const DebuggerItem *debugger = DebuggerItemManager::findByCommand(command); - QVariant debuggerId; - if (!debugger) { - DebuggerItem newDebugger; - newDebugger.setCommand(command); - newDebugger.setUnexpandedDisplayName( - McuSupportOptionsPage::tr("Arm GDB at %1").arg(command.toUserOutput())); - debuggerId = DebuggerItemManager::registerDebugger(newDebugger); - } else { - debuggerId = debugger->id(); - } - - DebuggerKitAspect::setDebugger(k, debuggerId); -} - -static void setKitDevice(ProjectExplorer::Kit *k) -{ - using namespace ProjectExplorer; - - DeviceTypeKitAspect::setDeviceTypeId(k, Constants::DEVICE_TYPE); -} - -static void setKitEnvironment(ProjectExplorer::Kit *k, const BoardOptions* board) -{ - using namespace ProjectExplorer; - - Utils::EnvironmentItems changes; - QStringList pathAdditions; - for (auto package : board->packages()) { - if (package->addToPath()) - pathAdditions.append(QDir::toNativeSeparators(package->path())); - if (!package->environmentVariableName().isEmpty()) - changes.append({package->environmentVariableName(), - QDir::toNativeSeparators(package->path())}); - } - if (!pathAdditions.isEmpty()) { - pathAdditions.append("${Path}"); - changes.append({"Path", pathAdditions.join(Utils::HostOsInfo::pathListSeparator())}); - } - EnvironmentKitAspect::setEnvironmentChanges(k, changes); -} - -static void setKitCMakeOptions(ProjectExplorer::Kit *k, const BoardOptions* board) -{ - using namespace CMakeProjectManager; - - CMakeConfig config = CMakeConfigurationKitAspect::configuration(k); - config.append(CMakeConfigItem("CMAKE_TOOLCHAIN_FILE", - ("%{CurrentBuild:Env:Qul_DIR}/" + - board->toolChainFile()).toUtf8())); - CMakeConfigurationKitAspect::setConfiguration(k, config); -} - -static ProjectExplorer::Kit* boardKit(const BoardOptions* board, const QString &armGccPath) -{ - using namespace ProjectExplorer; - - Kit *kit = KitManager::kit([board](const Kit *k){ - return board->model() == k->value(Constants::KIT_BOARD_MODEL_KEY).toString(); - }); - if (!kit) { - const auto init = [board, &armGccPath](Kit *k) { - KitGuard kitGuard(k); - - setKitProperties(k, board); - setKitToolchains(k, armGccPath); - setKitDebugger(k, armGccPath); - setKitDevice(k); - setKitEnvironment(k, board); - setKitCMakeOptions(k, board); - - k->setup(); - k->fix(); - }; - kit = KitManager::registerKit(init); - } - return kit; -} - void McuSupportOptionsPage::apply() { for (auto package : m_options->packages) @@ -723,7 +166,7 @@ void McuSupportOptionsPage::apply() using namespace ProjectExplorer; for (auto board : validBoards) - boardKit(board, m_options->toolchainPackage->path()); + m_options->kit(board); } void McuSupportOptionsPage::finish() From 8d03546d6ba2733d6a939a5c5fcaeaff65e4a61a Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 22 Oct 2019 16:51:11 +0200 Subject: [PATCH 43/45] Mcu: Compile fix Change-Id: I45134ffc02adfe770127bd6648ed378fdd616264 Reviewed-by: Alessandro Portale --- src/plugins/mcusupport/mcusupportoptionspage.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index d22f213be58..1396d4226fc 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -178,5 +178,3 @@ void McuSupportOptionsPage::finish() } // Internal } // McuSupport - -#include "mcusupportoptionspage.moc" From 6df9e8f8be73d94842d491c35379e18465673505 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 23 Oct 2019 06:44:21 +0200 Subject: [PATCH 44/45] McuSupport: Fix missing include Amends 6bdc6c1584f16271fc54733416e8efe7e8d0252e. Change-Id: I13a927c872aac3b7e76d8d2604dbe7a0a8dfadcf Reviewed-by: David Schulz --- src/plugins/mcusupport/mcusupportoptions.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/mcusupport/mcusupportoptions.h b/src/plugins/mcusupport/mcusupportoptions.h index 0cfdd2a4ff8..3df2d065aba 100644 --- a/src/plugins/mcusupport/mcusupportoptions.h +++ b/src/plugins/mcusupport/mcusupportoptions.h @@ -26,6 +26,7 @@ #pragma once #include +#include QT_FORWARD_DECLARE_CLASS(QWidget) QT_FORWARD_DECLARE_CLASS(QLabel) From 1b655f76ad61cc17483d00b8ece06e08afaeaf01 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 22 Oct 2019 08:38:28 +0200 Subject: [PATCH 45/45] AutoTest: Fix gathering Boost test cases When multiple test executables are defined inside a single project file all or selected tests did just use the first defined target which in turn led to execute only the test cases of one of the executables or none at all. Take all targets into account and make Run All and Run Selected work correctly for this scenario. Fixes: QTCREATORBUG-23091 Change-Id: Idf0dd99f9a8782072cbc5792c937232673fee445 Reviewed-by: David Schulz --- .../autotest/boost/boosttesttreeitem.cpp | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/plugins/autotest/boost/boosttesttreeitem.cpp b/src/plugins/autotest/boost/boosttesttreeitem.cpp index e2e58c28aff..98a27c04977 100644 --- a/src/plugins/autotest/boost/boosttesttreeitem.cpp +++ b/src/plugins/autotest/boost/boosttesttreeitem.cpp @@ -203,12 +203,14 @@ QList BoostTestTreeItem::getAllTestConfigurations() const }); for (auto it = testsPerProjectfile.begin(), end = testsPerProjectfile.end(); it != end; ++it) { - BoostTestConfiguration *config = new BoostTestConfiguration; - config->setProject(project); - config->setProjectFile(it.key()); - config->setTestCaseCount(it.value().testCases); - config->setInternalTargets(it.value().internalTargets); - result.append(config); + for (const QString &target : qAsConst(it.value().internalTargets)) { + BoostTestConfiguration *config = new BoostTestConfiguration; + config->setProject(project); + config->setProjectFile(it.key()); + config->setTestCaseCount(it.value().testCases); + config->setInternalTarget(target); + result.append(config); + } } return result; } @@ -245,12 +247,14 @@ QList BoostTestTreeItem::getSelectedTestConfigurations() co auto end = testCasesForProjectFile.cend(); for (auto it = testCasesForProjectFile.cbegin(); it != end; ++it) { - BoostTestConfiguration *config = new BoostTestConfiguration; - config->setProject(project); - config->setProjectFile(it.key()); - config->setTestCases(it.value().testCases); - config->setInternalTargets(it.value().internalTargets); - result.append(config); + for (const QString &target : it.value().internalTargets) { + BoostTestConfiguration *config = new BoostTestConfiguration; + config->setProject(project); + config->setProjectFile(it.key()); + config->setTestCases(it.value().testCases); + config->setInternalTarget(target); + result.append(config); + } } return result; }