forked from qt-creator/qt-creator
Merge "Merge remote-tracking branch 'origin/qds/dev' into 12.0" into 12.0
This commit is contained in:
@@ -792,6 +792,7 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
extend_qtc_plugin(QmlDesigner
|
extend_qtc_plugin(QmlDesigner
|
||||||
SOURCES_PREFIX components/collectioneditor
|
SOURCES_PREFIX components/collectioneditor
|
||||||
SOURCES
|
SOURCES
|
||||||
|
collectiondetails.cpp collectiondetails.h
|
||||||
collectioneditorconstants.h
|
collectioneditorconstants.h
|
||||||
collectionlistmodel.cpp collectionlistmodel.h
|
collectionlistmodel.cpp collectionlistmodel.h
|
||||||
collectionsourcemodel.cpp collectionsourcemodel.h
|
collectionsourcemodel.cpp collectionsourcemodel.h
|
||||||
|
@@ -0,0 +1,199 @@
|
|||||||
|
// 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 "collectiondetails.h"
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class CollectionDetails::Private
|
||||||
|
{
|
||||||
|
using SourceFormat = CollectionEditor::SourceFormat;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QStringList headers;
|
||||||
|
QList<QJsonObject> elements;
|
||||||
|
SourceFormat sourceFormat = SourceFormat::Unknown;
|
||||||
|
CollectionReference reference;
|
||||||
|
bool isChanged = false;
|
||||||
|
|
||||||
|
bool isValidColumnId(int column) const { return column > -1 && column < headers.size(); }
|
||||||
|
|
||||||
|
bool isValidRowId(int row) const { return row > -1 && row < elements.size(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
CollectionDetails::CollectionDetails()
|
||||||
|
: d(new Private())
|
||||||
|
{}
|
||||||
|
|
||||||
|
CollectionDetails::CollectionDetails(const CollectionReference &reference)
|
||||||
|
: CollectionDetails()
|
||||||
|
{
|
||||||
|
d->reference = reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionDetails::CollectionDetails(const CollectionDetails &other) = default;
|
||||||
|
|
||||||
|
CollectionDetails::~CollectionDetails() = default;
|
||||||
|
|
||||||
|
void CollectionDetails::resetDetails(const QStringList &headers,
|
||||||
|
const QList<QJsonObject> &elements,
|
||||||
|
CollectionEditor::SourceFormat format)
|
||||||
|
{
|
||||||
|
if (!isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
d->headers = headers;
|
||||||
|
d->elements = elements;
|
||||||
|
d->sourceFormat = format;
|
||||||
|
|
||||||
|
markSaved();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectionDetails::insertHeader(const QString &header, int place, const QVariant &defaultValue)
|
||||||
|
{
|
||||||
|
if (!isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (d->headers.contains(header))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (d->isValidColumnId(place))
|
||||||
|
d->headers.insert(place, header);
|
||||||
|
else
|
||||||
|
d->headers.append(header);
|
||||||
|
|
||||||
|
QJsonValue defaultJsonValue = QJsonValue::fromVariant(defaultValue);
|
||||||
|
for (QJsonObject &element : d->elements)
|
||||||
|
element.insert(header, defaultJsonValue);
|
||||||
|
|
||||||
|
markChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectionDetails::removeHeader(int place)
|
||||||
|
{
|
||||||
|
if (!isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!d->isValidColumnId(place))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QString header = d->headers.takeAt(place);
|
||||||
|
|
||||||
|
for (QJsonObject &element : d->elements)
|
||||||
|
element.remove(header);
|
||||||
|
|
||||||
|
markChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectionDetails::insertElementAt(std::optional<QJsonObject> object, int row)
|
||||||
|
{
|
||||||
|
if (!isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto insertJson = [this, row](const QJsonObject &jsonObject) {
|
||||||
|
if (d->isValidRowId(row))
|
||||||
|
d->elements.insert(row, jsonObject);
|
||||||
|
else
|
||||||
|
d->elements.append(jsonObject);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (object.has_value()) {
|
||||||
|
insertJson(object.value());
|
||||||
|
} else {
|
||||||
|
QJsonObject defaultObject;
|
||||||
|
for (const QString &header : std::as_const(d->headers))
|
||||||
|
defaultObject.insert(header, {});
|
||||||
|
insertJson(defaultObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
markChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionReference CollectionDetails::reference() const
|
||||||
|
{
|
||||||
|
return d->reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionEditor::SourceFormat CollectionDetails::sourceFormat() const
|
||||||
|
{
|
||||||
|
return d->sourceFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant CollectionDetails::data(int row, int column) const
|
||||||
|
{
|
||||||
|
if (!isValid())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!d->isValidRowId(row))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!d->isValidColumnId(column))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const QString &propertyName = d->headers.at(column);
|
||||||
|
const QJsonObject &elementNode = d->elements.at(row);
|
||||||
|
|
||||||
|
if (elementNode.contains(propertyName))
|
||||||
|
return elementNode.value(propertyName).toVariant();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CollectionDetails::headerAt(int column) const
|
||||||
|
{
|
||||||
|
if (!d->isValidColumnId(column))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return d->headers.at(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CollectionDetails::isValid() const
|
||||||
|
{
|
||||||
|
return d->reference.node.isValid() && d->reference.name.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CollectionDetails::isChanged() const
|
||||||
|
{
|
||||||
|
return d->isChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CollectionDetails::columns() const
|
||||||
|
{
|
||||||
|
return d->headers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int CollectionDetails::rows() const
|
||||||
|
{
|
||||||
|
return d->elements.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CollectionDetails::markSaved()
|
||||||
|
{
|
||||||
|
if (d->isChanged) {
|
||||||
|
d->isChanged = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectionDetails::swap(CollectionDetails &other)
|
||||||
|
{
|
||||||
|
d.swap(other.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionDetails &CollectionDetails::operator=(const CollectionDetails &other)
|
||||||
|
{
|
||||||
|
CollectionDetails value(other);
|
||||||
|
swap(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollectionDetails::markChanged()
|
||||||
|
{
|
||||||
|
d->isChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,76 @@
|
|||||||
|
// 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 "collectioneditorconstants.h"
|
||||||
|
#include "modelnode.h"
|
||||||
|
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QJsonObject;
|
||||||
|
class QVariant;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
struct CollectionReference
|
||||||
|
{
|
||||||
|
ModelNode node;
|
||||||
|
QString name;
|
||||||
|
|
||||||
|
friend auto qHash(const CollectionReference &collection)
|
||||||
|
{
|
||||||
|
return qHash(collection.node) ^ ::qHash(collection.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const CollectionReference &other) const
|
||||||
|
{
|
||||||
|
return node == other.node && name == other.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const CollectionReference &other) const { return !(*this == other); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class CollectionDetails
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit CollectionDetails();
|
||||||
|
CollectionDetails(const CollectionReference &reference);
|
||||||
|
CollectionDetails(const CollectionDetails &other);
|
||||||
|
~CollectionDetails();
|
||||||
|
|
||||||
|
void resetDetails(const QStringList &headers,
|
||||||
|
const QList<QJsonObject> &elements,
|
||||||
|
CollectionEditor::SourceFormat format);
|
||||||
|
void insertHeader(const QString &header, int place = -1, const QVariant &defaultValue = {});
|
||||||
|
void removeHeader(int place);
|
||||||
|
|
||||||
|
void insertElementAt(std::optional<QJsonObject> object, int row = -1);
|
||||||
|
|
||||||
|
CollectionReference reference() const;
|
||||||
|
CollectionEditor::SourceFormat sourceFormat() const;
|
||||||
|
QVariant data(int row, int column) const;
|
||||||
|
QString headerAt(int column) const;
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
bool isChanged() const;
|
||||||
|
|
||||||
|
int columns() const;
|
||||||
|
int rows() const;
|
||||||
|
|
||||||
|
bool markSaved();
|
||||||
|
|
||||||
|
void swap(CollectionDetails &other);
|
||||||
|
CollectionDetails &operator=(const CollectionDetails &other);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void markChanged();
|
||||||
|
|
||||||
|
// The private data is supposed to be shared between the copies
|
||||||
|
class Private;
|
||||||
|
QSharedPointer<Private> d;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
namespace QmlDesigner::CollectionEditor {
|
namespace QmlDesigner::CollectionEditor {
|
||||||
|
|
||||||
|
enum class SourceFormat { Unknown, Json, Csv };
|
||||||
|
|
||||||
inline constexpr char SOURCEFILE_PROPERTY[] = "sourceFile";
|
inline constexpr char SOURCEFILE_PROPERTY[] = "sourceFile";
|
||||||
|
|
||||||
inline constexpr char COLLECTIONMODEL_IMPORT[] = "QtQuick.Studio.Models";
|
inline constexpr char COLLECTIONMODEL_IMPORT[] = "QtQuick.Studio.Models";
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
#include <QJsonObject>
|
||||||
#include <QJsonParseError>
|
#include <QJsonParseError>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -39,26 +40,19 @@ SingleCollectionModel::SingleCollectionModel(QObject *parent)
|
|||||||
|
|
||||||
int SingleCollectionModel::rowCount([[maybe_unused]] const QModelIndex &parent) const
|
int SingleCollectionModel::rowCount([[maybe_unused]] const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return m_elements.count();
|
return m_currentCollection.rows();
|
||||||
}
|
}
|
||||||
|
|
||||||
int SingleCollectionModel::columnCount([[maybe_unused]] const QModelIndex &parent) const
|
int SingleCollectionModel::columnCount([[maybe_unused]] const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return m_headers.count();
|
return m_currentCollection.columns();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant SingleCollectionModel::data(const QModelIndex &index, int) const
|
QVariant SingleCollectionModel::data(const QModelIndex &index, int) const
|
||||||
{
|
{
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return {};
|
return {};
|
||||||
|
return m_currentCollection.data(index.row(), index.column());
|
||||||
const QString &propertyName = m_headers.at(index.column());
|
|
||||||
const QJsonObject &elementNode = m_elements.at(index.row());
|
|
||||||
|
|
||||||
if (elementNode.contains(propertyName))
|
|
||||||
return elementNode.value(propertyName).toVariant();
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SingleCollectionModel::setData(const QModelIndex &, const QVariant &, int)
|
bool SingleCollectionModel::setData(const QModelIndex &, const QVariant &, int)
|
||||||
@@ -79,7 +73,7 @@ QVariant SingleCollectionModel::headerData(int section,
|
|||||||
[[maybe_unused]] int role) const
|
[[maybe_unused]] int role) const
|
||||||
{
|
{
|
||||||
if (orientation == Qt::Horizontal)
|
if (orientation == Qt::Horizontal)
|
||||||
return m_headers.at(section);
|
return m_currentCollection.headerAt(section);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -88,16 +82,62 @@ void SingleCollectionModel::loadCollection(const ModelNode &sourceNode, const QS
|
|||||||
{
|
{
|
||||||
QString fileName = sourceNode.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY).value().toString();
|
QString fileName = sourceNode.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY).value().toString();
|
||||||
|
|
||||||
if (sourceNode.type() == CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME)
|
CollectionReference newReference{sourceNode, collection};
|
||||||
loadJsonCollection(fileName, collection);
|
bool alreadyOpen = m_openedCollections.contains(newReference);
|
||||||
else if (sourceNode.type() == CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME)
|
|
||||||
loadCsvCollection(fileName, collection);
|
if (alreadyOpen) {
|
||||||
|
if (m_currentCollection.reference() != newReference) {
|
||||||
|
beginResetModel();
|
||||||
|
switchToCollection(newReference);
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switchToCollection(newReference);
|
||||||
|
if (sourceNode.type() == CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME)
|
||||||
|
loadJsonCollection(fileName, collection);
|
||||||
|
else if (sourceNode.type() == CollectionEditor::CSVCOLLECTIONMODEL_TYPENAME)
|
||||||
|
loadCsvCollection(fileName, collection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCollectionModel::switchToCollection(const CollectionReference &collection)
|
||||||
|
{
|
||||||
|
if (m_currentCollection.reference() == collection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
closeCurrentCollectionIfSaved();
|
||||||
|
|
||||||
|
if (!m_openedCollections.contains(collection))
|
||||||
|
m_openedCollections.insert(collection, CollectionDetails(collection));
|
||||||
|
|
||||||
|
m_currentCollection = m_openedCollections.value(collection);
|
||||||
|
|
||||||
|
setCollectionName(collection.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCollectionModel::closeCollectionIfSaved(const CollectionReference &collection)
|
||||||
|
{
|
||||||
|
if (!m_openedCollections.contains(collection))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const CollectionDetails &collectionDetails = m_openedCollections.value(collection);
|
||||||
|
|
||||||
|
if (!collectionDetails.isChanged())
|
||||||
|
m_openedCollections.remove(collection);
|
||||||
|
|
||||||
|
m_currentCollection = CollectionDetails{};
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCollectionModel::closeCurrentCollectionIfSaved()
|
||||||
|
{
|
||||||
|
if (m_currentCollection.isValid())
|
||||||
|
closeCollectionIfSaved(m_currentCollection.reference());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleCollectionModel::loadJsonCollection(const QString &source, const QString &collection)
|
void SingleCollectionModel::loadJsonCollection(const QString &source, const QString &collection)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
using CollectionEditor::SourceFormat;
|
||||||
setCollectionName(collection);
|
|
||||||
QFile sourceFile(source);
|
QFile sourceFile(source);
|
||||||
QJsonArray collectionNodes;
|
QJsonArray collectionNodes;
|
||||||
bool jsonFileIsOk = false;
|
bool jsonFileIsOk = false;
|
||||||
@@ -119,62 +159,64 @@ void SingleCollectionModel::loadJsonCollection(const QString &source, const QStr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setCollectionSourceFormat(jsonFileIsOk ? SourceFormat::Json : SourceFormat::Unknown);
|
|
||||||
|
|
||||||
if (collectionNodes.isEmpty()) {
|
if (collectionNodes.isEmpty()) {
|
||||||
m_headers.clear();
|
closeCurrentCollectionIfSaved();
|
||||||
m_elements.clear();
|
|
||||||
endResetModel();
|
endResetModel();
|
||||||
return;
|
return;
|
||||||
}
|
};
|
||||||
|
|
||||||
m_headers = getJsonHeaders(collectionNodes);
|
QList<QJsonObject> elements;
|
||||||
|
|
||||||
m_elements.clear();
|
|
||||||
for (const QJsonValue &value : std::as_const(collectionNodes)) {
|
for (const QJsonValue &value : std::as_const(collectionNodes)) {
|
||||||
if (value.isObject()) {
|
if (value.isObject()) {
|
||||||
QJsonObject object = value.toObject();
|
QJsonObject object = value.toObject();
|
||||||
m_elements.append(object);
|
elements.append(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceFormat sourceFormat = jsonFileIsOk ? SourceFormat::Json : SourceFormat::Unknown;
|
||||||
|
|
||||||
|
beginResetModel();
|
||||||
|
m_currentCollection.resetDetails(getJsonHeaders(collectionNodes), elements, sourceFormat);
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleCollectionModel::loadCsvCollection(const QString &source, const QString &collectionName)
|
void SingleCollectionModel::loadCsvCollection(const QString &source,
|
||||||
|
[[maybe_unused]] const QString &collectionName)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
using CollectionEditor::SourceFormat;
|
||||||
|
|
||||||
setCollectionName(collectionName);
|
|
||||||
QFile sourceFile(source);
|
QFile sourceFile(source);
|
||||||
m_headers.clear();
|
QStringList headers;
|
||||||
m_elements.clear();
|
QList<QJsonObject> elements;
|
||||||
bool csvFileIsOk = false;
|
bool csvFileIsOk = false;
|
||||||
|
|
||||||
if (sourceFile.open(QFile::ReadOnly)) {
|
if (sourceFile.open(QFile::ReadOnly)) {
|
||||||
QTextStream stream(&sourceFile);
|
QTextStream stream(&sourceFile);
|
||||||
|
|
||||||
if (!stream.atEnd())
|
if (!stream.atEnd())
|
||||||
m_headers = stream.readLine().split(',');
|
headers = stream.readLine().split(',');
|
||||||
|
|
||||||
if (!m_headers.isEmpty()) {
|
if (!headers.isEmpty()) {
|
||||||
while (!stream.atEnd()) {
|
while (!stream.atEnd()) {
|
||||||
const QStringList recordDataList = stream.readLine().split(',');
|
const QStringList recordDataList = stream.readLine().split(',');
|
||||||
int column = -1;
|
int column = -1;
|
||||||
QJsonObject recordData;
|
QJsonObject recordData;
|
||||||
for (const QString &cellData : recordDataList) {
|
for (const QString &cellData : recordDataList) {
|
||||||
if (++column == m_headers.size())
|
if (++column == headers.size())
|
||||||
break;
|
break;
|
||||||
recordData.insert(m_headers.at(column), cellData);
|
recordData.insert(headers.at(column), cellData);
|
||||||
}
|
}
|
||||||
if (recordData.count())
|
if (recordData.count())
|
||||||
m_elements.append(recordData);
|
elements.append(recordData);
|
||||||
}
|
}
|
||||||
csvFileIsOk = true;
|
csvFileIsOk = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setCollectionSourceFormat(csvFileIsOk ? SourceFormat::Csv : SourceFormat::Unknown);
|
SourceFormat sourceFormat = csvFileIsOk ? SourceFormat::Csv : SourceFormat::Unknown;
|
||||||
|
|
||||||
|
beginResetModel();
|
||||||
|
m_currentCollection.resetDetails(headers, elements, sourceFormat);
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,8 +228,4 @@ void SingleCollectionModel::setCollectionName(const QString &newCollectionName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleCollectionModel::setCollectionSourceFormat(SourceFormat sourceFormat)
|
|
||||||
{
|
|
||||||
m_sourceFormat = sourceFormat;
|
|
||||||
}
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -3,8 +3,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "collectiondetails.h"
|
||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
#include <QJsonObject>
|
#include <QHash>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
@@ -17,7 +19,6 @@ class SingleCollectionModel : public QAbstractTableModel
|
|||||||
Q_PROPERTY(QString collectionName MEMBER m_collectionName NOTIFY collectionNameChanged)
|
Q_PROPERTY(QString collectionName MEMBER m_collectionName NOTIFY collectionNameChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class SourceFormat { Unknown, Json, Csv };
|
|
||||||
explicit SingleCollectionModel(QObject *parent = nullptr);
|
explicit SingleCollectionModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent) const override;
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
@@ -35,15 +36,17 @@ signals:
|
|||||||
void collectionNameChanged(const QString &collectionName);
|
void collectionNameChanged(const QString &collectionName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void switchToCollection(const CollectionReference &collection);
|
||||||
|
void closeCollectionIfSaved(const CollectionReference &collection);
|
||||||
|
void closeCurrentCollectionIfSaved();
|
||||||
void setCollectionName(const QString &newCollectionName);
|
void setCollectionName(const QString &newCollectionName);
|
||||||
void setCollectionSourceFormat(SourceFormat sourceFormat);
|
|
||||||
void loadJsonCollection(const QString &source, const QString &collection);
|
void loadJsonCollection(const QString &source, const QString &collection);
|
||||||
void loadCsvCollection(const QString &source, const QString &collectionName);
|
void loadCsvCollection(const QString &source, const QString &collectionName);
|
||||||
|
|
||||||
QStringList m_headers;
|
QHash<CollectionReference, CollectionDetails> m_openedCollections;
|
||||||
QList<QJsonObject> m_elements;
|
CollectionDetails m_currentCollection;
|
||||||
|
|
||||||
QString m_collectionName;
|
QString m_collectionName;
|
||||||
SourceFormat m_sourceFormat = SourceFormat::Unknown;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -744,8 +744,9 @@ std::shared_ptr<NodeMetaInfoPrivate> NodeMetaInfoPrivate::create(Model *model,
|
|||||||
newData->minorVersion());
|
newData->minorVersion());
|
||||||
|
|
||||||
if (auto found = cache.find(stringfiedQualifiedType); found != cache.end()) {
|
if (auto found = cache.find(stringfiedQualifiedType); found != cache.end()) {
|
||||||
cache.insert(stringfiedType, *found);
|
newData = *found;
|
||||||
return *found;
|
cache.insert(stringfiedType, newData);
|
||||||
|
return newData;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stringfiedQualifiedType != stringfiedType)
|
if (stringfiedQualifiedType != stringfiedType)
|
||||||
@@ -1709,10 +1710,12 @@ std::vector<NodeMetaInfo> NodeMetaInfo::selfAndPrototypes() const
|
|||||||
NodeMetaInfos hierarchy = {*this};
|
NodeMetaInfos hierarchy = {*this};
|
||||||
Model *model = m_privateData->model();
|
Model *model = m_privateData->model();
|
||||||
for (const TypeDescription &type : m_privateData->prototypes()) {
|
for (const TypeDescription &type : m_privateData->prototypes()) {
|
||||||
hierarchy.emplace_back(model,
|
auto &last = hierarchy.emplace_back(model,
|
||||||
type.className.toUtf8(),
|
type.className.toUtf8(),
|
||||||
type.majorVersion,
|
type.majorVersion,
|
||||||
type.minorVersion);
|
type.minorVersion);
|
||||||
|
if (!last.isValid())
|
||||||
|
hierarchy.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
return hierarchy;
|
return hierarchy;
|
||||||
@@ -1735,11 +1738,14 @@ NodeMetaInfos NodeMetaInfo::prototypes() const
|
|||||||
if (isValid()) {
|
if (isValid()) {
|
||||||
NodeMetaInfos hierarchy;
|
NodeMetaInfos hierarchy;
|
||||||
Model *model = m_privateData->model();
|
Model *model = m_privateData->model();
|
||||||
for (const TypeDescription &type : m_privateData->prototypes())
|
for (const TypeDescription &type : m_privateData->prototypes()) {
|
||||||
hierarchy.emplace_back(model,
|
auto &last = hierarchy.emplace_back(model,
|
||||||
type.className.toUtf8(),
|
type.className.toUtf8(),
|
||||||
type.majorVersion,
|
type.majorVersion,
|
||||||
type.minorVersion);
|
type.minorVersion);
|
||||||
|
if (!last.isValid())
|
||||||
|
hierarchy.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
return hierarchy;
|
return hierarchy;
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,5 @@ CustomMaterial {
|
|||||||
sourceBlend: CustomMaterial.NoBlend
|
sourceBlend: CustomMaterial.NoBlend
|
||||||
destinationBlend: CustomMaterial.NoBlend
|
destinationBlend: CustomMaterial.NoBlend
|
||||||
shadingMode: CustomMaterial.Unshaded
|
shadingMode: CustomMaterial.Unshaded
|
||||||
depthDrawMode: Material.AlwaysDepthDraw
|
|
||||||
cullMode: Material.NoCulling
|
cullMode: Material.NoCulling
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,18 @@ Node {
|
|||||||
property double distance: 500
|
property double distance: 500
|
||||||
|
|
||||||
readonly property int maxGridStep: 32 * _generalHelper.minGridStep
|
readonly property int maxGridStep: 32 * _generalHelper.minGridStep
|
||||||
readonly property int gridArea: _generalHelper.minGridStep * 512
|
|
||||||
|
readonly property int gridArea: {
|
||||||
|
let newArea = _generalHelper.minGridStep * 512
|
||||||
|
|
||||||
|
// Let's limit the grid size to something sensible
|
||||||
|
while (newArea > 30000)
|
||||||
|
newArea -= gridStep
|
||||||
|
|
||||||
|
return newArea
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property double gridOpacity: 0.99
|
||||||
|
|
||||||
// Step of the main lines of the grid, between those is always one subdiv line
|
// Step of the main lines of the grid, between those is always one subdiv line
|
||||||
property int gridStep: 100
|
property int gridStep: 100
|
||||||
@@ -71,7 +82,7 @@ Node {
|
|||||||
orthoMode: grid.orthoMode
|
orthoMode: grid.orthoMode
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
opacity: 0.99
|
opacity: grid.gridOpacity
|
||||||
}
|
}
|
||||||
|
|
||||||
Model { // Subdivision lines
|
Model { // Subdivision lines
|
||||||
@@ -91,7 +102,7 @@ Node {
|
|||||||
orthoMode: grid.orthoMode
|
orthoMode: grid.orthoMode
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
opacity: 0.99
|
opacity: grid.gridOpacity
|
||||||
}
|
}
|
||||||
|
|
||||||
Model { // Z Axis
|
Model { // Z Axis
|
||||||
@@ -110,7 +121,7 @@ Node {
|
|||||||
orthoMode: grid.orthoMode
|
orthoMode: grid.orthoMode
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
opacity: 0.99
|
opacity: grid.gridOpacity
|
||||||
}
|
}
|
||||||
Model { // X Axis
|
Model { // X Axis
|
||||||
readonly property bool _edit3dLocked: true // Make this non-pickable
|
readonly property bool _edit3dLocked: true // Make this non-pickable
|
||||||
@@ -129,6 +140,6 @@ Node {
|
|||||||
orthoMode: grid.orthoMode
|
orthoMode: grid.orthoMode
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
opacity: 0.99
|
opacity: grid.gridOpacity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,8 +22,12 @@ View3D {
|
|||||||
// gives a reasonable grid spacing in most cases while keeping spacing constant when
|
// gives a reasonable grid spacing in most cases while keeping spacing constant when
|
||||||
// orbiting the camera.
|
// orbiting the camera.
|
||||||
readonly property double cameraDistance: {
|
readonly property double cameraDistance: {
|
||||||
if (usePerspective)
|
if (usePerspective) {
|
||||||
return cameraLookAt.minus(camera.position).length() + Math.abs(cameraLookAt.y)
|
// Round to five decimals to avoid rounding errors causing constant property updates
|
||||||
|
// on the material when simply orbiting.
|
||||||
|
let dist = cameraLookAt.minus(camera.position).length() + Math.abs(cameraLookAt.y)
|
||||||
|
return Number(dist.toPrecision(5));
|
||||||
|
}
|
||||||
|
|
||||||
// Orthocamera should only care about camera magnification,
|
// Orthocamera should only care about camera magnification,
|
||||||
// as grid will be same size regardless of distance, so setting steps based on distance
|
// as grid will be same size regardless of distance, so setting steps based on distance
|
||||||
|
@@ -19,15 +19,9 @@ void MAIN()
|
|||||||
if (depth > 90000.0)
|
if (depth > 90000.0)
|
||||||
alpha *= clamp((100000.0 - depth) / 10000.0, 0, 1);
|
alpha *= clamp((100000.0 - depth) / 10000.0, 0, 1);
|
||||||
|
|
||||||
if (alpha > 0.01) {
|
if (alpha > 0.01)
|
||||||
vec2 uv = FRAGCOORD.xy / vec2(textureSize(SCREEN_TEXTURE, 0));
|
FRAGCOLOR = vec4(color.xyz * alpha, alpha);
|
||||||
vec4 sc = texture(SCREEN_TEXTURE, uv);
|
else
|
||||||
if (sc.a == 0.0)
|
|
||||||
FRAGCOLOR = vec4(color.xyz * alpha, alpha);
|
|
||||||
else
|
|
||||||
FRAGCOLOR = vec4((color.xyz * alpha + sc.xyz * (1.0 - alpha)) * alpha, alpha);
|
|
||||||
} else {
|
|
||||||
discard;
|
discard;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -81,9 +81,12 @@ void GridGeometry::doUpdateGeometry()
|
|||||||
setVertexData(vertexData);
|
setVertexData(vertexData);
|
||||||
|
|
||||||
int lastIndex = (vertexData.size() - 1) / int(sizeof(QVector3D));
|
int lastIndex = (vertexData.size() - 1) / int(sizeof(QVector3D));
|
||||||
auto vertexPtr = reinterpret_cast<QVector3D *>(vertexData.data());
|
|
||||||
setBounds(QVector3D(vertexPtr[0][0], vertexPtr[0][1], 0.0),
|
// Set bounds based on main grid size instead of actual mesh size to make all parts of the
|
||||||
QVector3D(vertexPtr[lastIndex][0], vertexPtr[lastIndex][1], 0.0));
|
// grid have consistent bounds.
|
||||||
|
const float extent = float(m_lines) * m_step;
|
||||||
|
setBounds(QVector3D(-extent, -extent, 0.0),
|
||||||
|
QVector3D(extent, extent, 0.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION_MAJOR == 6 && QT_VERSION_MINOR == 4
|
#if QT_VERSION_MAJOR == 6 && QT_VERSION_MINOR == 4
|
||||||
|
Reference in New Issue
Block a user