From 86d4fbab79a0efe9ca0ada6ee46256f26a2fdf8e Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Wed, 7 Jun 2023 15:52:58 +0300 Subject: [PATCH] QmlDesigner: Import only mandatory libraries or directories Only mandatory files are imported by the newly created component. In the case that the import data is empty, All parent imports would be included. Task-number: QDS-9829 Change-Id: Ie96e2bc04a10e00b15ae12c5e58b5dc2392886ae Reviewed-by: Thomas Hartmann Reviewed-by: Miikka Heikkinen Reviewed-by: Qt CI Bot --- .../include/basetexteditmodifier.h | 2 +- .../include/componenttextmodifier.h | 2 +- .../designercore/include/nodemetainfo.h | 1 + .../include/plaintexteditmodifier.h | 2 +- .../designercore/include/textmodifier.h | 2 +- .../designercore/metainfo/nodemetainfo.cpp | 50 +++++++++++++++++++ .../model/basetexteditmodifier.cpp | 5 +- .../designercore/model/rewriterview.cpp | 17 ++++++- .../qmljscomponentfromobjectdef.cpp | 20 +++----- .../qmljseditor/qmljscomponentfromobjectdef.h | 3 +- src/plugins/qmljseditor/qmljsquickfix.h | 4 +- src/plugins/qmljseditor/qmljsquickfixes.cpp | 6 ++- src/plugins/qmljseditor/qmljswrapinloader.cpp | 3 +- .../qmljstools/qmljsrefactoringchanges.cpp | 12 +++++ .../qmljstools/qmljsrefactoringchanges.h | 1 + 15 files changed, 106 insertions(+), 24 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/include/basetexteditmodifier.h b/src/plugins/qmldesigner/designercore/include/basetexteditmodifier.h index 3bbd9d74298..23b8dc30bda 100644 --- a/src/plugins/qmldesigner/designercore/include/basetexteditmodifier.h +++ b/src/plugins/qmldesigner/designercore/include/basetexteditmodifier.h @@ -25,7 +25,7 @@ public: TextEditor::TabSettings tabSettings() const override; bool renameId(const QString &oldId, const QString &newId) override; - bool moveToComponent(int nodeOffset) override; + bool moveToComponent(int nodeOffset, const QString &importData) override; QStringList autoComplete(QTextDocument *textDocument, int position, bool explicitComplete) override; private: diff --git a/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h b/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h index 3210734e47f..a65e934c46a 100644 --- a/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h +++ b/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h @@ -36,7 +36,7 @@ public: { return false; } QStringList autoComplete(QTextDocument * textDocument, int position, bool explicitComplete) override { return m_originalModifier->autoComplete(textDocument, position, explicitComplete); } - bool moveToComponent(int /* nodeOffset */) override + bool moveToComponent(int /* nodeOffset */, const QString & /* importData */) override { return false; } private: diff --git a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h index 0ee4e19fe37..3736079cdc2 100644 --- a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h +++ b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h @@ -194,6 +194,7 @@ public: bool isEnumeration() const; QString importDirectoryPath() const; + QString requiredImportString() const; friend bool operator==(const NodeMetaInfo &first, const NodeMetaInfo &second) { diff --git a/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h b/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h index 4172e8921ee..32a9480d55c 100644 --- a/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h +++ b/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h @@ -50,7 +50,7 @@ public: QStringList autoComplete(QTextDocument * /*textDocument*/, int /*position*/, bool /*explicitComplete*/) override { return QStringList(); } - bool moveToComponent(int /* nodeOffset */) override + bool moveToComponent(int /* nodeOffset */, const QString & /* importData */) override { return false; } private: diff --git a/src/plugins/qmldesigner/designercore/include/textmodifier.h b/src/plugins/qmldesigner/designercore/include/textmodifier.h index fb442a8aca7..e361d806a16 100644 --- a/src/plugins/qmldesigner/designercore/include/textmodifier.h +++ b/src/plugins/qmldesigner/designercore/include/textmodifier.h @@ -68,7 +68,7 @@ public: virtual bool renameId(const QString &oldId, const QString &newId) = 0; virtual QStringList autoComplete(QTextDocument * /*textDocument*/, int /*position*/, bool explicitComplete = true) = 0; - virtual bool moveToComponent(int nodeOffset) = 0; + virtual bool moveToComponent(int nodeOffset, const QString &importData) = 0; signals: void textChanged(); diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp index 5208428ca42..016117ab9cd 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp @@ -623,6 +623,7 @@ public: QString componentFileName() const; QString importDirectoryPath() const; + Import requiredImport() const; static std::shared_ptr create(Model *model, const TypeName &type, @@ -1228,6 +1229,43 @@ QString NodeMetaInfoPrivate::importDirectoryPath() const return QString(); } +Import NodeMetaInfoPrivate::requiredImport() const +{ + if (!isValid()) + return {}; + + const auto *imports = context()->imports(document()); + ImportInfo importInfo = imports->info(lookupNameComponent().constLast(), context().data()); + + if (importInfo.type() == ImportType::Directory) { + return Import::createFileImport(importInfo.name(), + importInfo.version().toString(), + importInfo.as()); + } else if (importInfo.type() == ImportType::Library) { + const QStringList importPaths = model()->importPaths(); + for (const QString &importPath : importPaths) { + const QDir importDir(importPath); + const QString targetPathVersion = importDir.filePath( + importInfo.path() + '.' + QString::number(importInfo.version().majorVersion())); + if (QDir(targetPathVersion).exists()) { + return Import::createLibraryImport(importInfo.name(), + importInfo.version().toString(), + importInfo.as(), + {targetPathVersion}); + } + + const QString targetPath = importDir.filePath(importInfo.path()); + if (QDir(targetPath).exists()) { + return Import::createLibraryImport(importInfo.name(), + importInfo.version().toString(), + importInfo.as(), + {targetPath}); + } + } + } + return {}; +} + QString NodeMetaInfoPrivate::lookupName() const { QString className = QString::fromUtf8(m_qualfiedTypeName); @@ -1747,6 +1785,18 @@ QString NodeMetaInfo::importDirectoryPath() const return {}; } +QString NodeMetaInfo::requiredImportString() const +{ + if (!isValid()) + return {}; + + Import imp = m_privateData->requiredImport(); + if (!imp.isEmpty()) + return imp.toImportString(); + + return {}; +} + const Storage::Info::Type &NodeMetaInfo::typeData() const { if (!m_typeData) diff --git a/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp b/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp index 69c74ec6cf8..eb7f0604184 100644 --- a/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp +++ b/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp @@ -100,7 +100,7 @@ static QmlJS::AST::UiObjectDefinition *getObjectDefinition(const QList( @@ -115,7 +115,8 @@ bool BaseTextEditModifier::moveToComponent(int nodeOffset) QmlJSEditor::performComponentFromObjectDef(qobject_cast( m_textEdit), document->filePath().toString(), - object); + object, + importData); return true; } } diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index 60067a6bc91..1f80d6fe490 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -1031,11 +1032,25 @@ QSet > RewriterView::qrcMapping() const void RewriterView::moveToComponent(const ModelNode &modelNode) { + if (!modelNode.isValid()) + return; + int offset = nodeOffset(modelNode); + const QList nodes = modelNode.allSubModelNodesAndThisNode(); + QSet directPaths; - textModifier()->moveToComponent(offset); + for (const ModelNode &partialNode : nodes) { + QString importStr = partialNode.metaInfo().requiredImportString(); + if (importStr.size()) + directPaths << importStr; + } + QString importData = Utils::sorted(directPaths.values()).join(QChar::LineFeed); + if (importData.size()) + importData.append(QString(2, QChar::LineFeed)); + + textModifier()->moveToComponent(offset, importData); } QStringList RewriterView::autoComplete(const QString &text, int pos, bool explicitComplete) diff --git a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp index b29d1627db5..4f040d12dfc 100644 --- a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp +++ b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp @@ -79,7 +79,8 @@ public: } void performChanges(QmlJSRefactoringFilePtr currentFile, - const QmlJSRefactoringChanges &refactoring) override + const QmlJSRefactoringChanges &refactoring, + const QString &imports = QString()) override { QString componentName = m_componentName; @@ -128,18 +129,12 @@ public: const Utils::FilePath newFileName = path.pathAppended(componentName + QLatin1String(".") + suffix); - QString imports; - UiProgram *prog = currentFile->qmljsDocument()->qmlProgram(); - if (prog && prog->headers) { - const unsigned int start = currentFile->startOf(prog->headers->firstSourceLocation()); - const unsigned int end = currentFile->startOf(prog->members->member->firstSourceLocation()); - imports = currentFile->textOf(start, end); - } + QString qmlImports = imports.size() ? imports : currentFile->qmlImports(); const unsigned int start = currentFile->startOf(m_firstSourceLocation); const unsigned int end = currentFile->startOf(m_lastSourceLocation); - QString newComponentSource = imports + currentFile->textOf(start, end) - + QLatin1String("}\n"); + QString newComponentSource = qmlImports + currentFile->textOf(start, end) + + QLatin1String("}\n"); //Remove properties from resulting code... @@ -248,7 +243,8 @@ void matchComponentFromObjectDefQuickFix(const QmlJSQuickFixAssistInterface *int void performComponentFromObjectDef(QmlJSEditorWidget *editor, const QString &fileName, - QmlJS::AST::UiObjectDefinition *objDef) + QmlJS::AST::UiObjectDefinition *objDef, + const QString &importData) { QmlJSRefactoringChanges refactoring(QmlJS::ModelManagerInterface::instance(), QmlJS::ModelManagerInterface::instance()->snapshot()); @@ -257,7 +253,7 @@ void performComponentFromObjectDef(QmlJSEditorWidget *editor, QmlJSQuickFixAssistInterface interface(editor, TextEditor::AssistReason::ExplicitlyInvoked); Operation operation(&interface, objDef); - operation.performChanges(current, refactoring); + operation.performChanges(current, refactoring, importData); } } //namespace QmlJSEditor diff --git a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.h b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.h index 72a0f50e20e..1f723074556 100644 --- a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.h +++ b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.h @@ -15,6 +15,7 @@ QMLJSEDITOR_EXPORT void matchComponentFromObjectDefQuickFix( QMLJSEDITOR_EXPORT void performComponentFromObjectDef(QmlJSEditorWidget *editor, const QString &fileName, - QmlJS::AST::UiObjectDefinition *objDef); + QmlJS::AST::UiObjectDefinition *objDef, + const QString &importData); } // namespace QmlJSEditor diff --git a/src/plugins/qmljseditor/qmljsquickfix.h b/src/plugins/qmljseditor/qmljsquickfix.h index b050ba4d1f1..a787c0ed6d2 100644 --- a/src/plugins/qmljseditor/qmljsquickfix.h +++ b/src/plugins/qmljseditor/qmljsquickfix.h @@ -40,7 +40,9 @@ protected: using Range = Utils::ChangeSet::Range; virtual void performChanges(QmlJSTools::QmlJSRefactoringFilePtr currentFile, - const QmlJSTools::QmlJSRefactoringChanges &refactoring) = 0; + const QmlJSTools::QmlJSRefactoringChanges &refactoring, + const QString &imports = QString()) + = 0; const QmlJSTools::SemanticInfo &semanticInfo() const; diff --git a/src/plugins/qmljseditor/qmljsquickfixes.cpp b/src/plugins/qmljseditor/qmljsquickfixes.cpp index f6baa01509d..44ee1bd5226 100644 --- a/src/plugins/qmljseditor/qmljsquickfixes.cpp +++ b/src/plugins/qmljseditor/qmljsquickfixes.cpp @@ -50,7 +50,8 @@ public: } void performChanges(QmlJSRefactoringFilePtr currentFile, - const QmlJSRefactoringChanges &) override + const QmlJSRefactoringChanges &, + const QString &) override { Q_ASSERT(_objectInitializer); @@ -115,7 +116,8 @@ public: } void performChanges(QmlJSRefactoringFilePtr currentFile, - const QmlJSRefactoringChanges &) override + const QmlJSRefactoringChanges &, + const QString &) override { Utils::ChangeSet changes; const int insertLoc = _message.location.begin() - _message.location.startColumn + 1; diff --git a/src/plugins/qmljseditor/qmljswrapinloader.cpp b/src/plugins/qmljseditor/qmljswrapinloader.cpp index 91a762191aa..70dc321f419 100644 --- a/src/plugins/qmljseditor/qmljswrapinloader.cpp +++ b/src/plugins/qmljseditor/qmljswrapinloader.cpp @@ -90,7 +90,8 @@ public: } void performChanges(QmlJSRefactoringFilePtr currentFile, - const QmlJSRefactoringChanges &) override + const QmlJSRefactoringChanges &, + const QString &) override { UiScriptBinding *idBinding; const QString id = idOfObject(m_objDef, &idBinding); diff --git a/src/plugins/qmljstools/qmljsrefactoringchanges.cpp b/src/plugins/qmljstools/qmljsrefactoringchanges.cpp index 635be5a51f6..e431b6ef718 100644 --- a/src/plugins/qmljstools/qmljsrefactoringchanges.cpp +++ b/src/plugins/qmljstools/qmljsrefactoringchanges.cpp @@ -136,6 +136,18 @@ Document::Ptr QmlJSRefactoringFile::qmljsDocument() const return m_qmljsDocument; } +QString QmlJSRefactoringFile::qmlImports() const +{ + QString imports; + QmlJS::AST::UiProgram *prog = qmljsDocument()->qmlProgram(); + if (prog && prog->headers) { + const unsigned int start = startOf(prog->headers->firstSourceLocation()); + const unsigned int end = startOf(prog->members->member->firstSourceLocation()); + imports = textOf(start, end); + } + return imports; +} + unsigned QmlJSRefactoringFile::startOf(const SourceLocation &loc) const { return position(loc.startLine, loc.startColumn); diff --git a/src/plugins/qmljstools/qmljsrefactoringchanges.h b/src/plugins/qmljstools/qmljsrefactoringchanges.h index 33545e2bfc5..b95da2076cf 100644 --- a/src/plugins/qmljstools/qmljsrefactoringchanges.h +++ b/src/plugins/qmljstools/qmljsrefactoringchanges.h @@ -22,6 +22,7 @@ class QMLJSTOOLS_EXPORT QmlJSRefactoringFile: public TextEditor::RefactoringFile { public: QmlJS::Document::Ptr qmljsDocument() const; + QString qmlImports() const; /*! Returns the offset in the document for the start position of the given