aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorThe Qt Project <gerrit-noreply@qt-project.org>2024-01-18 12:32:01 +0000
committerThe Qt Project <gerrit-noreply@qt-project.org>2024-01-18 12:32:01 +0000
commit5772a85751b905fa070f9c11fc930cb256c231c5 (patch)
treee93dd6cb9e9a0d340f0ebbc8e833f0b601492c70 /src/plugins
parentd51e116ac4219f90ce8ca35e032f4387fe581a6f (diff)
parent399f7a1968c7d64580bdd209c4747a6979e07c93 (diff)
Merge "Merge remote-tracking branch 'origin/qds/dev'"
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/clangformat/clangformatbaseindenter.cpp1
-rw-r--r--src/plugins/cppeditor/cpptoolsreuse.cpp1
-rw-r--r--src/plugins/effectmakernew/compositionnode.cpp3
-rw-r--r--src/plugins/effectmakernew/effectmakermodel.cpp129
-rw-r--r--src/plugins/effectmakernew/effectmakermodel.h2
-rw-r--r--src/plugins/mcusupport/mcusupportimportprovider.cpp25
-rw-r--r--src/plugins/mcusupport/mcusupportimportprovider.h3
-rw-r--r--src/plugins/projectexplorer/abi.cpp19
-rw-r--r--src/plugins/qmldesigner/CMakeLists.txt1
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp44
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h6
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp164
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h6
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.cpp4
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h4
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp211
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h16
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.cpp113
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h18
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp9
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp47
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h2
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp15
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp21
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp207
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h9
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp36
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp2
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp18
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.cpp33
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.h13
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp23
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditoritem.h5
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorview.cpp30
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorview.h3
-rw-r--r--src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp14
-rw-r--r--src/plugins/qmldesigner/components/toolbar/toolbarbackend.h3
-rw-r--r--src/plugins/qmldesigner/designercore/include/qmlitemnode.h2
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp20
-rw-r--r--src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp6
-rw-r--r--src/plugins/qmldesigner/designmodewidget.cpp35
-rw-r--r--src/plugins/qmldesigner/designmodewidget.h1
-rw-r--r--src/plugins/qmlprojectmanager/qmlproject.cpp13
-rw-r--r--src/plugins/qmlprojectmanager/qmlproject.h2
-rw-r--r--src/plugins/qtsupport/baseqtversion.cpp9
-rw-r--r--src/plugins/studiowelcome/studiowelcomeplugin.cpp3
47 files changed, 931 insertions, 422 deletions
diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp
index ac788c8a4b..dbbacd48a9 100644
--- a/src/plugins/clangformat/clangformatbaseindenter.cpp
+++ b/src/plugins/clangformat/clangformatbaseindenter.cpp
@@ -389,6 +389,7 @@ Utils::ChangeSet convertReplacements(const QTextDocument *doc,
.size();
QString replacementText = QString::fromStdString(replacement.getReplacementText().str());
+ replacementText.replace("\r", "");
auto sameCharAt = [&](int replacementOffset) {
if (replacementText.size() <= replacementOffset || replacementOffset < 0)
return false;
diff --git a/src/plugins/cppeditor/cpptoolsreuse.cpp b/src/plugins/cppeditor/cpptoolsreuse.cpp
index c8ce0effea..d7e403a1cc 100644
--- a/src/plugins/cppeditor/cpptoolsreuse.cpp
+++ b/src/plugins/cppeditor/cpptoolsreuse.cpp
@@ -786,6 +786,7 @@ SearchResultItems symbolOccurrencesInDeclarationComments(
QList<Text::Range> symbolOccurrencesInText(const QTextDocument &doc, QStringView text, int offset,
const QString &symbolName)
{
+ QTC_ASSERT(!symbolName.isEmpty(), return QList<Text::Range>());
QList<Text::Range> ranges;
int index = 0;
while (true) {
diff --git a/src/plugins/effectmakernew/compositionnode.cpp b/src/plugins/effectmakernew/compositionnode.cpp
index 9412153dde..811cdbcb8f 100644
--- a/src/plugins/effectmakernew/compositionnode.cpp
+++ b/src/plugins/effectmakernew/compositionnode.cpp
@@ -113,6 +113,9 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c
m_fragmentCode = EffectUtils::codeFromJsonArray(json.value("fragmentCode").toArray());
m_vertexCode = EffectUtils::codeFromJsonArray(json.value("vertexCode").toArray());
+ if (json.contains("enabled"))
+ m_isEnabled = json["enabled"].toBool();
+
m_id = json.value("id").toString();
if (m_id.isEmpty() && !qenPath.isEmpty()) {
QString fileName = qenPath.split('/').last();
diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp
index 4fcb6686a7..dc71418f1d 100644
--- a/src/plugins/effectmakernew/effectmakermodel.cpp
+++ b/src/plugins/effectmakernew/effectmakermodel.cpp
@@ -87,6 +87,7 @@ bool EffectMakerModel::setData(const QModelIndex &index, const QVariant &value,
if (role == EnabledRole) {
m_nodes.at(index.row())->setIsEnabled(value.toBool());
bakeShaders();
+ setHasUnsavedChanges(true);
emit dataChanged(index, index, {role});
}
@@ -192,14 +193,17 @@ void EffectMakerModel::removeNode(int idx)
emit nodesChanged();
}
-void EffectMakerModel::clear()
+void EffectMakerModel::clear(bool clearName)
{
beginResetModel();
qDeleteAll(m_nodes);
m_nodes.clear();
endResetModel();
+
+ if (clearName)
+ setCurrentComposition("");
+
setHasUnsavedChanges(!m_currentComposition.isEmpty());
- setCurrentComposition("");
setIsEmpty(true);
emit nodesChanged();
@@ -413,6 +417,7 @@ void EffectMakerModel::setEffectError(const QString &errorMessage, int type, int
QString additionalErrorInfo = detectErrorMessage(errorMessage);
error.m_message = additionalErrorInfo + errorMessage;
m_effectErrors.insert(type, error);
+ qWarning() << QString("Effect error (line: %2): %1").arg(error.m_message, error.m_line);
Q_EMIT effectErrorChanged();
}
@@ -556,13 +561,23 @@ QString EffectMakerModel::getQmlEffectString()
{
QString s;
- s += QString("// Created with Qt Design Studio (version %1), %2\n\n")
- .arg(qApp->applicationVersion(), QDateTime::currentDateTime().toString());
- s += "import QtQuick\n";
- s += '\n';
- s += "Item {\n";
- s += " id: rootItem\n";
- s += '\n';
+ // _isEffectItem is type var to hide it from property view
+ QString header{
+R"(
+// Created with Qt Design Studio (version %1), %2
+
+import QtQuick
+
+Item {
+ id: rootItem
+
+ property var _isEffectItem
+ property Item _oldParent: null
+)"
+ };
+
+ s += header.arg(qApp->applicationVersion(), QDateTime::currentDateTime().toString());
+
if (m_shaderFeatures.enabled(ShaderFeatures::Source)) {
s += " // This is the main source for the effect\n";
s += " property Item source: null\n";
@@ -570,7 +585,7 @@ QString EffectMakerModel::getQmlEffectString()
if (m_shaderFeatures.enabled(ShaderFeatures::Time)
|| m_shaderFeatures.enabled(ShaderFeatures::Frame)) {
s += " // Enable this to animate iTime property\n";
- s += " property bool timeRunning: false\n";
+ s += " property bool timeRunning: true\n";
}
if (m_shaderFeatures.enabled(ShaderFeatures::Time)) {
s += " // When timeRunning is false, this can be used to control iTime manually\n";
@@ -580,7 +595,33 @@ QString EffectMakerModel::getQmlEffectString()
s += " // When timeRunning is false, this can be used to control iFrame manually\n";
s += " property int animatedFrame: frameAnimation.currentFrame\n";
}
- s += '\n';
+
+ QString parentChanged{
+R"(
+ onParentChanged: {
+ if (_oldParent && _oldParent !== parent) {
+ _oldParent.layer.enabled = false
+ _oldParent.layer.effect = null
+ %2
+ _oldParent.update()
+ _oldParent = null
+ }
+ if (parent) {
+ _oldParent = parent
+ parent.layer.enabled = true
+ parent.layer.effect = effectComponent
+ %1
+ }
+ }
+)"
+ };
+
+ parentChanged = parentChanged.arg(m_shaderFeatures.enabled(ShaderFeatures::Source)
+ ? QString("source = parent") : QString(),
+ m_shaderFeatures.enabled(ShaderFeatures::Source)
+ ? QString("source = null") : QString());
+ s += parentChanged;
+
// Custom properties
if (!m_exportedRootPropertiesString.isEmpty()) {
s += m_exportedRootPropertiesString;
@@ -595,19 +636,14 @@ QString EffectMakerModel::getQmlEffectString()
s += '\n';
}
- if (m_shaderFeatures.enabled(ShaderFeatures::BlurSources)) {
- s += " BlurHelper {\n";
- s += " id: blurHelper\n";
- s += " anchors.fill: parent\n";
- int blurMax = 32;
- if (g_propertyData.contains("BLUR_HELPER_MAX_LEVEL"))
- blurMax = g_propertyData["BLUR_HELPER_MAX_LEVEL"].toInt();
- s += QString(" property int blurMax: %1\n").arg(blurMax);
- s += " property real blurMultiplier: rootItem.blurMultiplier\n";
- s += " }\n";
- }
+ QString customImagesString = getQmlImagesString(true);
+ if (!customImagesString.isEmpty())
+ s += customImagesString;
+ s += " Component {\n";
+ s += " id: effectComponent\n";
s += getQmlComponentString(true);
+ s += " }\n";
s += "}\n";
return s;
}
@@ -651,7 +687,7 @@ void EffectMakerModel::saveComposition(const QString &name)
void EffectMakerModel::openComposition(const QString &path)
{
- clear();
+ clear(true);
const QString effectName = QFileInfo(path).baseName();
setCurrentComposition(effectName);
@@ -785,10 +821,10 @@ void EffectMakerModel::saveResources(const QString &name)
for (int i = 1; i < qmlStringList.size(); i++) {
QString line = qmlStringList.at(i).trimmed();
if (line.startsWith("vertexShader")) {
- QString vsLine = " vertexShader: '" + vsFilename + "'";
+ QString vsLine = " vertexShader: '" + vsFilename + "'";
qmlStringList[i] = vsLine;
} else if (line.startsWith("fragmentShader")) {
- QString fsLine = " fragmentShader: '" + fsFilename + "'";
+ QString fsLine = " fragmentShader: '" + fsFilename + "'";
qmlStringList[i] = fsLine;
}
}
@@ -1287,17 +1323,17 @@ void EffectMakerModel::updateCustomUniforms()
if (!uniform->description().isEmpty()) {
const QStringList descriptionLines = uniform->description().split('\n');
for (const QString &line : descriptionLines)
- exportedEffectPropertiesString += QStringLiteral(" // ") + line + '\n';
+ exportedEffectPropertiesString += QStringLiteral(" // ") + line + '\n';
}
- exportedEffectPropertiesString += QStringLiteral(" ") + readOnly
+ exportedEffectPropertiesString += QStringLiteral(" ") + readOnly
+ "property " + propertyType + " " + propertyName
+ boundValueString + '\n';
} else {
// Custom values are not added into root
exportedRootPropertiesString += " property " + propertyType + " " + propertyName
+ valueString + '\n';
- exportedEffectPropertiesString += QStringLiteral(" ")
- + readOnly + "property alias " + propertyName
+ exportedEffectPropertiesString += QStringLiteral(" ")
+ + readOnly + "property " + propertyType + " " + propertyName
+ ": rootItem." + uniform->name() + '\n';
}
}
@@ -1488,22 +1524,26 @@ QString EffectMakerModel::getQmlComponentString(bool localFiles)
{
if (localFiles) {
const QString parent = blurHelper ? QString("blurHelper.") : QString("rootItem.");
- return QString("readonly property alias %1: %2%3\n").arg(name, parent, var);
+ return QString("readonly property %1 %2: %3%4\n").arg(type, name, parent, var);
} else {
const QString parent = blurHelper ? "blurHelper." : QString();
return QString("readonly property %1 %2: %3%4\n").arg(type, name, parent, var);
}
};
- QString customImagesString = getQmlImagesString(localFiles);
QString s;
- QString l1 = localFiles ? QStringLiteral(" ") : QStringLiteral("");
- QString l2 = localFiles ? QStringLiteral(" ") : QStringLiteral(" ");
- QString l3 = localFiles ? QStringLiteral(" ") : QStringLiteral(" ");
+ QString l1 = localFiles ? QStringLiteral(" ") : QStringLiteral("");
+ QString l2 = localFiles ? QStringLiteral(" ") : QStringLiteral(" ");
+ QString l3 = localFiles ? QStringLiteral(" ") : QStringLiteral(" ");
if (!localFiles)
s += "import QtQuick\n";
s += l1 + "ShaderEffect {\n";
+
+ if (localFiles) {
+ // Explicit "source" property is required for render puppet to detect effect correctly
+ s += l2 + "property Item source: null\n";
+ }
if (m_shaderFeatures.enabled(ShaderFeatures::Source))
s += l2 + addProperty("iSource", "source", "Item");
if (m_shaderFeatures.enabled(ShaderFeatures::Time))
@@ -1529,15 +1569,18 @@ QString EffectMakerModel::getQmlComponentString(bool localFiles)
// and when in exported component, property with binding to root value.
s += localFiles ? m_exportedEffectPropertiesString : m_previewEffectPropertiesString;
- if (!customImagesString.isEmpty())
- s += '\n' + customImagesString;
+ if (!localFiles) {
+ QString customImagesString = getQmlImagesString(false);
+ if (!customImagesString.isEmpty())
+ s += '\n' + customImagesString;
+ }
s += '\n';
const QString vertFile = localFiles ? m_vertexShaderFilename : m_vertexShaderPreviewFilename;
const QString fragFile = localFiles ? m_fragmentShaderFilename : m_fragmentShaderPreviewFilename;
s += l2 + "vertexShader: 'file:///" + vertFile + "'\n";
s += l2 + "fragmentShader: 'file:///" + fragFile + "'\n";
- s += l2 + "anchors.fill: parent\n";
+ s += l2 + "anchors.fill: " + (localFiles ? "rootItem.source" : "parent") + "\n";
if (m_shaderFeatures.enabled(ShaderFeatures::GridMesh)) {
QString gridSize = QString("%1, %2").arg(m_shaderFeatures.gridMeshWidth())
.arg(m_shaderFeatures.gridMeshHeight());
@@ -1545,6 +1588,18 @@ QString EffectMakerModel::getQmlComponentString(bool localFiles)
s += l3 + QString("resolution: Qt.size(%1)\n").arg(gridSize);
s += l2 + "}\n";
}
+ if (localFiles && m_shaderFeatures.enabled(ShaderFeatures::BlurSources)) {
+ s += l2 + "BlurHelper {\n";
+ s += l3 + "id: blurHelper\n";
+ s += l3 + "source: rootItem.source\n";
+ int blurMax = 32;
+ if (g_propertyData.contains("BLUR_HELPER_MAX_LEVEL"))
+ blurMax = g_propertyData["BLUR_HELPER_MAX_LEVEL"].toInt();
+ s += l3 + QString("property int blurMax: %1\n").arg(blurMax);
+ s += l3 + "property real blurMultiplier: rootItem.blurMultiplier\n";
+ s += l2 + "}\n";
+ }
+
s += l1 + "}\n";
return s;
}
diff --git a/src/plugins/effectmakernew/effectmakermodel.h b/src/plugins/effectmakernew/effectmakermodel.h
index a25a4e4091..1bbac9cd55 100644
--- a/src/plugins/effectmakernew/effectmakermodel.h
+++ b/src/plugins/effectmakernew/effectmakermodel.h
@@ -66,7 +66,7 @@ public:
Q_INVOKABLE void moveNode(int fromIdx, int toIdx);
Q_INVOKABLE void removeNode(int idx);
- Q_INVOKABLE void clear();
+ Q_INVOKABLE void clear(bool clearName = false);
Q_INVOKABLE void assignToSelected();
Q_INVOKABLE QString getUniqueEffectName() const;
diff --git a/src/plugins/mcusupport/mcusupportimportprovider.cpp b/src/plugins/mcusupport/mcusupportimportprovider.cpp
index b78baf8bd9..f83dec6cb7 100644
--- a/src/plugins/mcusupport/mcusupportimportprovider.cpp
+++ b/src/plugins/mcusupport/mcusupportimportprovider.cpp
@@ -119,6 +119,30 @@ void McuSupportImportProvider::loadBuiltins(ImportsPerDocument *importsPerDocume
import.info = ImportInfo::moduleImport("qul", {1, 0}, QString());
getInterfacesImport(context->fileName(), importsPerDocument, import, valueOwner, snapshot);
imports->append(import);
+}
+
+FilePaths McuSupportImportProvider::prioritizeImportPaths(const Document *context,
+ const FilePaths &importPaths)
+{
+ if (!context)
+ return importPaths;
+ const std::optional<FilePath> cmakeFilesPathOpt = getTargetBuildFolder(context->fileName());
+ if (!cmakeFilesPathOpt)
+ return importPaths;
+ FilePaths ret;
+ // qmltocpp uses an incomplete QtQuick folder present in the build folder
+ // to avoid taking precedence over the correct qul_install/include/*/StyleDefault
+ // move the import path to be last
+ std::copy_if(importPaths.cbegin(),
+ importPaths.cend(),
+ std::back_inserter(ret),
+ [cmakeFilesPathOpt](const FilePath &path) { return path != *cmakeFilesPathOpt; });
+
+ // nothing was removed
+ if (ret.size() == importPaths.size())
+ return importPaths;
+ ret.push_back(*cmakeFilesPathOpt);
+ return ret;
};
void McuSupportImportProvider::getInterfacesImport(const FilePath &path,
@@ -156,6 +180,7 @@ std::optional<FilePath> McuSupportImportProvider::getFileModule(const FilePath &
const FilePath &inputFile) const
{
const auto doc = QJsonDocument::fromJson(inputFile.fileContents().value_or(""));
+
if (!doc.isObject())
return {};
diff --git a/src/plugins/mcusupport/mcusupportimportprovider.h b/src/plugins/mcusupport/mcusupportimportprovider.h
index c1a130ed3d..f7457751b0 100644
--- a/src/plugins/mcusupport/mcusupportimportprovider.h
+++ b/src/plugins/mcusupport/mcusupportimportprovider.h
@@ -29,6 +29,9 @@ public:
ValueOwner *valueOwner,
Snapshot *snapshot) override;
+ virtual Utils::FilePaths prioritizeImportPaths(const Document *context,
+ const Utils::FilePaths &importPaths) override;
+
// Add to the interfaces needed for a document
// path: opened qml document
// importsPerDocument: imports available in the document (considered imported)
diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp
index 07365fc5dd..d1bd01b89b 100644
--- a/src/plugins/projectexplorer/abi.cpp
+++ b/src/plugins/projectexplorer/abi.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "abi.h"
+#include "projectexplorerconstants.h"
#include <utils/algorithm.h>
#include <utils/environment.h>
@@ -437,6 +438,18 @@ static Abis abiOf(const QByteArray &data)
return result;
}
+static QString androidAbiFromAbi(const Abi &abi)
+{
+ QString androidAbi;
+ if (abi.architecture() == Abi::Architecture::ArmArchitecture)
+ androidAbi = QLatin1String(abi.wordWidth() == 64 ? Constants::ANDROID_ABI_ARM64_V8A
+ : Constants::ANDROID_ABI_ARMEABI_V7A);
+ else
+ androidAbi = QLatin1String(abi.wordWidth() == 64 ? Constants::ANDROID_ABI_X86_64
+ : Constants::ANDROID_ABI_X86);
+ return androidAbi;
+}
+
// --------------------------------------------------------------------------
// Abi
// --------------------------------------------------------------------------
@@ -908,7 +921,11 @@ Abi Abi::fromString(const QString &abiString)
return Abi(architecture, os, flavor, format, 0);
}
- return Abi(architecture, os, flavor, format, wordWidth);
+ Abi abi(architecture, os, flavor, format, wordWidth);
+ if (abi.os() == LinuxOS && abi.osFlavor() == AndroidLinuxFlavor)
+ abi.m_param = androidAbiFromAbi(abi);
+
+ return abi;
}
Abi::Architecture Abi::architectureFromString(const QString &a)
diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt
index e167a83db3..b13841019c 100644
--- a/src/plugins/qmldesigner/CMakeLists.txt
+++ b/src/plugins/qmldesigner/CMakeLists.txt
@@ -839,7 +839,6 @@ extend_qtc_plugin(QmlDesigner
collectiondetailssortfiltermodel.cpp collectiondetailssortfiltermodel.h
collectioneditorconstants.h
collectioneditorutils.cpp collectioneditorutils.h
- collectionimporttools.cpp collectionimporttools.h
collectionlistmodel.cpp collectionlistmodel.h
collectionsourcemodel.cpp collectionsourcemodel.h
collectionview.cpp collectionview.h
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp
index 4cc6717d91..90f0061c87 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp
+++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp
@@ -28,7 +28,7 @@ const QMap<DataTypeWarning::Warning, QString> DataTypeWarning::dataTypeWarnings
class CollectionDetails::Private
{
- using SourceFormat = CollectionEditor::SourceFormat;
+ using SourceFormat = CollectionEditorConstants::SourceFormat;
public:
QList<CollectionProperty> properties;
@@ -85,6 +85,24 @@ static QVariant valueToVariant(const QJsonValue &value, CollectionDetails::DataT
}
}
+static QJsonValue variantToJsonValue(const QVariant &variant)
+{
+ using VariantType = QVariant::Type;
+
+ switch (variant.type()) {
+ case VariantType::Bool:
+ return variant.toBool();
+ case VariantType::Double:
+ case VariantType::Int:
+ return variant.toDouble();
+ case VariantType::String:
+ case VariantType::Color:
+ case VariantType::Url:
+ default:
+ return variant.toString();
+ }
+}
+
CollectionDetails::CollectionDetails()
: d(new Private())
{}
@@ -101,7 +119,7 @@ CollectionDetails::~CollectionDetails() = default;
void CollectionDetails::resetDetails(const QStringList &propertyNames,
const QList<QJsonObject> &elements,
- CollectionEditor::SourceFormat format)
+ CollectionEditorConstants::SourceFormat format)
{
if (!isValid())
return;
@@ -238,6 +256,7 @@ bool CollectionDetails::setPropertyValue(int row, int column, const QVariant &va
return false;
element.insert(d->properties.at(column).name, QJsonValue::fromVariant(value));
+ markChanged();
return true;
}
@@ -277,8 +296,10 @@ bool CollectionDetails::setPropertyType(int column, DataType type)
for (QJsonObject &element : d->elements) {
if (element.contains(property.name)) {
- QJsonValue value = element.value(property.name);
- element.insert(property.name, valueToVariant(value, type).toJsonValue());
+ const QJsonValue value = element.value(property.name);
+ const QVariant properTypedValue = valueToVariant(value, type);
+ const QJsonValue properTypedJsonValue = variantToJsonValue(properTypedValue);
+ element.insert(property.name, properTypedJsonValue);
changed = true;
}
}
@@ -294,7 +315,7 @@ CollectionReference CollectionDetails::reference() const
return d->reference;
}
-CollectionEditor::SourceFormat CollectionDetails::sourceFormat() const
+CollectionEditorConstants::SourceFormat CollectionDetails::sourceFormat() const
{
return d->sourceFormat;
}
@@ -354,8 +375,10 @@ DataTypeWarning::Warning CollectionDetails::cellWarningCheck(int row, int column
const QString &propertyName = d->properties.at(column).name;
const QJsonObject &element = d->elements.at(row);
- if (element.isEmpty())
+ if (typeAt(column) == DataType::Unknown || element.isEmpty()
+ || data(row, column) == QVariant::fromValue(nullptr)) {
return DataTypeWarning::Warning::None;
+ }
if (element.contains(propertyName) && typeAt(column) != typeAt(row, column))
return DataTypeWarning::Warning::CellDataTypeMismatch;
@@ -458,16 +481,19 @@ void CollectionDetails::resetPropertyTypes()
resetPropertyType(property);
}
-QString CollectionDetails::getCollectionAsJsonString() const
+QJsonArray CollectionDetails::getCollectionAsJsonArray() const
{
QJsonArray collectionArray;
for (const QJsonObject &element : std::as_const(d->elements))
collectionArray.push_back(element);
- QString collectionString = QString::fromUtf8(QJsonDocument(collectionArray).toJson());
+ return collectionArray;
+}
- return collectionString;
+QString CollectionDetails::getCollectionAsJsonString() const
+{
+ return QString::fromUtf8(QJsonDocument(getCollectionAsJsonArray()).toJson());
}
QString CollectionDetails::getCollectionAsCsvString() const
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h
index c35068ce6f..9d8eb7eca0 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h
+++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h
@@ -70,7 +70,7 @@ public:
void resetDetails(const QStringList &propertyNames,
const QList<QJsonObject> &elements,
- CollectionEditor::SourceFormat format);
+ CollectionEditorConstants::SourceFormat format);
void insertColumn(const QString &propertyName,
int colIdx = -1,
const QVariant &defaultValue = {},
@@ -86,7 +86,7 @@ public:
bool setPropertyType(int column, DataType type);
CollectionReference reference() const;
- CollectionEditor::SourceFormat sourceFormat() const;
+ CollectionEditorConstants::SourceFormat sourceFormat() const;
QVariant data(int row, int column) const;
QString propertyAt(int column) const;
DataType typeAt(int column) const;
@@ -106,6 +106,8 @@ public:
QString getCollectionAsJsonString() const;
QString getCollectionAsCsvString() const;
+ QJsonArray getCollectionAsJsonArray() const;
+
static void registerDeclarativeType();
CollectionDetails &operator=(const CollectionDetails &other);
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp
index 2279b60d13..52d5a6e2ba 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp
+++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp
@@ -7,11 +7,16 @@
#include "collectioneditorutils.h"
#include "modelnode.h"
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <utils/fileutils.h>
#include <utils/qtcassert.h>
+#include <utils/textfileformat.h>
#include <QFile>
#include <QFileInfo>
#include <QJsonArray>
+#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
@@ -19,17 +24,27 @@ namespace {
QStringList getJsonHeaders(const QJsonArray &collectionArray)
{
- QSet<QString> result;
+ QSet<QString> resultSet;
+ QList<QString> result;
+
for (const QJsonValue &value : collectionArray) {
if (value.isObject()) {
const QJsonObject object = value.toObject();
- const QStringList headers = object.toVariantMap().keys();
- for (const QString &header : headers)
- result.insert(header);
+ QJsonObject::ConstIterator element = object.constBegin();
+ const QJsonObject::ConstIterator stopItem = object.constEnd();
+
+ while (element != stopItem) {
+ const QString property = element.key();
+ if (!resultSet.contains(property)) {
+ result.append(property);
+ resultSet.insert(property);
+ }
+ ++element;
+ }
}
}
- return result.values();
+ return result;
}
class CollectionDataTypeHelper
@@ -339,8 +354,10 @@ bool CollectionDetailsModel::setPropertyType(int column, const QString &newValue
newValue));
if (changed) {
emit headerDataChanged(Qt::Horizontal, column, column);
- emit dataChanged(index(0, column), index(rowCount() - 1, column),
- {Qt::DisplayRole, DataTypeRole, DataTypeWarningRole});
+ emit dataChanged(
+ index(0, column),
+ index(rowCount() - 1, column),
+ {Qt::DisplayRole, Qt::EditRole, DataTypeRole, DataTypeWarningRole, ColumnDataTypeRole});
}
return changed;
@@ -353,8 +370,8 @@ bool CollectionDetailsModel::selectRow(int row)
const int rows = rowCount();
- if (m_selectedRow >= rows)
- return false;
+ if (row >= rows)
+ row = rows - 1;
selectColumn(-1);
@@ -388,7 +405,7 @@ QStringList CollectionDetailsModel::typesList()
void CollectionDetailsModel::loadCollection(const ModelNode &sourceNode, const QString &collection)
{
- QString fileName = CollectionEditor::getSourceCollectionPath(sourceNode);
+ QString fileName = CollectionEditorUtils::getSourceCollectionPath(sourceNode);
CollectionReference newReference{sourceNode, collection};
bool alreadyOpen = m_openedCollections.contains(newReference);
@@ -403,21 +420,83 @@ void CollectionDetailsModel::loadCollection(const ModelNode &sourceNode, const Q
} else {
deselectAll();
switchToCollection(newReference);
- if (sourceNode.type() == CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME)
+ if (sourceNode.type() == CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME)
loadJsonCollection(fileName, collection);
- else if (sourceNode.type() == CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME)
+ else if (sourceNode.type() == CollectionEditorConstants::CSVCOLLECTIONMODEL_TYPENAME)
loadCsvCollection(fileName, collection);
}
}
-bool CollectionDetailsModel::saveCurrentCollection()
+bool CollectionDetailsModel::saveDataStoreCollections()
{
- return saveCollection({}, &m_currentCollection);
+ const ModelNode node = m_currentCollection.reference().node;
+ const Utils::FilePath path = CollectionEditorUtils::dataStoreJsonFilePath();
+ Utils::FileReader fileData;
+ Utils::FileSaver sourceFile(path);
+
+ if (!fileData.fetch(path)) {
+ qWarning() << Q_FUNC_INFO << "Cannot read the json file:" << fileData.errorString();
+ return false;
+ }
+
+ QJsonParseError jpe;
+ QJsonDocument document = QJsonDocument::fromJson(fileData.data(), &jpe);
+
+ if (jpe.error == QJsonParseError::NoError) {
+ QJsonObject obj = document.object();
+
+ QList<CollectionDetails> collectionsToBeSaved;
+ for (CollectionDetails &openedCollection : m_openedCollections) {
+ const CollectionReference reference = openedCollection.reference();
+ if (reference.node == node) {
+ obj.insert(reference.name, openedCollection.getCollectionAsJsonArray());
+ collectionsToBeSaved << openedCollection;
+ }
+ }
+
+ document.setObject(obj);
+ bool saved = sourceFile.write(document.toJson());
+ saved &= sourceFile.finalize();
+
+ if (saved) {
+ const CollectionReference currentReference = m_currentCollection.reference();
+ for (CollectionDetails &collection : collectionsToBeSaved) {
+ collection.markSaved();
+ const CollectionReference reference = collection.reference();
+ if (reference != currentReference)
+ closeCollectionIfSaved(reference);
+ }
+ return true;
+ }
+ }
+ return false;
}
-bool CollectionDetailsModel::exportCollection(const QString &filePath)
+bool CollectionDetailsModel::exportCollection(const QUrl &url)
{
- return saveCollection(filePath, &m_currentCollection);
+ using Core::EditorManager;
+ using Utils::FilePath;
+ using Utils::TextFileFormat;
+
+ QTC_ASSERT(m_currentCollection.isValid(), return false);
+
+ bool saved = false;
+ const FilePath filePath = FilePath::fromUserInput(url.isLocalFile() ? url.toLocalFile()
+ : url.toString());
+ const QString saveFormat = filePath.toFileInfo().suffix().toLower();
+ const QString content = saveFormat == "csv" ? m_currentCollection.getCollectionAsCsvString()
+ : m_currentCollection.getCollectionAsJsonString();
+
+ TextFileFormat textFileFormat;
+ textFileFormat.codec = EditorManager::defaultTextCodec();
+ textFileFormat.lineTerminationMode = EditorManager::defaultLineEnding();
+ QString errorMessage;
+ saved = textFileFormat.writeFile(filePath, content, &errorMessage);
+
+ if (!saved)
+ qWarning() << Q_FUNC_INFO << "Unable to write file" << errorMessage;
+
+ return saved;
}
void CollectionDetailsModel::updateEmpty()
@@ -453,19 +532,19 @@ void CollectionDetailsModel::closeCollectionIfSaved(const CollectionReference &c
if (!collectionDetails.isChanged())
m_openedCollections.remove(collection);
-
- m_currentCollection = CollectionDetails{};
}
void CollectionDetailsModel::closeCurrentCollectionIfSaved()
{
- if (m_currentCollection.isValid())
+ if (m_currentCollection.isValid()) {
closeCollectionIfSaved(m_currentCollection.reference());
+ m_currentCollection = CollectionDetails{};
+ }
}
void CollectionDetailsModel::loadJsonCollection(const QString &source, const QString &collection)
{
- using CollectionEditor::SourceFormat;
+ using CollectionEditorConstants::SourceFormat;
QFile sourceFile(source);
QJsonArray collectionNodes;
@@ -510,7 +589,7 @@ void CollectionDetailsModel::loadJsonCollection(const QString &source, const QSt
void CollectionDetailsModel::loadCsvCollection(const QString &source,
[[maybe_unused]] const QString &collectionName)
{
- using CollectionEditor::SourceFormat;
+ using CollectionEditorConstants::SourceFormat;
QFile sourceFile(source);
QStringList headers;
@@ -594,49 +673,6 @@ void CollectionDetailsModel::setCollectionName(const QString &newCollectionName)
}
}
-bool CollectionDetailsModel::saveCollection(const QString &filePath, CollectionDetails *collection)
-{
- bool saved = false;
-
- auto saveSingleCollection = [&](CollectionDetails &singleCollection) {
-
- const ModelNode node = singleCollection.reference().node;
- QString path = CollectionEditor::getSourceCollectionPath(node);
- QString saveFormat = CollectionEditor::getSourceCollectionType(node);
-
- if (!filePath.isEmpty()) {
- QUrl url(filePath);
- path = url.isLocalFile() ? QFileInfo(url.toLocalFile()).absoluteFilePath() : url.toString();
- saveFormat = url.isLocalFile() ? QFileInfo(url.toLocalFile()).suffix().toLower() : saveFormat;
- }
-
- saved = saveCollectionFromString(path, (saveFormat == "json") ? singleCollection.getCollectionAsJsonString() :
- (saveFormat == "csv") ? singleCollection.getCollectionAsCsvString() : QString());
-
- if (saved && filePath.isEmpty())
- singleCollection.markSaved();
- };
-
- if (!collection) {
- for (CollectionDetails &openedCollection : m_openedCollections)
- saveSingleCollection(openedCollection);
- } else {
- saveSingleCollection(*collection);
- }
-
- return saved;
-}
-
-bool CollectionDetailsModel::saveCollectionFromString(const QString &path, const QString &content)
-{
- QFile file(path);
-
- if (file.open(QFile::WriteOnly) && file.write(content.toUtf8()))
- return true;
-
- return false;
-}
-
QString CollectionDetailsModel::warningToString(DataTypeWarning::Warning warning) const
{
return DataTypeWarning::getDataTypeWarningString(warning);
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h
index bf87d3838f..4fef84a3df 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h
+++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h
@@ -62,8 +62,8 @@ public:
void loadCollection(const ModelNode &sourceNode, const QString &collection);
- Q_INVOKABLE bool saveCurrentCollection();
- Q_INVOKABLE bool exportCollection(const QString &filePath);
+ Q_INVOKABLE bool saveDataStoreCollections();
+ Q_INVOKABLE bool exportCollection(const QUrl &url);
signals:
void collectionNameChanged(const QString &collectionName);
@@ -81,8 +81,6 @@ private:
void setCollectionName(const QString &newCollectionName);
void loadJsonCollection(const QString &source, const QString &collection);
void loadCsvCollection(const QString &source, const QString &collectionName);
- bool saveCollection(const QString &filePath = {}, CollectionDetails *collection = nullptr);
- bool saveCollectionFromString(const QString &path, const QString &content);
QVariant variantFromString(const QString &value);
QHash<CollectionReference, CollectionDetails> m_openedCollections;
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.cpp
index 50fcadd494..f56bb36e88 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.cpp
+++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.cpp
@@ -80,7 +80,9 @@ bool CollectionDetailsSortFilterModel::lessThan(const QModelIndex &sourceleft,
if (sourceleft.column() == sourceRight.column()) {
int column = sourceleft.column();
CollectionDetails::DataType columnType = m_source->propertyDataType(column);
- return CollectionEditor::variantIslessThan(sourceleft.data(), sourceRight.data(), columnType);
+ return CollectionEditorUtils::variantIslessThan(sourceleft.data(),
+ sourceRight.data(),
+ columnType);
}
return false;
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h
index e914891de3..a591719d87 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h
+++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h
@@ -3,7 +3,7 @@
#pragma once
-namespace QmlDesigner::CollectionEditor {
+namespace QmlDesigner::CollectionEditorConstants {
enum class SourceFormat { Unknown, Json, Csv };
@@ -17,4 +17,4 @@ inline constexpr char CSVCOLLECTIONMODEL_TYPENAME[] = "QtQuick.Studio.Ut
inline constexpr char JSONCOLLECTIONCHILDMODEL_TYPENAME[] = "QtQuick.Studio.Utils.ChildListModel";
inline constexpr char JSONBACKEND_TYPENAME[] = "JsonData";
-} // namespace QmlDesigner::CollectionEditor
+} // namespace QmlDesigner::CollectionEditorConstants
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp
index f48b6547ae..33867228d5 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp
+++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp
@@ -18,7 +18,10 @@
#include <QColor>
#include <QJsonArray>
+#include <QJsonDocument>
#include <QJsonObject>
+#include <QJsonParseError>
+#include <QJsonValue>
#include <QUrl>
namespace {
@@ -104,32 +107,32 @@ inline Utils::FilePath qmlDirFilePath()
} // namespace
-namespace QmlDesigner::CollectionEditor {
+namespace QmlDesigner::CollectionEditorUtils {
bool variantIslessThan(const QVariant &a, const QVariant &b, CollectionDetails::DataType type)
{
return std::visit(LessThanVisitor{}, valueToVariant(a, type), valueToVariant(b, type));
}
-SourceFormat getSourceCollectionFormat(const ModelNode &node)
+CollectionEditorConstants::SourceFormat getSourceCollectionFormat(const ModelNode &node)
{
using namespace QmlDesigner;
- if (node.type() == CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME)
- return CollectionEditor::SourceFormat::Json;
+ if (node.type() == CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME)
+ return CollectionEditorConstants::SourceFormat::Json;
- if (node.type() == CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME)
- return CollectionEditor::SourceFormat::Csv;
+ if (node.type() == CollectionEditorConstants::CSVCOLLECTIONMODEL_TYPENAME)
+ return CollectionEditorConstants::SourceFormat::Csv;
- return CollectionEditor::SourceFormat::Unknown;
+ return CollectionEditorConstants::SourceFormat::Unknown;
}
QString getSourceCollectionType(const ModelNode &node)
{
using namespace QmlDesigner;
- if (node.type() == CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME)
+ if (node.type() == CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME)
return "json";
- if (node.type() == CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME)
+ if (node.type() == CollectionEditorConstants::CSVCOLLECTIONMODEL_TYPENAME)
return "csv";
return {};
@@ -159,6 +162,20 @@ bool canAcceptCollectionAsModel(const ModelNode &node)
&& modelProperty.propertyType().isVariant();
}
+bool hasTextRoleProperty(const ModelNode &node)
+{
+ const NodeMetaInfo nodeMetaInfo = node.metaInfo();
+ if (!nodeMetaInfo.isValid())
+ return false;
+
+ const PropertyMetaInfo textRoleProperty = nodeMetaInfo.property("textRole");
+ if (!textRoleProperty.isValid())
+ return false;
+
+ return textRoleProperty.isWritable() && !textRoleProperty.isPrivate()
+ && textRoleProperty.propertyType().isString();
+}
+
QString getSourceCollectionPath(const ModelNode &dataStoreNode)
{
using Utils::FilePath;
@@ -280,4 +297,178 @@ bool ensureDataStoreExists(bool &justCreated)
return false;
}
-} // namespace QmlDesigner::CollectionEditor
+QJsonArray loadAsSingleJsonCollection(const QUrl &url)
+{
+ QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString());
+ QJsonArray collection;
+ QByteArray jsonData;
+ if (file.open(QFile::ReadOnly))
+ jsonData = file.readAll();
+
+ file.close();
+ if (jsonData.isEmpty())
+ return {};
+
+ QJsonParseError parseError;
+ QJsonDocument document = QJsonDocument::fromJson(jsonData, &parseError);
+ if (parseError.error != QJsonParseError::NoError)
+ return {};
+
+ auto refineJsonArray = [](const QJsonArray &array) -> QJsonArray {
+ QJsonArray resultArray;
+ for (const QJsonValue &collectionData : array) {
+ if (collectionData.isObject()) {
+ QJsonObject rowObject = collectionData.toObject();
+ const QStringList rowKeys = rowObject.keys();
+ for (const QString &key : rowKeys) {
+ QJsonValue cellValue = rowObject.value(key);
+ if (cellValue.isArray())
+ rowObject.remove(key);
+ }
+ resultArray.push_back(rowObject);
+ }
+ }
+ return resultArray;
+ };
+
+ if (document.isArray()) {
+ collection = refineJsonArray(document.array());
+ } else if (document.isObject()) {
+ QJsonObject documentObject = document.object();
+ const QStringList mainKeys = documentObject.keys();
+
+ bool arrayFound = false;
+ for (const QString &key : mainKeys) {
+ const QJsonValue &value = documentObject.value(key);
+ if (value.isArray()) {
+ arrayFound = true;
+ collection = refineJsonArray(value.toArray());
+ break;
+ }
+ }
+
+ if (!arrayFound) {
+ QJsonObject singleObject;
+ for (const QString &key : mainKeys) {
+ const QJsonValue value = documentObject.value(key);
+
+ if (!value.isObject())
+ singleObject.insert(key, value);
+ }
+ collection.push_back(singleObject);
+ }
+ }
+ return collection;
+}
+
+QJsonArray loadAsCsvCollection(const QUrl &url)
+{
+ QFile sourceFile(url.isLocalFile() ? url.toLocalFile() : url.toString());
+ QStringList headers;
+ QJsonArray elements;
+
+ if (sourceFile.open(QFile::ReadOnly)) {
+ QTextStream stream(&sourceFile);
+
+ if (!stream.atEnd())
+ headers = stream.readLine().split(',');
+
+ for (QString &header : headers)
+ header = header.trimmed();
+
+ if (!headers.isEmpty()) {
+ while (!stream.atEnd()) {
+ const QStringList recordDataList = stream.readLine().split(',');
+ int column = -1;
+ QJsonObject recordData;
+ for (const QString &cellData : recordDataList) {
+ if (++column == headers.size())
+ break;
+ recordData.insert(headers.at(column), cellData);
+ }
+ elements.append(recordData);
+ }
+ }
+ }
+
+ return elements;
+}
+
+QString getFirstColumnName(const QString &collectionName)
+{
+ Utils::FilePath dataStorePath = CollectionEditorUtils::dataStoreJsonFilePath();
+
+ if (!dataStorePath.exists())
+ return {};
+
+ Utils::FileReader dataStoreFile;
+ if (!dataStoreFile.fetch(dataStorePath))
+ return {};
+
+ QJsonParseError jsonError;
+ QJsonDocument dataStoreDocument = QJsonDocument::fromJson(dataStoreFile.data(), &jsonError);
+ if (jsonError.error == QJsonParseError::NoError) {
+ QJsonObject rootObject = dataStoreDocument.object();
+ if (rootObject.contains(collectionName)) {
+ QJsonArray collectionArray = rootObject.value(collectionName).toArray();
+ for (const QJsonValue &elementValue : std::as_const(collectionArray)) {
+ const QJsonObject elementObject = elementValue.toObject();
+ QJsonObject::ConstIterator element = elementObject.constBegin();
+ if (element != elementObject.constEnd())
+ return element.key();
+ }
+ } else {
+ qWarning() << Q_FUNC_INFO << __LINE__
+ << QString("Collection \"%1\" not found.").arg(collectionName);
+ }
+ } else {
+ qWarning() << Q_FUNC_INFO << __LINE__ << "Problem in reading json file."
+ << jsonError.errorString();
+ }
+
+ return {};
+}
+
+bool collectionHasColumn(const QString &collectionName, const QString &columnName)
+{
+ Utils::FilePath dataStorePath = CollectionEditorUtils::dataStoreJsonFilePath();
+
+ if (!dataStorePath.exists())
+ return false;
+
+ Utils::FileReader dataStoreFile;
+ if (!dataStoreFile.fetch(dataStorePath))
+ return false;
+
+ QJsonParseError jsonError;
+ QJsonDocument dataStoreDocument = QJsonDocument::fromJson(dataStoreFile.data(), &jsonError);
+ if (jsonError.error == QJsonParseError::NoError) {
+ QJsonObject rootObject = dataStoreDocument.object();
+ if (rootObject.contains(collectionName)) {
+ QJsonArray collectionArray = rootObject.value(collectionName).toArray();
+ for (const QJsonValue &elementValue : std::as_const(collectionArray)) {
+ const QJsonObject elementObject = elementValue.toObject();
+ QJsonObject::ConstIterator element = elementObject.constBegin();
+ const QJsonObject::ConstIterator stopItem = elementObject.constEnd();
+
+ while (element != stopItem) {
+ const QString keyName = element.key();
+ ++element;
+
+ if (columnName == keyName)
+ return true;
+ }
+ }
+ } else {
+ qWarning() << Q_FUNC_INFO << __LINE__
+ << QString("Collection \"%1\" not found.").arg(collectionName);
+ }
+ } else {
+ qWarning() << Q_FUNC_INFO << __LINE__ << "Problem in reading json file."
+ << jsonError.errorString();
+ }
+
+ return false;
+}
+
+} // namespace QmlDesigner::CollectionEditorUtils
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h
index 036304a381..46429f04b6 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h
+++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h
@@ -14,11 +14,11 @@ namespace Utils {
class FilePath;
}
-namespace QmlDesigner::CollectionEditor {
+namespace QmlDesigner::CollectionEditorUtils {
bool variantIslessThan(const QVariant &a, const QVariant &b, CollectionDetails::DataType type);
-SourceFormat getSourceCollectionFormat(const QmlDesigner::ModelNode &node);
+CollectionEditorConstants::SourceFormat getSourceCollectionFormat(const QmlDesigner::ModelNode &node);
QString getSourceCollectionType(const QmlDesigner::ModelNode &node);
@@ -34,6 +34,16 @@ bool ensureDataStoreExists(bool &justCreated);
bool canAcceptCollectionAsModel(const ModelNode &node);
+bool hasTextRoleProperty(const ModelNode &node);
+
QJsonArray defaultCollectionArray();
-} // namespace QmlDesigner::CollectionEditor
+QJsonArray loadAsSingleJsonCollection(const QUrl &url);
+
+QJsonArray loadAsCsvCollection(const QUrl &url);
+
+QString getFirstColumnName(const QString &collectionName);
+
+bool collectionHasColumn(const QString &collectionName, const QString &columnName);
+
+} // namespace QmlDesigner::CollectionEditorUtils
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.cpp
deleted file mode 100644
index 183730873d..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (C) 2023 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "collectionimporttools.h"
-
-#include <QFile>
-#include <QJsonArray>
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonParseError>
-#include <QJsonValue>
-#include <QUrl>
-
-namespace QmlDesigner::CollectionEditor::ImportTools {
-
-QJsonArray loadAsSingleJsonCollection(const QUrl &url)
-{
- QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString());
- QJsonArray collection;
- QByteArray jsonData;
- if (file.open(QFile::ReadOnly))
- jsonData = file.readAll();
-
- file.close();
- if (jsonData.isEmpty())
- return {};
-
- QJsonParseError parseError;
- QJsonDocument document = QJsonDocument::fromJson(jsonData, &parseError);
- if (parseError.error != QJsonParseError::NoError)
- return {};
-
- auto refineJsonArray = [](const QJsonArray &array) -> QJsonArray {
- QJsonArray resultArray;
- for (const QJsonValue &collectionData : array) {
- if (collectionData.isObject()) {
- QJsonObject rowObject = collectionData.toObject();
- const QStringList rowKeys = rowObject.keys();
- for (const QString &key : rowKeys) {
- QJsonValue cellValue = rowObject.value(key);
- if (cellValue.isArray())
- rowObject.remove(key);
- }
- resultArray.push_back(rowObject);
- }
- }
- return resultArray;
- };
-
- if (document.isArray()) {
- collection = refineJsonArray(document.array());
- } else if (document.isObject()) {
- QJsonObject documentObject = document.object();
- const QStringList mainKeys = documentObject.keys();
-
- bool arrayFound = false;
- for (const QString &key : mainKeys) {
- const QJsonValue &value = documentObject.value(key);
- if (value.isArray()) {
- arrayFound = true;
- collection = refineJsonArray(value.toArray());
- break;
- }
- }
-
- if (!arrayFound) {
- QJsonObject singleObject;
- for (const QString &key : mainKeys) {
- const QJsonValue value = documentObject.value(key);
-
- if (!value.isObject())
- singleObject.insert(key, value);
- }
- collection.push_back(singleObject);
- }
- }
- return collection;
-}
-
-QJsonArray loadAsCsvCollection(const QUrl &url)
-{
- QFile sourceFile(url.isLocalFile() ? url.toLocalFile() : url.toString());
- QStringList headers;
- QJsonArray elements;
-
- if (sourceFile.open(QFile::ReadOnly)) {
- QTextStream stream(&sourceFile);
-
- if (!stream.atEnd())
- headers = stream.readLine().split(',');
-
- for (QString &header : headers)
- header = header.trimmed();
-
- if (!headers.isEmpty()) {
- while (!stream.atEnd()) {
- const QStringList recordDataList = stream.readLine().split(',');
- int column = -1;
- QJsonObject recordData;
- for (const QString &cellData : recordDataList) {
- if (++column == headers.size())
- break;
- recordData.insert(headers.at(column), cellData);
- }
- elements.append(recordData);
- }
- }
- }
-
- return elements;
-}
-
-} // namespace QmlDesigner::CollectionEditor::ImportTools
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h b/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h
deleted file mode 100644
index 6ee4f590f7..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (C) 2023 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include <QtCore/qtconfigmacros.h>
-
-QT_BEGIN_NAMESPACE
-class QJsonArray;
-class QUrl;
-QT_END_NAMESPACE
-
-namespace QmlDesigner::CollectionEditor::ImportTools {
-
-QJsonArray loadAsSingleJsonCollection(const QUrl &url);
-QJsonArray loadAsCsvCollection(const QUrl &url);
-
-} // namespace QmlDesigner::CollectionEditor::ImportTools
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp
index d910569f0d..214ece078a 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp
+++ b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp
@@ -29,7 +29,7 @@ namespace QmlDesigner {
CollectionListModel::CollectionListModel(const ModelNode &sourceModel)
: QStringListModel()
, m_sourceNode(sourceModel)
- , m_sourceType(CollectionEditor::getSourceCollectionType(sourceModel))
+ , m_sourceType(CollectionEditorUtils::getSourceCollectionType(sourceModel))
{
connect(this, &CollectionListModel::modelReset, this, &CollectionListModel::updateEmpty);
connect(this, &CollectionListModel::rowsRemoved, this, &CollectionListModel::updateEmpty);
@@ -87,8 +87,11 @@ bool CollectionListModel::removeRows(int row, int count, const QModelIndex &pare
QStringList removedCollections = stringList().mid(row, count);
bool itemsRemoved = Super::removeRows(row, count, parent);
- if (itemsRemoved)
+ if (itemsRemoved) {
emit collectionsRemoved(removedCollections);
+ if (m_selectedIndex >= row)
+ selectCollectionIndex(m_selectedIndex - count, true);
+ }
return itemsRemoved;
}
@@ -121,7 +124,7 @@ ModelNode CollectionListModel::sourceNode() const
QString CollectionListModel::sourceAddress() const
{
- return CollectionEditor::getSourceCollectionPath(m_sourceNode);
+ return CollectionEditorUtils::getSourceCollectionPath(m_sourceNode);
}
bool CollectionListModel::contains(const QString &collectionName) const
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp
index 0c57f18778..1f9c7aa5d7 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp
+++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp
@@ -25,7 +25,8 @@ QSharedPointer<QmlDesigner::CollectionListModel> loadCollection(
const QmlDesigner::ModelNode &sourceNode,
QSharedPointer<QmlDesigner::CollectionListModel> initialCollection = {})
{
- using namespace QmlDesigner::CollectionEditor;
+ using namespace QmlDesigner::CollectionEditorConstants;
+ using namespace QmlDesigner::CollectionEditorUtils;
QString sourceFileAddress = getSourceCollectionPath(sourceNode);
QSharedPointer<QmlDesigner::CollectionListModel> collectionsList;
@@ -88,9 +89,9 @@ QVariant CollectionSourceModel::data(const QModelIndex &index, int role) const
case NodeRole:
return QVariant::fromValue(*collectionSource);
case CollectionTypeRole:
- return CollectionEditor::getSourceCollectionType(*collectionSource);
+ return CollectionEditorUtils::getSourceCollectionType(*collectionSource);
case SourceRole:
- return collectionSource->variantProperty(CollectionEditor::SOURCEFILE_PROPERTY).value();
+ return collectionSource->variantProperty(CollectionEditorConstants::SOURCEFILE_PROPERTY).value();
case SelectedRole:
return index.row() == m_selectedIndex;
case CollectionsRole:
@@ -116,7 +117,8 @@ bool CollectionSourceModel::setData(const QModelIndex &index, const QVariant &va
collectionName.setValue(value.toString());
} break;
case SourceRole: {
- auto sourceAddress = collectionSource.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY);
+ auto sourceAddress = collectionSource.variantProperty(
+ CollectionEditorConstants::SOURCEFILE_PROPERTY);
if (sourceAddress.value() == value)
return false;
@@ -281,13 +283,13 @@ bool CollectionSourceModel::addCollectionToSource(const ModelNode &node,
if (idx < 0)
return returnError(tr("Node is not indexed in the models."));
- if (node.type() != CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME)
+ if (node.type() != CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME)
return returnError(tr("Node should be a JSON model."));
if (collectionExists(node, collectionName))
return returnError(tr("A model with the identical name already exists."));
- QString sourceFileAddress = CollectionEditor::getSourceCollectionPath(node);
+ QString sourceFileAddress = CollectionEditorUtils::getSourceCollectionPath(node);
QFileInfo sourceFileInfo(sourceFileAddress);
if (!sourceFileInfo.isFile())
@@ -325,6 +327,7 @@ bool CollectionSourceModel::addCollectionToSource(const ModelNode &node,
return returnError(tr("No model is available for the JSON model group."));
collections->selectCollectionName(collectionName);
+ setSelectedCollectionName(collectionName);
return true;
} else {
return returnError(tr("JSON document type should be an object containing models."));
@@ -403,9 +406,11 @@ void CollectionSourceModel::onSelectedCollectionChanged(CollectionListModel *col
m_previousSelectedList = collectionList;
- emit collectionSelected(collectionList->collectionNameAt(collectionIndex));
+ setSelectedCollectionName(collectionList->collectionNameAt(collectionIndex));
selectSourceIndex(sourceIndex(collectionList->sourceNode()));
+ } else {
+ setSelectedCollectionName({});
}
}
@@ -413,7 +418,7 @@ void CollectionSourceModel::onCollectionNameChanged(CollectionListModel *collect
const QString &oldName, const QString &newName)
{
auto emitRenameWarning = [this](const QString &msg) -> void {
- emit this->warning(tr("Rename Model"), msg);
+ emit warning(tr("Rename Model"), msg);
};
const ModelNode node = collectionList->sourceNode();
@@ -424,16 +429,16 @@ void CollectionSourceModel::onCollectionNameChanged(CollectionListModel *collect
return;
}
- if (node.type() == CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME) {
+ if (node.type() == CollectionEditorConstants::CSVCOLLECTIONMODEL_TYPENAME) {
if (!setData(nodeIndex, newName, NameRole))
emitRenameWarning(tr("Can't rename the node"));
return;
- } else if (node.type() != CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME) {
+ } else if (node.type() != CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME) {
emitRenameWarning(tr("Invalid node type"));
return;
}
- QString sourceFileAddress = CollectionEditor::getSourceCollectionPath(node);
+ QString sourceFileAddress = CollectionEditorUtils::getSourceCollectionPath(node);
QFileInfo sourceFileInfo(sourceFileAddress);
if (!sourceFileInfo.isFile()) {
@@ -513,15 +518,15 @@ void CollectionSourceModel::onCollectionsRemoved(CollectionListModel *collection
return;
}
- if (node.type() == CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME) {
+ if (node.type() == CollectionEditorConstants::CSVCOLLECTIONMODEL_TYPENAME) {
removeSource(node);
return;
- } else if (node.type() != CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME) {
+ } else if (node.type() != CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME) {
emitDeleteWarning(tr("Invalid node type"));
return;
}
- QString sourceFileAddress = CollectionEditor::getSourceCollectionPath(node);
+ QString sourceFileAddress = CollectionEditorUtils::getSourceCollectionPath(node);
QFileInfo sourceFileInfo(sourceFileAddress);
if (!sourceFileInfo.isFile()) {
@@ -575,9 +580,11 @@ void CollectionSourceModel::onCollectionsRemoved(CollectionListModel *collection
}
for (const QString &collectionName : std::as_const(collectionsRemovedFromDocument))
- emit this->collectionRemoved(collectionName);
+ emit collectionRemoved(collectionName);
updateCollectionList(nodeIndex);
+ if (m_previousSelectedList == collectionList)
+ onSelectedCollectionChanged(collectionList, collectionList->selectedIndex());
}
}
@@ -607,12 +614,20 @@ void CollectionSourceModel::setSelectedIndex(int idx)
} else if (m_previousSelectedList) {
m_previousSelectedList->selectCollectionIndex(-1);
m_previousSelectedList = {};
- emit this->collectionSelected({});
+ setSelectedCollectionName({});
}
}
}
}
+void CollectionSourceModel::setSelectedCollectionName(const QString &collectionName)
+{
+ if (m_selectedCollectionName != collectionName) {
+ m_selectedCollectionName = collectionName;
+ emit collectionSelected(m_selectedCollectionName);
+ }
+}
+
void CollectionSourceModel::updateEmpty()
{
bool isEmptyNow = m_collectionSources.isEmpty();
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h
index 487b616b97..5ab77f2a98 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h
+++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h
@@ -87,6 +87,7 @@ private slots:
private:
void setSelectedIndex(int idx);
+ void setSelectedCollectionName(const QString &collectionName);
void updateEmpty();
void updateCollectionList(QModelIndex index);
void registerCollection(const QSharedPointer<CollectionListModel> &collection);
@@ -98,6 +99,7 @@ private:
QHash<qint32, int> m_sourceIndexHash; // internalId -> index
QList<QSharedPointer<CollectionListModel>> m_collectionList;
QPointer<CollectionListModel> m_previousSelectedList;
+ QString m_selectedCollectionName;
int m_selectedIndex = -1;
bool m_isEmpty = true;
};
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp
index f17abf5d9f..7f3ee7192a 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp
+++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp
@@ -31,7 +31,7 @@ namespace {
inline bool isStudioCollectionModel(const QmlDesigner::ModelNode &node)
{
- using namespace QmlDesigner::CollectionEditor;
+ using namespace QmlDesigner::CollectionEditorConstants;
return node.metaInfo().typeName() == JSONCOLLECTIONMODEL_TYPENAME
|| node.metaInfo().typeName() == CSVCOLLECTIONMODEL_TYPENAME;
}
@@ -151,7 +151,7 @@ void CollectionView::variantPropertiesChanged(const QList<VariantProperty> &prop
if (isStudioCollectionModel(node)) {
if (property.name() == "objectName")
m_widget->sourceModel()->updateNodeName(node);
- else if (property.name() == CollectionEditor::SOURCEFILE_PROPERTY)
+ else if (property.name() == CollectionEditorConstants::SOURCEFILE_PROPERTY)
m_widget->sourceModel()->updateNodeSource(node);
}
}
@@ -169,7 +169,8 @@ void CollectionView::selectedNodesChanged(const QList<ModelNode> &selectedNodeLi
bool singleSelectedHasModelProperty = false;
if (singleNonCollectionNodeSelected) {
const ModelNode selectedNode = selectedNodeList.first();
- singleSelectedHasModelProperty = CollectionEditor::canAcceptCollectionAsModel(selectedNode);
+ singleSelectedHasModelProperty = CollectionEditorUtils::canAcceptCollectionAsModel(
+ selectedNode);
}
m_widget->setTargetNodeSelected(singleSelectedHasModelProperty);
@@ -204,7 +205,7 @@ void CollectionView::addResource(const QUrl &url, const QString &name, const QSt
resourceMetaInfo.majorVersion(),
resourceMetaInfo.minorVersion());
VariantProperty sourceProperty = resourceNode.variantProperty(
- CollectionEditor::SOURCEFILE_PROPERTY);
+ CollectionEditorConstants::SOURCEFILE_PROPERTY);
VariantProperty nameProperty = resourceNode.variantProperty("objectName");
sourceProperty.setValue(sourceAddress);
nameProperty.setValue(name);
@@ -252,18 +253,18 @@ void CollectionView::refreshModel()
NodeMetaInfo CollectionView::jsonCollectionMetaInfo() const
{
- return model()->metaInfo(CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME);
+ return model()->metaInfo(CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME);
}
NodeMetaInfo CollectionView::csvCollectionMetaInfo() const
{
- return model()->metaInfo(CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME);
+ return model()->metaInfo(CollectionEditorConstants::CSVCOLLECTIONMODEL_TYPENAME);
}
void CollectionView::ensureStudioModelImport()
{
executeInTransaction(__FUNCTION__, [&] {
- Import import = Import::createLibraryImport(CollectionEditor::COLLECTIONMODEL_IMPORT);
+ Import import = Import::createLibraryImport(CollectionEditorConstants::COLLECTIONMODEL_IMPORT);
try {
if (!model()->hasImport(import, true, true))
model()->changeImports({import}, {});
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp
index 9b14c2cd03..39097cbeb3 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp
+++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp
@@ -6,7 +6,6 @@
#include "collectiondetailsmodel.h"
#include "collectiondetailssortfiltermodel.h"
#include "collectioneditorutils.h"
-#include "collectionimporttools.h"
#include "collectionsourcemodel.h"
#include "collectionview.h"
#include "qmldesignerconstants.h"
@@ -216,7 +215,7 @@ bool CollectionWidget::addCollection(const QString &collectionName,
if (collectionType == "json") {
QJsonObject jsonObject;
- jsonObject.insert(collectionName, CollectionEditor::defaultCollectionArray());
+ jsonObject.insert(collectionName, CollectionEditorUtils::defaultCollectionArray());
QFile sourceFile(sourcePath);
if (!sourceFile.open(QFile::WriteOnly)) {
@@ -258,10 +257,8 @@ bool CollectionWidget::addCollection(const QString &collectionName,
}
} else if (collectionType == "json") {
QString errorMsg;
- bool added = m_sourceModel->addCollectionToSource(node,
- collectionName,
- CollectionEditor::defaultCollectionArray(),
- &errorMsg);
+ bool added = m_sourceModel->addCollectionToSource(
+ node, collectionName, CollectionEditorUtils::defaultCollectionArray(), &errorMsg);
if (!added)
warn(tr("Can not add a model to the JSON file"), errorMsg);
return added;
@@ -274,10 +271,10 @@ bool CollectionWidget::importToJson(const QVariant &sourceNode,
const QString &collectionName,
const QUrl &url)
{
- using CollectionEditor::SourceFormat;
+ using CollectionEditorConstants::SourceFormat;
using Utils::FilePath;
const ModelNode node = sourceNode.value<ModelNode>();
- const SourceFormat nodeFormat = CollectionEditor::getSourceCollectionFormat(node);
+ const SourceFormat nodeFormat = CollectionEditorUtils::getSourceCollectionFormat(node);
QTC_ASSERT(node.isValid() && nodeFormat == SourceFormat::Json, return false);
FilePath fileInfo = FilePath::fromUserInput(url.isLocalFile() ? url.toLocalFile()
@@ -287,9 +284,9 @@ bool CollectionWidget::importToJson(const QVariant &sourceNode,
QJsonArray loadedCollection;
if (fileInfo.suffix() == "json")
- loadedCollection = CollectionEditor::ImportTools::loadAsSingleJsonCollection(url);
+ loadedCollection = CollectionEditorUtils::loadAsSingleJsonCollection(url);
else if (fileInfo.suffix() == "csv")
- loadedCollection = CollectionEditor::ImportTools::loadAsCsvCollection(url);
+ loadedCollection = CollectionEditorUtils::loadAsCsvCollection(url);
if (!loadedCollection.isEmpty()) {
const QString newCollectionName = generateUniqueCollectionName(node, collectionName);
@@ -327,7 +324,7 @@ bool CollectionWidget::addCollectionToDataStore(const QString &collectionName)
bool added = m_sourceModel->addCollectionToSource(node,
generateUniqueCollectionName(node,
collectionName),
- CollectionEditor::defaultCollectionArray(),
+ CollectionEditorUtils::defaultCollectionArray(),
&errorMsg);
if (!added)
warn(tr("Failed to add a model to the default model group"), errorMsg);
@@ -343,7 +340,7 @@ void CollectionWidget::assignCollectionToSelectedNode(const QString collectionNa
void CollectionWidget::ensureDataStoreExists()
{
bool filesJustCreated = false;
- bool filesExist = CollectionEditor::ensureDataStoreExists(filesJustCreated);
+ bool filesExist = CollectionEditorUtils::ensureDataStoreExists(filesJustCreated);
if (filesExist && filesJustCreated)
m_view->resetDataStoreNode();
}
diff --git a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp
index bebc60f1de..a1f82bbc65 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp
+++ b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp
@@ -7,6 +7,10 @@
#include "collectioneditorconstants.h"
#include "collectioneditorutils.h"
#include "model/qmltextgenerator.h"
+#include "plaintexteditmodifier.h"
+#include "qmldesignerbase/qmldesignerbaseplugin.h"
+#include "qmldesignerexternaldependencies.h"
+#include "rewriterview.h"
#include <model.h>
#include <nodemetainfo.h>
@@ -23,20 +27,25 @@
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
+#include <QPlainTextEdit>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
+#include <QScopedPointer>
namespace {
+inline constexpr char CHILDLISTMODEL_TYPENAME[] = "ChildListModel";
+
QmlDesigner::PropertyNameList createNameList(const QmlDesigner::ModelNode &node)
{
using QmlDesigner::AbstractProperty;
using QmlDesigner::PropertyName;
using QmlDesigner::PropertyNameList;
- static PropertyNameList defaultsNodeProps = {"id",
- QmlDesigner::CollectionEditor::SOURCEFILE_PROPERTY,
- QmlDesigner::CollectionEditor::JSONCHILDMODELNAME_PROPERTY,
- "backend"};
+ static PropertyNameList defaultsNodeProps = {
+ "id",
+ QmlDesigner::CollectionEditorConstants::SOURCEFILE_PROPERTY,
+ QmlDesigner::CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY,
+ "backend"};
PropertyNameList dynamicPropertyNames = Utils::transform(
node.dynamicProperties(),
[](const AbstractProperty &property) -> PropertyName { return property.name(); });
@@ -49,8 +58,8 @@ QmlDesigner::PropertyNameList createNameList(const QmlDesigner::ModelNode &node)
bool isValidCollectionPropertyName(const QString &collectionId)
{
static const QmlDesigner::PropertyNameList reservedKeywords = {
- QmlDesigner::CollectionEditor::SOURCEFILE_PROPERTY,
- QmlDesigner::CollectionEditor::JSONBACKEND_TYPENAME,
+ QmlDesigner::CollectionEditorConstants::SOURCEFILE_PROPERTY,
+ QmlDesigner::CollectionEditorConstants::JSONBACKEND_TYPENAME,
"backend",
"models",
};
@@ -59,6 +68,58 @@ bool isValidCollectionPropertyName(const QString &collectionId)
&& !reservedKeywords.contains(collectionId.toLatin1());
}
+QMap<QString, QmlDesigner::PropertyName> getModelIdMap(const QmlDesigner::ModelNode &rootNode)
+{
+ using namespace QmlDesigner;
+ QMap<QString, PropertyName> modelNameForId;
+
+ const QList<AbstractProperty> propertyNames = rootNode.dynamicProperties();
+
+ for (const AbstractProperty &property : std::as_const(propertyNames)) {
+ if (!property.isNodeProperty())
+ continue;
+
+ NodeProperty nodeProperty = property.toNodeProperty();
+ if (!nodeProperty.hasDynamicTypeName(CHILDLISTMODEL_TYPENAME))
+ continue;
+
+ ModelNode childNode = nodeProperty.modelNode();
+ if (childNode.hasProperty(CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY)) {
+ QString modelName = childNode
+ .property(CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY)
+ .toVariantProperty()
+ .value()
+ .toString();
+
+ if (!modelName.isEmpty())
+ modelNameForId.insert(modelName, property.name());
+ }
+ }
+ return modelNameForId;
+}
+
+void setQmlContextToModel(QmlDesigner::Model *model, const QString &qmlContext)
+{
+ using namespace QmlDesigner;
+ Q_ASSERT(model);
+
+ QScopedPointer<QPlainTextEdit> textEdit(new QPlainTextEdit);
+ QScopedPointer<NotIndentingTextEditModifier> modifier(
+ new NotIndentingTextEditModifier(textEdit.data()));
+ textEdit->hide();
+ textEdit->setPlainText(qmlContext);
+ QmlDesigner::ExternalDependencies externalDependencies{QmlDesignerBasePlugin::settings()};
+ QScopedPointer<RewriterView> rewriter(
+ new RewriterView(externalDependencies, QmlDesigner::RewriterView::Validate));
+
+ rewriter->setParent(model);
+ rewriter->setTextModifier(modifier.get());
+ rewriter->setCheckSemanticErrors(false);
+
+ model->attachView(rewriter.get());
+ model->detachView(rewriter.get());
+}
+
} // namespace
namespace QmlDesigner {
@@ -77,15 +138,16 @@ void DataStoreModelNode::reloadModel()
}
bool forceUpdate = false;
- const FilePath dataStoreQmlPath = CollectionEditor::dataStoreQmlFilePath();
- const FilePath dataStoreJsonPath = CollectionEditor::dataStoreJsonFilePath();
+ const FilePath dataStoreQmlPath = CollectionEditorUtils::dataStoreQmlFilePath();
+ const FilePath dataStoreJsonPath = CollectionEditorUtils::dataStoreJsonFilePath();
QUrl dataStoreQmlUrl = dataStoreQmlPath.toUrl();
if (dataStoreQmlPath.exists() && dataStoreJsonPath.exists()) {
if (!m_model.get() || m_model->fileUrl() != dataStoreQmlUrl) {
- m_model = Model::create(CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME, 1, 1);
+ m_model = Model::create(CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME, 1, 1);
forceUpdate = true;
- Import import = Import::createLibraryImport(CollectionEditor::COLLECTIONMODEL_IMPORT);
+ Import import = Import::createLibraryImport(
+ CollectionEditorConstants::COLLECTIONMODEL_IMPORT);
try {
if (!m_model->hasImport(import, true, true))
m_model->changeImports({import}, {});
@@ -102,8 +164,10 @@ void DataStoreModelNode::reloadModel()
m_dataRelativePath = dataStoreJsonPath.relativePathFrom(dataStoreQmlPath).toFSPathString();
- if (forceUpdate)
+ if (forceUpdate) {
+ preloadFile();
update();
+ }
}
QStringList DataStoreModelNode::collectionNames() const
@@ -143,6 +207,25 @@ void DataStoreModelNode::reset()
setCollectionNames({});
}
+void DataStoreModelNode::preloadFile()
+{
+ using Utils::FilePath;
+ using Utils::FileReader;
+
+ if (!m_model)
+ return;
+
+ const FilePath dataStoreQmlPath = dataStoreQmlFilePath();
+ FileReader dataStoreQmlFile;
+ QString sourceQmlContext;
+
+ if (dataStoreQmlFile.fetch(dataStoreQmlPath))
+ sourceQmlContext = QString::fromLatin1(dataStoreQmlFile.data());
+
+ setQmlContextToModel(m_model.get(), sourceQmlContext);
+ m_collectionPropertyNames = getModelIdMap(m_model->rootModelNode());
+}
+
void DataStoreModelNode::updateDataStoreProperties()
{
QTC_ASSERT(model(), return);
@@ -150,8 +233,6 @@ void DataStoreModelNode::updateDataStoreProperties()
ModelNode rootNode = modelNode();
QTC_ASSERT(rootNode.isValid(), return);
- static TypeName childNodeTypename = "ChildListModel";
-
QSet<QString> collectionNamesToBeAdded;
const QStringList allCollectionNames = m_collectionPropertyNames.keys();
for (const QString &collectionName : allCollectionNames)
@@ -165,12 +246,13 @@ void DataStoreModelNode::updateDataStoreProperties()
continue;
NodeProperty nodeProprty = property.toNodeProperty();
- if (!nodeProprty.hasDynamicTypeName(childNodeTypename))
+ if (!nodeProprty.hasDynamicTypeName(CHILDLISTMODEL_TYPENAME))
continue;
ModelNode childNode = nodeProprty.modelNode();
- if (childNode.hasProperty(CollectionEditor::JSONCHILDMODELNAME_PROPERTY)) {
- QString modelName = childNode.property(CollectionEditor::JSONCHILDMODELNAME_PROPERTY)
+ if (childNode.hasProperty(CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY)) {
+ QString modelName = childNode
+ .property(CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY)
.toVariantProperty()
.value()
.toString();
@@ -189,32 +271,17 @@ void DataStoreModelNode::updateDataStoreProperties()
QStringList collectionNamesLeft = collectionNamesToBeAdded.values();
Utils::sort(collectionNamesLeft);
- for (const QString &collectionName : std::as_const(collectionNamesLeft)) {
- PropertyName newPropertyName = getUniquePropertyName(collectionName);
- if (newPropertyName.isEmpty()) {
- qWarning() << __FUNCTION__ << __LINE__
- << QString("The property name cannot be generated from \"%1\"").arg(collectionName);
- continue;
- }
-
- ModelNode collectionNode = model()->createModelNode(childNodeTypename);
- VariantProperty modelNameProperty = collectionNode.variantProperty(
- CollectionEditor::JSONCHILDMODELNAME_PROPERTY);
- modelNameProperty.setValue(collectionName);
-
- NodeProperty nodeProp = rootNode.nodeProperty(newPropertyName);
- nodeProp.setDynamicTypeNameAndsetModelNode(childNodeTypename, collectionNode);
-
- m_collectionPropertyNames.insert(collectionName, newPropertyName);
- }
+ for (const QString &collectionName : std::as_const(collectionNamesLeft))
+ addCollectionNameToTheModel(collectionName, getUniquePropertyName(collectionName));
// Backend Property
- ModelNode backendNode = model()->createModelNode(CollectionEditor::JSONBACKEND_TYPENAME);
+ ModelNode backendNode = model()->createModelNode(CollectionEditorConstants::JSONBACKEND_TYPENAME);
NodeProperty backendProperty = rootNode.nodeProperty("backend");
- backendProperty.setDynamicTypeNameAndsetModelNode(CollectionEditor::JSONBACKEND_TYPENAME,
+ backendProperty.setDynamicTypeNameAndsetModelNode(CollectionEditorConstants::JSONBACKEND_TYPENAME,
backendNode);
// Source Property
- VariantProperty sourceProp = rootNode.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY);
+ VariantProperty sourceProp = rootNode.variantProperty(
+ CollectionEditorConstants::SOURCEFILE_PROPERTY);
sourceProp.setValue(m_dataRelativePath);
}
@@ -231,19 +298,50 @@ void DataStoreModelNode::updateSingletonFile()
imports += QStringLiteral("import %1\n").arg(import.toString(true));
QString content = pragmaSingleTone + imports + getModelQmlText();
- QUrl modelUrl = m_model->fileUrl();
- FileSaver file(FilePath::fromUserInput(modelUrl.isLocalFile() ? modelUrl.toLocalFile()
- : modelUrl.toString()));
+ FileSaver file(dataStoreQmlFilePath());
file.write(content.toLatin1());
file.finalize();
}
void DataStoreModelNode::update()
{
+ if (!m_model.get())
+ return;
+
updateDataStoreProperties();
updateSingletonFile();
}
+void DataStoreModelNode::addCollectionNameToTheModel(const QString &collectionName,
+ const PropertyName &dataStorePropertyName)
+{
+ ModelNode rootNode = modelNode();
+ QTC_ASSERT(rootNode.isValid(), return);
+
+ if (dataStorePropertyName.isEmpty()) {
+ qWarning() << __FUNCTION__ << __LINE__
+ << QString("The property name cannot be generated from \"%1\"").arg(collectionName);
+ return;
+ }
+
+ ModelNode collectionNode = model()->createModelNode(CHILDLISTMODEL_TYPENAME);
+ VariantProperty modelNameProperty = collectionNode.variantProperty(
+ CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY);
+ modelNameProperty.setValue(collectionName);
+
+ NodeProperty nodeProp = rootNode.nodeProperty(dataStorePropertyName);
+ nodeProp.setDynamicTypeNameAndsetModelNode(CHILDLISTMODEL_TYPENAME, collectionNode);
+
+ m_collectionPropertyNames.insert(collectionName, dataStorePropertyName);
+}
+
+Utils::FilePath DataStoreModelNode::dataStoreQmlFilePath() const
+{
+ QUrl modelUrl = m_model->fileUrl();
+ return Utils::FilePath::fromUserInput(modelUrl.isLocalFile() ? modelUrl.toLocalFile()
+ : modelUrl.toString());
+}
+
PropertyName DataStoreModelNode::getUniquePropertyName(const QString &collectionName)
{
ModelNode dataStoreNode = modelNode();
@@ -300,7 +398,7 @@ void DataStoreModelNode::renameCollection(const QString &oldName, const QString
NodeProperty collectionNode = dataStoreNode.property(oldPropertyName).toNodeProperty();
if (collectionNode.isValid()) {
VariantProperty modelNameProperty = collectionNode.modelNode().variantProperty(
- CollectionEditor::JSONCHILDMODELNAME_PROPERTY);
+ CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY);
modelNameProperty.setValue(newName);
m_collectionPropertyNames.remove(oldName);
m_collectionPropertyNames.insert(newName, collectionNode.name());
@@ -333,7 +431,7 @@ void DataStoreModelNode::assignCollectionToNode(AbstractView *view,
{
QTC_ASSERT(targetNode.isValid(), return);
- if (!CollectionEditor::canAcceptCollectionAsModel(targetNode))
+ if (!CollectionEditorUtils::canAcceptCollectionAsModel(targetNode))
return;
if (!m_collectionPropertyNames.contains(collectionName)) {
@@ -352,12 +450,27 @@ void DataStoreModelNode::assignCollectionToNode(AbstractView *view,
return;
}
- BindingProperty modelProperty = targetNode.bindingProperty("model");
-
- QString identifier = QString("DataStore.%1").arg(QString::fromLatin1(sourceProperty.name()));
-
- view->executeInTransaction("assignCollectionToNode", [&modelProperty, &identifier]() {
+ view->executeInTransaction("assignCollectionToNode", [&]() {
+ QString identifier = QString("DataStore.%1").arg(QString::fromLatin1(sourceProperty.name()));
+ BindingProperty modelProperty = targetNode.bindingProperty("model");
modelProperty.setExpression(identifier);
+ if (CollectionEditorUtils::hasTextRoleProperty(targetNode)) {
+ VariantProperty textRoleProperty = targetNode.variantProperty("textRole");
+ const QVariant currentTextRoleValue = textRoleProperty.value();
+
+ if (currentTextRoleValue.isValid() && !currentTextRoleValue.isNull()) {
+ if (currentTextRoleValue.type() == QVariant::String) {
+ const QString currentTextRole = currentTextRoleValue.toString();
+ if (CollectionEditorUtils::collectionHasColumn(collectionName, currentTextRole))
+ return;
+ } else {
+ return;
+ }
+ }
+
+ QString textRoleValue = CollectionEditorUtils::getFirstColumnName(collectionName);
+ textRoleProperty.setValue(textRoleValue);
+ }
});
}
diff --git a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h
index 3048fc4fc9..1c855bca7a 100644
--- a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h
+++ b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h
@@ -7,6 +7,10 @@
#include <QMap>
+namespace Utils {
+class FilePath;
+}
+
namespace QmlDesigner {
class Model;
@@ -34,9 +38,14 @@ private:
QString getModelQmlText();
void reset();
+ void preloadFile();
void updateDataStoreProperties();
void updateSingletonFile();
void update();
+ void addCollectionNameToTheModel(const QString &collectionName,
+ const PropertyName &dataStorePropertyName);
+ Utils::FilePath dataStoreQmlFilePath() const;
+
PropertyName getUniquePropertyName(const QString &collectionName);
ModelPointer m_model;
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
index 6ad7ed994b..6e4b1a1efd 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
@@ -11,6 +11,7 @@
#include "formatoperation.h"
#include "groupitemaction.h"
#include "modelnodecontextmenu_helper.h"
+#include "propertytreemodel.h"
#include "qmldesignerconstants.h"
#include "qmleditormenu.h"
#include "rewritingexception.h"
@@ -475,35 +476,20 @@ QStringList getSignalsList(const ModelNode &node)
if (!node.hasMetaInfo())
return {};
- QStringList signalsList;
- NodeMetaInfo nodeMetaInfo = node.metaInfo();
-
- for (const auto &signalName : nodeMetaInfo.signalNames()) {
- signalsList << QString::fromUtf8(signalName);
- }
-
- //on...Changed are the most regular signals, we assign them the lowest priority,
- //we don't need them right now
-// QStringList signalsWithChanged = signalsList.filter("Changed");
-
- //these are item specific, like MouseArea.clicked, they have higher priority
- QStringList signalsWithoutChanged = signalsList;
- signalsWithoutChanged.removeIf([](QString str) {
- if (str.endsWith("Changed"))
- return true;
- return false;
- });
-
- QStringList finalResult;
- finalResult.append(signalsWithoutChanged);
+ QStringList signalList;
+ std::vector<PropertyName> signalVector = PropertyTreeModel::sortedAndFilteredSignalNames(
+ node.metaInfo());
- if (finalResult.isEmpty())
- finalResult = signalsList;
+ std::vector<QString> signalVectorString = Utils::transform(signalVector,
+ [](const PropertyName &name) {
+ return QString::fromUtf8(name);
+ });
- finalResult.removeDuplicates();
+ signalList.reserve(Utils::ssize(signalVectorString));
+ std::copy(signalVectorString.begin(), signalVectorString.end(), std::back_inserter(signalList));
- return finalResult;
+ return signalList;
}
struct SlotEntry
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
index 79ff364c40..dd00cd48d4 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
@@ -1731,7 +1731,7 @@ bool useLayerEffect()
QtcSettings *settings = Core::ICore::settings();
const Key layerEffectEntry = "QML/Designer/UseLayerEffect";
- return settings->value(layerEffectEntry, true).toBool();
+ return settings->value(layerEffectEntry, false).toBool();
}
bool validateEffect(const QString &effectPath)
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp
index e25f14411e..97919fa4fe 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp
@@ -309,6 +309,13 @@ ModelNode ConnectionModel::getTargetNodeForConnection(const ModelNode &connectio
static QString addOnToSignalName(const QString &signal)
{
+ if (signal.isEmpty())
+ return {};
+
+ static const QRegularExpression rx("^on[A-Z]");
+ if (rx.match(signal).hasMatch())
+ return signal;
+
QString ret = signal;
ret[0] = ret.at(0).toUpper();
ret.prepend("on");
@@ -361,11 +368,10 @@ void ConnectionModel::addConnection(const PropertyName &signalName)
ModelNode selectedNode = connectionView()->selectedModelNodes().constFirst();
PropertyName signalHandlerName = signalName;
- if (signalHandlerName.isEmpty()) {
- signalHandlerName = addOnToSignalName(QString::fromUtf8(getFirstSignalForTarget(
- selectedNode.metaInfo())))
- .toUtf8();
- }
+ if (signalHandlerName.isEmpty())
+ signalHandlerName = getFirstSignalForTarget(selectedNode.metaInfo());
+
+ signalHandlerName = addOnToSignalName(QString::fromUtf8(signalHandlerName)).toUtf8();
connectionView()
->executeInTransaction("ConnectionModel::addConnection", [=, &rootModelNode]() {
@@ -855,7 +861,7 @@ int ConnectionModelBackendDelegate::currentRow() const
return m_currentRow;
}
-QString removeOnFromSignalName(const QString &signal)
+static QString removeOnFromSignalName(const QString &signal)
{
if (signal.isEmpty())
return {};
diff --git a/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.cpp
index 2b1f53243a..4189496316 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.cpp
@@ -72,9 +72,7 @@ const std::vector<PropertyName> blockListSlots = {"childAt",
"inputMethodQuery",
"positionAt",
"positionToRectangle",
- "isRightToLeft"
-
-};
+ "isRightToLeft"};
const std::vector<PropertyName> priorityListSignals = {"clicked",
"doubleClicked",
@@ -99,7 +97,8 @@ const std::vector<PropertyName> priorityListSignals = {"clicked",
"enabledChanged",
"visibleChanged",
"opacityChanged",
- "rotationChanged"};
+ "rotationChanged",
+ "positionChanged"};
const std::vector<PropertyName> priorityListProperties = {"opacity",
"checked",
@@ -572,8 +571,7 @@ const std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredPropertyName
const PropertyName name = metaInfo.name();
- if (!m_includeDotPropertiesOnFirstLevel
- && name.contains("."))
+ if (!m_includeDotPropertiesOnFirstLevel && name.contains("."))
return false;
return filterProperty(name, metaInfo, recursive);
@@ -606,8 +604,8 @@ const std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredPropertyName
return checkedPriorityList;
}
-const std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredSignalNames(
- const NodeMetaInfo &metaInfo, bool recursive) const
+std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredSignalNames(const NodeMetaInfo &metaInfo,
+ bool recursive)
{
Q_UNUSED(recursive);
@@ -627,15 +625,14 @@ const std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredSignalNames(
std::set<PropertyName> set(std::make_move_iterator(sorted.begin()),
std::make_move_iterator(sorted.end()));
- auto checkedPriorityList = Utils::filtered(priorityListSignals,
- [&set](const PropertyName &name) {
- auto it = set.find(name);
- const bool b = it != set.end();
- if (b)
- set.erase(it);
+ auto checkedPriorityList = Utils::filtered(priorityListSignals, [&set](const PropertyName &name) {
+ auto it = set.find(name);
+ const bool b = it != set.end();
+ if (b)
+ set.erase(it);
- return b;
- });
+ return b;
+ });
//const int priorityLength = checkedPriorityList.size(); We eventually require this to get the prioproperties
@@ -648,8 +645,8 @@ const std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredSignalNames(
return checkedPriorityList;
}
-const std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredSlotNames(
- const NodeMetaInfo &metaInfo, bool recursive) const
+std::vector<PropertyName> PropertyTreeModel::sortedAndFilteredSlotNames(const NodeMetaInfo &metaInfo,
+ bool recursive)
{
Q_UNUSED(recursive);
diff --git a/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.h b/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.h
index df17c112da..07e1401c4a 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/propertytreemodel.h
@@ -84,6 +84,12 @@ public:
QHash<int, QByteArray> roleNames() const override;
+ static std::vector<PropertyName> sortedAndFilteredSignalNames(const NodeMetaInfo &metaInfo,
+ bool recursive = false);
+
+ static std::vector<PropertyName> sortedAndFilteredSlotNames(const NodeMetaInfo &metaInfo,
+ bool recursive = false);
+
private:
QModelIndex ensureModelIndex(const ModelNode &node, int row) const;
QModelIndex ensureModelIndex(const ModelNode &node, const PropertyName &name, int row) const;
@@ -94,15 +100,10 @@ private:
const std::vector<PropertyName> getDynamicProperties(const ModelNode &modelNode) const;
const std::vector<PropertyName> getDynamicSignals(const ModelNode &modelNode) const;
+
const std::vector<PropertyName> sortedAndFilteredPropertyNames(const NodeMetaInfo &metaInfo,
bool recursive = false) const;
- const std::vector<PropertyName> sortedAndFilteredSignalNames(const NodeMetaInfo &metaInfo,
- bool recursive = false) const;
-
- const std::vector<PropertyName> sortedAndFilteredSlotNames(const NodeMetaInfo &metaInfo,
- bool recursive = false) const;
-
const std::vector<PropertyName> sortedDotPropertyNames(const NodeMetaInfo &metaInfo,
const PropertyName &propertyName) const;
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp
index 404a5f5730..496f0e4b2c 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp
@@ -262,6 +262,27 @@ void FormEditorItem::setFrameColor(const QColor &color)
update();
}
+void FormEditorItem::setHasEffect(bool hasEffect)
+{
+ m_hasEffect = hasEffect;
+}
+
+bool FormEditorItem::hasEffect() const
+{
+ return m_hasEffect;
+}
+
+bool FormEditorItem::parentHasEffect() const
+{
+ FormEditorItem *pi = parentItem();
+ while (pi) {
+ if (pi->hasEffect())
+ return true;
+ pi = pi->parentItem();
+ }
+ return false;
+}
+
FormEditorItem::~FormEditorItem()
{
scene()->removeItemFromHash(this);
@@ -421,7 +442,7 @@ void FormEditorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *,
painter->setClipRegion(boundingRect().toRect());
painter->setClipping(true);
- if (!hideCompletely) {
+ if (!hideCompletely && !parentHasEffect()) {
if (showPlaceHolder) {
if (scene()->showBoundingRects() && m_boundingRect.width() > 15 && m_boundingRect.height() > 15)
paintPlaceHolderForInvisbleItem(painter);
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.h b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h
index 69b67d0006..b035699772 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditoritem.h
+++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h
@@ -98,6 +98,10 @@ public:
void setFrameColor(const QColor &color);
+ void setHasEffect(bool hasEffect);
+ bool hasEffect() const;
+ bool parentHasEffect() const;
+
protected:
AbstractFormEditorTool* tool() const;
void paintBoundingRect(QPainter *painter) const;
@@ -129,6 +133,7 @@ private: // variables
bool m_highlightBoundingRect;
bool m_blurContent;
bool m_isContentVisible;
+ bool m_hasEffect;
};
class FormEditorFlowItem : public FormEditorItem
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp
index 4b63d9ced8..fcc04ed026 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp
@@ -140,7 +140,7 @@ void FormEditorView::setupFormEditorItemTree(const QmlItemNode &qmlItemNode)
setupFormEditorItemTree(childNode.toQmlItemNode());
}
}
- } else {
+ } else if (!qmlItemNode.isEffectItem()) {
m_scene->addFormEditorItem(qmlItemNode, FormEditorScene::Default);
for (const QmlObjectNode &nextNode : qmlItemNode.allDirectSubNodes()) //TODO instance children
//If the node has source for components/custom parsers we ignore it.
@@ -280,6 +280,13 @@ void FormEditorView::nodeAboutToBeRemoved(const ModelNode &removedNode)
removeNodeFromScene(qmlItemNode);
}
+void FormEditorView::nodeRemoved(const ModelNode &/*removedNode*/,
+ const NodeAbstractProperty &/*parentProperty*/,
+ PropertyChangeFlags /*propertyChange*/)
+{
+ updateHasEffects();
+}
+
void FormEditorView::rootNodeTypeChanged(const QString &/*type*/, int /*majorVersion*/, int /*minorVersion*/)
{
const QList<FormEditorItem *> items = m_scene->allFormEditorItems();
@@ -343,6 +350,8 @@ static inline bool hasNodeSourceOrNonItemParent(const ModelNode &node)
void FormEditorView::nodeReparented(const ModelNode &node, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/)
{
addOrRemoveFormEditorItem(node);
+
+ updateHasEffects();
}
void FormEditorView::nodeSourceChanged(const ModelNode &node,
@@ -830,6 +839,8 @@ void FormEditorView::setupFormEditorWidget()
m_formEditorWidget->showWarningMessageBox(rewriterView()->warnings());
checkRootModelNode();
+
+ updateHasEffects();
}
QmlItemNode findRecursiveQmlItemNode(const QmlObjectNode &firstQmlObjectNode)
@@ -991,6 +1002,23 @@ void FormEditorView::setupRootItemSize()
}
}
+void FormEditorView::updateHasEffects()
+{
+ if (model()) {
+ const QList<ModelNode> nodes = allModelNodes();
+ for (const auto &node : nodes) {
+ QmlItemNode qmlNode(node);
+ FormEditorItem *item = m_scene->itemForQmlItemNode(qmlNode);
+ if (item)
+ item->setHasEffect(false);
+ if (qmlNode.isEffectItem()) {
+ FormEditorItem *parentItem = m_scene->itemForQmlItemNode(qmlNode.modelParentItem());
+ parentItem->setHasEffect(true);
+ }
+ }
+ }
+}
+
void FormEditorView::reset()
{
QTimer::singleShot(200, this, &FormEditorView::delayedReset);
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.h b/src/plugins/qmldesigner/components/formeditor/formeditorview.h
index 1a9f15d016..d3c6cb21db 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditorview.h
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.h
@@ -52,6 +52,8 @@ public:
void nodeCreated(const ModelNode &createdNode) override;
void nodeAboutToBeRemoved(const ModelNode &removedNode) override;
+ void nodeRemoved(const ModelNode &removedNode, const NodeAbstractProperty &parentProperty,
+ PropertyChangeFlags propertyChange) override;
void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) override;
void nodeSourceChanged(const ModelNode &node, const QString &newNodeSource) override;
void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) override;
@@ -138,6 +140,7 @@ private:
void checkRootModelNode();
void setupFormEditor3DView();
void setupRootItemSize();
+ void updateHasEffects();
QPointer<FormEditorWidget> m_formEditorWidget;
QPointer<FormEditorScene> m_scene;
diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp
index ff0fa2ab9f..67043f02d1 100644
--- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp
+++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp
@@ -149,6 +149,14 @@ WorkspaceModel::WorkspaceModel(QObject *)
};
if (!connectDockManager())
connect(designModeWidget(), &Internal::DesignModeWidget::initialized, this, connectDockManager);
+
+ connect(ProjectExplorer::ProjectManager::instance(),
+ &ProjectExplorer::ProjectManager::projectFinishedParsing,
+ this,
+ [this]() {
+ beginResetModel();
+ endResetModel();
+ });
}
int WorkspaceModel::rowCount(const QModelIndex &) const
@@ -162,7 +170,8 @@ int WorkspaceModel::rowCount(const QModelIndex &) const
QHash<int, QByteArray> WorkspaceModel::roleNames() const
{
static QHash<int, QByteArray> roleNames{{DisplayNameRole, "displayName"},
- {FileNameRole, "fileName"}};
+ {FileNameRole, "fileName"},
+ {Enabled, "enabled"}};
return roleNames;
}
@@ -176,6 +185,9 @@ QVariant WorkspaceModel::data(const QModelIndex &index, int role) const
return workspace.name();
} else if (role == FileNameRole) {
return workspace.fileName();
+ } else if (role == Enabled) {
+ if (QmlProjectManager::QmlProject::isMCUs())
+ return workspace.isMcusEnabled();
} else {
qWarning() << Q_FUNC_INFO << "invalid role";
}
diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h
index 307704d63a..eb258f9ab7 100644
--- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h
+++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h
@@ -29,7 +29,8 @@ public:
class WorkspaceModel : public QAbstractListModel
{
Q_OBJECT
- enum { DisplayNameRole = Qt::DisplayRole, FileNameRole = Qt::UserRole };
+
+ enum { DisplayNameRole = Qt::DisplayRole, FileNameRole = Qt::UserRole, Enabled };
public:
explicit WorkspaceModel(QObject *parent = nullptr);
diff --git a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h
index 5816d60ce1..5948ec7ab1 100644
--- a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h
+++ b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h
@@ -139,6 +139,8 @@ public:
bool isFlowActionArea() const;
ModelNode rootModelNode() const;
+ bool isEffectItem() const;
+
friend auto qHash(const QmlItemNode &node) { return qHash(node.modelNode()); }
};
diff --git a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
index 0ce155ca6b..e01bdaaec3 100644
--- a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
@@ -182,14 +182,19 @@ QmlItemNode QmlItemNode::createQmlItemNodeForEffect(AbstractView *view,
const QString effectName = QFileInfo(effectPath).baseName();
Import import = Import::createLibraryImport("Effects." + effectName, "1.0");
try {
- if (!view->model()->hasImport(import, true, true))
+ if (!view->model()->hasImport(import, true, true)) {
view->model()->changeImports({import}, {});
+ // Trigger async reset puppet to ensure full transaction is done before reset
+ view->resetPuppet();
+ }
} catch (const Exception &) {
QTC_ASSERT(false, return);
}
TypeName type(effectName.toUtf8());
- newQmlItemNode = QmlItemNode(view->createModelNode(type, -1, -1));
+ ModelNode newModelNode = view->createModelNode(type, -1, -1);
+ newModelNode.setIdWithoutRefactoring(view->model()->generateNewId(effectName));
+ newQmlItemNode = QmlItemNode(newModelNode);
placeEffectNode(parentProperty, newQmlItemNode, isLayerEffect);
};
@@ -206,12 +211,8 @@ void QmlItemNode::placeEffectNode(NodeAbstractProperty &parentProperty, const Qm
parentProperty.reparentHere(effectNode);
- if (!isLayerEffect) {
- effectNode.modelNode().bindingProperty("source").setExpression("parent");
- effectNode.modelNode().bindingProperty("anchors.fill").setExpression("parent");
- } else {
+ if (isLayerEffect)
parentProperty.parentModelNode().variantProperty("layer.enabled").setValue(true);
- }
if (effectNode.modelNode().metaInfo().hasProperty("timeRunning"))
effectNode.modelNode().variantProperty("timeRunning").setValue(true);
@@ -617,6 +618,11 @@ ModelNode QmlItemNode::rootModelNode() const
return {};
}
+bool QmlItemNode::isEffectItem() const
+{
+ return modelNode().metaInfo().hasProperty("_isEffectItem");
+}
+
void QmlItemNode::setSize(const QSizeF &size)
{
if (!hasBindingProperty("width") && !(anchors().instanceHasAnchor(AnchorLineRight)
diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
index 889f847197..037259e87e 100644
--- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
+++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
@@ -388,6 +388,7 @@ bool smartVeryFuzzyCompare(const QVariant &value1, const QVariant &value2)
void removeModelNode(const QmlDesigner::ModelNode &modelNode)
{
+ QTC_ASSERT(modelNode.isValid(), return );
modelNode.model()->removeModelNodes({modelNode},
QmlDesigner::BypassModelResourceManagement::Yes);
}
@@ -400,6 +401,7 @@ bool smartColorCompare(const QVariant &value1, const QVariant &value2)
void removeProperty(const QmlDesigner::AbstractProperty &modelProperty)
{
+ QTC_ASSERT(modelProperty.isValid(), return );
modelProperty.model()->removeProperties({modelProperty},
QmlDesigner::BypassModelResourceManagement::Yes);
}
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp
index b7f6d2ae55..f9eb8080f7 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp
@@ -294,10 +294,16 @@ Storage::Synchronization::Type QmlDocumentParser::parse(const QString &sourceCon
QString filePath{m_pathCache.sourcePath(sourceId)};
environment.loadFile(
+#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
filePath,
filePath,
sourceContent,
QDateTime{},
+#else
+ QQmlJS::Dom::FileToLoad::fromMemory(environment.ownerAs<QQmlJS::Dom::DomEnvironment>(),
+ filePath,
+ sourceContent),
+#endif
[&](QmlDom::Path, const QmlDom::DomItem &, const QmlDom::DomItem &newItems) {
items = newItems;
},
diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp
index a8567dec38..a26eada911 100644
--- a/src/plugins/qmldesigner/designmodewidget.cpp
+++ b/src/plugins/qmldesigner/designmodewidget.cpp
@@ -34,6 +34,7 @@
#include <coreplugin/idocument.h>
#include <coreplugin/inavigationwidgetfactory.h>
+#include <projectexplorer/projectmanager.h>
#include <qmlprojectmanager/qmlproject.h>
#include <utils/algorithm.h>
@@ -219,6 +220,13 @@ void DesignModeWidget::setup()
QString sheet = QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/dockwidgets.css"));
m_dockManager->setStyleSheet(Theme::replaceCssColors(sheet));
+ connect(ProjectExplorer::ProjectManager::instance(),
+ &ProjectExplorer::ProjectManager::projectFinishedParsing,
+ m_dockManager,
+ [this]() {
+ this->m_dockManager->setMcusProject(QmlProjectManager::QmlProject::isMCUs());
+ });
+
// Setup icons
const QString closeUnicode = Theme::getIconUnicode(Theme::Icon::close_small);
const QString maximizeUnicode = Theme::getIconUnicode(Theme::Icon::maxBar_small);
@@ -273,6 +281,7 @@ void DesignModeWidget::setup()
Core::ActionContainer *mview = Core::ActionManager::actionContainer(Core::Constants::M_VIEW);
// View > Views
Core::ActionContainer *mviews = Core::ActionManager::createMenu(Core::Constants::M_VIEW_VIEWS);
+ connect(mviews->menu(), &QMenu::aboutToShow, this, &DesignModeWidget::aboutToShowViews);
mviews->menu()->addSeparator();
// View > Workspaces
Core::ActionContainer *mworkspaces = Core::ActionManager::createMenu(QmlDesigner::Constants::M_VIEW_WORKSPACES);
@@ -482,6 +491,29 @@ void DesignModeWidget::setup()
show();
}
+static bool isMcuDisabledView(const QString viewId)
+{
+ static const QStringList mcuDisabledViews = {"Editor3D", "MaterialEditor", "MaterialBrowser", "TextureEditor"};
+ return mcuDisabledViews.contains(viewId);
+}
+
+void DesignModeWidget::aboutToShowViews()
+{
+ for (const WidgetInfo &widgetInfo : viewManager().widgetInfos()) {
+ QString id = widgetInfo.uniqueId;
+ ADS::DockWidget *dockWidget = m_dockManager->findDockWidget(id);
+ QAction *action = dockWidget->toggleViewAction();
+
+ bool isMcuProject = currentDesignDocument() && currentDesignDocument()->isQtForMCUsProject();
+ if (isMcuProject && isMcuDisabledView(id) && action->isEnabled()) {
+ action->setChecked(false);
+ action->setEnabled(false);
+ } else if (!isMcuProject && !action->isEnabled()) {
+ action->setEnabled(true);
+ }
+ }
+}
+
void DesignModeWidget::aboutToShowWorkspaces()
{
Core::ActionContainer *aci = Core::ActionManager::actionContainer(
@@ -520,6 +552,9 @@ void DesignModeWidget::aboutToShowWorkspaces()
action->setCheckable(true);
if (workspace == *m_dockManager->activeWorkspace())
action->setChecked(true);
+
+ if (currentDesignDocument() && currentDesignDocument()->isQtForMCUsProject())
+ action->setEnabled(workspace.isMcusEnabled());
}
menu->addActions(ag->actions());
}
diff --git a/src/plugins/qmldesigner/designmodewidget.h b/src/plugins/qmldesigner/designmodewidget.h
index 432549e694..464994b7e3 100644
--- a/src/plugins/qmldesigner/designmodewidget.h
+++ b/src/plugins/qmldesigner/designmodewidget.h
@@ -93,6 +93,7 @@ private:
QWidget *createCenterWidget();
QWidget *createCrumbleBarFrame();
+ void aboutToShowViews();
void aboutToShowWorkspaces();
QPointer<QWidget> m_bottomSideBar;
diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp
index 0acba25ded..62a2d7bdfc 100644
--- a/src/plugins/qmlprojectmanager/qmlproject.cpp
+++ b/src/plugins/qmlprojectmanager/qmlproject.cpp
@@ -238,4 +238,17 @@ bool QmlProject::allowOnlySingleProject()
return !settings->value(key, false).toBool();
}
+bool QmlProject::isMCUs()
+{
+ if (!ProjectExplorer::ProjectManager::startupTarget())
+ return false;
+
+ const QmlProjectManager::QmlBuildSystem *buildSystem
+ = qobject_cast<QmlProjectManager::QmlBuildSystem *>(
+ ProjectExplorer::ProjectManager::startupTarget()->buildSystem());
+ QTC_ASSERT(buildSystem, return false);
+
+ return buildSystem && buildSystem->qtForMCUs();
+}
+
} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h
index a41b05e57b..0091d77d6c 100644
--- a/src/plugins/qmlprojectmanager/qmlproject.h
+++ b/src/plugins/qmlprojectmanager/qmlproject.h
@@ -24,6 +24,8 @@ public:
ProjectExplorer::Tasks projectIssues(const ProjectExplorer::Kit *k) const final;
+ static bool isMCUs();
+
protected:
RestoreResult fromMap(const Utils::Store &map, QString *errorMessage) override;
diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp
index fb28d16aa3..da669423e3 100644
--- a/src/plugins/qtsupport/baseqtversion.cpp
+++ b/src/plugins/qtsupport/baseqtversion.cpp
@@ -77,7 +77,7 @@ class QtVersionData
{
public:
// Update version if you add data members!
- static const int version = 2;
+ static const int version = 3;
bool installed = true;
bool hasExamples = false;
@@ -203,8 +203,11 @@ public:
hostDataPath = FilePath::fromSettings(map.value("HostDataPath"));
hostPrefixPath = FilePath::fromSettings(map.value("HostPrefixPath"));
auto it = map.find("QtAbis");
- if (it != map.end())
- qtAbis = Utils::transform(it.value().toStringList(), &Abi::fromString);
+ if (it != map.end()) {
+ const auto qtAbisList = it.value().toStringList();
+ if (!qtAbisList.isEmpty())
+ qtAbis = Utils::transform(qtAbisList, &Abi::fromString);
+ }
versionInfo = fromStore(map.value("VersionInfo").value<Store>());
}
};
diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp
index b48d87121f..c80b64601b 100644
--- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp
+++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp
@@ -759,7 +759,8 @@ WelcomeMode::WelcomeMode()
m_dataModelDownloader->setForceDownload(true);
connect(m_dataModelDownloader, &DataModelDownloader::progressChanged, this, [this](){
- m_quickWidget->rootObject()->setProperty("loadingProgress", m_dataModelDownloader->progress());
+ if (m_quickWidget->rootObject())
+ m_quickWidget->rootObject()->setProperty("loadingProgress", m_dataModelDownloader->progress());
});
connect(m_dataModelDownloader, &DataModelDownloader::finished, this, [this, welcomePagePath]() {