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