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 <thomas.hartmann@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Ali Kianian
2023-06-07 15:52:58 +03:00
parent e2f5b37fce
commit 86d4fbab79
15 changed files with 106 additions and 24 deletions

View File

@@ -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:

View File

@@ -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:

View File

@@ -194,6 +194,7 @@ public:
bool isEnumeration() const;
QString importDirectoryPath() const;
QString requiredImportString() const;
friend bool operator==(const NodeMetaInfo &first, const NodeMetaInfo &second)
{

View File

@@ -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:

View File

@@ -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();

View File

@@ -623,6 +623,7 @@ public:
QString componentFileName() const;
QString importDirectoryPath() const;
Import requiredImport() const;
static std::shared_ptr<NodeMetaInfoPrivate> 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)

View File

@@ -100,7 +100,7 @@ static QmlJS::AST::UiObjectDefinition *getObjectDefinition(const QList<QmlJS::AS
return object;
}
bool BaseTextEditModifier::moveToComponent(int nodeOffset)
bool BaseTextEditModifier::moveToComponent(int nodeOffset, const QString &importData)
{
if (m_textEdit) {
if (auto document = qobject_cast<QmlJSEditor::QmlJSEditorDocument *>(
@@ -115,7 +115,8 @@ bool BaseTextEditModifier::moveToComponent(int nodeOffset)
QmlJSEditor::performComponentFromObjectDef(qobject_cast<QmlJSEditor::QmlJSEditorWidget *>(
m_textEdit),
document->filePath().toString(),
object);
object,
importData);
return true;
}
}

View File

@@ -32,6 +32,7 @@
#include <utils/qtcassert.h>
#include <QRegularExpression>
#include <QSet>
#include <utility>
#include <vector>
@@ -1031,11 +1032,25 @@ QSet<QPair<QString, QString> > RewriterView::qrcMapping() const
void RewriterView::moveToComponent(const ModelNode &modelNode)
{
if (!modelNode.isValid())
return;
int offset = nodeOffset(modelNode);
const QList<ModelNode> nodes = modelNode.allSubModelNodesAndThisNode();
QSet<QString> 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)

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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