diff options
187 files changed, 3269 insertions, 2459 deletions
@@ -276,7 +276,7 @@ http://llvm.org/docs/GettingStarted.html#git-mirror: The ClangFormat plugin depends on the additional patch - https://code.qt.io/cgit/clang/clang.git/commit/?h=release_80-based&id=f98a155c89df094fb8f419a20629065f25fe599a + https://code.qt.io/cgit/clang/clang.git/commit/?h=release_80-based&id=fa1b9053729ec6a4425a44ec5502dd388928274a While the plugin builds without it, it will be disabled on start with an error message. diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake index 300b7cd50a..35ba699ee0 100644 --- a/cmake/QtCreatorAPI.cmake +++ b/cmake/QtCreatorAPI.cmake @@ -15,6 +15,13 @@ list(APPEND DEFAULT_DEFINES if (WIN32) list(APPEND DEFAULT_DEFINES UNICODE _UNICODE _CRT_SECURE_NO_WARNINGS) + + if (NOT BUILD_WITH_PCH) + # Windows 8 0x0602 + list(APPEND DEFAULT_DEFINES + WINVER=0x0602 _WIN32_WINNT=0x0602 + WIN32_LEAN_AND_MEAN) + endif() endif() # diff --git a/doc/src/howto/creator-only/creator-cli.qdoc b/doc/src/howto/creator-only/creator-cli.qdoc index 1982c00655..e02b026409 100644 --- a/doc/src/howto/creator-only/creator-cli.qdoc +++ b/doc/src/howto/creator-only/creator-cli.qdoc @@ -219,6 +219,11 @@ wizards, see \l{Adding New Custom Wizards} \row + \li -ensure-kit-for-binary <path to binary> + \li ProjectExplorer plugin: create a kit with a toolchain + corresponding to the given binary's architecture. + + \row \li -lastsession \li ProjectExplorer plugin: load the last session when \QC starts. Open the projects and files that were open when you last exited diff --git a/doc/src/howto/creator-sidebar-views.qdoc b/doc/src/howto/creator-sidebar-views.qdoc index 444a601842..1966224775 100644 --- a/doc/src/howto/creator-sidebar-views.qdoc +++ b/doc/src/howto/creator-sidebar-views.qdoc @@ -145,6 +145,9 @@ \li To hide source files which are automatically generated by the build system, select \uicontrol {Filter Tree > Hide Generated Files}. + \li To hide source files which are not enabled for the current target, + select \uicontrol {Filter Tree} > \uicontrol {Hide Disabled Files}. + \li To hide directories that do not contain any files, select \uicontrol {Filter Tree} > \uicontrol {Hide Empty Directories}. diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp index ff555f6514..61b21b7810 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp @@ -97,7 +97,7 @@ void Quick3DNodeInstance::setHideInEditor(bool b) if (privateNode) privateNode->setIsHiddenInEditor(b); #else - Q_UNUSED(b); + Q_UNUSED(b) #endif } diff --git a/src/libs/qmljs/CMakeLists.txt b/src/libs/qmljs/CMakeLists.txt index 6a4ef362bc..9576fe860b 100644 --- a/src/libs/qmljs/CMakeLists.txt +++ b/src/libs/qmljs/CMakeLists.txt @@ -49,5 +49,5 @@ add_qtc_library(qmljs qmljstypedescriptionreader.cpp qmljstypedescriptionreader.h qmljsutils.cpp qmljsutils.h qmljsvalueowner.cpp qmljsvalueowner.h - qmljsviewercontext.cpp qmljsviewercontext.h + qmljsviewercontext.h ) diff --git a/src/libs/qmljs/qmljs-lib.pri b/src/libs/qmljs/qmljs-lib.pri index 47967446bf..c9800eab81 100644 --- a/src/libs/qmljs/qmljs-lib.pri +++ b/src/libs/qmljs/qmljs-lib.pri @@ -70,7 +70,6 @@ SOURCES += \ $$PWD/qmljssimplereader.cpp \ $$PWD/persistenttrie.cpp \ $$PWD/qmljsimportdependencies.cpp \ - $$PWD/qmljsviewercontext.cpp \ $$PWD/qmljsdialect.cpp contains(QT, gui) { diff --git a/src/libs/qmljs/qmljs.qbs b/src/libs/qmljs/qmljs.qbs index a2580cab1e..d75bfcef7b 100644 --- a/src/libs/qmljs/qmljs.qbs +++ b/src/libs/qmljs/qmljs.qbs @@ -53,7 +53,7 @@ Project { "qmljstypedescriptionreader.cpp", "qmljstypedescriptionreader.h", "qmljsutils.cpp", "qmljsutils.h", "qmljsvalueowner.cpp", "qmljsvalueowner.h", - "qmljsviewercontext.cpp", "qmljsviewercontext.h" + "qmljsviewercontext.h" ] } diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp index 659531f130..dfa7414438 100644 --- a/src/libs/qmljs/qmljsdocument.cpp +++ b/src/libs/qmljs/qmljsdocument.cpp @@ -359,8 +359,6 @@ Bind *Document::bind() const } LibraryInfo::LibraryInfo() - : _status(NotScanned) - , _dumpStatus(NoTypeInfo) { static const QByteArray emptyFingerprint = calculateFingerprint(); _fingerprint = emptyFingerprint; @@ -368,18 +366,23 @@ LibraryInfo::LibraryInfo() LibraryInfo::LibraryInfo(Status status) : _status(status) - , _dumpStatus(NoTypeInfo) { updateFingerprint(); } +LibraryInfo::LibraryInfo(const QmlDirParser::TypeInfo &typeInfo) + : _status(Found) +{ + _typeinfos.append(typeInfo); + updateFingerprint(); +} + LibraryInfo::LibraryInfo(const QmlDirParser &parser, const QByteArray &fingerprint) : _status(Found) , _components(parser.components().values()) , _plugins(parser.plugins()) , _typeinfos(parser.typeInfos()) , _fingerprint(fingerprint) - , _dumpStatus(NoTypeInfo) { if (_fingerprint.isEmpty()) updateFingerprint(); diff --git a/src/libs/qmljs/qmljsdocument.h b/src/libs/qmljs/qmljsdocument.h index 5e80e7612b..7e3b499f5a 100644 --- a/src/libs/qmljs/qmljsdocument.h +++ b/src/libs/qmljs/qmljsdocument.h @@ -150,7 +150,7 @@ public: }; private: - Status _status; + Status _status = NotScanned; QList<QmlDirParser::Component> _components; QList<QmlDirParser::Plugin> _plugins; QList<QmlDirParser::TypeInfo> _typeinfos; @@ -160,12 +160,13 @@ private: QStringList _dependencies; QByteArray _fingerprint; - PluginTypeInfoStatus _dumpStatus; + PluginTypeInfoStatus _dumpStatus = NoTypeInfo; QString _dumpError; public: LibraryInfo(); explicit LibraryInfo(Status status); + explicit LibraryInfo(const QmlDirParser::TypeInfo &typeInfo); explicit LibraryInfo(const QmlDirParser &parser, const QByteArray &fingerprint = QByteArray()); ~LibraryInfo() = default; LibraryInfo(const LibraryInfo &other) = default; diff --git a/src/libs/qmljs/qmljsimportdependencies.cpp b/src/libs/qmljs/qmljsimportdependencies.cpp index e5d0161665..a438b93a73 100644 --- a/src/libs/qmljs/qmljsimportdependencies.cpp +++ b/src/libs/qmljs/qmljsimportdependencies.cpp @@ -40,6 +40,34 @@ static Q_LOGGING_CATEGORY(importsLog, "qtc.qmljs.imports", QtWarningMsg) namespace QmlJS { +/* + which languages might be imported in this context + */ +static bool languageIsCompatible(Dialect contextLanguage, Dialect importLanguage) +{ + if (importLanguage == Dialect::AnyLanguage && contextLanguage != Dialect::NoLanguage) + return true; + switch (contextLanguage.dialect()) { + case Dialect::JavaScript: + case Dialect::Json: + case Dialect::QmlProject: + case Dialect::QmlQbs: + case Dialect::QmlTypeInfo: + return contextLanguage == importLanguage; + case Dialect::Qml: + return importLanguage == Dialect::Qml || importLanguage == Dialect::QmlQtQuick2 || importLanguage == Dialect::JavaScript; + case Dialect::QmlQtQuick2: + case Dialect::QmlQtQuick2Ui: + return importLanguage == Dialect::Qml || importLanguage == Dialect::QmlQtQuick2 || importLanguage == Dialect::QmlQtQuick2Ui + || importLanguage == Dialect::JavaScript; + case Dialect::AnyLanguage: + return true; + case Dialect::NoLanguage: + break; + } + return false; +} + ImportKind::Enum toImportKind(ImportType::Enum type) { switch (type) { @@ -587,7 +615,7 @@ void ImportDependencies::filter(const ViewerContext &vContext) bool hasChanges = false; for (auto j = m_coreImports.cbegin(), end = m_coreImports.cend(); j != end; ++j) { const CoreImport &cImport = j.value(); - if (vContext.languageIsCompatible(cImport.language)) { + if (languageIsCompatible(vContext.language, cImport.language)) { QList<Export> newExports; foreach (const Export &e, cImport.possibleExports) { if (e.visibleInVContext(vContext)) { @@ -637,7 +665,7 @@ void ImportDependencies::iterateOnCandidateImports( const QStringList imp = m_importCache.value(key.flatKey()); foreach (const QString &cImportName, imp) { CoreImport cImport = coreImport(cImportName); - if (vContext.languageIsCompatible(cImport.language)) { + if (languageIsCompatible(vContext.language, cImport.language)) { foreach (const Export e, cImport.possibleExports) { if (e.visibleInVContext(vContext)) { ImportMatchStrength m = e.exportName.matchImport(key, vContext); @@ -659,7 +687,7 @@ void ImportDependencies::iterateOnCandidateImports( if (c == ImportKey::SameDir) { foreach (const QString &cImportName, lb.value()) { CoreImport cImport = coreImport(cImportName); - if (vContext.languageIsCompatible(cImport.language)) { + if (languageIsCompatible(vContext.language, cImport.language)) { foreach (const Export e, cImport.possibleExports) { if (e.visibleInVContext(vContext)) { ImportMatchStrength m = e.exportName.matchImport(key, vContext); @@ -835,7 +863,7 @@ void ImportDependencies::iterateOnLibraryImports( qCDebug(importsLog) << "libloop:" << i.key().toString() << i.value(); foreach (const QString &cImportName, i.value()) { CoreImport cImport = coreImport(cImportName); - if (vContext.languageIsCompatible(cImport.language)) { + if (languageIsCompatible(vContext.language, cImport.language)) { foreach (const Export &e, cImport.possibleExports) { if (e.visibleInVContext(vContext) && e.exportName.type == ImportType::Library) { ImportMatchStrength m = e.exportName.matchImport(i.key(), vContext); @@ -869,7 +897,7 @@ void ImportDependencies::iterateOnSubImports( break; foreach (const QString &cImportName, i.value()) { CoreImport cImport = coreImport(cImportName); - if (vContext.languageIsCompatible(cImport.language)) { + if (languageIsCompatible(vContext.language, cImport.language)) { foreach (const Export &e, cImport.possibleExports) { if (e.visibleInVContext(vContext)) { ImportMatchStrength m = e.exportName.matchImport(i.key(), vContext); diff --git a/src/libs/qmljs/qmljsimportdependencies.h b/src/libs/qmljs/qmljsimportdependencies.h index 7b6fae431d..903246c034 100644 --- a/src/libs/qmljs/qmljsimportdependencies.h +++ b/src/libs/qmljs/qmljsimportdependencies.h @@ -46,7 +46,7 @@ QT_END_NAMESPACE namespace QmlJS { class ImportInfo; -class ViewerContext; +struct ViewerContext; namespace Internal { class ImportDependenciesPrivate; } class ImportDependencies; diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index 396e69b8e5..1f62cf1343 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -46,63 +46,51 @@ class ImportCacheKey { public: explicit ImportCacheKey(const ImportInfo &info) - : type(info.type()) - , path(info.path()) - , majorVersion(info.version().majorVersion()) - , minorVersion(info.version().minorVersion()) + : m_type(info.type()) + , m_path(info.path()) + , m_majorVersion(info.version().majorVersion()) + , m_minorVersion(info.version().minorVersion()) {} - int type; - QString path; - int majorVersion; - int minorVersion; +private: + friend uint qHash(const ImportCacheKey &); + friend bool operator==(const ImportCacheKey &, const ImportCacheKey &); + + int m_type; + QString m_path; + int m_majorVersion; + int m_minorVersion; }; uint qHash(const ImportCacheKey &info) { - return ::qHash(info.type) ^ ::qHash(info.path) ^ - ::qHash(info.majorVersion) ^ ::qHash(info.minorVersion); + return ::qHash(info.m_type) ^ ::qHash(info.m_path) ^ + ::qHash(info.m_majorVersion) ^ ::qHash(info.m_minorVersion); } bool operator==(const ImportCacheKey &i1, const ImportCacheKey &i2) { - return i1.type == i2.type - && i1.path == i2.path - && i1.majorVersion == i2.majorVersion - && i1.minorVersion == i2.minorVersion; + return i1.m_type == i2.m_type + && i1.m_path == i2.m_path + && i1.m_majorVersion == i2.m_majorVersion + && i1.m_minorVersion == i2.m_minorVersion; } } class LinkPrivate { public: - Snapshot snapshot; - ValueOwner *valueOwner; - QStringList importPaths; - LibraryInfo builtins; - ViewerContext vContext; - - QHash<ImportCacheKey, Import> importCache; - - QHash<QString, QList<ModuleApiInfo> > importableModuleApis; - - Document::Ptr document; - QList<DiagnosticMessage> *diagnosticMessages; - - QHash<QString, QList<DiagnosticMessage> > *allDiagnosticMessages; - Context::ImportsPerDocument linkImports(); - void populateImportedTypes(Imports *imports, Document::Ptr doc); + void populateImportedTypes(Imports *imports, const Document::Ptr &doc); Import importFileOrDirectory( - Document::Ptr doc, + const Document::Ptr &doc, const ImportInfo &importInfo); Import importNonFile( - Document::Ptr doc, + const Document::Ptr &doc, const ImportInfo &importInfo); - void importObject(Bind *bind, const QString &name, ObjectValue *object, NameId *targetNamespace); - bool importLibrary(Document::Ptr doc, + bool importLibrary(const Document::Ptr &doc, const QString &libraryPath, Import *import, const QString &importPath = QString()); @@ -110,12 +98,30 @@ public: LanguageUtils::ComponentVersion version, const LibraryInfo &libraryInfo, const QString &libraryPath); - void loadImplicitDirectoryImports(Imports *imports, Document::Ptr doc); + void loadImplicitDirectoryImports(Imports *imports, const Document::Ptr &doc); void loadImplicitDefaultImports(Imports *imports); void error(const Document::Ptr &doc, const AST::SourceLocation &loc, const QString &message); void warning(const Document::Ptr &doc, const AST::SourceLocation &loc, const QString &message); void appendDiagnostic(const Document::Ptr &doc, const DiagnosticMessage &message); + +private: + friend class Link; + + Snapshot m_snapshot; + ValueOwner *m_valueOwner = nullptr; + QStringList m_importPaths; + QStringList m_applicationDirectories; + LibraryInfo m_builtins; + ViewerContext m_vContext; + + QHash<ImportCacheKey, Import> importCache; + QHash<QString, QList<ModuleApiInfo>> importableModuleApis; + + Document::Ptr document; + + QList<DiagnosticMessage> *diagnosticMessages = nullptr; + QHash<QString, QList<DiagnosticMessage>> *allDiagnosticMessages = nullptr; }; /*! @@ -132,11 +138,12 @@ public: Link::Link(const Snapshot &snapshot, const ViewerContext &vContext, const LibraryInfo &builtins) : d(new LinkPrivate) { - d->valueOwner = new ValueOwner; - d->snapshot = snapshot; - d->importPaths = vContext.paths; - d->builtins = builtins; - d->vContext = vContext; + d->m_valueOwner = new ValueOwner; + d->m_snapshot = snapshot; + d->m_importPaths = vContext.paths; + d->m_applicationDirectories = vContext.applicationDirectories; + d->m_builtins = builtins; + d->m_vContext = vContext; d->diagnosticMessages = nullptr; d->allDiagnosticMessages = nullptr; @@ -147,38 +154,39 @@ Link::Link(const Snapshot &snapshot, const ViewerContext &vContext, const Librar { // populate engine with types from C++ for (auto it = cppDataHash.cbegin(), end = cppDataHash.cend(); it != end; ++it) - d->valueOwner->cppQmlTypes().load(it.key(), it.value().exportedTypes); + d->m_valueOwner->cppQmlTypes().load(it.key(), it.value().exportedTypes); } // build an object with the context properties from C++ - ObjectValue *cppContextProperties = d->valueOwner->newObject(/* prototype = */ nullptr); + ObjectValue *cppContextProperties = d->m_valueOwner->newObject(/* prototype = */ nullptr); for (const ModelManagerInterface::CppData &cppData : cppDataHash) { - for (auto it = cppData.contextProperties.cbegin(), end = cppData.contextProperties.cend(); - it != end; ++it) { + for (auto it = cppData.contextProperties.cbegin(), + end = cppData.contextProperties.cend(); + it != end; ++it) { const Value *value = nullptr; - const QString cppTypeName = it.value(); + const QString &cppTypeName = it.value(); if (!cppTypeName.isEmpty()) - value = d->valueOwner->cppQmlTypes().objectByCppName(cppTypeName); + value = d->m_valueOwner->cppQmlTypes().objectByCppName(cppTypeName); if (!value) - value = d->valueOwner->unknownValue(); + value = d->m_valueOwner->unknownValue(); cppContextProperties->setMember(it.key(), value); } } - d->valueOwner->cppQmlTypes().setCppContextProperties(cppContextProperties); + d->m_valueOwner->cppQmlTypes().setCppContextProperties(cppContextProperties); } } ContextPtr Link::operator()(QHash<QString, QList<DiagnosticMessage> > *messages) { d->allDiagnosticMessages = messages; - return Context::create(d->snapshot, d->valueOwner, d->linkImports(), d->vContext); + return Context::create(d->m_snapshot, d->m_valueOwner, d->linkImports(), d->m_vContext); } ContextPtr Link::operator()(const Document::Ptr &doc, QList<DiagnosticMessage> *messages) { d->document = doc; d->diagnosticMessages = messages; - return Context::create(d->snapshot, d->valueOwner, d->linkImports(), d->vContext); + return Context::create(d->m_snapshot, d->m_valueOwner, d->linkImports(), d->m_vContext); } Link::~Link() @@ -191,34 +199,38 @@ Context::ImportsPerDocument LinkPrivate::linkImports() Context::ImportsPerDocument importsPerDocument; // load builtin objects - if (builtins.pluginTypeInfoStatus() == LibraryInfo::DumpDone - || builtins.pluginTypeInfoStatus() == LibraryInfo::TypeInfoFileDone) { - valueOwner->cppQmlTypes().load(QLatin1String("<builtins>"), builtins.metaObjects()); + if (m_builtins.pluginTypeInfoStatus() == LibraryInfo::DumpDone + || m_builtins.pluginTypeInfoStatus() == LibraryInfo::TypeInfoFileDone) { + m_valueOwner->cppQmlTypes().load(QLatin1String("<builtins>"), m_builtins.metaObjects()); } else { - valueOwner->cppQmlTypes().load(QLatin1String("<defaults>"), CppQmlTypesLoader::defaultQtObjects); + m_valueOwner->cppQmlTypes().load(QLatin1String("<defaults>"), + CppQmlTypesLoader::defaultQtObjects); } // load library objects shipped with Creator - valueOwner->cppQmlTypes().load(QLatin1String("<defaultQt4>"), CppQmlTypesLoader::defaultLibraryObjects); + m_valueOwner->cppQmlTypes().load(QLatin1String("<defaultQt4>"), + CppQmlTypesLoader::defaultLibraryObjects); if (document) { // do it on document first, to make sure import errors are shown - Imports *imports = new Imports(valueOwner); + auto *imports = new Imports(m_valueOwner); // Add custom imports for the opened document - for (const auto &provider : CustomImportsProvider::allProviders()) - foreach (const auto &import, provider->imports(valueOwner, document.data())) + for (const auto &provider : CustomImportsProvider::allProviders()) { + const auto providerImports = provider->imports(m_valueOwner, document.data()); + for (const auto &import : providerImports) importCache.insert(ImportCacheKey(import.info), import); + } populateImportedTypes(imports, document); importsPerDocument.insert(document.data(), QSharedPointer<Imports>(imports)); } - foreach (Document::Ptr doc, snapshot) { + for (const Document::Ptr &doc : qAsConst(m_snapshot)) { if (doc == document) continue; - Imports *imports = new Imports(valueOwner); + auto *imports = new Imports(m_valueOwner); populateImportedTypes(imports, doc); importsPerDocument.insert(doc.data(), QSharedPointer<Imports>(imports)); } @@ -226,7 +238,7 @@ Context::ImportsPerDocument LinkPrivate::linkImports() return importsPerDocument; } -void LinkPrivate::populateImportedTypes(Imports *imports, Document::Ptr doc) +void LinkPrivate::populateImportedTypes(Imports *imports, const Document::Ptr &doc) { importableModuleApis.clear(); @@ -239,7 +251,8 @@ void LinkPrivate::populateImportedTypes(Imports *imports, Document::Ptr doc) loadImplicitDirectoryImports(imports, doc); // explicit imports, whether directories, files or libraries - foreach (const ImportInfo &info, doc->bind()->imports()) { + const auto docImports = doc->bind()->imports(); + for (const ImportInfo &info : docImports) { Import import = importCache.value(ImportCacheKey(info)); // ensure usage of the right ImportInfo, the cached import @@ -285,7 +298,7 @@ void LinkPrivate::populateImportedTypes(Imports *imports, Document::Ptr doc) import "file.js" as Foo */ -Import LinkPrivate::importFileOrDirectory(Document::Ptr doc, const ImportInfo &importInfo) +Import LinkPrivate::importFileOrDirectory(const Document::Ptr &doc, const ImportInfo &importInfo) { Import import; import.info = importInfo; @@ -296,20 +309,19 @@ Import LinkPrivate::importFileOrDirectory(Document::Ptr doc, const ImportInfo &i if (importInfo.type() == ImportType::Directory || importInfo.type() == ImportType::ImplicitDirectory) { - import.object = new ObjectValue(valueOwner); + import.object = new ObjectValue(m_valueOwner); importLibrary(doc, path, &import); - const QList<Document::Ptr> &documentsInDirectory = snapshot.documentsInDirectory(path); - foreach (Document::Ptr importedDoc, documentsInDirectory) { + const QList<Document::Ptr> documentsInDirectory = m_snapshot.documentsInDirectory(path); + for (const Document::Ptr &importedDoc : documentsInDirectory) { if (importedDoc->bind()->rootObjectValue()) { const QString targetName = importedDoc->componentName(); import.object->setMember(targetName, importedDoc->bind()->rootObjectValue()); } } } else if (importInfo.type() == ImportType::File) { - Document::Ptr importedDoc = snapshot.document(path); - if (importedDoc) + if (Document::Ptr importedDoc = m_snapshot.document(path)) import.object = importedDoc->bind()->rootObjectValue(); } else if (importInfo.type() == ImportType::QrcFile) { QLocale locale; @@ -318,19 +330,19 @@ Import LinkPrivate::importFileOrDirectory(Document::Ptr doc, const ImportInfo &i if (filePaths.isEmpty()) filePaths = ModelManagerInterface::instance()->filesAtQrcPath(path); if (!filePaths.isEmpty()) { - Document::Ptr importedDoc = snapshot.document(filePaths.at(0)); - if (importedDoc) + if (Document::Ptr importedDoc = m_snapshot.document(filePaths.at(0))) import.object = importedDoc->bind()->rootObjectValue(); } } else if (importInfo.type() == ImportType::QrcDirectory){ - import.object = new ObjectValue(valueOwner); + import.object = new ObjectValue(m_valueOwner); importLibrary(doc, path, &import); - const QMap<QString, QStringList> paths = ModelManagerInterface::instance()->filesInQrcPath(path); + const QMap<QString, QStringList> paths + = ModelManagerInterface::instance()->filesInQrcPath(path); for (auto iter = paths.cbegin(), end = paths.cend(); iter != end; ++iter) { if (ModelManagerInterface::guessLanguageOfFile(iter.key()).isQmlLikeLanguage()) { - Document::Ptr importedDoc = snapshot.document(iter.value().at(0)); + Document::Ptr importedDoc = m_snapshot.document(iter.value().at(0)); if (importedDoc && importedDoc->bind()->rootObjectValue()) { const QString targetName = QFileInfo(iter.key()).baseName(); import.object->setMember(targetName, importedDoc->bind()->rootObjectValue()); @@ -341,10 +353,11 @@ Import LinkPrivate::importFileOrDirectory(Document::Ptr doc, const ImportInfo &i return import; } -static ModuleApiInfo findBestModuleApi(const QList<ModuleApiInfo> &apis, const ComponentVersion &version) +static ModuleApiInfo findBestModuleApi(const QList<ModuleApiInfo> &apis, + const ComponentVersion &version) { ModuleApiInfo best; - foreach (const ModuleApiInfo &moduleApi, apis) { + for (const ModuleApiInfo &moduleApi : apis) { if (moduleApi.version <= version && (!best.version.isValid() || best.version < moduleApi.version)) { best = moduleApi; @@ -357,33 +370,41 @@ static ModuleApiInfo findBestModuleApi(const QList<ModuleApiInfo> &apis, const C import Qt 4.6 import Qt 4.6 as Xxx */ -Import LinkPrivate::importNonFile(Document::Ptr doc, const ImportInfo &importInfo) +Import LinkPrivate::importNonFile(const Document::Ptr &doc, const ImportInfo &importInfo) { Import import; import.info = importInfo; - import.object = new ObjectValue(valueOwner); + import.object = new ObjectValue(m_valueOwner); import.valid = true; const QString packageName = importInfo.name(); const ComponentVersion version = importInfo.version(); - QString libraryPath = modulePath(packageName, version.toString(), importPaths); + QString libraryPath = modulePath(packageName, version.toString(), m_importPaths); bool importFound = !libraryPath.isEmpty() && importLibrary(doc, libraryPath, &import); + if (!importFound) { + for (const QString &dir : qAsConst(m_applicationDirectories)) { + // This adds the types to the C++ types, to be found below if applicable. + if (QFile::exists(dir + "/app.qmltypes")) + importLibrary(doc, dir, &import); + } + } + // if there are cpp-based types for this package, use them too - if (valueOwner->cppQmlTypes().hasModule(packageName)) { + if (m_valueOwner->cppQmlTypes().hasModule(packageName)) { importFound = true; - foreach (const CppComponentValue *object, - valueOwner->cppQmlTypes().createObjectsForImport(packageName, version)) { + const auto objects = m_valueOwner->cppQmlTypes().createObjectsForImport(packageName, + version); + for (const CppComponentValue *object : objects) import.object->setMember(object->className(), object); - } } // check module apis that previous imports may have enabled ModuleApiInfo moduleApi = findBestModuleApi(importableModuleApis.value(packageName), version); if (moduleApi.version.isValid()) { importFound = true; - import.object->setPrototype(valueOwner->cppQmlTypes().objectByCppName(moduleApi.cppName)); + import.object->setPrototype(m_valueOwner->cppQmlTypes().objectByCppName(moduleApi.cppName)); } // TODO: at the moment there is not any types information on Qbs imports. @@ -402,22 +423,21 @@ Import LinkPrivate::importNonFile(Document::Ptr doc, const ImportInfo &importInf "For Qbs projects, declare and set a qmlImportPaths property in your product " "to add import paths.\n" "For qmlproject projects, use the importPaths property to add import paths.\n" - "For CMake projects, make sure QML_IMPORT_PATH variable is in CMakeCache.txt.\n").arg( - importInfo.name(), importPaths.join(QLatin1Char('\n')))); + "For CMake projects, make sure QML_IMPORT_PATH variable is in CMakeCache.txt.\n") + .arg(importInfo.name(), m_importPaths.join(QLatin1Char('\n')))); } return import; } -bool LinkPrivate::importLibrary(Document::Ptr doc, - const QString &libraryPath_, - Import *import, - const QString &importPath) +bool LinkPrivate::importLibrary(const Document::Ptr &doc, + const QString &libraryPath, + Import *import, + const QString &importPath) { const ImportInfo &importInfo = import->info; - QString libraryPath = libraryPath_; - LibraryInfo libraryInfo = snapshot.libraryInfo(libraryPath); + LibraryInfo libraryInfo = m_snapshot.libraryInfo(libraryPath); if (!libraryInfo.isValid()) return false; @@ -446,9 +466,10 @@ bool LinkPrivate::importLibrary(Document::Ptr doc, } } if (errorLoc.isValid()) { - appendDiagnostic(doc, DiagnosticMessage(Severity::ReadingTypeInfoWarning, - errorLoc, - Link::tr("QML module contains C++ plugins, currently reading type information..."))); + appendDiagnostic(doc, DiagnosticMessage( + Severity::ReadingTypeInfoWarning, errorLoc, + Link::tr("QML module contains C++ plugins, " + "currently reading type information..."))); import->valid = false; } } else if (libraryInfo.pluginTypeInfoStatus() == LibraryInfo::DumpError @@ -456,21 +477,25 @@ bool LinkPrivate::importLibrary(Document::Ptr doc, // Only underline import if package isn't described in .qmltypes anyway // and is not a private package QString packageName = importInfo.name(); - if (errorLoc.isValid() && (packageName.isEmpty() || !valueOwner->cppQmlTypes().hasModule(packageName)) + if (errorLoc.isValid() + && (packageName.isEmpty() + || !m_valueOwner->cppQmlTypes().hasModule(packageName)) && !packageName.endsWith(QLatin1String("private"), Qt::CaseInsensitive)) { error(doc, errorLoc, libraryInfo.pluginTypeInfoError()); import->valid = false; } } else { const QString packageName = importInfo.name(); - valueOwner->cppQmlTypes().load(libraryPath, libraryInfo.metaObjects(), packageName); - foreach (const CppComponentValue *object, valueOwner->cppQmlTypes().createObjectsForImport(packageName, version)) { + m_valueOwner->cppQmlTypes().load(libraryPath, libraryInfo.metaObjects(), packageName); + const auto objects = m_valueOwner->cppQmlTypes().createObjectsForImport(packageName, + version); + for (const CppComponentValue *object : objects) import->object->setMember(object->className(), object); - } // all but no-uri module apis become available for import QList<ModuleApiInfo> noUriModuleApis; - foreach (const ModuleApiInfo &moduleApi, libraryInfo.moduleApis()) { + const auto moduleApis = libraryInfo.moduleApis(); + for (const ModuleApiInfo &moduleApi : moduleApis) { if (moduleApi.uri.isEmpty()) noUriModuleApis += moduleApi; else @@ -479,8 +504,10 @@ bool LinkPrivate::importLibrary(Document::Ptr doc, // if a module api has no uri, it shares the same name ModuleApiInfo sameUriModuleApi = findBestModuleApi(noUriModuleApis, version); - if (sameUriModuleApi.version.isValid()) - import->object->setPrototype(valueOwner->cppQmlTypes().objectByCppName(sameUriModuleApi.cppName)); + if (sameUriModuleApi.version.isValid()) { + import->object->setPrototype(m_valueOwner->cppQmlTypes() + .objectByCppName(sameUriModuleApi.cppName)); + } } } @@ -489,12 +516,14 @@ bool LinkPrivate::importLibrary(Document::Ptr doc, return true; } -void LinkPrivate::error(const Document::Ptr &doc, const AST::SourceLocation &loc, const QString &message) +void LinkPrivate::error(const Document::Ptr &doc, const AST::SourceLocation &loc, + const QString &message) { appendDiagnostic(doc, DiagnosticMessage(Severity::Error, loc, message)); } -void LinkPrivate::warning(const Document::Ptr &doc, const AST::SourceLocation &loc, const QString &message) +void LinkPrivate::warning(const Document::Ptr &doc, const AST::SourceLocation &loc, + const QString &message) { appendDiagnostic(doc, DiagnosticMessage(Severity::Warning, loc, message)); } @@ -516,17 +545,17 @@ void LinkPrivate::loadQmldirComponents(ObjectValue *import, ComponentVersion ver QSet<QString> importedTypes; - foreach (const QmlDirParser::Component &component, libraryInfo.components()) { + const auto components = libraryInfo.components(); + for (const QmlDirParser::Component &component : components) { if (importedTypes.contains(component.typeName)) continue; - ComponentVersion componentVersion(component.majorVersion, - component.minorVersion); + ComponentVersion componentVersion(component.majorVersion, component.minorVersion); if (version < componentVersion) continue; importedTypes.insert(component.typeName); - if (Document::Ptr importedDoc = snapshot.document( + if (Document::Ptr importedDoc = m_snapshot.document( libraryPath + QLatin1Char('/') + component.fileName)) { if (ObjectValue *v = importedDoc->bind()->rootObjectValue()) import->setMember(component.typeName, v); @@ -534,7 +563,7 @@ void LinkPrivate::loadQmldirComponents(ObjectValue *import, ComponentVersion ver } } -void LinkPrivate::loadImplicitDirectoryImports(Imports *imports, Document::Ptr doc) +void LinkPrivate::loadImplicitDirectoryImports(Imports *imports, const Document::Ptr &doc) { auto processImport = [this, imports, doc](const ImportInfo &importInfo){ Import directoryImport = importCache.value(ImportCacheKey(importInfo)); @@ -548,8 +577,8 @@ void LinkPrivate::loadImplicitDirectoryImports(Imports *imports, Document::Ptr d }; processImport(ImportInfo::implicitDirectoryImport(doc->path())); - foreach (const QString &path, - ModelManagerInterface::instance()->qrcPathsForFile(doc->fileName())) { + const auto qrcPaths = ModelManagerInterface::instance()->qrcPathsForFile(doc->fileName()); + for (const QString &path : qrcPaths) { processImport(ImportInfo::qrcDirectoryImport( Utils::QrcParser::qrcDirectoryPathForQrcFilePath(path))); } @@ -558,19 +587,21 @@ void LinkPrivate::loadImplicitDirectoryImports(Imports *imports, Document::Ptr d void LinkPrivate::loadImplicitDefaultImports(Imports *imports) { const QString defaultPackage = CppQmlTypes::defaultPackage; - if (valueOwner->cppQmlTypes().hasModule(defaultPackage)) { - const ComponentVersion maxVersion(ComponentVersion::MaxVersion, ComponentVersion::MaxVersion); + if (m_valueOwner->cppQmlTypes().hasModule(defaultPackage)) { + const ComponentVersion maxVersion(ComponentVersion::MaxVersion, + ComponentVersion::MaxVersion); const ImportInfo info = ImportInfo::moduleImport(defaultPackage, maxVersion, QString()); Import import = importCache.value(ImportCacheKey(info)); if (!import.object) { import.valid = true; import.info = info; - import.object = new ObjectValue(valueOwner, QLatin1String("<defaults>")); - foreach (const CppComponentValue *object, - valueOwner->cppQmlTypes().createObjectsForImport( - defaultPackage, maxVersion)) { + import.object = new ObjectValue(m_valueOwner, QLatin1String("<defaults>")); + + const auto objects = m_valueOwner->cppQmlTypes().createObjectsForImport(defaultPackage, + maxVersion); + for (const CppComponentValue *object : objects) import.object->setMember(object->className(), object); - } + importCache.insert(ImportCacheKey(info), import); } imports->append(import); diff --git a/src/libs/qmljs/qmljslink.h b/src/libs/qmljs/qmljslink.h index e4357061b3..78e97c90cf 100644 --- a/src/libs/qmljs/qmljslink.h +++ b/src/libs/qmljs/qmljslink.h @@ -43,10 +43,13 @@ class QMLJS_EXPORT Link Q_DECLARE_TR_FUNCTIONS(QmlJS::Link) public: + Link(Link &&) = delete; + Link &operator=(Link &&) = delete; + Link(const Snapshot &snapshot, const ViewerContext &vContext, const LibraryInfo &builtins); // Link all documents in snapshot, collecting all diagnostic messages (if messages != 0) - ContextPtr operator()(QHash<QString, QList<DiagnosticMessage> > *messages = nullptr); + ContextPtr operator()(QHash<QString, QList<DiagnosticMessage>> *messages = nullptr); // Link all documents in snapshot, appending the diagnostic messages // for 'doc' in 'messages' diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index 4453172e8a..a7f2b3d3ae 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -50,8 +50,6 @@ #include <QtAlgorithms> #include <QLibraryInfo> -#include <stdio.h> - using namespace Utils; namespace QmlJS { @@ -78,8 +76,13 @@ QMLJS_EXPORT Q_LOGGING_CATEGORY(qmljsLog, "qtc.qmljs.common", QtWarningMsg) */ static ModelManagerInterface *g_instance = nullptr; +static const char *qtQuickUISuffix = "ui.qml"; -const char qtQuickUISuffix[] = "ui.qml"; +static void maybeAddPath(ViewerContext &context, const QString &path) +{ + if (!path.isEmpty() && !context.paths.contains(path)) + context.paths.append(path); +} static QStringList environmentImportPaths() { @@ -105,13 +108,15 @@ ModelManagerInterface::ModelManagerInterface(QObject *parent) m_indexerDisabled = qEnvironmentVariableIsSet("QTC_NO_CODE_INDEXER"); m_updateCppQmlTypesTimer = new QTimer(this); - m_updateCppQmlTypesTimer->setInterval(1000); + const int second = 1000; + m_updateCppQmlTypesTimer->setInterval(second); m_updateCppQmlTypesTimer->setSingleShot(true); connect(m_updateCppQmlTypesTimer, &QTimer::timeout, this, &ModelManagerInterface::startCppQmlTypeUpdate); m_asyncResetTimer = new QTimer(this); - m_asyncResetTimer->setInterval(15000); + const int fifteenSeconds = 15000; + m_asyncResetTimer->setInterval(fifteenSeconds); m_asyncResetTimer->setSingleShot(true); connect(m_asyncResetTimer, &QTimer::timeout, this, &ModelManagerInterface::resetCodeModel); @@ -173,7 +178,7 @@ Dialect ModelManagerInterface::guessLanguageOfFile(const QString &fileName) return lMapping.value(fileSuffix, Dialect::NoLanguage); } -QStringList ModelManagerInterface::globPatternsForLanguages(const QList<Dialect> languages) +QStringList ModelManagerInterface::globPatternsForLanguages(const QList<Dialect> &languages) { QStringList patterns; const QHash<QString, Dialect> lMapping = @@ -229,7 +234,7 @@ ModelManagerInterface::WorkingCopy ModelManagerInterface::workingCopyInternal() return res; } -void ModelManagerInterface::addTaskInternal(QFuture<void> result, const QString &msg, +void ModelManagerInterface::addTaskInternal(const QFuture<void> &result, const QString &msg, const char *taskId) const { Q_UNUSED(result) @@ -264,9 +269,9 @@ void ModelManagerInterface::loadQmlTypeDescriptionsInternal(const QString &resou CppQmlTypesLoader::defaultLibraryObjects.unite( CppQmlTypesLoader::loadQmlTypes(qmlTypesFiles, &errors, &warnings)); - foreach (const QString &error, errors) + for (const QString &error : qAsConst(errors)) writeMessageInternal(error); - foreach (const QString &warning, warnings) + for (const QString &warning : qAsConst(warnings)) writeMessageInternal(warning); } @@ -291,7 +296,7 @@ Snapshot ModelManagerInterface::newestSnapshot() const } void ModelManagerInterface::updateSourceFiles(const QStringList &files, - bool emitDocumentOnDiskChanged) + bool emitDocumentOnDiskChanged) { if (m_indexerDisabled) return; @@ -300,10 +305,11 @@ void ModelManagerInterface::updateSourceFiles(const QStringList &files, void ModelManagerInterface::cleanupFutures() { - if (m_futures.size() > 10) { - QList<QFuture<void> > futures = m_futures; + const int maxFutures = 10; + if (m_futures.size() > maxFutures) { + const QList<QFuture<void>> futures = m_futures; m_futures.clear(); - foreach (const QFuture<void> &future, futures) { + for (const QFuture<void> &future : futures) { if (!(future.isFinished() || future.isCanceled())) m_futures.append(future); } @@ -311,7 +317,7 @@ void ModelManagerInterface::cleanupFutures() } QFuture<void> ModelManagerInterface::refreshSourceFiles(const QStringList &sourceFiles, - bool emitDocumentOnDiskChanged) + bool emitDocumentOnDiskChanged) { if (sourceFiles.isEmpty()) return QFuture<void>(); @@ -356,14 +362,15 @@ void ModelManagerInterface::removeFiles(const QStringList &files) QMutexLocker locker(&m_mutex); - foreach (const QString &file, files) { + for (const QString &file : files) { m_validSnapshot.remove(file); m_newestSnapshot.remove(file); } } namespace { -bool pInfoLessThanActive(const ModelManagerInterface::ProjectInfo &p1, const ModelManagerInterface::ProjectInfo &p2) +bool pInfoLessThanActive(const ModelManagerInterface::ProjectInfo &p1, + const ModelManagerInterface::ProjectInfo &p2) { QStringList s1 = p1.activeResourceFiles; QStringList s2 = p2.activeResourceFiles; @@ -374,13 +381,14 @@ bool pInfoLessThanActive(const ModelManagerInterface::ProjectInfo &p1, const Mod for (int i = 0; i < s1.size(); ++i) { if (s1.at(i) < s2.at(i)) return true; - else if (s1.at(i) > s2.at(i)) + if (s1.at(i) > s2.at(i)) return false; } return false; } -bool pInfoLessThanAll(const ModelManagerInterface::ProjectInfo &p1, const ModelManagerInterface::ProjectInfo &p2) +bool pInfoLessThanAll(const ModelManagerInterface::ProjectInfo &p1, + const ModelManagerInterface::ProjectInfo &p2) { QStringList s1 = p1.allResourceFiles; QStringList s2 = p2.allResourceFiles; @@ -391,13 +399,14 @@ bool pInfoLessThanAll(const ModelManagerInterface::ProjectInfo &p1, const ModelM for (int i = 0; i < s1.size(); ++i) { if (s1.at(i) < s2.at(i)) return true; - else if (s1.at(i) > s2.at(i)) + if (s1.at(i) > s2.at(i)) return false; } return false; } -bool pInfoLessThanImports(const ModelManagerInterface::ProjectInfo &p1, const ModelManagerInterface::ProjectInfo &p2) +bool pInfoLessThanImports(const ModelManagerInterface::ProjectInfo &p1, + const ModelManagerInterface::ProjectInfo &p2) { if (p1.qtQmlPath < p2.qtQmlPath) return true; @@ -412,7 +421,7 @@ bool pInfoLessThanImports(const ModelManagerInterface::ProjectInfo &p1, const Mo for (int i = 0; i < s1.size(); ++i) { if (s1.at(i) < s2.at(i)) return true; - else if (s2.at(i) < s1.at(i)) + if (s2.at(i) < s1.at(i)) return false; } return false; @@ -420,9 +429,9 @@ bool pInfoLessThanImports(const ModelManagerInterface::ProjectInfo &p1, const Mo } -void ModelManagerInterface::iterateQrcFiles(ProjectExplorer::Project *project, - QrcResourceSelector resources, - std::function<void(QrcParser::ConstPtr)> callback) +void ModelManagerInterface::iterateQrcFiles( + ProjectExplorer::Project *project, QrcResourceSelector resources, + const std::function<void(QrcParser::ConstPtr)> &callback) { QList<ProjectInfo> pInfos; if (project) { @@ -436,13 +445,13 @@ void ModelManagerInterface::iterateQrcFiles(ProjectExplorer::Project *project, } QSet<QString> pathsChecked; - foreach (const ModelManagerInterface::ProjectInfo &pInfo, pInfos) { + for (const ModelManagerInterface::ProjectInfo &pInfo : qAsConst(pInfos)) { QStringList qrcFilePaths; if (resources == ActiveQrcResources) qrcFilePaths = pInfo.activeResourceFiles; else qrcFilePaths = pInfo.allResourceFiles; - foreach (const QString &qrcFilePath, qrcFilePaths) { + for (const QString &qrcFilePath : qAsConst(qrcFilePaths)) { if (pathsChecked.contains(qrcFilePath)) continue; pathsChecked.insert(qrcFilePath); @@ -459,7 +468,7 @@ QStringList ModelManagerInterface::qrcPathsForFile(const QString &file, const QL QrcResourceSelector resources) { QStringList res; - iterateQrcFiles(project, resources, [&](QrcParser::ConstPtr qrcFile) { + iterateQrcFiles(project, resources, [&](const QrcParser::ConstPtr &qrcFile) { qrcFile->collectResourceFilesForSourceFile(file, &res, locale); }); return res; @@ -471,7 +480,7 @@ QStringList ModelManagerInterface::filesAtQrcPath(const QString &path, const QLo { QString normPath = QrcParser::normalizedQrcFilePath(path); QStringList res; - iterateQrcFiles(project, resources, [&](QrcParser::ConstPtr qrcFile) { + iterateQrcFiles(project, resources, [&](const QrcParser::ConstPtr &qrcFile) { qrcFile->collectFilesAtPath(normPath, &res, locale); }); return res; @@ -485,7 +494,7 @@ QMap<QString, QStringList> ModelManagerInterface::filesInQrcPath(const QString & { QString normPath = QrcParser::normalizedQrcDirectoryPath(path); QMap<QString, QStringList> res; - iterateQrcFiles(project, resources, [&](QrcParser::ConstPtr qrcFile) { + iterateQrcFiles(project, resources, [&](const QrcParser::ConstPtr &qrcFile) { qrcFile->collectFilesInPath(normPath, &res, addDirs, locale); }); return res; @@ -498,18 +507,22 @@ QList<ModelManagerInterface::ProjectInfo> ModelManagerInterface::projectInfos() return m_projects.values(); } -ModelManagerInterface::ProjectInfo ModelManagerInterface::projectInfo( - ProjectExplorer::Project *project, - const ModelManagerInterface::ProjectInfo &defaultValue) const +bool ModelManagerInterface::containsProject(ProjectExplorer::Project *project) const { QMutexLocker locker(&m_mutex); + return m_projects.contains(project); +} - return m_projects.value(project, defaultValue); +ModelManagerInterface::ProjectInfo ModelManagerInterface::projectInfo( + ProjectExplorer::Project *project) const +{ + QMutexLocker locker(&m_mutex); + return m_projects.value(project); } void ModelManagerInterface::updateProjectInfo(const ProjectInfo &pinfo, ProjectExplorer::Project *p) { - if (! pinfo.isValid() || !p || m_indexerDisabled) + if (pinfo.project.isNull() || !p || m_indexerDisabled) return; Snapshot snapshot; @@ -533,7 +546,7 @@ void ModelManagerInterface::updateProjectInfo(const ProjectInfo &pinfo, ProjectE // remove files that are no longer in the project and have been deleted QStringList deletedFiles; - foreach (const QString &oldFile, oldInfo.sourceFiles) { + for (const QString &oldFile : qAsConst(oldInfo.sourceFiles)) { if (snapshot.document(oldFile) && !pinfo.sourceFiles.contains(oldFile) && !QFile::exists(oldFile)) { @@ -541,38 +554,27 @@ void ModelManagerInterface::updateProjectInfo(const ProjectInfo &pinfo, ProjectE } } removeFiles(deletedFiles); - foreach (const QString &oldFile, deletedFiles) + for (const QString &oldFile : qAsConst(deletedFiles)) m_fileToProject.remove(oldFile, p); // parse any files not yet in the snapshot QStringList newFiles; - foreach (const QString &file, pinfo.sourceFiles) { + for (const QString &file : qAsConst(pinfo.sourceFiles)) { if (!snapshot.document(file)) newFiles += file; } - foreach (const QString &newFile, newFiles) + for (const QString &newFile : qAsConst(newFiles)) m_fileToProject.insert(newFile, p); updateSourceFiles(newFiles, false); // update qrc cache m_qrcContents = pinfo.resourceFileContents; - foreach (const QString &newQrc, pinfo.allResourceFiles) + for (const QString &newQrc : qAsConst(pinfo.allResourceFiles)) m_qrcCache.addPath(newQrc, m_qrcContents.value(newQrc)); - foreach (const QString &oldQrc, oldInfo.allResourceFiles) + for (const QString &oldQrc : qAsConst(oldInfo.allResourceFiles)) m_qrcCache.removePath(oldQrc); - int majorVersion, minorVersion, patchVersion; - // dump builtin types if the shipped definitions are probably outdated and the - // Qt version ships qmlplugindump - if (::sscanf(pinfo.qtVersionString.toLatin1().constData(), "%d.%d.%d", - &majorVersion, &minorVersion, &patchVersion) != 3) - majorVersion = minorVersion = patchVersion = -1; - - if (majorVersion > 4 || (majorVersion == 4 && (minorVersion > 8 || (minorVersion == 8 - && patchVersion >= 5)))) { - m_pluginDumper->loadBuiltinTypes(pinfo); - } - + m_pluginDumper->loadBuiltinTypes(pinfo); emit projectInfoUpdated(pinfo); } @@ -595,22 +597,27 @@ void ModelManagerInterface::removeProjectInfo(ProjectExplorer::Project *project) \note Project pointer will be empty */ -ModelManagerInterface::ProjectInfo ModelManagerInterface::projectInfoForPath(const QString &path) const +ModelManagerInterface::ProjectInfo ModelManagerInterface::projectInfoForPath( + const QString &path) const { ProjectInfo res; - foreach (const ProjectInfo &pInfo, allProjectInfosForPath(path)) { + const auto allProjectInfos = allProjectInfosForPath(path); + for (const ProjectInfo &pInfo : allProjectInfos) { if (res.qtQmlPath.isEmpty()) res.qtQmlPath = pInfo.qtQmlPath; - for (int i = 0; i < pInfo.importPaths.size(); ++i) - res.importPaths.maybeInsert(pInfo.importPaths.at(i)); + res.applicationDirectories.append(pInfo.applicationDirectories); + for (const auto &importPath : pInfo.importPaths) + res.importPaths.maybeInsert(importPath); } + res.applicationDirectories = Utils::filteredUnique(res.applicationDirectories); return res; } /*! Returns list of project infos for \a path */ -QList<ModelManagerInterface::ProjectInfo> ModelManagerInterface::allProjectInfosForPath(const QString &path) const +QList<ModelManagerInterface::ProjectInfo> ModelManagerInterface::allProjectInfosForPath( + const QString &path) const { QList<ProjectExplorer::Project *> projects; { @@ -622,9 +629,9 @@ QList<ModelManagerInterface::ProjectInfo> ModelManagerInterface::allProjectInfos } } QList<ProjectInfo> infos; - foreach (ProjectExplorer::Project *project, projects) { + for (ProjectExplorer::Project *project : qAsConst(projects)) { ProjectInfo info = projectInfo(project); - if (info.isValid()) + if (!info.project.isNull()) infos.append(info); } std::sort(infos.begin(), infos.end(), &pInfoLessThanImports); @@ -638,14 +645,16 @@ bool ModelManagerInterface::isIdle() const } void ModelManagerInterface::emitDocumentChangedOnDisk(Document::Ptr doc) -{ emit documentChangedOnDisk(doc); } +{ + emit documentChangedOnDisk(std::move(doc)); +} void ModelManagerInterface::updateQrcFile(const QString &path) { m_qrcCache.updatePath(path, m_qrcContents.value(path)); } -void ModelManagerInterface::updateDocument(Document::Ptr doc) +void ModelManagerInterface::updateDocument(const Document::Ptr &doc) { { QMutexLocker locker(&m_mutex); @@ -670,27 +679,29 @@ void ModelManagerInterface::updateLibraryInfo(const QString &path, const Library emit libraryInfoUpdated(path, info); } -static QStringList filesInDirectoryForLanguages(const QString &path, QList<Dialect> languages) +static QStringList filesInDirectoryForLanguages(const QString &path, + const QList<Dialect> &languages) { const QStringList pattern = ModelManagerInterface::globPatternsForLanguages(languages); QStringList files; const QDir dir(path); - foreach (const QFileInfo &fi, dir.entryInfoList(pattern, QDir::Files)) + const auto entries = dir.entryInfoList(pattern, QDir::Files); + for (const QFileInfo &fi : entries) files += fi.absoluteFilePath(); return files; } static void findNewImplicitImports(const Document::Ptr &doc, const Snapshot &snapshot, - QStringList *importedFiles, QSet<QString> *scannedPaths) + QStringList *importedFiles, QSet<QString> *scannedPaths) { // scan files that could be implicitly imported // it's important we also do this for JS files, otherwise the isEmpty check will fail if (snapshot.documentsInDirectory(doc->path()).isEmpty()) { - if (! scannedPaths->contains(doc->path())) { + if (!scannedPaths->contains(doc->path())) { *importedFiles += filesInDirectoryForLanguages(doc->path(), - doc->language().companionLanguages()); + doc->language().companionLanguages()); scannedPaths->insert(doc->path()); } } @@ -700,7 +711,8 @@ static void findNewFileImports(const Document::Ptr &doc, const Snapshot &snapsho QStringList *importedFiles, QSet<QString> *scannedPaths) { // scan files and directories that are explicitly imported - foreach (const ImportInfo &import, doc->bind()->imports()) { + const auto imports = doc->bind()->imports(); + for (const ImportInfo &import : imports) { const QString &importName = import.path(); if (import.type() == ImportType::File) { if (! snapshot.document(importName)) @@ -708,24 +720,26 @@ static void findNewFileImports(const Document::Ptr &doc, const Snapshot &snapsho } else if (import.type() == ImportType::Directory) { if (snapshot.documentsInDirectory(importName).isEmpty()) { if (! scannedPaths->contains(importName)) { - *importedFiles += filesInDirectoryForLanguages(importName, - doc->language().companionLanguages()); + *importedFiles += filesInDirectoryForLanguages( + importName, doc->language().companionLanguages()); scannedPaths->insert(importName); } } } else if (import.type() == ImportType::QrcFile) { - QStringList importPaths = ModelManagerInterface::instance()->filesAtQrcPath(importName); - foreach (const QString &importPath, importPaths) { - if (! snapshot.document(importPath)) + const QStringList importPaths + = ModelManagerInterface::instance()->filesAtQrcPath(importName); + for (const QString &importPath : importPaths) { + if (!snapshot.document(importPath)) *importedFiles += importPath; } } else if (import.type() == ImportType::QrcDirectory) { - const QMap<QString, QStringList> files = ModelManagerInterface::instance()->filesInQrcPath(importName); - for (auto dirContents = files.cbegin(), end = files.cend(); dirContents != end; ++dirContents) { - if (ModelManagerInterface::guessLanguageOfFile(dirContents.key()).isQmlLikeOrJsLanguage()) { - foreach (const QString &filePath, dirContents.value()) { - if (! snapshot.document(filePath)) - *importedFiles += filePath; + const QMap<QString, QStringList> files + = ModelManagerInterface::instance()->filesInQrcPath(importName); + for (auto qrc = files.cbegin(), end = files.cend(); qrc != end; ++qrc) { + if (ModelManagerInterface::guessLanguageOfFile(qrc.key()).isQmlLikeOrJsLanguage()) { + for (const QString &sourceFile : qrc.value()) { + if (!snapshot.document(sourceFile)) + *importedFiles += sourceFile; } } } @@ -733,6 +747,55 @@ static void findNewFileImports(const Document::Ptr &doc, const Snapshot &snapsho } } +enum class LibraryStatus { + Accepted, + Rejected, + Unknown +}; + +static LibraryStatus libraryStatus(const QString &path, const Snapshot &snapshot, + QSet<QString> *newLibraries) +{ + if (path.isEmpty()) + return LibraryStatus::Rejected; + // if we know there is a library, done + const LibraryInfo &existingInfo = snapshot.libraryInfo(path); + if (existingInfo.isValid()) + return LibraryStatus::Accepted; + if (newLibraries->contains(path)) + return LibraryStatus::Accepted; + // if we looked at the path before, done + return existingInfo.wasScanned() + ? LibraryStatus::Rejected + : LibraryStatus::Unknown; +} + +static bool findNewQmlApplicationInPath(const QString &path, + const Snapshot &snapshot, + ModelManagerInterface *modelManager, + QSet<QString> *newLibraries) +{ + switch (libraryStatus(path, snapshot, newLibraries)) { + case LibraryStatus::Accepted: return true; + case LibraryStatus::Rejected: return false; + default: break; + } + + const QDir dir(path); + const QLatin1String appQmltypes("app.qmltypes"); + QFile appQmltypesFile(dir.filePath(appQmltypes)); + if (!appQmltypesFile.exists()) + return false; + + LibraryInfo libraryInfo = LibraryInfo(QmlDirParser::TypeInfo(appQmltypes)); + const QString libraryPath = dir.absolutePath(); + newLibraries->insert(libraryPath); + modelManager->updateLibraryInfo(path, libraryInfo); + modelManager->loadPluginTypes(QFileInfo(libraryPath).canonicalFilePath(), libraryPath, + QString(), QString()); + return true; +} + static bool findNewQmlLibraryInPath(const QString &path, const Snapshot &snapshot, ModelManagerInterface *modelManager, @@ -741,15 +804,11 @@ static bool findNewQmlLibraryInPath(const QString &path, QSet<QString> *newLibraries, bool ignoreMissing) { - // if we know there is a library, done - const LibraryInfo &existingInfo = snapshot.libraryInfo(path); - if (existingInfo.isValid()) - return true; - if (newLibraries->contains(path)) - return true; - // if we looked at the path before, done - if (existingInfo.wasScanned()) - return false; + switch (libraryStatus(path, snapshot, newLibraries)) { + case LibraryStatus::Accepted: return true; + case LibraryStatus::Rejected: return false; + default: break; + } const QDir dir(path); QFile qmldirFile(dir.filePath(QLatin1String("qmldir"))); @@ -780,13 +839,14 @@ static bool findNewQmlLibraryInPath(const QString &path, QString(), QString()); // scan the qml files in the library - foreach (const QmlDirParser::Component &component, qmldirParser.components()) { - if (! component.fileName.isEmpty()) { + const auto components = qmldirParser.components(); + for (const QmlDirParser::Component &component : components) { + if (!component.fileName.isEmpty()) { const QFileInfo componentFileInfo(dir.filePath(component.fileName)); const QString path = QDir::cleanPath(componentFileInfo.absolutePath()); - if (! scannedPaths->contains(path)) { - *importedFiles += filesInDirectoryForLanguages(path, - Dialect(Dialect::AnyLanguage).companionLanguages()); + if (!scannedPaths->contains(path)) { + *importedFiles += filesInDirectoryForLanguages(path, Dialect(Dialect::AnyLanguage) + .companionLanguages()); scannedPaths->insert(path); } } @@ -803,8 +863,8 @@ static QString modulePath(const ImportInfo &import, const QStringList &paths) } static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snapshot, - ModelManagerInterface *modelManager, - QStringList *importedFiles, QSet<QString> *scannedPaths, QSet<QString> *newLibraries) + ModelManagerInterface *modelManager, QStringList *importedFiles, + QSet<QString> *scannedPaths, QSet<QString> *newLibraries) { // scan current dir findNewQmlLibraryInPath(doc->path(), snapshot, modelManager, @@ -812,31 +872,31 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap // scan dir and lib imports const QStringList importPaths = modelManager->importPathsNames(); - foreach (const ImportInfo &import, doc->bind()->imports()) { - if (import.type() == ImportType::Directory) { - const QString targetPath = import.path(); - findNewQmlLibraryInPath(targetPath, snapshot, modelManager, + const auto imports = doc->bind()->imports(); + for (const ImportInfo &import : imports) { + switch (import.type()) { + case ImportType::Directory: + findNewQmlLibraryInPath(import.path(), snapshot, modelManager, importedFiles, scannedPaths, newLibraries, false); - } - - if (import.type() == ImportType::Library) { - const QString libraryPath = modulePath(import, importPaths); - if (libraryPath.isEmpty()) - continue; - findNewQmlLibraryInPath(libraryPath, snapshot, modelManager, importedFiles, - scannedPaths, newLibraries, false); + break; + case ImportType::Library: + findNewQmlLibraryInPath(modulePath(import, importPaths), snapshot, modelManager, + importedFiles, scannedPaths, newLibraries, false); + break; + default: + break; } } } void ModelManagerInterface::parseLoop(QSet<QString> &scannedPaths, - QSet<QString> &newLibraries, - WorkingCopy workingCopy, - QStringList files, - ModelManagerInterface *modelManager, - Dialect mainLanguage, - bool emitDocChangedOnDisk, - std::function<bool(qreal)> reportProgress) + QSet<QString> &newLibraries, + const WorkingCopy &workingCopy, + QStringList files, + ModelManagerInterface *modelManager, + Dialect mainLanguage, + bool emitDocChangedOnDisk, + const std::function<bool(qreal)> &reportProgress) { for (int i = 0; i < files.size(); ++i) { if (!reportProgress(qreal(i) / files.size())) @@ -889,11 +949,12 @@ void ModelManagerInterface::parseLoop(QSet<QString> &scannedPaths, QStringList importedFiles; findNewImplicitImports(doc, snapshot, &importedFiles, &scannedPaths); findNewFileImports(doc, snapshot, &importedFiles, &scannedPaths); - findNewLibraryImports(doc, snapshot, modelManager, &importedFiles, &scannedPaths, &newLibraries); + findNewLibraryImports(doc, snapshot, modelManager, &importedFiles, &scannedPaths, + &newLibraries); // add new files to parse list - foreach (const QString &file, importedFiles) { - if (! files.contains(file)) + for (const QString &file : qAsConst(importedFiles)) { + if (!files.contains(file)) files.append(file); } @@ -906,9 +967,10 @@ void ModelManagerInterface::parseLoop(QSet<QString> &scannedPaths, class FutureReporter { public: - FutureReporter(QFutureInterface<void> &future, int multiplier = 100, int base = 0) - :future(future), multiplier(multiplier), base(base) - { } + FutureReporter(QFutureInterface<void> &future, int multiplier, int base) + : future(future), multiplier(multiplier), base(base) + {} + bool operator()(qreal val) { if (future.isCanceled()) @@ -923,37 +985,36 @@ private: }; void ModelManagerInterface::parse(QFutureInterface<void> &future, - WorkingCopy workingCopy, - QStringList files, - ModelManagerInterface *modelManager, - Dialect mainLanguage, - bool emitDocChangedOnDisk) + const WorkingCopy &workingCopy, + QStringList files, + ModelManagerInterface *modelManager, + Dialect mainLanguage, + bool emitDocChangedOnDisk) { - FutureReporter reporter(future); - future.setProgressRange(0, 100); + const int progressMax = 100; + FutureReporter reporter(future, progressMax, 0); + future.setProgressRange(0, progressMax); // paths we have scanned for files and added to the files list QSet<QString> scannedPaths; // libraries we've found while scanning imports QSet<QString> newLibraries; - parseLoop(scannedPaths, newLibraries, workingCopy, files, modelManager, mainLanguage, + parseLoop(scannedPaths, newLibraries, workingCopy, std::move(files), modelManager, mainLanguage, emitDocChangedOnDisk, reporter); - future.setProgressValue(100); + future.setProgressValue(progressMax); } struct ScanItem { QString path; - int depth; - Dialect language; - ScanItem(QString path = QString(), int depth = 0, Dialect language = Dialect::AnyLanguage) - : path(path), depth(depth), language(language) - { } + int depth = 0; + Dialect language = Dialect::AnyLanguage; }; void ModelManagerInterface::importScan(QFutureInterface<void> &future, - ModelManagerInterface::WorkingCopy workingCopy, - PathsAndLanguages paths, ModelManagerInterface *modelManager, - bool emitDocChangedOnDisk, bool libOnly, bool forceRescan) + const ModelManagerInterface::WorkingCopy &workingCopy, + const PathsAndLanguages &paths, + ModelManagerInterface *modelManager, + bool emitDocChangedOnDisk, bool libOnly, bool forceRescan) { // paths we have scanned for files and added to the files list QSet<QString> scannedPaths; @@ -968,18 +1029,18 @@ void ModelManagerInterface::importScan(QFutureInterface<void> &future, pathsToScan.reserve(paths.size()); { QMutexLocker l(&modelManager->m_mutex); - for (int i = 0; i < paths.size(); ++i) { - PathAndLanguage pAndL = paths.at(i); - QString cPath = QDir::cleanPath(pAndL.path().toString()); + for (const auto &path : paths) { + QString cPath = QDir::cleanPath(path.path().toString()); if (!forceRescan && modelManager->m_scannedPaths.contains(cPath)) continue; - pathsToScan.append(ScanItem(cPath, 0, pAndL.language())); + pathsToScan.append({cPath, 0, path.language()}); modelManager->m_scannedPaths.insert(cPath); } } const int maxScanDepth = 5; int progressRange = pathsToScan.size() * (1 << (2 + maxScanDepth)); - int totalWork(progressRange), workDone(0); + int totalWork = progressRange; + int workDone = 0; future.setProgressRange(0, progressRange); // update max length while iterating? const Snapshot snapshot = modelManager->snapshot(); bool isCanceled = future.isCanceled(); @@ -991,10 +1052,10 @@ void ModelManagerInterface::importScan(QFutureInterface<void> &future, QStringList importedFiles; if (forceRescan || (!findNewQmlLibraryInPath(toScan.path, snapshot, modelManager, &importedFiles, - &scannedPaths, &newLibraries, true) + &scannedPaths, &newLibraries, true) && !libOnly && snapshot.documentsInDirectory(toScan.path).isEmpty())) { importedFiles += filesInDirectoryForLanguages(toScan.path, - toScan.language.companionLanguages()); + toScan.language.companionLanguages()); } workDone += 1; future.setProgressValue(progressRange * workDone / totalWork); @@ -1016,8 +1077,8 @@ void ModelManagerInterface::importScan(QFutureInterface<void> &future, QStringList subDirs(dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)); workDone += 1; totalWork += pathBudget / 2 * subDirs.size() - pathBudget * 3 / 4 + 1; - foreach (const QString path, subDirs) - pathsToScan.append(ScanItem(dir.absoluteFilePath(path), toScan.depth + 1, toScan.language)); + for (const QString &path : qAsConst(subDirs)) + pathsToScan.append({dir.absoluteFilePath(path), toScan.depth + 1, toScan.language}); } else { workDone += pathBudget * 3 / 4; } @@ -1028,8 +1089,8 @@ void ModelManagerInterface::importScan(QFutureInterface<void> &future, if (isCanceled) { // assume no work has been done QMutexLocker l(&modelManager->m_mutex); - for (int i = 0; i < paths.size(); ++i) - modelManager->m_scannedPaths.remove(paths.at(i).path().toString()); + for (const auto &path : paths) + modelManager->m_scannedPaths.remove(path.path().toString()); } } @@ -1062,7 +1123,7 @@ void ModelManagerInterface::maybeScan(const PathsAndLanguages &importPaths) PathsAndLanguages pathToScan; { QMutexLocker l(&m_mutex); - foreach (const PathAndLanguage &importPath, importPaths) + for (const PathAndLanguage &importPath : importPaths) if (!m_scannedPaths.contains(importPath.path().toString())) pathToScan.maybeInsert(importPath); } @@ -1083,48 +1144,56 @@ void ModelManagerInterface::updateImportPaths() if (m_indexerDisabled) return; PathsAndLanguages allImportPaths; + QStringList allApplicationDirectories; QmlLanguageBundles activeBundles; QmlLanguageBundles extendedBundles; - for (auto pInfoIter = m_projects.cbegin(), end = m_projects.cend(); pInfoIter != end; ++pInfoIter) { - const PathsAndLanguages &iPaths = pInfoIter.value().importPaths; - for (int i = 0; i < iPaths.size(); ++i) { - PathAndLanguage pAndL = iPaths.at(i); - const QString canonicalPath = pAndL.path().toFileInfo().canonicalFilePath(); - if (!canonicalPath.isEmpty()) + for (const ProjectInfo &pInfo : qAsConst(m_projects)) { + for (const auto &importPath : pInfo.importPaths) { + const QString canonicalPath = importPath.path().toFileInfo().canonicalFilePath(); + if (!canonicalPath.isEmpty()) { allImportPaths.maybeInsert(Utils::FilePath::fromString(canonicalPath), - pAndL.language()); + importPath.language()); + } } + allApplicationDirectories.append(pInfo.applicationDirectories); } - for (auto vCtxsIter = m_defaultVContexts.cbegin(), end = m_defaultVContexts.cend(); - vCtxsIter != end; ++ vCtxsIter) { - foreach (const QString &path, vCtxsIter.value().paths) - allImportPaths.maybeInsert(Utils::FilePath::fromString(path), vCtxsIter.value().language); + + for (const ViewerContext &vContext : qAsConst(m_defaultVContexts)) { + for (const QString &path : vContext.paths) + allImportPaths.maybeInsert(Utils::FilePath::fromString(path), vContext.language); + allApplicationDirectories.append(vContext.applicationDirectories); } - for (auto pInfoIter = m_projects.cbegin(), end = m_projects.cend(); pInfoIter != end; ++pInfoIter) { - activeBundles.mergeLanguageBundles(pInfoIter.value().activeBundle); - foreach (Dialect l, pInfoIter.value().activeBundle.languages()) { - foreach (const QString &path, pInfoIter.value().activeBundle.bundleForLanguage(l) - .searchPaths().stringList()) { + + for (const ProjectInfo &pInfo : qAsConst(m_projects)) { + activeBundles.mergeLanguageBundles(pInfo.activeBundle); + const auto languages = pInfo.activeBundle.languages(); + for (Dialect l : languages) { + const auto paths = pInfo.activeBundle.bundleForLanguage(l).searchPaths().stringList(); + for (const QString &path : paths) { const QString canonicalPath = QFileInfo(path).canonicalFilePath(); if (!canonicalPath.isEmpty()) allImportPaths.maybeInsert(Utils::FilePath::fromString(canonicalPath), l); } } } - for (auto pInfoIter = m_projects.cbegin(), end = m_projects.cend(); pInfoIter != end; ++pInfoIter) { - QString pathAtt = pInfoIter.value().qtQmlPath; - if (!pathAtt.isEmpty()) - allImportPaths.maybeInsert(Utils::FilePath::fromString(pathAtt), Dialect::QmlQtQuick2); + + for (const ProjectInfo &pInfo : qAsConst(m_projects)) { + if (!pInfo.qtQmlPath.isEmpty()) { + allImportPaths.maybeInsert(Utils::FilePath::fromString(pInfo.qtQmlPath), + Dialect::QmlQtQuick2); + } } + { - QString pathAtt = defaultProjectInfo().qtQmlPath; + const QString pathAtt = defaultProjectInfo().qtQmlPath; if (!pathAtt.isEmpty()) allImportPaths.maybeInsert(Utils::FilePath::fromString(pathAtt), Dialect::QmlQtQuick2); } - foreach (const QString &path, m_defaultImportPaths) + for (const QString &path : qAsConst(m_defaultImportPaths)) allImportPaths.maybeInsert(Utils::FilePath::fromString(path), Dialect::Qml); allImportPaths.compact(); + allApplicationDirectories = Utils::filteredUnique(allApplicationDirectories); { QMutexLocker l(&m_mutex); @@ -1139,8 +1208,10 @@ void ModelManagerInterface::updateImportPaths() QStringList importedFiles; QSet<QString> scannedPaths; QSet<QString> newLibraries; - foreach (const Document::Ptr &doc, snapshot) + for (const Document::Ptr &doc : qAsConst(snapshot)) findNewLibraryImports(doc, snapshot, this, &importedFiles, &scannedPaths, &newLibraries); + for (const QString &path : allApplicationDirectories) + findNewQmlApplicationInPath(path, snapshot, this, &newLibraries); updateSourceFiles(importedFiles, true); @@ -1224,13 +1295,14 @@ bool rescanExports(const QString &fileName, FindExportedCppTypes &finder, } else { ModelManagerInterface::CppData &data = newData[fileName]; if (!hasNewInfo && (data.exportedTypes.size() != exported.size() - || data.contextProperties != contextProperties)) + || data.contextProperties != contextProperties)) { hasNewInfo = true; + } if (!hasNewInfo) { QHash<QString, QByteArray> newFingerprints; - foreach (LanguageUtils::FakeMetaObject::ConstPtr newType, exported) + for (const auto &newType : qAsConst(exported)) newFingerprints[newType->className()]=newType->fingerprint(); - foreach (LanguageUtils::FakeMetaObject::ConstPtr oldType, data.exportedTypes) { + for (const auto &oldType : qAsConst(data.exportedTypes)) { if (newFingerprints.value(oldType->className()) != oldType->fingerprint()) { hasNewInfo = true; break; @@ -1243,16 +1315,16 @@ bool rescanExports(const QString &fileName, FindExportedCppTypes &finder, return hasNewInfo; } -void ModelManagerInterface::updateCppQmlTypes(QFutureInterface<void> &futureInterface, - ModelManagerInterface *qmlModelManager, - CPlusPlus::Snapshot snapshot, - QHash<QString, QPair<CPlusPlus::Document::Ptr, bool> > documents) +void ModelManagerInterface::updateCppQmlTypes( + QFutureInterface<void> &futureInterface, ModelManagerInterface *qmlModelManager, + const CPlusPlus::Snapshot &snapshot, + const QHash<QString, QPair<CPlusPlus::Document::Ptr, bool>> &documents) { futureInterface.setProgressRange(0, documents.size()); futureInterface.setProgressValue(0); CppDataHash newData; - QHash<QString, QList<CPlusPlus::Document::Ptr> > newDeclarations; + QHash<QString, QList<CPlusPlus::Document::Ptr>> newDeclarations; { QMutexLocker locker(&qmlModelManager->m_cppDataMutex); newData = qmlModelManager->m_cppDataHash; @@ -1262,8 +1334,8 @@ void ModelManagerInterface::updateCppQmlTypes(QFutureInterface<void> &futureInte FindExportedCppTypes finder(snapshot); bool hasNewInfo = false; - typedef QPair<CPlusPlus::Document::Ptr, bool> DocScanPair; - foreach (const DocScanPair &pair, documents) { + using DocScanPair = QPair<CPlusPlus::Document::Ptr, bool>; + for (const DocScanPair &pair : documents) { if (futureInterface.isCanceled()) return; futureInterface.setProgressValue(futureInterface.progressValue() + 1); @@ -1273,7 +1345,8 @@ void ModelManagerInterface::updateCppQmlTypes(QFutureInterface<void> &futureInte const QString fileName = doc->fileName(); if (!scan) { hasNewInfo = newData.remove(fileName) > 0 || hasNewInfo; - foreach (const CPlusPlus::Document::Ptr &savedDoc, newDeclarations.value(fileName)) { + const auto savedDocs = newDeclarations.value(fileName); + for (const CPlusPlus::Document::Ptr &savedDoc : savedDocs) { finder(savedDoc); hasNewInfo = rescanExports(savedDoc->fileName(), finder, newData) || hasNewInfo; } @@ -1282,14 +1355,13 @@ void ModelManagerInterface::updateCppQmlTypes(QFutureInterface<void> &futureInte for (auto it = newDeclarations.begin(), end = newDeclarations.end(); it != end;) { for (auto docIt = it->begin(), endDocIt = it->end(); docIt != endDocIt;) { - CPlusPlus::Document::Ptr &savedDoc = *docIt; + const CPlusPlus::Document::Ptr &savedDoc = *docIt; if (savedDoc->fileName() == fileName) { savedDoc->releaseSourceAndAST(); it->erase(docIt); break; - } else { - ++docIt; } + ++docIt; } if (it->isEmpty()) it = newDeclarations.erase(it); @@ -1297,7 +1369,8 @@ void ModelManagerInterface::updateCppQmlTypes(QFutureInterface<void> &futureInte ++it; } - foreach (const QString &declarationFile, finder(doc)) { + const auto found = finder(doc); + for (const QString &declarationFile : found) { newDeclarations[declarationFile].append(doc); doc->keepSourceAndAST(); // keep for later reparsing when dependent doc changes } @@ -1323,7 +1396,7 @@ ModelManagerInterface::CppDataHash ModelManagerInterface::cppData() const LibraryInfo ModelManagerInterface::builtins(const Document::Ptr &doc) const { const ProjectInfo info = projectInfoForPath(doc->fileName()); - if (info.isValid() && !info.qtQmlPath.isEmpty()) + if (!info.project.isNull() && !info.qtQmlPath.isEmpty()) return m_validSnapshot.libraryInfo(info.qtQmlPath); return LibraryInfo(); } @@ -1346,6 +1419,8 @@ ViewerContext ModelManagerInterface::completeVContext(const ViewerContext &vCtx, ProjectInfo defaultInfo = defaultProjectInfo(); if (info.qtQmlPath.isEmpty()) info.qtQmlPath = defaultInfo.qtQmlPath; + info.applicationDirectories = Utils::filteredUnique(info.applicationDirectories + + defaultInfo.applicationDirectories); switch (res.flags) { case ViewerContext::Complete: break; @@ -1354,18 +1429,18 @@ ViewerContext ModelManagerInterface::completeVContext(const ViewerContext &vCtx, Q_FALLTHROUGH(); case ViewerContext::AddAllPaths: { - foreach (const QString &path, defaultVCtx.paths) - res.maybeAddPath(path); + for (const QString &path : qAsConst(defaultVCtx.paths)) + maybeAddPath(res, path); switch (res.language.dialect()) { case Dialect::AnyLanguage: case Dialect::Qml: - res.maybeAddPath(info.qtQmlPath); + maybeAddPath(res, info.qtQmlPath); Q_FALLTHROUGH(); case Dialect::QmlQtQuick2: case Dialect::QmlQtQuick2Ui: { if (res.language == Dialect::QmlQtQuick2 || res.language == Dialect::QmlQtQuick2Ui) - res.maybeAddPath(info.qtQmlPath); + maybeAddPath(res, info.qtQmlPath); QList<ProjectInfo> allProjects; { QMutexLocker locker(&m_mutex); @@ -1373,15 +1448,17 @@ ViewerContext ModelManagerInterface::completeVContext(const ViewerContext &vCtx, } std::sort(allProjects.begin(), allProjects.end(), &pInfoLessThanImports); QList<Dialect> languages = res.language.companionLanguages(); - foreach (const ProjectInfo &pInfo, allProjects) { - for (int i = 0; i< pInfo.importPaths.size(); ++i) { - PathAndLanguage pAndL = pInfo.importPaths.at(i); - if (languages.contains(pAndL.language()) || pAndL.language().companionLanguages().contains(res.language)) - res.maybeAddPath(pAndL.path().toString()); + for (const ProjectInfo &pInfo : qAsConst(allProjects)) { + for (const auto &importPath : pInfo.importPaths) { + if (languages.contains(importPath.language()) + || importPath.language().companionLanguages().contains(res.language)) { + maybeAddPath(res, importPath.path().toString()); + } } } - foreach (const QString &path, environmentImportPaths()) - res.maybeAddPath(path); + const auto environmentPaths = environmentImportPaths(); + for (const QString &path : environmentPaths) + maybeAddPath(res, path); break; } case Dialect::NoLanguage: @@ -1398,18 +1475,20 @@ ViewerContext ModelManagerInterface::completeVContext(const ViewerContext &vCtx, res.selectors.append(defaultVCtx.selectors); Q_FALLTHROUGH(); case ViewerContext::AddDefaultPaths: - foreach (const QString &path, defaultVCtx.paths) - res.maybeAddPath(path); + for (const QString &path : qAsConst(defaultVCtx.paths)) + maybeAddPath(res, path); if (res.language == Dialect::AnyLanguage || res.language == Dialect::Qml) - res.maybeAddPath(info.qtQmlPath); + maybeAddPath(res, info.qtQmlPath); if (res.language == Dialect::AnyLanguage || res.language == Dialect::Qml || res.language == Dialect::QmlQtQuick2 || res.language == Dialect::QmlQtQuick2Ui) { - foreach (const QString &path, environmentImportPaths()) - res.maybeAddPath(path); + const auto environemntPaths = environmentImportPaths(); + for (const QString &path : environemntPaths) + maybeAddPath(res, path); } break; } res.flags = ViewerContext::Complete; + res.applicationDirectories = info.applicationDirectories; return res; } @@ -1431,10 +1510,7 @@ ViewerContext ModelManagerInterface::defaultVContext(Dialect language, defaultCtx = m_defaultVContexts.value(language); } defaultCtx.language = language; - if (autoComplete) - return completeVContext(defaultCtx, doc); - else - return defaultCtx; + return autoComplete ? completeVContext(defaultCtx, doc) : defaultCtx; } ModelManagerInterface::ProjectInfo ModelManagerInterface::defaultProjectInfo() const @@ -1457,7 +1533,7 @@ void ModelManagerInterface::setDefaultVContext(const ViewerContext &vContext) void ModelManagerInterface::joinAllThreads() { - foreach (QFuture<void> future, m_futures) + for (QFuture<void> &future : m_futures) future.waitForFinished(); m_futures.clear(); } @@ -1483,7 +1559,7 @@ void ModelManagerInterface::resetCodeModel() QMutexLocker locker(&m_mutex); // find all documents currently in the code model - foreach (Document::Ptr doc, m_validSnapshot) + for (const Document::Ptr &doc : qAsConst(m_validSnapshot)) documents.append(doc->fileName()); // reset the snapshot diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h index b9bfe67db4..4337adcb79 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.h +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h @@ -49,48 +49,33 @@ namespace QmlJS { class Snapshot; class PluginDumper; -class QMLJS_EXPORT ModelManagerInterface: public QObject +class QMLJS_EXPORT ModelManagerInterface : public QObject { Q_OBJECT + Q_DISABLE_COPY(ModelManagerInterface) public: + ModelManagerInterface(ModelManagerInterface &&) = delete; + ModelManagerInterface &operator=(ModelManagerInterface &&) = delete; + enum QrcResourceSelector { ActiveQrcResources, AllQrcResources }; - class ProjectInfo + struct ProjectInfo { - public: - ProjectInfo() - : tryQmlDump(false), qmlDumpHasRelocatableFlag(true) - { } - - ProjectInfo(QPointer<ProjectExplorer::Project> project) - : project(project) - , tryQmlDump(false), qmlDumpHasRelocatableFlag(true) - { } - - explicit operator bool() const - { return ! project.isNull(); } - - bool isValid() const - { return ! project.isNull(); } - - bool isNull() const - { return project.isNull(); } - - public: // attributes QPointer<ProjectExplorer::Project> project; QStringList sourceFiles; PathsAndLanguages importPaths; QStringList activeResourceFiles; QStringList allResourceFiles; QHash<QString, QString> resourceFileContents; + QStringList applicationDirectories; // whether trying to run qmldump makes sense - bool tryQmlDump; - bool qmlDumpHasRelocatableFlag; + bool tryQmlDump = false; + bool qmlDumpHasRelocatableFlag = true; QString qmlDumpPath; ::Utils::Environment qmlDumpEnvironment; @@ -103,42 +88,41 @@ public: class WorkingCopy { public: - typedef QHash<QString, QPair<QString, int> > Table; + using Table = QHash<QString, QPair<QString, int>>; void insert(const QString &fileName, const QString &source, int revision = 0) - { _elements.insert(fileName, {source, revision}); } + { m_elements.insert(fileName, {source, revision}); } bool contains(const QString &fileName) const - { return _elements.contains(fileName); } + { return m_elements.contains(fileName); } QString source(const QString &fileName) const - { return _elements.value(fileName).first; } + { return m_elements.value(fileName).first; } QPair<QString, int> get(const QString &fileName) const - { return _elements.value(fileName); } + { return m_elements.value(fileName); } Table all() const - { return _elements; } + { return m_elements; } private: - Table _elements; + Table m_elements; }; - class CppData + struct CppData { - public: QList<LanguageUtils::FakeMetaObject::ConstPtr> exportedTypes; QHash<QString, QString> contextProperties; }; - typedef QHash<QString, CppData> CppDataHash; + using CppDataHash = QHash<QString, CppData>; public: ModelManagerInterface(QObject *parent = nullptr); ~ModelManagerInterface() override; static Dialect guessLanguageOfFile(const QString &fileName); - static QStringList globPatternsForLanguages(const QList<Dialect> languages); + static QStringList globPatternsForLanguages(const QList<Dialect> &languages); static ModelManagerInterface *instance(); static void writeWarning(const QString &msg); static WorkingCopy workingCopy(); @@ -157,18 +141,18 @@ public: QStringList filesAtQrcPath(const QString &path, const QLocale *locale = nullptr, ProjectExplorer::Project *project = nullptr, QrcResourceSelector resources = AllQrcResources); - QMap<QString,QStringList> filesInQrcPath(const QString &path, - const QLocale *locale = nullptr, - ProjectExplorer::Project *project = nullptr, - bool addDirs = false, - QrcResourceSelector resources = AllQrcResources); + QMap<QString, QStringList> filesInQrcPath(const QString &path, + const QLocale *locale = nullptr, + ProjectExplorer::Project *project = nullptr, + bool addDirs = false, + QrcResourceSelector resources = AllQrcResources); QList<ProjectInfo> projectInfos() const; - ProjectInfo projectInfo(ProjectExplorer::Project *project, - const ModelManagerInterface::ProjectInfo &defaultValue = ProjectInfo()) const; + bool containsProject(ProjectExplorer::Project *project) const; + ProjectInfo projectInfo(ProjectExplorer::Project *project) const; void updateProjectInfo(const ProjectInfo &pinfo, ProjectExplorer::Project *p); - void updateDocument(QmlJS::Document::Ptr doc); + void updateDocument(const QmlJS::Document::Ptr& doc); void updateLibraryInfo(const QString &path, const QmlJS::LibraryInfo &info); void emitDocumentChangedOnDisk(QmlJS::Document::Ptr doc); void updateQrcFile(const QString &path); @@ -199,11 +183,10 @@ public: void joinAllThreads(); QmlJS::Document::Ptr ensuredGetDocumentForPath(const QString &filePath); - static void importScan(QFutureInterface<void> &future, - WorkingCopy workingCopyInternal, - PathsAndLanguages paths, - ModelManagerInterface *modelManager, - bool emitDocChangedOnDisk, bool libOnly = true, bool forceRescan = false); + static void importScan(QFutureInterface<void> &future, const WorkingCopy& workingCopyInternal, + const PathsAndLanguages& paths, ModelManagerInterface *modelManager, + bool emitDocChangedOnDisk, bool libOnly = true, + bool forceRescan = false); virtual void resetCodeModel(); void removeProjectInfo(ProjectExplorer::Project *project); @@ -225,25 +208,27 @@ protected: virtual QHash<QString,Dialect> languageForSuffix() const; virtual void writeMessageInternal(const QString &msg) const; virtual WorkingCopy workingCopyInternal() const; - virtual void addTaskInternal(QFuture<void> result, const QString &msg, const char *taskId) const; + virtual void addTaskInternal(const QFuture<void> &result, const QString &msg, + const char *taskId) const; QFuture<void> refreshSourceFiles(const QStringList &sourceFiles, bool emitDocumentOnDiskChanged); static void parseLoop(QSet<QString> &scannedPaths, QSet<QString> &newLibraries, - WorkingCopy workingCopyInternal, QStringList files, ModelManagerInterface *modelManager, + const WorkingCopy &workingCopyInternal, QStringList files, + ModelManagerInterface *modelManager, QmlJS::Dialect mainLanguage, bool emitDocChangedOnDisk, - std::function<bool (qreal)> reportProgress); + const std::function<bool(qreal)> &reportProgress); static void parse(QFutureInterface<void> &future, - WorkingCopy workingCopyInternal, + const WorkingCopy &workingCopyInternal, QStringList files, ModelManagerInterface *modelManager, QmlJS::Dialect mainLanguage, bool emitDocChangedOnDisk); - static void updateCppQmlTypes(QFutureInterface<void> &futureInterface, - ModelManagerInterface *qmlModelManager, - CPlusPlus::Snapshot snapshot, - QHash<QString, QPair<CPlusPlus::Document::Ptr, bool> > documents); + static void updateCppQmlTypes( + QFutureInterface<void> &futureInterface, ModelManagerInterface *qmlModelManager, + const CPlusPlus::Snapshot &snapshot, + const QHash<QString, QPair<CPlusPlus::Document::Ptr, bool>> &documents); void maybeScan(const PathsAndLanguages &importPaths); void updateImportPaths(); @@ -254,7 +239,7 @@ private: void cleanupFutures(); void iterateQrcFiles(ProjectExplorer::Project *project, QrcResourceSelector resources, - std::function<void(Utils::QrcParser::ConstPtr)> callback); + const std::function<void(Utils::QrcParser::ConstPtr)> &callback); mutable QMutex m_mutex; QmlJS::Snapshot m_validSnapshot; @@ -269,13 +254,13 @@ private: QTimer *m_updateCppQmlTypesTimer = nullptr; QTimer *m_asyncResetTimer = nullptr; - QHash<QString, QPair<CPlusPlus::Document::Ptr, bool> > m_queuedCppDocuments; + QHash<QString, QPair<CPlusPlus::Document::Ptr, bool>> m_queuedCppDocuments; QFuture<void> m_cppQmlTypesUpdater; Utils::QrcCache m_qrcCache; QHash<QString, QString> m_qrcContents; CppDataHash m_cppDataHash; - QHash<QString, QList<CPlusPlus::Document::Ptr> > m_cppDeclarationFiles; + QHash<QString, QList<CPlusPlus::Document::Ptr>> m_cppDeclarationFiles; mutable QMutex m_cppDataMutex; // project integration diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index e4f51e64c2..d74b4663fa 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -41,6 +41,12 @@ using namespace LanguageUtils; using namespace QmlJS; +static const QStringList qmltypesFileNames = { + QLatin1String("plugins.qmltypes"), + QLatin1String("app.qmltypes"), + QLatin1String("lib.qmltypes") +}; + PluginDumper::PluginDumper(ModelManagerInterface *modelManager) : QObject(modelManager) , m_modelManager(modelManager) @@ -146,10 +152,11 @@ void PluginDumper::onLoadPluginTypes(const QString &libraryPath, const QString & plugin.importVersion = importVersion; // add default qmltypes file if it exists - const QLatin1String defaultQmltypesFileName("plugins.qmltypes"); - const QString defaultQmltypesPath = makeAbsolute(defaultQmltypesFileName, canonicalLibraryPath); - if (!plugin.typeInfoPaths.contains(defaultQmltypesPath) && QFile::exists(defaultQmltypesPath)) - plugin.typeInfoPaths += defaultQmltypesPath; + for (const QString &qmltypesFileName : qmltypesFileNames) { + const QString defaultQmltypesPath = makeAbsolute(qmltypesFileName, canonicalLibraryPath); + if (!plugin.typeInfoPaths.contains(defaultQmltypesPath) && QFile::exists(defaultQmltypesPath)) + plugin.typeInfoPaths += defaultQmltypesPath; + } // add typeinfo files listed in qmldir foreach (const QmlDirParser::TypeInfo &typeInfo, libraryInfo.typeInfos()) { @@ -398,10 +405,11 @@ QString PluginDumper::buildQmltypesPath(const QString &name) const if (path.isEmpty()) return QString(); - const QString filename = path + QLatin1String("/plugins.qmltypes"); - - if (QFile::exists(filename)) - return filename; + for (const QString &qmltypesFileName : qmltypesFileNames) { + const QString filename = path + QLatin1Char('/') + qmltypesFileName; + if (QFile::exists(filename)) + return filename; + } return QString(); } diff --git a/src/libs/qmljs/qmljsviewercontext.cpp b/src/libs/qmljs/qmljsviewercontext.cpp deleted file mode 100644 index bc5d8e5b48..0000000000 --- a/src/libs/qmljs/qmljsviewercontext.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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 "qmljsviewercontext.h" - -namespace QmlJS { -/*! - \class QmlJS::ViewerContext - \brief The ViewerContext class encapsulate selector and paths for a given viewer. - - Using a a different viewer context can emulate (the pure qml part) of a device. - This allows checking how a given qml would be interpreted on another platform/viewer. - - Screen information will also most likely need to be added here. -*/ -ViewerContext::ViewerContext() - : language(Dialect::Qml), flags(AddAllPaths) -{ } - -ViewerContext::ViewerContext(const QStringList &selectors, const QStringList &paths, - QmlJS::Dialect language, - QmlJS::ViewerContext::Flags flags) - : selectors(selectors), paths(paths), language(language), - flags(flags) -{ } - - -/* - which languages might be imported in this context - */ -bool ViewerContext::languageIsCompatible(Dialect l) const -{ - if (l == Dialect::AnyLanguage && language != Dialect::NoLanguage) - return true; - switch (language.dialect()) { - case Dialect::JavaScript: - case Dialect::Json: - case Dialect::QmlProject: - case Dialect::QmlQbs: - case Dialect::QmlTypeInfo: - return language == l; - case Dialect::Qml: - return l == Dialect::Qml || l == Dialect::QmlQtQuick2 || l == Dialect::JavaScript; - case Dialect::QmlQtQuick2: - case Dialect::QmlQtQuick2Ui: - return l == Dialect::Qml || l == Dialect::QmlQtQuick2 || l == Dialect::QmlQtQuick2Ui - || l == Dialect::JavaScript; - case Dialect::AnyLanguage: - return true; - case Dialect::NoLanguage: - break; - } - return false; -} - -void ViewerContext::maybeAddPath(const QString &path) -{ - if (!path.isEmpty() && !paths.contains(path)) - paths.append(path); -} - -} // namespace QmlJS diff --git a/src/libs/qmljs/qmljsviewercontext.h b/src/libs/qmljs/qmljsviewercontext.h index a04596cdd3..1598bcfe18 100644 --- a/src/libs/qmljs/qmljsviewercontext.h +++ b/src/libs/qmljs/qmljsviewercontext.h @@ -32,9 +32,8 @@ namespace QmlJS { -class QMLJS_EXPORT ViewerContext +struct QMLJS_EXPORT ViewerContext { -public: enum Flags { Complete, AddAllPathsAndDefaultSelectors, @@ -43,18 +42,11 @@ public: AddDefaultPathsAndSelectors }; - ViewerContext(); - ViewerContext(const QStringList &selectors, const QStringList &paths, - Dialect language = Dialect::Qml, - Flags flags = AddAllPaths); - - bool languageIsCompatible(Dialect l) const; - void maybeAddPath(const QString &path); - QStringList selectors; QStringList paths; - Dialect language; - Flags flags; + QStringList applicationDirectories; + Dialect language = Dialect::Qml; + Flags flags = AddAllPaths; }; } // namespace QmlJS diff --git a/src/libs/utils/fancylineedit.cpp b/src/libs/utils/fancylineedit.cpp index d67c336544..0f96122a94 100644 --- a/src/libs/utils/fancylineedit.cpp +++ b/src/libs/utils/fancylineedit.cpp @@ -129,6 +129,7 @@ public: bool m_isFiltering = false; bool m_firstChange = true; + bool m_toolTipSet = false; QString m_lastFilterText; @@ -520,7 +521,10 @@ void FancyLineEdit::validate() const bool validates = d->m_validationFunction(this, &d->m_errorMessage); const State newState = isDisplayingPlaceholderText ? DisplayingPlaceholderText : (validates ? Valid : Invalid); - setToolTip(d->m_errorMessage); + if (!validates || d->m_toolTipSet) { + setToolTip(d->m_errorMessage); + d->m_toolTipSet = true; + } // Changed..figure out if valid changed. DisplayingPlaceholderText is not valid, // but should not show error color. Also trigger on the first change. if (newState != d->m_state || d->m_firstChange) { diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 3e8e2ac3bc..8b79923c51 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -45,10 +45,6 @@ #endif #ifdef Q_OS_WIN -// We need defines for Windows 8 -#undef _WIN32_WINNT -#define _WIN32_WINNT _WIN32_WINNT_WIN8 - #include <qt_windows.h> #include <shlobj.h> #endif diff --git a/src/libs/utils/hostosinfo.cpp b/src/libs/utils/hostosinfo.cpp index 8a3c0e814d..c5f313d5ce 100644 --- a/src/libs/utils/hostosinfo.cpp +++ b/src/libs/utils/hostosinfo.cpp @@ -32,8 +32,6 @@ #endif #ifdef Q_OS_WIN -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 /* WinXP, needed for GetNativeSystemInfo() */ #include <qt_windows.h> #endif diff --git a/src/libs/utils/process_ctrlc_stub.cpp b/src/libs/utils/process_ctrlc_stub.cpp index e5469e208d..951c135265 100644 --- a/src/libs/utils/process_ctrlc_stub.cpp +++ b/src/libs/utils/process_ctrlc_stub.cpp @@ -36,7 +36,10 @@ #define _WIN32_WINNT 0x0501 #endif +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#endif + #include <windows.h> #include <shellapi.h> #include <wchar.h> diff --git a/src/libs/utils/winutils.cpp b/src/libs/utils/winutils.cpp index 69eb0d11e8..0f98d91ace 100644 --- a/src/libs/utils/winutils.cpp +++ b/src/libs/utils/winutils.cpp @@ -26,10 +26,7 @@ #include "winutils.h" #include "qtcassert.h" -// Enable WinAPI Windows Vista and later #ifdef Q_OS_WIN -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 // Needed for QueryFullProcessImageName #include <windows.h> #endif diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 8d3f734c2b..1744739288 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -82,7 +82,13 @@ add_subdirectory(ctfvisualizer) # Level 7: add_subdirectory(boot2qt) -add_subdirectory(qmldesigner) +unset(qmldesigner_builddir) +if (WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # Workaround for @CMakeFiles\QmlDesigner.rsp ld.lld.exe: The filename or extension is too long. + # Clang on Windows is having problems with QmlDesigner.rsp which is bigger than 32KiB + set(qmldesigner_builddir ${PROJECT_BINARY_DIR}/qmldsgnr) +endif() +add_subdirectory(qmldesigner ${qmldesigner_builddir}) add_subdirectory(qnx) add_subdirectory(webassembly) add_subdirectory(mcusupport) diff --git a/src/plugins/android/adbcommandswidget.cpp b/src/plugins/android/adbcommandswidget.cpp index 282f4c7644..4fe5c76d8c 100644 --- a/src/plugins/android/adbcommandswidget.cpp +++ b/src/plugins/android/adbcommandswidget.cpp @@ -71,9 +71,8 @@ private: friend class AdbCommandsWidget; }; -AdbCommandsWidget::AdbCommandsWidget(QWidget *parent) : - QGroupBox(parent), - d(new AdbCommandsWidgetPrivate(this)) +AdbCommandsWidget::AdbCommandsWidget() + : d(new AdbCommandsWidgetPrivate(this)) { } diff --git a/src/plugins/android/adbcommandswidget.h b/src/plugins/android/adbcommandswidget.h index 6231d4e414..4650639cc2 100644 --- a/src/plugins/android/adbcommandswidget.h +++ b/src/plugins/android/adbcommandswidget.h @@ -39,7 +39,7 @@ class AdbCommandsWidget : public QGroupBox { Q_OBJECT public: - explicit AdbCommandsWidget(QWidget *parent); + AdbCommandsWidget(); ~AdbCommandsWidget() override; QStringList commandsList() const; diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp index 01b0c6050a..ac4aa5f0c0 100644 --- a/src/plugins/android/androidrunconfiguration.cpp +++ b/src/plugins/android/androidrunconfiguration.cpp @@ -62,13 +62,13 @@ BaseStringListAspect::BaseStringListAspect(const QString &settingsKey, Core::Id BaseStringListAspect::~BaseStringListAspect() = default; -void BaseStringListAspect::addToConfigurationLayout(QFormLayout *layout) +void BaseStringListAspect::addToLayout(LayoutBuilder &builder) { QTC_CHECK(!m_widget); - m_widget = new AdbCommandsWidget(layout->parentWidget()); + m_widget = new AdbCommandsWidget; m_widget->setCommandList(m_value); m_widget->setTitleText(m_label); - layout->addRow(m_widget); + builder.addItem(m_widget.data()); connect(m_widget.data(), &AdbCommandsWidget::commandsChanged, this, [this] { m_value = m_widget->commandsList(); emit changed(); diff --git a/src/plugins/android/androidrunconfiguration.h b/src/plugins/android/androidrunconfiguration.h index 6723048f37..5d1d32c7e5 100644 --- a/src/plugins/android/androidrunconfiguration.h +++ b/src/plugins/android/androidrunconfiguration.h @@ -43,7 +43,7 @@ public: Core::Id id = Core::Id()); ~BaseStringListAspect() override; - void addToConfigurationLayout(QFormLayout *layout) override; + void addToLayout(ProjectExplorer::LayoutBuilder &builder) override; QStringList value() const; void setValue(const QStringList &val); diff --git a/src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.cpp b/src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.cpp index e3cd87f0ce..977ddade3e 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.cpp +++ b/src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.cpp @@ -50,7 +50,7 @@ AutotoolsProject::AutotoolsProject(const Utils::FilePath &fileName) setHasMakeInstallEquivalent(true); - setBuildSystem(std::make_unique<AutotoolsBuildSystem>(this)); + setBuildSystemCreator([](Project *p) { return new AutotoolsBuildSystem(p); }); } class AutotoolsProjectPluginPrivate diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index 7e92932d20..aa0caae7ec 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -51,6 +51,8 @@ #include <QPushButton> #include <QSet> +#include <app/app_version.h> + using namespace ProjectExplorer; using namespace Utils; @@ -123,28 +125,44 @@ void BuildDirManager::emitErrorOccured(const QString &message) const void BuildDirManager::emitReparseRequest() const { - if (m_reparseParameters & REPARSE_URGENT) + if (m_reparseParameters & REPARSE_URGENT) { + qCDebug(cmakeBuildDirManagerLog) << "emitting requestReparse"; emit requestReparse(); - else + } else { + qCDebug(cmakeBuildDirManagerLog) << "emitting requestDelayedReparse"; emit requestDelayedReparse(); + } } void BuildDirManager::updateReaderType(const BuildDirParameters &p, std::function<void()> todo) { - if (!m_reader || !m_reader->isCompatible(p)) + if (!m_reader || !m_reader->isCompatible(p)) { + if (m_reader) { + stopParsingAndClearState(); + qCDebug(cmakeBuildDirManagerLog) << "Creating new reader do to incompatible parameters"; + } else { + qCDebug(cmakeBuildDirManagerLog) << "Creating first reader"; + } m_reader = BuildDirReader::createReader(p); - QTC_ASSERT(m_reader, return); + connect(m_reader.get(), + &BuildDirReader::configurationStarted, + this, + &BuildDirManager::parsingStarted); + connect(m_reader.get(), + &BuildDirReader::dataAvailable, + this, + &BuildDirManager::emitDataAvailable); + connect(m_reader.get(), + &BuildDirReader::errorOccured, + this, + &BuildDirManager::emitErrorOccured); + connect(m_reader.get(), &BuildDirReader::dirty, this, &BuildDirManager::becameDirty); + connect(m_reader.get(), &BuildDirReader::isReadyNow, this, todo); + } - connect(m_reader.get(), &BuildDirReader::configurationStarted, - this, &BuildDirManager::parsingStarted); - connect(m_reader.get(), &BuildDirReader::dataAvailable, - this, &BuildDirManager::emitDataAvailable); - connect(m_reader.get(), &BuildDirReader::errorOccured, - this, &BuildDirManager::emitErrorOccured); - connect(m_reader.get(), &BuildDirReader::dirty, this, &BuildDirManager::becameDirty); - connect(m_reader.get(), &BuildDirReader::isReadyNow, this, todo); + QTC_ASSERT(m_reader, return ); m_reader->setParameters(p); } @@ -213,6 +231,28 @@ bool BuildDirManager::hasConfigChanged() return mustReparse || kcit != targetConfig.constEnd(); } +void BuildDirManager::writeConfigurationIntoBuildDirectory(const Utils::MacroExpander *expander) +{ + QTC_ASSERT(expander, return ); + + const FilePath buildDir = workDirectory(m_parameters); + QTC_ASSERT(buildDir.exists(), return ); + + const FilePath settingsFile = buildDir.pathAppended("qtcsettings.cmake"); + + QByteArray contents; + contents.append("# This file is managed by Qt Creator, do not edit!\n\n"); + contents.append( + transform(m_parameters.configuration, + [expander](const CMakeConfigItem &item) { return item.toCMakeSetLine(expander); }) + .join('\n') + .toUtf8()); + + QFile file(settingsFile.toString()); + QTC_ASSERT(file.open(QFile::WriteOnly | QFile::Truncate), return ); + file.write(contents); +} + bool BuildDirManager::isParsing() const { return m_reader && m_reader->isParsing(); @@ -220,7 +260,10 @@ bool BuildDirManager::isParsing() const void BuildDirManager::stopParsingAndClearState() { + qCDebug(cmakeBuildDirManagerLog) << "stopping parsing run!"; if (m_reader) { + if (m_reader->isParsing()) + m_reader->errorOccured(tr("Parsing has been canceled.")); disconnect(m_reader.get(), nullptr, this, nullptr); m_reader->stop(); } @@ -231,6 +274,7 @@ void BuildDirManager::stopParsingAndClearState() void BuildDirManager::setParametersAndRequestParse(const BuildDirParameters ¶meters, const int reparseParameters) { + qCDebug(cmakeBuildDirManagerLog) << "setting parameters and requesting reparse"; if (!parameters.cmakeTool()) { TaskHub::addTask(Task::Error, tr("The kit needs to define a CMake tool to parse this project."), @@ -239,8 +283,6 @@ void BuildDirManager::setParametersAndRequestParse(const BuildDirParameters &par } QTC_ASSERT(parameters.isValid(), return ); - stopParsingAndClearState(); - m_parameters = parameters; m_parameters.workDirectory = workDirectory(parameters); updateReparseParameters(reparseParameters); @@ -262,6 +304,7 @@ FilePath BuildDirManager::buildDirectory() const void BuildDirManager::becameDirty() { + qCDebug(cmakeBuildDirManagerLog) << "BuildDirManager: becameDirty was triggered."; if (isParsing() || !buildConfiguration()) return; @@ -310,8 +353,10 @@ bool BuildDirManager::isFilesystemScanRequested() const void BuildDirManager::parse() { + qCDebug(cmakeBuildDirManagerLog) << "parsing!"; QTC_ASSERT(m_parameters.isValid(), return ); - QTC_ASSERT(m_reader, return); + QTC_ASSERT(m_reader, return ); + QTC_ASSERT(!m_reader->isParsing(), return ); m_reader->stop(); @@ -335,6 +380,9 @@ void BuildDirManager::parse() } } + writeConfigurationIntoBuildDirectory(m_parameters.expander); + + qCDebug(cmakeBuildDirManagerLog) << "Asking reader to parse"; m_reader->parse(reparseParameters & REPARSE_FORCE_CMAKE_RUN, reparseParameters & REPARSE_FORCE_CONFIGURATION); } @@ -512,21 +560,27 @@ bool BuildDirManager::checkConfiguration() QStringList keyList = changedKeys.keys(); Utils::sort(keyList); QString table = QString::fromLatin1("<table><tr><th>%1</th><th>%2</th><th>%3</th></tr>") - .arg(tr("Key")).arg(tr("CMakeCache.txt")).arg(tr("Project")); + .arg(tr("Key")) + .arg(tr("%1 Project").arg(Core::Constants::IDE_DISPLAY_NAME)) + .arg(tr("Changed value")); foreach (const QString &k, keyList) { const QPair<QString, QString> data = changedKeys.value(k); table += QString::fromLatin1("\n<tr><td>%1</td><td>%2</td><td>%3</td></tr>") - .arg(k) - .arg(data.first.toHtmlEscaped()) - .arg(data.second.toHtmlEscaped()); + .arg(k) + .arg(data.second.toHtmlEscaped()) + .arg(data.first.toHtmlEscaped()); } table += QLatin1String("\n</table>"); QPointer<QMessageBox> box = new QMessageBox(Core::ICore::mainWindow()); - box->setText(tr("CMake configuration has changed on disk.")); + box->setText(tr("The project has been changed outside of %1.") + .arg(Core::Constants::IDE_DISPLAY_NAME)); box->setInformativeText(table); - auto *defaultButton = box->addButton(tr("Overwrite Changes in CMakeCache.txt"), QMessageBox::RejectRole); - auto *applyButton = box->addButton(tr("Apply Changes to Project"), QMessageBox::ApplyRole); + auto *defaultButton = box->addButton(tr("Discard external changes"), + QMessageBox::RejectRole); + auto *applyButton = box->addButton(tr("Adapt %1 project to changes") + .arg(Core::Constants::IDE_DISPLAY_NAME), + QMessageBox::ApplyRole); box->setDefaultButton(defaultButton); box->exec(); diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.h b/src/plugins/cmakeprojectmanager/builddirmanager.h index 91233b79a8..d3537104cc 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.h +++ b/src/plugins/cmakeprojectmanager/builddirmanager.h @@ -127,6 +127,7 @@ private: bool hasConfigChanged(); + void writeConfigurationIntoBuildDirectory(const Utils::MacroExpander *expander); void becameDirty(); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index adbf2bc3f8..a638ec439a 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -287,7 +287,8 @@ bool CMakeBuildConfiguration::fromMap(const QVariantMap &map) const QList<BuildTargetInfo> CMakeBuildConfiguration::appTargets() const { QList<BuildTargetInfo> appTargetList; - bool forAndroid = DeviceTypeKitAspect::deviceTypeId(target()->kit()) == Android::Constants::ANDROID_DEVICE_TYPE; + const bool forAndroid = DeviceTypeKitAspect::deviceTypeId(target()->kit()) + == Android::Constants::ANDROID_DEVICE_TYPE; for (const CMakeBuildTarget &ct : m_buildTargets) { if (ct.targetType == UtilityType) continue; @@ -464,8 +465,10 @@ void CMakeBuildConfiguration::clearError(ForceEnabledChanged fec) m_error.clear(); fec = ForceEnabledChanged::True; } - if (fec == ForceEnabledChanged::True) + if (fec == ForceEnabledChanged::True) { + qCDebug(cmakeBuildConfigurationLog) << "Emitting enabledChanged signal"; emit enabledChanged(); + } } void CMakeBuildConfiguration::emitBuildTypeChanged() @@ -524,11 +527,16 @@ CMakeConfig CMakeBuildConfiguration::configurationForCMake() const void CMakeBuildConfiguration::setError(const QString &message) { + qCDebug(cmakeBuildConfigurationLog) << "Setting error to" << message; + QTC_ASSERT(!message.isEmpty(), return ); + const QString oldMessage = m_error; if (m_error != message) m_error = message; - if (oldMessage.isEmpty() && !message.isEmpty()) + if (oldMessage.isEmpty() != !message.isEmpty()) { + qCDebug(cmakeBuildConfigurationLog) << "Emitting enabledChanged signal"; emit enabledChanged(); + } emit errorOccured(m_error); } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp index 5814083832..710828ff01 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp @@ -81,6 +81,7 @@ static QModelIndex mapToSource(const QAbstractItemView *view, const QModelIndex // -------------------------------------------------------------------- CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) : + NamedWidget(tr("CMake")), m_buildConfiguration(bc), m_configModel(new ConfigModel(this)), m_configFilterModel(new Utils::CategorySortFilterModel), @@ -88,8 +89,6 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) { QTC_CHECK(bc); - setDisplayName(tr("CMake")); - auto vbox = new QVBoxLayout(this); vbox->setContentsMargins(0, 0, 0, 0); auto container = new Utils::DetailsWidget; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index 68b514d6f1..00032dabff 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -57,6 +57,7 @@ #include <QGroupBox> #include <QLineEdit> #include <QListWidget> +#include <QRadioButton> using namespace CMakeProjectManager; using namespace CMakeProjectManager::Internal; @@ -321,11 +322,6 @@ void CMakeBuildStep::setBuildTarget(const QString &buildTarget) emit targetToBuildChanged(); } -void CMakeBuildStep::clearBuildTargets() -{ - m_buildTarget.clear(); -} - QString CMakeBuildStep::toolArguments() const { return m_toolArguments; @@ -440,11 +436,20 @@ CMakeBuildStepConfigWidget::CMakeBuildStepConfigWidget(CMakeBuildStep *buildStep connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged, this, &CMakeBuildStepConfigWidget::updateDetails); - connect(m_buildStep, &CMakeBuildStep::buildTargetsChanged, this, &CMakeBuildStepConfigWidget::buildTargetsChanged); - connect(m_buildStep, &CMakeBuildStep::targetToBuildChanged, this, &CMakeBuildStepConfigWidget::selectedBuildTargetsChanged); + connect(m_buildStep, + &CMakeBuildStep::buildTargetsChanged, + this, + &CMakeBuildStepConfigWidget::buildTargetsChanged); - connect(m_buildStep->buildConfiguration(), &BuildConfiguration::environmentChanged, - this, &CMakeBuildStepConfigWidget::updateDetails); + connect(m_buildStep, + &CMakeBuildStep::targetToBuildChanged, + this, + &CMakeBuildStepConfigWidget::updateBuildTarget); + + connect(m_buildStep->buildConfiguration(), + &BuildConfiguration::environmentChanged, + this, + &CMakeBuildStepConfigWidget::updateDetails); } void CMakeBuildStepConfigWidget::toolArgumentsEdited() @@ -464,6 +469,19 @@ void CMakeBuildStepConfigWidget::itemChanged(QListWidgetItem *item) void CMakeBuildStepConfigWidget::buildTargetsChanged() { { + auto addItem = [this](const QString &buildTarget, + const QString &displayName) { + auto item = new QListWidgetItem(m_buildTargetsList); + auto button = new QRadioButton(displayName); + connect(button, &QRadioButton::toggled, this, [this, buildTarget](bool toggled) { + if (toggled) { + m_buildStep->setBuildTarget(buildTarget); + } + }); + m_buildTargetsList->setItemWidget(item, button); + item->setData(Qt::UserRole, buildTarget); + }; + QSignalBlocker blocker(m_buildTargetsList); m_buildTargetsList->clear(); @@ -473,42 +491,49 @@ void CMakeBuildStepConfigWidget::buildTargetsChanged() QFont italics; italics.setItalic(true); - auto exeItem = new QListWidgetItem(tr(ADD_RUNCONFIGURATION_TEXT), m_buildTargetsList); - exeItem->setData(Qt::UserRole, ADD_RUNCONFIGURATION_TEXT); + addItem(ADD_RUNCONFIGURATION_TEXT, tr(ADD_RUNCONFIGURATION_TEXT)); - foreach (const QString &buildTarget, targetList) { - auto item = new QListWidgetItem(buildTarget, m_buildTargetsList); - item->setData(Qt::UserRole, buildTarget); - } + foreach (const QString &buildTarget, targetList) + addItem(buildTarget, buildTarget); for (int i = 0; i < m_buildTargetsList->count(); ++i) { QListWidgetItem *item = m_buildTargetsList->item(i); const QString title = item->data(Qt::UserRole).toString(); + QRadioButton *radio = itemWidget(item); - item->setFlags(item->flags() | Qt::ItemIsUserCheckable); - item->setCheckState(m_buildStep->buildsBuildTarget(title) ? Qt::Checked : Qt::Unchecked); + radio->setChecked(m_buildStep->buildsBuildTarget(title)); // Print utility targets in italics: if (CMakeBuildStep::specialTargets().contains(title) || title == ADD_RUNCONFIGURATION_TEXT) - item->setFont(italics); + radio->setFont(italics); } } updateDetails(); } -void CMakeBuildStepConfigWidget::selectedBuildTargetsChanged() +void CMakeBuildStepConfigWidget::updateBuildTarget() { + const QString buildTarget = m_buildStep->buildTarget(); { QSignalBlocker blocker(m_buildTargetsList); for (int y = 0; y < m_buildTargetsList->count(); ++y) { QListWidgetItem *item = m_buildTargetsList->item(y); - item->setCheckState(m_buildStep->buildsBuildTarget(item->data(Qt::UserRole).toString()) - ? Qt::Checked : Qt::Unchecked); + const QString itemTarget = item->data(Qt::UserRole).toString(); + + if (itemTarget == buildTarget) { + QRadioButton *radio = itemWidget(item); + radio->setChecked(true); + } } } updateDetails(); } +QRadioButton *CMakeBuildStepConfigWidget::itemWidget(QListWidgetItem *item) +{ + return static_cast<QRadioButton *>(m_buildTargetsList->itemWidget(item)); +} + void CMakeBuildStepConfigWidget::updateDetails() { BuildConfiguration *bc = m_buildStep->buildConfiguration(); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.h b/src/plugins/cmakeprojectmanager/cmakebuildstep.h index 28c6ccb46e..99de0046d5 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.h @@ -33,6 +33,7 @@ QT_BEGIN_NAMESPACE class QLineEdit; class QListWidget; class QListWidgetItem; +class QRadioButton; QT_END_NAMESPACE namespace Utils { @@ -64,7 +65,6 @@ public: QString buildTarget() const; bool buildsBuildTarget(const QString &target) const; void setBuildTarget(const QString &target); - void clearBuildTargets(); QString toolArguments() const; void setToolArguments(const QString &list); @@ -131,7 +131,9 @@ private: void toolArgumentsEdited(); void updateDetails(); void buildTargetsChanged(); - void selectedBuildTargetsChanged(); + void updateBuildTarget(); + + QRadioButton *itemWidget(QListWidgetItem *item); CMakeBuildStep *m_buildStep; QLineEdit *m_toolArguments; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 4b71fa135c..ae1e20972f 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -57,8 +57,8 @@ Q_LOGGING_CATEGORY(cmakeBuildSystemLog, "qtc.cmake.buildsystem", QtWarningMsg); // CMakeBuildSystem: // -------------------------------------------------------------------- -CMakeBuildSystem::CMakeBuildSystem(CMakeProject *p) - : BuildSystem(p) +CMakeBuildSystem::CMakeBuildSystem(Project *project) + : BuildSystem(project) , m_cppCodeModelUpdater(new CppTools::CppProjectUpdater) { // TreeScanner: @@ -67,9 +67,9 @@ CMakeBuildSystem::CMakeBuildSystem(CMakeProject *p) this, &CMakeBuildSystem::handleTreeScanningFinished); - m_treeScanner.setFilter([this, p](const Utils::MimeType &mimeType, const Utils::FilePath &fn) { + m_treeScanner.setFilter([this](const MimeType &mimeType, const FilePath &fn) { // Mime checks requires more resources, so keep it last in check list - auto isIgnored = fn.toString().startsWith(p->projectFilePath().toString() + ".user") + auto isIgnored = fn.toString().startsWith(projectFilePath().toString() + ".user") || TreeScanner::isWellKnownBinary(mimeType, fn); // Cache mime check result for speed up @@ -114,6 +114,7 @@ CMakeBuildSystem::~CMakeBuildSystem() bool CMakeBuildSystem::validateParsingContext(const ParsingContext &ctx) { + QTC_ASSERT(!m_currentContext.guard.guardsProject(), return false); return ctx.project && qobject_cast<CMakeBuildConfiguration *>(ctx.buildConfiguration); } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index 1170a38e12..c1325dcc0c 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -48,13 +48,20 @@ class CMakeBuildSystem : public ProjectExplorer::BuildSystem Q_OBJECT public: - explicit CMakeBuildSystem(CMakeProject *project); + explicit CMakeBuildSystem(ProjectExplorer::Project *project); ~CMakeBuildSystem() final; protected: bool validateParsingContext(const ParsingContext &ctx) final; void parseProject(ParsingContext &&ctx) final; + bool supportsAction(ProjectExplorer::Node *context, + ProjectExplorer::ProjectAction action, + const ProjectExplorer::Node *node) const override; + + bool addFiles(ProjectExplorer::Node *context, + const QStringList &filePaths, QStringList *) final; + private: // Treescanner states: void handleTreeScanningFinished(); diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp index e63641cf28..7fdb7b2d60 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp @@ -149,6 +149,26 @@ CMakeConfigItem::Type CMakeConfigItem::typeStringToType(const QByteArray &type) return CMakeConfigItem::INTERNAL; } +QString CMakeConfigItem::typeToTypeString(const CMakeConfigItem::Type t) +{ + switch (t) { + case CMakeProjectManager::CMakeConfigItem::FILEPATH: + return {"FILEPATH"}; + case CMakeProjectManager::CMakeConfigItem::PATH: + return {"PATH"}; + case CMakeProjectManager::CMakeConfigItem::STRING: + return {"STRING"}; + case CMakeProjectManager::CMakeConfigItem::INTERNAL: + return {"INTERNAL"}; + case CMakeProjectManager::CMakeConfigItem::STATIC: + return {"STATIC"}; + case CMakeConfigItem::BOOL: + return {"BOOL"}; + } + QTC_CHECK(false); + return {}; +} + Utils::optional<bool> CMakeConfigItem::toBool(const QByteArray &value) { // Taken from CMakes if(<constant>) documentation: @@ -367,6 +387,18 @@ QString CMakeConfigItem::toArgument(const Utils::MacroExpander *expander) const return "-D" + toString(expander); } +QString CMakeConfigItem::toCMakeSetLine(const Utils::MacroExpander *expander) const +{ + if (isUnset) { + return QString("unset(\"%1\" CACHE)").arg(QString::fromUtf8(key)); + } + return QString("set(\"%1\" \"%2\" CACHE \"%3\" \"%4\" FORCE)") + .arg(QString::fromUtf8(key)) + .arg(expandedValue(expander)) + .arg(typeToTypeString(type)) + .arg(QString::fromUtf8(documentation)); +} + bool CMakeConfigItem::operator==(const CMakeConfigItem &o) const { // type, isAdvanced and documentation do not matter for a match! diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h index 8b5fce8eb7..15dae12a9c 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h @@ -54,6 +54,7 @@ public: const QList<CMakeConfigItem> &input); static QStringList cmakeSplitValue(const QString &in, bool keepEmpty = false); static Type typeStringToType(const QByteArray &typeString); + static QString typeToTypeString(const Type t); static Utils::optional<bool> toBool(const QByteArray &value); bool isNull() const { return key.isEmpty(); } @@ -65,6 +66,7 @@ public: static QList<CMakeConfigItem> itemsFromFile(const Utils::FilePath &input, QString *errorMessage); QString toString(const Utils::MacroExpander *expander = nullptr) const; QString toArgument(const Utils::MacroExpander *expander = nullptr) const; + QString toCMakeSetLine(const Utils::MacroExpander *expander = nullptr) const; bool operator==(const CMakeConfigItem &o) const; diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index 4745dc4cfa..f7149a4eb2 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -155,7 +155,6 @@ void BuildCMakeTargetLocatorFilter::accept(Core::LocatorFilterEntry selection, // Change the make step to build only the given target QString oldTarget = buildStep->buildTarget(); - buildStep->clearBuildTargets(); buildStep->setBuildTarget(selection.displayName); // Build diff --git a/src/plugins/cmakeprojectmanager/cmakeparser.cpp b/src/plugins/cmakeprojectmanager/cmakeparser.cpp index 515bf89222..458b7b8b4e 100644 --- a/src/plugins/cmakeprojectmanager/cmakeparser.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeparser.cpp @@ -105,6 +105,9 @@ void CMakeParser::stdError(const QString &line) Utils::FilePath(), -1, Constants::TASK_CATEGORY_BUILDSYSTEM); m_lines = 1; return; + } else if (trimmedLine.startsWith("-- ") || trimmedLine.startsWith(" * ")) { + // Do not pass on lines starting with "-- " or "* ". Those are typical CMake output + return; } IOutputParser::stdError(line); return; @@ -288,6 +291,10 @@ void Internal::CMakeProjectPlugin::testCMakeParser_data() Utils::FilePath::fromUserInput(QLatin1String("/test/path/CMakeLists.txt")), 9, categoryBuild)) << QString(); + QTest::newRow("eat normal CMake output") + << QString::fromLatin1("-- Qt5 install prefix: /usr/lib\n" + " * Plugin componentsplugin, with CONDITION TARGET QmlDesigner") + << OutputParserTester::STDERR << QString() << QString() << (Tasks()) << QString(); } void Internal::CMakeProjectPlugin::testCMakeParser() diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp index 07bf943f3d..8517a5ee7f 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp @@ -84,13 +84,6 @@ CMakeProcess::~CMakeProcess() } } -QStringList CMakeProcess::toArguments(const CMakeConfig &config, - const Utils::MacroExpander *expander) { - return Utils::transform(config, [expander](const CMakeConfigItem &i) -> QString { - return i.toArgument(expander); - }); -} - void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList &arguments) { QTC_ASSERT(!m_process && !m_parser && !m_future, return); @@ -135,9 +128,10 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & connect(process.get(), QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &CMakeProcess::handleProcessFinished); - QStringList args(srcDir); + QStringList args; args += parameters.generatorArguments; args += arguments; + args += srcDir; Utils::CommandLine commandLine(cmake->cmakeExecutable(), args); TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM); diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.h b/src/plugins/cmakeprojectmanager/cmakeprocess.h index 9675822435..6d03d1ab83 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.h +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.h @@ -47,8 +47,6 @@ public: CMakeProcess(const CMakeProcess&) = delete; ~CMakeProcess(); - static QStringList toArguments(const CMakeConfig &config, const Utils::MacroExpander *expander); - void run(const BuildDirParameters ¶meters, const QStringList &arguments); QProcess::ProcessState state() const; diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 9ebc052b06..e44018affd 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -91,7 +91,7 @@ CMakeProject::CMakeProject(const FilePath &fileName) setKnowsAllBuildExecutables(false); setHasMakeInstallEquivalent(true); - setBuildSystem(std::make_unique<CMakeBuildSystem>(this)); + setBuildSystemCreator([](Project *p) { return new CMakeBuildSystem(p); }); } CMakeProject::~CMakeProject() = default; @@ -115,10 +115,10 @@ void CMakeProject::runCMake() return; BuildDirParameters parameters(bc); - bc->m_buildDirManager - .setParametersAndRequestParse(parameters, - BuildDirManager::REPARSE_CHECK_CONFIGURATION - | BuildDirManager::REPARSE_FORCE_CMAKE_RUN); + bc->m_buildDirManager.setParametersAndRequestParse(parameters, + BuildDirManager::REPARSE_CHECK_CONFIGURATION + | BuildDirManager::REPARSE_FORCE_CMAKE_RUN + | BuildDirManager::REPARSE_URGENT); } void CMakeProject::runCMakeAndScanProjectTree() diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h index cf7a1f058e..1b5dcca35c 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.h +++ b/src/plugins/cmakeprojectmanager/cmakeproject.h @@ -35,25 +35,10 @@ #include <projectexplorer/buildsystem.h> #include <projectexplorer/project.h> -#include <utils/fileutils.h> - -#include <QFuture> -#include <QHash> -#include <QTimer> - #include <memory> -namespace CppTools { class CppProjectUpdater; } -namespace ProjectExplorer { class FileNode; } - namespace CMakeProjectManager { -namespace Internal { -class CMakeBuildConfiguration; -class CMakeBuildSettingsWidget; -class CMakeProjectNode; -} // namespace Internal - class CMAKE_EXPORT CMakeProject : public ProjectExplorer::Project { Q_OBJECT diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp index 8d66d920cf..9943ca5784 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp @@ -138,11 +138,6 @@ bool CMakeListsNode::showInSimpleTree() const return false; } -bool CMakeListsNode::supportsAction(ProjectExplorer::ProjectAction action, const ProjectExplorer::Node *) const -{ - return action == ProjectExplorer::ProjectAction::AddNewFile; -} - Utils::optional<Utils::FilePath> CMakeListsNode::visibleAfterAddFileAction() const { return filePath().pathAppended("CMakeLists.txt"); @@ -161,10 +156,19 @@ QString CMakeProjectNode::tooltip() const return QString(); } -bool CMakeProjectNode::addFiles(const QStringList &filePaths, QStringList *) +bool CMakeBuildSystem::addFiles(Node *context, const QStringList &filePaths, QStringList *notAdded) { - noAutoAdditionNotify(filePaths, this); - return true; // Return always true as autoadd is not supported! + if (auto n = dynamic_cast<CMakeProjectNode *>(context)) { + noAutoAdditionNotify(filePaths, n); + return true; // Return always true as autoadd is not supported! + } + + if (auto n = dynamic_cast<CMakeTargetNode *>(context)) { + noAutoAdditionNotify(filePaths, n); + return true; // Return always true as autoadd is not supported! + } + + return BuildSystem::addFiles(context, filePaths, notAdded); } CMakeTargetNode::CMakeTargetNode(const Utils::FilePath &directory, const QString &target) : @@ -243,16 +247,15 @@ void CMakeTargetNode::setConfig(const CMakeConfig &config) m_config = config; } -bool CMakeTargetNode::supportsAction(ProjectExplorer::ProjectAction action, - const ProjectExplorer::Node *) const +bool CMakeBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const { - return action == ProjectExplorer::ProjectAction::AddNewFile; -} + if (dynamic_cast<CMakeTargetNode *>(context)) + return action == ProjectAction::AddNewFile; -bool CMakeTargetNode::addFiles(const QStringList &filePaths, QStringList *) -{ - noAutoAdditionNotify(filePaths, this); - return true; // Return always true as autoadd is not supported! + if (dynamic_cast<CMakeListsNode *>(context)) + return action == ProjectAction::AddNewFile; + + return BuildSystem::supportsAction(context, action, node); } Utils::optional<Utils::FilePath> CMakeTargetNode::visibleAfterAddFileAction() const diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h index f4cea98db4..5698f00c9c 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h @@ -44,7 +44,6 @@ public: CMakeListsNode(const Utils::FilePath &cmakeListPath); bool showInSimpleTree() const final; - bool supportsAction(ProjectExplorer::ProjectAction action, const Node *node) const override; Utils::optional<Utils::FilePath> visibleAfterAddFileAction() const override; }; @@ -54,8 +53,6 @@ public: CMakeProjectNode(const Utils::FilePath &directory); QString tooltip() const final; - - bool addFiles(const QStringList &filePaths, QStringList *notAdded) override; }; class CMakeTargetNode : public ProjectExplorer::ProjectNode @@ -70,8 +67,6 @@ public: Utils::FilePath buildDirectory() const; void setBuildDirectory(const Utils::FilePath &directory); - bool supportsAction(ProjectExplorer::ProjectAction action, const Node *node) const override; - bool addFiles(const QStringList &filePaths, QStringList *notAdded) override; Utils::optional<Utils::FilePath> visibleAfterAddFileAction() const override; void build() override; diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp index 5418a1994e..9eeeb71048 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp @@ -54,6 +54,7 @@ using namespace Core; using namespace ProjectExplorer; +using namespace Utils; namespace CMakeProjectManager { namespace Internal { @@ -63,11 +64,17 @@ class CMakeProjectPluginPrivate public: CMakeToolManager cmakeToolManager; // have that before the first CMakeKitAspect - Utils::ParameterAction *m_buildTargetContextAction = nullptr; + ParameterAction buildTargetContextAction{ + CMakeProjectPlugin::tr("Build"), + CMakeProjectPlugin:: tr("Build \"%1\""), + ParameterAction::AlwaysEnabled/*handled manually*/ + }; + QMetaObject::Connection m_actionConnect; CMakeSettingsPage settingsPage; - static const std::unique_ptr<CMakeSpecificSettings> projectTypeSpecificSettings; + CMakeSpecificSettingsPage specificSettings{CMakeProjectPlugin::projectTypeSpecificSettings()}; + CMakeManager manager; CMakeBuildStepFactory buildStepFactory; CMakeBuildConfigurationFactory buildConfigFactory; @@ -80,12 +87,10 @@ public: CMakeConfigurationKitAspect cmakeConfigurationKitAspect; }; -const std::unique_ptr<CMakeSpecificSettings> -CMakeProjectPluginPrivate::projectTypeSpecificSettings{std::make_unique<CMakeSpecificSettings>()}; - CMakeSpecificSettings *CMakeProjectPlugin::projectTypeSpecificSettings() { - return CMakeProjectPluginPrivate::projectTypeSpecificSettings.get(); + static CMakeSpecificSettings theSettings; + return &theSettings; } CMakeProjectPlugin::~CMakeProjectPlugin() @@ -98,36 +103,27 @@ bool CMakeProjectPlugin::initialize(const QStringList & /*arguments*/, QString * Q_UNUSED(errorMessage) d = new CMakeProjectPluginPrivate; - CMakeProjectPluginPrivate::projectTypeSpecificSettings->fromSettings(ICore::settings()); - new CMakeSpecificSettingsPage(CMakeProjectPluginPrivate::projectTypeSpecificSettings.get(), - this); //do not store as this will be cleaned after program close + projectTypeSpecificSettings()->fromSettings(ICore::settings()); - const Context projectContext(CMakeProjectManager::Constants::CMAKEPROJECT_ID); + const Context projectContext{CMakeProjectManager::Constants::CMAKEPROJECT_ID}; - Core::FileIconProvider::registerIconOverlayForSuffix(Constants::FILEOVERLAY_CMAKE, "cmake"); - Core::FileIconProvider::registerIconOverlayForFilename(Constants::FILEOVERLAY_CMAKE, - "CMakeLists.txt"); + FileIconProvider::registerIconOverlayForSuffix(Constants::FILEOVERLAY_CMAKE, "cmake"); + FileIconProvider::registerIconOverlayForFilename(Constants::FILEOVERLAY_CMAKE, + "CMakeLists.txt"); TextEditor::SnippetProvider::registerGroup(Constants::CMAKE_SNIPPETS_GROUP_ID, tr("CMake", "SnippetProvider")); ProjectManager::registerProjectType<CMakeProject>(Constants::CMAKEPROJECTMIMETYPE); - //menus - ActionContainer *msubproject = - ActionManager::actionContainer(ProjectExplorer::Constants::M_SUBPROJECTCONTEXT); - //register actions - Command *command = nullptr; - - d->m_buildTargetContextAction = new Utils::ParameterAction(tr("Build"), tr("Build \"%1\""), - Utils::ParameterAction::AlwaysEnabled/*handled manually*/, - this); - command = ActionManager::registerAction(d->m_buildTargetContextAction, - Constants::BUILD_TARGET_CONTEXTMENU, projectContext); + Command *command = ActionManager::registerAction(&d->buildTargetContextAction, + Constants::BUILD_TARGET_CONTEXTMENU, projectContext); command->setAttribute(Command::CA_Hide); command->setAttribute(Command::CA_UpdateText); - command->setDescription(d->m_buildTargetContextAction->text()); - msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD); + command->setDescription(d->buildTargetContextAction.text()); + + ActionManager::actionContainer(ProjectExplorer::Constants::M_SUBPROJECTCONTEXT) + ->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD); // Wire up context menu updates: connect(ProjectTree::instance(), &ProjectTree::currentNodeChanged, @@ -153,11 +149,11 @@ void CMakeProjectPlugin::updateContextActions() // Build Target: disconnect(d->m_actionConnect); - d->m_buildTargetContextAction->setParameter(targetDisplayName); - d->m_buildTargetContextAction->setEnabled(targetNode); - d->m_buildTargetContextAction->setVisible(targetNode); + d->buildTargetContextAction.setParameter(targetDisplayName); + d->buildTargetContextAction.setEnabled(targetNode); + d->buildTargetContextAction.setVisible(targetNode); if (cmProject && targetNode) { - d->m_actionConnect = connect(d->m_buildTargetContextAction, &Utils::ParameterAction::triggered, + d->m_actionConnect = connect(&d->buildTargetContextAction, &ParameterAction::triggered, cmProject, [cmProject, targetDisplayName]() { cmProject->buildCMakeTarget(targetDisplayName); }); diff --git a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp index 5b4ca9d051..939383672d 100644 --- a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp +++ b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp @@ -69,13 +69,22 @@ public: CMakeToolTreeItem *cmakeToolItem(const Core::Id &id) const; CMakeToolTreeItem *cmakeToolItem(const QModelIndex &index) const; - QModelIndex addCMakeTool(const QString &name, const FilePath &executable, const bool autoRun, const bool autoCreate, const bool isAutoDetected); + QModelIndex addCMakeTool(const QString &name, + const FilePath &executable, + const FilePath &qchFile, + const bool autoRun, + const bool autoCreate, + const bool isAutoDetected); void addCMakeTool(const CMakeTool *item, bool changed); TreeItem *autoGroupItem() const; TreeItem *manualGroupItem() const; void reevaluateChangedFlag(CMakeToolTreeItem *item) const; - void updateCMakeTool(const Core::Id &id, const QString &displayName, const FilePath &executable, - bool autoRun, bool autoCreate); + void updateCMakeTool(const Core::Id &id, + const QString &displayName, + const FilePath &executable, + const FilePath &qchFile, + bool autoRun, + bool autoCreate); void removeCMakeTool(const Core::Id &id); void apply(); @@ -97,6 +106,7 @@ public: : m_id(item->id()) , m_name(item->displayName()) , m_executable(item->filePath()) + , m_qchFile(item->qchFilePath()) , m_isAutoRun(item->isAutoRun()) , m_autoCreateBuildDirectory(item->autoCreateBuildDirectory()) , m_autodetected(item->isAutoDetected()) @@ -111,12 +121,14 @@ public: CMakeToolTreeItem(const QString &name, const Utils::FilePath &executable, + const FilePath &qchFile, bool autoRun, bool autoCreate, bool autodetected) : m_id(Core::Id::fromString(QUuid::createUuid().toString())) , m_name(name) , m_executable(executable) + , m_qchFile(qchFile) , m_isAutoRun(autoRun) , m_autoCreateBuildDirectory(autoCreate) , m_autodetected(autodetected) @@ -197,6 +209,7 @@ public: QString m_name; QString m_tooltip; FilePath m_executable; + FilePath m_qchFile; bool m_isAutoRun = true; bool m_pathExists = false; bool m_pathIsFile = false; @@ -224,11 +237,14 @@ CMakeToolItemModel::CMakeToolItemModel() } -QModelIndex CMakeToolItemModel::addCMakeTool(const QString &name, const FilePath &executable, - const bool autoRun, const bool autoCreate, +QModelIndex CMakeToolItemModel::addCMakeTool(const QString &name, + const FilePath &executable, + const FilePath &qchFile, + const bool autoRun, + const bool autoCreate, const bool isAutoDetected) { - auto item = new CMakeToolTreeItem(name, executable, autoRun, autoCreate, isAutoDetected); + auto item = new CMakeToolTreeItem(name, executable, qchFile, autoRun, autoCreate, isAutoDetected); if (isAutoDetected) autoGroupItem()->appendChild(item); else @@ -265,7 +281,8 @@ void CMakeToolItemModel::reevaluateChangedFlag(CMakeToolTreeItem *item) const { CMakeTool *orig = CMakeToolManager::findById(item->m_id); item->m_changed = !orig || orig->displayName() != item->m_name - || orig->filePath() != item->m_executable; + || orig->filePath() != item->m_executable + || orig->qchFilePath() != item->m_qchFile; //make sure the item is marked as changed when the default cmake was changed CMakeTool *origDefTool = CMakeToolManager::defaultCMakeTool(); @@ -278,8 +295,11 @@ void CMakeToolItemModel::reevaluateChangedFlag(CMakeToolTreeItem *item) const item->update(); // Notify views. } -void CMakeToolItemModel::updateCMakeTool(const Core::Id &id, const QString &displayName, - const FilePath &executable, bool autoRun, +void CMakeToolItemModel::updateCMakeTool(const Core::Id &id, + const QString &displayName, + const FilePath &executable, + const FilePath &qchFile, + bool autoRun, bool autoCreate) { CMakeToolTreeItem *treeItem = cmakeToolItem(id); @@ -287,6 +307,7 @@ void CMakeToolItemModel::updateCMakeTool(const Core::Id &id, const QString &disp treeItem->m_name = displayName; treeItem->m_executable = executable; + treeItem->m_qchFile = qchFile; treeItem->m_isAutoRun = autoRun; treeItem->m_autoCreateBuildDirectory = autoCreate; @@ -328,6 +349,7 @@ void CMakeToolItemModel::apply() if (CMakeTool *cmake = CMakeToolManager::findById(item->m_id)) { cmake->setDisplayName(item->m_name); cmake->setFilePath(item->m_executable); + cmake->setQchFilePath(item->m_qchFile); cmake->setAutorun(item->m_isAutoRun); cmake->setAutoCreateBuildDirectory(item->m_autoCreateBuildDirectory); } else { @@ -341,6 +363,7 @@ void CMakeToolItemModel::apply() auto cmake = std::make_unique<CMakeTool>(detection, item->m_id); cmake->setDisplayName(item->m_name); cmake->setFilePath(item->m_executable); + cmake->setQchFilePath(item->m_qchFile); if (!CMakeToolManager::registerCMakeTool(std::move(cmake))) item->m_changed = true; } @@ -392,11 +415,14 @@ public: void store() const; private: + void updateQchFilePath(); + CMakeToolItemModel *m_model; QLineEdit *m_displayNameLineEdit; QCheckBox *m_autoRunCheckBox; QCheckBox *m_autoCreateBuildDirectoryCheckBox; PathChooser *m_binaryChooser; + PathChooser *m_qchFileChooser; Core::Id m_id; bool m_loadingItem; }; @@ -412,6 +438,13 @@ CMakeToolItemConfigWidget::CMakeToolItemConfigWidget(CMakeToolItemModel *model) m_binaryChooser->setHistoryCompleter(QLatin1String("Cmake.Command.History")); m_binaryChooser->setCommandVersionArguments({"--version"}); + m_qchFileChooser = new PathChooser(this); + m_qchFileChooser->setExpectedKind(PathChooser::File); + m_qchFileChooser->setMinimumWidth(400); + m_qchFileChooser->setHistoryCompleter(QLatin1String("Cmake.qchFile.History")); + m_qchFileChooser->setPromptDialogFilter("*.qch"); + m_qchFileChooser->setPromptDialogTitle(tr("CMake .qch File")); + m_autoRunCheckBox = new QCheckBox; m_autoRunCheckBox->setText(tr("Autorun CMake")); m_autoRunCheckBox->setToolTip(tr("Automatically run CMake after changes to CMake project files.")); @@ -424,13 +457,17 @@ CMakeToolItemConfigWidget::CMakeToolItemConfigWidget(CMakeToolItemModel *model) formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); formLayout->addRow(new QLabel(tr("Name:")), m_displayNameLineEdit); formLayout->addRow(new QLabel(tr("Path:")), m_binaryChooser); + formLayout->addRow(new QLabel(tr("Help File:")), m_qchFileChooser); formLayout->addRow(m_autoRunCheckBox); formLayout->addRow(m_autoCreateBuildDirectoryCheckBox); - connect(m_binaryChooser, &PathChooser::rawPathChanged, - this, &CMakeToolItemConfigWidget::store); - connect(m_displayNameLineEdit, &QLineEdit::textChanged, - this, &CMakeToolItemConfigWidget::store); + connect(m_binaryChooser, &PathChooser::rawPathChanged, this, [this]() { + updateQchFilePath(); + m_qchFileChooser->setBaseFileName(m_binaryChooser->fileName().parentDir()); + store(); + }); + connect(m_qchFileChooser, &PathChooser::rawPathChanged, this, &CMakeToolItemConfigWidget::store); + connect(m_displayNameLineEdit, &QLineEdit::textChanged, this, &CMakeToolItemConfigWidget::store); connect(m_autoRunCheckBox, &QCheckBox::toggled, this, &CMakeToolItemConfigWidget::store); connect(m_autoCreateBuildDirectoryCheckBox, &QCheckBox::toggled, @@ -440,11 +477,20 @@ CMakeToolItemConfigWidget::CMakeToolItemConfigWidget(CMakeToolItemModel *model) void CMakeToolItemConfigWidget::store() const { if (!m_loadingItem && m_id.isValid()) - m_model->updateCMakeTool(m_id, m_displayNameLineEdit->text(), m_binaryChooser->fileName(), + m_model->updateCMakeTool(m_id, + m_displayNameLineEdit->text(), + m_binaryChooser->fileName(), + m_qchFileChooser->fileName(), m_autoRunCheckBox->checkState() == Qt::Checked, m_autoCreateBuildDirectoryCheckBox->checkState() == Qt::Checked); } +void CMakeToolItemConfigWidget::updateQchFilePath() +{ + if (m_qchFileChooser->fileName().isEmpty()) + m_qchFileChooser->setFileName(CMakeTool::searchQchFile(m_binaryChooser->fileName())); +} + void CMakeToolItemConfigWidget::load(const CMakeToolTreeItem *item) { m_loadingItem = true; // avoid intermediate signal handling @@ -461,6 +507,10 @@ void CMakeToolItemConfigWidget::load(const CMakeToolTreeItem *item) m_binaryChooser->setReadOnly(item->m_autodetected); m_binaryChooser->setFileName(item->m_executable); + m_qchFileChooser->setReadOnly(item->m_autodetected); + m_qchFileChooser->setBaseFileName(item->m_executable.parentDir()); + m_qchFileChooser->setFileName(item->m_qchFile); + m_autoRunCheckBox->setChecked(item->m_isAutoRun); m_autoCreateBuildDirectoryCheckBox->setChecked(item->m_autoCreateBuildDirectory); @@ -568,8 +618,10 @@ void CMakeToolConfigWidget::cloneCMakeTool() QModelIndex newItem = m_model.addCMakeTool(tr("Clone of %1").arg(m_currentItem->m_name), m_currentItem->m_executable, + m_currentItem->m_qchFile, m_currentItem->m_isAutoRun, - m_currentItem->m_autoCreateBuildDirectory, false); + m_currentItem->m_autoCreateBuildDirectory, + false); m_cmakeToolsView->setCurrentIndex(newItem); } @@ -577,7 +629,11 @@ void CMakeToolConfigWidget::cloneCMakeTool() void CMakeToolConfigWidget::addCMakeTool() { QModelIndex newItem = m_model.addCMakeTool(m_model.uniqueDisplayName(tr("New CMake")), - FilePath(), true, false, false); + FilePath(), + FilePath(), + true, + false, + false); m_cmakeToolsView->setCurrentIndex(newItem); } diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.cpp index e458e7fbd5..cc37b325e5 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.cpp +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.cpp @@ -72,9 +72,8 @@ void CMakeSpecificSettingWidget::setProjectPopupSetting(AfterAddFileAction mode) } } -CMakeSpecificSettingsPage::CMakeSpecificSettingsPage(CMakeSpecificSettings *settings, - QObject *parent): - Core::IOptionsPage(parent), m_settings(settings) +CMakeSpecificSettingsPage::CMakeSpecificSettingsPage(CMakeSpecificSettings *settings) + : m_settings(settings) { setId("CMakeSpecificSettings"); setDisplayName(tr("CMake")); diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.h b/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.h index 2d4419d0d5..f54b1bc8ac 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.h +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettingspage.h @@ -54,8 +54,9 @@ private: class CMakeSpecificSettingsPage : public Core::IOptionsPage { Q_OBJECT + public: - CMakeSpecificSettingsPage(CMakeSpecificSettings *settings, QObject *parent); + explicit CMakeSpecificSettingsPage(CMakeSpecificSettings *settings); QWidget *widget() override; void apply() override; diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp index 361e0acd88..e8284c5e7e 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp @@ -30,6 +30,7 @@ #include <utils/environment.h> #include <utils/qtcassert.h> +#include <QDir> #include <QFileInfo> #include <QJsonDocument> #include <QJsonObject> @@ -46,6 +47,7 @@ const char CMAKE_INFORMATION_ID[] = "Id"; const char CMAKE_INFORMATION_COMMAND[] = "Binary"; const char CMAKE_INFORMATION_DISPLAYNAME[] = "DisplayName"; const char CMAKE_INFORMATION_AUTORUN[] = "AutoRun"; +const char CMAKE_INFORMATION_QCH_FILE_PATH[] = "QchFile"; const char CMAKE_INFORMATION_AUTO_CREATE_BUILD_DIRECTORY[] = "AutoCreateBuildDirectory"; const char CMAKE_INFORMATION_AUTODETECTED[] = "AutoDetected"; const char CMAKE_INFORMATION_READERTYPE[] = "ReaderType"; @@ -146,6 +148,11 @@ CMakeTool::CMakeTool(const QVariantMap &map, bool fromSdk) : m_isAutoDetected = map.value(CMAKE_INFORMATION_AUTODETECTED, false).toBool(); setFilePath(Utils::FilePath::fromString(map.value(CMAKE_INFORMATION_COMMAND).toString())); + + m_qchFilePath = Utils::FilePath::fromVariant(map.value(CMAKE_INFORMATION_QCH_FILE_PATH)); + + if (m_qchFilePath.isEmpty()) + m_qchFilePath = searchQchFile(m_executable); } CMakeTool::~CMakeTool() = default; @@ -228,6 +235,7 @@ QVariantMap CMakeTool::toMap() const data.insert(CMAKE_INFORMATION_DISPLAYNAME, m_displayName); data.insert(CMAKE_INFORMATION_ID, m_id.toSetting()); data.insert(CMAKE_INFORMATION_COMMAND, m_executable.toString()); + data.insert(CMAKE_INFORMATION_QCH_FILE_PATH, m_qchFilePath.toString()); data.insert(CMAKE_INFORMATION_AUTORUN, m_isAutoRun); data.insert(CMAKE_INFORMATION_AUTO_CREATE_BUILD_DIRECTORY, m_autoCreateBuildDirectory); if (m_readerType.has_value()) @@ -242,6 +250,16 @@ Utils::FilePath CMakeTool::cmakeExecutable() const return cmakeExecutable(m_executable); } +void CMakeTool::setQchFilePath(const Utils::FilePath &path) +{ + m_qchFilePath = path; +} + +Utils::FilePath CMakeTool::qchFilePath() const +{ + return m_qchFilePath; +} + Utils::FilePath CMakeTool::cmakeExecutable(const Utils::FilePath &path) { if (Utils::HostOsInfo::isMacHost()) { @@ -375,21 +393,41 @@ CMakeTool::ReaderType CMakeTool::readerType() const return m_readerType.value(); } -void CMakeTool::readInformation(CMakeTool::QueryType type) const +Utils::FilePath CMakeTool::searchQchFile(const Utils::FilePath &executable) { - if ((type == QueryType::GENERATORS && !m_introspection->m_generators.isEmpty()) - || (type == QueryType::SERVER_MODE && m_introspection->m_queriedServerMode) - || (type == QueryType::VERSION && !m_introspection->m_version.fullVersion.isEmpty())) - return; + if (executable.isEmpty()) + return {}; + + Utils::FilePath prefixDir = executable.parentDir().parentDir(); + QDir docDir{prefixDir.pathAppended("doc/cmake").toString()}; + if (!docDir.exists()) + docDir.setPath(prefixDir.pathAppended("share/doc/cmake").toString()); + if (!docDir.exists()) + return {}; + const QStringList files = docDir.entryList(QStringList("*.qch")); + for (const QString &docFile : files) { + if (docFile.startsWith("cmake", Qt::CaseInsensitive)) { + return Utils::FilePath::fromString(docDir.absoluteFilePath(docFile)); + } + } + + return {}; +} + +void CMakeTool::readInformation(CMakeTool::QueryType type) const +{ if (!m_introspection->m_triedCapabilities) { fetchFromCapabilities(); m_introspection->m_triedCapabilities = true; m_introspection->m_queriedServerMode = true; // Got added after "-E capabilities" support! - if (type == QueryType::GENERATORS && !m_introspection->m_generators.isEmpty()) - return; } + if ((type == QueryType::GENERATORS && !m_introspection->m_generators.isEmpty()) + || (type == QueryType::SERVER_MODE && m_introspection->m_queriedServerMode) + || (type == QueryType::VERSION && !m_introspection->m_version.fullVersion.isEmpty())) + return; + if (type == QueryType::GENERATORS) { fetchGeneratorsFromHelp(); } else if (type == QueryType::SERVER_MODE) { diff --git a/src/plugins/cmakeprojectmanager/cmaketool.h b/src/plugins/cmakeprojectmanager/cmaketool.h index 579f6e4d72..1e305b2dd3 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.h +++ b/src/plugins/cmakeprojectmanager/cmaketool.h @@ -95,6 +95,8 @@ public: void setFilePath(const Utils::FilePath &executable); Utils::FilePath filePath() const; Utils::FilePath cmakeExecutable() const; + void setQchFilePath(const Utils::FilePath &path); + Utils::FilePath qchFilePath() const; static Utils::FilePath cmakeExecutable(const Utils::FilePath &path); bool isAutoRun() const; bool autoCreateBuildDirectory() const; @@ -114,6 +116,8 @@ public: ReaderType readerType() const; + static Utils::FilePath searchQchFile(const Utils::FilePath &executable); + private: enum class QueryType { GENERATORS, @@ -136,6 +140,7 @@ private: Core::Id m_id; QString m_displayName; Utils::FilePath m_executable; + Utils::FilePath m_qchFilePath; bool m_isAutoRun = true; bool m_isAutoDetected = false; diff --git a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp index 77f3e077a2..fd7af452c7 100644 --- a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp @@ -27,6 +27,7 @@ #include "cmaketoolsettingsaccessor.h" +#include <coreplugin/helpmanager.h> #include <coreplugin/icore.h> #include <utils/pointeralgorithm.h> @@ -105,6 +106,8 @@ bool CMakeToolManager::registerCMakeTool(std::unique_ptr<CMakeTool> &&tool) ensureDefaultCMakeToolIsValid(); + updateDocumentation(); + return true; } @@ -112,9 +115,10 @@ void CMakeToolManager::deregisterCMakeTool(const Id &id) { auto toRemove = Utils::take(d->m_cmakeTools, Utils::equal(&CMakeTool::id, id)); if (toRemove.has_value()) { - ensureDefaultCMakeToolIsValid(); + updateDocumentation(); + emit m_instance->cmakeRemoved(id); } } @@ -152,9 +156,22 @@ void CMakeToolManager::restoreCMakeTools() d->m_cmakeTools = std::move(tools.cmakeTools); setDefaultCMakeTool(tools.defaultToolId); + updateDocumentation(); + emit m_instance->cmakeToolsLoaded(); } +void CMakeToolManager::updateDocumentation() +{ + const QList<CMakeTool *> tools = cmakeTools(); + QStringList docs; + for (const auto tool : tools) { + if (!tool->qchFilePath().isEmpty()) + docs.append(tool->qchFilePath().toString()); + } + Core::HelpManager::registerDocumentation(docs); +} + void CMakeToolManager::notifyAboutUpdate(CMakeTool *tool) { if (!tool || !Utils::contains(d->m_cmakeTools, tool)) diff --git a/src/plugins/cmakeprojectmanager/cmaketoolmanager.h b/src/plugins/cmakeprojectmanager/cmaketoolmanager.h index b5ea3221dd..c91f649850 100644 --- a/src/plugins/cmakeprojectmanager/cmaketoolmanager.h +++ b/src/plugins/cmakeprojectmanager/cmaketoolmanager.h @@ -58,6 +58,8 @@ public: static void notifyAboutUpdate(CMakeTool *); static void restoreCMakeTools(); + static void updateDocumentation(); + signals: void cmakeAdded (const Core::Id &id); void cmakeRemoved (const Core::Id &id); diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp index f1fcbe1ea2..0ef2df3370 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.cpp +++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp @@ -131,8 +131,8 @@ void FileApiReader::parse(bool forceCMakeRun, bool forceConfiguration) if (forceConfiguration) { // Initial create: qCDebug(cmakeFileApiMode) << "FileApiReader: Starting CMake with forced configuration."; - startCMakeState( - CMakeProcess::toArguments(m_parameters.configuration, m_parameters.expander)); + const FilePath path = m_parameters.workDirectory.pathAppended("qtcsettings.cmake"); + startCMakeState(QStringList({QString("-C"), path.toUserOutput()})); // Keep m_isParsing enabled! return; } @@ -294,6 +294,8 @@ void FileApiReader::cmakeFinishedState(int code, QProcess::ExitStatus status) Q_UNUSED(code) Q_UNUSED(status) + m_cmakeProcess.release()->deleteLater(); + endState(m_fileApi->scanForCMakeReplyFile()); } diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.cpp b/src/plugins/cmakeprojectmanager/tealeafreader.cpp index b611f12c65..31f13234a6 100644 --- a/src/plugins/cmakeprojectmanager/tealeafreader.cpp +++ b/src/plugins/cmakeprojectmanager/tealeafreader.cpp @@ -133,7 +133,8 @@ void TeaLeafReader::parse(bool forceCMakeRun, bool forceConfiguration) const QFileInfo cbpFileFi = cbpFile.isEmpty() ? QFileInfo() : QFileInfo(cbpFile); if (!cbpFileFi.exists() || forceConfiguration) { // Initial create: - startCMake(CMakeProcess::toArguments(m_parameters.configuration, m_parameters.expander)); + const FilePath path = m_parameters.workDirectory.pathAppended("qtcsettings.cmake"); + startCMake(QStringList({QString("-C"), path.toUserOutput()})); return; } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp index ec16d72bd5..d9bf685f08 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp @@ -34,6 +34,7 @@ #include <projectexplorer/buildinfo.h> #include <projectexplorer/buildsteplist.h> #include <projectexplorer/buildtargetinfo.h> +#include <projectexplorer/deploymentdata.h> #include <projectexplorer/gcctoolchain.h> #include <projectexplorer/headerpath.h> #include <projectexplorer/kitinformation.h> @@ -47,6 +48,7 @@ #include <texteditor/textdocument.h> #include <utils/algorithm.h> +#include <utils/filesystemwatcher.h> #include <utils/qtcassert.h> #include <utils/runextensions.h> @@ -390,26 +392,27 @@ void CompilationDatabaseProject::buildTreeAndProjectParts() setRootProjectNode(std::move(root)); m_cppCodeModelUpdater->update({this, kitInfo, activeParseEnvironment(), rpps}); + updateDeploymentData(); } CompilationDatabaseProject::CompilationDatabaseProject(const Utils::FilePath &projectFile) : Project(Constants::COMPILATIONDATABASEMIMETYPE, projectFile) , m_cppCodeModelUpdater(std::make_unique<CppTools::CppProjectUpdater>()) , m_parseDelay(new QTimer(this)) + , m_deployFileWatcher(new FileSystemWatcher(this)) { setId(Constants::COMPILATIONDATABASEPROJECT_ID); setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); setDisplayName(projectDirectory().fileName()); - setRequiredKitPredicate([](const Kit *) { return false; }); - setPreferredKitPredicate([](const Kit *) { return false; }); m_kit.reset(KitManager::defaultKit()->clone()); addTargetForKit(m_kit.get()); - connect(this, - &CompilationDatabaseProject::rootProjectDirectoryChanged, - m_parseDelay, - QOverload<>::of(&QTimer::start)); + connect(this, &CompilationDatabaseProject::rootProjectDirectoryChanged, + this, [this] { + m_projectFileHash.clear(); + m_parseDelay->start(); + }); setExtraProjectFiles( {projectFile.stringAppended(Constants::COMPILATIONDATABASEPROJECT_FILES_SUFFIX)}); @@ -419,6 +422,10 @@ CompilationDatabaseProject::CompilationDatabaseProject(const Utils::FilePath &pr m_parseDelay->setInterval(1000); connect(this, &Project::projectFileIsDirty, this, &CompilationDatabaseProject::reparseProject); + connect(m_deployFileWatcher, &FileSystemWatcher::fileChanged, + this, &CompilationDatabaseProject::updateDeploymentData); + connect(this, &Project::activeTargetChanged, + this, &CompilationDatabaseProject::updateDeploymentData); } Utils::FilePath CompilationDatabaseProject::rootPathFromSettings() const @@ -458,14 +465,34 @@ void CompilationDatabaseProject::reparseProject() m_mimeBinaryCache, guardParsingRun(), this); - connect(m_parser, &CompilationDbParser::finished, this, [this](bool success) { - if (success) + connect(m_parser, &CompilationDbParser::finished, this, [this](ParseResult result) { + m_projectFileHash = m_parser->projectFileHash(); + if (result == ParseResult::Success) buildTreeAndProjectParts(); m_parser = nullptr; }); + m_parser->setPreviousProjectFileHash(m_projectFileHash); m_parser->start(); } +void CompilationDatabaseProject::updateDeploymentData() +{ + Target * const target = activeTarget(); + if (!target) + return; + const Utils::FilePath deploymentFilePath = projectDirectory() + .pathAppended("QtCreatorDeployment.txt"); + DeploymentData deploymentData; + deploymentData.addFilesFromDeploymentFile(deploymentFilePath.toString(), + projectDirectory().toString()); + target->setDeploymentData(deploymentData); + if (m_deployFileWatcher->files() != QStringList(deploymentFilePath.toString())) { + m_deployFileWatcher->removeFiles(m_deployFileWatcher->files()); + m_deployFileWatcher->addFile(deploymentFilePath.toString(), + FileSystemWatcher::WatchModifiedDate); + } +} + CompilationDatabaseProject::~CompilationDatabaseProject() { m_parserWatcher.cancel(); @@ -498,19 +525,6 @@ CompilationDatabaseBuildConfiguration::CompilationDatabaseBuildConfiguration( ProjectExplorer::Target *target, Core::Id id) : ProjectExplorer::BuildConfiguration(target, id) { - target->setApplicationTargets({BuildTargetInfo()}); -} - -void CompilationDatabaseBuildConfiguration::initialize() -{ - ProjectExplorer::BuildConfiguration::initialize(); - BuildStepList *buildSteps = stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); - buildSteps->appendStep(ProjectExplorer::Constants::PROCESS_STEP_ID); -} - -ProjectExplorer::NamedWidget *CompilationDatabaseBuildConfiguration::createConfigWidget() -{ - return new ProjectExplorer::NamedWidget(); } CompilationDatabaseBuildConfigurationFactory::CompilationDatabaseBuildConfigurationFactory() @@ -523,13 +537,14 @@ CompilationDatabaseBuildConfigurationFactory::CompilationDatabaseBuildConfigurat } QList<BuildInfo> CompilationDatabaseBuildConfigurationFactory::availableBuilds - (const Kit *kit, const FilePath &, bool) const + (const Kit *kit, const FilePath &projectPath, bool) const { const QString name = tr("Release"); ProjectExplorer::BuildInfo info(this); info.typeName = name; info.displayName = name; info.buildType = BuildConfiguration::Release; + info.buildDirectory = projectPath.parentDir(); info.kitId = kit->id(); return {info}; } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h index ca829f312a..900f7d3675 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h @@ -38,13 +38,9 @@ QT_BEGIN_NAMESPACE class QTimer; QT_END_NAMESPACE -namespace CppTools { -class CppProjectUpdater; -} - -namespace ProjectExplorer { -class Kit; -} +namespace CppTools { class CppProjectUpdater; } +namespace ProjectExplorer { class Kit; } +namespace Utils { class FileSystemWatcher; } namespace CompilationDatabaseProjectManager { namespace Internal { @@ -63,6 +59,7 @@ private: RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override; void reparseProject(); + void updateDeploymentData(); void buildTreeAndProjectParts(); Utils::FilePath rootPathFromSettings() const; @@ -70,8 +67,10 @@ private: std::unique_ptr<CppTools::CppProjectUpdater> m_cppCodeModelUpdater; std::unique_ptr<ProjectExplorer::Kit> m_kit; MimeBinaryCache m_mimeBinaryCache; + QByteArray m_projectFileHash; QTimer * const m_parseDelay; CompilationDbParser *m_parser = nullptr; + Utils::FileSystemWatcher * const m_deployFileWatcher; }; class CompilationDatabaseEditorFactory : public TextEditor::TextEditorFactory @@ -87,10 +86,6 @@ class CompilationDatabaseBuildConfiguration : public ProjectExplorer::BuildConfi Q_OBJECT public: CompilationDatabaseBuildConfiguration(ProjectExplorer::Target *target, Core::Id id); - ProjectExplorer::NamedWidget *createConfigWidget() override; - -protected: - void initialize() override; }; class CompilationDatabaseBuildConfigurationFactory diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp index 0eca37325c..04d9af3e91 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.cpp @@ -33,75 +33,87 @@ #include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/command.h> #include <coreplugin/fileiconprovider.h> + #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectmanager.h> #include <projectexplorer/projecttree.h> #include <projectexplorer/session.h> + +#include <utils/parameteraction.h> #include <utils/utilsicons.h> +using namespace Core; +using namespace ProjectExplorer; + namespace CompilationDatabaseProjectManager { namespace Internal { const char CHANGEROOTDIR[] = "CompilationDatabaseProjectManager.ChangeRootDirectory"; const char COMPILE_COMMANDS_JSON[] = "compile_commands.json"; +class CompilationDatabaseProjectManagerPluginPrivate +{ +public: + CompilationDatabaseEditorFactory editorFactory; + CompilationDatabaseBuildConfigurationFactory buildConfigFactory; + QAction changeRootAction{CompilationDatabaseProjectManagerPlugin::tr("Change Root Directory")}; +}; + +CompilationDatabaseProjectManagerPlugin::~CompilationDatabaseProjectManagerPlugin() +{ + delete d; +} + bool CompilationDatabaseProjectManagerPlugin::initialize(const QStringList &arguments, QString *errorMessage) { Q_UNUSED(arguments) Q_UNUSED(errorMessage) - Core::FileIconProvider::registerIconOverlayForFilename( + + d = new CompilationDatabaseProjectManagerPluginPrivate; + + FileIconProvider::registerIconOverlayForFilename( Utils::Icons::PROJECT.imageFileName(), COMPILE_COMMANDS_JSON); - Core::FileIconProvider::registerIconOverlayForFilename( + FileIconProvider::registerIconOverlayForFilename( Utils::Icons::PROJECT.imageFileName(), QString(COMPILE_COMMANDS_JSON) + Constants::COMPILATIONDATABASEPROJECT_FILES_SUFFIX); - ProjectExplorer::ProjectManager::registerProjectType<CompilationDatabaseProject>( + ProjectManager::registerProjectType<CompilationDatabaseProject>( Constants::COMPILATIONDATABASEMIMETYPE); - m_changeProjectRootDirectoryAction = new QAction(tr("Change Root Directory"), this); - Core::Command *cmd = Core::ActionManager::registerAction(m_changeProjectRootDirectoryAction, - CHANGEROOTDIR); - Core::ActionContainer *mprojectContextMenu = Core::ActionManager::actionContainer( + + Command *cmd = ActionManager::registerAction(&d->changeRootAction, CHANGEROOTDIR); + + ActionContainer *mprojectContextMenu = ActionManager::actionContainer( ProjectExplorer::Constants::M_PROJECTCONTEXT); mprojectContextMenu->addSeparator(ProjectExplorer::Constants::G_PROJECT_TREE); mprojectContextMenu->addAction(cmd, ProjectExplorer::Constants::G_PROJECT_TREE); - connect(m_changeProjectRootDirectoryAction, - &QAction::triggered, - ProjectExplorer::ProjectTree::instance(), - &ProjectExplorer::ProjectTree::changeProjectRootDirectory); + connect(&d->changeRootAction, &QAction::triggered, + ProjectTree::instance(), &ProjectTree::changeProjectRootDirectory); - connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::startupProjectChanged, - this, - &CompilationDatabaseProjectManagerPlugin::projectChanged); - connect(ProjectExplorer::ProjectTree::instance(), - &ProjectExplorer::ProjectTree::currentProjectChanged, - this, - &CompilationDatabaseProjectManagerPlugin::projectChanged); + const auto onProjectChanged = [this] { + const auto currentProject = qobject_cast<CompilationDatabaseProject *>( + ProjectTree::currentProject()); - return true; -} + d->changeRootAction.setEnabled(currentProject); + }; -void CompilationDatabaseProjectManagerPlugin::projectChanged() -{ - const auto *currentProject = qobject_cast<CompilationDatabaseProject *>( - ProjectExplorer::ProjectTree::currentProject()); + connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + this, onProjectChanged); - m_changeProjectRootDirectoryAction->setEnabled(currentProject); -} + connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, + this, onProjectChanged); -void CompilationDatabaseProjectManagerPlugin::extensionsInitialized() -{ + return true; } QVector<QObject *> CompilationDatabaseProjectManagerPlugin::createTestObjects() const { - QVector<QObject *> tests; + return { #ifdef WITH_TESTS - tests << new CompilationDatabaseTests; + new CompilationDatabaseTests #endif - return tests; + }; } } // namespace Internal diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.h b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.h index 42a15ad3cf..b825172ca6 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.h +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseprojectmanagerplugin.h @@ -25,11 +25,7 @@ #pragma once -#include "compilationdatabaseproject.h" - -#include <coreplugin/id.h> #include <extensionsystem/iplugin.h> -#include <utils/parameteraction.h> namespace CompilationDatabaseProjectManager { namespace Internal { @@ -39,17 +35,13 @@ class CompilationDatabaseProjectManagerPlugin final : public ExtensionSystem::IP Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "CompilationDatabaseProjectManager.json") -public: - bool initialize(const QStringList &arguments, QString *errorMessage) final; - void extensionsInitialized() final; -private: - void projectChanged(); + ~CompilationDatabaseProjectManagerPlugin(); + bool initialize(const QStringList &arguments, QString *errorMessage) final; + void extensionsInitialized() final {} QVector<QObject *> createTestObjects() const final; - CompilationDatabaseEditorFactory factory; - CompilationDatabaseBuildConfigurationFactory buildConfigFactory; - QAction *m_changeProjectRootDirectoryAction; + class CompilationDatabaseProjectManagerPluginPrivate *d = nullptr; }; } // namespace Internal diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp index 6c91311898..374c245b23 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp @@ -31,6 +31,7 @@ #include <utils/mimetypes/mimetype.h> #include <utils/runextensions.h> +#include <QCryptographicHash> #include <QDir> #include <QFileInfo> #include <QJsonArray> @@ -59,12 +60,27 @@ CompilationDbParser::CompilationDbParser(const QString &projectName, connect(&m_parserWatcher, &QFutureWatcher<void>::finished, this, [this] { m_dbContents = m_parserWatcher.result(); if (!m_treeScanner || m_treeScanner->isFinished()) - finish(); + finish(ParseResult::Success); }); } void CompilationDbParser::start() { + // Check hash first. + QFile file(m_projectFilePath.toString()); + if (!file.open(QIODevice::ReadOnly)) { + finish(ParseResult::Failure); + return; + } + m_projectFileContents = file.readAll(); + const QByteArray newHash = QCryptographicHash::hash(m_projectFileContents, + QCryptographicHash::Sha1); + if (m_projectFileHash == newHash) { + finish(ParseResult::Cached); + return; + } + m_projectFileHash = newHash; + // Thread 1: Scan disk. if (!m_rootPath.isEmpty()) { m_treeScanner = new TreeScanner(this); @@ -95,7 +111,7 @@ void CompilationDbParser::start() "CompilationDatabase.Scan.Tree"); connect(m_treeScanner, &TreeScanner::finished, this, [this] { if (m_parserWatcher.isFinished()) - finish(); + finish(ParseResult::Success); }); } @@ -126,9 +142,9 @@ QList<FileNode *> CompilationDbParser::scannedFiles() const ? m_treeScanner->release() : QList<FileNode *>(); } -void CompilationDbParser::finish() +void CompilationDbParser::finish(ParseResult result) { - emit finished(true); + emit finished(result); deleteLater(); } @@ -158,24 +174,20 @@ static FilePath jsonObjectFilename(const QJsonObject &object) return fileName; } -static std::vector<DbEntry> readJsonObjects(const QString &filePath) +std::vector<DbEntry> CompilationDbParser::readJsonObjects() const { std::vector<DbEntry> result; - QFile file(filePath); - if (!file.open(QIODevice::ReadOnly)) - return result; - const QByteArray contents = file.readAll(); - int objectStart = contents.indexOf('{'); - int objectEnd = contents.indexOf('}', objectStart + 1); + int objectStart = m_projectFileContents.indexOf('{'); + int objectEnd = m_projectFileContents.indexOf('}', objectStart + 1); QSet<QString> flagsCache; while (objectStart >= 0 && objectEnd >= 0) { const QJsonDocument document = QJsonDocument::fromJson( - contents.mid(objectStart, objectEnd - objectStart + 1)); + m_projectFileContents.mid(objectStart, objectEnd - objectStart + 1)); if (document.isNull()) { // The end was found incorrectly, search for the next one. - objectEnd = contents.indexOf('}', objectEnd + 1); + objectEnd = m_projectFileContents.indexOf('}', objectEnd + 1); continue; } @@ -185,8 +197,8 @@ static std::vector<DbEntry> readJsonObjects(const QString &filePath) fileName.toFileInfo().baseName()); result.push_back({flags, fileName, object["directory"].toString()}); - objectStart = contents.indexOf('{', objectEnd + 1); - objectEnd = contents.indexOf('}', objectStart + 1); + objectStart = m_projectFileContents.indexOf('{', objectEnd + 1); + objectEnd = m_projectFileContents.indexOf('}', objectStart + 1); } return result; @@ -217,7 +229,7 @@ QStringList readExtraFiles(const QString &filePath) DbContents CompilationDbParser::parseProject() { DbContents dbContents; - dbContents.entries = readJsonObjects(m_projectFilePath.toString()); + dbContents.entries = readJsonObjects(); dbContents.extraFileName = m_projectFilePath.toString() + Constants::COMPILATIONDATABASEPROJECT_FILES_SUFFIX; dbContents.extras = readExtraFiles(dbContents.extraFileName); diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.h b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.h index fe3e319076..ac5fbb0afb 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.h +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.h @@ -46,6 +46,8 @@ class TreeScanner; namespace CompilationDatabaseProjectManager { namespace Internal { +enum class ParseResult { Success, Failure, Cached }; + class CompilationDbParser : public QObject { Q_OBJECT @@ -57,6 +59,10 @@ public: ProjectExplorer::Project::ParseGuard &&guard, QObject *parent = nullptr); + + void setPreviousProjectFileHash(const QByteArray &fileHash) { m_projectFileHash = fileHash; } + QByteArray projectFileHash() const { return m_projectFileHash; } + void start(); void stop(); @@ -68,11 +74,12 @@ public: } signals: - void finished(bool success); + void finished(ParseResult result); private: - void finish(); + void finish(ParseResult result); DbContents parseProject(); + std::vector<DbEntry> readJsonObjects() const; const QString m_projectName; const Utils::FilePath m_projectFilePath; @@ -81,6 +88,8 @@ private: ProjectExplorer::TreeScanner *m_treeScanner = nullptr; QFutureWatcher<DbContents> m_parserWatcher; DbContents m_dbContents; + QByteArray m_projectFileContents; + QByteArray m_projectFileHash; ProjectExplorer::Project::ParseGuard m_guard; }; diff --git a/src/plugins/ctfvisualizer/ctfstatisticsmodel.cpp b/src/plugins/ctfvisualizer/ctfstatisticsmodel.cpp index 1f1320c403..8738d3d747 100644 --- a/src/plugins/ctfvisualizer/ctfstatisticsmodel.cpp +++ b/src/plugins/ctfvisualizer/ctfstatisticsmodel.cpp @@ -47,11 +47,9 @@ void CtfStatisticsModel::beginLoading() m_data.clear(); } -void CtfStatisticsModel::addEvent(const json &event, qint64 durationInNs) +void CtfStatisticsModel::addEvent(const QString &title, qint64 durationInNs) { - const std::string name = event.value(CtfEventNameKey, ""); - - EventData &data = m_data[QString::fromStdString(name)]; + EventData &data = m_data[title]; ++data.count; if (durationInNs >= 0) { data.totalDuration += durationInNs; @@ -60,6 +58,11 @@ void CtfStatisticsModel::addEvent(const json &event, qint64 durationInNs) } } +void CtfStatisticsModel::setMeasurementDuration(qint64 timeInNs) +{ + m_measurementDurationInNs = timeInNs; +} + void CtfStatisticsModel::endLoading() { endResetModel(); @@ -89,6 +92,7 @@ QVariant CtfStatisticsModel::data(const QModelIndex &index, int role) const return Qt::AlignLeft; case Column::Count: case Column::TotalDuration: + case Column::RelativeDuration: case Column::MinDuration: case Column::AvgDuration: case Column::MaxDuration: @@ -105,6 +109,8 @@ QVariant CtfStatisticsModel::data(const QModelIndex &index, int role) const return m_data.value(title).count; case Column::TotalDuration: return m_data.value(title).totalDuration; + case Column::RelativeDuration: + return m_data.value(title).totalDuration; case Column::MinDuration: { auto minDuration = m_data.value(title).minDuration; @@ -136,6 +142,16 @@ QVariant CtfStatisticsModel::data(const QModelIndex &index, int role) const else return "-"; } + case Column::RelativeDuration: + { + auto totalDuration = m_data.value(title).totalDuration; + if (m_measurementDurationInNs > 0 && totalDuration > 0) { + const double percent = (totalDuration / double(m_measurementDurationInNs)) * 100; + return QString("%1 %").arg(percent, 0, 'f', 2); + } else { + return "-"; + } + } case Column::MinDuration: { auto minDuration = m_data.value(title).minDuration; @@ -177,6 +193,8 @@ QVariant CtfStatisticsModel::headerData(int section, Qt::Orientation orientation return tr("Count"); case Column::TotalDuration: return tr("Total Time"); + case Column::RelativeDuration: + return tr("Percentage"); case Column::MinDuration: return tr("Minimum Time"); case Column::AvgDuration: diff --git a/src/plugins/ctfvisualizer/ctfstatisticsmodel.h b/src/plugins/ctfvisualizer/ctfstatisticsmodel.h index 10af0b8b3a..434d7c9c96 100644 --- a/src/plugins/ctfvisualizer/ctfstatisticsmodel.h +++ b/src/plugins/ctfvisualizer/ctfstatisticsmodel.h @@ -49,6 +49,7 @@ public: Title = 0, Count, TotalDuration, + RelativeDuration, MinDuration, AvgDuration, MaxDuration, @@ -66,7 +67,8 @@ public: ~CtfStatisticsModel() override = default; void beginLoading(); - void addEvent(const nlohmann::json &event, qint64 duration); + void addEvent(const QString &title, qint64 durationInNs); + void setMeasurementDuration(qint64 timeInNs); void endLoading(); private: @@ -77,6 +79,7 @@ private: QVariant headerData(int section, Qt::Orientation orientation, int role) const override; QHash<QString, EventData> m_data; + qint64 m_measurementDurationInNs = 0; }; diff --git a/src/plugins/ctfvisualizer/ctftimelinemodel.cpp b/src/plugins/ctfvisualizer/ctftimelinemodel.cpp index 4b0d6b1a61..827f919055 100644 --- a/src/plugins/ctfvisualizer/ctftimelinemodel.cpp +++ b/src/plugins/ctfvisualizer/ctftimelinemodel.cpp @@ -87,6 +87,14 @@ QVariantList CtfTimelineModel::labels() const QVariantMap CtfTimelineModel::orderedDetails(int index) const { QMap<int, QPair<QString, QString>> info = m_details.value(index); + const int counterIdx = m_itemToCounterIdx.value(index, 0); + if (counterIdx > 0) { + // this item is a counter, add its properties: + info.insert(0, {{}, QString::fromStdString(m_counterNames.at(counterIdx - 1))}); + info.insert(4, {tr("Value"), QString::number(double(m_counterValues.at(index)), 'g')}); + info.insert(5, {tr("Min"), QString::number(double(m_counterData.at(counterIdx - 1).min), 'g')}); + info.insert(6, {tr("Max"), QString::number(double(m_counterData.at(counterIdx - 1).max), 'g')}); + } info.insert(2, {tr("Start"), Timeline::formatTime(startTime(index))}); info.insert(3, {tr("Wall Duration"), Timeline::formatTime(duration(index))}); QVariantMap data; @@ -209,12 +217,26 @@ void CtfTimelineModel::finalize(double traceBegin, double traceEnd, const QStrin emit contentChanged(); } +int CtfTimelineModel::tid() const +{ + return m_threadId; +} + +QString CtfTimelineModel::eventTitle(int index) const +{ + const int counterIdx = m_itemToCounterIdx.value(index, 0); + if (counterIdx > 0) { + return QString::fromStdString(m_counterNames.at(counterIdx - 1)); + } + return m_details.value(index).value(0).second; +} + void CtfTimelineModel::updateName() { if (m_threadName.isEmpty()) { - setDisplayName(tr("> Thread %1").arg(m_threadId)); + setDisplayName(tr("Thread %1").arg(m_threadId)); } else { - setDisplayName(QString("> %1 (%2)").arg(m_threadName).arg(m_threadId)); + setDisplayName(QString("%1 (%2)").arg(m_threadName).arg(m_threadId)); } QString process = m_processName.isEmpty() ? QString::number(m_processId) : QString("%1 (%2)").arg(m_processName).arg(m_processId); diff --git a/src/plugins/ctfvisualizer/ctftimelinemodel.h b/src/plugins/ctfvisualizer/ctftimelinemodel.h index 4be3012ba4..3c80cb6ec9 100644 --- a/src/plugins/ctfvisualizer/ctftimelinemodel.h +++ b/src/plugins/ctfvisualizer/ctftimelinemodel.h @@ -67,6 +67,9 @@ public: void finalize(double traceBegin, double traceEnd, const QString &processName, const QString &threadName); + int tid() const; + QString eventTitle(int index) const; + signals: void detailsRequested(const QString &eventName) const; diff --git a/src/plugins/ctfvisualizer/ctftracemanager.cpp b/src/plugins/ctfvisualizer/ctftracemanager.cpp index 855f834128..52859e08b1 100644 --- a/src/plugins/ctfvisualizer/ctftracemanager.cpp +++ b/src/plugins/ctfvisualizer/ctftracemanager.cpp @@ -146,7 +146,6 @@ void CtfTraceManager::addEvent(const json &event) if (visibleOnTimeline) { m_traceBegin = std::min(m_traceBegin, timestamp); m_traceEnd = std::max(m_traceEnd, timestamp); - m_statisticsModel->addEvent(event, result.second); } else if (m_timeOffset == timestamp) { // this timestamp was used as the time offset but it is not a visible element // -> reset the time offset again: @@ -169,10 +168,9 @@ void CtfVisualizer::Internal::CtfTraceManager::load(const QString &filename) json::parser_callback_t callback = [&ctfParser](int depth, json::parse_event_t event, json &parsed) { return ctfParser.callback(depth, event, parsed); }; - m_statisticsModel->beginLoading(); json unusedValues = json::parse(file, callback, /*allow_exceptions*/ false); - m_statisticsModel->endLoading(); file.close(); + updateStatistics(); } void CtfTraceManager::finalize() @@ -192,6 +190,7 @@ void CtfTraceManager::finalize() } } m_threadModels.remove(tid); + m_threadRestrictions.remove(tid); } } for (CtfTimelineModel *model: m_threadModels) { @@ -216,27 +215,75 @@ int CtfTraceManager::getSelectionId(const std::string &name) return *it; } +QList<CtfTimelineModel *> CtfTraceManager::getSortedThreads() const +{ + QList<CtfTimelineModel *> models = m_threadModels.values(); + std::sort(models.begin(), models.end(), [](const CtfTimelineModel *a, const CtfTimelineModel *b) -> bool { + return (a->m_processId != b->m_processId) ? (a->m_processId < b->m_processId) + : (std::abs(a->m_threadId) < std::abs(b->m_threadId)); + }); + return models; +} + +void CtfTraceManager::setThreadRestriction(int tid, bool restrictToThisThread) +{ + if (m_threadRestrictions.value(tid) == restrictToThisThread) + return; + + m_threadRestrictions[tid] = restrictToThisThread; + addModelsToAggregator(); +} + +bool CtfTraceManager::isRestrictedTo(int tid) const +{ + return m_threadRestrictions.value(tid); +} + void CtfTraceManager::addModelForThread(int threadId, int processId) { CtfTimelineModel *model = new CtfTimelineModel(m_modelAggregator, this, threadId, processId); m_threadModels.insert(threadId, model); + m_threadRestrictions.insert(threadId, false); connect(model, &CtfTimelineModel::detailsRequested, this, &CtfTraceManager::detailsRequested); } void CtfTraceManager::addModelsToAggregator() { - QList<CtfTimelineModel *> models = m_threadModels.values(); - std::sort(models.begin(), models.end(), [](const CtfTimelineModel *a, const CtfTimelineModel *b) -> bool { - return (a->m_processId != b->m_processId) ? (a->m_processId < b->m_processId) - : (std::abs(a->m_threadId) < std::abs(b->m_threadId)); + const QList<CtfTimelineModel *> models = getSortedThreads(); + + const bool showAll = std::none_of(m_threadRestrictions.begin(), m_threadRestrictions.end(), [](bool value) { + return value; }); QVariantList modelsToAdd; for (CtfTimelineModel *model: models) { - modelsToAdd.append(QVariant::fromValue(model)); + if (showAll || isRestrictedTo(model->tid())) + modelsToAdd.append(QVariant::fromValue(model)); } m_modelAggregator->setModels(modelsToAdd); + updateStatistics(); +} + +void CtfTraceManager::updateStatistics() +{ + const bool showAll = std::none_of(m_threadRestrictions.begin(), m_threadRestrictions.end(), [](bool value) { + return value; + }); + + m_statisticsModel->beginLoading(); + for (auto thread : m_threadModels) { + if (showAll || m_threadRestrictions[thread->tid()]) + { + const int eventCount = thread->count(); + for (int i = 0; i < eventCount; ++i) { + QString title = thread->eventTitle(i); + m_statisticsModel->addEvent(title, thread->duration(i)); + } + } + } + m_statisticsModel->setMeasurementDuration(qint64((m_traceEnd - m_traceBegin) * 1000)); + m_statisticsModel->endLoading(); } void CtfTraceManager::clearAll() diff --git a/src/plugins/ctfvisualizer/ctftracemanager.h b/src/plugins/ctfvisualizer/ctftracemanager.h index 5de87eafad..adcb65c35e 100644 --- a/src/plugins/ctfvisualizer/ctftracemanager.h +++ b/src/plugins/ctfvisualizer/ctftracemanager.h @@ -64,6 +64,11 @@ public: int getSelectionId(const std::string &name); + QList<CtfTimelineModel *> getSortedThreads() const; + + void setThreadRestriction(int tid, bool restrictToThisThread); + bool isRestrictedTo(int tid) const; + signals: void detailsRequested(const QString &title); @@ -72,6 +77,8 @@ protected: void addModelForThread(int threadId, int processId); void addModelsToAggregator(); + void updateStatistics(); + void clearAll(); Timeline::TimelineModelAggregator *const m_modelAggregator; @@ -81,6 +88,7 @@ protected: QHash<qint64, QString> m_processNames; QHash<qint64, QString> m_threadNames; QMap<std::string, int> m_name2selectionId; + QHash<qint64, bool> m_threadRestrictions; double m_traceBegin = std::numeric_limits<double>::max(); double m_traceEnd = std::numeric_limits<double>::min(); diff --git a/src/plugins/ctfvisualizer/ctfvisualizertool.cpp b/src/plugins/ctfvisualizer/ctfvisualizertool.cpp index 96b1489978..2c7a38b7b7 100644 --- a/src/plugins/ctfvisualizer/ctfvisualizertool.cpp +++ b/src/plugins/ctfvisualizer/ctfvisualizertool.cpp @@ -29,6 +29,7 @@ #include "ctfstatisticsmodel.h" #include "ctfstatisticsview.h" +#include "ctftimelinemodel.h" #include "ctfvisualizertraceview.h" #include <coreplugin/actionmanager/actioncontainer.h> @@ -36,6 +37,7 @@ #include <coreplugin/icore.h> #include <coreplugin/progressmanager/progressmanager.h> #include <debugger/analyzer/analyzerconstants.h> +#include <utils/utilsicons.h> #include <QAction> #include <QApplication> @@ -62,6 +64,8 @@ CtfVisualizerTool::CtfVisualizerTool() , m_statisticsModel(new CtfStatisticsModel(this)) , m_statisticsView(nullptr) , m_traceManager(new CtfTraceManager(this, m_modelAggregator.get(), m_statisticsModel.get())) + , m_restrictToThreadsButton(new QToolButton) + , m_restrictToThreadsMenu(new QMenu(m_restrictToThreadsButton)) { ActionContainer *menu = ActionManager::actionContainer(Debugger::Constants::M_DEBUG_ANALYZER); ActionContainer *options = ActionManager::createMenu(Constants::CtfVisualizerMenuId); @@ -78,6 +82,16 @@ CtfVisualizerTool::CtfVisualizerTool() options->addAction(command); m_perspective.setAboutToActivateCallback([this]() { createViews(); }); + + m_restrictToThreadsButton->setIcon(Utils::Icons::FILTER.icon()); + m_restrictToThreadsButton->setToolTip(tr("Restrict to threads")); + m_restrictToThreadsButton->setPopupMode(QToolButton::InstantPopup); + m_restrictToThreadsButton->setProperty("noArrow", true); + m_restrictToThreadsButton->setMenu(m_restrictToThreadsMenu); + connect(m_restrictToThreadsMenu, &QMenu::triggered, + this, &CtfVisualizerTool::toggleThreadRestriction); + + m_perspective.addToolBarWidget(m_restrictToThreadsButton); } CtfVisualizerTool::~CtfVisualizerTool() = default; @@ -116,6 +130,24 @@ void CtfVisualizerTool::createViews() m_perspective.setAboutToActivateCallback(Utils::Perspective::Callback()); } +void CtfVisualizerTool::setAvailableThreads(const QList<CtfTimelineModel *> &threads) +{ + m_restrictToThreadsMenu->clear(); + + for (auto timelineModel : threads) { + QAction *action = m_restrictToThreadsMenu->addAction(timelineModel->displayName()); + action->setCheckable(true); + action->setData(timelineModel->tid()); + action->setChecked(m_traceManager->isRestrictedTo(timelineModel->tid())); + } +} + +void CtfVisualizerTool::toggleThreadRestriction(QAction *action) +{ + const int tid = action->data().toInt(); + m_traceManager->setThreadRestriction(tid, action->isChecked()); +} + Timeline::TimelineModelAggregator *CtfVisualizerTool::modelAggregator() const { return m_modelAggregator.get(); @@ -169,6 +201,7 @@ void CtfVisualizerTool::loadJson() zoomControl()->setTrace(m_traceManager->traceBegin(), m_traceManager->traceEnd() + m_traceManager->traceDuration() / 20); zoomControl()->setRange(m_traceManager->traceBegin(), m_traceManager->traceEnd() + m_traceManager->traceDuration() / 20); } + setAvailableThreads(m_traceManager->getSortedThreads()); thread->deleteLater(); delete task; delete futureInterface; diff --git a/src/plugins/ctfvisualizer/ctfvisualizertool.h b/src/plugins/ctfvisualizer/ctfvisualizertool.h index c5085d0f04..c1bec1def1 100644 --- a/src/plugins/ctfvisualizer/ctfvisualizertool.h +++ b/src/plugins/ctfvisualizer/ctfvisualizertool.h @@ -40,6 +40,7 @@ namespace Internal { class CtfTraceManager; class CtfStatisticsModel; class CtfStatisticsView; +class CtfTimelineModel; class CtfVisualizerTraceView; @@ -63,6 +64,9 @@ private: void initialize(); void finalize(); + void setAvailableThreads(const QList<CtfTimelineModel *> &threads); + void toggleThreadRestriction(QAction *action); + Utils::Perspective m_perspective{Constants::CtfVisualizerPerspectiveId, tr("Chrome Trace Format Visualizer")}; @@ -77,6 +81,9 @@ private: CtfStatisticsView *m_statisticsView; const QScopedPointer<CtfTraceManager> m_traceManager; + + QToolButton *const m_restrictToThreadsButton; + QMenu *const m_restrictToThreadsMenu; }; } // namespace Internal diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp index 702fe98c84..bf9d4d9a20 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp @@ -62,7 +62,7 @@ class DebuggerLanguageAspect : public ProjectConfigurationAspect public: DebuggerLanguageAspect() = default; - void addToConfigurationLayout(QFormLayout *layout) override; + void addToLayout(LayoutBuilder &builder) override; bool value() const; void setValue(bool val); @@ -91,35 +91,29 @@ public: std::function<void(bool)> m_clickCallBack; }; -void DebuggerLanguageAspect::addToConfigurationLayout(QFormLayout *layout) +void DebuggerLanguageAspect::addToLayout(LayoutBuilder &builder) { QTC_CHECK(!m_checkBox); - m_checkBox = new QCheckBox(m_label, layout->parentWidget()); + m_checkBox = new QCheckBox(m_label); m_checkBox->setChecked(m_value); QTC_CHECK(m_clickCallBack); connect(m_checkBox, &QAbstractButton::clicked, this, m_clickCallBack, Qt::QueuedConnection); - auto innerLayout = new QHBoxLayout; - innerLayout->setContentsMargins(0, 0, 0, 0); - connect(m_checkBox.data(), &QAbstractButton::clicked, this, [this] { m_value = m_checkBox->isChecked() ? EnabledLanguage : DisabledLanguage; emit changed(); }); - innerLayout->addWidget(m_checkBox); + builder.addItem(m_checkBox.data()); if (!m_infoLabelText.isEmpty()) { QTC_CHECK(!m_infoLabel); - m_infoLabel = new QLabel(m_infoLabelText, layout->parentWidget()); + m_infoLabel = new QLabel(m_infoLabelText); connect(m_infoLabel, &QLabel::linkActivated, [](const QString &link) { Core::HelpManager::showHelpUrl(link); }); - innerLayout->addWidget(m_infoLabel); + builder.addItem(m_infoLabel.data()); } - - innerLayout->addStretch(); - layout->addRow(innerLayout); } void DebuggerLanguageAspect::setAutoSettingsKey(const QString &settingsKey) @@ -172,18 +166,19 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target) setConfigWidgetCreator([this] { QWidget *w = new QWidget; - auto layout = new QFormLayout; - layout->setContentsMargins(0, 0, 0, 0); - - m_cppAspect->addToConfigurationLayout(layout); - m_qmlAspect->addToConfigurationLayout(layout); - m_overrideStartupAspect->addToConfigurationLayout(layout); + LayoutBuilder builder(w); + m_cppAspect->addToLayout(builder); + builder.startNewRow(); + m_qmlAspect->addToLayout(builder); + builder.startNewRow(); + m_overrideStartupAspect->addToLayout(builder); static const QByteArray env = qgetenv("QTC_DEBUGGER_MULTIPROCESS"); - if (env.toInt()) - m_multiProcessAspect->addToConfigurationLayout(layout); + if (env.toInt()) { + builder.startNewRow(); + m_multiProcessAspect->addToLayout(builder); + } - w->setLayout(layout); return w; }); diff --git a/src/plugins/debugger/procinterrupt.cpp b/src/plugins/debugger/procinterrupt.cpp index 085747ea60..b9605e653a 100644 --- a/src/plugins/debugger/procinterrupt.cpp +++ b/src/plugins/debugger/procinterrupt.cpp @@ -40,10 +40,6 @@ static inline QString msgCannotInterrupt(qint64 pid, const QString &why) } #if defined(Q_OS_WIN) - -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 /* WinXP, needed for DebugBreakProcess() */ - #include <utils/winutils.h> #include <windows.h> diff --git a/src/plugins/debugger/registerpostmortemaction.cpp b/src/plugins/debugger/registerpostmortemaction.cpp index be37504a70..477b04b354 100644 --- a/src/plugins/debugger/registerpostmortemaction.cpp +++ b/src/plugins/debugger/registerpostmortemaction.cpp @@ -23,10 +23,6 @@ ** ****************************************************************************/ -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0400 -#endif - #include "registerpostmortemaction.h" #include <registryaccess.h> diff --git a/src/plugins/debugger/shared/hostutils.cpp b/src/plugins/debugger/shared/hostutils.cpp index 5a65d5a6ea..326876fe5a 100644 --- a/src/plugins/debugger/shared/hostutils.cpp +++ b/src/plugins/debugger/shared/hostutils.cpp @@ -28,10 +28,6 @@ #ifdef Q_OS_WIN #include <QTextStream> - -// Enable Win API of XP SP1 and later -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0502 #include <windows.h> #include <utils/winutils.h> #include <tlhelp32.h> diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp index 1c280eb490..4cbfdd2117 100644 --- a/src/plugins/genericprojectmanager/genericproject.cpp +++ b/src/plugins/genericprojectmanager/genericproject.cpp @@ -40,13 +40,16 @@ #include <projectexplorer/abi.h> #include <projectexplorer/buildsteplist.h> +#include <projectexplorer/buildsystem.h> #include <projectexplorer/customexecutablerunconfiguration.h> #include <projectexplorer/deploymentdata.h> #include <projectexplorer/headerpath.h> #include <projectexplorer/kitinformation.h> #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectnodes.h> +#include <projectexplorer/selectablefilesmodel.h> #include <projectexplorer/target.h> +#include <projectexplorer/taskhub.h> #include <qtsupport/baseqtversion.h> #include <qtsupport/qtcppkitinfo.h> @@ -72,6 +75,12 @@ using namespace Utils; namespace GenericProjectManager { namespace Internal { +enum RefreshOptions { + Files = 0x01, + Configuration = 0x02, + Everything = Files | Configuration +}; + //////////////////////////////////////////////////////////////////////////////////// // // GenericProjectFile @@ -81,10 +90,8 @@ namespace Internal { class GenericProjectFile : public Core::IDocument { public: - GenericProjectFile(GenericProject *parent, const FilePath &fileName, - GenericProject::RefreshOptions options) : - m_project(parent), - m_options(options) + GenericProjectFile(GenericProject *parent, const FilePath &fileName, RefreshOptions options) + : m_project(parent), m_options(options) { setId("Generic.ProjectFile"); setMimeType(Constants::GENERICMIMETYPE); @@ -96,19 +103,11 @@ public: return BehaviorSilent; } - bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override - { - Q_UNUSED(errorString) - Q_UNUSED(flag) - if (type == TypePermissions) - return true; - m_project->refresh(m_options); - return true; - } + bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override; private: GenericProject *m_project = nullptr; - GenericProject::RefreshOptions m_options; + RefreshOptions m_options; }; @@ -118,17 +117,13 @@ private: // //////////////////////////////////////////////////////////////////////////////////// -class GenericProjectNode : public ProjectNode +class GenericBuildSystem : public BuildSystem { public: - explicit GenericProjectNode(GenericProject *project) : - ProjectNode(project->projectDirectory()), - m_project(project) - { - setDisplayName(project->projectFilePath().toFileInfo().completeBaseName()); - } + explicit GenericBuildSystem(Project *project); + ~GenericBuildSystem(); - bool supportsAction(ProjectAction action, const Node *) const override + bool supportsAction(Node *, ProjectAction action, const Node *) const final { return action == AddNewFile || action == AddExistingFile @@ -137,25 +132,47 @@ public: || action == Rename; } - bool addFiles(const QStringList &filePaths, QStringList * = nullptr) override - { - return m_project->addFiles(filePaths); - } + RemovedFilesFromProject removeFiles(Node *, const QStringList &filePaths, QStringList *) final; + bool renameFile(Node *, const QString &filePath, const QString &newFilePath) final; + bool addFiles(Node *, const QStringList &filePaths, QStringList *) final; - RemovedFilesFromProject removeFiles(const QStringList &filePaths, - QStringList * = nullptr) override - { - return m_project->removeFiles(filePaths) ? RemovedFilesFromProject::Ok - : RemovedFilesFromProject::Error; - } + GenericProject *project() const { return static_cast<GenericProject *>(BuildSystem::project()); } - bool renameFile(const QString &filePath, const QString &newFilePath) override - { - return m_project->renameFile(filePath, newFilePath); - } + FilePath filesFilePath() const { return ::FilePath::fromString(m_filesFileName); } + + void refresh(RefreshOptions options); + + bool saveRawFileList(const QStringList &rawFileList); + bool saveRawList(const QStringList &rawList, const QString &fileName); + void parse(RefreshOptions options); + + QStringList processEntries(const QStringList &paths, + QHash<QString, QString> *map = nullptr) const; + + Utils::FilePath findCommonSourceRoot(); + void refreshCppCodeModel(); + void updateDeploymentData(); + + bool setFiles(const QStringList &filePaths); + void removeFiles(const QStringList &filesToRemove); private: - GenericProject *m_project = nullptr; + QString m_filesFileName; + QString m_includesFileName; + QString m_configFileName; + QString m_cxxflagsFileName; + QString m_cflagsFileName; + QStringList m_rawFileList; + QStringList m_files; + QHash<QString, QString> m_rawListEntries; + QStringList m_rawProjectIncludePaths; + ProjectExplorer::HeaderPaths m_projectIncludePaths; + QStringList m_cxxflags; + QStringList m_cflags; + + CppTools::CppProjectUpdaterInterface *m_cppCodeModelUpdater = nullptr; + + Utils::FileSystemWatcher * const m_deployFileWatcher = nullptr; }; @@ -173,12 +190,16 @@ static bool writeFile(const QString &filePath, const QString &contents) GenericProject::GenericProject(const Utils::FilePath &fileName) : Project(Constants::GENERICMIMETYPE, fileName) - , m_deployFileWatcher(new FileSystemWatcher(this)) { setId(Constants::GENERICPROJECT_ID); setProjectLanguages(Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); setDisplayName(fileName.toFileInfo().completeBaseName()); + setBuildSystemCreator([](Project *p) { return new GenericBuildSystem(p); }); +} +GenericBuildSystem::GenericBuildSystem(Project *project) + : BuildSystem(project) +{ QObject *projectUpdaterFactory = ExtensionSystem::PluginManager::getObjectByName( "CppProjectUpdaterFactory"); if (projectUpdaterFactory) { @@ -190,7 +211,7 @@ GenericProject::GenericProject(const Utils::FilePath &fileName) QTC_CHECK(successFullyCreatedProjectUpdater); } - connect(this, &GenericProject::projectFileIsDirty, this, [this](const FilePath &p) { + connect(project, &Project::projectFileIsDirty, this, [this](const FilePath &p) { if (p.endsWith(".files")) refresh(Files); else if (p.endsWith(".includes") || p.endsWith(".config") || p.endsWith(".cxxflags") @@ -221,23 +242,21 @@ GenericProject::GenericProject(const Utils::FilePath &fileName) QTC_CHECK(writeFile(m_cflagsFileName, Constants::GENERICPROJECT_CFLAGS_FILE_TEMPLATE)); } - setExtraProjectFiles({FilePath::fromString(m_filesFileName), - FilePath::fromString(m_includesFileName), - FilePath::fromString(m_configFileName), - FilePath::fromString(m_cxxflagsFileName), - FilePath::fromString(m_cflagsFileName)}); + project->setExtraProjectFiles({FilePath::fromString(m_filesFileName), + FilePath::fromString(m_includesFileName), + FilePath::fromString(m_configFileName), + FilePath::fromString(m_cxxflagsFileName), + FilePath::fromString(m_cflagsFileName)}); - connect(m_deployFileWatcher, - &FileSystemWatcher::fileChanged, - this, - &GenericProject::updateDeploymentData); + connect(m_deployFileWatcher, &FileSystemWatcher::fileChanged, + this, &GenericBuildSystem::updateDeploymentData); - connect(this, &Project::activeTargetChanged, this, [this] { refresh(Everything); }); + connect(project, &Project::activeTargetChanged, this, [this] { refresh(Everything); }); - connect(this, &Project::activeBuildConfigurationChanged, this, [this] { refresh(Everything); }); + connect(project, &Project::activeBuildConfigurationChanged, this, [this] { refresh(Everything); }); } -GenericProject::~GenericProject() +GenericBuildSystem::~GenericBuildSystem() { delete m_cppCodeModelUpdater; } @@ -262,14 +281,14 @@ static QStringList readLines(const QString &absoluteFileName) return lines; } -bool GenericProject::saveRawFileList(const QStringList &rawFileList) +bool GenericBuildSystem::saveRawFileList(const QStringList &rawFileList) { bool result = saveRawList(rawFileList, m_filesFileName); - refresh(GenericProject::Files); + refresh(Files); return result; } -bool GenericProject::saveRawList(const QStringList &rawList, const QString &fileName) +bool GenericBuildSystem::saveRawList(const QStringList &rawList, const QString &fileName) { FileChangeBlocker changeGuard(fileName); // Make sure we can open the file for writing @@ -293,7 +312,7 @@ static void insertSorted(QStringList *list, const QString &value) list->insert(pos, value); } -bool GenericProject::addFiles(const QStringList &filePaths) +bool GenericBuildSystem::addFiles(Node *, const QStringList &filePaths, QStringList *) { QStringList newList = m_rawFileList; @@ -322,12 +341,12 @@ bool GenericProject::addFiles(const QStringList &filePaths) bool result = saveRawList(newList, m_filesFileName); result &= saveRawList(m_rawProjectIncludePaths, m_includesFileName); - refresh(GenericProject::Everything); + refresh(Everything); return result; } -bool GenericProject::removeFiles(const QStringList &filePaths) +RemovedFilesFromProject GenericBuildSystem::removeFiles(Node *, const QStringList &filePaths, QStringList *) { QStringList newList = m_rawFileList; @@ -337,10 +356,11 @@ bool GenericProject::removeFiles(const QStringList &filePaths) newList.removeOne(i.value()); } - return saveRawFileList(newList); + return saveRawFileList(newList) ? RemovedFilesFromProject::Ok + : RemovedFilesFromProject::Error; } -bool GenericProject::setFiles(const QStringList &filePaths) +bool GenericBuildSystem::setFiles(const QStringList &filePaths) { QStringList newList; QDir baseDir(projectDirectory().toString()); @@ -351,7 +371,7 @@ bool GenericProject::setFiles(const QStringList &filePaths) return saveRawFileList(newList); } -bool GenericProject::renameFile(const QString &filePath, const QString &newFilePath) +bool GenericBuildSystem::renameFile(Node *, const QString &filePath, const QString &newFilePath) { QStringList newList = m_rawFileList; @@ -376,7 +396,7 @@ static QStringList readFlags(const QString &filePath) return QtcProcess::splitArgs(lines.first()); } -void GenericProject::parseProject(RefreshOptions options) +void GenericBuildSystem::parse(RefreshOptions options) { if (options & Files) { m_rawListEntries.clear(); @@ -406,7 +426,7 @@ void GenericProject::parseProject(RefreshOptions options) } } -FilePath GenericProject::findCommonSourceRoot() +FilePath GenericBuildSystem::findCommonSourceRoot() { if (m_files.isEmpty()) return FilePath::fromFileInfo(QFileInfo(m_filesFileName).absolutePath()); @@ -426,16 +446,17 @@ FilePath GenericProject::findCommonSourceRoot() return FilePath::fromString(QFileInfo(root).absolutePath()); } -void GenericProject::refresh(RefreshOptions options) +void GenericBuildSystem::refresh(RefreshOptions options) { - ParseGuard guard = guardParsingRun(); - parseProject(options); + Project::ParseGuard guard = project()->guardParsingRun(); + parse(options); if (options & Files) { - auto newRoot = std::make_unique<GenericProjectNode>(this); + auto newRoot = std::make_unique<ProjectNode>(projectDirectory()); + newRoot->setDisplayName(projectFilePath().toFileInfo().completeBaseName()); // find the common base directory of all source files - Utils::FilePath baseDir = findCommonSourceRoot(); + FilePath baseDir = findCommonSourceRoot(); for (const QString &f : qAsConst(m_files)) { FileType fileType = FileType::Source; // ### FIXME @@ -456,7 +477,7 @@ void GenericProject::refresh(RefreshOptions options) FileType::Project)); newRoot->compress(); - setRootProjectNode(std::move(newRoot)); + project()->setRootProjectNode(std::move(newRoot)); } refreshCppCodeModel(); @@ -471,20 +492,21 @@ void GenericProject::refresh(RefreshOptions options) * The \a map variable is an optional argument that will map the returned * absolute paths back to their original \a entries. */ -QStringList GenericProject::processEntries(const QStringList &paths, - QHash<QString, QString> *map) const +QStringList GenericBuildSystem::processEntries(const QStringList &paths, + QHash<QString, QString> *map) const { - const BuildConfiguration *const buildConfig = activeTarget() ? activeTarget()->activeBuildConfiguration() - : nullptr; + Target *target = project()->activeTarget(); + const BuildConfiguration *const buildConfig = target ? target->activeBuildConfiguration() + : nullptr; const Utils::Environment buildEnv = buildConfig ? buildConfig->environment() : Utils::Environment::systemEnvironment(); - const Utils::MacroExpander *expander = macroExpander(); + const Utils::MacroExpander *expander = project()->macroExpander(); if (buildConfig) expander = buildConfig->macroExpander(); - else if (activeTarget()) - expander = activeTarget()->macroExpander(); + else if (target) + expander = target->macroExpander(); const QDir projectDir(projectDirectory().toString()); @@ -512,15 +534,15 @@ QStringList GenericProject::processEntries(const QStringList &paths, return absolutePaths; } -void GenericProject::refreshCppCodeModel() +void GenericBuildSystem::refreshCppCodeModel() { if (!m_cppCodeModelUpdater) return; - QtSupport::CppKitInfo kitInfo(this); + QtSupport::CppKitInfo kitInfo(project()); QTC_ASSERT(kitInfo.isValid(), return); RawProjectPart rpp; - rpp.setDisplayName(displayName()); + rpp.setDisplayName(project()->displayName()); rpp.setProjectFileLocation(projectFilePath().toString()); rpp.setQtVersion(kitInfo.projectPartQtVersion); rpp.setHeaderPaths(m_projectIncludePaths); @@ -529,15 +551,16 @@ void GenericProject::refreshCppCodeModel() rpp.setFlagsForC({nullptr, m_cflags}); rpp.setFiles(m_files); - m_cppCodeModelUpdater->update({this, kitInfo, activeParseEnvironment(), {rpp}}); + m_cppCodeModelUpdater->update({project(), kitInfo, project()->activeParseEnvironment(), {rpp}}); } -void GenericProject::updateDeploymentData() +void GenericBuildSystem::updateDeploymentData() { static const QString fileName("QtCreatorDeployment.txt"); Utils::FilePath deploymentFilePath; - if (activeTarget() && activeTarget()->activeBuildConfiguration()) { - deploymentFilePath = activeTarget()->activeBuildConfiguration()->buildDirectory() + Target *target = project()->activeTarget(); + if (target && target->activeBuildConfiguration()) { + deploymentFilePath = target->activeBuildConfiguration()->buildDirectory() .pathAppended(fileName); } bool hasDeploymentData = QFileInfo::exists(deploymentFilePath.toString()); @@ -549,7 +572,7 @@ void GenericProject::updateDeploymentData() DeploymentData deploymentData; deploymentData.addFilesFromDeploymentFile(deploymentFilePath.toString(), projectDirectory().toString()); - activeTarget()->setDeploymentData(deploymentData); + project()->activeTarget()->setDeploymentData(deploymentData); if (m_deployFileWatcher->files() != QStringList(deploymentFilePath.toString())) { m_deployFileWatcher->removeFiles(m_deployFileWatcher->files()); m_deployFileWatcher->addFile(deploymentFilePath.toString(), @@ -558,6 +581,15 @@ void GenericProject::updateDeploymentData() } } +void GenericBuildSystem::removeFiles(const QStringList &filesToRemove) +{ + if (removeFiles(nullptr, filesToRemove, nullptr) == RemovedFilesFromProject::Error) { + TaskHub::addTask(Task::Error, tr("Project files list update failed."), + ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM, + filesFilePath()); + } +} + Project::RestoreResult GenericProject::fromMap(const QVariantMap &map, QString *errorMessage) { const RestoreResult result = Project::fromMap(map, errorMessage); @@ -581,7 +613,7 @@ Project::RestoreResult GenericProject::fromMap(const QVariantMap &map, QString * t->addRunConfiguration(new CustomExecutableRunConfiguration(t)); } - refresh(Everything); + static_cast<GenericBuildSystem *>(buildSystem())->refresh(Everything); return RestoreResult::Ok; } @@ -590,5 +622,30 @@ ProjectExplorer::DeploymentKnowledge GenericProject::deploymentKnowledge() const return DeploymentKnowledge::Approximative; } +bool GenericProjectFile::reload(QString *errorString, IDocument::ReloadFlag flag, IDocument::ChangeType type) +{ + Q_UNUSED(errorString) + Q_UNUSED(flag) + if (type == TypePermissions) + return true; + static_cast<GenericBuildSystem *>(m_project->buildSystem())->refresh(m_options); + return true; +} + +void GenericProject::editFilesTriggered() +{ + SelectableFilesDialogEditFiles sfd(projectDirectory(), + files(Project::AllFiles), + ICore::mainWindow()); + if (sfd.exec() == QDialog::Accepted) + static_cast<GenericBuildSystem *>(buildSystem()) + ->setFiles(transform(sfd.selectedFiles(), &FilePath::toString)); +} + +void GenericProject::removeFilesTriggered(const QStringList &filesToRemove) +{ + static_cast<GenericBuildSystem *>(buildSystem())->removeFiles(filesToRemove); +} + } // namespace Internal } // namespace GenericProjectManager diff --git a/src/plugins/genericprojectmanager/genericproject.h b/src/plugins/genericprojectmanager/genericproject.h index 37053e0de3..f1a1763032 100644 --- a/src/plugins/genericprojectmanager/genericproject.h +++ b/src/plugins/genericprojectmanager/genericproject.h @@ -25,14 +25,7 @@ #pragma once -#include <projectexplorer/headerpath.h> #include <projectexplorer/project.h> -#include <utils/fileutils.h> - -namespace CppTools { -class CppProjectUpdaterInterface; -} -namespace Utils { class FileSystemWatcher; } namespace GenericProjectManager { namespace Internal { @@ -43,55 +36,13 @@ class GenericProject : public ProjectExplorer::Project public: explicit GenericProject(const Utils::FilePath &filename); - ~GenericProject() override; - - bool addFiles(const QStringList &filePaths); - bool removeFiles(const QStringList &filePaths); - bool setFiles(const QStringList &filePaths); - bool renameFile(const QString &filePath, const QString &newFilePath); - - Utils::FilePath filesFilePath() const { return Utils::FilePath::fromString(m_filesFileName); } - - enum RefreshOptions { - Files = 0x01, - Configuration = 0x02, - Everything = Files | Configuration - }; - - void refresh(RefreshOptions options); -protected: - RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override; + void editFilesTriggered(); + void removeFilesTriggered(const QStringList &filesToRemove); private: - ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override; - - bool saveRawFileList(const QStringList &rawFileList); - bool saveRawList(const QStringList &rawList, const QString &fileName); - void parseProject(RefreshOptions options); - QStringList processEntries(const QStringList &paths, - QHash<QString, QString> *map = nullptr) const; - - Utils::FilePath findCommonSourceRoot(); - void refreshCppCodeModel(); - void updateDeploymentData(); - - QString m_filesFileName; - QString m_includesFileName; - QString m_configFileName; - QString m_cxxflagsFileName; - QString m_cflagsFileName; - QStringList m_rawFileList; - QStringList m_files; - QHash<QString, QString> m_rawListEntries; - QStringList m_rawProjectIncludePaths; - ProjectExplorer::HeaderPaths m_projectIncludePaths; - QStringList m_cxxflags; - QStringList m_cflags; - - CppTools::CppProjectUpdaterInterface *m_cppCodeModelUpdater = nullptr; - - Utils::FileSystemWatcher * const m_deployFileWatcher = nullptr; + RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) final; + ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const final; }; } // namespace Internal diff --git a/src/plugins/genericprojectmanager/genericprojectplugin.cpp b/src/plugins/genericprojectmanager/genericprojectplugin.cpp index 0ffa12e2cf..b585980c3b 100644 --- a/src/plugins/genericprojectmanager/genericprojectplugin.cpp +++ b/src/plugins/genericprojectmanager/genericprojectplugin.cpp @@ -70,16 +70,14 @@ public: QAction editFilesAction{GenericProjectPlugin::tr("Edit Files..."), nullptr}; }; -static GenericProjectPluginPrivate *dd = nullptr; - GenericProjectPlugin::~GenericProjectPlugin() { - delete dd; + delete d; } bool GenericProjectPlugin::initialize(const QStringList &, QString *) { - dd = new GenericProjectPluginPrivate; + d = new GenericProjectPluginPrivate; return true; } @@ -97,14 +95,8 @@ GenericProjectPluginPrivate::GenericProjectPluginPrivate() mproject->addAction(command, PEC::G_PROJECT_FILES); connect(&editFilesAction, &QAction::triggered, this, [] { - auto genericProject = qobject_cast<GenericProject *>(ProjectTree::currentProject()); - if (!genericProject) - return; - SelectableFilesDialogEditFiles sfd(genericProject->projectDirectory(), - genericProject->files(Project::AllFiles), - ICore::mainWindow()); - if (sfd.exec() == QDialog::Accepted) - genericProject->setFiles(transform(sfd.selectedFiles(), &FilePath::toString)); + if (auto genericProject = qobject_cast<GenericProject *>(ProjectTree::currentProject())) + genericProject->editFilesTriggered(); }); @@ -120,10 +112,7 @@ GenericProjectPluginPrivate::GenericProjectPluginPrivate() const QStringList filesToRemove = transform<QStringList>( folderNode->findNodes([](const Node *node) { return node->asFileNode(); }), [](const Node *node) { return node->filePath().toString();}); - if (!project->removeFiles(filesToRemove)) { - TaskHub::addTask(Task::Error, tr("Project files list update failed."), - PEC::TASK_CATEGORY_BUILDSYSTEM, project->filesFilePath()); - } + project->removeFilesTriggered(filesToRemove); }); } diff --git a/src/plugins/genericprojectmanager/genericprojectplugin.h b/src/plugins/genericprojectmanager/genericprojectplugin.h index 84865383cb..7158920534 100644 --- a/src/plugins/genericprojectmanager/genericprojectplugin.h +++ b/src/plugins/genericprojectmanager/genericprojectplugin.h @@ -41,6 +41,8 @@ public: private: bool initialize(const QStringList &arguments, QString *errorString) override; void extensionsInitialized() override { } + + class GenericProjectPluginPrivate *d = nullptr; }; } // namespace Internal diff --git a/src/plugins/ios/iosbuildconfiguration.cpp b/src/plugins/ios/iosbuildconfiguration.cpp index 4a37779ca3..e7b4fdd03a 100644 --- a/src/plugins/ios/iosbuildconfiguration.cpp +++ b/src/plugins/ios/iosbuildconfiguration.cpp @@ -98,7 +98,8 @@ private: }; IosBuildSettingsWidget::IosBuildSettingsWidget(IosBuildConfiguration *bc) - : m_bc(bc), + : NamedWidget(IosBuildConfiguration::tr("iOS Settings")), + m_bc(bc), m_isDevice(DeviceTypeKitAspect::deviceTypeId(bc->target()->kit()) == Constants::IOS_DEVICE_TYPE) { @@ -166,8 +167,6 @@ IosBuildSettingsWidget::IosBuildSettingsWidget(IosBuildConfiguration *bc) detailsWidget->setState(Utils::DetailsWidget::NoSummary); detailsWidget->setWidget(container); - setDisplayName(IosBuildConfiguration::tr("iOS Settings")); - if (m_isDevice) { connect(IosConfigurations::instance(), &IosConfigurations::provisioningDataChanged, this, &IosBuildSettingsWidget::populateDevelopmentTeams); diff --git a/src/plugins/ios/iosrunconfiguration.cpp b/src/plugins/ios/iosrunconfiguration.cpp index b49f383051..92cb1965ab 100644 --- a/src/plugins/ios/iosrunconfiguration.cpp +++ b/src/plugins/ios/iosrunconfiguration.cpp @@ -84,7 +84,7 @@ public: void fromMap(const QVariantMap &map) override; void toMap(QVariantMap &map) const override; - void addToConfigurationLayout(QFormLayout *layout) override; + void addToLayout(ProjectExplorer::LayoutBuilder &builder) override; IosDeviceType deviceType() const; void setDeviceType(const IosDeviceType &deviceType); @@ -321,14 +321,15 @@ IosDeviceTypeAspect::IosDeviceTypeAspect(IosRunConfiguration *runConfiguration) this, &IosDeviceTypeAspect::deviceChanges); } -void IosDeviceTypeAspect::addToConfigurationLayout(QFormLayout *layout) +void IosDeviceTypeAspect::addToLayout(LayoutBuilder &builder) { - m_deviceTypeComboBox = new QComboBox(layout->parentWidget()); + m_deviceTypeComboBox = new QComboBox; m_deviceTypeComboBox->setModel(&m_deviceTypeModel); - m_deviceTypeLabel = new QLabel(IosRunConfiguration::tr("Device type:"), layout->parentWidget()); + m_deviceTypeLabel = new QLabel(IosRunConfiguration::tr("Device type:")); - layout->addRow(m_deviceTypeLabel, m_deviceTypeComboBox); + builder.addItem(m_deviceTypeLabel); + builder.addItem(m_deviceTypeComboBox); updateValues(); diff --git a/src/plugins/nim/project/nimbuildsystem.cpp b/src/plugins/nim/project/nimbuildsystem.cpp index d5d34452d4..21b87702ea 100644 --- a/src/plugins/nim/project/nimbuildsystem.cpp +++ b/src/plugins/nim/project/nimbuildsystem.cpp @@ -34,34 +34,6 @@ #include <QVariantMap> -#if 0 -#include "nimbuildconfiguration.h" -#include "nimtoolchain.h" - -#include "../nimconstants.h" - -#include <coreplugin/icontext.h> -#include <coreplugin/progressmanager/progressmanager.h> -#include <coreplugin/iversioncontrol.h> -#include <coreplugin/vcsmanager.h> -#include <projectexplorer/buildconfiguration.h> -#include <projectexplorer/kit.h> -#include <projectexplorer/projectexplorerconstants.h> -#include <projectexplorer/projectnodes.h> -#include <projectexplorer/target.h> -#include <projectexplorer/toolchain.h> -#include <projectexplorer/kitinformation.h> -#include <texteditor/textdocument.h> - -#include <utils/runextensions.h> - -#include <coreplugin/editormanager/editormanager.h> -#include <coreplugin/editormanager/ieditor.h> - -#include <QFileInfo> -#include <QQueue> -#endif - using namespace ProjectExplorer; using namespace Utils; @@ -176,4 +148,40 @@ void NimBuildSystem::updateProject() m_currentContext = {}; } +bool NimBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const +{ + if (node->asFileNode()) { + return action == ProjectAction::Rename + || action == ProjectAction::RemoveFile; + } + if (node->isFolderNodeType() || node->isProjectNodeType()) { + return action == ProjectAction::AddNewFile + || action == ProjectAction::RemoveFile + || action == ProjectAction::AddExistingFile; + } + return BuildSystem::supportsAction(context, action, node); +} + +bool NimBuildSystem::addFiles(Node *, const QStringList &filePaths, QStringList *) +{ + return addFiles(filePaths); +} + +RemovedFilesFromProject NimBuildSystem::removeFiles(Node *, + const QStringList &filePaths, + QStringList *) +{ + return removeFiles(filePaths) ? RemovedFilesFromProject::Ok + : RemovedFilesFromProject::Error; +} + +bool NimBuildSystem::deleteFiles(Node *, const QStringList &) +{ + return true; +} + +bool NimBuildSystem::renameFile(Node *, const QString &filePath, const QString &newFilePath) +{ + return renameFile(filePath, newFilePath); +} } // namespace Nim diff --git a/src/plugins/nim/project/nimbuildsystem.h b/src/plugins/nim/project/nimbuildsystem.h index dde498f452..b725cf4d9d 100644 --- a/src/plugins/nim/project/nimbuildsystem.h +++ b/src/plugins/nim/project/nimbuildsystem.h @@ -43,6 +43,18 @@ public: bool removeFiles(const QStringList &filePaths); bool renameFile(const QString &filePath, const QString &newFilePath); + bool supportsAction(ProjectExplorer::Node *, + ProjectExplorer::ProjectAction action, + const ProjectExplorer::Node *node) const override; + bool addFiles(ProjectExplorer::Node *node, + const QStringList &filePaths, QStringList *) override; + ProjectExplorer::RemovedFilesFromProject removeFiles(ProjectExplorer::Node *node, + const QStringList &filePaths, + QStringList *) override; + bool deleteFiles(ProjectExplorer::Node *, const QStringList &) override; + bool renameFile(ProjectExplorer::Node *, + const QString &filePath, const QString &newFilePath) override; + void setExcludedFiles(const QStringList &list); // Keep for compatibility with Qt Creator 4.10 QStringList excludedFiles(); // Make private when no longer supporting Qt Creator 4.10 diff --git a/src/plugins/nim/project/nimproject.cpp b/src/plugins/nim/project/nimproject.cpp index 08f1019c8a..7fb17f2c36 100644 --- a/src/plugins/nim/project/nimproject.cpp +++ b/src/plugins/nim/project/nimproject.cpp @@ -45,7 +45,7 @@ NimProject::NimProject(const FilePath &fileName) : Project(Constants::C_NIM_MIME // ensure debugging is enabled (Nim plugin translates nim code to C code) setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); - setBuildSystem(std::make_unique<NimBuildSystem>(this)); + setBuildSystemCreator([](Project *p) { return new NimBuildSystem(p); }); } Tasks NimProject::projectIssues(const Kit *k) const diff --git a/src/plugins/nim/project/nimprojectnode.cpp b/src/plugins/nim/project/nimprojectnode.cpp index 5232ea500c..8e2570d950 100644 --- a/src/plugins/nim/project/nimprojectnode.cpp +++ b/src/plugins/nim/project/nimprojectnode.cpp @@ -25,59 +25,10 @@ #include "nimprojectnode.h" -#include "nimbuildsystem.h" - -#include <projectexplorer/projecttree.h> - -using namespace ProjectExplorer; -using namespace Utils; - namespace Nim { -NimProjectNode::NimProjectNode(const FilePath &projectFilePath) +NimProjectNode::NimProjectNode(const Utils::FilePath &projectFilePath) : ProjectNode(projectFilePath) {} -bool NimProjectNode::supportsAction(ProjectAction action, const Node *node) const -{ - if (node->asFileNode()) { - return action == ProjectAction::Rename - || action == ProjectAction::RemoveFile; - } - if (node->isFolderNodeType() || node->isProjectNodeType()) { - return action == ProjectAction::AddNewFile - || action == ProjectAction::RemoveFile - || action == ProjectAction::AddExistingFile; - } - return ProjectNode::supportsAction(action, node); -} - -bool NimProjectNode::addFiles(const QStringList &filePaths, QStringList *) -{ - return buildSystem()->addFiles(filePaths); -} - -RemovedFilesFromProject NimProjectNode::removeFiles(const QStringList &filePaths, - QStringList *) -{ - return buildSystem()->removeFiles(filePaths) ? RemovedFilesFromProject::Ok - : RemovedFilesFromProject::Error; -} - -bool NimProjectNode::deleteFiles(const QStringList &) -{ - return true; -} - -bool NimProjectNode::renameFile(const QString &filePath, const QString &newFilePath) -{ - return buildSystem()->renameFile(filePath, newFilePath); -} - -NimBuildSystem *NimProjectNode::buildSystem() const -{ - return qobject_cast<NimBuildSystem *>( - ProjectTree::instance()->projectForNode(this)->buildSystem()); -} - } // namespace Nim diff --git a/src/plugins/nim/project/nimprojectnode.h b/src/plugins/nim/project/nimprojectnode.h index 98ea5aeff1..3eb4ac709e 100644 --- a/src/plugins/nim/project/nimprojectnode.h +++ b/src/plugins/nim/project/nimprojectnode.h @@ -27,26 +27,12 @@ #include <projectexplorer/projectnodes.h> -namespace Utils { class FilePath; } - namespace Nim { -class NimBuildSystem; - class NimProjectNode : public ProjectExplorer::ProjectNode { public: NimProjectNode(const Utils::FilePath &projectFilePath); - - bool supportsAction(ProjectExplorer::ProjectAction action, const Node *node) const override; - bool addFiles(const QStringList &filePaths, QStringList *) override; - ProjectExplorer::RemovedFilesFromProject removeFiles(const QStringList &filePaths, - QStringList *) override; - bool deleteFiles(const QStringList &) override; - bool renameFile(const QString &filePath, const QString &newFilePath) override; - -private: - NimBuildSystem *buildSystem() const; }; } diff --git a/src/plugins/perfprofiler/perfprofilerflamegraphmodel.cpp b/src/plugins/perfprofiler/perfprofilerflamegraphmodel.cpp index 14716e4a29..49385fbaa9 100644 --- a/src/plugins/perfprofiler/perfprofilerflamegraphmodel.cpp +++ b/src/plugins/perfprofiler/perfprofilerflamegraphmodel.cpp @@ -38,9 +38,10 @@ class Payload { public: Payload(const PerfProfilerFlameGraphData *parent, PerfProfilerFlameGraphModel::Data *data, - int numSamples) + uint numSamples) : m_parent(parent), m_data(data), m_numSamples(numSamples) {} + ~Payload() = default; Payload(const Payload &other) = delete; Payload &operator=(const Payload &other) = delete; @@ -55,12 +56,12 @@ public: void countLostRequest(); private: - const PerfProfilerFlameGraphData *m_parent; - PerfProfilerFlameGraphModel::Data *m_data; - int m_numSamples; + const PerfProfilerFlameGraphData *m_parent = nullptr; + PerfProfilerFlameGraphModel::Data *m_data = nullptr; + uint m_numSamples = 0; }; -typedef PerfResourceCounter<Payload> ThreadResourceCounter; +using ThreadResourceCounter = PerfResourceCounter<Payload>; class ProcessResourceCounter { @@ -78,29 +79,41 @@ private: ThreadResourceCounter::Container m_container; }; -struct PerfProfilerFlameGraphData +class PerfProfilerFlameGraphData { - +public: PerfProfilerFlameGraphData() { clear(); } void loadEvent(const PerfEvent &event, const PerfEventType &type); PerfProfilerFlameGraphModel::Data *pushChild(PerfProfilerFlameGraphModel::Data *parent, int typeId, int numSamples); void updateTraceData(const PerfEvent &event, const PerfEventType &type, - PerfProfilerFlameGraphModel::Data *data, int numSamples); + PerfProfilerFlameGraphModel::Data *data, uint numSamples); void clear(); bool isEmpty() const; - QScopedPointer<PerfProfilerFlameGraphModel::Data> stackBottom; - std::unordered_map<quint32, ProcessResourceCounter> resourceBlocks; - QPointer<const PerfProfilerTraceManager> manager; - uint resourcePeakId = 0; + void setManager(const PerfProfilerTraceManager *manager) { m_manager = manager; } + const PerfProfilerTraceManager *manager() const { return m_manager; } + + PerfProfilerFlameGraphModel::Data *stackBottom() const { return m_stackBottom.data(); } + void swapStackBottom(QScopedPointer<PerfProfilerFlameGraphModel::Data> &stackBottom) + { + m_stackBottom.swap(stackBottom); + } + + uint resourcePeakId() const { return m_resourcePeakId; } + +private: + QScopedPointer<PerfProfilerFlameGraphModel::Data> m_stackBottom; + std::unordered_map<quint32, ProcessResourceCounter> m_resourceBlocks; + QPointer<const PerfProfilerTraceManager> m_manager; + uint m_resourcePeakId = 0; }; PerfProfilerFlameGraphModel::PerfProfilerFlameGraphModel(PerfProfilerTraceManager *manager) : - QAbstractItemModel(manager), m_stackBottom(new Data(nullptr, -1, 0)) + QAbstractItemModel(manager), m_stackBottom(new Data) { - PerfProfilerFlameGraphData *data = new PerfProfilerFlameGraphData; + auto *data = new PerfProfilerFlameGraphData; manager->registerFeatures(PerfEventType::attributeFeatures(), std::bind(&PerfProfilerFlameGraphData::loadEvent, data, std::placeholders::_1, std::placeholders::_2), @@ -120,10 +133,9 @@ QModelIndex PerfProfilerFlameGraphModel::index(int row, int column, const QModel { if (parent.isValid()) { Data *parentData = static_cast<Data *>(parent.internalPointer()); - return createIndex(row, column, parentData->children[row]); - } else { - return createIndex(row, column, row >= 0 ? m_stackBottom->children[row] : nullptr); + return createIndex(row, column, parentData->children[row].get()); } + return createIndex(row, column, row >= 0 ? m_stackBottom->children[row].get() : nullptr); } QModelIndex PerfProfilerFlameGraphModel::parent(const QModelIndex &child) const @@ -132,19 +144,17 @@ QModelIndex PerfProfilerFlameGraphModel::parent(const QModelIndex &child) const Data *childData = static_cast<Data *>(child.internalPointer()); return childData->parent == m_stackBottom.data() ? QModelIndex() : createIndex(0, 0, childData->parent); - } else { - return QModelIndex(); } + return {}; } int PerfProfilerFlameGraphModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { Data *parentData = static_cast<Data *>(parent.internalPointer()); - return parentData->children.count(); - } else { - return m_stackBottom->children.count(); + return parentData->children.size(); } + return m_stackBottom->children.size(); } int PerfProfilerFlameGraphModel::columnCount(const QModelIndex &parent) const @@ -192,16 +202,19 @@ QVariant PerfProfilerFlameGraphModel::data(const QModelIndex &index, int role) c return QVariant(); // Need to look up stuff from modelmanager - PerfProfilerTraceManager *manager = - static_cast<PerfProfilerTraceManager *>(QObject::parent()); + auto *manager = qobject_cast<PerfProfilerTraceManager *>(QObject::parent()); + QTC_ASSERT(manager, return QVariant()); const bool aggregated = manager->aggregateAddresses(); const PerfProfilerTraceManager::Symbol &symbol = manager->symbol(aggregated ? data->typeId : manager->symbolLocation(data->typeId)); const PerfEventType::Location &location = manager->location(data->typeId); + const int hexBase = 16; + const int addressWidth = 16; switch (role) { case DisplayNameRole: - return QString::fromLatin1("0x%1").arg(location.address, 16, 16, QLatin1Char('0')); + return QString::fromLatin1("0x%1").arg(location.address, addressWidth, hexBase, + QLatin1Char('0')); case FunctionRole: return orUnknown(manager->string(symbol.name)); case ElfFileRole: @@ -220,37 +233,38 @@ void PerfProfilerFlameGraphModel::initialize() PerfProfilerFlameGraphData *offline = m_offlineData.take(); QTC_ASSERT(offline, return); QTC_ASSERT(offline->isEmpty(), offline->clear()); - offline->manager = static_cast<PerfProfilerTraceManager *>(QObject::parent()); + offline->setManager(qobject_cast<PerfProfilerTraceManager *>(QObject::parent())); + QTC_CHECK(offline->manager()); } void PerfProfilerFlameGraphData::updateTraceData(const PerfEvent &event, const PerfEventType &type, PerfProfilerFlameGraphModel::Data *data, - int numSamples) + uint numSamples) { Q_UNUSED(type) for (int i = 0, end = event.numAttributes(); i < end; ++i) { - const PerfEventType::Attribute &attribute = manager->attribute(event.attributeId(i)); + const PerfEventType::Attribute &attribute = m_manager->attribute(event.attributeId(i)); if (attribute.type != PerfEventType::TypeTracepoint) continue; const PerfProfilerTraceManager::TracePoint &tracePoint - = manager->tracePoint(static_cast<int>(attribute.config)); + = m_manager->tracePoint(static_cast<int>(attribute.config)); - const QByteArray &name = manager->string(tracePoint.name); + const QByteArray &name = m_manager->string(tracePoint.name); if (name.startsWith(PerfProfilerTraceManager::s_resourceNamePrefix)) { const QHash<qint32, QVariant> &traceData = event.traceData(); const auto end = traceData.end(); - const auto released = traceData.find(manager->resourceReleasedIdId()); - const auto amount = traceData.find(manager->resourceRequestedAmountId()); - const auto obtained = traceData.find(manager->resourceObtainedIdId()); - const auto moved = traceData.find(manager->resourceMovedIdId()); + const auto released = traceData.find(m_manager->resourceReleasedIdId()); + const auto amount = traceData.find(m_manager->resourceRequestedAmountId()); + const auto obtained = traceData.find(m_manager->resourceObtainedIdId()); + const auto moved = traceData.find(m_manager->resourceMovedIdId()); - auto &threadCounter = resourceBlocks[event.pid()][event.tid()]; + auto &threadCounter = m_resourceBlocks[event.pid()][event.tid()]; Payload payload(this, data, numSamples); if (amount != end) { - const auto blocks = traceData.find(manager->resourceRequestedBlocksId()); + const auto blocks = traceData.find(m_manager->resourceRequestedBlocksId()); const qint64 amountValue = amount.value().toLongLong() * (blocks == end ? 1 : blocks.value().toLongLong()); @@ -270,32 +284,32 @@ void PerfProfilerFlameGraphData::updateTraceData(const PerfEvent &event, const P threadCounter.move(moved.value().toULongLong(), std::move(payload)); } - if (stackBottom->resourceUsage > stackBottom->resourcePeak) - resourcePeakId += numSamples; + if (m_stackBottom->resourceUsage > m_stackBottom->resourcePeak) + m_resourcePeakId += numSamples; } } } void PerfProfilerFlameGraphData::clear() { - if (!stackBottom || !stackBottom->isEmpty()) - stackBottom.reset(new PerfProfilerFlameGraphModel::Data(nullptr, -1, 0)); - resourceBlocks.clear(); - manager.clear(); - resourcePeakId = 0; + if (!m_stackBottom || m_stackBottom->samples != 0) + m_stackBottom.reset(new PerfProfilerFlameGraphModel::Data); + m_resourceBlocks.clear(); + m_manager.clear(); + m_resourcePeakId = 0; } bool PerfProfilerFlameGraphData::isEmpty() const { - return stackBottom->isEmpty() && resourceBlocks.empty() && manager.isNull() - && resourcePeakId == 0; + return m_stackBottom->samples == 0 && m_resourceBlocks.empty() && m_manager.isNull() + && m_resourcePeakId == 0; } void PerfProfilerFlameGraphData::loadEvent(const PerfEvent &event, const PerfEventType &type) { - const int numSamples = (event.timestamp() < 0) ? 0 : 1; - stackBottom->samples += numSamples; - auto data = stackBottom.data(); + const uint numSamples = (event.timestamp() < 0) ? 0 : 1; + m_stackBottom->samples += numSamples; + auto data = m_stackBottom.data(); const QVector<int> &stack = event.frames(); for (auto it = stack.rbegin(), end = stack.rend(); it != end; ++it) data = pushChild(data, *it, numSamples); @@ -307,23 +321,23 @@ void PerfProfilerFlameGraphModel::finalize(PerfProfilerFlameGraphData *data) { beginResetModel(); - m_stackBottom.swap(data->stackBottom); + data->swapStackBottom(m_stackBottom); QQueue<Data *> nodes; nodes.enqueue(m_stackBottom.data()); while (!nodes.isEmpty()) { Data *node = nodes.dequeue(); - if (node->lastResourceChangeId < data->resourcePeakId) { + if (node->lastResourceChangeId < data->resourcePeakId()) { node->resourcePeak = node->resourceUsage; - node->lastResourceChangeId = data->resourcePeakId; + node->lastResourceChangeId = data->resourcePeakId(); } - for (Data *child : qAsConst(node->children)) - nodes.enqueue(child); + for (const auto &child : qAsConst(node->children)) + nodes.enqueue(child.get()); } endResetModel(); - QTC_CHECK(data->stackBottom->isEmpty()); + QTC_CHECK(data->stackBottom()->samples == 0); data->clear(); m_offlineData.reset(data); } @@ -338,17 +352,17 @@ void PerfProfilerFlameGraphModel::clear(PerfProfilerFlameGraphData *data) } else { QTC_CHECK(data == m_offlineData.data()); } - m_stackBottom.reset(new Data(nullptr, -1, 0)); + m_stackBottom.reset(new Data); endResetModel(); } PerfProfilerFlameGraphModel::Data *PerfProfilerFlameGraphData::pushChild( PerfProfilerFlameGraphModel::Data *parent, int typeId, int numSamples) { - QVector<PerfProfilerFlameGraphModel::Data *> &siblings = parent->children; + auto &siblings = parent->children; for (auto it = siblings.begin(), end = siblings.end(); it != end; ++it) { - PerfProfilerFlameGraphModel::Data *child = *it; + PerfProfilerFlameGraphModel::Data *child = it->get(); if (child->typeId == typeId) { child->samples += numSamples; for (auto back = it, front = siblings.begin(); back != front;) { @@ -362,19 +376,21 @@ PerfProfilerFlameGraphModel::Data *PerfProfilerFlameGraphData::pushChild( } } - PerfProfilerFlameGraphModel::Data *child - = new PerfProfilerFlameGraphModel::Data(parent, typeId, numSamples); - parent->children.append(child); - return child; + auto child = std::make_unique<PerfProfilerFlameGraphModel::Data>(); + child->parent = parent; + child->typeId = typeId; + child->samples = numSamples; + parent->children.push_back(std::move(child)); + return parent->children.back().get(); } void Payload::adjust(qint64 diff) { for (auto allocator = m_data; allocator; allocator = allocator->parent) { - if (allocator->lastResourceChangeId < m_parent->resourcePeakId) + if (allocator->lastResourceChangeId < m_parent->resourcePeakId()) allocator->resourcePeak = allocator->resourceUsage; - allocator->lastResourceChangeId = m_parent->resourcePeakId; + allocator->lastResourceChangeId = m_parent->resourcePeakId(); allocator->resourceUsage += diff; } } diff --git a/src/plugins/perfprofiler/perfprofilerflamegraphmodel.h b/src/plugins/perfprofiler/perfprofilerflamegraphmodel.h index 45691fa10e..712e96a5e8 100644 --- a/src/plugins/perfprofiler/perfprofilerflamegraphmodel.h +++ b/src/plugins/perfprofiler/perfprofilerflamegraphmodel.h @@ -38,8 +38,12 @@ struct PerfProfilerFlameGraphData; class PerfProfilerFlameGraphModel : public QAbstractItemModel { Q_OBJECT + Q_DISABLE_COPY(PerfProfilerFlameGraphModel); Q_ENUMS(Role) public: + PerfProfilerFlameGraphModel(PerfProfilerFlameGraphModel &&) = delete; + PerfProfilerFlameGraphModel &operator=(PerfProfilerFlameGraphModel &&) = delete; + enum Role { TypeIdRole = Qt::UserRole + 1, // Sort by data, not by displayed string DisplayNameRole, @@ -59,20 +63,9 @@ public: }; struct Data { - Data(Data *parent = nullptr, int typeId = -1, uint samples = 1) : - parent(parent), typeId(typeId), samples(samples) - {} - - ~Data() { qDeleteAll(children); } - - bool isEmpty() const - { - return samples == 0; - } - - Data *parent; - int typeId; - uint samples; + Data *parent = nullptr; + int typeId = -1; + uint samples = 0; uint lastResourceChangeId = 0; uint observedResourceAllocations = 0; @@ -84,7 +77,7 @@ public: qint64 resourceUsage = 0; qint64 resourcePeak = 0; - QVector<Data *> children; + std::vector<std::unique_ptr<Data>> children; }; PerfProfilerFlameGraphModel(PerfProfilerTraceManager *manager); diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index aae6811779..a2ccaa1170 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -161,7 +161,6 @@ add_qtc_plugin(ProjectExplorer sessionview.cpp sessionview.h showineditortaskhandler.cpp showineditortaskhandler.h showoutputtaskhandler.cpp showoutputtaskhandler.h - subscription.cpp subscription.h target.cpp target.h targetsettingspanel.cpp targetsettingspanel.h targetsetuppage.cpp targetsetuppage.h diff --git a/src/plugins/projectexplorer/ProjectExplorer.json.in b/src/plugins/projectexplorer/ProjectExplorer.json.in index 6b87ce64a6..d6efb13cde 100644 --- a/src/plugins/projectexplorer/ProjectExplorer.json.in +++ b/src/plugins/projectexplorer/ProjectExplorer.json.in @@ -22,6 +22,11 @@ \"Description\" : \"Verbose loading of custom wizards\" }, { + \"Name\" : \"-ensure-kit-for-binary\", + \"Parameter\" : \"<file path>\", + \"Description\" : \"Create kit with architecture matching a given application or library\" + }, + { \"Name\" : \"-lastsession\", \"Description\" : \"Restore the last session\" }, diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index ccf333aa21..9496ec76a1 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -62,9 +62,31 @@ static const char USER_ENVIRONMENT_CHANGES_KEY[] = "ProjectExplorer.BuildConfigu static const char BUILDDIRECTORY_KEY[] = "ProjectExplorer.BuildConfiguration.BuildDirectory"; namespace ProjectExplorer { +namespace Internal { + +class BuildConfigurationPrivate +{ +public: + bool m_clearSystemEnvironment = false; + Utils::EnvironmentItems m_userEnvironmentChanges; + QList<BuildStepList *> m_stepLists; + ProjectExplorer::BaseStringAspect *m_buildDirectoryAspect = nullptr; + Utils::FilePath m_lastEmittedBuildDirectory; + mutable Utils::Environment m_cachedEnvironment; + QString m_configWidgetDisplayName; + bool m_configWidgetHasFrame = false; + + // FIXME: Remove. + BuildConfiguration::BuildType m_initialBuildType = BuildConfiguration::Unknown; + Utils::FilePath m_initialBuildDirectory; + QString m_initialDisplayName; + QVariant m_extraInfo; +}; + +} // Internal BuildConfiguration::BuildConfiguration(Target *target, Core::Id id) - : ProjectConfiguration(target, id) + : ProjectConfiguration(target, id), d(new Internal::BuildConfigurationPrivate) { QTC_CHECK(target && target == this->target()); Utils::MacroExpander *expander = macroExpander(); @@ -91,18 +113,18 @@ BuildConfiguration::BuildConfiguration(Target *target, Core::Id id) connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, this, &BuildConfiguration::updateCacheAndEmitEnvironmentChanged); - m_buildDirectoryAspect = addAspect<BaseStringAspect>(); - m_buildDirectoryAspect->setSettingsKey(BUILDDIRECTORY_KEY); - m_buildDirectoryAspect->setLabelText(tr("Build directory:")); - m_buildDirectoryAspect->setDisplayStyle(BaseStringAspect::PathChooserDisplay); - m_buildDirectoryAspect->setExpectedKind(Utils::PathChooser::Directory); - m_buildDirectoryAspect->setBaseFileName(target->project()->projectDirectory()); - m_buildDirectoryAspect->setEnvironment(environment()); - connect(m_buildDirectoryAspect, &BaseStringAspect::changed, + d->m_buildDirectoryAspect = addAspect<BaseStringAspect>(); + d->m_buildDirectoryAspect->setSettingsKey(BUILDDIRECTORY_KEY); + d->m_buildDirectoryAspect->setLabelText(tr("Build directory:")); + d->m_buildDirectoryAspect->setDisplayStyle(BaseStringAspect::PathChooserDisplay); + d->m_buildDirectoryAspect->setExpectedKind(Utils::PathChooser::Directory); + d->m_buildDirectoryAspect->setBaseFileName(target->project()->projectDirectory()); + d->m_buildDirectoryAspect->setEnvironment(environment()); + connect(d->m_buildDirectoryAspect, &BaseStringAspect::changed, this, &BuildConfiguration::buildDirectoryChanged); connect(this, &BuildConfiguration::environmentChanged, this, [this] { - m_buildDirectoryAspect->setEnvironment(environment()); + d->m_buildDirectoryAspect->setEnvironment(environment()); this->target()->buildEnvironmentChanged(this); }); @@ -117,34 +139,38 @@ BuildConfiguration::BuildConfiguration(Target *target, Core::Id id) }); } +BuildConfiguration::~BuildConfiguration() +{ + delete d; +} + Utils::FilePath BuildConfiguration::buildDirectory() const { - QString path = environment().expandVariables(m_buildDirectoryAspect->value().trimmed()); + QString path = environment().expandVariables(d->m_buildDirectoryAspect->value().trimmed()); path = QDir::cleanPath(macroExpander()->expand(path)); return Utils::FilePath::fromString(QDir::cleanPath(QDir(target()->project()->projectDirectory().toString()).absoluteFilePath(path))); } Utils::FilePath BuildConfiguration::rawBuildDirectory() const { - return m_buildDirectoryAspect->filePath(); + return d->m_buildDirectoryAspect->filePath(); } void BuildConfiguration::setBuildDirectory(const Utils::FilePath &dir) { - if (dir == m_buildDirectoryAspect->filePath()) + if (dir == d->m_buildDirectoryAspect->filePath()) return; - m_buildDirectoryAspect->setFilePath(dir); + d->m_buildDirectoryAspect->setFilePath(dir); emitBuildDirectoryChanged(); } NamedWidget *BuildConfiguration::createConfigWidget() { - NamedWidget *named = new NamedWidget; - named->setDisplayName(m_configWidgetDisplayName); + NamedWidget *named = new NamedWidget(d->m_configWidgetDisplayName); QWidget *widget = nullptr; - if (m_configWidgetHasFrame) { + if (d->m_configWidgetHasFrame) { auto container = new Utils::DetailsWidget(named); widget = new QWidget(container); container->setState(Utils::DetailsWidget::NoSummary); @@ -157,13 +183,12 @@ NamedWidget *BuildConfiguration::createConfigWidget() widget = named; } - auto formLayout = new QFormLayout(widget); - formLayout->setContentsMargins(0, 0, 0, 0); - formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); - + LayoutBuilder builder(widget); for (ProjectConfigurationAspect *aspect : aspects()) { - if (aspect->isVisible()) - aspect->addToConfigurationLayout(formLayout); + if (aspect->isVisible()) { + builder.startNewRow(); + aspect->addToLayout(builder); + } } return named; @@ -171,8 +196,8 @@ NamedWidget *BuildConfiguration::createConfigWidget() void BuildConfiguration::initialize() { - m_stepLists.append(new BuildStepList(this, Constants::BUILDSTEPS_BUILD)); - m_stepLists.append(new BuildStepList(this, Constants::BUILDSTEPS_CLEAN)); + d->m_stepLists.append(new BuildStepList(this, Constants::BUILDSTEPS_BUILD)); + d->m_stepLists.append(new BuildStepList(this, Constants::BUILDSTEPS_CLEAN)); } QList<NamedWidget *> BuildConfiguration::createSubConfigWidgets() @@ -182,36 +207,36 @@ QList<NamedWidget *> BuildConfiguration::createSubConfigWidgets() QList<Core::Id> BuildConfiguration::knownStepLists() const { - return Utils::transform(m_stepLists, &BuildStepList::id); + return Utils::transform(d->m_stepLists, &BuildStepList::id); } BuildStepList *BuildConfiguration::stepList(Core::Id id) const { - return Utils::findOrDefault(m_stepLists, Utils::equal(&BuildStepList::id, id)); + return Utils::findOrDefault(d->m_stepLists, Utils::equal(&BuildStepList::id, id)); } QVariantMap BuildConfiguration::toMap() const { QVariantMap map(ProjectConfiguration::toMap()); - map.insert(QLatin1String(CLEAR_SYSTEM_ENVIRONMENT_KEY), m_clearSystemEnvironment); - map.insert(QLatin1String(USER_ENVIRONMENT_CHANGES_KEY), Utils::EnvironmentItem::toStringList(m_userEnvironmentChanges)); + map.insert(QLatin1String(CLEAR_SYSTEM_ENVIRONMENT_KEY), d->m_clearSystemEnvironment); + map.insert(QLatin1String(USER_ENVIRONMENT_CHANGES_KEY), Utils::EnvironmentItem::toStringList(d->m_userEnvironmentChanges)); - map.insert(QLatin1String(BUILD_STEP_LIST_COUNT), m_stepLists.count()); - for (int i = 0; i < m_stepLists.count(); ++i) - map.insert(QLatin1String(BUILD_STEP_LIST_PREFIX) + QString::number(i), m_stepLists.at(i)->toMap()); + map.insert(QLatin1String(BUILD_STEP_LIST_COUNT), d->m_stepLists.count()); + for (int i = 0; i < d->m_stepLists.count(); ++i) + map.insert(QLatin1String(BUILD_STEP_LIST_PREFIX) + QString::number(i), d->m_stepLists.at(i)->toMap()); return map; } bool BuildConfiguration::fromMap(const QVariantMap &map) { - m_clearSystemEnvironment = map.value(QLatin1String(CLEAR_SYSTEM_ENVIRONMENT_KEY)).toBool(); - m_userEnvironmentChanges = Utils::EnvironmentItem::fromStringList(map.value(QLatin1String(USER_ENVIRONMENT_CHANGES_KEY)).toStringList()); + d->m_clearSystemEnvironment = map.value(QLatin1String(CLEAR_SYSTEM_ENVIRONMENT_KEY)).toBool(); + d->m_userEnvironmentChanges = Utils::EnvironmentItem::fromStringList(map.value(QLatin1String(USER_ENVIRONMENT_CHANGES_KEY)).toStringList()); updateCacheAndEmitEnvironmentChanged(); - qDeleteAll(m_stepLists); - m_stepLists.clear(); + qDeleteAll(d->m_stepLists); + d->m_stepLists.clear(); int maxI = map.value(QLatin1String(BUILD_STEP_LIST_COUNT), 0).toInt(); for (int i = 0; i < maxI; ++i) { @@ -226,7 +251,7 @@ bool BuildConfiguration::fromMap(const QVariantMap &map) delete list; return false; } - m_stepLists.append(list); + d->m_stepLists.append(list); } // We currently assume there to be at least a clean and build list! @@ -240,48 +265,53 @@ void BuildConfiguration::updateCacheAndEmitEnvironmentChanged() { Utils::Environment env = baseEnvironment(); env.modify(userEnvironmentChanges()); - if (env == m_cachedEnvironment) + if (env == d->m_cachedEnvironment) return; - m_cachedEnvironment = env; + d->m_cachedEnvironment = env; emit environmentChanged(); // might trigger buildDirectoryChanged signal! } void BuildConfiguration::emitBuildDirectoryChanged() { - if (buildDirectory() != m_lastEmmitedBuildDirectory) { - m_lastEmmitedBuildDirectory = buildDirectory(); + if (buildDirectory() != d->m_lastEmittedBuildDirectory) { + d->m_lastEmittedBuildDirectory = buildDirectory(); emit buildDirectoryChanged(); } } QString BuildConfiguration::initialDisplayName() const { - return m_initialDisplayName; + return d->m_initialDisplayName; +} + +QVariant BuildConfiguration::extraInfo() const +{ + return d->m_extraInfo; } ProjectExplorer::BaseStringAspect *BuildConfiguration::buildDirectoryAspect() const { - return m_buildDirectoryAspect; + return d->m_buildDirectoryAspect; } void BuildConfiguration::setConfigWidgetDisplayName(const QString &display) { - m_configWidgetDisplayName = display; + d->m_configWidgetDisplayName = display; } void BuildConfiguration::setBuildDirectoryHistoryCompleter(const QString &history) { - m_buildDirectoryAspect->setHistoryCompleter(history); + d->m_buildDirectoryAspect->setHistoryCompleter(history); } void BuildConfiguration::setConfigWidgetHasFrame(bool configWidgetHasFrame) { - m_configWidgetHasFrame = configWidgetHasFrame; + d->m_configWidgetHasFrame = configWidgetHasFrame; } void BuildConfiguration::setBuildDirectorySettingsKey(const QString &key) { - m_buildDirectoryAspect->setSettingsKey(key); + d->m_buildDirectoryAspect->setSettingsKey(key); } Utils::Environment BuildConfiguration::baseEnvironment() const @@ -304,14 +334,14 @@ QString BuildConfiguration::baseEnvironmentText() const Utils::Environment BuildConfiguration::environment() const { - return m_cachedEnvironment; + return d->m_cachedEnvironment; } void BuildConfiguration::setUseSystemEnvironment(bool b) { if (useSystemEnvironment() == b) return; - m_clearSystemEnvironment = !b; + d->m_clearSystemEnvironment = !b; updateCacheAndEmitEnvironmentChanged(); } @@ -322,19 +352,19 @@ void BuildConfiguration::addToEnvironment(Utils::Environment &env) const bool BuildConfiguration::useSystemEnvironment() const { - return !m_clearSystemEnvironment; + return !d->m_clearSystemEnvironment; } Utils::EnvironmentItems BuildConfiguration::userEnvironmentChanges() const { - return m_userEnvironmentChanges; + return d->m_userEnvironmentChanges; } void BuildConfiguration::setUserEnvironmentChanges(const Utils::EnvironmentItems &diff) { - if (m_userEnvironmentChanges == diff) + if (d->m_userEnvironmentChanges == diff) return; - m_userEnvironmentChanges = diff; + d->m_userEnvironmentChanges = diff; updateCacheAndEmitEnvironmentChanged(); } @@ -358,6 +388,21 @@ bool BuildConfiguration::regenerateBuildFiles(Node *node) return false; } +BuildConfiguration::BuildType BuildConfiguration::buildType() const +{ + return d->m_initialBuildType; +} + +BuildConfiguration::BuildType BuildConfiguration::initialBuildType() const +{ + return d->m_initialBuildType; +} + +FilePath BuildConfiguration::initialBuildDirectory() const +{ + return d->m_initialBuildDirectory; +} + QString BuildConfiguration::buildTypeName(BuildConfiguration::BuildType type) { switch (type) { @@ -511,10 +556,10 @@ BuildConfiguration *BuildConfigurationFactory::create(Target *parent, const Buil bc->setDefaultDisplayName(info.displayName); bc->setBuildDirectory(info.buildDirectory); - bc->m_initialBuildType = info.buildType; - bc->m_initialDisplayName = info.displayName; - bc->m_initialBuildDirectory = info.buildDirectory; - bc->m_extraInfo = info.extraInfo; + bc->d->m_initialBuildType = info.buildType; + bc->d->m_initialDisplayName = info.displayName; + bc->d->m_initialBuildDirectory = info.buildDirectory; + bc->d->m_extraInfo = info.extraInfo; bc->initialize(); diff --git a/src/plugins/projectexplorer/buildconfiguration.h b/src/plugins/projectexplorer/buildconfiguration.h index 89cbc77f53..6160e3b6a4 100644 --- a/src/plugins/projectexplorer/buildconfiguration.h +++ b/src/plugins/projectexplorer/buildconfiguration.h @@ -34,6 +34,8 @@ namespace ProjectExplorer { +namespace Internal { class BuildConfigurationPrivate; } + class BaseStringAspect; class BuildInfo; class BuildStepList; @@ -51,6 +53,8 @@ protected: explicit BuildConfiguration(Target *target, Core::Id id); public: + ~BuildConfiguration(); + Utils::FilePath buildDirectory() const; Utils::FilePath rawBuildDirectory() const; void setBuildDirectory(const Utils::FilePath &dir); @@ -86,12 +90,12 @@ public: Profile, Release }; - virtual BuildType buildType() const { return m_initialBuildType; } + virtual BuildType buildType() const; - BuildType initialBuildType() const { return m_initialBuildType; } // FIXME: Remove. - Utils::FilePath initialBuildDirectory() const { return m_initialBuildDirectory; } // FIXME: Remove. + BuildType initialBuildType() const; // FIXME: Remove. + Utils::FilePath initialBuildDirectory() const; // FIXME: Remove. QString initialDisplayName() const; // FIXME: Remove. - QVariant extraInfo() const { return m_extraInfo; } // FIXME: Remove. + QVariant extraInfo() const; // FIXME: Remove. static QString buildTypeName(BuildType type); @@ -117,21 +121,7 @@ protected: private: void emitBuildDirectoryChanged(); - - bool m_clearSystemEnvironment = false; - Utils::EnvironmentItems m_userEnvironmentChanges; - QList<BuildStepList *> m_stepLists; - ProjectExplorer::BaseStringAspect *m_buildDirectoryAspect = nullptr; - Utils::FilePath m_lastEmmitedBuildDirectory; - mutable Utils::Environment m_cachedEnvironment; - QString m_configWidgetDisplayName; - bool m_configWidgetHasFrame = false; - - // FIXME: Remove. - BuildConfiguration::BuildType m_initialBuildType = BuildConfiguration::Unknown; - Utils::FilePath m_initialBuildDirectory; - QString m_initialDisplayName; - QVariant m_extraInfo; + Internal::BuildConfigurationPrivate *d = nullptr; }; class PROJECTEXPLORER_EXPORT BuildConfigurationFactory : public QObject diff --git a/src/plugins/projectexplorer/buildenvironmentwidget.cpp b/src/plugins/projectexplorer/buildenvironmentwidget.cpp index 4995d1bc50..68211385e8 100644 --- a/src/plugins/projectexplorer/buildenvironmentwidget.cpp +++ b/src/plugins/projectexplorer/buildenvironmentwidget.cpp @@ -33,10 +33,10 @@ #include <QVBoxLayout> #include <QCheckBox> -using namespace ProjectExplorer; +namespace ProjectExplorer { -BuildEnvironmentWidget::BuildEnvironmentWidget(BuildConfiguration *bc) : - m_buildConfiguration(nullptr) +BuildEnvironmentWidget::BuildEnvironmentWidget(BuildConfiguration *bc) + : NamedWidget(tr("Build Environment")), m_buildConfiguration(bc) { auto vbox = new QVBoxLayout(this); vbox->setContentsMargins(0, 0, 0, 0); @@ -52,8 +52,6 @@ BuildEnvironmentWidget::BuildEnvironmentWidget(BuildConfiguration *bc) : connect(m_clearSystemEnvironmentCheckBox, &QAbstractButton::toggled, this, &BuildEnvironmentWidget::clearSystemEnvironmentCheckBoxClicked); - m_buildConfiguration = bc; - connect(m_buildConfiguration, &BuildConfiguration::environmentChanged, this, &BuildEnvironmentWidget::environmentChanged); @@ -61,8 +59,6 @@ BuildEnvironmentWidget::BuildEnvironmentWidget(BuildConfiguration *bc) : m_buildEnvironmentWidget->setBaseEnvironment(m_buildConfiguration->baseEnvironment()); m_buildEnvironmentWidget->setBaseEnvironmentText(m_buildConfiguration->baseEnvironmentText()); m_buildEnvironmentWidget->setUserChanges(m_buildConfiguration->userEnvironmentChanges()); - - setDisplayName(tr("Build Environment")); } void BuildEnvironmentWidget::environmentModelUserChangesChanged() @@ -82,3 +78,5 @@ void BuildEnvironmentWidget::environmentChanged() m_buildEnvironmentWidget->setBaseEnvironment(m_buildConfiguration->baseEnvironment()); m_buildEnvironmentWidget->setBaseEnvironmentText(m_buildConfiguration->baseEnvironmentText()); } + +} // ProjectExplorer diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp index eabce92bee..468d4751ac 100644 --- a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp @@ -143,8 +143,6 @@ void BuildSettingsWidget::addSubWidget(NamedWidget *widget) auto label = new QLabel(this); label->setText(widget->displayName()); - connect(widget, &NamedWidget::displayNameChanged, - label, &QLabel::setText); QFont f = label->font(); f.setBold(true); f.setPointSizeF(f.pointSizeF() * 1.2); @@ -167,11 +165,6 @@ void BuildSettingsWidget::clearWidgets() m_labels.clear(); } -QList<NamedWidget *> BuildSettingsWidget::subWidgets() const -{ - return m_subWidgets; -} - void BuildSettingsWidget::updateAddButtonMenu() { m_addButtonMenu->clear(); @@ -207,13 +200,11 @@ void BuildSettingsWidget::updateBuildSettings() if (generalConfigWidget) addSubWidget(generalConfigWidget); - auto buildStepsWidget = new BuildStepListWidget(this); - buildStepsWidget->init(m_buildConfiguration->stepList(Constants::BUILDSTEPS_BUILD)); - addSubWidget(buildStepsWidget); + BuildStepList *buildSteps = m_buildConfiguration->stepList(Constants::BUILDSTEPS_BUILD); + addSubWidget(new BuildStepListWidget(buildSteps, this)); - auto cleanStepsWidget = new BuildStepListWidget(this); - cleanStepsWidget->init(m_buildConfiguration->stepList(Constants::BUILDSTEPS_CLEAN)); - addSubWidget(cleanStepsWidget); + BuildStepList *cleanSteps = m_buildConfiguration->stepList(Constants::BUILDSTEPS_CLEAN); + addSubWidget(new BuildStepListWidget(cleanSteps, this)); QList<NamedWidget *> subConfigWidgets = m_buildConfiguration->createSubConfigWidgets(); foreach (NamedWidget *subConfigWidget, subConfigWidgets) diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.h b/src/plugins/projectexplorer/buildsettingspropertiespage.h index 990b43c69c..778109d189 100644 --- a/src/plugins/projectexplorer/buildsettingspropertiespage.h +++ b/src/plugins/projectexplorer/buildsettingspropertiespage.h @@ -52,7 +52,6 @@ public: void clearWidgets(); void addSubWidget(NamedWidget *widget); - QList<NamedWidget *> subWidgets() const; private: void updateBuildSettings(); diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp index 38968fe514..97d1874e81 100644 --- a/src/plugins/projectexplorer/buildstep.cpp +++ b/src/plugins/projectexplorer/buildstep.cpp @@ -149,13 +149,14 @@ BuildStepConfigWidget *BuildStep::createConfigWidget() { auto widget = new BuildStepConfigWidget(this); - auto formLayout = new QFormLayout(widget); - formLayout->setContentsMargins(0, 0, 0, 0); - formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); - - for (ProjectConfigurationAspect *aspect : m_aspects) { - if (aspect->isVisible()) - aspect->addToConfigurationLayout(formLayout); + { + LayoutBuilder builder(widget); + for (ProjectConfigurationAspect *aspect : m_aspects) { + if (aspect->isVisible()) { + builder.startNewRow(); + aspect->addToLayout(builder); + } + } } connect(buildConfiguration(), &BuildConfiguration::buildDirectoryChanged, diff --git a/src/plugins/projectexplorer/buildstepspage.cpp b/src/plugins/projectexplorer/buildstepspage.cpp index de40258b11..76fadceb68 100644 --- a/src/plugins/projectexplorer/buildstepspage.cpp +++ b/src/plugins/projectexplorer/buildstepspage.cpp @@ -191,9 +191,33 @@ BuildStepsWidgetData::~BuildStepsWidgetData() // We do not own the step } -BuildStepListWidget::BuildStepListWidget(QWidget *parent) : - NamedWidget(parent) -{ } +BuildStepListWidget::BuildStepListWidget(BuildStepList *bsl, QWidget *parent) + //: %1 is the name returned by BuildStepList::displayName + : NamedWidget(tr("%1 Steps").arg(bsl->displayName()), parent), m_buildStepList(bsl) +{ + setupUi(); + + connect(bsl, &BuildStepList::stepInserted, this, &BuildStepListWidget::addBuildStep); + connect(bsl, &BuildStepList::stepRemoved, this, &BuildStepListWidget::removeBuildStep); + connect(bsl, &BuildStepList::stepMoved, this, &BuildStepListWidget::stepMoved); + + for (int i = 0; i < bsl->count(); ++i) { + addBuildStep(i); + // addBuilStep expands the config widget by default, which we don't want here + if (m_buildStepsData.at(i)->step->widgetExpandedByDefault()) { + m_buildStepsData.at(i)->detailsWidget->setState( + m_buildStepsData.at(i)->step->wasUserExpanded() + ? DetailsWidget::Expanded : DetailsWidget::Collapsed); + } + } + + m_noStepsLabel->setVisible(bsl->isEmpty()); + m_noStepsLabel->setText(tr("No %1 Steps").arg(m_buildStepList->displayName())); + + m_addButton->setText(tr("Add %1 Step").arg(m_buildStepList->displayName())); + + updateBuildStepButtonsState(); +} BuildStepListWidget::~BuildStepListWidget() { @@ -227,52 +251,6 @@ void BuildStepListWidget::updateEnabledState() } } -void BuildStepListWidget::init(BuildStepList *bsl) -{ - Q_ASSERT(bsl); - if (bsl == m_buildStepList) - return; - - setupUi(); - - if (m_buildStepList) { - disconnect(m_buildStepList, &BuildStepList::stepInserted, - this, &BuildStepListWidget::addBuildStep); - disconnect(m_buildStepList, &BuildStepList::stepRemoved, - this, &BuildStepListWidget::removeBuildStep); - disconnect(m_buildStepList, &BuildStepList::stepMoved, - this, &BuildStepListWidget::stepMoved); - } - - connect(bsl, &BuildStepList::stepInserted, this, &BuildStepListWidget::addBuildStep); - connect(bsl, &BuildStepList::stepRemoved, this, &BuildStepListWidget::removeBuildStep); - connect(bsl, &BuildStepList::stepMoved, this, &BuildStepListWidget::stepMoved); - - qDeleteAll(m_buildStepsData); - m_buildStepsData.clear(); - - m_buildStepList = bsl; - //: %1 is the name returned by BuildStepList::displayName - setDisplayName(tr("%1 Steps").arg(m_buildStepList->displayName())); - - for (int i = 0; i < bsl->count(); ++i) { - addBuildStep(i); - // addBuilStep expands the config widget by default, which we don't want here - if (m_buildStepsData.at(i)->step->widgetExpandedByDefault()) { - m_buildStepsData.at(i)->detailsWidget->setState( - m_buildStepsData.at(i)->step->wasUserExpanded() - ? DetailsWidget::Expanded : DetailsWidget::Collapsed); - } - } - - m_noStepsLabel->setVisible(bsl->isEmpty()); - m_noStepsLabel->setText(tr("No %1 Steps").arg(m_buildStepList->displayName())); - - m_addButton->setText(tr("Add %1 Step").arg(m_buildStepList->displayName())); - - updateBuildStepButtonsState(); -} - void BuildStepListWidget::updateAddBuildStepMenu() { QMap<QString, QPair<Core::Id, BuildStepFactory *> > map; diff --git a/src/plugins/projectexplorer/buildstepspage.h b/src/plugins/projectexplorer/buildstepspage.h index 2453c9e784..7eade2d663 100644 --- a/src/plugins/projectexplorer/buildstepspage.h +++ b/src/plugins/projectexplorer/buildstepspage.h @@ -97,11 +97,9 @@ class BuildStepListWidget : public NamedWidget Q_OBJECT public: - BuildStepListWidget(QWidget *parent = nullptr); + BuildStepListWidget(BuildStepList *bsl, QWidget *parent = nullptr); ~BuildStepListWidget() override; - void init(BuildStepList *bsl); - private: void updateAddBuildStepMenu(); void addBuildStep(int pos); diff --git a/src/plugins/projectexplorer/buildsystem.cpp b/src/plugins/projectexplorer/buildsystem.cpp index 84c9b12381..496f9cc9f4 100644 --- a/src/plugins/projectexplorer/buildsystem.cpp +++ b/src/plugins/projectexplorer/buildsystem.cpp @@ -54,6 +54,16 @@ Project *BuildSystem::project() const return m_project; } +FilePath BuildSystem::projectFilePath() const +{ + return m_project->projectFilePath(); +} + +FilePath BuildSystem::projectDirectory() const +{ + return m_project->projectDirectory(); +} + bool BuildSystem::isWaitingForParse() const { return m_delayedParsingTimer.isActive(); @@ -77,7 +87,7 @@ void BuildSystem::requestParse(int delay) void BuildSystem::triggerParsing() { - QTC_CHECK(!project()->isParsing()); + QTC_ASSERT(!project()->isParsing(), return ); Project *p = project(); Target *t = p->activeTarget(); @@ -95,8 +105,56 @@ void BuildSystem::triggerParsing() ParsingContext ctx(p->guardParsingRun(), p, bc, e, env); + QTC_ASSERT(ctx.guard.guardsProject(), return ); + if (validateParsingContext(ctx)) parseProject(std::move(ctx)); } +bool BuildSystem::addFiles(Node *, const QStringList &filePaths, QStringList *notAdded) +{ + Q_UNUSED(filePaths) + Q_UNUSED(notAdded) + return false; +} + +RemovedFilesFromProject BuildSystem::removeFiles(Node *, const QStringList &filePaths, + QStringList *notRemoved) +{ + Q_UNUSED(filePaths) + Q_UNUSED(notRemoved) + return RemovedFilesFromProject::Error; +} + +bool BuildSystem::deleteFiles(Node *, const QStringList &filePaths) +{ + Q_UNUSED(filePaths) + return false; +} + +bool BuildSystem::canRenameFile(Node *, const QString &filePath, const QString &newFilePath) +{ + Q_UNUSED(filePath) + Q_UNUSED(newFilePath) + return true; +} + +bool BuildSystem::renameFile(Node *, const QString &filePath, const QString &newFilePath) +{ + Q_UNUSED(filePath) + Q_UNUSED(newFilePath) + return false; +} + +bool BuildSystem::addDependencies(Node *, const QStringList &dependencies) +{ + Q_UNUSED(dependencies) + return false; +} + +bool BuildSystem::supportsAction(Node *, ProjectAction, const Node *) const +{ + return false; +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/buildsystem.h b/src/plugins/projectexplorer/buildsystem.h index dd8456074c..9bd5de6639 100644 --- a/src/plugins/projectexplorer/buildsystem.h +++ b/src/plugins/projectexplorer/buildsystem.h @@ -36,6 +36,7 @@ namespace ProjectExplorer { class BuildConfiguration; class ExtraCompiler; +class Node; // -------------------------------------------------------------------- // BuildSystem: @@ -51,12 +52,23 @@ public: BuildSystem(const BuildSystem &other) = delete; Project *project() const; + Utils::FilePath projectFilePath() const; + Utils::FilePath projectDirectory() const; bool isWaitingForParse() const; void requestParse(); void requestDelayedParse(); + virtual bool addFiles(Node *context, const QStringList &filePaths, QStringList *notAdded = nullptr); + virtual RemovedFilesFromProject removeFiles(Node *context, const QStringList &filePaths, + QStringList *notRemoved = nullptr); + virtual bool deleteFiles(Node *context, const QStringList &filePaths); + virtual bool canRenameFile(Node *context, const QString &filePath, const QString &newFilePath); + virtual bool renameFile(Node *context, const QString &filePath, const QString &newFilePath); + virtual bool addDependencies(Node *context, const QStringList &dependencies); + virtual bool supportsAction(Node *context, ProjectAction action, const Node *node) const; + protected: class ParsingContext { @@ -65,8 +77,22 @@ protected: ParsingContext(const ParsingContext &other) = delete; ParsingContext &operator=(const ParsingContext &other) = delete; - ParsingContext(ParsingContext &&other) = default; - ParsingContext &operator=(ParsingContext &&other) = default; + ParsingContext(ParsingContext &&other) + : guard{std::move(other.guard)} + , project{std::move(other.project)} + , buildConfiguration{std::move(other.buildConfiguration)} + , expander{std::move(other.expander)} + , environment{std::move(other.environment)} + {} + ParsingContext &operator=(ParsingContext &&other) + { + guard = std::move(other.guard); + project = std::move(other.project); + buildConfiguration = std::move(other.buildConfiguration); + expander = std::move(other.expander); + environment = std::move(other.environment); + return *this; + } Project::ParseGuard guard; @@ -97,7 +123,7 @@ protected: return true; } - virtual void parseProject(ParsingContext &&ctx) = 0; // actual code to parse project + virtual void parseProject(ParsingContext &&) {} // actual code to parse project private: void requestParse(int delay); // request a (delayed!) parser run. diff --git a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp index 2f5e4463b7..e3dfd2f1a0 100644 --- a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp +++ b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp @@ -99,10 +99,6 @@ CustomExecutableDialog::CustomExecutableDialog(RunConfiguration *rc) auto vbox = new QVBoxLayout(this); vbox->addWidget(new QLabel(tr("Could not find the executable, please specify one."))); - auto layout = new QFormLayout; - layout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); - layout->setContentsMargins(0, 0, 0, 0); - auto detailsContainer = new DetailsWidget(this); detailsContainer->setState(DetailsWidget::NoSummary); vbox->addWidget(detailsContainer); @@ -116,24 +112,27 @@ CustomExecutableDialog::CustomExecutableDialog(RunConfiguration *rc) auto detailsWidget = new QWidget(detailsContainer); detailsContainer->setWidget(detailsWidget); - detailsWidget->setLayout(layout); m_executableChooser = new PathChooser(this); m_executableChooser->setHistoryCompleter("Qt.CustomExecutable.History"); m_executableChooser->setExpectedKind(PathChooser::ExistingCommand); m_executableChooser->setPath(rc->aspect<ExecutableAspect>()->executable().toString()); - layout->addRow(tr("Executable:"), m_executableChooser); connect(m_executableChooser, &PathChooser::rawPathChanged, this, &CustomExecutableDialog::changed); copyAspect(rc->aspect<ArgumentsAspect>(), &m_arguments); - m_arguments.addToConfigurationLayout(layout); - copyAspect(rc->aspect<WorkingDirectoryAspect>(), &m_workingDirectory); - m_workingDirectory.addToConfigurationLayout(layout); - copyAspect(rc->aspect<TerminalAspect>(), &m_terminal); - m_terminal.addToConfigurationLayout(layout); + + { + LayoutBuilder builder(detailsWidget); + builder.addItem(tr("Executable:")); + builder.addItem(m_executableChooser); + builder.startNewRow(); + m_arguments.addToLayout(builder); + m_workingDirectory.addToLayout(builder); + m_terminal.addToLayout(builder); + } auto enviromentAspect = rc->aspect<EnvironmentAspect>(); connect(enviromentAspect, &EnvironmentAspect::environmentChanged, diff --git a/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp b/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp index e0ac77deca..b53d8dbeb7 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopprocesssignaloperation.cpp @@ -36,7 +36,6 @@ #include <QProcess> #ifdef Q_OS_WIN -#define _WIN32_WINNT 0x0502 #include <windows.h> #ifndef PROCESS_SUSPEND_RESUME #define PROCESS_SUSPEND_RESUME 0x0800 diff --git a/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp b/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp index 24d692dd28..46249f1c24 100644 --- a/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp +++ b/src/plugins/projectexplorer/devicesupport/localprocesslist.cpp @@ -40,9 +40,6 @@ #endif #ifdef Q_OS_WIN -// Enable Win API of XP SP1 and later -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0502 #include <windows.h> #include <utils/winutils.h> #include <tlhelp32.h> diff --git a/src/plugins/projectexplorer/environmentaspect.cpp b/src/plugins/projectexplorer/environmentaspect.cpp index 68eff43620..a3c2cb4b23 100644 --- a/src/plugins/projectexplorer/environmentaspect.cpp +++ b/src/plugins/projectexplorer/environmentaspect.cpp @@ -43,7 +43,7 @@ namespace ProjectExplorer { EnvironmentAspect::EnvironmentAspect() { - setDisplayName(tr("Run Environment")); + setDisplayName(tr("Environment")); setId("EnvironmentAspect"); setConfigWidgetCreator([this] { return new EnvironmentAspectWidget(this); }); } @@ -74,9 +74,7 @@ void EnvironmentAspect::setUserEnvironmentChanges(const Utils::EnvironmentItems Utils::Environment EnvironmentAspect::environment() const { QTC_ASSERT(m_base >= 0 && m_base < m_baseEnvironments.size(), return Environment()); - Environment env = m_baseEnvironments.at(m_base).unmodifiedBaseEnvironment(); - for (const EnvironmentModifier &modifier : m_modifiers) - modifier(env); + Environment env = baseEnvironment(); env.modify(m_userChanges); return env; } @@ -124,10 +122,13 @@ void EnvironmentAspect::toMap(QVariantMap &data) const data.insert(QLatin1String(CHANGES_KEY), Utils::EnvironmentItem::toStringList(m_userChanges)); } -Environment EnvironmentAspect::currentUnmodifiedBaseEnvironment() const +Environment EnvironmentAspect::baseEnvironment() const { QTC_ASSERT(m_base >= 0 && m_base < m_baseEnvironments.size(), return Environment()); - return m_baseEnvironments.at(m_base).unmodifiedBaseEnvironment(); + Environment env = m_baseEnvironments.at(m_base).unmodifiedBaseEnvironment(); + for (const EnvironmentModifier &modifier : m_modifiers) + modifier(env); + return env; } QString EnvironmentAspect::currentDisplayName() const diff --git a/src/plugins/projectexplorer/environmentaspect.h b/src/plugins/projectexplorer/environmentaspect.h index ef5ed2907e..5b73f93e63 100644 --- a/src/plugins/projectexplorer/environmentaspect.h +++ b/src/plugins/projectexplorer/environmentaspect.h @@ -58,7 +58,7 @@ public: const std::function<Utils::Environment()> &getter); // The environment the user chose as base for his modifications. - Utils::Environment currentUnmodifiedBaseEnvironment() const; + Utils::Environment baseEnvironment() const; QString currentDisplayName() const; const QStringList displayNames() const; diff --git a/src/plugins/projectexplorer/environmentaspectwidget.cpp b/src/plugins/projectexplorer/environmentaspectwidget.cpp index d846c1b303..d287f3b771 100644 --- a/src/plugins/projectexplorer/environmentaspectwidget.cpp +++ b/src/plugins/projectexplorer/environmentaspectwidget.cpp @@ -75,7 +75,7 @@ EnvironmentAspectWidget::EnvironmentAspectWidget(EnvironmentAspect *aspect, QWid const EnvironmentWidget::Type widgetType = aspect->isLocal() ? EnvironmentWidget::TypeLocal : EnvironmentWidget::TypeRemote; m_environmentWidget = new EnvironmentWidget(this, widgetType, baseEnvironmentWidget); - m_environmentWidget->setBaseEnvironment(m_aspect->currentUnmodifiedBaseEnvironment()); + m_environmentWidget->setBaseEnvironment(m_aspect->baseEnvironment()); m_environmentWidget->setBaseEnvironmentText(m_aspect->currentDisplayName()); m_environmentWidget->setUserChanges(m_aspect->userEnvironmentChanges()); m_environmentWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); @@ -106,7 +106,7 @@ void EnvironmentAspectWidget::baseEnvironmentSelected(int idx) { m_ignoreChange = true; m_aspect->setBaseEnvironmentBase(idx); - m_environmentWidget->setBaseEnvironment(m_aspect->currentUnmodifiedBaseEnvironment()); + m_environmentWidget->setBaseEnvironment(m_aspect->baseEnvironment()); m_environmentWidget->setBaseEnvironmentText(m_aspect->currentDisplayName()); m_ignoreChange = false; } @@ -122,7 +122,7 @@ void EnvironmentAspectWidget::changeBaseEnvironment() m_baseEnvironmentComboBox->setCurrentIndex(i); } m_environmentWidget->setBaseEnvironmentText(m_aspect->currentDisplayName()); - m_environmentWidget->setBaseEnvironment(m_aspect->currentUnmodifiedBaseEnvironment()); + m_environmentWidget->setBaseEnvironment(m_aspect->baseEnvironment()); } void EnvironmentAspectWidget::userChangesEdited() @@ -143,7 +143,7 @@ void EnvironmentAspectWidget::environmentChanged() { if (m_ignoreChange) return; - m_environmentWidget->setBaseEnvironment(m_aspect->currentUnmodifiedBaseEnvironment()); + m_environmentWidget->setBaseEnvironment(m_aspect->baseEnvironment()); } } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/gccparser.cpp b/src/plugins/projectexplorer/gccparser.cpp index ef88b51403..344474db0a 100644 --- a/src/plugins/projectexplorer/gccparser.cpp +++ b/src/plugins/projectexplorer/gccparser.cpp @@ -132,7 +132,7 @@ void GccParser::stdError(const QString &line) match.captured(3).toInt() /* linenumber */, Constants::TASK_CATEGORY_COMPILE)); return; - } else if (lne.startsWith(QLatin1Char(' '))) { + } else if (lne.startsWith(' ') && !m_currentTask.isNull()) { amendDescription(lne, true); return; } @@ -866,6 +866,19 @@ void ProjectExplorerPlugin::testGccOutputParsers_data() ) << QString(); + + QTest::newRow("Undefined symbol (Apple ld)") + << "Undefined symbols for architecture x86_64:\n" + " \"SvgLayoutTest()\", referenced from:\n" + " _main in main.cpp.o" + << OutputParserTester::STDERR + << QString() << QString() + << Tasks({Task(Task::Error, "Undefined symbols for architecture x86_64:\n" + " \"SvgLayoutTest()\", referenced from:\n" + " _main in main.cpp.o", + FilePath::fromString("main.cpp.o"), -1, categoryCompile)}) + << QString(); + QTest::newRow("ld: undefined member function reference") << "obj/gtest-clang-printing.o:gtest-clang-printing.cpp:llvm::VerifyDisableABIBreakingChecks: error: undefined reference to 'llvm::DisableABIBreakingChecks'" << OutputParserTester::STDERR diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index c9597844af..ecb8c52ae7 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -38,6 +38,11 @@ #include <coreplugin/icore.h> +#include <android/androidconstants.h> +#include <baremetal/baremetalconstants.h> +#include <qnx/qnxconstants.h> +#include <remotelinux/remotelinux_constants.h> + #include <utils/environment.h> #include <utils/persistentsettings.h> #include <utils/pointeralgorithm.h> @@ -114,11 +119,16 @@ public: return m_aspectList; } + void setBinaryForKit(const FilePath &fp) { m_binaryForKit = fp; } + FilePath binaryForKit() const { return m_binaryForKit; } + private: // Sorted by priority, in descending order... QList<KitAspect *> m_aspectList; // ... if this here is set: bool m_aspectListIsSorted = true; + + FilePath m_binaryForKit; }; } // namespace Internal @@ -225,17 +235,33 @@ void KitManager::restoreKits() // Delete all loaded autodetected kits that were not rediscovered: kitsToCheck.clear(); - if (resultList.empty()) { - // No kits exist yet, so let's try to autoconfigure some from the toolchains we know. - // We consider only host toolchains, because for other ones we lack the knowledge how to - // map them to their respective device type. - static const auto isHostToolchain = [](const ToolChain *tc) { - static const Abi hostAbi = Abi::hostAbi(); + static const auto kitMatchesAbiList = [](const Kit *kit, const Abis &abis) { + const QList<ToolChain *> toolchains = ToolChainKitAspect::toolChains(kit); + for (const ToolChain * const tc : toolchains) { const Abi tcAbi = tc->targetAbi(); - return tcAbi.os() == hostAbi.os() && tcAbi.architecture() == hostAbi.architecture() - && (tcAbi.os() != Abi::LinuxOS || tcAbi.osFlavor() == hostAbi.osFlavor()); - }; - const QList<ToolChain *> allToolchains = ToolChainManager::toolChains(isHostToolchain); + for (const Abi &abi : abis) { + if (tcAbi.os() == abi.os() && tcAbi.architecture() == abi.architecture() + && (tcAbi.os() != Abi::LinuxOS || tcAbi.osFlavor() == abi.osFlavor())) { + return true; + } + } + } + return false; + }; + + const Abis abisOfBinary = d->binaryForKit().isEmpty() + ? Abis() : Abi::abisOfBinary(d->binaryForKit()); + const auto kitMatchesAbiOfBinary = [&abisOfBinary](const Kit *kit) { + return kitMatchesAbiList(kit, abisOfBinary); + }; + const bool haveKitForBinary = abisOfBinary.isEmpty() + || contains(resultList, [&kitMatchesAbiOfBinary](const std::unique_ptr<Kit> &kit) { + return kitMatchesAbiOfBinary(kit.get()); + }); + Kit *kitForBinary = nullptr; + + if (resultList.empty() || !haveKitForBinary) { + // No kits exist yet, so let's try to autoconfigure some from the toolchains we know. QHash<Abi, QHash<Core::Id, ToolChain *>> uniqueToolchains; // On Linux systems, we usually detect a plethora of same-ish toolchains. The following @@ -244,7 +270,7 @@ void KitManager::restoreKits() // TODO: This should not need to be done here. Instead, it should be a convenience // operation on some lower level, e.g. in the toolchain class(es). // Also, we shouldn't detect so many doublets in the first place. - for (ToolChain * const tc : allToolchains) { + for (ToolChain * const tc : ToolChainManager::toolChains()) { ToolChain *&bestTc = uniqueToolchains[tc->targetAbi()][tc->language()]; if (!bestTc) { bestTc = tc; @@ -269,28 +295,111 @@ void KitManager::restoreKits() bestTc = tc; } - int maxWeight = 0; + static const auto isHostKit = [](const Kit *kit) { + return kitMatchesAbiList(kit, {Abi::hostAbi()}); + }; + + static const auto deviceTypeForKit = [](const Kit *kit) { + if (isHostKit(kit)) + return Constants::DESKTOP_DEVICE_TYPE; + const QList<ToolChain *> toolchains = ToolChainKitAspect::toolChains(kit); + for (const ToolChain * const tc : toolchains) { + const Abi tcAbi = tc->targetAbi(); + switch (tcAbi.os()) { + case Abi::BareMetalOS: + return BareMetal::Constants::BareMetalOsType; + case Abi::BsdOS: + case Abi::DarwinOS: + case Abi::UnixOS: + return RemoteLinux::Constants::GenericLinuxOsType; + case Abi::LinuxOS: + if (tcAbi.osFlavor() == Abi::AndroidLinuxFlavor) + return Android::Constants::ANDROID_DEVICE_TYPE; + return RemoteLinux::Constants::GenericLinuxOsType; + case Abi::QnxOS: + return Qnx::Constants::QNX_QNX_OS_TYPE; + case Abi::VxWorks: + return "VxWorks.Device.Type"; + default: + break; + } + } + return Constants::DESKTOP_DEVICE_TYPE; + }; + + // Create temporary kits for all toolchains found. + decltype(resultList) tempList; for (auto it = uniqueToolchains.cbegin(); it != uniqueToolchains.cend(); ++it) { auto kit = std::make_unique<Kit>(); kit->setSdkProvided(false); kit->setAutoDetected(false); // TODO: Why false? What does autodetected mean here? for (ToolChain * const tc : it.value()) ToolChainKitAspect::setToolChain(kit.get(), tc); - kit->setUnexpandedDisplayName(tr("Desktop (%1)").arg(it.key().toString())); - kit->setup(); - if (kit->weight() < maxWeight) + if (contains(resultList, [&kit](const std::unique_ptr<Kit> &existingKit) { + return ToolChainKitAspect::toolChains(kit.get()) + == ToolChainKitAspect::toolChains(existingKit.get()); + })) { continue; - if (kit->weight() > maxWeight) { - maxWeight = kit->weight(); - resultList.clear(); } - resultList.emplace_back(std::move(kit)); + if (isHostKit(kit.get())) + kit->setUnexpandedDisplayName(tr("Desktop (%1)").arg(it.key().toString())); + else + kit->setUnexpandedDisplayName(it.key().toString()); + DeviceTypeKitAspect::setDeviceTypeId(kit.get(), deviceTypeForKit(kit.get())); + kit->setup(); + tempList.emplace_back(std::move(kit)); } - if (resultList.size() == 1) - resultList.front()->setUnexpandedDisplayName(tr("Desktop")); + + // Now make the "best" temporary kits permanent. The logic is as follows: + // - If the user has requested a kit for a given binary and one or more kits + // with a matching ABI exist, then we randomly choose exactly one among those with + // the highest weight. + // - If the user has not requested a kit for a given binary or no such kit could + // be created, we choose all kits with the highest weight. If none of these + // is a host kit, then we also add the host kit with the highest weight. + Utils::sort(tempList, [](const std::unique_ptr<Kit> &k1, const std::unique_ptr<Kit> &k2) { + return k1->weight() > k2->weight(); + }); + if (!abisOfBinary.isEmpty()) { + for (auto it = tempList.begin(); it != tempList.end(); ++it) { + if (kitMatchesAbiOfBinary(it->get())) { + kitForBinary = it->get(); + resultList.emplace_back(std::move(*it)); + tempList.erase(it); + break; + } + } + } + QList<Kit *> hostKits; + if (!kitForBinary && !tempList.empty()) { + const int maxWeight = tempList.front()->weight(); + for (auto it = tempList.begin(); it != tempList.end(); it = tempList.erase(it)) { + if ((*it)->weight() < maxWeight) + break; + if (isHostKit(it->get())) + hostKits << it->get(); + resultList.emplace_back(std::move(*it)); + } + if (!contains(resultList, [](const std::unique_ptr<Kit> &kit) { + return isHostKit(kit.get());})) { + QTC_ASSERT(hostKits.isEmpty(), hostKits.clear()); + for (auto &kit : tempList) { + if (isHostKit(kit.get())) { + hostKits << kit.get(); + resultList.emplace_back(std::move(kit)); + break; + } + } + } + } + + if (hostKits.size() == 1) + hostKits.first()->setUnexpandedDisplayName(tr("Desktop")); } - Kit *k = Utils::findOrDefault(resultList, Utils::equal(&Kit::id, defaultUserKit)); + Kit *k = kitForBinary; + if (!k) + k = Utils::findOrDefault(resultList, Utils::equal(&Kit::id, defaultUserKit)); if (!k) k = Utils::findOrDefault(resultList, &Kit::isValid); std::swap(resultList, d->m_kitList); @@ -359,6 +468,12 @@ void KitManager::deregisterKitAspect(KitAspect *ki) d->removeKitAspect(ki); } +void KitManager::setBinaryForKit(const FilePath &binary) +{ + QTC_ASSERT(d, return); + d->setBinaryForKit(binary); +} + QList<Kit *> KitManager::sortKits(const QList<Kit *> &kits) { // This method was added to delay the sorting of kits as long as possible. diff --git a/src/plugins/projectexplorer/kitmanager.h b/src/plugins/projectexplorer/kitmanager.h index c33c176e5c..610ee159a2 100644 --- a/src/plugins/projectexplorer/kitmanager.h +++ b/src/plugins/projectexplorer/kitmanager.h @@ -208,6 +208,8 @@ private: static void registerKitAspect(KitAspect *ki); static void deregisterKitAspect(KitAspect *ki); + static void setBinaryForKit(const Utils::FilePath &binary); + // Make sure the this is only called after all // KitAspects are registered! static void restoreKits(); diff --git a/src/plugins/projectexplorer/ldparser.cpp b/src/plugins/projectexplorer/ldparser.cpp index 919c9db30b..8c00f9f424 100644 --- a/src/plugins/projectexplorer/ldparser.cpp +++ b/src/plugins/projectexplorer/ldparser.cpp @@ -25,7 +25,6 @@ #include "ldparser.h" #include "projectexplorerconstants.h" -#include "task.h" #include <utils/qtcassert.h> @@ -58,6 +57,9 @@ LdParser::LdParser() void LdParser::stdError(const QString &line) { QString lne = rightTrimmed(line); + if (!lne.isEmpty() && !lne.at(0).isSpace() && !m_incompleteTask.isNull()) + flush(); + if (lne.startsWith(QLatin1String("TeamBuilder ")) || lne.startsWith(QLatin1String("distcc[")) || lne.contains(QLatin1String("ar: creating "))) { @@ -65,6 +67,21 @@ void LdParser::stdError(const QString &line) return; } + // ld on macOS + if (lne.startsWith("Undefined symbols for architecture") && lne.endsWith(":")) { + m_incompleteTask = Task(Task::Error, lne, Utils::FilePath(), -1, + Constants::TASK_CATEGORY_COMPILE); + return; + } + if (!m_incompleteTask.isNull() && lne.startsWith(" ")) { + m_incompleteTask.description.append('\n').append(lne); + static const QRegularExpression locRegExp(" (?<symbol>\\S+) in (?<file>\\S+)"); + const QRegularExpressionMatch match = locRegExp.match(lne); + if (match.hasMatch()) + m_incompleteTask.setFile(Utils::FilePath::fromString(match.captured("file"))); + return; + } + if (lne.startsWith("collect2:") || lne.startsWith("collect2.exe:")) { Task task = Task(Task::Error, lne /* description */, @@ -134,3 +151,12 @@ void LdParser::stdError(const QString &line) IOutputParser::stdError(line); } + +void LdParser::doFlush() +{ + if (m_incompleteTask.isNull()) + return; + const Task t = m_incompleteTask; + m_incompleteTask.clear(); + emit addTask(t); +} diff --git a/src/plugins/projectexplorer/ldparser.h b/src/plugins/projectexplorer/ldparser.h index ccee344d0e..bf6a441cbe 100644 --- a/src/plugins/projectexplorer/ldparser.h +++ b/src/plugins/projectexplorer/ldparser.h @@ -26,6 +26,7 @@ #pragma once #include "ioutputparser.h" +#include "task.h" #include <QRegularExpression> @@ -37,12 +38,15 @@ class LdParser : public ProjectExplorer::IOutputParser public: LdParser(); +private: void stdError(const QString &line) override; + void doFlush() override; -private: QRegularExpression m_ranlib; QRegularExpression m_regExpLinker; QRegularExpression m_regExpGccNames; + + Task m_incompleteTask; }; } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/localenvironmentaspect.cpp b/src/plugins/projectexplorer/localenvironmentaspect.cpp index 48eac49492..92a0319e1f 100644 --- a/src/plugins/projectexplorer/localenvironmentaspect.cpp +++ b/src/plugins/projectexplorer/localenvironmentaspect.cpp @@ -34,7 +34,7 @@ using namespace Utils; namespace ProjectExplorer { -LocalEnvironmentAspect::LocalEnvironmentAspect(Target *target) +LocalEnvironmentAspect::LocalEnvironmentAspect(Target *target, bool includeBuildEnvironment) { setIsLocal(true); addSupportedBaseEnvironment(tr("Clean Environment"), {}); @@ -43,21 +43,27 @@ LocalEnvironmentAspect::LocalEnvironmentAspect(Target *target) return Environment::systemEnvironment(); }); - addPreferredBaseEnvironment(tr("Build Environment"), [target] { - Environment env; - if (BuildConfiguration *bc = target->activeBuildConfiguration()) { - env = bc->environment(); - } else { // Fallback for targets without buildconfigurations: - env = Environment::systemEnvironment(); - target->kit()->addToEnvironment(env); - } - return env; - }); + if (includeBuildEnvironment) { + addPreferredBaseEnvironment(tr("Build Environment"), [target] { + Environment env; + if (BuildConfiguration *bc = target->activeBuildConfiguration()) { + env = bc->environment(); + } else { // Fallback for targets without buildconfigurations: + env = Environment::systemEnvironment(); + target->kit()->addToEnvironment(env); + } + return env; + }); - connect(target, &Target::activeBuildConfigurationChanged, - this, &EnvironmentAspect::environmentChanged); - connect(target, &Target::buildEnvironmentChanged, - this, &EnvironmentAspect::environmentChanged); + connect(target, + &Target::activeBuildConfigurationChanged, + this, + &EnvironmentAspect::environmentChanged); + connect(target, + &Target::buildEnvironmentChanged, + this, + &EnvironmentAspect::environmentChanged); + } } } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/localenvironmentaspect.h b/src/plugins/projectexplorer/localenvironmentaspect.h index b1e4d5fd55..e00f4252c6 100644 --- a/src/plugins/projectexplorer/localenvironmentaspect.h +++ b/src/plugins/projectexplorer/localenvironmentaspect.h @@ -34,7 +34,7 @@ class PROJECTEXPLORER_EXPORT LocalEnvironmentAspect : public EnvironmentAspect Q_OBJECT public: - explicit LocalEnvironmentAspect(Target *parent); + explicit LocalEnvironmentAspect(Target *parent, bool includeBuildEnvironment = true); }; } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/namedwidget.cpp b/src/plugins/projectexplorer/namedwidget.cpp index f3a0e4beb4..9aed84c73a 100644 --- a/src/plugins/projectexplorer/namedwidget.cpp +++ b/src/plugins/projectexplorer/namedwidget.cpp @@ -25,24 +25,16 @@ #include "namedwidget.h" -using namespace ProjectExplorer; +namespace ProjectExplorer { -/// -// NamedWidget -/// - -NamedWidget::NamedWidget(QWidget *parent) : QWidget(parent) -{ } +NamedWidget::NamedWidget(const QString &displayName, QWidget *parent) + : QWidget(parent), m_displayName(displayName) +{ +} QString NamedWidget::displayName() const { return m_displayName; } -void NamedWidget::setDisplayName(const QString &displayName) -{ - if (m_displayName == displayName) - return; - m_displayName = displayName; - emit displayNameChanged(m_displayName); -} +} // ProjectExplorer diff --git a/src/plugins/projectexplorer/namedwidget.h b/src/plugins/projectexplorer/namedwidget.h index 870941c73b..b1e80111e2 100644 --- a/src/plugins/projectexplorer/namedwidget.h +++ b/src/plugins/projectexplorer/namedwidget.h @@ -33,16 +33,10 @@ namespace ProjectExplorer { class PROJECTEXPLORER_EXPORT NamedWidget : public QWidget { - Q_OBJECT - public: - explicit NamedWidget(QWidget *parent = nullptr); + explicit NamedWidget(const QString &displayName, QWidget *parent = nullptr); QString displayName() const; - void setDisplayName(const QString &displayName); - -signals: - void displayNameChanged(const QString &); private: QString m_displayName; diff --git a/src/plugins/projectexplorer/processparameters.cpp b/src/plugins/projectexplorer/processparameters.cpp index d8b91e49b9..6d7c78b22a 100644 --- a/src/plugins/projectexplorer/processparameters.cpp +++ b/src/plugins/projectexplorer/processparameters.cpp @@ -28,6 +28,7 @@ #include <utils/fileutils.h> #include <utils/macroexpander.h> #include <utils/qtcprocess.h> +#include <utils/theme/theme.h> #include <QDir> @@ -169,8 +170,19 @@ QString ProcessParameters::prettyArguments() const return args.toString(); } +static QString invalidCommandMessage(const QString &displayName) +{ + return QString("<b>%1:</b> <font color='%3'>%2</font>") + .arg(displayName, + QtcProcess::tr("Invalid command"), + creatorTheme()->color(Theme::TextColorError).name()); +} + QString ProcessParameters::summary(const QString &displayName) const { + if (m_commandMissing) + return invalidCommandMessage(displayName); + return QString::fromLatin1("<b>%1:</b> %2 %3") .arg(displayName, Utils::QtcProcess::quoteArg(prettyCommand()), @@ -179,6 +191,9 @@ QString ProcessParameters::summary(const QString &displayName) const QString ProcessParameters::summaryInWorkdir(const QString &displayName) const { + if (m_commandMissing) + return invalidCommandMessage(displayName); + return QString::fromLatin1("<b>%1:</b> %2 %3 in %4") .arg(displayName, Utils::QtcProcess::quoteArg(prettyCommand()), diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 9735203427..2e75cd3caf 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -888,10 +888,9 @@ Utils::Environment Project::activeParseEnvironment() const return result; } -void Project::setBuildSystem(std::unique_ptr<BuildSystem> &&bs) +void Project::setBuildSystemCreator(const std::function<BuildSystem *(Project *)> &creator) { - QTC_ASSERT(!bs->parent(), bs->setParent(nullptr)); - d->m_buildSystem = std::move(bs); + d->m_buildSystem.reset(creator(this)); } Core::Context Project::projectContext() const diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index 9c4f38fecb..326763bf8c 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -29,7 +29,6 @@ #include "deploymentdata.h" #include "kit.h" -#include "subscription.h" #include <coreplugin/id.h> #include <coreplugin/idocument.h> @@ -54,7 +53,6 @@ class BuildSystem; class ContainerNode; class EditorConfiguration; class FolderNode; -class NamedWidget; class Node; class ProjectConfiguration; class ProjectImporter; @@ -164,24 +162,6 @@ public: ProjectNode *findNodeForBuildKey(const QString &buildKey) const; - template<typename S, typename R, typename T, typename ...Args1, typename ...Args2> - void subscribeSignal(void (S::*sig)(Args1...), R*recv, T (R::*sl)(Args2...)) { - new Internal::ProjectSubscription([sig, recv, sl, this](ProjectConfiguration *pc) { - if (S* sender = qobject_cast<S*>(pc)) - return connect(sender, sig, recv, sl); - return QMetaObject::Connection(); - }, recv, this); - } - - template<typename S, typename R, typename T, typename ...Args1> - void subscribeSignal(void (S::*sig)(Args1...), R*recv, T sl) { - new Internal::ProjectSubscription([sig, recv, sl, this](ProjectConfiguration *pc) { - if (S* sender = qobject_cast<S*>(pc)) - return connect(sender, sig, recv, sl); - return QMetaObject::Connection(); - }, recv, this); - } - bool needsInitialExpansion() const; void setNeedsInitialExpansion(bool needsInitialExpansion); @@ -192,27 +172,29 @@ public: : ParseGuard(nullptr) {} - ~ParseGuard() - { - if (m_project) - m_project->emitParsingFinished(m_success); - } + ~ParseGuard() { release(); } void markAsSuccess() const { m_success = true; } bool isSuccess() const { return m_success; } - bool isNull() const { return !m_project; } + bool guardsProject() const { return m_project; } ParseGuard(const ParseGuard &other) = delete; ParseGuard &operator=(const ParseGuard &other) = delete; ParseGuard(ParseGuard &&other) + : m_project{std::move(other.m_project)} + , m_success{std::move(other.m_success)} { - std::swap(m_project, other.m_project); - std::swap(m_success, other.m_success); + // No need to release this as this is invalid anyway:-) + other.m_project = nullptr; } ParseGuard &operator=(ParseGuard &&other) { - std::swap(m_project, other.m_project); - std::swap(m_success, other.m_success); + release(); + + m_project = std::move(other.m_project); + m_success = std::move(other.m_success); + + other.m_project = nullptr; return *this; } @@ -220,8 +202,17 @@ public: ParseGuard(Project *p) : m_project(p) { - if (m_project) + if (m_project && !m_project->isParsing()) m_project->emitParsingStarted(); + else + m_project = nullptr; + } + + void release() + { + if (m_project) + m_project->emitParsingFinished(m_success); + m_project = nullptr; } Project *m_project = nullptr; @@ -299,7 +290,7 @@ protected: static ProjectExplorer::Task createProjectTask(ProjectExplorer::Task::TaskType type, const QString &description); - void setBuildSystem(std::unique_ptr<BuildSystem> &&bs); // takes ownership! + void setBuildSystemCreator(const std::function<BuildSystem *(Project *)> &creator); private: // Helper methods to manage parsing state and signalling diff --git a/src/plugins/projectexplorer/projectconfiguration.cpp b/src/plugins/projectexplorer/projectconfiguration.cpp index 5ad0299034..442438fc3d 100644 --- a/src/plugins/projectexplorer/projectconfiguration.cpp +++ b/src/plugins/projectexplorer/projectconfiguration.cpp @@ -29,6 +29,9 @@ #include <utils/algorithm.h> #include <utils/qtcassert.h> +#include <QFormLayout> +#include <QWidget> + using namespace ProjectExplorer; const char CONFIGURATION_ID_KEY[] = "ProjectExplorer.ProjectConfiguration.Id"; @@ -51,6 +54,92 @@ QWidget *ProjectConfigurationAspect::createConfigWidget() const return m_configWidgetCreator ? m_configWidgetCreator() : nullptr; } +void ProjectConfigurationAspect::addToLayout(LayoutBuilder &) +{ +} + +// LayoutBuilder + +LayoutBuilder::LayoutBuilder(QWidget *parent) + : m_layout(new QFormLayout(parent)) +{ + m_layout->setContentsMargins(0, 0, 0, 0); + if (auto fl = qobject_cast<QFormLayout *>(m_layout)) + fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); +} + +LayoutBuilder::~LayoutBuilder() +{ + flushPendingItems(); +} + +void LayoutBuilder::startNewRow() +{ + flushPendingItems(); +} + +void LayoutBuilder::flushPendingItems() +{ + if (m_pendingItems.isEmpty()) + return; + + if (auto fl = qobject_cast<QFormLayout *>(m_layout)) { + // If there are more than two items, we cram the last ones in one hbox. + if (m_pendingItems.size() > 2) { + auto hbox = new QHBoxLayout; + for (int i = 1; i < m_pendingItems.size(); ++i) { + if (QWidget *w = m_pendingItems.at(i).widget) + hbox->addWidget(w); + else if (QLayout *l = m_pendingItems.at(i).layout) + hbox->addItem(l); + else + QTC_CHECK(false); + } + while (m_pendingItems.size() >= 2) + m_pendingItems.takeLast(); + m_pendingItems.append(LayoutItem(hbox)); + } + + if (m_pendingItems.size() == 1) { // One one item given, so this spans both columns. + if (auto layout = m_pendingItems.at(0).layout) + fl->addRow(layout); + else if (auto widget = m_pendingItems.at(0).widget) + fl->addRow(widget); + } else if (m_pendingItems.size() == 2) { // Normal case, both columns used. + if (auto label = m_pendingItems.at(0).widget) { + if (auto layout = m_pendingItems.at(1).layout) + fl->addRow(label, layout); + else if (auto widget = m_pendingItems.at(1).widget) + fl->addRow(label, widget); + } else { + if (auto layout = m_pendingItems.at(1).layout) + fl->addRow(m_pendingItems.at(0).text, layout); + else if (auto widget = m_pendingItems.at(1).widget) + fl->addRow(m_pendingItems.at(0).text, widget); + } + } else { + QTC_CHECK(false); + } + } else { + QTC_CHECK(false); + } + + m_pendingItems.clear(); +} + +QLayout *LayoutBuilder::layout() const +{ + return m_layout; +} + +void LayoutBuilder::addItem(LayoutItem item) +{ + if (item.widget && !item.widget->parent()) + item.widget->setParent(m_layout->parentWidget()); + + m_pendingItems.append(item); +} + // ProjectConfigurationAspects diff --git a/src/plugins/projectexplorer/projectconfiguration.h b/src/plugins/projectexplorer/projectconfiguration.h index 4f7a219455..76b3080291 100644 --- a/src/plugins/projectexplorer/projectconfiguration.h +++ b/src/plugins/projectexplorer/projectconfiguration.h @@ -32,12 +32,10 @@ #include <utils/macroexpander.h> #include <QObject> +#include <QPointer> #include <QString> #include <QVariantMap> - -QT_BEGIN_NAMESPACE -class QFormLayout; -QT_END_NAMESPACE +#include <QWidget> namespace ProjectExplorer { @@ -45,6 +43,36 @@ class Project; class ProjectConfigurationAspects; class Target; +class PROJECTEXPLORER_EXPORT LayoutBuilder +{ +public: + explicit LayoutBuilder(QWidget *parent); + ~LayoutBuilder(); + + class LayoutItem + { + public: + LayoutItem(QLayout *layout) : layout(layout) {} + LayoutItem(QWidget *widget) : widget(widget) {} + LayoutItem(const QString &text) : text(text) {} + + QLayout *layout = nullptr; + QWidget *widget = nullptr; + QString text; + }; + + void addItem(LayoutItem item); + void startNewRow(); + + QLayout *layout() const; + +private: + void flushPendingItems(); + + QLayout *m_layout = nullptr; + QList<LayoutItem> m_pendingItems; +}; + class PROJECTEXPLORER_EXPORT ProjectConfigurationAspect : public QObject { Q_OBJECT @@ -70,9 +98,10 @@ public: virtual void fromMap(const QVariantMap &) {} virtual void toMap(QVariantMap &) const {} - virtual void addToConfigurationLayout(QFormLayout *) {} virtual void acquaintSiblings(const ProjectConfigurationAspects &) {} + virtual void addToLayout(LayoutBuilder &builder); + signals: void changed(); @@ -182,7 +211,7 @@ protected: ProjectConfigurationAspects m_aspects; private: - Target *m_target = nullptr; + QPointer<Target> m_target; const Core::Id m_id; Utils::DisplayName m_displayName; QString m_toolTip; diff --git a/src/plugins/projectexplorer/projectconfigurationaspects.cpp b/src/plugins/projectexplorer/projectconfigurationaspects.cpp index 692c5d77b9..60b1ff400b 100644 --- a/src/plugins/projectexplorer/projectconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/projectconfigurationaspects.cpp @@ -253,20 +253,19 @@ void BaseStringAspect::setReadOnly(bool readOnly) d->m_textEditDisplay->setReadOnly(readOnly); } -void BaseStringAspect::addToConfigurationLayout(QFormLayout *layout) +void BaseStringAspect::addToLayout(LayoutBuilder &builder) { QTC_CHECK(!d->m_label); - QWidget *parent = layout->parentWidget(); - d->m_label = new QLabel(parent); + d->m_label = new QLabel; d->m_label->setTextInteractionFlags(Qt::TextSelectableByMouse); d->m_label->setText(d->m_labelText); if (!d->m_labelPixmap.isNull()) d->m_label->setPixmap(d->m_labelPixmap); + builder.addItem(d->m_label.data()); - auto hbox = new QHBoxLayout; switch (d->m_displayStyle) { case PathChooserDisplay: - d->m_pathChooserDisplay = new PathChooser(parent); + d->m_pathChooserDisplay = new PathChooser; d->m_pathChooserDisplay->setExpectedKind(d->m_expectedKind); if (!d->m_historyCompleterKey.isEmpty()) d->m_pathChooserDisplay->setHistoryCompleter(d->m_historyCompleterKey); @@ -275,20 +274,20 @@ void BaseStringAspect::addToConfigurationLayout(QFormLayout *layout) d->m_pathChooserDisplay->setReadOnly(d->m_readOnly); connect(d->m_pathChooserDisplay, &PathChooser::pathChanged, this, &BaseStringAspect::setValue); - hbox->addWidget(d->m_pathChooserDisplay); + builder.addItem(d->m_pathChooserDisplay.data()); break; case LineEditDisplay: - d->m_lineEditDisplay = new FancyLineEdit(parent); + d->m_lineEditDisplay = new FancyLineEdit; d->m_lineEditDisplay->setPlaceholderText(d->m_placeHolderText); if (!d->m_historyCompleterKey.isEmpty()) d->m_lineEditDisplay->setHistoryCompleter(d->m_historyCompleterKey); d->m_lineEditDisplay->setReadOnly(d->m_readOnly); connect(d->m_lineEditDisplay, &FancyLineEdit::textEdited, this, &BaseStringAspect::setValue); - hbox->addWidget(d->m_lineEditDisplay); + builder.addItem(d->m_lineEditDisplay.data()); break; case TextEditDisplay: - d->m_textEditDisplay = new QTextEdit(parent); + d->m_textEditDisplay = new QTextEdit; d->m_textEditDisplay->setPlaceholderText(d->m_placeHolderText); d->m_textEditDisplay->setReadOnly(d->m_readOnly); connect(d->m_textEditDisplay, &QTextEdit::textChanged, this, [this] { @@ -298,23 +297,17 @@ void BaseStringAspect::addToConfigurationLayout(QFormLayout *layout) emit changed(); } }); - hbox->addWidget(d->m_textEditDisplay); + builder.addItem(d->m_textEditDisplay.data()); break; case LabelDisplay: - d->m_labelDisplay = new QLabel(parent); + d->m_labelDisplay = new QLabel; d->m_labelDisplay->setTextInteractionFlags(Qt::TextSelectableByMouse); - hbox->addWidget(d->m_labelDisplay); + builder.addItem(d->m_labelDisplay.data()); break; } - if (d->m_checker) { - auto form = new QFormLayout; - form->setContentsMargins(0, 0, 0, 0); - form->setFormAlignment(Qt::AlignLeft | Qt::AlignVCenter); - d->m_checker->addToConfigurationLayout(form); - hbox->addLayout(form); - } - layout->addRow(d->m_label, hbox); + if (d->m_checker) + d->m_checker->addToLayout(builder); update(); } @@ -378,13 +371,14 @@ BaseBoolAspect::BaseBoolAspect(const QString &settingsKey) BaseBoolAspect::~BaseBoolAspect() = default; -void BaseBoolAspect::addToConfigurationLayout(QFormLayout *layout) +void BaseBoolAspect::addToLayout(LayoutBuilder &builder) { QTC_CHECK(!d->m_checkBox); - d->m_checkBox = new QCheckBox(d->m_label, layout->parentWidget()); + d->m_checkBox = new QCheckBox(d->m_label); d->m_checkBox->setChecked(d->m_value); d->m_checkBox->setToolTip(d->m_tooltip); - layout->addRow(QString(), d->m_checkBox); + builder.addItem(QString()); + builder.addItem(d->m_checkBox.data()); connect(d->m_checkBox.data(), &QAbstractButton::clicked, this, [this] { d->m_value = d->m_checkBox->isChecked(); emit changed(); @@ -444,7 +438,7 @@ BaseSelectionAspect::BaseSelectionAspect() BaseSelectionAspect::~BaseSelectionAspect() = default; -void BaseSelectionAspect::addToConfigurationLayout(QFormLayout *layout) +void BaseSelectionAspect::addToLayout(LayoutBuilder &builder) { QTC_CHECK(d->m_buttonGroup == nullptr); d->m_buttonGroup = new QButtonGroup; @@ -453,10 +447,11 @@ void BaseSelectionAspect::addToConfigurationLayout(QFormLayout *layout) QTC_ASSERT(d->m_buttons.isEmpty(), d->m_buttons.clear()); for (int i = 0, n = d->m_options.size(); i < n; ++i) { const Internal::BaseSelectionAspectPrivate::Option &option = d->m_options.at(i); - auto button = new QRadioButton(option.displayName, layout->parentWidget()); + auto button = new QRadioButton(option.displayName); button->setChecked(i == d->m_value); button->setToolTip(option.tooltip); - layout->addRow(QString(), button); + builder.addItem(QString()); + builder.addItem(button); d->m_buttons.append(button); d->m_buttonGroup->addButton(button); connect(button, &QAbstractButton::clicked, this, [this, i] { @@ -515,10 +510,10 @@ BaseIntegerAspect::BaseIntegerAspect() BaseIntegerAspect::~BaseIntegerAspect() = default; -void BaseIntegerAspect::addToConfigurationLayout(QFormLayout *layout) +void BaseIntegerAspect::addToLayout(LayoutBuilder &builder) { QTC_CHECK(!d->m_spinBox); - d->m_spinBox = new QSpinBox(layout->parentWidget()); + d->m_spinBox = new QSpinBox; d->m_spinBox->setValue(int(d->m_value / d->m_displayScaleFactor)); d->m_spinBox->setDisplayIntegerBase(d->m_displayIntegerBase); d->m_spinBox->setPrefix(d->m_prefix); @@ -526,7 +521,8 @@ void BaseIntegerAspect::addToConfigurationLayout(QFormLayout *layout) if (d->m_maximumValue.isValid() && d->m_maximumValue.isValid()) d->m_spinBox->setRange(int(d->m_minimumValue.toLongLong() / d->m_displayScaleFactor), int(d->m_maximumValue.toLongLong() / d->m_displayScaleFactor)); - layout->addRow(d->m_label, d->m_spinBox); + builder.addItem(d->m_label); + builder.addItem(d->m_spinBox.data()); connect(d->m_spinBox.data(), QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int value) { d->m_value = value * d->m_displayScaleFactor; diff --git a/src/plugins/projectexplorer/projectconfigurationaspects.h b/src/plugins/projectexplorer/projectconfigurationaspects.h index 3195ad63fc..90bdcbc2bb 100644 --- a/src/plugins/projectexplorer/projectconfigurationaspects.h +++ b/src/plugins/projectexplorer/projectconfigurationaspects.h @@ -50,7 +50,7 @@ public: explicit BaseBoolAspect(const QString &settingsKey = QString()); ~BaseBoolAspect() override; - void addToConfigurationLayout(QFormLayout *layout) override; + void addToLayout(LayoutBuilder &builder) override; bool value() const; void setValue(bool val); @@ -76,7 +76,7 @@ public: BaseSelectionAspect(); ~BaseSelectionAspect() override; - void addToConfigurationLayout(QFormLayout *layout) override; + void addToLayout(LayoutBuilder &builder) override; int value() const; void setValue(int val); @@ -101,7 +101,7 @@ public: BaseStringAspect(); ~BaseStringAspect() override; - void addToConfigurationLayout(QFormLayout *layout) override; + void addToLayout(LayoutBuilder &builder) override; QString value() const; void setValue(const QString &val); @@ -150,7 +150,7 @@ public: BaseIntegerAspect(); ~BaseIntegerAspect() override; - void addToConfigurationLayout(QFormLayout *layout) override; + void addToLayout(LayoutBuilder &builder) override; qint64 value() const; void setValue(qint64 val); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 30fdbcc58a..4d7aee5fc8 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -659,8 +659,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er qRegisterMetaType<ProjectExplorer::RunControl *>(); qRegisterMetaType<ProjectExplorer::DeployableFile>("ProjectExplorer::DeployableFile"); - CustomWizard::setVerbose(arguments.count(QLatin1String("-customwizard-verbose"))); - JsonWizardFactory::setVerbose(arguments.count(QLatin1String("-customwizard-verbose"))); + handleCommandLineArguments(arguments); dd->m_toolChainManager = new ToolChainManager; @@ -2794,6 +2793,26 @@ bool ProjectExplorerPlugin::coreAboutToClose() return dd->m_outputPane.aboutToClose(); } +void ProjectExplorerPlugin::handleCommandLineArguments(const QStringList &arguments) +{ + CustomWizard::setVerbose(arguments.count(QLatin1String("-customwizard-verbose"))); + JsonWizardFactory::setVerbose(arguments.count(QLatin1String("-customwizard-verbose"))); + + const int kitForBinaryOptionIndex = arguments.indexOf("-ensure-kit-for-binary"); + if (kitForBinaryOptionIndex != -1) { + if (kitForBinaryOptionIndex == arguments.count() - 1) { + qWarning() << "The \"-ensure-kit-for-binary\" option requires a file path argument."; + } else { + const Utils::FilePath binary = + Utils::FilePath::fromString(arguments.at(kitForBinaryOptionIndex + 1)); + if (binary.isEmpty() || !binary.exists()) + qWarning() << QString("No such file \"%1\".").arg(binary.toUserOutput()); + else + KitManager::setBinaryForKit(binary); + } + } +} + static bool hasDeploySettings(Project *pro) { return Utils::anyOf(SessionManager::projectOrder(pro), [](Project *project) { diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index feb53ccdef..c2dffd4f6f 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -187,6 +187,7 @@ signals: private: static bool coreAboutToClose(); + void handleCommandLineArguments(const QStringList &arguments); #ifdef WITH_TESTS private slots: diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index a63af418d9..6fbc74ea24 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -32,7 +32,6 @@ HEADERS += projectexplorer.h \ projectimporter.h \ projectwindow.h \ removetaskhandler.h \ - subscription.h \ targetsetuppage.h \ targetsetupwidget.h \ kit.h \ @@ -191,7 +190,6 @@ SOURCES += projectexplorer.cpp \ projectimporter.cpp \ projectwindow.cpp \ removetaskhandler.cpp \ - subscription.cpp \ targetsetuppage.cpp \ targetsetupwidget.cpp \ kit.cpp \ diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 9fabfcb98f..9a4131d0fd 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -141,7 +141,6 @@ Project { "sessiondialog.cpp", "sessiondialog.h", "sessiondialog.ui", "showineditortaskhandler.cpp", "showineditortaskhandler.h", "showoutputtaskhandler.cpp", "showoutputtaskhandler.h", - "subscription.cpp", "subscription.h", "target.cpp", "target.h", "targetsettingspanel.cpp", "targetsettingspanel.h", "targetsetuppage.cpp", "targetsetuppage.h", diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index 9714c1aa09..ce39300600 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -425,6 +425,8 @@ void FlatModel::addFolderNode(WrapperNode *parent, FolderNode *folderNode, QSet< for (Node *node : folderNode->nodes()) { if (m_filterGeneratedFiles && node->isGenerated()) continue; + if (m_filterDisabledFiles && !node->isEnabled()) + continue; if (FolderNode *subFolderNode = node->asFolderNode()) { const bool isHidden = m_filterProjects && !subFolderNode->showInSimpleTree(); if (!isHidden && !seen->contains(subFolderNode)) { @@ -810,6 +812,14 @@ void FlatModel::setGeneratedFilesFilterEnabled(bool filter) rebuildModel(); } +void FlatModel::setDisabledFilesFilterEnabled(bool filter) +{ + if (filter == m_filterDisabledFiles) + return; + m_filterDisabledFiles = filter; + rebuildModel(); +} + void FlatModel::setTrimEmptyDirectories(bool filter) { if (filter == m_trimEmptyDirectories) diff --git a/src/plugins/projectexplorer/projectmodels.h b/src/plugins/projectexplorer/projectmodels.h index f4412eae28..835e28993d 100644 --- a/src/plugins/projectexplorer/projectmodels.h +++ b/src/plugins/projectexplorer/projectmodels.h @@ -80,9 +80,11 @@ public: bool projectFilterEnabled(); bool generatedFilesFilterEnabled(); + bool disabledFilesFilterEnabled() const { return m_filterDisabledFiles; } bool trimEmptyDirectoriesEnabled(); void setProjectFilterEnabled(bool filter); void setGeneratedFilesFilterEnabled(bool filter); + void setDisabledFilesFilterEnabled(bool filter); void setTrimEmptyDirectories(bool filter); void onExpanded(const QModelIndex &idx); @@ -95,6 +97,7 @@ signals: private: bool m_filterProjects = false; bool m_filterGeneratedFiles = true; + bool m_filterDisabledFiles = false; bool m_trimEmptyDirectories = true; static const QLoggingCategory &logger(); diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index c2244ed010..1424333fcc 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -25,6 +25,7 @@ #include "projectnodes.h" +#include "buildsystem.h" #include "project.h" #include "projectexplorerconstants.h" #include "projecttree.h" @@ -882,47 +883,51 @@ bool ProjectNode::removeSubProject(const QString &proFilePath) bool ProjectNode::addFiles(const QStringList &filePaths, QStringList *notAdded) { - Q_UNUSED(filePaths) - Q_UNUSED(notAdded) + if (BuildSystem *bs = buildSystem()) + return bs->addFiles(this, filePaths, notAdded); return false; } RemovedFilesFromProject ProjectNode::removeFiles(const QStringList &filePaths, QStringList *notRemoved) { - Q_UNUSED(filePaths) - Q_UNUSED(notRemoved) + if (BuildSystem *bs = buildSystem()) + return bs->removeFiles(this, filePaths, notRemoved); return RemovedFilesFromProject::Error; } bool ProjectNode::deleteFiles(const QStringList &filePaths) { - Q_UNUSED(filePaths) + if (BuildSystem *bs = buildSystem()) + return bs->deleteFiles(this, filePaths); return false; } bool ProjectNode::canRenameFile(const QString &filePath, const QString &newFilePath) { - Q_UNUSED(filePath) - Q_UNUSED(newFilePath) + if (BuildSystem *bs = buildSystem()) + return bs->canRenameFile(this, filePath, newFilePath); return true; } bool ProjectNode::renameFile(const QString &filePath, const QString &newFilePath) { - Q_UNUSED(filePath) - Q_UNUSED(newFilePath) + if (BuildSystem *bs = buildSystem()) + return bs->renameFile(this, filePath, newFilePath); return false; } bool ProjectNode::addDependencies(const QStringList &dependencies) { - Q_UNUSED(dependencies) + if (BuildSystem *bs = buildSystem()) + return bs->addDependencies(this, dependencies); return false; } -bool ProjectNode::supportsAction(ProjectAction, const Node *) const +bool ProjectNode::supportsAction(ProjectAction action, const Node *node) const { + if (BuildSystem *bs = buildSystem()) + return bs->supportsAction(const_cast<ProjectNode *>(this), action, node); return false; } @@ -959,6 +964,12 @@ void ProjectNode::setFallbackData(Core::Id key, const QVariant &value) m_fallbackData.insert(key, value); } +BuildSystem *ProjectNode::buildSystem() const +{ + Project *p = getProject(); + return p ? p->buildSystem() : nullptr; +} + bool FolderNode::isEmpty() const { return m_nodes.size() == 0; diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index 68e11a178d..7ad184cdf7 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -42,6 +42,7 @@ namespace Utils { class MimeType; } namespace ProjectExplorer { +class BuildSystem; class Project; // File types common for qt projects @@ -357,14 +358,14 @@ public: bool isProjectNodeType() const override { return true; } bool showInSimpleTree() const override { return true; } - bool addFiles(const QStringList &filePaths, QStringList *notAdded = nullptr) override; + bool addFiles(const QStringList &filePaths, QStringList *notAdded = nullptr) final; RemovedFilesFromProject removeFiles(const QStringList &filePaths, - QStringList *notRemoved = nullptr) override; - bool deleteFiles(const QStringList &filePaths) override; - bool canRenameFile(const QString &filePath, const QString &newFilePath) override; - bool renameFile(const QString &filePath, const QString &newFilePath) override; - bool addDependencies(const QStringList &dependencies) override; - bool supportsAction(ProjectAction action, const Node *node) const override; + QStringList *notRemoved = nullptr) final; + bool deleteFiles(const QStringList &filePaths) final; + bool canRenameFile(const QString &filePath, const QString &newFilePath) final; + bool renameFile(const QString &filePath, const QString &newFilePath) final; + bool addDependencies(const QStringList &dependencies) final; + bool supportsAction(ProjectAction action, const Node *node) const final; // by default returns false virtual bool deploysFolder(const QString &folder) const; @@ -399,6 +400,8 @@ protected: QString m_target; private: + BuildSystem *buildSystem() const; + QHash<Core::Id, QVariant> m_fallbackData; // Used in data(), unless overridden. ProductType m_productType = ProductType::None; }; diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp index 14e6feca16..b3ae5756e7 100644 --- a/src/plugins/projectexplorer/projecttreewidget.cpp +++ b/src/plugins/projectexplorer/projecttreewidget.cpp @@ -257,6 +257,12 @@ ProjectTreeWidget::ProjectTreeWidget(QWidget *parent) : QWidget(parent) connect(m_filterGeneratedFilesAction, &QAction::toggled, this, &ProjectTreeWidget::setGeneratedFilesFilter); + m_filterDisabledFilesAction = new QAction(tr("Hide Disabled Files"), this); + m_filterDisabledFilesAction->setCheckable(true); + m_filterDisabledFilesAction->setChecked(false); + connect(m_filterDisabledFilesAction, &QAction::toggled, + this, &ProjectTreeWidget::setDisabledFilesFilter); + const char focusActionId[] = "ProjectExplorer.FocusDocumentInProjectTree"; if (!ActionManager::command(focusActionId)) { auto focusDocumentInProjectTree = new QAction(tr("Focus Document in Project Tree"), this); @@ -557,6 +563,12 @@ void ProjectTreeWidget::setGeneratedFilesFilter(bool filter) m_filterGeneratedFilesAction->setChecked(filter); } +void ProjectTreeWidget::setDisabledFilesFilter(bool filter) +{ + m_model->setDisabledFilesFilterEnabled(filter); + m_filterDisabledFilesAction->setChecked(filter); +} + void ProjectTreeWidget::setTrimEmptyDirectories(bool filter) { m_model->setTrimEmptyDirectories(filter); @@ -568,6 +580,11 @@ bool ProjectTreeWidget::generatedFilesFilter() return m_model->generatedFilesFilterEnabled(); } +bool ProjectTreeWidget::disabledFilesFilter() +{ + return m_model->disabledFilesFilterEnabled(); +} + bool ProjectTreeWidget::trimEmptyDirectoriesFilter() { return m_model->trimEmptyDirectoriesEnabled(); @@ -601,6 +618,7 @@ NavigationView ProjectTreeWidgetFactory::createWidget() auto filterMenu = new QMenu(filter); filterMenu->addAction(ptw->m_filterProjectsAction); filterMenu->addAction(ptw->m_filterGeneratedFilesAction); + filterMenu->addAction(ptw->m_filterDisabledFilesAction); filterMenu->addAction(ptw->m_trimEmptyDirectoriesAction); filter->setMenu(filterMenu); @@ -615,6 +633,7 @@ void ProjectTreeWidgetFactory::saveSettings(QSettings *settings, int position, Q const QString baseKey = QLatin1String("ProjectTreeWidget.") + QString::number(position); settings->setValue(baseKey + QLatin1String(".ProjectFilter"), ptw->projectFilter()); settings->setValue(baseKey + QLatin1String(".GeneratedFilter"), ptw->generatedFilesFilter()); + settings->setValue(baseKey + ".DisabledFilesFilter", ptw->disabledFilesFilter()); settings->setValue(baseKey + QLatin1String(".TrimEmptyDirsFilter"), ptw->trimEmptyDirectoriesFilter()); settings->setValue(baseKey + QLatin1String(".SyncWithEditor"), ptw->autoSynchronization()); } @@ -626,6 +645,7 @@ void ProjectTreeWidgetFactory::restoreSettings(QSettings *settings, int position const QString baseKey = QLatin1String("ProjectTreeWidget.") + QString::number(position); ptw->setProjectFilter(settings->value(baseKey + QLatin1String(".ProjectFilter"), false).toBool()); ptw->setGeneratedFilesFilter(settings->value(baseKey + QLatin1String(".GeneratedFilter"), true).toBool()); + ptw->setDisabledFilesFilter(settings->value(baseKey + ".DisabledFilesFilter", false).toBool()); ptw->setTrimEmptyDirectories(settings->value(baseKey + QLatin1String(".TrimEmptyDirsFilter"), true).toBool()); ptw->setAutoSynchronization(settings->value(baseKey + QLatin1String(".SyncWithEditor"), true).toBool()); } diff --git a/src/plugins/projectexplorer/projecttreewidget.h b/src/plugins/projectexplorer/projecttreewidget.h index 74b301e93b..e53396c4b9 100644 --- a/src/plugins/projectexplorer/projecttreewidget.h +++ b/src/plugins/projectexplorer/projecttreewidget.h @@ -56,6 +56,7 @@ public: void setAutoSynchronization(bool sync); bool projectFilter(); bool generatedFilesFilter(); + bool disabledFilesFilter(); bool trimEmptyDirectoriesFilter(); QToolButton *toggleSync(); Node *currentNode(); @@ -72,6 +73,7 @@ public: private: void setProjectFilter(bool filter); void setGeneratedFilesFilter(bool filter); + void setDisabledFilesFilter(bool filter); void setTrimEmptyDirectories(bool filter); void handleCurrentItemChange(const QModelIndex ¤t); @@ -89,6 +91,7 @@ private: FlatModel *m_model = nullptr; QAction *m_filterProjectsAction = nullptr; QAction *m_filterGeneratedFilesAction = nullptr; + QAction *m_filterDisabledFilesAction = nullptr; QAction *m_trimEmptyDirectoriesAction = nullptr; QToolButton *m_toggleSync = nullptr; diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 2c2394c7e3..903c6f878a 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -248,13 +248,14 @@ QString RunConfiguration::disabledReason() const QWidget *RunConfiguration::createConfigurationWidget() { auto widget = new QWidget; - auto formLayout = new QFormLayout(widget); - formLayout->setContentsMargins(0, 0, 0, 0); - formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); - - for (ProjectConfigurationAspect *aspect : m_aspects) { - if (aspect->isVisible()) - aspect->addToConfigurationLayout(formLayout); + { + LayoutBuilder builder(widget); + for (ProjectConfigurationAspect *aspect : m_aspects) { + if (aspect->isVisible()) { + builder.startNewRow(); + aspect->addToLayout(builder); + } + } } Core::VariableChooser::addSupportForChildWidgets(widget, macroExpander()); diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index 0358dd54a5..0d1e963263 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -63,12 +63,13 @@ TerminalAspect::TerminalAspect() this, &TerminalAspect::calculateUseTerminal); } -void TerminalAspect::addToConfigurationLayout(QFormLayout *layout) +void TerminalAspect::addToLayout(LayoutBuilder &builder) { QTC_CHECK(!m_checkBox); - m_checkBox = new QCheckBox(tr("Run in terminal"), layout->parentWidget()); + m_checkBox = new QCheckBox(tr("Run in terminal")); m_checkBox->setChecked(m_useTerminal); - layout->addRow(QString(), m_checkBox); + builder.addItem(QString()); + builder.addItem(m_checkBox.data()); connect(m_checkBox.data(), &QAbstractButton::clicked, this, [this] { m_userSet = true; m_useTerminal = m_checkBox->isChecked(); @@ -103,7 +104,7 @@ void TerminalAspect::calculateUseTerminal() switch (ProjectExplorerPlugin::projectExplorerSettings().terminalMode) { case Internal::TerminalMode::On: useTerminal = true; break; case Internal::TerminalMode::Off: useTerminal = false; break; - case Internal::TerminalMode::Smart: useTerminal = m_useTerminalHint; + default: useTerminal = m_useTerminalHint; } if (m_useTerminal != useTerminal) { m_useTerminal = useTerminal; @@ -140,10 +141,10 @@ WorkingDirectoryAspect::WorkingDirectoryAspect() setSettingsKey("RunConfiguration.WorkingDirectory"); } -void WorkingDirectoryAspect::addToConfigurationLayout(QFormLayout *layout) +void WorkingDirectoryAspect::addToLayout(LayoutBuilder &builder) { QTC_CHECK(!m_chooser); - m_chooser = new PathChooser(layout->parentWidget()); + m_chooser = new PathChooser; m_chooser->setHistoryCompleter(settingsKey()); m_chooser->setExpectedKind(Utils::PathChooser::Directory); m_chooser->setPromptDialogTitle(tr("Select Working Directory")); @@ -155,7 +156,7 @@ void WorkingDirectoryAspect::addToConfigurationLayout(QFormLayout *layout) m_resetButton->setEnabled(m_workingDirectory != m_defaultWorkingDirectory); }); - m_resetButton = new QToolButton(layout->parentWidget()); + m_resetButton = new QToolButton; m_resetButton->setToolTip(tr("Reset to Default")); m_resetButton->setIcon(Utils::Icons::RESET.icon()); connect(m_resetButton.data(), &QAbstractButton::clicked, this, &WorkingDirectoryAspect::resetPath); @@ -168,10 +169,9 @@ void WorkingDirectoryAspect::addToConfigurationLayout(QFormLayout *layout) m_chooser->setEnvironment(m_envAspect->environment()); } - auto hbox = new QHBoxLayout; - hbox->addWidget(m_chooser); - hbox->addWidget(m_resetButton); - layout->addRow(tr("Working directory:"), hbox); + builder.addItem(tr("Working directory:")); + builder.addItem(m_chooser.data()); + builder.addItem(m_resetButton.data()); } void WorkingDirectoryAspect::acquaintSiblings(const ProjectConfigurationAspects &siblings) @@ -337,9 +337,10 @@ QWidget *ArgumentsAspect::setupChooser() return m_chooser.data(); } -void ArgumentsAspect::addToConfigurationLayout(QFormLayout *layout) +void ArgumentsAspect::addToLayout(LayoutBuilder &builder) { QTC_CHECK(!m_chooser && !m_multiLineChooser && !m_multiLineButton); + builder.addItem(tr("Command line arguments:")); const auto container = new QWidget; const auto containerLayout = new QHBoxLayout(container); @@ -371,7 +372,8 @@ void ArgumentsAspect::addToConfigurationLayout(QFormLayout *layout) }); containerLayout->addWidget(m_multiLineButton); containerLayout->setAlignment(m_multiLineButton, Qt::AlignTop); - layout->addRow(tr("Command line arguments:"), container); + + builder.addItem(container); } /*! @@ -450,11 +452,13 @@ FilePath ExecutableAspect::executable() const return m_executable.filePath(); } -void ExecutableAspect::addToConfigurationLayout(QFormLayout *layout) +void ExecutableAspect::addToLayout(LayoutBuilder &builder) { - m_executable.addToConfigurationLayout(layout); - if (m_alternativeExecutable) - m_alternativeExecutable->addToConfigurationLayout(layout); + m_executable.addToLayout(builder); + if (m_alternativeExecutable) { + builder.startNewRow(); + m_alternativeExecutable->addToLayout(builder); + } } void ExecutableAspect::setLabelText(const QString &labelText) diff --git a/src/plugins/projectexplorer/runconfigurationaspects.h b/src/plugins/projectexplorer/runconfigurationaspects.h index 2b65737789..ca41d04df8 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.h +++ b/src/plugins/projectexplorer/runconfigurationaspects.h @@ -48,7 +48,7 @@ class PROJECTEXPLORER_EXPORT TerminalAspect : public ProjectConfigurationAspect public: TerminalAspect(); - void addToConfigurationLayout(QFormLayout *layout) override; + void addToLayout(LayoutBuilder &builder) override; bool useTerminal() const; void setUseTerminalHint(bool useTerminal); @@ -74,7 +74,7 @@ class PROJECTEXPLORER_EXPORT WorkingDirectoryAspect : public ProjectConfiguratio public: WorkingDirectoryAspect(); - void addToConfigurationLayout(QFormLayout *layout) override; + void addToLayout(LayoutBuilder &builder) override; void acquaintSiblings(const ProjectConfigurationAspects &) override; Utils::FilePath workingDirectory(const Utils::MacroExpander *expander) const; @@ -104,7 +104,7 @@ class PROJECTEXPLORER_EXPORT ArgumentsAspect : public ProjectConfigurationAspect public: ArgumentsAspect(); - void addToConfigurationLayout(QFormLayout *layout) override; + void addToLayout(LayoutBuilder &builder) override; QString arguments(const Utils::MacroExpander *expander) const; QString unexpandedArguments() const; @@ -157,7 +157,7 @@ public: void setSettingsKey(const QString &key); void makeOverridable(const QString &overridingKey, const QString &useOverridableKey); - void addToConfigurationLayout(QFormLayout *layout) override; + void addToLayout(LayoutBuilder &builder) override; void setLabelText(const QString &labelText); void setPlaceHolderText(const QString &placeHolderText); void setExecutablePathStyle(Utils::OsType osType); diff --git a/src/plugins/projectexplorer/runsettingspropertiespage.cpp b/src/plugins/projectexplorer/runsettingspropertiespage.cpp index 4695eff651..1cde0b89d4 100644 --- a/src/plugins/projectexplorer/runsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/runsettingspropertiespage.cpp @@ -424,8 +424,7 @@ void RunSettingsWidget::updateDeployConfiguration(DeployConfiguration *dc) if (m_deployConfigurationWidget) m_deployLayout->addWidget(m_deployConfigurationWidget); - m_deploySteps = new BuildStepListWidget; - m_deploySteps->init(dc->stepList()); + m_deploySteps = new BuildStepListWidget(dc->stepList()); m_deployLayout->addWidget(m_deploySteps); } diff --git a/src/plugins/projectexplorer/runsettingspropertiespage.h b/src/plugins/projectexplorer/runsettingspropertiespage.h index 12f1403c42..7db4db3e9a 100644 --- a/src/plugins/projectexplorer/runsettingspropertiespage.h +++ b/src/plugins/projectexplorer/runsettingspropertiespage.h @@ -39,9 +39,7 @@ QT_END_NAMESPACE namespace ProjectExplorer { class DeployConfiguration; -class NamedWidget; class RunConfiguration; -class RunConfigWidget; class Target; namespace Internal { diff --git a/src/plugins/projectexplorer/subscription.cpp b/src/plugins/projectexplorer/subscription.cpp deleted file mode 100644 index a8092ed3ba..0000000000 --- a/src/plugins/projectexplorer/subscription.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "subscription.h" - -#include "project.h" -#include "projectconfiguration.h" -#include "session.h" -#include "target.h" - -#include <utils/qtcassert.h> - -namespace ProjectExplorer { -namespace Internal { - -Subscription::Subscription(const Subscription::Connector &s, const QObject *receiver, QObject *parent) : - QObject(parent), m_subscriber(s) -{ - if (receiver != parent) - connect(receiver, &QObject::destroyed, this, &Subscription::destroy); -} - -Subscription::~Subscription() -{ - unsubscribeAll(); -} - -void Subscription::subscribe(ProjectConfiguration *pc) -{ - if (!m_subscriber) - return; - - connectTo(pc); -} - -void Subscription::subscribeTarget(Target *target) -{ - if (!m_subscriber) - return; - - for (ProjectConfiguration *pc : target->projectConfigurations()) - connectTo(pc); -} - -void Subscription::unsubscribe(ProjectConfiguration *pc) -{ - disconnectFrom(pc); -} - -void Subscription::unsubscribeTarget(Target *target) -{ - for (ProjectConfiguration *pc : target->projectConfigurations()) - disconnectFrom(pc); -} - -void Subscription::unsubscribeAll() -{ - for (const auto &c : qAsConst(m_connections)) - disconnect(c); - m_connections.clear(); -} - -void Subscription::connectTo(ProjectConfiguration *pc) -{ - if (!m_subscriber) - return; // May happen during shutdown of a subscription - - QTC_ASSERT(!m_connections.contains(pc), return); - - QMetaObject::Connection conn = m_subscriber(pc); - if (conn) - m_connections.insert(pc, conn); -} - -void Subscription::disconnectFrom(ProjectConfiguration *pc) -{ - auto c = m_connections.value(pc); - if (!c) - return; - - disconnect(c); - m_connections.remove(pc); -} - -void Subscription::destroy() -{ - unsubscribeAll(); - m_subscriber = Connector(); // Reset subscriber - deleteLater(); -} - -ProjectSubscription::ProjectSubscription(const Subscription::Connector &s, const QObject *r, - Project *p) : - Subscription(s, r, p) -{ - QTC_ASSERT(m_subscriber, return); - - for (Target *t : p->targets()) - subscribeTarget(t); - - // Disconnect on removal of a project, to make it save to remove/add a project: - connect(SessionManager::instance(), &SessionManager::projectRemoved, - this, [this, p](Project *reported) { if (p == reported) { destroy(); } }); - connect(p, &Project::addedProjectConfiguration, this, &ProjectSubscription::subscribe); - connect(p, &Project::addedTarget, this, &ProjectSubscription::subscribeTarget); - connect(p, &Project::removedProjectConfiguration, this, &ProjectSubscription::unsubscribe); - connect(p, &Project::removedTarget, this, &ProjectSubscription::unsubscribeTarget); -} - -ProjectSubscription::~ProjectSubscription() = default; - -} // namespace Internal -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/subscription.h b/src/plugins/projectexplorer/subscription.h deleted file mode 100644 index baff689d8e..0000000000 --- a/src/plugins/projectexplorer/subscription.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include "projectexplorer_export.h" - -#include <QHash> -#include <QObject> - -#include <functional> - -namespace ProjectExplorer { - -class Project; -class ProjectConfiguration; -class Target; - -namespace Internal { - -class PROJECTEXPLORER_EXPORT Subscription : public QObject -{ - Q_OBJECT -public: - using Connector = std::function<QMetaObject::Connection(ProjectConfiguration *)>; - - Subscription(const Connector &s, const QObject *receiver, QObject *parent); - ~Subscription() override; - -protected: - void subscribe(ProjectConfiguration *pc); - void subscribeTarget(Target *target); - void unsubscribe(ProjectConfiguration *pc); - void unsubscribeTarget(Target *target); - - void unsubscribeAll(); - void connectTo(ProjectConfiguration *pc); - void disconnectFrom(ProjectConfiguration *pc); - - void destroy(); - - Connector m_subscriber; - QHash<ProjectConfiguration *, QMetaObject::Connection> m_connections; -}; - -class PROJECTEXPLORER_EXPORT ProjectSubscription : public Subscription -{ -public: - ProjectSubscription(const Connector &s, const QObject *receiver, Project *p); - ~ProjectSubscription() final; -}; - -} // namespace Internal -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/target.h b/src/plugins/projectexplorer/target.h index d7e64beda4..2fdf555bf3 100644 --- a/src/plugins/projectexplorer/target.h +++ b/src/plugins/projectexplorer/target.h @@ -28,8 +28,6 @@ #include "projectconfiguration.h" #include "projectexplorer_export.h" -#include "subscription.h" - #include <memory> QT_FORWARD_DECLARE_CLASS(QIcon) diff --git a/src/plugins/python/pythonproject.cpp b/src/plugins/python/pythonproject.cpp index c38394a0be..921f66b043 100644 --- a/src/plugins/python/pythonproject.cpp +++ b/src/plugins/python/pythonproject.cpp @@ -27,6 +27,7 @@ #include "pythonconstants.h" +#include <projectexplorer/buildsystem.h> #include <projectexplorer/buildtargetinfo.h> #include <projectexplorer/kitmanager.h> #include <projectexplorer/projectexplorerconstants.h> @@ -53,19 +54,34 @@ using namespace Utils; namespace Python { namespace Internal { -class PythonProjectNode : public ProjectNode +class PythonBuildSystem : public BuildSystem { public: - PythonProjectNode(PythonProject *project); + explicit PythonBuildSystem(Project *project); + + bool supportsAction(Node *context, ProjectAction action, const Node *node) const override; + bool addFiles(Node *, const QStringList &filePaths, QStringList *) override; + RemovedFilesFromProject removeFiles(Node *, const QStringList &filePaths, QStringList *) override; + bool deleteFiles(Node *, const QStringList &) override; + bool renameFile(Node *, const QString &filePath, const QString &newFilePath) override; + + bool saveRawFileList(const QStringList &rawFileList); + bool saveRawList(const QStringList &rawList, const QString &fileName); + void parse(); + QStringList processEntries(const QStringList &paths, + QHash<QString, QString> *map = nullptr) const; - bool supportsAction(ProjectAction action, const Node *node) const override; - bool addFiles(const QStringList &filePaths, QStringList *) override; - RemovedFilesFromProject removeFiles(const QStringList &filePaths, QStringList *) override; - bool deleteFiles(const QStringList &) override; - bool renameFile(const QString &filePath, const QString &newFilePath) override; + bool writePyProjectFile(const QString &fileName, QString &content, + const QStringList &rawList, QString *errorMessage); + + void refresh(); private: - PythonProject *m_project; + PythonProject *project() const; + + QStringList m_rawFileList; + QStringList m_files; + QHash<QString, QString> m_rawListEntries; }; @@ -156,6 +172,17 @@ static QStringList readLinesJson(const FilePath &projectFile, QString *errorMess return lines; } +class PythonProjectNode : public ProjectNode +{ +public: + PythonProjectNode(const Utils::FilePath &path) + : ProjectNode(path) + { + setDisplayName(path.toFileInfo().completeBaseName()); + setAddFileFilter("*.py"); + } +}; + PythonProject::PythonProject(const FilePath &fileName) : Project(Constants::C_PY_MIMETYPE, fileName) { @@ -164,18 +191,18 @@ PythonProject::PythonProject(const FilePath &fileName) setDisplayName(fileName.toFileInfo().completeBaseName()); setNeedsBuildConfigurations(false); - - connect(this, &PythonProject::projectFileIsDirty, this, [this]() { refresh(); }); + setBuildSystemCreator([](Project *p) { return new PythonBuildSystem(p); }); } -void PythonProject::refresh(Target *target) +void PythonBuildSystem::refresh() { - ParseGuard guard = guardParsingRun(); - parseProject(); + Project::ParseGuard guard = project()->guardParsingRun(); + parse(); const QDir baseDir(projectDirectory().toString()); QList<BuildTargetInfo> appTargets; - auto newRoot = std::make_unique<PythonProjectNode>(this); + + auto newRoot = std::make_unique<PythonProjectNode>(projectDirectory()); for (const QString &f : qAsConst(m_files)) { const QString displayName = baseDir.relativeFilePath(f); const FileType fileType = f.endsWith(".pyproject") || f.endsWith(".pyqtc") ? FileType::Project @@ -190,24 +217,22 @@ void PythonProject::refresh(Target *target) appTargets.append(bti); } } - setRootProjectNode(std::move(newRoot)); + project()->setRootProjectNode(std::move(newRoot)); - if (!target) - target = activeTarget(); - if (target) + if (Target *target = project()->activeTarget()) target->setApplicationTargets(appTargets); guard.markAsSuccess(); } -bool PythonProject::saveRawFileList(const QStringList &rawFileList) +bool PythonBuildSystem::saveRawFileList(const QStringList &rawFileList) { const bool result = saveRawList(rawFileList, projectFilePath().toString()); // refresh(PythonProject::Files); return result; } -bool PythonProject::saveRawList(const QStringList &rawList, const QString &fileName) +bool PythonBuildSystem::saveRawList(const QStringList &rawList, const QString &fileName) { FileChangeBlocker changeGuarg(fileName); bool result = false; @@ -238,7 +263,7 @@ bool PythonProject::saveRawList(const QStringList &rawList, const QString &fileN return result; } -bool PythonProject::writePyProjectFile(const QString &fileName, QString &content, +bool PythonBuildSystem::writePyProjectFile(const QString &fileName, QString &content, const QStringList &rawList, QString *errorMessage) { QFile file(fileName); @@ -265,7 +290,7 @@ bool PythonProject::writePyProjectFile(const QString &fileName, QString &content return true; } -bool PythonProject::addFiles(const QStringList &filePaths) +bool PythonBuildSystem::addFiles(Node *, const QStringList &filePaths, QStringList *) { QStringList newList = m_rawFileList; @@ -276,7 +301,7 @@ bool PythonProject::addFiles(const QStringList &filePaths) return saveRawFileList(newList); } -bool PythonProject::removeFiles(const QStringList &filePaths) +RemovedFilesFromProject PythonBuildSystem::removeFiles(Node *, const QStringList &filePaths, QStringList *) { QStringList newList = m_rawFileList; @@ -286,10 +311,17 @@ bool PythonProject::removeFiles(const QStringList &filePaths) newList.removeOne(i.value()); } - return saveRawFileList(newList); + bool res = saveRawFileList(newList); + + return res ? RemovedFilesFromProject::Ok : RemovedFilesFromProject::Error; } -bool PythonProject::renameFile(const QString &filePath, const QString &newFilePath) +bool PythonBuildSystem::deleteFiles(Node *, const QStringList &) +{ + return true; +} + +bool PythonBuildSystem::renameFile(Node *, const QString &filePath, const QString &newFilePath) { QStringList newList = m_rawFileList; @@ -305,7 +337,7 @@ bool PythonProject::renameFile(const QString &filePath, const QString &newFilePa return saveRawFileList(newList); } -void PythonProject::parseProject() +void PythonBuildSystem::parse() { m_rawListEntries.clear(); const FilePath filePath = projectFilePath(); @@ -323,6 +355,7 @@ void PythonProject::parseProject() m_files = processEntries(m_rawFileList, &m_rawListEntries); } + /** * Expands environment variables in the given \a string when they are written * like $$(VARIABLE). @@ -349,7 +382,7 @@ static void expandEnvironmentVariables(const QProcessEnvironment &env, QString & * The \a map variable is an optional argument that will map the returned * absolute paths back to their original \a paths. */ -QStringList PythonProject::processEntries(const QStringList &paths, +QStringList PythonBuildSystem::processEntries(const QStringList &paths, QHash<QString, QString> *map) const { const QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); @@ -382,10 +415,11 @@ Project::RestoreResult PythonProject::fromMap(const QVariantMap &map, QString *e { Project::RestoreResult res = Project::fromMap(map, errorMessage); if (res == RestoreResult::Ok) { - refresh(); - if (!activeTarget()) addTargetForDefaultKit(); + + if (auto bs = dynamic_cast<PythonBuildSystem *>(buildSystem())) + bs->refresh(); } return res; @@ -393,19 +427,20 @@ Project::RestoreResult PythonProject::fromMap(const QVariantMap &map, QString *e bool PythonProject::setupTarget(Target *t) { - refresh(t); - return Project::setupTarget(t); + bool res = Project::setupTarget(t); + if (auto bs = dynamic_cast<PythonBuildSystem *>(buildSystem())) + QTimer::singleShot(0, bs, &PythonBuildSystem::refresh); + return res; } -PythonProjectNode::PythonProjectNode(PythonProject *project) - : ProjectNode(project->projectDirectory()) - , m_project(project) +PythonBuildSystem::PythonBuildSystem(Project *project) + : BuildSystem(project) { - setDisplayName(project->projectFilePath().toFileInfo().completeBaseName()); - setAddFileFilter("*.py"); + connect(project, &Project::projectFileIsDirty, this, [this]() { refresh(); }); + QTimer::singleShot(0, this, &PythonBuildSystem::refresh); } -bool PythonProjectNode::supportsAction(ProjectAction action, const Node *node) const +bool PythonBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const { if (node->asFileNode()) { return action == ProjectAction::Rename @@ -416,28 +451,12 @@ bool PythonProjectNode::supportsAction(ProjectAction action, const Node *node) c || action == ProjectAction::RemoveFile || action == ProjectAction::AddExistingFile; } - return ProjectNode::supportsAction(action, node); -} - -bool PythonProjectNode::addFiles(const QStringList &filePaths, QStringList *) -{ - return m_project->addFiles(filePaths); -} - -RemovedFilesFromProject PythonProjectNode::removeFiles(const QStringList &filePaths, QStringList *) -{ - return m_project->removeFiles(filePaths) ? RemovedFilesFromProject::Ok - : RemovedFilesFromProject::Error; -} - -bool PythonProjectNode::deleteFiles(const QStringList &) -{ - return true; + return BuildSystem::supportsAction(context, action, node); } -bool PythonProjectNode::renameFile(const QString &filePath, const QString &newFilePath) +PythonProject *PythonBuildSystem::project() const { - return m_project->renameFile(filePath, newFilePath); + return static_cast<PythonProject *>(BuildSystem::project()); } } // namespace Internal diff --git a/src/plugins/python/pythonproject.h b/src/plugins/python/pythonproject.h index 6f2d4b6d73..d030c92dcd 100644 --- a/src/plugins/python/pythonproject.h +++ b/src/plugins/python/pythonproject.h @@ -40,29 +40,10 @@ class PythonProject : public ProjectExplorer::Project public: explicit PythonProject(const Utils::FilePath &filename); - bool addFiles(const QStringList &filePaths); - bool removeFiles(const QStringList &filePaths); - bool renameFile(const QString &filePath, const QString &newFilePath); - void refresh(ProjectExplorer::Target *target = nullptr); - bool needsConfiguration() const final { return false; } - - bool writePyProjectFile(const QString &fileName, QString &content, - const QStringList &rawList, QString *errorMessage); - private: RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override; bool setupTarget(ProjectExplorer::Target *t) override; - - bool saveRawFileList(const QStringList &rawFileList); - bool saveRawList(const QStringList &rawList, const QString &fileName); - void parseProject(); - QStringList processEntries(const QStringList &paths, - QHash<QString, QString> *map = nullptr) const; - - QStringList m_rawFileList; - QStringList m_files; - QHash<QString, QString> m_rawListEntries; }; } // namespace Internal diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp index d6bc6061e1..41386ef611 100644 --- a/src/plugins/python/pythonrunconfiguration.cpp +++ b/src/plugins/python/pythonrunconfiguration.cpp @@ -157,7 +157,7 @@ public: void fromMap(const QVariantMap &) override; void toMap(QVariantMap &) const override; - void addToConfigurationLayout(QFormLayout *layout) override; + void addToLayout(LayoutBuilder &builder) override; private: void updateCurrentInterpreter(); @@ -190,26 +190,23 @@ void InterpreterAspect::toMap(QVariantMap &map) const map.insert(settingsKey(), m_currentId); } -void InterpreterAspect::addToConfigurationLayout(QFormLayout *layout) +void InterpreterAspect::addToLayout(LayoutBuilder &builder) { if (QTC_GUARD(m_comboBox.isNull())) m_comboBox = new QComboBox; updateComboBox(); - connect(m_comboBox, - &QComboBox::currentTextChanged, - this, - &InterpreterAspect::updateCurrentInterpreter); + connect(m_comboBox, &QComboBox::currentTextChanged, + this, &InterpreterAspect::updateCurrentInterpreter); auto manageButton = new QPushButton(tr("Manage...")); connect(manageButton, &QPushButton::clicked, []() { Core::ICore::showOptionsDialog(Constants::C_PYTHONOPTIONS_PAGE_ID); }); - auto rowLayout = new QHBoxLayout; - rowLayout->addWidget(m_comboBox); - rowLayout->addWidget(manageButton); - layout->addRow(tr("Interpreter"), rowLayout); + builder.addItem(tr("Interpreter")); + builder.addItem(m_comboBox.data()); + builder.addItem(manageButton); } void InterpreterAspect::updateCurrentInterpreter() diff --git a/src/plugins/qbsprojectmanager/qbsnodes.cpp b/src/plugins/qbsprojectmanager/qbsnodes.cpp index 4a7f5fa541..002ebe77fb 100644 --- a/src/plugins/qbsprojectmanager/qbsnodes.cpp +++ b/src/plugins/qbsprojectmanager/qbsnodes.cpp @@ -236,72 +236,6 @@ QbsGroupNode::QbsGroupNode(const qbs::GroupData &grp, const QString &productPath m_qbsGroupData = grp; } -bool QbsGroupNode::supportsAction(ProjectAction action, const Node *node) const -{ - if (action == AddNewFile || action == AddExistingFile) - return true; - - return supportsNodeAction(action, node); -} - -bool QbsGroupNode::addFiles(const QStringList &filePaths, QStringList *notAdded) -{ - QStringList notAddedDummy; - if (!notAdded) - notAdded = ¬AddedDummy; - - const QbsProjectNode *prjNode = parentQbsProjectNode(this); - if (!prjNode || !prjNode->qbsProject().isValid()) { - *notAdded += filePaths; - return false; - } - - const QbsProductNode *prdNode = parentQbsProductNode(this); - if (!prdNode || !prdNode->qbsProductData().isValid()) { - *notAdded += filePaths; - return false; - } - - return prjNode->project()->addFilesToProduct(filePaths, prdNode->qbsProductData(), - m_qbsGroupData, notAdded); -} - -RemovedFilesFromProject QbsGroupNode::removeFiles(const QStringList &filePaths, - QStringList *notRemoved) -{ - QStringList notRemovedDummy; - if (!notRemoved) - notRemoved = ¬RemovedDummy; - - const QbsProjectNode *prjNode = parentQbsProjectNode(this); - if (!prjNode || !prjNode->qbsProject().isValid()) { - *notRemoved += filePaths; - return RemovedFilesFromProject::Error; - } - - const QbsProductNode *prdNode = parentQbsProductNode(this); - if (!prdNode || !prdNode->qbsProductData().isValid()) { - *notRemoved += filePaths; - return RemovedFilesFromProject::Error; - } - - return prjNode->project()->removeFilesFromProduct(filePaths, prdNode->qbsProductData(), - m_qbsGroupData, notRemoved); -} - -bool QbsGroupNode::renameFile(const QString &filePath, const QString &newFilePath) -{ - const QbsProjectNode *prjNode = parentQbsProjectNode(this); - if (!prjNode || !prjNode->qbsProject().isValid()) - return false; - const QbsProductNode *prdNode = parentQbsProductNode(this); - if (!prdNode || !prdNode->qbsProductData().isValid()) - return false; - - return prjNode->project()->renameFileInProduct(filePath, newFilePath, - prdNode->qbsProductData(), m_qbsGroupData); -} - FolderNode::AddNewInformation QbsGroupNode::addNewInformation(const QStringList &files, Node *context) const { @@ -338,66 +272,6 @@ QbsProductNode::QbsProductNode(const qbs::ProductData &prd) : } } -bool QbsProductNode::supportsAction(ProjectAction action, const Node *node) const -{ - if (action == AddNewFile || action == AddExistingFile) - return true; - - return supportsNodeAction(action, node); -} - -bool QbsProductNode::addFiles(const QStringList &filePaths, QStringList *notAdded) -{ - QStringList notAddedDummy; - if (!notAdded) - notAdded = ¬AddedDummy; - - const QbsProjectNode *prjNode = parentQbsProjectNode(this); - if (!prjNode || !prjNode->qbsProject().isValid()) { - *notAdded += filePaths; - return false; - } - - qbs::GroupData grp = findMainQbsGroup(m_qbsProductData); - if (grp.isValid()) { - return prjNode->project()->addFilesToProduct(filePaths, m_qbsProductData, grp, notAdded); - } - - QTC_ASSERT(false, return false); -} - -RemovedFilesFromProject QbsProductNode::removeFiles(const QStringList &filePaths, - QStringList *notRemoved) -{ - QStringList notRemovedDummy; - if (!notRemoved) - notRemoved = ¬RemovedDummy; - - const QbsProjectNode *prjNode = parentQbsProjectNode(this); - if (!prjNode || !prjNode->qbsProject().isValid()) { - *notRemoved += filePaths; - return RemovedFilesFromProject::Error; - } - - qbs::GroupData grp = findMainQbsGroup(m_qbsProductData); - if (grp.isValid()) { - return prjNode->project()->removeFilesFromProduct(filePaths, m_qbsProductData, grp, - notRemoved); - } - - QTC_ASSERT(false, return RemovedFilesFromProject::Error); -} - -bool QbsProductNode::renameFile(const QString &filePath, const QString &newFilePath) -{ - const QbsProjectNode * prjNode = parentQbsProjectNode(this); - if (!prjNode || !prjNode->qbsProject().isValid()) - return false; - const qbs::GroupData grp = findMainQbsGroup(m_qbsProductData); - QTC_ASSERT(grp.isValid(), return false); - return prjNode->project()->renameFileInProduct(filePath, newFilePath, m_qbsProductData, grp); -} - void QbsProductNode::build() { QbsProjectManagerPlugin::buildNamedProduct(static_cast<QbsProject *>(getProject()), @@ -487,5 +361,151 @@ QbsRootProjectNode::QbsRootProjectNode(QbsProject *project) : m_project(project) { } +// -------------------------------------------------------------------- +// QbsBuildSystem: +// -------------------------------------------------------------------- + +QbsBuildSystem::QbsBuildSystem(Project *project) + : BuildSystem(project) +{ +} + +bool QbsBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const +{ + if (dynamic_cast<QbsGroupNode *>(context)) { + if (action == AddNewFile || action == AddExistingFile) + return true; + } + + if (dynamic_cast<QbsProductNode *>(context)) { + if (action == AddNewFile || action == AddExistingFile) + return true; + } + + return supportsNodeAction(action, node); +} + +bool QbsBuildSystem::addFiles(Node *context, const QStringList &filePaths, QStringList *notAdded) +{ + if (auto n = dynamic_cast<QbsGroupNode *>(context)) { + QStringList notAddedDummy; + if (!notAdded) + notAdded = ¬AddedDummy; + + const QbsProjectNode *prjNode = parentQbsProjectNode(n); + if (!prjNode || !prjNode->qbsProject().isValid()) { + *notAdded += filePaths; + return false; + } + + const QbsProductNode *prdNode = parentQbsProductNode(n); + if (!prdNode || !prdNode->qbsProductData().isValid()) { + *notAdded += filePaths; + return false; + } + + return prjNode->project()->addFilesToProduct(filePaths, prdNode->qbsProductData(), + n->m_qbsGroupData, notAdded); + } + + if (auto n = dynamic_cast<QbsProductNode *>(context)) { + QStringList notAddedDummy; + if (!notAdded) + notAdded = ¬AddedDummy; + + const QbsProjectNode *prjNode = parentQbsProjectNode(n); + if (!prjNode || !prjNode->qbsProject().isValid()) { + *notAdded += filePaths; + return false; + } + + qbs::GroupData grp = findMainQbsGroup(n->qbsProductData()); + if (grp.isValid()) + return prjNode->project()->addFilesToProduct(filePaths, n->qbsProductData(), grp, notAdded); + + QTC_ASSERT(false, return false); + } + + return BuildSystem::addFiles(context, filePaths, notAdded); +} + +RemovedFilesFromProject QbsBuildSystem::removeFiles(Node *context, const QStringList &filePaths, + QStringList *notRemoved) +{ + if (auto n = dynamic_cast<QbsGroupNode *>(context)) { + QStringList notRemovedDummy; + if (!notRemoved) + notRemoved = ¬RemovedDummy; + + const QbsProjectNode *prjNode = parentQbsProjectNode(n); + if (!prjNode || !prjNode->qbsProject().isValid()) { + *notRemoved += filePaths; + return RemovedFilesFromProject::Error; + } + + const QbsProductNode *prdNode = parentQbsProductNode(n); + if (!prdNode || !prdNode->qbsProductData().isValid()) { + *notRemoved += filePaths; + return RemovedFilesFromProject::Error; + } + + return project()->removeFilesFromProduct(filePaths, prdNode->qbsProductData(), + n->m_qbsGroupData, notRemoved); + } + + if (auto n = dynamic_cast<QbsProductNode *>(context)) { + QStringList notRemovedDummy; + if (!notRemoved) + notRemoved = ¬RemovedDummy; + + const QbsProjectNode *prjNode = parentQbsProjectNode(n); + if (!prjNode || !prjNode->qbsProject().isValid()) { + *notRemoved += filePaths; + return RemovedFilesFromProject::Error; + } + + qbs::GroupData grp = findMainQbsGroup(n->qbsProductData()); + if (grp.isValid()) { + return prjNode->project()->removeFilesFromProduct(filePaths, n->qbsProductData(), grp, + notRemoved); + } + + QTC_ASSERT(false, return RemovedFilesFromProject::Error); + } + + return BuildSystem::removeFiles(context, filePaths, notRemoved); +} + +bool QbsBuildSystem::renameFile(Node *context, const QString &filePath, const QString &newFilePath) +{ + if (auto *n = dynamic_cast<QbsGroupNode *>(context)) { + const QbsProjectNode *prjNode = parentQbsProjectNode(n); + if (!prjNode || !prjNode->qbsProject().isValid()) + return false; + const QbsProductNode *prdNode = parentQbsProductNode(n); + if (!prdNode || !prdNode->qbsProductData().isValid()) + return false; + + return project()->renameFileInProduct(filePath, newFilePath, + prdNode->qbsProductData(), n->m_qbsGroupData); + } + + if (auto *n = dynamic_cast<QbsProductNode *>(context)) { + const QbsProjectNode * prjNode = parentQbsProjectNode(n); + if (!prjNode || !prjNode->qbsProject().isValid()) + return false; + const qbs::GroupData grp = findMainQbsGroup(n->qbsProductData()); + QTC_ASSERT(grp.isValid(), return false); + return prjNode->project()->renameFileInProduct(filePath, newFilePath, n->qbsProductData(), grp); + } + + return BuildSystem::renameFile(context, filePath, newFilePath); +} + +QbsProject *QbsBuildSystem::project() const +{ + return static_cast<QbsProject *>(BuildSystem::project()); +} + } // namespace Internal } // namespace QbsProjectManager diff --git a/src/plugins/qbsprojectmanager/qbsnodes.h b/src/plugins/qbsprojectmanager/qbsnodes.h index e31fc2b9b9..a2439dcdb6 100644 --- a/src/plugins/qbsprojectmanager/qbsnodes.h +++ b/src/plugins/qbsprojectmanager/qbsnodes.h @@ -25,6 +25,7 @@ #pragma once +#include <projectexplorer/buildsystem.h> #include <projectexplorer/projectnodes.h> #include <qbs.h> @@ -35,6 +36,26 @@ namespace Internal { class QbsNodeTreeBuilder; class QbsProject; +class QbsBuildSystem : public ProjectExplorer::BuildSystem +{ +public: + explicit QbsBuildSystem(ProjectExplorer::Project *project); + + bool supportsAction(ProjectExplorer::Node *context, + ProjectExplorer::ProjectAction action, + const ProjectExplorer::Node *node) const final; + bool addFiles(ProjectExplorer::Node *context, + const QStringList &filePaths, + QStringList *notAdded = nullptr) override; + ProjectExplorer::RemovedFilesFromProject removeFiles(ProjectExplorer::Node *context, + const QStringList &filePaths, + QStringList *notRemoved = nullptr) override; + bool renameFile(ProjectExplorer::Node *context, + const QString &filePath, const QString &newFilePath) override; + + QbsProject *project() const; +}; + // -------------------------------------------------------------------- // QbsGroupNode: // -------------------------------------------------------------------- @@ -45,13 +66,9 @@ public: QbsGroupNode(const qbs::GroupData &grp, const QString &productPath); bool showInSimpleTree() const final { return false; } - bool supportsAction(ProjectExplorer::ProjectAction action, const Node *node) const final; - bool addFiles(const QStringList &filePaths, QStringList *notAdded = nullptr) override; - ProjectExplorer::RemovedFilesFromProject removeFiles(const QStringList &filePaths, - QStringList *notRemoved = nullptr) override; - bool renameFile(const QString &filePath, const QString &newFilePath) override; private: + friend class QbsBuildSystem; AddNewInformation addNewInformation(const QStringList &files, Node *context) const override; QVariant data(Core::Id role) const override; @@ -68,11 +85,6 @@ class QbsProductNode : public ProjectExplorer::ProjectNode public: explicit QbsProductNode(const qbs::ProductData &prd); - bool supportsAction(ProjectExplorer::ProjectAction action, const Node *node) const final; - bool addFiles(const QStringList &filePaths, QStringList *notAdded = nullptr) override; - ProjectExplorer::RemovedFilesFromProject removeFiles(const QStringList &filePaths, - QStringList *notRemoved = nullptr) override; - bool renameFile(const QString &filePath, const QString &newFilePath) override; void build() override; QStringList targetApplications() const override; diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 37e94751ff..ade70195c9 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -135,6 +135,8 @@ QbsProject::QbsProject(const FilePath &fileName) setProjectLanguages(Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); setCanBuildProducts(); + setBuildSystemCreator([](Project *p) { return new QbsBuildSystem(p); }); + rebuildProjectTree(); connect(this, &Project::activeTargetChanged, this, &QbsProject::changeActiveTarget); diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index c2a15c9eaf..59c650e675 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -82,67 +82,76 @@ QmakeProFileNode *QmakePriFileNode::proFileNode() const return m_qmakeProFileNode; } -bool QmakePriFileNode::supportsAction(ProjectAction action, const Node *node) const +bool QmakeBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const { - if (action == Rename) { - const FileNode *fileNode = node->asFileNode(); - return (fileNode && fileNode->fileType() != FileType::Project) - || dynamic_cast<const ResourceEditor::ResourceTopLevelNode *>(node); - } + if (auto n = dynamic_cast<QmakePriFileNode *>(context)) { // Covers QmakeProfile, too. + if (action == Rename) { + const FileNode *fileNode = node->asFileNode(); + return (fileNode && fileNode->fileType() != FileType::Project) + || dynamic_cast<const ResourceEditor::ResourceTopLevelNode *>(node); + } - const FolderNode *folderNode = this; - const QmakeProFileNode *proFileNode; - while (!(proFileNode = dynamic_cast<const QmakeProFileNode*>(folderNode))) { - folderNode = folderNode->parentFolderNode(); - QTC_ASSERT(folderNode, return false); - } - QTC_ASSERT(proFileNode, return false); - const QmakeProFile *pro = proFileNode->proFile(); - - switch (pro ? pro->projectType() : ProjectType::Invalid) { - case ProjectType::ApplicationTemplate: - case ProjectType::StaticLibraryTemplate: - case ProjectType::SharedLibraryTemplate: - case ProjectType::AuxTemplate: { - // TODO: Some of the file types don't make much sense for aux - // projects (e.g. cpp). It'd be nice if the "add" action could - // work on a subset of the file types according to project type. - if (action == AddNewFile) - return true; - if (action == EraseFile) - return pro && pro->knowsFile(node->filePath()); - if (action == RemoveFile) - return !(pro && pro->knowsFile(node->filePath())); - - bool addExistingFiles = true; - if (node->isVirtualFolderType()) { - // A virtual folder, we do what the projectexplorer does - const FolderNode *folder = node->asFolderNode(); - if (folder) { - QStringList list; - foreach (FolderNode *f, folder->folderNodes()) - list << f->filePath().toString() + QLatin1Char('/'); - if (deploysFolder(Utils::commonPath(list))) - addExistingFiles = false; - } + const FolderNode *folderNode = n; + const QmakeProFileNode *proFileNode; + while (!(proFileNode = dynamic_cast<const QmakeProFileNode*>(folderNode))) { + folderNode = folderNode->parentFolderNode(); + QTC_ASSERT(folderNode, return false); } + QTC_ASSERT(proFileNode, return false); + const QmakeProFile *pro = proFileNode->proFile(); + + switch (pro ? pro->projectType() : ProjectType::Invalid) { + case ProjectType::ApplicationTemplate: + case ProjectType::StaticLibraryTemplate: + case ProjectType::SharedLibraryTemplate: + case ProjectType::AuxTemplate: { + // TODO: Some of the file types don't make much sense for aux + // projects (e.g. cpp). It'd be nice if the "add" action could + // work on a subset of the file types according to project type. + if (action == AddNewFile) + return true; + if (action == EraseFile) + return pro && pro->knowsFile(node->filePath()); + if (action == RemoveFile) + return !(pro && pro->knowsFile(node->filePath())); + + bool addExistingFiles = true; + if (node->isVirtualFolderType()) { + // A virtual folder, we do what the projectexplorer does + const FolderNode *folder = node->asFolderNode(); + if (folder) { + QStringList list; + foreach (FolderNode *f, folder->folderNodes()) + list << f->filePath().toString() + QLatin1Char('/'); + if (n->deploysFolder(Utils::commonPath(list))) + addExistingFiles = false; + } + } - addExistingFiles = addExistingFiles && !deploysFolder(node->filePath().toString()); + addExistingFiles = addExistingFiles && !n->deploysFolder(node->filePath().toString()); - if (action == AddExistingFile || action == AddExistingDirectory) - return addExistingFiles; + if (action == AddExistingFile || action == AddExistingDirectory) + return addExistingFiles; - break; + break; + } + case ProjectType::SubDirsTemplate: + if (action == AddSubProject || action == AddExistingProject) + return true; + break; + default: + break; + } + + return false; } - case ProjectType::SubDirsTemplate: - if (action == AddSubProject || action == AddExistingProject) - return true; - break; - default: - break; + + if (auto n = dynamic_cast<QmakeProFileNode *>(context)) { + if (action == RemoveSubProject) + return n->parentProjectNode() && !n->parentProjectNode()->asContainerNode(); } - return false; + return BuildSystem::supportsAction(context, action, node); } bool QmakePriFileNode::canAddSubProject(const QString &proFilePath) const @@ -168,80 +177,104 @@ QStringList QmakePriFileNode::subProjectFileNamePatterns() const return QStringList("*.pro"); } -bool QmakePriFileNode::addFiles(const QStringList &filePaths, QStringList *notAdded) -{ - QmakePriFile *pri = priFile(); - if (!pri) - return false; - QList<Node *> matchingNodes = findNodes([filePaths](const Node *n) { - return n->asFileNode() && filePaths.contains(n->filePath().toString()); - }); - matchingNodes = filtered(matchingNodes, [](const Node *n) { - for (const Node *parent = n->parentFolderNode(); parent; - parent = parent->parentFolderNode()) { - if (dynamic_cast<const ResourceEditor::ResourceTopLevelNode *>(parent)) - return false; - } - return true; - }); - QStringList alreadyPresentFiles = transform<QStringList>(matchingNodes, - [](const Node *n) { return n->filePath().toString(); }); - alreadyPresentFiles.removeDuplicates(); - QStringList actualFilePaths = filePaths; - for (const QString &e : alreadyPresentFiles) - actualFilePaths.removeOne(e); - if (notAdded) - *notAdded = alreadyPresentFiles; - return pri->addFiles(actualFilePaths, notAdded); -} - -RemovedFilesFromProject QmakePriFileNode::removeFiles(const QStringList &filePaths, +bool QmakeBuildSystem::addFiles(Node *context, const QStringList &filePaths, QStringList *notAdded) +{ + if (auto n = dynamic_cast<QmakePriFileNode *>(context)) { + QmakePriFile *pri = n->priFile(); + if (!pri) + return false; + QList<Node *> matchingNodes = n->findNodes([filePaths](const Node *nn) { + return nn->asFileNode() && filePaths.contains(nn->filePath().toString()); + }); + matchingNodes = filtered(matchingNodes, [](const Node *n) { + for (const Node *parent = n->parentFolderNode(); parent; + parent = parent->parentFolderNode()) { + if (dynamic_cast<const ResourceEditor::ResourceTopLevelNode *>(parent)) + return false; + } + return true; + }); + QStringList alreadyPresentFiles = transform<QStringList>(matchingNodes, + [](const Node *n) { return n->filePath().toString(); }); + alreadyPresentFiles.removeDuplicates(); + QStringList actualFilePaths = filePaths; + for (const QString &e : alreadyPresentFiles) + actualFilePaths.removeOne(e); + if (notAdded) + *notAdded = alreadyPresentFiles; + return pri->addFiles(actualFilePaths, notAdded); + } + + return BuildSystem::addFiles(context, filePaths, notAdded); +} + +RemovedFilesFromProject QmakeBuildSystem::removeFiles(Node *context, const QStringList &filePaths, QStringList *notRemoved) { - QmakePriFile * const pri = priFile(); - if (!pri) - return RemovedFilesFromProject::Error; - QStringList wildcardFiles; - QStringList nonWildcardFiles; - for (const QString &file : filePaths) { - if (pri->proFile()->isFileFromWildcard(file)) - wildcardFiles << file; - else - nonWildcardFiles << file; + if (auto n = dynamic_cast<QmakePriFileNode *>(context)) { + QmakePriFile * const pri = n->priFile(); + if (!pri) + return RemovedFilesFromProject::Error; + QStringList wildcardFiles; + QStringList nonWildcardFiles; + for (const QString &file : filePaths) { + if (pri->proFile()->isFileFromWildcard(file)) + wildcardFiles << file; + else + nonWildcardFiles << file; + } + const bool success = pri->removeFiles(nonWildcardFiles, notRemoved); + if (notRemoved) + *notRemoved += wildcardFiles; + if (!success) + return RemovedFilesFromProject::Error; + if (!wildcardFiles.isEmpty()) + return RemovedFilesFromProject::Wildcard; + return RemovedFilesFromProject::Ok; } - const bool success = pri->removeFiles(nonWildcardFiles, notRemoved); - if (notRemoved) - *notRemoved += wildcardFiles; - if (!success) - return RemovedFilesFromProject::Error; - if (!wildcardFiles.isEmpty()) - return RemovedFilesFromProject::Wildcard; - return RemovedFilesFromProject::Ok; + + return BuildSystem::removeFiles(context, filePaths, notRemoved); } -bool QmakePriFileNode::deleteFiles(const QStringList &filePaths) +bool QmakeBuildSystem::deleteFiles(Node *context, const QStringList &filePaths) { - QmakePriFile *pri = priFile(); - return pri ? pri->deleteFiles(filePaths) : false; + if (auto n = dynamic_cast<QmakePriFileNode *>(context)) { + QmakePriFile *pri = n->priFile(); + return pri ? pri->deleteFiles(filePaths) : false; + } + + return BuildSystem::deleteFiles(context, filePaths); } -bool QmakePriFileNode::canRenameFile(const QString &filePath, const QString &newFilePath) +bool QmakeBuildSystem::canRenameFile(Node *context, const QString &filePath, const QString &newFilePath) { - QmakePriFile *pri = priFile(); - return pri ? pri->canRenameFile(filePath, newFilePath) : false; + if (auto n = dynamic_cast<QmakePriFileNode *>(context)) { + QmakePriFile *pri = n->priFile(); + return pri ? pri->canRenameFile(filePath, newFilePath) : false; + } + + return BuildSystem::canRenameFile(context, filePath, newFilePath); } -bool QmakePriFileNode::renameFile(const QString &filePath, const QString &newFilePath) +bool QmakeBuildSystem::renameFile(Node *context, const QString &filePath, const QString &newFilePath) { - QmakePriFile *pri = priFile(); - return pri ? pri->renameFile(filePath, newFilePath) : false; + if (auto n = dynamic_cast<QmakePriFileNode *>(context)) { + QmakePriFile *pri = n->priFile(); + return pri ? pri->renameFile(filePath, newFilePath) : false; + } + + return BuildSystem::renameFile(context, filePath, newFilePath); } -bool QmakePriFileNode::addDependencies(const QStringList &dependencies) +bool QmakeBuildSystem::addDependencies(Node *context, const QStringList &dependencies) { - if (QmakePriFile * const pri = priFile()) - return pri->addDependencies(dependencies); - return false; + if (auto n = dynamic_cast<QmakePriFileNode *>(context)) { + if (QmakePriFile * const pri = n->priFile()) + return pri->addDependencies(dependencies); + return false; + } + + return BuildSystem::addDependencies(context, dependencies); } FolderNode::AddNewInformation QmakePriFileNode::addNewInformation(const QStringList &files, Node *context) const @@ -405,13 +438,6 @@ bool QmakeProFileNode::includedInExactParse() const return pro && pro->includedInExactParse(); } -bool QmakeProFileNode::supportsAction(ProjectAction action, const Node *node) const -{ - if (action == RemoveSubProject) - return parentProjectNode() && !parentProjectNode()->asContainerNode(); - return QmakePriFileNode::supportsAction(action, node); -} - FolderNode::AddNewInformation QmakeProFileNode::addNewInformation(const QStringList &files, Node *context) const { Q_UNUSED(files) @@ -474,4 +500,9 @@ TargetInformation QmakeProFileNode::targetInformation() const return proFile() ? proFile()->targetInformation() : TargetInformation(); } +QmakeBuildSystem::QmakeBuildSystem(Project *project) + : BuildSystem(project) +{ +} + } // namespace QmakeProjectManager diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.h b/src/plugins/qmakeprojectmanager/qmakenodes.h index 7d9138615e..473f400620 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.h +++ b/src/plugins/qmakeprojectmanager/qmakenodes.h @@ -28,6 +28,7 @@ #include "qmakeprojectmanager_global.h" #include "qmakeparsernodes.h" +#include <projectexplorer/buildsystem.h> #include <projectexplorer/projectnodes.h> namespace Utils { class FilePath; } @@ -36,6 +37,31 @@ namespace QmakeProjectManager { class QmakeProFileNode; class QmakeProject; +class QmakeBuildSystem : public ProjectExplorer::BuildSystem +{ +public: + explicit QmakeBuildSystem(ProjectExplorer::Project *project); + + bool supportsAction(ProjectExplorer::Node *context, + ProjectExplorer::ProjectAction action, + const ProjectExplorer::Node *node) const override; + + bool addFiles(ProjectExplorer::Node *context, + const QStringList &filePaths, + QStringList *notAdded = nullptr) override; + ProjectExplorer::RemovedFilesFromProject removeFiles(ProjectExplorer::Node *context, + const QStringList &filePaths, + QStringList *notRemoved = nullptr) override; + bool deleteFiles(ProjectExplorer::Node *context, + const QStringList &filePaths) override; + bool canRenameFile(ProjectExplorer::Node *context, + const QString &filePath, const QString &newFilePath) override; + bool renameFile(ProjectExplorer::Node *context, + const QString &filePath, const QString &newFilePath) override; + bool addDependencies(ProjectExplorer::Node *context, + const QStringList &dependencies) override; +}; + // Implements ProjectNode for qmake .pri files class QMAKEPROJECTMANAGER_EXPORT QmakePriFileNode : public ProjectExplorer::ProjectNode { @@ -45,9 +71,6 @@ public: QmakePriFile *priFile() const; - // ProjectNode interface - bool supportsAction(ProjectExplorer::ProjectAction action, const Node *node) const override; - bool showInSimpleTree() const override { return false; } bool canAddSubProject(const QString &proFilePath) const override; @@ -55,13 +78,6 @@ public: bool removeSubProject(const QString &proFilePath) override; QStringList subProjectFileNamePatterns() const override; - bool addFiles(const QStringList &filePaths, QStringList *notAdded = nullptr) override; - ProjectExplorer::RemovedFilesFromProject removeFiles(const QStringList &filePaths, - QStringList *notRemoved = nullptr) override; - bool deleteFiles(const QStringList &filePaths) override; - bool canRenameFile(const QString &filePath, const QString &newFilePath) override; - bool renameFile(const QString &filePath, const QString &newFilePath) override; - bool addDependencies(const QStringList &dependencies) override; AddNewInformation addNewInformation(const QStringList &files, Node *context) const override; bool deploysFolder(const QString &folder) const override; @@ -92,7 +108,6 @@ public: bool isQtcRunnable() const; bool includedInExactParse() const; - bool supportsAction(ProjectExplorer::ProjectAction action, const Node *node) const override; bool showInSimpleTree() const override; QString buildKey() const override; diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 2865841453..01916251c7 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -145,6 +145,7 @@ QmakeProject::QmakeProject(const FilePath &fileName) : this, &QmakeProject::buildFinished); setPreferredKitPredicate([this](const Kit *kit) -> bool { return matchesKit(kit); }); + setBuildSystemCreator([](Project *p) { return new QmakeBuildSystem(p); }); } QmakeProject::~QmakeProject() @@ -476,8 +477,8 @@ void QmakeProject::decrementPendingEvaluateFutures() // After being done, we need to call: m_asyncUpdateState = Base; - updateCodeModels(); updateBuildSystemData(); + updateCodeModels(); if (activeTarget()) activeTarget()->updateDefaultDeployConfigurations(); m_guard.markAsSuccess(); // Qmake always returns (some) data, even when it failed:-) diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectconfigwidget.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectconfigwidget.cpp index 962fd13b31..7949d21f72 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectconfigwidget.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectconfigwidget.cpp @@ -54,7 +54,7 @@ static bool isShadowBuild(BuildConfiguration *bc) } QmakeProjectConfigWidget::QmakeProjectConfigWidget(QmakeBuildConfiguration *bc) - : NamedWidget(), + : NamedWidget(tr("General")), m_buildConfiguration(bc) { Project *project = bc->target()->project(); @@ -164,8 +164,6 @@ QmakeProjectConfigWidget::QmakeProjectConfigWidget(QmakeBuildConfiguration *bc) connect(m_buildConfiguration, &QmakeBuildConfiguration::qmakeBuildConfigurationChanged, this, &QmakeProjectConfigWidget::updateProblemLabel); - setDisplayName(tr("General")); - updateDetails(); updateProblemLabel(); } diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp index 4f23154945..5adc18347c 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp @@ -76,7 +76,7 @@ DesignDocument::DesignDocument(QObject *parent) : m_subComponentManager(new SubComponentManager(m_documentModel.data(), this)), m_rewriterView (new RewriterView(RewriterView::Amend, m_documentModel.data())), m_documentLoaded(false), - m_currentKit(nullptr) + m_currentTarget(nullptr) { } @@ -216,9 +216,9 @@ Utils::FilePath DesignDocument::fileName() const return Utils::FilePath(); } -Kit *DesignDocument::currentKit() const +ProjectExplorer::Target *DesignDocument::currentTarget() const { - return m_currentKit; + return m_currentTarget; } bool DesignDocument::isDocumentLoaded() const @@ -551,8 +551,8 @@ void DesignDocument::setEditor(Core::IEditor *editor) connect(editor->document(), &Core::IDocument::filePathChanged, this, &DesignDocument::updateFileName); - updateActiveQtVersion(); - updateCurrentProject(); + updateActiveTarget(); + updateActiveTarget(); } Core::IEditor *DesignDocument::editor() const @@ -594,53 +594,38 @@ void DesignDocument::redo() viewManager().resetPropertyEditorView(); } -static inline Kit *getActiveKit(DesignDocument *designDocument) +static Target *getActiveTarget(DesignDocument *designDocument) { - ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::projectForFile(designDocument->fileName()); + Project *currentProject = SessionManager::projectForFile(designDocument->fileName()); if (!currentProject) - currentProject = ProjectExplorer::ProjectTree::currentProject(); + currentProject = ProjectTree::currentProject(); if (!currentProject) return nullptr; QObject::connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, - designDocument, &DesignDocument::updateActiveQtVersion, Qt::UniqueConnection); + designDocument, &DesignDocument::updateActiveTarget, Qt::UniqueConnection); QObject::connect(currentProject, &Project::activeTargetChanged, - designDocument, &DesignDocument::updateActiveQtVersion, Qt::UniqueConnection); - - QObject::connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, - designDocument, &DesignDocument::updateCurrentProject, Qt::UniqueConnection); - - QObject::connect(currentProject, &Project::activeTargetChanged, - designDocument, &DesignDocument::updateCurrentProject, Qt::UniqueConnection); - + designDocument, &DesignDocument::updateActiveTarget, Qt::UniqueConnection); Target *target = currentProject->activeTarget(); - if (!target) + if (!target || !target->kit()->isValid()) return nullptr; - if (!target->kit() || !target->kit()->isValid()) - return nullptr; QObject::connect(target, &Target::kitChanged, - designDocument, &DesignDocument::updateActiveQtVersion, Qt::UniqueConnection); + designDocument, &DesignDocument::updateActiveTarget, Qt::UniqueConnection); - return target->kit(); + return target; } -void DesignDocument::updateActiveQtVersion() +void DesignDocument::updateActiveTarget() { - m_currentKit = getActiveKit(this); - viewManager().setNodeInstanceViewKit(m_currentKit); -} - -void DesignDocument::updateCurrentProject() -{ - ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::projectForFile(fileName()); - viewManager().setNodeInstanceViewProject(currentProject); + m_currentTarget = getActiveTarget(this); + viewManager().setNodeInstanceViewTarget(m_currentTarget); } void DesignDocument::contextHelp(const Core::IContext::HelpCallback &callback) const diff --git a/src/plugins/qmldesigner/components/integration/designdocument.h b/src/plugins/qmldesigner/components/integration/designdocument.h index eba0cf4060..7e8509eb4d 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.h +++ b/src/plugins/qmldesigner/components/integration/designdocument.h @@ -39,12 +39,11 @@ #include <QStackedWidget> QT_BEGIN_NAMESPACE -class QWidget; class QPlainTextEdit; QT_END_NAMESPACE namespace ProjectExplorer { -class Kit; +class Target; } namespace QmlDesigner { @@ -91,7 +90,7 @@ public: TextEditor::BaseTextEditor *textEditor() const; QPlainTextEdit *plainTextEdit() const; Utils::FilePath fileName() const; - ProjectExplorer::Kit *currentKit() const; + ProjectExplorer::Target *currentTarget() const; bool isDocumentLoaded() const; void resetToDocumentModel(); @@ -115,8 +114,7 @@ public: void selectAll(); void undo(); void redo(); - void updateActiveQtVersion(); - void updateCurrentProject(); + void updateActiveTarget(); void changeToSubComponent(const ModelNode &componentNode); void changeToMaster(); @@ -152,7 +150,7 @@ private: // variables QScopedPointer<RewriterView> m_rewriterView; bool m_documentLoaded; - ProjectExplorer::Kit *m_currentKit; + ProjectExplorer::Target *m_currentTarget; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index a2aa30f40a..ba2f6b283c 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -40,16 +40,8 @@ #include <QRectF> #include <QTime> -QT_BEGIN_NAMESPACE -class QDeclarativeEngine; -class QGraphicsView; -class QFileSystemWatcher; -class QPainter; -QT_END_NAMESPACE - namespace ProjectExplorer { -class Kit; -class Project; +class Target; } namespace QmlDesigner { @@ -131,8 +123,7 @@ public: QImage statePreviewImage(const ModelNode &stateNode) const; - void setKit(ProjectExplorer::Kit *kit); - void setProject(ProjectExplorer::Project *project); + void setTarget(ProjectExplorer::Target *newTarget); void sendToken(const QString &token, int number, const QVector<ModelNode> &nodeVector); @@ -208,8 +199,7 @@ private: //variables QImage m_baseStatePreviewImage; QElapsedTimer m_lastCrashTime; NodeInstanceServerInterface::RunModus m_runModus; - ProjectExplorer::Kit *m_currentKit = nullptr; - ProjectExplorer::Project *m_currentProject = nullptr; + ProjectExplorer::Target *m_currentTarget = nullptr; int m_restartProcessTimerId; RewriterTransaction m_puppetTransaction; }; diff --git a/src/plugins/qmldesigner/designercore/include/viewmanager.h b/src/plugins/qmldesigner/designercore/include/viewmanager.h index 71c869916e..8f1ccbfe08 100644 --- a/src/plugins/qmldesigner/designercore/include/viewmanager.h +++ b/src/plugins/qmldesigner/designercore/include/viewmanager.h @@ -32,8 +32,7 @@ #include <utils/fileutils.h> namespace ProjectExplorer { -class Kit; -class Project; +class Target; } namespace QmlDesigner { @@ -66,8 +65,7 @@ public: void setItemLibraryViewResourcePath(const QString &resourcePath); void setComponentNode(const ModelNode &componentNode); void setComponentViewToMaster(); - void setNodeInstanceViewKit(ProjectExplorer::Kit *kit); - void setNodeInstanceViewProject(ProjectExplorer::Project *project); + void setNodeInstanceViewTarget(ProjectExplorer::Target *target); void resetPropertyEditorView(); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp index 3d57b3a16a..025402f7bc 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp @@ -103,8 +103,7 @@ void NodeInstanceServerProxy::showCannotConnectToPuppetWarningAndSwitchToEditMod NodeInstanceServerProxy::NodeInstanceServerProxy(NodeInstanceView *nodeInstanceView, RunModus runModus, - ProjectExplorer::Kit *kit, - ProjectExplorer::Project *project) + ProjectExplorer::Target *target) : NodeInstanceServerInterface(nodeInstanceView), m_localServer(new QLocalServer(this)), m_nodeInstanceView(nodeInstanceView), @@ -117,7 +116,7 @@ NodeInstanceServerProxy::NodeInstanceServerProxy(NodeInstanceView *nodeInstanceV m_localServer->listen(socketToken); m_localServer->setMaxPendingConnections(3); - PuppetCreator puppetCreator(kit, project, nodeInstanceView->model()); + PuppetCreator puppetCreator(target, nodeInstanceView->model()); puppetCreator.setQrcMappingString(qrcMappingString()); puppetCreator.createQml2PuppetExecutableIfMissing(); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h index a6a7f6ce99..b79857d925 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h @@ -40,8 +40,7 @@ class QProcess; QT_END_NAMESPACE namespace ProjectExplorer { -class Kit; -class Project; +class Target; } namespace QmlDesigner { @@ -63,8 +62,7 @@ public: explicit NodeInstanceServerProxy(NodeInstanceView *nodeInstanceView, RunModus runModus, - ProjectExplorer::Kit *kit, - ProjectExplorer::Project *project); + ProjectExplorer::Target *target); ~NodeInstanceServerProxy() override; void createInstances(const CreateInstancesCommand &command) override; void changeFileUrl(const ChangeFileUrlCommand &command) override; diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index fd17c83551..899dc5caee 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -123,7 +123,7 @@ NodeInstanceView::~NodeInstanceView() { removeAllInstanceNodeRelationships(); delete nodeInstanceServer(); - m_currentKit = nullptr; + m_currentTarget = nullptr; } //\{ @@ -173,7 +173,7 @@ bool static parentTakesOverRendering(const ModelNode &modelNode) void NodeInstanceView::modelAttached(Model *model) { AbstractView::modelAttached(model); - auto server = new NodeInstanceServerProxy(this, m_runModus, m_currentKit, m_currentProject); + auto server = new NodeInstanceServerProxy(this, m_runModus, m_currentTarget); m_nodeInstanceServer = server; m_lastCrashTime.start(); connect(server, &NodeInstanceServerProxy::processCrashed, this, &NodeInstanceView::handleCrash); @@ -256,7 +256,7 @@ void NodeInstanceView::restartProcess() if (model()) { delete nodeInstanceServer(); - auto server = new NodeInstanceServerProxy(this, m_runModus, m_currentKit, m_currentProject); + auto server = new NodeInstanceServerProxy(this, m_runModus, m_currentTarget); m_nodeInstanceServer = server; connect(server, &NodeInstanceServerProxy::processCrashed, this, &NodeInstanceView::handleCrash); @@ -1304,18 +1304,10 @@ QImage NodeInstanceView::statePreviewImage(const ModelNode &stateNode) const return m_statePreviewImage.value(stateNode); } -void NodeInstanceView::setKit(ProjectExplorer::Kit *newKit) +void NodeInstanceView::setTarget(ProjectExplorer::Target *newTarget) { - if (m_currentKit != newKit) { - m_currentKit = newKit; - restartProcess(); - } -} - -void NodeInstanceView::setProject(ProjectExplorer::Project *project) -{ - if (m_currentProject != project) { - m_currentProject = project; + if (m_currentTarget != newTarget) { + m_currentTarget = newTarget; restartProcess(); } } diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp index adf962c2cc..a577abc3a2 100644 --- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp +++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp @@ -90,7 +90,7 @@ QHash<Core::Id, PuppetCreator::PuppetType> PuppetCreator::m_qml2PuppetForKitPupp QByteArray PuppetCreator::qtHash() const { - QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(m_kit); + QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(m_target->kit()); if (currentQtVersion) { return QCryptographicHash::hash(currentQtVersion->dataPath().toString().toUtf8(), QCryptographicHash::Sha1) @@ -102,7 +102,7 @@ QByteArray PuppetCreator::qtHash() const QDateTime PuppetCreator::qtLastModified() const { - QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(m_kit); + QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(m_target->kit()); if (currentQtVersion) return currentQtVersion->libraryPath().toFileInfo().lastModified(); @@ -140,10 +140,10 @@ QDateTime PuppetCreator::puppetSourceLastModified() const bool PuppetCreator::useOnlyFallbackPuppet() const { #ifndef QMLDESIGNER_TEST - if (!m_kit || !m_kit->isValid()) + if (!m_target || !m_target->kit()->isValid()) qWarning() << "Invalid kit for QML puppet"; - return m_designerSettings.value(DesignerSettingsKey::USE_DEFAULT_PUPPET - ).toBool() || m_kit == nullptr || !m_kit->isValid(); + return m_designerSettings.value(DesignerSettingsKey::USE_DEFAULT_PUPPET).toBool() + || m_target == nullptr || !m_target->kit()->isValid(); #else return true; #endif @@ -152,8 +152,8 @@ bool PuppetCreator::useOnlyFallbackPuppet() const QString PuppetCreator::getStyleConfigFileName() const { #ifndef QMLDESIGNER_TEST - if (m_currentProject) { - for (const Utils::FilePath &fileName : m_currentProject->files(ProjectExplorer::Project::SourceFiles)) { + if (m_target) { + for (const Utils::FilePath &fileName : m_target->project()->files(ProjectExplorer::Project::SourceFiles)) { if (fileName.fileName() == "qtquickcontrols2.conf") return fileName.toString(); } @@ -162,17 +162,14 @@ QString PuppetCreator::getStyleConfigFileName() const return QString(); } -PuppetCreator::PuppetCreator(ProjectExplorer::Kit *kit, - ProjectExplorer::Project *project, - const Model *model) +PuppetCreator::PuppetCreator(ProjectExplorer::Target *target, const Model *model) - : m_kit(kit) + : m_target(target) , m_availablePuppetType(FallbackPuppet) , m_model(model) #ifndef QMLDESIGNER_TEST , m_designerSettings(QmlDesignerPlugin::instance()->settings()) #endif - , m_currentProject(project) { } @@ -330,18 +327,18 @@ void PuppetCreator::createQml2PuppetExecutableIfMissing() if (!useOnlyFallbackPuppet()) { // check if there was an already failing try to get the UserSpacePuppet // -> imagine as result a FallbackPuppet and nothing will happen again - if (m_qml2PuppetForKitPuppetHash.value(m_kit->id(), UserSpacePuppet) == UserSpacePuppet ) { + if (m_qml2PuppetForKitPuppetHash.value(m_target->id(), UserSpacePuppet) == UserSpacePuppet ) { if (checkPuppetIsReady(qml2PuppetPath(UserSpacePuppet))) { m_availablePuppetType = UserSpacePuppet; } else { - if (m_kit->isValid()) { + if (m_target->kit()->isValid()) { bool buildSucceeded = build(qml2PuppetProjectFile()); if (buildSucceeded) m_availablePuppetType = UserSpacePuppet; } else { warnAboutInvalidKit(); } - m_qml2PuppetForKitPuppetHash.insert(m_kit->id(), m_availablePuppetType); + m_qml2PuppetForKitPuppetHash.insert(m_target->id(), m_availablePuppetType); } } } @@ -418,8 +415,8 @@ QProcessEnvironment PuppetCreator::processEnvironment() const static const QString pathSep = Utils::HostOsInfo::pathListSeparator(); Utils::Environment environment = Utils::Environment::systemEnvironment(); if (!useOnlyFallbackPuppet()) - m_kit->addToEnvironment(environment); - const QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(m_kit); + m_target->kit()->addToEnvironment(environment); + const QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(m_target->kit()); if (QTC_GUARD(qt)) { // Kits without a Qt version should not have a puppet! // Update PATH to include QT_HOST_BINS const Utils::FilePath qtBinPath = qt->hostBinPath(); @@ -490,13 +487,11 @@ QProcessEnvironment PuppetCreator::processEnvironment() const QStringList customFileSelectors; - if (m_currentProject && m_currentProject->activeTarget()) { - QStringList designerImports = m_currentProject->activeTarget() - ->additionalData("QmlDesignerImportPath").toStringList(); + if (m_target) { + QStringList designerImports = m_target->additionalData("QmlDesignerImportPath").toStringList(); importPaths.append(designerImports); - customFileSelectors = m_currentProject->activeTarget() - ->additionalData("CustomFileSelectorsData").toStringList(); + customFileSelectors = m_target->additionalData("CustomFileSelectorsData").toStringList(); } if (m_availablePuppetType == FallbackPuppet) @@ -519,10 +514,10 @@ QProcessEnvironment PuppetCreator::processEnvironment() const QString PuppetCreator::buildCommand() const { Utils::Environment environment = Utils::Environment::systemEnvironment(); - m_kit->addToEnvironment(environment); + m_target->kit()->addToEnvironment(environment); ProjectExplorer::ToolChain *toolChain - = ProjectExplorer::ToolChainKitAspect::toolChain(m_kit, + = ProjectExplorer::ToolChainKitAspect::toolChain(m_target->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID); if (toolChain) @@ -533,7 +528,7 @@ QString PuppetCreator::buildCommand() const QString PuppetCreator::qmakeCommand() const { - QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(m_kit); + QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(m_target->kit()); if (currentQtVersion) return currentQtVersion->qmakeCommand().toString(); @@ -620,7 +615,7 @@ static bool nonEarlyQt5Version(const QtSupport::QtVersionNumber ¤tQtVersio bool PuppetCreator::qtIsSupported() const { - QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(m_kit); + QtSupport::BaseQtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(m_target->kit()); return currentQtVersion && currentQtVersion->isValid() diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.h b/src/plugins/qmldesigner/designercore/instances/puppetcreator.h index 8cde9692ad..d11a798a31 100644 --- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.h +++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.h @@ -33,8 +33,7 @@ #include <coreplugin/id.h> namespace ProjectExplorer { -class Kit; -class Project; +class Target; } // namespace ProjectExplorer namespace QmlDesigner { @@ -50,9 +49,7 @@ public: UserSpacePuppet }; - PuppetCreator(ProjectExplorer::Kit *kit, - ProjectExplorer::Project *project, - const Model *model); + PuppetCreator(ProjectExplorer::Target *target, const Model *model); void createQml2PuppetExecutableIfMissing(); @@ -106,7 +103,7 @@ protected: private: mutable QString m_compileLog; - ProjectExplorer::Kit *m_kit = nullptr; + ProjectExplorer::Target *m_target = nullptr; PuppetType m_availablePuppetType; static QHash<Core::Id, PuppetType> m_qml2PuppetForKitPuppetHash; const Model *m_model = nullptr; @@ -114,7 +111,6 @@ private: const DesignerSettings m_designerSettings; #endif QString m_qrcMapping; - ProjectExplorer::Project *m_currentProject = nullptr; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp index 989ea8dbb4..65d7616484 100644 --- a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp +++ b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp @@ -109,7 +109,7 @@ void ViewManager::attachNodeInstanceView() qCInfo(viewBenchmark) << Q_FUNC_INFO; - setNodeInstanceViewKit(currentDesignDocument()->currentKit()); + setNodeInstanceViewTarget(currentDesignDocument()->currentTarget()); currentModel()->setNodeInstanceView(&d->nodeInstanceView); qCInfo(viewBenchmark) << "NodeInstanceView:" << time.elapsed(); @@ -328,14 +328,9 @@ void ViewManager::setComponentViewToMaster() d->componentView.setComponentToMaster(); } -void ViewManager::setNodeInstanceViewKit(ProjectExplorer::Kit *kit) +void ViewManager::setNodeInstanceViewTarget(ProjectExplorer::Target *target) { - d->nodeInstanceView.setKit(kit); -} - -void QmlDesigner::ViewManager::setNodeInstanceViewProject(ProjectExplorer::Project *project) -{ - d->nodeInstanceView.setProject(project); + d->nodeInstanceView.setTarget(target); } QList<WidgetInfo> ViewManager::widgetInfos() const diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 928c19b02c..2dbf40a7bb 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -436,8 +436,8 @@ void QmlDesignerPlugin::activateAutoSynchronization() if (!currentDesignDocument()->isDocumentLoaded()) currentDesignDocument()->loadDocument(currentDesignDocument()->plainTextEdit()); - currentDesignDocument()->updateActiveQtVersion(); - currentDesignDocument()->updateCurrentProject(); + currentDesignDocument()->updateActiveTarget(); + currentDesignDocument()->updateActiveTarget(); d->mainWidget.enableWidgets(); currentDesignDocument()->attachRewriterToModel(); diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index b33846faf9..e5b9014543 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -41,6 +41,7 @@ #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectnodes.h> #include <projectexplorer/projecttree.h> +#include <projectexplorer/runconfiguration.h> #include <projectexplorer/session.h> #include <projectexplorer/target.h> #include <qmljs/qmljsbind.h> @@ -76,10 +77,36 @@ using namespace QmlJS; namespace QmlJSTools { namespace Internal { +static void setupProjectInfoQmlBundles(ModelManagerInterface::ProjectInfo &projectInfo) +{ + Target *activeTarget = nullptr; + if (projectInfo.project) + activeTarget = projectInfo.project->activeTarget(); + Kit *activeKit = activeTarget ? activeTarget->kit() : KitManager::defaultKit(); + const QHash<QString, QString> replacements = {{QLatin1String("$(QT_INSTALL_QML)"), projectInfo.qtQmlPath}}; + + for (IBundleProvider *bp : IBundleProvider::allBundleProviders()) + bp->mergeBundlesForKit(activeKit, projectInfo.activeBundle, replacements); + + projectInfo.extendedBundle = projectInfo.activeBundle; + + if (projectInfo.project) { + QSet<Kit *> currentKits; + foreach (const Target *t, projectInfo.project->targets()) + currentKits.insert(t->kit()); + currentKits.remove(activeKit); + foreach (Kit *kit, currentKits) { + for (IBundleProvider *bp : IBundleProvider::allBundleProviders()) + bp->mergeBundlesForKit(kit, projectInfo.extendedBundle, replacements); + } + } +} + ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject( Project *project) const { - ModelManagerInterface::ProjectInfo projectInfo(project); + ModelManagerInterface::ProjectInfo projectInfo; + projectInfo.project = project; projectInfo.qmlDumpEnvironment = Utils::Environment::systemEnvironment(); Target *activeTarget = nullptr; if (project) { @@ -113,6 +140,13 @@ ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject( // plugins that are not installed in default Qt qml installation directory. projectInfo.qmlDumpEnvironment.appendOrSet("QML2_IMPORT_PATH", bc->environment().expandedValueForKey("QML2_IMPORT_PATH"), ":"); } + + const auto appTargets = activeTarget->applicationTargets(); + for (const auto &target : appTargets) { + if (target.targetFilePath.isEmpty()) + continue; + projectInfo.applicationDirectories.append(target.targetFilePath.parentDir().toString()); + } } if (!setPreferDump && qtVersion) preferDebugDump = (qtVersion->defaultBuildConfig() & QtSupport::BaseQtVersion::DebugBuild); @@ -139,35 +173,6 @@ ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject( return projectInfo; } -} // namespace Internal - -void setupProjectInfoQmlBundles(ModelManagerInterface::ProjectInfo &projectInfo) -{ - Target *activeTarget = nullptr; - if (projectInfo.project) - activeTarget = projectInfo.project->activeTarget(); - Kit *activeKit = activeTarget ? activeTarget->kit() : KitManager::defaultKit(); - const QHash<QString, QString> replacements = {{QLatin1String("$(QT_INSTALL_QML)"), projectInfo.qtQmlPath}}; - - for (IBundleProvider *bp : IBundleProvider::allBundleProviders()) - bp->mergeBundlesForKit(activeKit, projectInfo.activeBundle, replacements); - - projectInfo.extendedBundle = projectInfo.activeBundle; - - if (projectInfo.project) { - QSet<Kit *> currentKits; - foreach (const Target *t, projectInfo.project->targets()) - currentKits.insert(t->kit()); - currentKits.remove(activeKit); - foreach (Kit *kit, currentKits) { - for (IBundleProvider *bp : IBundleProvider::allBundleProviders()) - bp->mergeBundlesForKit(kit, projectInfo.extendedBundle, replacements); - } - } -} - -namespace Internal { - QHash<QString,Dialect> ModelManager::initLanguageForSuffix() const { QHash<QString,Dialect> res = ModelManagerInterface::languageForSuffix(); @@ -224,7 +229,7 @@ void ModelManager::delayedInitialization() ViewerContext qbsVContext; qbsVContext.language = Dialect::QmlQbs; - qbsVContext.maybeAddPath(ICore::resourcePath() + QLatin1String("/qbs")); + qbsVContext.paths.append(ICore::resourcePath() + QLatin1String("/qbs")); setDefaultVContext(qbsVContext); } @@ -267,13 +272,15 @@ void ModelManager::updateDefaultProjectInfo() { // needs to be performed in the ui thread Project *currentProject = SessionManager::startupProject(); - ProjectInfo newDefaultProjectInfo = projectInfo(currentProject, - defaultProjectInfoForProject(currentProject)); - setDefaultProject(projectInfo(currentProject,newDefaultProjectInfo), currentProject); + setDefaultProject(containsProject(currentProject) + ? projectInfo(currentProject) + : defaultProjectInfoForProject(currentProject), + currentProject); } -void ModelManager::addTaskInternal(QFuture<void> result, const QString &msg, const char *taskId) const +void ModelManager::addTaskInternal(const QFuture<void> &result, const QString &msg, + const char *taskId) const { ProgressManager::addTask(result, msg, taskId); } diff --git a/src/plugins/qmljstools/qmljsmodelmanager.h b/src/plugins/qmljstools/qmljsmodelmanager.h index 678882ec3a..ae31fe6282 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.h +++ b/src/plugins/qmljstools/qmljsmodelmanager.h @@ -54,7 +54,8 @@ protected: QHash<QString, QmlJS::Dialect> languageForSuffix() const override; void writeMessageInternal(const QString &msg) const override; WorkingCopy workingCopyInternal() const override; - void addTaskInternal(QFuture<void> result, const QString &msg, const char *taskId) const override; + void addTaskInternal(const QFuture<void> &result, const QString &msg, + const char *taskId) const override; ProjectInfo defaultProjectInfoForProject(ProjectExplorer::Project *project) const override; private: void updateDefaultProjectInfo(); @@ -64,6 +65,4 @@ private: } // namespace Internal -QMLJSTOOLS_EXPORT void setupProjectInfoQmlBundles(QmlJS::ModelManagerInterface::ProjectInfo &projectInfo); - } // namespace QmlJSTools diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index d3d96c20ce..d227db6fe5 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -67,6 +67,7 @@ QmlProject::QmlProject(const Utils::FilePath &fileName) setDisplayName(fileName.toFileInfo().completeBaseName()); setNeedsBuildConfigurations(false); + setBuildSystemCreator([](Project *p) { return new Internal::QmlBuildSystem(p); }); connect(this, &QmlProject::projectFileIsDirty, this, &QmlProject::refreshProjectFile); } @@ -398,5 +399,6 @@ void QmlProject::updateDeploymentData(ProjectExplorer::Target *target) target->setDeploymentData(deploymentData); } + } // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h index 9b09cbd528..d911d7946e 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.h +++ b/src/plugins/qmlprojectmanager/qmlproject.h @@ -28,6 +28,7 @@ #include "qmlprojectmanager_global.h" #include "qmlprojectnodes.h" +#include <projectexplorer/buildsystem.h> #include <projectexplorer/project.h> #include <utils/environment.h> @@ -38,8 +39,31 @@ namespace ProjectExplorer { class RunConfiguration; } namespace QmlProjectManager { +class QmlProject; class QmlProjectItem; +namespace Internal { + +class QmlBuildSystem : public ProjectExplorer::BuildSystem +{ +public: + explicit QmlBuildSystem(ProjectExplorer::Project *project) : BuildSystem(project) {} + + bool supportsAction(ProjectExplorer::Node *context, + ProjectExplorer::ProjectAction action, + const ProjectExplorer::Node *node) const override; + bool addFiles(ProjectExplorer::Node *context, + const QStringList &filePaths, QStringList *notAdded = nullptr) override; + bool deleteFiles(ProjectExplorer::Node *context, + const QStringList &filePaths) override; + bool renameFile(ProjectExplorer::Node *context, + const QString &filePath, const QString &newFilePath) override; + + QmlProject *project() const; +}; + +} // Internal + class QMLPROJECTMANAGER_EXPORT QmlProject : public ProjectExplorer::Project { Q_OBJECT diff --git a/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp b/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp index a4494e7064..2d7a4daddb 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp @@ -53,71 +53,90 @@ QmlProjectNode::QmlProjectNode(QmlProject *project) : ProjectNode(project->proje setIcon(qmlProjectIcon); } -bool QmlProjectNode::supportsAction(ProjectAction action, const Node *node) const +bool QmlBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const { - if (action == AddNewFile || action == EraseFile) - return true; - QTC_ASSERT(node, return false); + if (dynamic_cast<QmlProjectNode *>(context)) { + if (action == AddNewFile || action == EraseFile) + return true; + QTC_ASSERT(node, return false); + + if (action == Rename && node->asFileNode()) { + const FileNode *fileNode = node->asFileNode(); + QTC_ASSERT(fileNode, return false); + return fileNode->fileType() != FileType::Project; + } - if (action == Rename && node->asFileNode()) { - const FileNode *fileNode = node->asFileNode(); - QTC_ASSERT(fileNode, return false); - return fileNode->fileType() != FileType::Project; + return false; } - return false; + return BuildSystem::supportsAction(context, action, node); } -bool QmlProjectNode::addFiles(const QStringList &filePaths, QStringList * /*notAdded*/) +QmlProject *QmlBuildSystem::project() const { - return m_project->addFiles(filePaths); + return static_cast<QmlProject *>(BuildSystem::project()); } -bool QmlProjectNode::deleteFiles(const QStringList & /*filePaths*/) +bool QmlBuildSystem::addFiles(Node *context, const QStringList &filePaths, QStringList *notAdded) { - return true; + if (dynamic_cast<QmlProjectNode *>(context)) + return project()->addFiles(filePaths); + + return BuildSystem::addFiles(context, filePaths, notAdded); } -bool QmlProjectNode::renameFile(const QString & filePath, const QString & newFilePath) +bool QmlBuildSystem::deleteFiles(Node *context, const QStringList &filePaths) { - if (filePath.endsWith(m_project->mainFile())) { - m_project->setMainFile(newFilePath); - - // make sure to change it also in the qmlproject file - const QString qmlProjectFilePath = m_project->projectFilePath().toString(); - Core::FileChangeBlocker fileChangeBlocker(qmlProjectFilePath); - const QList<Core::IEditor *> editors = Core::DocumentModel::editorsForFilePath(qmlProjectFilePath); - TextEditor::TextDocument *document = nullptr; - if (!editors.isEmpty()) { - document = qobject_cast<TextEditor::TextDocument*>(editors.first()->document()); - if (document && document->isModified()) - if (!Core::DocumentManager::saveDocument(document)) - return false; - } - - QString fileContent; - QString error; - Utils::TextFileFormat textFileFormat; - const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8 - if (Utils::TextFileFormat::readFile(qmlProjectFilePath, codec, &fileContent, &textFileFormat, &error) - != Utils::TextFileFormat::ReadSuccess) { - qWarning() << "Failed to read file" << qmlProjectFilePath << ":" << error; - } + if (dynamic_cast<QmlProjectNode *>(context)) + return true; - // find the mainFile and do the file name with brackets in a capture group and mask the . with \. - QString originalFileName = QFileInfo(filePath).fileName(); - originalFileName.replace(".", "\\."); - const QRegularExpression expression(QString("mainFile:\\s*\"(%1)\"").arg(originalFileName)); - const QRegularExpressionMatch match = expression.match(fileContent); + return BuildSystem::deleteFiles(context, filePaths); +} - fileContent.replace(match.capturedStart(1), match.capturedLength(1), QFileInfo(newFilePath).fileName()); +bool QmlBuildSystem::renameFile(Node * context, const QString &filePath, const QString &newFilePath) +{ + if (dynamic_cast<QmlProjectNode *>(context)) { + if (filePath.endsWith(project()->mainFile())) { + project()->setMainFile(newFilePath); + + // make sure to change it also in the qmlproject file + const QString qmlProjectFilePath = project()->projectFilePath().toString(); + Core::FileChangeBlocker fileChangeBlocker(qmlProjectFilePath); + const QList<Core::IEditor *> editors = Core::DocumentModel::editorsForFilePath(qmlProjectFilePath); + TextEditor::TextDocument *document = nullptr; + if (!editors.isEmpty()) { + document = qobject_cast<TextEditor::TextDocument*>(editors.first()->document()); + if (document && document->isModified()) + if (!Core::DocumentManager::saveDocument(document)) + return false; + } + + QString fileContent; + QString error; + Utils::TextFileFormat textFileFormat; + const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8 + if (Utils::TextFileFormat::readFile(qmlProjectFilePath, codec, &fileContent, &textFileFormat, &error) + != Utils::TextFileFormat::ReadSuccess) { + qWarning() << "Failed to read file" << qmlProjectFilePath << ":" << error; + } + + // find the mainFile and do the file name with brackets in a capture group and mask the . with \. + QString originalFileName = QFileInfo(filePath).fileName(); + originalFileName.replace(".", "\\."); + const QRegularExpression expression(QString("mainFile:\\s*\"(%1)\"").arg(originalFileName)); + const QRegularExpressionMatch match = expression.match(fileContent); + + fileContent.replace(match.capturedStart(1), match.capturedLength(1), QFileInfo(newFilePath).fileName()); + + if (!textFileFormat.writeFile(qmlProjectFilePath, fileContent, &error)) + qWarning() << "Failed to write file" << qmlProjectFilePath << ":" << error; + project()->refresh(QmlProject::Everything); + } - if (!textFileFormat.writeFile(qmlProjectFilePath, fileContent, &error)) - qWarning() << "Failed to write file" << qmlProjectFilePath << ":" << error; - m_project->refresh(QmlProject::Everything); + return true; } - return true; + return BuildSystem::renameFile(context, filePath, newFilePath); } } // namespace Internal diff --git a/src/plugins/qmlprojectmanager/qmlprojectnodes.h b/src/plugins/qmlprojectmanager/qmlprojectnodes.h index 4d6fe4cfcf..13c25a31a7 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectnodes.h +++ b/src/plugins/qmlprojectmanager/qmlprojectnodes.h @@ -38,11 +38,6 @@ class QmlProjectNode : public ProjectExplorer::ProjectNode public: QmlProjectNode(QmlProject *project); - bool supportsAction(ProjectExplorer::ProjectAction action, const Node *node) const override; - bool addFiles(const QStringList &filePaths, QStringList *notAdded = nullptr) override; - bool deleteFiles(const QStringList &filePaths) override; - bool renameFile(const QString &filePath, const QString &newFilePath) override; - private: QmlProject *m_project; }; diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp index 6e67361d11..2b093fd7af 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp @@ -82,7 +82,7 @@ public: FileInSettings }; - void addToConfigurationLayout(QFormLayout *layout) final; + void addToLayout(LayoutBuilder &builder) final; void toMap(QVariantMap &map) const final; void fromMap(const QVariantMap &map) final; @@ -117,7 +117,7 @@ MainQmlFileAspect::MainQmlFileAspect(QmlProject *project) this, [this] { changeCurrentFile(); }); } -void MainQmlFileAspect::addToConfigurationLayout(QFormLayout *layout) +void MainQmlFileAspect::addToLayout(LayoutBuilder &builder) { QTC_ASSERT(!m_fileListCombo, delete m_fileListCombo); m_fileListCombo = new QComboBox; @@ -130,7 +130,8 @@ void MainQmlFileAspect::addToConfigurationLayout(QFormLayout *layout) connect(m_fileListCombo, QOverload<int>::of(&QComboBox::activated), this, &MainQmlFileAspect::setMainScript); - layout->addRow(QmlProjectRunConfiguration::tr("Main QML file:"), m_fileListCombo); + builder.addItem(QmlProjectRunConfiguration::tr("Main QML file:")); + builder.addItem(m_fileListCombo.data()); } void MainQmlFileAspect::toMap(QVariantMap &map) const diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 603a19aff5..8300b28b27 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -48,13 +48,14 @@ #include <qtsupport/qtsupportconstants.h> #include <utils/algorithm.h> +#include <utils/displayname.h> +#include <utils/fileinprojectfinder.h> #include <utils/hostosinfo.h> #include <utils/macroexpander.h> #include <utils/qtcassert.h> #include <utils/runextensions.h> #include <utils/synchronousprocess.h> #include <utils/winutils.h> -#include <utils/fileinprojectfinder.h> #include <resourceeditor/resourcenode.h> @@ -87,6 +88,51 @@ const char QTVERSION_ABIS[] = "Abis"; const char MKSPEC_VALUE_LIBINFIX[] = "QT_LIBINFIX"; const char MKSPEC_VALUE_NAMESPACE[] = "QT_NAMESPACE"; +// -------------------------------------------------------------------- +// QtVersionData: +// -------------------------------------------------------------------- + +class QtVersionData +{ +public: + bool installed = true; + bool hasExamples = false; + bool hasDemos = false; + bool hasDocumentation = false; + bool hasQtAbis = false; + + DisplayName unexpandedDisplayName; + QString qtVersionString; + + FilePath sourcePath; + FilePath qtSources; + + Utils::FilePath prefix; + + Utils::FilePath binPath; + Utils::FilePath configurationPath; + Utils::FilePath dataPath; + Utils::FilePath demosPath; + Utils::FilePath docsPath; + Utils::FilePath examplesPath; + // Utils::FilePath frameworkPath; // is derived from libraryPath + Utils::FilePath headerPath; + Utils::FilePath importsPath; + Utils::FilePath libraryPath; + Utils::FilePath pluginPath; + Utils::FilePath qmlPath; + Utils::FilePath translationsPath; + + Utils::FilePath hostBinPath; + Utils::FilePath hostDataPath; + + Abis qtAbis; +}; + +// -------------------------------------------------------------------- +// Helpers: +// -------------------------------------------------------------------- + static QSet<Id> versionedIds(const QByteArray &prefix, int major, int minor) { QSet<Id> result; @@ -129,9 +175,10 @@ enum HostBinaries { Designer, Linguist, Uic, QScxmlc }; class BaseQtVersionPrivate { public: - BaseQtVersionPrivate(BaseQtVersion *parent) : q(parent) {} + BaseQtVersionPrivate(BaseQtVersion *parent) + : q(parent) + {} - void setupQmakePathAndId(const FilePath &path); void updateVersionInfo(); QString findHostBinary(HostBinaries binary) const; @@ -160,6 +207,8 @@ public: bool m_isAutodetected = false; QString m_type; + QtVersionData m_data; + bool m_isUpdating = false; bool m_hasQmlDump = false; // controlled by m_versionInfoUpToDate bool m_mkspecUpToDate = false; @@ -168,18 +217,10 @@ public: bool m_defaultConfigIsDebugAndRelease = true; bool m_frameworkBuild = false; bool m_versionInfoUpToDate = false; - bool m_installed = true; - bool m_hasExamples = false; - bool m_hasDemos = false; - bool m_hasDocumentation = false; bool m_qmakeIsExecutable = true; - bool m_hasQtAbis = false; - QString m_unexpandedDisplayName; QString m_autodetectionSource; QSet<Core::Id> m_overrideFeatures; - FilePath m_sourcePath; - FilePath m_qtSources; FilePath m_mkspec; FilePath m_mkspecFullPath; @@ -189,15 +230,13 @@ public: QHash<ProKey, ProString> m_versionInfo; FilePath m_qmakeCommand; - QString m_qtVersionString; + QString m_uicCommand; QString m_designerCommand; QString m_linguistCommand; QString m_qscxmlcCommand; QString m_qmlsceneCommand; - Abis m_qtAbis; - MacroExpanderWrapper m_expander; }; @@ -293,29 +332,20 @@ BaseQtVersion::BaseQtVersion() : d(new BaseQtVersionPrivate(this)) {} - BaseQtVersion::~BaseQtVersion() { delete d; } -void BaseQtVersionPrivate::setupQmakePathAndId(const FilePath &qmakeCommand) -{ - m_id = QtVersionManager::getUniqueId(); - QTC_CHECK(m_qmakeCommand.isEmpty()); // Should only be used once. - m_qmakeCommand = qmakeCommand; - m_unexpandedDisplayName = BaseQtVersion::defaultUnexpandedDisplayName(m_qmakeCommand, false); -} - -QString BaseQtVersion::defaultUnexpandedDisplayName(const FilePath &qmakePath, bool fromPath) +QString BaseQtVersion::defaultUnexpandedDisplayName() const { QString location; - if (qmakePath.isEmpty()) { + if (qmakeCommand().isEmpty()) { location = QCoreApplication::translate("QtVersion", "<unknown>"); } else { // Deduce a description from '/foo/qt-folder/[qtbase]/bin/qmake' -> '/foo/qt-folder'. // '/usr' indicates System Qt 4.X on Linux. - QDir dir = qmakePath.toFileInfo().absoluteDir(); + QDir dir = qmakeCommand().toFileInfo().absoluteDir(); do { const QString dirName = dir.dirName(); if (dirName == "usr") { // System-installed Qt. @@ -332,7 +362,7 @@ QString BaseQtVersion::defaultUnexpandedDisplayName(const FilePath &qmakePath, b } while (!dir.isRoot() && dir.cdUp()); } - return fromPath ? + return autodetectionSource() == "PATH" ? QCoreApplication::translate("QtVersion", "Qt %{Qt:Version} in PATH (%2)").arg(location) : QCoreApplication::translate("QtVersion", "Qt %{Qt:Version} (%2)").arg(location); } @@ -520,67 +550,80 @@ Tasks BaseQtVersion::validateKit(const Kit *k) FilePath BaseQtVersion::prefix() const // QT_INSTALL_PREFIX { - return FilePath::fromUserInput(d->qmakeProperty("QT_INSTALL_PREFIX")); + d->updateVersionInfo(); + return d->m_data.prefix; } FilePath BaseQtVersion::binPath() const // QT_INSTALL_BINS { - return FilePath::fromUserInput(d->qmakeProperty("QT_INSTALL_BINS")); + d->updateVersionInfo(); + return d->m_data.binPath; } FilePath BaseQtVersion::configurationPath() const // QT_INSTALL_CONFIGURATION { - return FilePath::fromUserInput(d->qmakeProperty("QT_INSTALL_CONFIGURATION")); + d->updateVersionInfo(); + return d->m_data.configurationPath; } FilePath BaseQtVersion::headerPath() const // QT_INSTALL_HEADERS { - return FilePath::fromUserInput(d->qmakeProperty("QT_INSTALL_HEADERS")); + d->updateVersionInfo(); + return d->m_data.headerPath; } FilePath BaseQtVersion::dataPath() const // QT_INSTALL_DATA { - return FilePath::fromUserInput(d->qmakeProperty("QT_INSTALL_DATA")); + d->updateVersionInfo(); + return d->m_data.dataPath; } FilePath BaseQtVersion::docsPath() const // QT_INSTALL_DOCS { - return FilePath::fromUserInput(d->qmakeProperty("QT_INSTALL_DOCS")); + d->updateVersionInfo(); + return d->m_data.docsPath; } FilePath BaseQtVersion::importsPath() const // QT_INSTALL_IMPORTS { - return FilePath::fromUserInput(d->qmakeProperty("QT_INSTALL_IMPORTS")); + d->updateVersionInfo(); + return d->m_data.importsPath; } FilePath BaseQtVersion::libraryPath() const // QT_INSTALL_LIBS { - return FilePath::fromUserInput(d->qmakeProperty("QT_INSTALL_LIBS")); + d->updateVersionInfo(); + return d->m_data.libraryPath; } FilePath BaseQtVersion::pluginPath() const // QT_INSTALL_PLUGINS { - return FilePath::fromUserInput(d->qmakeProperty("QT_INSTALL_PLUGINS")); + d->updateVersionInfo(); + return d->m_data.pluginPath; } FilePath BaseQtVersion::qmlPath() const // QT_INSTALL_QML { - return FilePath::fromUserInput(d->qmakeProperty("QT_INSTALL_QML")); + d->updateVersionInfo(); + return d->m_data.qmlPath; } FilePath BaseQtVersion::translationsPath() const // QT_INSTALL_TRANSLATIONS { - return FilePath::fromUserInput(d->qmakeProperty("QT_INSTALL_TRANSLATIONS")); + d->updateVersionInfo(); + return d->m_data.translationsPath; } FilePath BaseQtVersion::hostBinPath() const // QT_HOST_BINS { - return FilePath::fromUserInput(d->qmakeProperty("QT_HOST_BINS")); + d->updateVersionInfo(); + return d->m_data.hostBinPath; } FilePath BaseQtVersion::hostDataPath() const // QT_HOST_DATA { - return FilePath::fromUserInput(d->qmakeProperty("QT_HOST_DATA")); + d->updateVersionInfo(); + return d->m_data.hostDataPath; } FilePath BaseQtVersion::mkspecsPath() const @@ -593,6 +636,7 @@ FilePath BaseQtVersion::mkspecsPath() const FilePath BaseQtVersion::qmlBinPath() const { + d->updateVersionInfo(); return FilePath::fromUserInput(d->m_mkspecValues.value("QT.qml.bins")); } @@ -651,22 +695,22 @@ void BaseQtVersion::fromMap(const QVariantMap &map) d->m_id = map.value(Constants::QTVERSIONID).toInt(); if (d->m_id == -1) // this happens on adding from installer, see updateFromInstaller => get a new unique id d->m_id = QtVersionManager::getUniqueId(); - d->m_unexpandedDisplayName = map.value(Constants::QTVERSIONNAME).toString(); + d->m_data.unexpandedDisplayName.fromMap(map, Constants::QTVERSIONNAME); d->m_isAutodetected = map.value(QTVERSIONAUTODETECTED).toBool(); - if (d->m_isAutodetected) - d->m_autodetectionSource = map.value(QTVERSIONAUTODETECTIONSOURCE).toString(); + d->m_autodetectionSource = map.value(QTVERSIONAUTODETECTIONSOURCE).toString(); d->m_overrideFeatures = Core::Id::fromStringList(map.value(QTVERSION_OVERRIDE_FEATURES).toStringList()); QString string = map.value(QTVERSIONQMAKEPATH).toString(); if (string.startsWith('~')) string.remove(0, 1).prepend(QDir::homePath()); - d->m_qtSources = FilePath::fromUserInput(map.value(QTVERSIONSOURCEPATH).toString()); + d->m_data.qtSources = FilePath::fromUserInput(map.value(QTVERSIONSOURCEPATH).toString()); // Handle ABIs provided by the SDKTool: // Note: Creator does not write these settings itself, so it has to come from the SDKTool! - d->m_qtAbis = Utils::transform<Abis>(map.value(QTVERSION_ABIS).toStringList(), &Abi::fromString); - d->m_qtAbis = Utils::filtered(d->m_qtAbis, &Abi::isValid); - d->m_hasQtAbis = !d->m_qtAbis.isEmpty(); + d->m_data.qtAbis = Utils::transform<Abis>(map.value(QTVERSION_ABIS).toStringList(), + &Abi::fromString); + d->m_data.qtAbis = Utils::filtered(d->m_data.qtAbis, &Abi::isValid); + d->m_data.hasQtAbis = !d->m_data.qtAbis.isEmpty(); QFileInfo fi(string); if (BuildableHelperLibrary::isQtChooser(fi)) { @@ -677,6 +721,7 @@ void BaseQtVersion::fromMap(const QVariantMap &map) } d->m_qmakeCommand = FilePath::fromString(string); + updateDefaultDisplayName(); // Clear the cached qmlscene command, it might not match the restored path anymore. d->m_qmlsceneCommand.clear(); @@ -686,10 +731,9 @@ QVariantMap BaseQtVersion::toMap() const { QVariantMap result; result.insert(Constants::QTVERSIONID, uniqueId()); - result.insert(Constants::QTVERSIONNAME, unexpandedDisplayName()); + d->m_data.unexpandedDisplayName.toMap(result, Constants::QTVERSIONNAME); result.insert(QTVERSIONAUTODETECTED, isAutodetected()); - if (isAutodetected()) - result.insert(QTVERSIONAUTODETECTIONSOURCE, autodetectionSource()); + result.insert(QTVERSIONAUTODETECTIONSOURCE, autodetectionSource()); if (!d->m_overrideFeatures.isEmpty()) result.insert(QTVERSION_OVERRIDE_FEATURES, Core::Id::toStringList(d->m_overrideFeatures)); @@ -704,7 +748,7 @@ bool BaseQtVersion::isValid() const d->updateVersionInfo(); d->updateMkspec(); - return !qmakeCommand().isEmpty() && d->m_installed && !binPath().isEmpty() + return !qmakeCommand().isEmpty() && d->m_data.installed && !binPath().isEmpty() && !d->m_mkspecFullPath.isEmpty() && d->m_qmakeIsExecutable; } @@ -723,7 +767,7 @@ QString BaseQtVersion::invalidReason() const return QCoreApplication::translate("QtVersion", "No qmake path set"); if (!d->m_qmakeIsExecutable) return QCoreApplication::translate("QtVersion", "qmake does not exist or is not executable"); - if (!d->m_installed) + if (!d->m_data.installed) return QCoreApplication::translate("QtVersion", "Qt version is not properly installed, please run make install"); if (binPath().isEmpty()) return QCoreApplication::translate("QtVersion", @@ -752,11 +796,11 @@ FilePath BaseQtVersion::qmakeCommand() const Abis BaseQtVersion::qtAbis() const { - if (!d->m_hasQtAbis) { - d->m_qtAbis = detectQtAbis(); - d->m_hasQtAbis = true; + if (!d->m_data.hasQtAbis) { + d->m_data.qtAbis = detectQtAbis(); + d->m_data.hasQtAbis = true; } - return d->m_qtAbis; + return d->m_data.qtAbis; } Abis BaseQtVersion::detectQtAbis() const @@ -802,17 +846,22 @@ QString BaseQtVersion::autodetectionSource() const QString BaseQtVersion::displayName() const { - return macroExpander()->expand(d->m_unexpandedDisplayName); + return macroExpander()->expand(unexpandedDisplayName()); } QString BaseQtVersion::unexpandedDisplayName() const { - return d->m_unexpandedDisplayName; + return d->m_data.unexpandedDisplayName.value(); } void BaseQtVersion::setUnexpandedDisplayName(const QString &name) { - d->m_unexpandedDisplayName = name; + d->m_data.unexpandedDisplayName.setValue(name); +} + +void BaseQtVersion::updateDefaultDisplayName() +{ + d->m_data.unexpandedDisplayName.setDefaultValue(defaultUnexpandedDisplayName()); } QString BaseQtVersion::toHtml(bool verbose) const @@ -898,16 +947,16 @@ QString BaseQtVersion::toHtml(bool verbose) const FilePath BaseQtVersion::sourcePath() const { - if (d->m_sourcePath.isEmpty()) { + if (d->m_data.sourcePath.isEmpty()) { d->updateVersionInfo(); - d->m_sourcePath = d->sourcePath(d->m_versionInfo); + d->m_data.sourcePath = d->sourcePath(d->m_versionInfo); } - return d->m_sourcePath; + return d->m_data.sourcePath; } FilePath BaseQtVersion::qtPackageSourcePath() const { - return d->m_qtSources; + return d->m_data.qtSources; } QString BaseQtVersion::designerCommand() const @@ -1172,7 +1221,7 @@ BaseQtVersion::QmakeBuildConfigs BaseQtVersion::defaultBuildConfig() const QString BaseQtVersion::qtVersionString() const { d->updateVersionInfo(); - return d->m_qtVersionString; + return d->m_data.qtVersionString; } QtVersionNumber BaseQtVersion::qtVersion() const @@ -1189,9 +1238,9 @@ void BaseQtVersionPrivate::updateVersionInfo() // extract data from qmake executable m_versionInfo.clear(); - m_installed = true; - m_hasExamples = false; - m_hasDocumentation = false; + m_data.installed = true; + m_data.hasExamples = false; + m_data.hasDocumentation = false; m_hasQmlDump = false; if (!queryQMakeVariables(m_qmakeCommand, q->qmakeRunEnvironment(), &m_versionInfo)) { @@ -1217,35 +1266,55 @@ void BaseQtVersionPrivate::updateVersionInfo() QString installDir = q->hostBinPath().toString(); if (!installDir.isNull()) { if (!QFileInfo::exists(installDir)) - m_installed = false; + m_data.installed = false; } // Framework builds for Qt 4.8 don't use QT_INSTALL_HEADERS // so we don't check on mac if (!HostOsInfo::isMacHost()) { if (!qtHeaderData.isNull()) { if (!QFileInfo::exists(qtHeaderData)) - m_installed = false; + m_data.installed = false; } } const QString qtInstallDocs = q->docsPath().toString(); if (!qtInstallDocs.isNull()) { if (QFileInfo::exists(qtInstallDocs)) - m_hasDocumentation = true; + m_data.hasDocumentation = true; } const QString qtInstallExamples = q->examplesPath().toString(); if (!qtInstallExamples.isNull()) { if (QFileInfo::exists(qtInstallExamples)) - m_hasExamples = true; + m_data.hasExamples = true; } const QString qtInstallDemos = q->demosPath().toString(); if (!qtInstallDemos.isNull()) { if (QFileInfo::exists(qtInstallDemos)) - m_hasDemos = true; + m_data.hasDemos = true; } - m_qtVersionString = qmakeProperty("QT_VERSION"); + m_data.qtVersionString = qmakeProperty("QT_VERSION"); m_isUpdating = false; m_versionInfoUpToDate = true; + + m_data.prefix = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_PREFIX")); + + m_data.binPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_BINS")); + m_data.configurationPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_CONFIGURATION")); + m_data.dataPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_DATA")); + m_data.demosPath = FilePath::fromString( + QFileInfo(qmakeProperty("QT_INSTALL_DEMOS")).canonicalFilePath()); + m_data.docsPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_DOCS")); + m_data.examplesPath = FilePath::fromString( + QFileInfo(qmakeProperty("QT_INSTALL_EXAMPLES")).canonicalFilePath()); + m_data.headerPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_HEADERS")); + m_data.importsPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_IMPORTS")); + m_data.libraryPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_LIBS")); + m_data.pluginPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_PLUGINS")); + m_data.qmlPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_QML")); + m_data.translationsPath = FilePath::fromUserInput(qmakeProperty("QT_INSTALL_TRANSLATIONS")); + + m_data.hostBinPath = FilePath::fromUserInput(qmakeProperty("QT_HOST_BINS")); + m_data.hostDataPath = FilePath::fromUserInput(qmakeProperty("QT_HOST_DATA")); } QHash<ProKey,ProString> BaseQtVersionPrivate::versionInfo() @@ -1278,18 +1347,18 @@ void BaseQtVersion::applyProperties(QMakeGlobals *qmakeGlobals) const bool BaseQtVersion::hasDocs() const { d->updateVersionInfo(); - return d->m_hasDocumentation; + return d->m_data.hasDocumentation; } bool BaseQtVersion::hasDemos() const { d->updateVersionInfo(); - return d->m_hasDemos; + return d->m_data.hasDemos; } FilePath BaseQtVersion::demosPath() const { - return FilePath::fromString(QFileInfo(d->qmakeProperty("QT_INSTALL_DEMOS")).canonicalFilePath()); + return d->m_data.demosPath; } FilePath BaseQtVersion::frameworkPath() const @@ -1302,28 +1371,21 @@ FilePath BaseQtVersion::frameworkPath() const bool BaseQtVersion::hasExamples() const { d->updateVersionInfo(); - return d->m_hasExamples; + return d->m_data.hasExamples; } FilePath BaseQtVersion::examplesPath() const // QT_INSTALL_EXAMPLES { - return FilePath::fromString( - QFileInfo(d->qmakeProperty("QT_INSTALL_EXAMPLES")).canonicalFilePath()); + return d->m_data.examplesPath; } QStringList BaseQtVersion::qtSoPaths() const { - static const char * const qMakeVariables[] = { - "QT_INSTALL_LIBS", - "QT_INSTALL_PLUGINS", - "QT_INSTALL_QML", - "QT_INSTALL_IMPORTS" - }; - + const FilePathList qtPaths = {libraryPath(), pluginPath(), qmlPath(), importsPath()}; QSet<QString> paths; - for (uint i = 0; i < sizeof qMakeVariables / sizeof qMakeVariables[0]; ++i) { - QString path = d->qmakeProperty(qMakeVariables[i]); - if (path.isNull()) + for (const FilePath &p : qtPaths) { + QString path = p.toString(); + if (path.isEmpty()) continue; QDirIterator it(path, QStringList("*.so"), QDir::Files, QDirIterator::Subdirectories); while (it.hasNext()) { @@ -1461,33 +1523,32 @@ BaseQtVersion::createMacroExpander(const std::function<const BaseQtVersion *()> return version->demosPath().toString(); })); - expander->registerVariable( - "Qt:QMAKE_MKSPECS", - QtKitAspect::tr("The current Qt version's default mkspecs (Qt 4)."), - versionProperty([](const BaseQtVersion *version) { - return version->d->qmakeProperty(version->d->m_versionInfo, "QMAKE_MKSPECS"); - })); + expander->registerVariable("Qt:QMAKE_MKSPECS", + QtKitAspect::tr("The current Qt version's default mkspecs (Qt 4)."), + versionProperty([](const BaseQtVersion *version) { + return version->d->qmakeProperty("QMAKE_MKSPECS"); + })); - expander->registerVariable( - "Qt:QMAKE_SPEC", - QtKitAspect::tr("The current Qt version's default mkspec (Qt 5; host system)."), - versionProperty([](const BaseQtVersion *version) { - return version->d->qmakeProperty(version->d->m_versionInfo, "QMAKE_SPEC"); - })); + expander->registerVariable("Qt:QMAKE_SPEC", + QtKitAspect::tr( + "The current Qt version's default mkspec (Qt 5; host system)."), + versionProperty([](const BaseQtVersion *version) { + return version->d->qmakeProperty("QMAKE_SPEC"); + })); - expander->registerVariable( - "Qt:QMAKE_XSPEC", - QtKitAspect::tr("The current Qt version's default mkspec (Qt 5; target system)."), - versionProperty([](const BaseQtVersion *version) { - return version->d->qmakeProperty(version->d->m_versionInfo, "QMAKE_XSPEC"); - })); + expander + ->registerVariable("Qt:QMAKE_XSPEC", + QtKitAspect::tr( + "The current Qt version's default mkspec (Qt 5; target system)."), + versionProperty([](const BaseQtVersion *version) { + return version->d->qmakeProperty("QMAKE_XSPEC"); + })); - expander->registerVariable( - "Qt:QMAKE_VERSION", - QtKitAspect::tr("The current Qt's qmake version."), - versionProperty([](const BaseQtVersion *version) { - return version->d->qmakeProperty(version->d->m_versionInfo, "QMAKE_VERSION"); - })); + expander->registerVariable("Qt:QMAKE_VERSION", + QtKitAspect::tr("The current Qt's qmake version."), + versionProperty([](const BaseQtVersion *version) { + return version->d->qmakeProperty("QMAKE_VERSION"); + })); // FIXME: Re-enable once we can detect expansion loops. // expander->registerVariable("Qt:Name", @@ -1944,7 +2005,7 @@ bool BaseQtVersion::isQtQuickCompilerSupported(QString *reason) const FilePathList BaseQtVersionPrivate::qtCorePaths() { updateVersionInfo(); - const QString versionString = m_qtVersionString; + const QString versionString = m_data.qtVersionString; const QString installLibsDir = q->libraryPath().toString(); const QString installBinDir = q->binPath().toString(); @@ -2209,9 +2270,12 @@ BaseQtVersion *QtVersionFactory::createQtVersionFromQMakePath if (!factory->m_restrictionChecker || factory->m_restrictionChecker(setup)) { BaseQtVersion *ver = factory->create(); QTC_ASSERT(ver, continue); - ver->d->setupQmakePathAndId(qmakePath); + ver->d->m_id = QtVersionManager::getUniqueId(); + QTC_CHECK(ver->d->m_qmakeCommand.isEmpty()); // Should only be used once. + ver->d->m_qmakeCommand = qmakePath; ver->d->m_autodetectionSource = autoDetectionSource; ver->d->m_isAutodetected = isAutoDetected; + ver->updateDefaultDisplayName(); ProFileCacheManager::instance()->decRefCount(); return ver; } diff --git a/src/plugins/qtsupport/baseqtversion.h b/src/plugins/qtsupport/baseqtversion.h index 8de93f138b..4a90ca531b 100644 --- a/src/plugins/qtsupport/baseqtversion.h +++ b/src/plugins/qtsupport/baseqtversion.h @@ -187,8 +187,7 @@ public: virtual QtConfigWidget *createConfigurationWidget() const; - static QString defaultUnexpandedDisplayName(const Utils::FilePath &qmakePath, - bool fromPath = false); + QString defaultUnexpandedDisplayName() const; virtual QSet<Core::Id> targetDeviceTypes() const = 0; @@ -249,6 +248,8 @@ protected: virtual void parseMkSpec(ProFileEvaluator *) const; private: + void updateDefaultDisplayName(); + friend class QtVersionFactory; friend class QtVersionManager; friend class Internal::BaseQtVersionPrivate; diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index d531677e14..5ce7e34a6a 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -637,7 +637,7 @@ void QtOptionsPageWidget::editPath() } // same type, replace version->setId(current->uniqueId()); - if (current->unexpandedDisplayName() != current->defaultUnexpandedDisplayName(current->qmakeCommand())) + if (current->unexpandedDisplayName() != current->defaultUnexpandedDisplayName()) version->setUnexpandedDisplayName(current->displayName()); // Update ui diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index 6f888e5401..5888f6a938 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -436,10 +436,8 @@ static void findSystemQt() BaseQtVersion *version = QtVersionFactory::createQtVersionFromQMakePath(qmakePath, false, "PATH"); - if (version) { - version->setUnexpandedDisplayName(BaseQtVersion::defaultUnexpandedDisplayName(qmakePath, true)); + if (version) m_versions.insert(version->uniqueId(), version); - } } } diff --git a/src/plugins/qtsupport/qtversionmanager.h b/src/plugins/qtsupport/qtversionmanager.h index fefe5b4273..2c05485c60 100644 --- a/src/plugins/qtsupport/qtversionmanager.h +++ b/src/plugins/qtsupport/qtversionmanager.h @@ -35,8 +35,9 @@ class QTSUPPORT_EXPORT QtVersionManager : public QObject Q_OBJECT // for getUniqueId(); friend class BaseQtVersion; - friend class Internal::BaseQtVersionPrivate; + friend class QtVersionFactory; friend class Internal::QtOptionsPageWidget; + public: static QtVersionManager *instance(); QtVersionManager(); diff --git a/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp b/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp index b74d73a5d4..c4c9f8f376 100644 --- a/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp +++ b/src/plugins/webassembly/webassemblyrunconfigurationaspects.cpp @@ -77,10 +77,10 @@ WebBrowserSelectionAspect::WebBrowserSelectionAspect(ProjectExplorer::Target *ta setSettingsKey("RunConfiguration.WebBrowser"); } -void WebBrowserSelectionAspect::addToConfigurationLayout(QFormLayout *layout) +void WebBrowserSelectionAspect::addToLayout(ProjectExplorer::LayoutBuilder &builder) { QTC_CHECK(!m_webBrowserComboBox); - m_webBrowserComboBox = new QComboBox(layout->parentWidget()); + m_webBrowserComboBox = new QComboBox; m_webBrowserComboBox->addItems(m_availableBrowsers); m_webBrowserComboBox->setCurrentText(m_currentBrowser); connect(m_webBrowserComboBox, &QComboBox::currentTextChanged, @@ -88,7 +88,8 @@ void WebBrowserSelectionAspect::addToConfigurationLayout(QFormLayout *layout) m_currentBrowser = selectedBrowser; emit changed(); }); - layout->addRow(tr("Web browser:"), m_webBrowserComboBox); + builder.addItem(tr("Web browser:")); + builder.addItem(m_webBrowserComboBox); } void WebBrowserSelectionAspect::fromMap(const QVariantMap &map) diff --git a/src/plugins/webassembly/webassemblyrunconfigurationaspects.h b/src/plugins/webassembly/webassemblyrunconfigurationaspects.h index 16b2d842ee..1f640f35a3 100644 --- a/src/plugins/webassembly/webassemblyrunconfigurationaspects.h +++ b/src/plugins/webassembly/webassemblyrunconfigurationaspects.h @@ -39,7 +39,7 @@ class WebBrowserSelectionAspect : public ProjectExplorer::ProjectConfigurationAs public: WebBrowserSelectionAspect(ProjectExplorer::Target *target); - void addToConfigurationLayout(QFormLayout *layout) override; + void addToLayout(ProjectExplorer::LayoutBuilder &builder) override; void fromMap(const QVariantMap &map) override; void toMap(QVariantMap &map) const override; diff --git a/src/shared/qtcreator_pch.h b/src/shared/qtcreator_pch.h index 4988f3d939..bd6ba76506 100644 --- a/src/shared/qtcreator_pch.h +++ b/src/shared/qtcreator_pch.h @@ -31,11 +31,29 @@ #if defined __cplusplus #include <QtGlobal> -#ifdef Q_WS_WIN -# define _POSIX_ -# include <limits.h> -# undef _POSIX_ -#endif +#ifdef Q_OS_WIN +#undef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN + +// lib/Utils needs defines for Windows 8 +#undef WINVER +#define WINVER 0x0602 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0602 + +#define NOHELP +#include <qt_windows.h> + +#undef DELETE +#undef IN +#undef OUT +#undef ERROR +#undef ABSOLUTE + +#define _POSIX_ +#include <limits.h> +#undef _POSIX_ +#endif // Q_OS_WIN #include <QCoreApplication> #include <QList> diff --git a/src/tools/perfparser b/src/tools/perfparser -Subproject f010f12d68fa5269e6b7e16b8c2c2dffcb97a26 +Subproject d25737577023ce9fa3bd593f22fa23c3fcaedbf diff --git a/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp b/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp index 0c11438e12..f6126b73af 100644 --- a/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp +++ b/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp @@ -70,7 +70,8 @@ void scanDir(const QString &dir) paths.maybeInsert(Utils::FilePath::fromString(dir), Dialect::Qml); ModelManagerInterface::importScan(result, ModelManagerInterface::workingCopy(), paths, ModelManagerInterface::instance(), false); - ViewerContext vCtx = ViewerContext(QStringList(), QStringList(dir)); + ViewerContext vCtx; + vCtx.paths.append(dir); Snapshot snap = ModelManagerInterface::instance()->snapshot(); ImportDependencies *iDeps = snap.importDependencies(); @@ -181,7 +182,8 @@ void tst_ImportCheck::test() lPaths.maybeInsert(Utils::FilePath::fromString(path), Dialect::Qml); ModelManagerInterface::importScan(result, ModelManagerInterface::workingCopy(), lPaths, ModelManagerInterface::instance(), false); - ViewerContext vCtx(QStringList(), paths); + ViewerContext vCtx; + vCtx.paths.append(paths); Snapshot snap = ModelManagerInterface::instance()->snapshot(); ImportDependencies *iDeps = snap.importDependencies(); diff --git a/tests/manual/genericproject/Makefile b/tests/manual/genericproject/Makefile new file mode 100644 index 0000000000..c8dc9d0154 --- /dev/null +++ b/tests/manual/genericproject/Makefile @@ -0,0 +1,18 @@ +CC := g++ +FLAGS := +FILES := $(shell find . -name '*.cpp' -o -name '*.h') +DESTNAME:= generic + +.PHONY: all clean + +TARGETS := Generic + +all: $(TARGETS) + +clean: + find . -type f -name '*.o' -delete + rm -rf .obj + rm -f generic + +$(TARGETS): + $(CC) $(FLAGS) $(FILES) -o $(DESTNAME) diff --git a/tests/manual/genericproject/genericproject.cflags b/tests/manual/genericproject/genericproject.cflags new file mode 100644 index 0000000000..85d51b3f9a --- /dev/null +++ b/tests/manual/genericproject/genericproject.cflags @@ -0,0 +1 @@ +-std=c17 diff --git a/tests/manual/genericproject/genericproject.config b/tests/manual/genericproject/genericproject.config new file mode 100644 index 0000000000..e0284f4257 --- /dev/null +++ b/tests/manual/genericproject/genericproject.config @@ -0,0 +1,2 @@ +// Add predefined macros for your project here. For example: +// #define THE_ANSWER 42 diff --git a/tests/manual/genericproject/genericproject.creator b/tests/manual/genericproject/genericproject.creator new file mode 100644 index 0000000000..e94cbbd302 --- /dev/null +++ b/tests/manual/genericproject/genericproject.creator @@ -0,0 +1 @@ +[General] diff --git a/tests/manual/genericproject/genericproject.cxxflags b/tests/manual/genericproject/genericproject.cxxflags new file mode 100644 index 0000000000..2d81d9d6e3 --- /dev/null +++ b/tests/manual/genericproject/genericproject.cxxflags @@ -0,0 +1 @@ +-std=c++17 diff --git a/tests/manual/genericproject/genericproject.files b/tests/manual/genericproject/genericproject.files new file mode 100644 index 0000000000..5454ad1511 --- /dev/null +++ b/tests/manual/genericproject/genericproject.files @@ -0,0 +1,2 @@ +main.cpp +Makefile diff --git a/tests/manual/genericproject/genericproject.includes b/tests/manual/genericproject/genericproject.includes new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/manual/genericproject/genericproject.includes diff --git a/tests/manual/genericproject/main.cpp b/tests/manual/genericproject/main.cpp new file mode 100644 index 0000000000..b007649eb1 --- /dev/null +++ b/tests/manual/genericproject/main.cpp @@ -0,0 +1,7 @@ +#include <iostream> + +int main() +{ + std::cout << "Generic hi!\n"; + return 0; +} |