QmlDesigner: Introduction of PropertyMetaInfo

Because the project storage is integer id based the string based API
isn't fitting well for the new approach. PropertyMetaInfo can be easier
mapped to the project storage.

Task-number: QDS-7197
Change-Id: I49bc650abdaacf4b039d76c2514b5ad05ec84abe
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2022-06-09 17:03:42 +02:00
parent ae0032dfd5
commit fd41105191
46 changed files with 747 additions and 450 deletions

View File

@@ -28,10 +28,13 @@
#include <QByteArray>
#include <QList>
#include <vector>
namespace QmlDesigner {
using PropertyName = QByteArray;
using PropertyNameList = QList<PropertyName>;
using PropertyNames = std::vector<PropertyName>;
using TypeName = QByteArray;
}

View File

@@ -143,6 +143,8 @@ void ActionEditor::setModelNode(const ModelNode &modelNode)
m_modelNode = modelNode;
}
namespace {
bool isLiteral(QmlJS::AST::Node *ast)
{
if (QmlJS::AST::cast<QmlJS::AST::StringLiteral *>(ast)
@@ -154,6 +156,17 @@ bool isLiteral(QmlJS::AST::Node *ast)
return false;
}
TypeName skipCpp(TypeName typeName)
{
// TODO remove after project storage introduction
if (typeName.contains("<cpp>."))
typeName.remove(0, 6);
return typeName;
}
} // namespace
void ActionEditor::prepareConnections()
{
if (!m_modelNode.isValid())
@@ -197,17 +210,15 @@ void ActionEditor::prepareConnections()
ActionEditorDialog::ConnectionOption connection(modelNode.id());
for (const auto &propertyName : modelNode.metaInfo().propertyNames()) {
if (!typeWhiteList.contains(modelNode.metaInfo().propertyTypeName(propertyName)))
for (const auto &property : modelNode.metaInfo().properties()) {
const auto &propertyTypeName = property.propertyTypeName();
if (!typeWhiteList.contains(propertyTypeName))
continue;
const QString name = QString::fromUtf8(propertyName);
const bool writeable = modelNode.metaInfo().propertyIsWritable(propertyName);
TypeName type = modelNode.metaInfo().propertyTypeName(propertyName);
if (type.contains("<cpp>."))
type.remove(0, 6);
connection.properties.append(ActionEditorDialog::PropertyOption(name, type, writeable));
connection.properties.append(
ActionEditorDialog::PropertyOption(QString::fromUtf8(property.name()),
skipCpp(std::move(propertyTypeName)),
property.isWritable()));
}
for (const VariantProperty &variantProperty : modelNode.variantProperties()) {
@@ -216,12 +227,12 @@ void ActionEditor::prepareConnections()
continue;
const QString name = QString::fromUtf8(variantProperty.name());
const bool writeable = modelNode.metaInfo().propertyIsWritable(variantProperty.name());
TypeName type = variantProperty.dynamicTypeName();
if (type.contains("<cpp>."))
type.remove(0, 6);
const bool writeable = modelNode.metaInfo().property(variantProperty.name()).isWritable();
connection.properties.append(ActionEditorDialog::PropertyOption(name, type, writeable));
connection.properties.append(
ActionEditorDialog::PropertyOption(name,
skipCpp(variantProperty.dynamicTypeName()),
writeable));
}
}
@@ -259,18 +270,16 @@ void ActionEditor::prepareConnections()
NodeMetaInfo metaInfo = m_modelNode.view()->model()->metaInfo(data.typeName.toUtf8());
if (metaInfo.isValid()) {
ActionEditorDialog::SingletonOption singelton;
for (const PropertyName &propertyName : metaInfo.propertyNames()) {
TypeName type = metaInfo.propertyTypeName(propertyName);
for (const auto &property : metaInfo.properties()) {
const TypeName &typeName = property.propertyTypeName();
if (!typeWhiteList.contains(type))
if (!typeWhiteList.contains(typeName))
continue;
const QString name = QString::fromUtf8(propertyName);
const bool writeable = metaInfo.propertyIsWritable(propertyName);
if (type.contains("<cpp>."))
type.remove(0, 6);
singelton.properties.append(ActionEditorDialog::PropertyOption(name, type, writeable));
singelton.properties.append(
ActionEditorDialog::PropertyOption(QString::fromUtf8(property.name()),
skipCpp(typeName),
property.isWritable()));
}
if (!singelton.properties.isEmpty()) {

View File

@@ -113,7 +113,7 @@ void BindingEditor::setBackendValue(const QVariant &backendValue)
const ModelNode node = propertyEditorValue->modelNode();
if (node.isValid()) {
m_backendValueTypeName = node.metaInfo().propertyTypeName(propertyEditorValue->name());
m_backendValueTypeName = node.metaInfo().property(propertyEditorValue->name()).propertyTypeName();
QString nodeId = node.id();
if (nodeId.isEmpty())
@@ -205,14 +205,14 @@ void BindingEditor::prepareBindings()
for (const auto &objnode : allNodes) {
BindingEditorDialog::BindingOption binding;
for (const auto &propertyName : objnode.metaInfo().propertyNames()) {
TypeName propertyTypeName = objnode.metaInfo().propertyTypeName(propertyName);
for (const auto &property : objnode.metaInfo().properties()) {
const TypeName &propertyTypeName = property.propertyTypeName();
if (skipTypeFiltering
|| (m_backendValueTypeName == propertyTypeName)
|| isVariant(propertyTypeName)
|| (targetTypeIsNumeric && isNumeric(propertyTypeName))) {
binding.properties.append(QString::fromUtf8(propertyName));
binding.properties.append(QString::fromUtf8(property.name()));
}
}
@@ -259,15 +259,15 @@ void BindingEditor::prepareBindings()
if (metaInfo.isValid()) {
BindingEditorDialog::BindingOption binding;
for (const PropertyName &propertyName : metaInfo.propertyNames()) {
TypeName propertyTypeName = metaInfo.propertyTypeName(propertyName);
for (const auto &property : metaInfo.properties()) {
TypeName propertyTypeName = property.propertyTypeName();
if (skipTypeFiltering
|| (m_backendValueTypeName == propertyTypeName)
|| (isVariant(propertyTypeName))
|| (targetTypeIsNumeric && isNumeric(propertyTypeName))
|| (isColor(m_backendValueTypeName) && isColor(propertyTypeName))) {
binding.properties.append(QString::fromUtf8(propertyName));
binding.properties.append(QString::fromUtf8(property.name()));
}
}

View File

@@ -39,6 +39,8 @@
#include <qmlitemnode.h>
#include <nodeabstractproperty.h>
#include <utils/set_algorithm.h>
#include <QStandardItemModel>
#include <QSortFilterProxyModel>
#include <QTableView>
@@ -137,6 +139,20 @@ void SignalList::setModelNode(const ModelNode &modelNode)
m_modelNode = modelNode;
}
namespace {
template<typename Callback>
void callOnlyMouseSignalNames(const PropertyNameList &signalNames,
const PropertyNameList &mouseSignalNames,
const Callback &callback)
{
std::set_union(signalNames.begin(),
signalNames.end(),
mouseSignalNames.begin(),
mouseSignalNames.end(),
Utils::make_iterator(callback));
}
} // namespace
void SignalList::prepareSignals()
{
if (!m_modelNode.isValid())
@@ -145,27 +161,21 @@ void SignalList::prepareSignals()
QList<QmlConnections> connections = QmlFlowViewNode::getAssociatedConnections(m_modelNode);
for (ModelNode &node : m_modelNode.view()->allModelNodes()) {
// Collect all items which contain at least one of the specified signals
const PropertyNameList signalNames = node.metaInfo().signalNames();
// Put the signals into a QSet to avoid duplicates
auto signalNamesSet = QSet<PropertyName>(signalNames.begin(), signalNames.end());
for (const PropertyName &signal : signalNamesSet) {
if (QmlFlowViewNode::st_mouseSignals.contains(signal))
appendSignalToModel(connections, node, signal);
}
callOnlyMouseSignalNames(node.metaInfo().signalNames(),
QmlFlowViewNode::mouseSignals(),
[&](const PropertyName &signal) {
appendSignalToModel(connections, node, signal);
});
// Gather valid properties and aliases from components
for (const PropertyName &property : node.metaInfo().propertyNames()) {
const TypeName propertyType = node.metaInfo().propertyTypeName(property);
const NodeMetaInfo info = m_modelNode.model()->metaInfo(propertyType);
// Collect all items which contain at least one of the specified signals
const PropertyNameList signalNames = info.signalNames();
// Put the signals into a QSet to avoid duplicates
auto signalNamesSet = QSet<PropertyName>(signalNames.begin(), signalNames.end());
for (const PropertyName &signal : signalNamesSet) {
if (QmlFlowViewNode::st_mouseSignals.contains(signal))
appendSignalToModel(connections, node, signal, property);
}
for (const auto &property : node.metaInfo().properties()) {
const NodeMetaInfo info = m_modelNode.model()->metaInfo(property.propertyTypeName());
callOnlyMouseSignalNames(info.signalNames(),
QmlFlowViewNode::mouseSignals(),
[&](const PropertyName &signal) {
appendSignalToModel(connections, node, signal);
});
}
}
}

View File

@@ -568,11 +568,17 @@ void layoutGridLayout(const SelectionContext &selectionContext)
}
}
static PropertyNameList sortedPropertyNameList(const PropertyNameList &nameList)
static PropertyNameList sortedPropertyNameList(const PropertyMetaInfos &properties)
{
PropertyNameList sortedPropertyNameList = nameList;
std::stable_sort(sortedPropertyNameList.begin(), sortedPropertyNameList.end());
return sortedPropertyNameList;
auto propertyNames = Utils::transform<PropertyNameList>(properties, [](const auto &property) {
return property.name();
});
std::sort(propertyNames.begin(), propertyNames.end());
propertyNames.erase(std::unique(propertyNames.begin(), propertyNames.end()), propertyNames.end());
return propertyNames;
}
static QString toUpper(const QString &signal)
@@ -628,12 +634,14 @@ static QStringList getSortedSignalNameList(const ModelNode &modelNode)
QStringList signalNames;
if (metaInfo.isValid()) {
const PropertyNameList signalNameList = sortedPropertyNameList(metaInfo.signalNames());
// TODO seem to be broken because there can be properties without notifier and the notifier can be even have a different name
const PropertyNameList signalNameList = metaInfo.signalNames();
for (const PropertyName &signalName : signalNameList)
if (!signalName.contains("Changed"))
signalNames.append(QString::fromUtf8(signalName));
const PropertyNameList propertyNameList = sortedPropertyNameList(metaInfo.propertyNames());
const PropertyNameList propertyNameList = sortedPropertyNameList(metaInfo.properties());
for (const PropertyName &propertyName : propertyNameList)
if (!propertyName.contains("."))
signalNames.append(QString::fromUtf8(propertyName + "Changed"));

View File

@@ -138,14 +138,15 @@ QStringList BindingModel::possibleTargetProperties(const BindingProperty &bindin
NodeMetaInfo metaInfo = modelNode.metaInfo();
if (metaInfo.isValid()) {
QStringList possibleProperties;
const QList<PropertyName> propertyNames = metaInfo.propertyNames();
for (const PropertyName &propertyName : propertyNames) {
if (metaInfo.propertyIsWritable(propertyName))
possibleProperties << QString::fromUtf8(propertyName);
const auto properties = metaInfo.properties();
QStringList writableProperties;
writableProperties.reserve(static_cast<int>(properties.size()));
for (const auto &property : properties) {
if (property.isWritable())
writableProperties.push_back(QString::fromUtf8(property.name()));
}
return possibleProperties;
return writableProperties;
}
return QStringList();
@@ -159,11 +160,10 @@ QStringList BindingModel::possibleSourceProperties(const BindingProperty &bindin
TypeName typeName;
if (bindingProperty.parentModelNode().metaInfo().isValid()) {
typeName = bindingProperty.parentModelNode().metaInfo().propertyTypeName(bindingProperty.name());
} else {
if (auto metaInfo = bindingProperty.parentModelNode().metaInfo(); metaInfo.isValid())
typeName = metaInfo.property(bindingProperty.name()).propertyTypeName();
else
qWarning() << " BindingModel::possibleSourcePropertiesForRow no meta info for target node";
}
const QString &id = stringlist.constFirst();
@@ -178,9 +178,9 @@ QStringList BindingModel::possibleSourceProperties(const BindingProperty &bindin
NodeMetaInfo metaInfo = connectionView()->model()->metaInfo(data.typeName.toUtf8());
if (metaInfo.isValid()) {
for (const PropertyName &propertyName : metaInfo.propertyNames()) {
for (const auto &property : metaInfo.properties()) {
//without check for now
possibleProperties << QString::fromUtf8(propertyName);
possibleProperties.push_back(QString::fromUtf8(property.name()));
}
return possibleProperties;
@@ -207,9 +207,9 @@ QStringList BindingModel::possibleSourceProperties(const BindingProperty &bindin
}
if (metaInfo.isValid()) {
for (const PropertyName &propertyName : metaInfo.propertyNames()) {
if (metaInfo.propertyTypeName(propertyName) == typeName) //### todo proper check
possibleProperties << QString::fromUtf8(propertyName);
for (const auto &property : metaInfo.properties()) {
if (property.propertyTypeName() == typeName) //### todo proper check
possibleProperties.push_back(QString::fromUtf8(property.name()));
}
} else {
qWarning() << " BindingModel::possibleSourcePropertiesForRow no meta info for source node";
@@ -233,10 +233,9 @@ static PropertyName unusedProperty(const ModelNode &modelNode)
{
PropertyName propertyName = "none";
if (modelNode.metaInfo().isValid()) {
const QList<PropertyName> propertyNames = modelNode.metaInfo().propertyNames();
for (const PropertyName &propertyName : propertyNames) {
if (modelNode.metaInfo().propertyIsWritable(propertyName) && !modelNode.hasProperty(propertyName))
return propertyName;
for (const auto &property : modelNode.metaInfo().properties()) {
if (property.isWritable() && !modelNode.hasProperty(propertyName))
return property.name();
}
}

View File

@@ -475,7 +475,7 @@ QStringList ConnectionModel::getPossibleSignalsForConnection(const ModelNode &co
auto getAliasMetaSignals = [&](QString aliasPart, NodeMetaInfo metaInfo) {
if (metaInfo.isValid() && metaInfo.hasProperty(aliasPart.toUtf8())) {
NodeMetaInfo propertyMetaInfo = connectionView()->model()->metaInfo(
metaInfo.propertyTypeName(aliasPart.toUtf8()));
metaInfo.property(aliasPart.toUtf8()).propertyTypeName());
if (propertyMetaInfo.isValid()) {
return propertyNameListToStringList(propertyMetaInfo.signalNames());
}

View File

@@ -216,8 +216,9 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event)
return;
const ModelNode node = property.parentModelNode();
const TypeName typeName = property.isDynamic() ? property.dynamicTypeName()
: node.metaInfo().propertyTypeName(property.name());
const TypeName typeName = property.isDynamic()
? property.dynamicTypeName()
: node.metaInfo().property(property.name()).propertyTypeName();
const QString targetName = node.displayName() + "." + property.name();

View File

@@ -298,23 +298,19 @@ QWidget *ConnectionDelegate::createEditor(QWidget *parent, const QStyleOptionVie
auto addMetaInfoProperties = [&](const NodeMetaInfo& itemMetaInfo, QString itemName){
if (itemMetaInfo.isValid()) {
for (const PropertyName &propertyName : itemMetaInfo.propertyNames()) {
TypeName propertyType = itemMetaInfo.propertyTypeName(propertyName);
for (const auto &property : itemMetaInfo.properties()) {
TypeName propertyType = property.propertyTypeName();
if (!propertyType.isEmpty()) {
//first letter is a reliable item indicator
QChar firstLetter = QString::fromUtf8(propertyType).at(0);
if (firstLetter.isLetter() && firstLetter.isUpper()) {
if (!itemMetaInfo.propertyIsEnumType(propertyName)
&& !itemMetaInfo.propertyIsPrivate(propertyName)
&& !itemMetaInfo.propertyIsListProperty(propertyName)
&& !itemMetaInfo.propertyIsPointer(propertyName)) {
if (!property.isEnumType() && !property.isPrivate()
&& !property.isListProperty() && !property.isPointer()) {
NodeMetaInfo propertyMetaInfo =
connectionModel->connectionView()->model()->metaInfo(propertyType);
if (propertyMetaInfo.isValid()) {
if (propertyMetaInfo.isQmlItem()) {
connectionComboBox->addItem(itemName
+ "."
+ propertyName);
connectionComboBox->addItem(itemName + "." + property.name());
}
}
}

View File

@@ -36,6 +36,7 @@
#include <qmldesignerplugin.h>
#include <qmldesignerconstants.h>
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <QMessageBox>
@@ -345,10 +346,9 @@ QStringList DynamicPropertiesModel::possibleTargetProperties(const BindingProper
if (metaInfo.isValid()) {
QStringList possibleProperties;
const QList<PropertyName> propertyNames = metaInfo.propertyNames();
for (const PropertyName &propertyName : propertyNames) {
if (metaInfo.propertyIsWritable(propertyName))
possibleProperties << QString::fromUtf8(propertyName);
for (const auto &property : metaInfo.properties()) {
if (property.isWritable())
possibleProperties.push_back(QString::fromUtf8(property.name()));
}
return possibleProperties;
@@ -383,8 +383,8 @@ QStringList DynamicPropertiesModel::possibleSourceProperties(const BindingProper
PropertyName typeName;
if (bindingProperty.parentModelNode().metaInfo().isValid()) {
typeName = bindingProperty.parentModelNode().metaInfo().propertyTypeName(bindingProperty.name());
if (auto metaInfo = bindingProperty.parentModelNode().metaInfo(); metaInfo.isValid()) {
typeName = metaInfo.property(bindingProperty.name()).propertyTypeName();
} else {
qWarning() << " BindingModel::possibleSourcePropertiesForRow no meta info for target node";
}
@@ -402,10 +402,9 @@ QStringList DynamicPropertiesModel::possibleSourceProperties(const BindingProper
if (metaInfo.isValid()) {
QStringList possibleProperties;
const QList<PropertyName> propertyNames = metaInfo.propertyNames();
for (const PropertyName &propertyName : propertyNames) {
if (metaInfo.propertyTypeName(propertyName) == typeName) //### todo proper check
possibleProperties << QString::fromUtf8(propertyName);
for (const auto &property : metaInfo.properties()) {
if (property.propertyTypeName() == typeName) //### todo proper check
possibleProperties.push_back(QString::fromUtf8(property.name()));
}
return possibleProperties;
} else {

View File

@@ -658,7 +658,7 @@ void DesignDocument::paste()
PropertyName defaultProperty(targetNode.metaInfo().defaultPropertyName());
scatterItem(pastedNode, targetNode);
if (targetNode.metaInfo().propertyIsListProperty(defaultProperty))
if (targetNode.metaInfo().property(defaultProperty).isListProperty())
targetNode.nodeListProperty(defaultProperty).reparentHere(pastedNode);
else
qWarning() << "Cannot reparent to" << targetNode;

View File

@@ -99,7 +99,8 @@ void MaterialEditorContextObject::changeTypeName(const QString &typeName)
QTC_ASSERT(metaInfo.isValid(), return);
// Create a list of properties available for the new type
PropertyNameList propertiesAndSignals(metaInfo.propertyNames());
PropertyNameList propertiesAndSignals = Utils::transform<PropertyNameList>(
metaInfo.properties(), [](const auto &property) { return property.name(); });
// Add signals to the list
const PropertyNameList signalNames = metaInfo.signalNames();
for (const PropertyName &signal : signalNames) {

View File

@@ -270,9 +270,12 @@ void MaterialEditorQmlBackend::setup(const QmlObjectNode &selectedMaterialNode,
if (selectedMaterialNode.isValid()) {
m_contextObject->setModel(materialEditor->model());
const PropertyNameList propertyNames = selectedMaterialNode.modelNode().metaInfo().propertyNames();
for (const PropertyName &propertyName : propertyNames)
createPropertyEditorValue(selectedMaterialNode, propertyName, selectedMaterialNode.instanceValue(propertyName), materialEditor);
for (const auto &property : selectedMaterialNode.modelNode().metaInfo().properties()) {
createPropertyEditorValue(selectedMaterialNode,
property.name(),
selectedMaterialNode.instanceValue(property.name()),
materialEditor);
}
// model node
m_backendModelNode.setup(selectedMaterialNode.modelNode());

View File

@@ -125,7 +125,7 @@ void MaterialEditorView::changeValue(const QString &name)
QVariant castedValue;
if (metaInfo.isValid() && metaInfo.hasProperty(propertyName)) {
castedValue = metaInfo.propertyCastedValue(propertyName, value->value());
castedValue = metaInfo.property(propertyName).castedValue(value->value());
} else {
qWarning() << __FUNCTION__ << propertyName << "cannot be casted (metainfo)";
return;
@@ -139,8 +139,7 @@ void MaterialEditorView::changeValue(const QString &name)
bool propertyTypeUrl = false;
if (metaInfo.isValid() && metaInfo.hasProperty(propertyName)) {
if (metaInfo.propertyTypeName(propertyName) == "QUrl"
|| metaInfo.propertyTypeName(propertyName) == "url") {
if (metaInfo.property(propertyName).hasPropertyTypeName("QUrl", "url")) {
// turn absolute local file paths into relative paths
propertyTypeUrl = true;
QString filePath = castedValue.toUrl().toString();
@@ -202,13 +201,15 @@ void MaterialEditorView::changeExpression(const QString &propertyName)
return;
}
if (m_selectedMaterial.metaInfo().isValid() && m_selectedMaterial.metaInfo().hasProperty(name)) {
if (m_selectedMaterial.metaInfo().propertyTypeName(name) == "QColor") {
if (auto metaInfo = m_selectedMaterial.metaInfo();
metaInfo.isValid() && metaInfo.hasProperty(name)) {
auto propertyTypeName = metaInfo.property(name).propertyTypeName();
if (propertyTypeName == "QColor") {
if (QColor(value->expression().remove('"')).isValid()) {
qmlObjectNode.setVariantProperty(name, QColor(value->expression().remove('"')));
return;
}
} else if (m_selectedMaterial.metaInfo().propertyTypeName(name) == "bool") {
} else if (propertyTypeName == "bool") {
if (isTrueFalseLiteral(value->expression())) {
if (value->expression().compare("true", Qt::CaseInsensitive) == 0)
qmlObjectNode.setVariantProperty(name, true);
@@ -216,21 +217,21 @@ void MaterialEditorView::changeExpression(const QString &propertyName)
qmlObjectNode.setVariantProperty(name, false);
return;
}
} else if (m_selectedMaterial.metaInfo().propertyTypeName(name) == "int") {
} else if (propertyTypeName == "int") {
bool ok;
int intValue = value->expression().toInt(&ok);
if (ok) {
qmlObjectNode.setVariantProperty(name, intValue);
return;
}
} else if (m_selectedMaterial.metaInfo().propertyTypeName(name) == "qreal") {
} else if (propertyTypeName == "qreal") {
bool ok;
qreal realValue = value->expression().toDouble(&ok);
if (ok) {
qmlObjectNode.setVariantProperty(name, realValue);
return;
}
} else if (m_selectedMaterial.metaInfo().propertyTypeName(name) == "QVariant") {
} else if (propertyTypeName == "QVariant") {
bool ok;
qreal realValue = value->expression().toDouble(&ok);
if (ok) {
@@ -809,7 +810,7 @@ void QmlDesigner::MaterialEditorView::highlightSupportedProperties(bool highligh
QTC_ASSERT(metaInfo.isValid(), return);
for (const QString &propName : propNames) {
if (metaInfo.propertyTypeName(propName.toLatin1()) == "QtQuick3D.Texture") {
if (metaInfo.property(propName.toUtf8()).hasPropertyTypeName("QtQuick3D.Texture")) {
QObject *propEditorValObj = propMap.value(propName).value<QObject *>();
PropertyEditorValue *propEditorVal = qobject_cast<PropertyEditorValue *>(propEditorValObj);
propEditorVal->setHasActiveDrag(highlight);

View File

@@ -65,11 +65,10 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i
if (parentInfo.isSubclassOf("QtQuick3D.DefaultMaterial")
|| parentInfo.isSubclassOf("QtQuick3D.PrincipledMaterial")) {
// All texture properties are valid targets
const PropertyNameList targetNodeNameList = parentInfo.propertyNames();
for (const PropertyName &name : targetNodeNameList) {
TypeName propType = parentInfo.propertyTypeName(name);
for (const auto &property : parentInfo.properties()) {
const TypeName &propType = property.propertyTypeName();
if (propType == textureType || propType == textureTypeCpp) {
propertyList.append(QString::fromLatin1(name));
propertyList.append(QString::fromUtf8(property.name()));
if (breakOnFirst)
return;
}
@@ -168,15 +167,13 @@ ChooseFromPropertyListDialog *ChooseFromPropertyListDialog::createIfNeeded(
// Create dialog for selecting writable properties of exact property type
ChooseFromPropertyListDialog *ChooseFromPropertyListDialog::createIfNeeded(
const ModelNode &targetNode, TypeName type, QWidget *parent)
const ModelNode &targetNode, TypeName propertyType, QWidget *parent)
{
const NodeMetaInfo metaInfo = targetNode.metaInfo();
const PropertyNameList propNames = metaInfo.propertyNames();
const TypeName property(type);
QStringList matchingNames;
for (const auto &propName : propNames) {
if (metaInfo.propertyTypeName(propName) == property && metaInfo.propertyIsWritable(propName))
matchingNames.append(QString::fromLatin1(propName));
for (const auto &property : metaInfo.properties()) {
if (property.hasPropertyTypeName(propertyType) && property.isWritable())
matchingNames.append(QString::fromUtf8(property.name()));
}
if (!matchingNames.isEmpty())

View File

@@ -725,7 +725,7 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in
}
}
if (targetNode.metaInfo().propertyIsListProperty(selectedProp)) {
if (targetNode.metaInfo().property(selectedProp).isListProperty()) {
BindingProperty listProp = targetNode.bindingProperty(selectedProp);
listProp.addModelNodeToArray(newModelNode);
validContainer = true;
@@ -1105,7 +1105,7 @@ ModelNode NavigatorTreeModel::createTextureNode(const NodeAbstractProperty &targ
TypeName propertyType(const NodeAbstractProperty &property)
{
return property.parentModelNode().metaInfo().propertyTypeName(property.name());
return property.parentModelNode().metaInfo().property(property.name()).propertyTypeName();
}
void NavigatorTreeModel::moveNodesInteractive(NodeAbstractProperty &parentProperty,

View File

@@ -220,7 +220,10 @@ void PropertyEditorContextObject::changeTypeName(const QString &typeName)
}
// Create a list of properties available for the new type
QList<PropertyName> propertiesAndSignals(metaInfo.propertyNames());
auto propertiesAndSignals = Utils::transform<PropertyNameList>(metaInfo.properties(),
[](const auto &property) {
return property.name();
});
// Add signals to the list
for (const auto &signal : metaInfo.signalNames()) {
if (signal.isEmpty())

View File

@@ -25,8 +25,9 @@
#include "propertyeditorqmlbackend.h"
#include "propertyeditorvalue.h"
#include "propertyeditortransaction.h"
#include "propertyeditorvalue.h"
#include "propertymetainfo.h"
#include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
#include <qmltimeline.h>
@@ -415,10 +416,13 @@ void PropertyEditorQmlBackend::setup(const QmlObjectNode &qmlObjectNode, const Q
if (propertyEditorBenchmark().isInfoEnabled())
time.start();
const QList<PropertyName> propertyNames = qmlObjectNode.modelNode().metaInfo().propertyNames();
for (const PropertyName &propertyName : propertyNames)
createPropertyEditorValue(qmlObjectNode, propertyName, qmlObjectNode.instanceValue(propertyName), propertyEditor);
for (const auto &property : qmlObjectNode.modelNode().metaInfo().properties()) {
auto propertyName = property.name();
createPropertyEditorValue(qmlObjectNode,
propertyName,
qmlObjectNode.instanceValue(propertyName),
propertyEditor);
}
setupLayoutAttachedProperties(qmlObjectNode, propertyEditor);
setupAuxiliaryProperties(qmlObjectNode, propertyEditor);
@@ -514,9 +518,11 @@ void PropertyEditorQmlBackend::initialSetup(const TypeName &typeName, const QUrl
{
NodeMetaInfo metaInfo = propertyEditor->model()->metaInfo(typeName);
const QList<PropertyName> propertyNames = metaInfo.propertyNames();
for (const PropertyName &propertyName : propertyNames)
setupPropertyEditorValue(propertyName, propertyEditor, QString::fromUtf8(metaInfo.propertyTypeName(propertyName)));
for (const auto &property : metaInfo.properties()) {
setupPropertyEditorValue(property.name(),
propertyEditor,
QString::fromUtf8(property.propertyTypeName()));
}
auto valueObject = qobject_cast<PropertyEditorValue *>(variantToQObject(
m_backendValuesPropertyMap.value(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY)));
@@ -579,7 +585,7 @@ inline bool dotPropertyHeuristic(const QmlObjectNode &node, const NodeMetaInfo &
const PropertyName parentProperty = list.first();
const PropertyName itemProperty = list.last();
TypeName typeName = type.propertyTypeName(parentProperty);
TypeName typeName = type.property(parentProperty).propertyTypeName();
NodeMetaInfo itemInfo = node.view()->model()->metaInfo("QtQuick.Item");
NodeMetaInfo textInfo = node.view()->model()->metaInfo("QtQuick.Text");
@@ -596,7 +602,7 @@ inline bool dotPropertyHeuristic(const QmlObjectNode &node, const NodeMetaInfo &
return true;
}
QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type,
QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &metaType,
const NodeMetaInfo &superType,
const QmlObjectNode &node)
{
@@ -615,20 +621,22 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type,
allTypes.append(variantToStringList(node->property("typeNames").value));
}
const QList<PropertyName> allProperties = type.propertyNames();
QMap<PropertyName, QList<PropertyName>> propertyMap;
QList<PropertyName> separateSectionProperties;
auto propertyMetaInfoCompare = [](const auto &first, const auto &second) {
return first.name() < second.name();
};
std::map<PropertyMetaInfo, PropertyMetaInfos, decltype(propertyMetaInfoCompare)> propertyMap(
propertyMetaInfoCompare);
PropertyMetaInfos separateSectionProperties;
// Iterate over all properties and isolate the properties which have their own template
for (const PropertyName &propertyName : allProperties) {
for (const auto &property : metaType.properties()) {
const auto &propertyName = property.name();
if (propertyName.startsWith("__"))
continue; // private API
if (!superType.hasProperty(propertyName)
&& type.propertyIsWritable(propertyName)
&& dotPropertyHeuristic(node, type, propertyName)) {
QString typeName = QString::fromLatin1(type.propertyTypeName(propertyName));
if (!superType.hasProperty(propertyName) // TODO add property.isLocalProperty()
&& property.isWritable() && dotPropertyHeuristic(node, metaType, propertyName)) {
QString typeName = QString::fromUtf8(property.propertyTypeName());
if (typeName == "alias" && node.isValid())
typeName = QString::fromLatin1(node.instanceType(propertyName));
@@ -636,18 +644,16 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type,
// Check if a template for the type exists
if (allTypes.contains(typeName)) {
if (separateSectionTypes.contains(typeName)) { // template enforces separate section
separateSectionProperties.append(propertyName);
separateSectionProperties.push_back(property);
} else {
if (propertyName.contains('.')) {
const PropertyName parentProperty = propertyName.split('.').first();
const PropertyName parentPropertyName = propertyName.split('.').first();
const PropertyMetaInfo parentProperty = metaType.property(
parentPropertyName);
if (propertyMap.contains(parentProperty))
propertyMap[parentProperty].append(propertyName);
else
propertyMap[parentProperty] = { propertyName };
propertyMap[parentProperty].push_back(property);
} else {
if (!propertyMap.contains(propertyName))
propertyMap[propertyName] = {};
propertyMap[property];
}
}
}
@@ -655,28 +661,29 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type,
}
// Filter out the properties which have a basic type e.g. int, string, bool
QList<PropertyName> basicProperties;
PropertyMetaInfos basicProperties;
auto it = propertyMap.begin();
while (it != propertyMap.end()) {
if (it.value().empty()) {
basicProperties.append(it.key());
if (it->second.empty()) {
basicProperties.push_back(it->first);
it = propertyMap.erase(it);
} else {
++it;
}
}
Utils::sort(basicProperties);
Utils::sort(basicProperties, propertyMetaInfoCompare);
auto findAndFillTemplate = [&nodes, &node, &type](const PropertyName &label,
const PropertyName &property) {
PropertyName underscoreProperty = property;
auto findAndFillTemplate = [&nodes, &node](const PropertyName &label,
const PropertyMetaInfo &property) {
const auto &propertyName = property.name();
PropertyName underscoreProperty = propertyName;
underscoreProperty.replace('.', '_');
TypeName typeName = type.propertyTypeName(property);
TypeName typeName = property.propertyTypeName();
// alias resolution only possible with instance
if (typeName == "alias" && node.isValid())
typeName = node.instanceType(property);
typeName = node.instanceType(propertyName);
QString filledTemplate;
for (const QmlJS::SimpleReaderNode::Ptr &n : nodes) {
@@ -730,8 +737,8 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type,
qmlInnerTemplate += "bottomPadding: 10\n";
qmlInnerTemplate += "SectionLayout {\n";
for (const auto &p : qAsConst(basicProperties))
qmlInnerTemplate += findAndFillTemplate(p, p);
for (const auto &basicProperty : std::as_const(basicProperties))
qmlInnerTemplate += findAndFillTemplate(basicProperty.name(), basicProperty);
qmlInnerTemplate += "}\n"; // SectionLayout
qmlInnerTemplate += "}\n"; // Column
@@ -740,16 +747,17 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type,
// Second the section containing properties of complex type for which no specific template exists e.g. Button
if (!propertyMap.empty()) {
emptyTemplate = false;
for (auto it = propertyMap.cbegin(); it != propertyMap.cend(); ++it) {
const auto &key = it.key();
TypeName parentTypeName = type.propertyTypeName(key);
for (auto &[property, properties] : propertyMap) {
// for (auto it = propertyMap.cbegin(); it != propertyMap.cend(); ++it) {
TypeName parentTypeName = property.propertyTypeName();
// alias resolution only possible with instance
if (parentTypeName == "alias" && node.isValid())
parentTypeName = node.instanceType(key);
parentTypeName = node.instanceType(property.name());
qmlInnerTemplate += "Section {\n";
qmlInnerTemplate += QStringLiteral("caption: \"%1 - %2\"\n")
.arg(QString::fromUtf8(key), QString::fromUtf8(parentTypeName));
.arg(QString::fromUtf8(property.name()),
QString::fromUtf8(parentTypeName));
qmlInnerTemplate += anchorLeftRight;
qmlInnerTemplate += "leftPadding: 8\n";
qmlInnerTemplate += "rightPadding: 0\n";
@@ -757,12 +765,14 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type,
qmlInnerTemplate += "level: 1\n";
qmlInnerTemplate += "SectionLayout {\n";
auto properties = it.value();
Utils::sort(properties);
Utils::sort(properties, propertyMetaInfoCompare);
for (const auto &p : qAsConst(properties)) {
const PropertyName shortName = p.contains('.') ? p.split('.').last() : p;
qmlInnerTemplate += findAndFillTemplate(shortName, p);
for (const auto &subProperty : properties) {
const auto &propertyName = subProperty.name();
auto found = std::find(propertyName.rbegin(), propertyName.rend(), '.');
const PropertyName shortName{found.base(),
std::distance(found.base(), propertyName.end())};
qmlInnerTemplate += findAndFillTemplate(shortName, property);
}
qmlInnerTemplate += "}\n"; // SectionLayout
@@ -773,9 +783,9 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type,
// Third the section containing properties of complex type for which a specific template exists e.g. Rectangle, Image
if (!separateSectionProperties.empty()) {
emptyTemplate = false;
Utils::sort(separateSectionProperties);
for (const auto &p : qAsConst(separateSectionProperties))
qmlInnerTemplate += findAndFillTemplate(p, p);
Utils::sort(separateSectionProperties, propertyMetaInfoCompare);
for (const auto &property : separateSectionProperties)
qmlInnerTemplate += findAndFillTemplate(property.name(), property);
}
qmlInnerTemplate += "}\n"; // Column

View File

@@ -60,9 +60,13 @@ PropertyEditorValue::PropertyEditorValue(QObject *parent)
QVariant PropertyEditorValue::value() const
{
QVariant returnValue = m_value;
if (modelNode().isValid() && modelNode().metaInfo().isValid() && modelNode().metaInfo().hasProperty(name()))
if (modelNode().metaInfo().propertyTypeName(name()) == "QUrl")
if (modelNode().isValid()) {
if (auto metaInfo = modelNode().metaInfo();
metaInfo.isValid() && metaInfo.hasProperty(name())
&& metaInfo.property(name()).hasPropertyTypeName("QUrl", "url")) {
returnValue = returnValue.toUrl().toString();
}
}
return returnValue;
}
@@ -100,28 +104,30 @@ static void fixAmbigousColorNames(const QmlDesigner::ModelNode &modelNode,
const QmlDesigner::PropertyName &name,
QVariant *value)
{
if (modelNode.isValid() && modelNode.metaInfo().isValid()
&& (modelNode.metaInfo().propertyTypeName(name) == "QColor"
|| modelNode.metaInfo().propertyTypeName(name) == "color")) {
if ((value->type() == QVariant::Color)) {
QColor color = value->value<QColor>();
int alpha = color.alpha();
color = QColor(color.name());
color.setAlpha(alpha);
*value = color;
} else if (value->toString() != QStringLiteral("transparent")) {
*value = QColor(value->toString()).name(QColor::HexArgb);
if (modelNode.isValid()) {
if (auto metaInfo = modelNode.metaInfo();
metaInfo.isValid() && metaInfo.property(name).hasPropertyTypeName("QColor", "color")) {
if ((value->type() == QVariant::Color)) {
QColor color = value->value<QColor>();
int alpha = color.alpha();
color = QColor(color.name());
color.setAlpha(alpha);
*value = color;
} else if (value->toString() != QStringLiteral("transparent")) {
*value = QColor(value->toString()).name(QColor::HexArgb);
}
}
}
}
static void fixUrl(const QmlDesigner::ModelNode &modelNode, const QmlDesigner::PropertyName &name, QVariant *value)
{
if (modelNode.isValid() && modelNode.metaInfo().isValid()
&& (modelNode.metaInfo().propertyTypeName(name) == "QUrl"
|| modelNode.metaInfo().propertyTypeName(name) == "url")) {
if (!value->isValid())
*value = QStringLiteral("");
if (modelNode.isValid()) {
if (auto metaInfo = modelNode.metaInfo();
metaInfo.isValid() && metaInfo.property(name).hasPropertyTypeName("QUrl", "url"))
if (!value->isValid())
*value = QStringLiteral("");
}
}
@@ -140,9 +146,13 @@ void PropertyEditorValue::setValueWithEmit(const QVariant &value)
{
if (!compareVariants(value, m_value ) || isBound()) {
QVariant newValue = value;
if (modelNode().isValid() && modelNode().metaInfo().isValid() && modelNode().metaInfo().hasProperty(name()))
if (modelNode().metaInfo().propertyTypeName(name()) == "QUrl")
if (modelNode().isValid()) {
if (auto metaInfo = modelNode().metaInfo();
metaInfo.isValid() && metaInfo.hasProperty(name())
&& metaInfo.property(name()).hasPropertyTypeName("QUrl")) {
newValue = QUrl(newValue.toString());
}
}
if (cleverDoubleCompare(newValue, m_value))
return;
@@ -255,12 +265,14 @@ void PropertyEditorValue::setIsValid(bool valid)
bool PropertyEditorValue::isTranslated() const
{
if (modelNode().isValid() && modelNode().metaInfo().isValid() && modelNode().metaInfo().hasProperty(name())) {
if (modelNode().metaInfo().propertyTypeName(name()) == "QString" || modelNode().metaInfo().propertyTypeName(name()) == "string") {
if (modelNode().isValid()) {
if (auto metaInfo = modelNode().metaInfo();
metaInfo.isValid() && metaInfo.hasProperty(name())
&& metaInfo.property(name()).hasPropertyTypeName("QString", "string")) {
const QmlDesigner::QmlObjectNode objectNode(modelNode());
if (objectNode.isValid() && objectNode.hasBindingProperty(name())) {
const QRegularExpression rx(QRegularExpression::anchoredPattern(
"qsTr(|Id|anslate)\\(\".*\"\\)"));
const QRegularExpression rx(
QRegularExpression::anchoredPattern("qsTr(|Id|anslate)\\(\".*\"\\)"));
//qsTr()
if (objectNode.propertyAffectedByCurrentState(name())) {
return expression().contains(rx);
@@ -268,7 +280,6 @@ bool PropertyEditorValue::isTranslated() const
return modelNode().bindingProperty(name()).expression().contains(rx);
}
}
return false;
}
}
return false;
@@ -424,12 +435,14 @@ void PropertyEditorValue::removeAliasExport()
QString PropertyEditorValue::getTranslationContext() const
{
if (modelNode().isValid() && modelNode().metaInfo().isValid() && modelNode().metaInfo().hasProperty(name())) {
if (modelNode().metaInfo().propertyTypeName(name()) == "QString" || modelNode().metaInfo().propertyTypeName(name()) == "string") {
if (modelNode().isValid()) {
if (auto metaInfo = modelNode().metaInfo();
metaInfo.isValid() && metaInfo.hasProperty(name())
&& metaInfo.property(name()).hasPropertyTypeName("QString", "string")) {
const QmlDesigner::QmlObjectNode objectNode(modelNode());
if (objectNode.isValid() && objectNode.hasBindingProperty(name())) {
const QRegularExpression rx(QRegularExpression::anchoredPattern(
"qsTranslate\\(\"(.*)\"\\s*,\\s*\".*\"\\s*\\)"));
"qsTranslate\\(\"(.*)\"\\s*,\\s*\".*\"\\s*\\)"));
const QRegularExpressionMatch match = rx.match(expression());
if (match.hasMatch())
return match.captured(1);
@@ -519,7 +532,7 @@ bool PropertyEditorValue::idListReplace(int idx, const QString &value)
void PropertyEditorValue::commitDrop(const QString &path)
{
if (m_modelNode.isSubclassOf("QtQuick3D.Material")
&& m_modelNode.metaInfo().propertyTypeName(m_name) == "QtQuick3D.Texture") {
&& m_modelNode.metaInfo().property(m_name).hasPropertyTypeName("QtQuick3D.Texture")) {
// create a texture node
QmlDesigner::NodeMetaInfo metaInfo = m_modelNode.view()->model()->metaInfo("QtQuick3D.Texture");
QmlDesigner::ModelNode texture = m_modelNode.view()->createModelNode("QtQuick3D.Texture",
@@ -618,8 +631,12 @@ void PropertyEditorNodeWrapper::add(const QString &type)
QmlDesigner::TypeName propertyType = type.toUtf8();
if ((m_editorValue && m_editorValue->modelNode().isValid())) {
if (propertyType.isEmpty())
propertyType = m_editorValue->modelNode().metaInfo().propertyTypeName(m_editorValue->name());
if (propertyType.isEmpty()) {
propertyType = m_editorValue->modelNode()
.metaInfo()
.property(m_editorValue->name())
.propertyTypeName();
}
while (propertyType.contains('*')) //strip star
propertyType.chop(1);
m_modelNode = m_editorValue->modelNode().view()->createModelNode(propertyType, 4, 7);
@@ -681,9 +698,9 @@ void PropertyEditorNodeWrapper::setup()
m_valuesPropertyMap.clear(propertyName);
qDeleteAll(m_valuesPropertyMap.children());
const QList<QmlDesigner::PropertyName> propertyNameList = m_modelNode.metaInfo().propertyNames();
for (const QmlDesigner::PropertyName &propertyName : propertyNameList) {
if (qmlObjectNode.isValid()) {
if (qmlObjectNode.isValid()) {
for (const auto &property : m_modelNode.metaInfo().properties()) {
const auto &propertyName = property.name();
auto valueObject = new PropertyEditorValue(&m_valuesPropertyMap);
valueObject->setName(propertyName);
valueObject->setValue(qmlObjectNode.instanceValue(propertyName));

View File

@@ -185,7 +185,7 @@ void PropertyEditorView::changeValue(const QString &name)
QVariant castedValue;
if (metaInfo.isValid() && metaInfo.hasProperty(propertyName)) {
castedValue = metaInfo.propertyCastedValue(propertyName, value->value());
castedValue = metaInfo.property(propertyName).castedValue(value->value());
} else if (propertyIsAttachedLayoutProperty(propertyName)) {
castedValue = value->value();
} else {
@@ -200,17 +200,15 @@ void PropertyEditorView::changeValue(const QString &name)
bool propertyTypeUrl = false;
if (metaInfo.isValid() && metaInfo.hasProperty(propertyName)) {
if (metaInfo.propertyTypeName(propertyName) == "QUrl"
|| metaInfo.propertyTypeName(propertyName) == "url") {
// turn absolute local file paths into relative paths
propertyTypeUrl = true;
QString filePath = castedValue.toUrl().toString();
QFileInfo fi(filePath);
if (fi.exists() && fi.isAbsolute()) {
QDir fileDir(QFileInfo(model()->fileUrl().toLocalFile()).absolutePath());
castedValue = QUrl(fileDir.relativeFilePath(filePath));
}
if (metaInfo.isValid() && metaInfo.hasProperty(propertyName)
&& metaInfo.property(propertyName).hasPropertyTypeName("QUrl", "url")) {
// turn absolute local file paths into relative paths
propertyTypeUrl = true;
QString filePath = castedValue.toUrl().toString();
QFileInfo fi(filePath);
if (fi.exists() && fi.isAbsolute()) {
QDir fileDir(QFileInfo(model()->fileUrl().toLocalFile()).absolutePath());
castedValue = QUrl(fileDir.relativeFilePath(filePath));
}
}
@@ -272,13 +270,15 @@ void PropertyEditorView::changeExpression(const QString &propertyName)
return;
}
if (qmlObjectNode->modelNode().metaInfo().isValid() && qmlObjectNode->modelNode().metaInfo().hasProperty(name)) {
if (qmlObjectNode->modelNode().metaInfo().propertyTypeName(name) == "QColor") {
if (auto metaInfo = qmlObjectNode->modelNode().metaInfo();
metaInfo.isValid() && metaInfo.hasProperty(name)) {
const auto &propertTypeName = metaInfo.property(name).propertyTypeName();
if (propertTypeName == "QColor") {
if (QColor(value->expression().remove('"')).isValid()) {
qmlObjectNode->setVariantProperty(name, QColor(value->expression().remove('"')));
return;
}
} else if (qmlObjectNode->modelNode().metaInfo().propertyTypeName(name) == "bool") {
} else if (propertTypeName == "bool") {
if (isTrueFalseLiteral(value->expression())) {
if (value->expression().compare("true", Qt::CaseInsensitive) == 0)
qmlObjectNode->setVariantProperty(name, true);
@@ -286,21 +286,21 @@ void PropertyEditorView::changeExpression(const QString &propertyName)
qmlObjectNode->setVariantProperty(name, false);
return;
}
} else if (qmlObjectNode->modelNode().metaInfo().propertyTypeName(name) == "int") {
} else if (propertTypeName == "int") {
bool ok;
int intValue = value->expression().toInt(&ok);
if (ok) {
qmlObjectNode->setVariantProperty(name, intValue);
return;
}
} else if (qmlObjectNode->modelNode().metaInfo().propertyTypeName(name) == "qreal") {
} else if (propertTypeName == "qreal") {
bool ok;
qreal realValue = value->expression().toDouble(&ok);
if (ok) {
qmlObjectNode->setVariantProperty(name, realValue);
return;
}
} else if (qmlObjectNode->modelNode().metaInfo().propertyTypeName(name) == "QVariant") {
} else if (propertTypeName == "QVariant") {
bool ok;
qreal realValue = value->expression().toDouble(&ok);
if (ok) {

View File

@@ -53,15 +53,8 @@ namespace {
bool modelNodeHasUrlSource(const QmlDesigner::ModelNode &modelNode)
{
QmlDesigner::NodeMetaInfo metaInfo = modelNode.metaInfo();
if (metaInfo.isValid()) {
if (metaInfo.hasProperty("source")) {
if (metaInfo.propertyTypeName("source") == "QUrl")
return true;
if (metaInfo.propertyTypeName("source") == "url")
return true;
}
}
return false;
return metaInfo.isValid() && metaInfo.hasProperty("source")
&& metaInfo.property("source").hasPropertyTypeName("QUrl", "url");
}
} //namespace

View File

@@ -234,8 +234,10 @@ TimelinePropertyItem *TimelinePropertyItem::create(const QmlTimelineKeyframeGrou
if (!objectNode.isValid())
return item;
auto nameOfType = objectNode.modelNode().metaInfo().propertyTypeName(
item->m_frames.propertyName());
auto nameOfType = objectNode.modelNode()
.metaInfo()
.property(item->m_frames.propertyName())
.propertyTypeName();
item->m_control = createTimelineControl(nameOfType);
if (item->m_control) {
item->m_control->setSize((TimelineConstants::sectionWidth / 2.6) - 10,

View File

@@ -226,7 +226,7 @@ ModelNode TransitionEditorView::addNewTransition()
if (target.isValid() && target.hasMetaInfo()) {
const QString targetId = target.id();
for (const VariantProperty &property : change.modelNode().variantProperties()) {
TypeName typeName = target.metaInfo().propertyTypeName(property.name());
TypeName typeName = target.metaInfo().property(property.name()).propertyTypeName();
if (typeName.startsWith("<cpp>."))
typeName.remove(0, 6);

View File

@@ -0,0 +1,51 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <qmldesignercorelib_global.h>
#include <QSharedPointer>
#include <QString>
#include <vector>
namespace QmlDesigner {
class EnumerationMetaInfo
{
public:
EnumerationMetaInfo(QSharedPointer<class NodeMetaInfoPrivate> nodeMetaInfoPrivateData,
const TypeName &enumeration);
~EnumerationMetaInfo();
private:
QSharedPointer<class NodeMetaInfoPrivate> m_nodeMetaInfoPrivateData;
const TypeName &m_enumeration;
};
using EnumerationMetaInfos = std::vector<EnumerationMetaInfo>;
} // namespace QmlDesigner

View File

@@ -42,6 +42,7 @@ class ItemLibraryInfo;
namespace Internal {
class MetaInfoPrivate;
class ModelPrivate;
class MetaInfoReader;
class SubComponentManagerPrivate;
using MetaInfoPrivatePointer = QSharedPointer<MetaInfoPrivate>;
}

View File

@@ -44,8 +44,7 @@ namespace QmlDesigner {
namespace Internal {
class ModelPrivate;
class WriteLocker;
class NodeMetaInfoPrivate;
} // namespace Internal
} //Internal
class AnchorLine;
class ModelNode;
@@ -70,7 +69,7 @@ class QMLDESIGNERCORE_EXPORT Model : public QObject
friend AbstractView;
friend Internal::ModelPrivate;
friend Internal::WriteLocker;
friend Internal::NodeMetaInfoPrivate;
friend class NodeMetaInfoPrivate;
Q_OBJECT
@@ -141,4 +140,4 @@ private:
Internal::ModelPrivate *d;
};
} // namespace QmlDesigner
}

View File

@@ -174,7 +174,7 @@ public:
Model *model() const;
AbstractView *view() const;
const NodeMetaInfo metaInfo() const;
NodeMetaInfo metaInfo() const;
bool hasMetaInfo() const;
bool isSelected() const;

View File

@@ -25,12 +25,15 @@
#pragma once
#include "invalidmetainfoexception.h"
#include "propertymetainfo.h"
#include "qmldesignercorelib_global.h"
#include <QList>
#include <QString>
#include <QIcon>
#include "qmldesignercorelib_global.h"
#include "invalidmetainfoexception.h"
#include <vector>
QT_BEGIN_NAMESPACE
class QDeclarativeContext;
@@ -42,14 +45,6 @@ class MetaInfo;
class Model;
class AbstractProperty;
namespace Internal {
class MetaInfoPrivate;
class MetaInfoReader;
class SubComponentManagerPrivate;
class ItemLibraryEntryData;
class NodeMetaInfoPrivate;
}
class QMLDESIGNERCORE_EXPORT NodeMetaInfo
{
public:
@@ -64,20 +59,13 @@ public:
bool isValid() const;
bool isFileComponent() const;
bool hasProperty(const PropertyName &propertyName) const;
PropertyNameList propertyNames() const;
PropertyMetaInfos properties() const;
PropertyMetaInfos localProperties() const;
PropertyMetaInfo property(const PropertyName &propertyName) const;
PropertyNameList signalNames() const;
PropertyNameList slotNames() const;
PropertyNameList directPropertyNames() const;
PropertyName defaultPropertyName() const;
bool hasDefaultProperty() const;
TypeName propertyTypeName(const PropertyName &propertyName) const;
bool propertyIsWritable(const PropertyName &propertyName) const;
bool propertyIsListProperty(const PropertyName &propertyName) const;
bool propertyIsEnumType(const PropertyName &propertyName) const;
bool propertyIsPrivate(const PropertyName &propertyName) const;
bool propertyIsPointer(const PropertyName &propertyName) const;
QStringList propertyKeysForEnum(const PropertyName &propertyName) const;
QVariant propertyCastedValue(const PropertyName &propertyName, const QVariant &value) const;
QList<NodeMetaInfo> classHierarchy() const;
QList<NodeMetaInfo> superClasses() const;
@@ -104,7 +92,9 @@ public:
QString importDirectoryPath() const;
private:
QSharedPointer<Internal::NodeMetaInfoPrivate> m_privateData;
QSharedPointer<class NodeMetaInfoPrivate> m_privateData;
};
using NodeMetaInfos = std::vector<NodeMetaInfo>;
} //QmlDesigner

View File

@@ -0,0 +1,69 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <qmldesignercorelib_global.h>
#include <QSharedPointer>
#include <QString>
#include <vector>
namespace QmlDesigner {
class PropertyMetaInfo
{
public:
PropertyMetaInfo(QSharedPointer<class NodeMetaInfoPrivate> nodeMetaInfoPrivateData,
const PropertyName &propertyName);
~PropertyMetaInfo();
const TypeName &propertyTypeName() const;
class NodeMetaInfo propertyNodeMetaInfo() const;
bool isWritable() const;
bool isListProperty() const;
bool isEnumType() const;
bool isPrivate() const;
bool isPointer() const;
QVariant castedValue(const QVariant &value) const;
const PropertyName &name() const & { return m_propertyName; }
template<typename... TypeName>
bool hasPropertyTypeName(const TypeName &...typeName) const
{
auto propertyTypeName_ = propertyTypeName();
return ((propertyTypeName_ == typeName) || ...);
}
private:
QSharedPointer<class NodeMetaInfoPrivate> m_nodeMetaInfoPrivateData;
PropertyName m_propertyName;
};
using PropertyMetaInfos = std::vector<PropertyMetaInfo>;
} // namespace QmlDesigner

View File

@@ -212,12 +212,14 @@ public:
void setStartFlowItem(const QmlFlowItemNode &flowItem);
ModelNode createTransition();
static PropertyNameList st_mouseSignals;
static QList<QmlConnections> getAssociatedConnections(const ModelNode &node);
static const PropertyNameList &mouseSignals() { return s_mouseSignals; }
protected:
QList<ModelNode> transitionsForProperty(const PropertyName &propertyName, const ModelNode &modelNode);
private:
static PropertyNameList s_mouseSignals;
};

View File

@@ -46,17 +46,6 @@
namespace QmlDesigner {
namespace Internal {
struct TypeDescription
{
QString className;
int minorVersion{};
int majorVersion{};
};
} //Internal
/*!
\class QmlDesigner::NodeMetaInfo
\ingroup CoreModel
@@ -74,7 +63,14 @@ NodeMetaInfo object will result in an InvalidMetaInfoException being thrown.
\see QmlDesigner::MetaInfo, QmlDesigner::PropertyMetaInfo, QmlDesigner::EnumeratorMetaInfo
*/
namespace Internal {
namespace {
struct TypeDescription
{
QString className;
int minorVersion{};
int majorVersion{};
};
using namespace QmlJS;
@@ -516,6 +512,9 @@ PropertyNameList getSignals(const ObjectValue *objectValue, const ContextPtr &co
signalList.append(getSignals(prototype, context, true));
}
std::sort(signalList.begin(), signalList.end());
signalList.erase(std::unique(signalList.begin(), signalList.end()), signalList.end());
return signalList;
}
@@ -544,6 +543,9 @@ PropertyNameList getSlots(const ObjectValue *objectValue, const ContextPtr &cont
slotList.append(getSlots(prototype, context, true));
}
std::sort(slotList.begin(), slotList.end());
slotList.erase(std::unique(slotList.begin(), slotList.end()), slotList.end());
return slotList;
}
@@ -604,6 +606,7 @@ QVector<PropertyInfo> getObjectTypes(const ObjectValue *objectValue, const Conte
return propertyList;
}
} // namespace
class NodeMetaInfoPrivate
{
@@ -614,12 +617,12 @@ public:
bool isValid() const;
bool isFileComponent() const;
PropertyNameList properties() const;
PropertyNameList localProperties() const;
const PropertyNameList &properties() const;
const PropertyNameList &localProperties() const;
PropertyNameList signalNames() const;
PropertyNameList slotNames() const;
PropertyName defaultPropertyName() const;
TypeName propertyType(const PropertyName &propertyName) const;
const TypeName &propertyType(const PropertyName &propertyName) const;
void setupPrototypes();
QList<TypeDescription> prototypes() const;
@@ -634,7 +637,7 @@ public:
int majorVersion() const;
int minorVersion() const;
TypeName qualfiedTypeName() const;
const TypeName &qualfiedTypeName() const;
Model *model() const;
QByteArray cppPackageName() const;
@@ -691,14 +694,14 @@ bool NodeMetaInfoPrivate::isFileComponent() const
return m_isFileComponent;
}
PropertyNameList NodeMetaInfoPrivate::properties() const
const PropertyNameList &NodeMetaInfoPrivate::properties() const
{
ensureProperties();
return m_properties;
}
PropertyNameList NodeMetaInfoPrivate::localProperties() const
const PropertyNameList &NodeMetaInfoPrivate::localProperties() const
{
ensureProperties();
@@ -741,8 +744,9 @@ static inline TypeName stringIdentifier( const TypeName &type, int maj, int min)
NodeMetaInfoPrivate::Pointer NodeMetaInfoPrivate::create(Model *model, const TypeName &type, int major, int minor)
{
if (model->d->m_nodeMetaInfoCache.contains(stringIdentifier(type, major, minor)))
return model->d->m_nodeMetaInfoCache.value(stringIdentifier(type, major, minor));
auto &&cache = model->d->m_nodeMetaInfoCache;
if (auto found = cache.find(stringIdentifier(type, major, minor)); found != cache.end())
return *found;
Pointer newData(new NodeMetaInfoPrivate(model, type, major, minor));
if (newData->isValid())
@@ -1144,7 +1148,7 @@ int NodeMetaInfoPrivate::minorVersion() const
return m_minorVersion;
}
TypeName NodeMetaInfoPrivate::qualfiedTypeName() const
const TypeName &NodeMetaInfoPrivate::qualfiedTypeName() const
{
return m_qualfiedTypeName;
}
@@ -1248,12 +1252,16 @@ bool NodeMetaInfoPrivate::isValid() const
return m_isValid && context() && document();
}
TypeName NodeMetaInfoPrivate::propertyType(const PropertyName &propertyName) const
namespace {
TypeName nonexistingTypeName("Property does not exist...");
}
const TypeName &NodeMetaInfoPrivate::propertyType(const PropertyName &propertyName) const
{
ensureProperties();
if (!m_properties.contains(propertyName))
return TypeName("Property does not exist...");
return nonexistingTypeName;
return m_propertyTypes.at(m_properties.indexOf(propertyName));
}
@@ -1386,14 +1394,14 @@ void NodeMetaInfoPrivate::initialiseProperties()
m_slots = getSlots(m_objectValue, context());
}
} //namespace Internal
NodeMetaInfo::NodeMetaInfo() : m_privateData(new Internal::NodeMetaInfoPrivate())
NodeMetaInfo::NodeMetaInfo()
: m_privateData(QSharedPointer<NodeMetaInfoPrivate>::create())
{
}
NodeMetaInfo::NodeMetaInfo(Model *model, const TypeName &type, int maj, int min) : m_privateData(Internal::NodeMetaInfoPrivate::create(model, type, maj, min))
NodeMetaInfo::NodeMetaInfo(Model *model, const TypeName &type, int maj, int min)
: m_privateData(NodeMetaInfoPrivate::create(model, type, maj, min))
{
}
@@ -1422,12 +1430,38 @@ bool NodeMetaInfo::isFileComponent() const
bool NodeMetaInfo::hasProperty(const PropertyName &propertyName) const
{
return propertyNames().contains(propertyName);
return m_privateData->properties().contains(propertyName);
}
PropertyNameList NodeMetaInfo::propertyNames() const
PropertyMetaInfos NodeMetaInfo::properties() const
{
return m_privateData->properties();
const auto &properties = m_privateData->properties();
PropertyMetaInfos propertyMetaInfos;
propertyMetaInfos.reserve(static_cast<std::size_t>(properties.size()));
for (const auto &name : properties)
propertyMetaInfos.emplace_back(m_privateData, name);
return propertyMetaInfos;
}
PropertyMetaInfos NodeMetaInfo::localProperties() const
{
const auto &properties = m_privateData->localProperties();
PropertyMetaInfos propertyMetaInfos;
propertyMetaInfos.reserve(static_cast<std::size_t>(properties.size()));
for (const auto &name : properties)
propertyMetaInfos.emplace_back(m_privateData, name);
return propertyMetaInfos;
}
PropertyMetaInfo NodeMetaInfo::property(const PropertyName &propertyName) const
{
return PropertyMetaInfo{m_privateData, propertyName};
}
PropertyNameList NodeMetaInfo::signalNames() const
@@ -1440,11 +1474,6 @@ PropertyNameList NodeMetaInfo::slotNames() const
return m_privateData->slotNames();
}
PropertyNameList NodeMetaInfo::directPropertyNames() const
{
return m_privateData->localProperties();
}
PropertyName NodeMetaInfo::defaultPropertyName() const
{
return m_privateData->defaultPropertyName();
@@ -1455,84 +1484,6 @@ bool NodeMetaInfo::hasDefaultProperty() const
return !defaultPropertyName().isEmpty();
}
TypeName NodeMetaInfo::propertyTypeName(const PropertyName &propertyName) const
{
return m_privateData->propertyType(propertyName);
}
bool NodeMetaInfo::propertyIsWritable(const PropertyName &propertyName) const
{
return m_privateData->isPropertyWritable(propertyName);
}
bool NodeMetaInfo::propertyIsListProperty(const PropertyName &propertyName) const
{
return m_privateData->isPropertyList(propertyName);
}
bool NodeMetaInfo::propertyIsEnumType(const PropertyName &propertyName) const
{
return m_privateData->isPropertyEnum(propertyName);
}
bool NodeMetaInfo::propertyIsPrivate(const PropertyName &propertyName) const
{
return propertyName.startsWith("__");
}
bool NodeMetaInfo::propertyIsPointer(const PropertyName &propertyName) const
{
return m_privateData->isPropertyPointer(propertyName);
}
QStringList NodeMetaInfo::propertyKeysForEnum(const PropertyName &propertyName) const
{
return m_privateData->keysForEnum(QString::fromUtf8(propertyTypeName(propertyName)));
}
QVariant NodeMetaInfo::propertyCastedValue(const PropertyName &propertyName, const QVariant &value) const
{
const QVariant variant = value;
QVariant copyVariant = variant;
if (propertyIsEnumType(propertyName)
|| variant.canConvert<Enumeration>())
return variant;
const TypeName typeName = propertyTypeName(propertyName);
QVariant::Type typeId = m_privateData->variantTypeId(propertyName);
if (variant.type() == QVariant::UserType && variant.userType() == ModelNode::variantUserType()) {
return variant;
} else if (typeId == QVariant::UserType && typeName == "QVariant") {
return variant;
} else if (typeId == QVariant::UserType && typeName == "variant") {
return variant;
} else if (typeId == QVariant::UserType && typeName == "var") {
return variant;
} else if (variant.type() == QVariant::List) {
// TODO: check the contents of the list
return variant;
} else if (typeName == "var" || typeName == "variant") {
return variant;
} else if (typeName == "alias") {
// TODO: The QML compiler resolves the alias type. We probably should do the same.
return variant;
} else if (typeName == "<cpp>.double") {
return variant.toDouble();
} else if (typeName == "<cpp>.float") {
return variant.toFloat();
} else if (typeName == "<cpp>.int") {
return variant.toInt();
} else if (typeName == "<cpp>.bool") {
return variant.toBool();
} else if (copyVariant.convert(typeId)) {
return copyVariant;
}
return Internal::PropertyParser::variantFromString(variant.toString());
}
QList<NodeMetaInfo> NodeMetaInfo::classHierarchy() const
{
QList<NodeMetaInfo> hierarchy = {*this};
@@ -1543,7 +1494,7 @@ QList<NodeMetaInfo> NodeMetaInfo::classHierarchy() const
QList<NodeMetaInfo> NodeMetaInfo::superClasses() const
{
Model *model = m_privateData->model();
return Utils::transform(m_privateData->prototypes(), [model](const Internal::TypeDescription &type) {
return Utils::transform(m_privateData->prototypes(), [model](const TypeDescription &type) {
return NodeMetaInfo(model, type.className.toUtf8(), type.majorVersion, type.minorVersion);
});
}
@@ -1556,7 +1507,7 @@ NodeMetaInfo NodeMetaInfo::directSuperClass() const
bool NodeMetaInfo::defaultPropertyIsComponent() const
{
if (hasDefaultProperty())
return propertyTypeName(defaultPropertyName()) == "Component";
return property(defaultPropertyName()).hasPropertyTypeName("Component");
return false;
}
@@ -1613,21 +1564,24 @@ bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int mino
if (typeName() == type && availableInVersion(majorVersion, minorVersion))
return true;
if (m_privateData->prototypeCachePositives().contains(Internal::stringIdentifier(type, majorVersion, minorVersion)))
if (m_privateData->prototypeCachePositives().contains(
stringIdentifier(type, majorVersion, minorVersion)))
return true; //take a shortcut - optimization
if (m_privateData->prototypeCacheNegatives().contains(Internal::stringIdentifier(type, majorVersion, minorVersion)))
if (m_privateData->prototypeCacheNegatives().contains(
stringIdentifier(type, majorVersion, minorVersion)))
return false; //take a shortcut - optimization
const QList<NodeMetaInfo> superClassList = superClasses();
for (const NodeMetaInfo &superClass : superClassList) {
if (superClass.m_privateData->cleverCheckType(type)
&& superClass.availableInVersion(majorVersion, minorVersion)) {
m_privateData->prototypeCachePositives().insert(Internal::stringIdentifier(type, majorVersion, minorVersion));
m_privateData->prototypeCachePositives().insert(
stringIdentifier(type, majorVersion, minorVersion));
return true;
}
}
m_privateData->prototypeCacheNegatives().insert(Internal::stringIdentifier(type, majorVersion, minorVersion));
m_privateData->prototypeCacheNegatives().insert(stringIdentifier(type, majorVersion, minorVersion));
return false;
}
@@ -1668,4 +1622,90 @@ bool NodeMetaInfo::isTabView() const
return isSubclassOf("QtQuick.Controls.TabView");
}
PropertyMetaInfo::PropertyMetaInfo(QSharedPointer<NodeMetaInfoPrivate> nodeMetaInfoPrivateData,
const PropertyName &propertyName)
: m_nodeMetaInfoPrivateData{nodeMetaInfoPrivateData}
, m_propertyName{propertyName}
{}
PropertyMetaInfo::~PropertyMetaInfo() {}
const TypeName &PropertyMetaInfo::propertyTypeName() const
{
return m_nodeMetaInfoPrivateData->propertyType(m_propertyName);
}
NodeMetaInfo PropertyMetaInfo::propertyNodeMetaInfo() const
{
return m_nodeMetaInfoPrivateData->model()->metaInfo(propertyTypeName());
}
bool PropertyMetaInfo::isWritable() const
{
return m_nodeMetaInfoPrivateData->isPropertyWritable(m_propertyName);
}
bool PropertyMetaInfo::isListProperty() const
{
return m_nodeMetaInfoPrivateData->isPropertyList(m_propertyName);
}
bool PropertyMetaInfo::isEnumType() const
{
return m_nodeMetaInfoPrivateData->isPropertyEnum(m_propertyName);
}
bool PropertyMetaInfo::isPrivate() const
{
return m_propertyName.startsWith("__");
}
bool PropertyMetaInfo::isPointer() const
{
return m_nodeMetaInfoPrivateData->isPropertyPointer(m_propertyName);
}
QVariant PropertyMetaInfo::castedValue(const QVariant &value) const
{
const QVariant variant = value;
QVariant copyVariant = variant;
if (isEnumType() || variant.canConvert<Enumeration>())
return variant;
const TypeName &typeName = propertyTypeName();
QVariant::Type typeId = m_nodeMetaInfoPrivateData->variantTypeId(m_propertyName);
if (variant.type() == QVariant::UserType && variant.userType() == ModelNode::variantUserType()) {
return variant;
} else if (typeId == QVariant::UserType && typeName == "QVariant") {
return variant;
} else if (typeId == QVariant::UserType && typeName == "variant") {
return variant;
} else if (typeId == QVariant::UserType && typeName == "var") {
return variant;
} else if (variant.type() == QVariant::List) {
// TODO: check the contents of the list
return variant;
} else if (typeName == "var" || typeName == "variant") {
return variant;
} else if (typeName == "alias") {
// TODO: The QML compiler resolves the alias type. We probably should do the same.
return variant;
} else if (typeName == "<cpp>.double") {
return variant.toDouble();
} else if (typeName == "<cpp>.float") {
return variant.toFloat();
} else if (typeName == "<cpp>.int") {
return variant.toInt();
} else if (typeName == "<cpp>.bool") {
return variant.toBool();
} else if (copyVariant.convert(typeId)) {
return copyVariant;
}
return Internal::PropertyParser::variantFromString(variant.toString());
}
} // namespace QmlDesigner

View File

@@ -46,6 +46,7 @@ namespace QmlDesigner {
class AbstractProperty;
class RewriterView;
class NodeInstanceView;
class NodeMetaInfoPrivate;
namespace Internal {
@@ -85,7 +86,7 @@ class ModelPrivate : public QObject {
friend Model;
friend Internal::WriteLocker;
friend Internal::NodeMetaInfoPrivate;
friend NodeMetaInfoPrivate;
public:
ModelPrivate(Model *model);

View File

@@ -855,7 +855,7 @@ bool ModelNode::hasAnySubModelNodes() const
return !nodeAbstractProperties().isEmpty();
}
const NodeMetaInfo ModelNode::metaInfo() const
NodeMetaInfo ModelNode::metaInfo() const
{
if (!isValid()) {
Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");

View File

@@ -33,6 +33,8 @@
#include "model.h"
#include "model_p.h"
#include <nodemetainfo.h>
namespace QmlDesigner {
NodeAbstractProperty::NodeAbstractProperty() = default;
@@ -53,10 +55,14 @@ NodeAbstractProperty::NodeAbstractProperty(const Internal::InternalNodeAbstractP
void NodeAbstractProperty::reparentHere(const ModelNode &modelNode)
{
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isNodeAbstractProperty())
if (internalNode()->hasProperty(name())
&& !internalNode()->property(name())->isNodeAbstractProperty()) {
reparentHere(modelNode, isNodeListProperty());
else
reparentHere(modelNode, parentModelNode().metaInfo().propertyIsListProperty(name()) || isDefaultProperty()); //we could use the metasystem instead?
} else {
reparentHere(modelNode,
parentModelNode().metaInfo().property(name()).isListProperty()
|| isDefaultProperty()); //we could use the metasystem instead?
}
}
void NodeAbstractProperty::reparentHere(const ModelNode &modelNode, bool isNodeList, const TypeName &dynamicTypeName)

View File

@@ -993,8 +993,14 @@ QList<ModelNode> QmlFlowViewNode::transitionsForProperty(const PropertyName &pro
return list;
}
PropertyNameList QmlFlowViewNode::st_mouseSignals = { "clicked", "doubleClicked", "pressAndHold",
"pressed", "released", "wheel" };
PropertyNameList QmlFlowViewNode::s_mouseSignals = []() {
PropertyNameList mouseSignals = {
"clicked", "doubleClicked", "pressed", "pressAndHold", "released", "wheel"};
Q_ASSERT(std::is_sorted(mouseSignals.begin(), mouseSignals.end()));
return mouseSignals;
}();
QList<QmlConnections> QmlFlowViewNode::getAssociatedConnections(const ModelNode &node)
{
@@ -1020,8 +1026,7 @@ QList<QmlConnections> QmlFlowViewNode::getAssociatedConnections(const ModelNode
sourceProperty = sourceComponents[1];
}
if (st_mouseSignals.contains(signalWithoutPrefix)
&& sourceId == node.id()
if (mouseSignals().contains(signalWithoutPrefix) && sourceId == node.id()
&& sourceProperty == "trigger()")
return true;
}

View File

@@ -246,17 +246,17 @@ QVariant QmlObjectNode::modelValue(const PropertyName &name) const
bool QmlObjectNode::isTranslatableText(const PropertyName &name) const
{
if (modelNode().metaInfo().isValid() && modelNode().metaInfo().hasProperty(name))
if (modelNode().metaInfo().propertyTypeName(name) == "QString" || modelNode().metaInfo().propertyTypeName(name) == "string") {
if (modelNode().hasBindingProperty(name)) {
static QRegularExpression regularExpressionPattern(
QLatin1String("^qsTr(|Id|anslate)\\(\".*\"\\)$"));
return modelNode().bindingProperty(name).expression().contains(regularExpressionPattern);
}
return false;
if (modelNode().metaInfo().isValid() && modelNode().metaInfo().hasProperty(name)
&& modelNode().metaInfo().property(name).hasPropertyTypeName("QString", "string")) {
if (modelNode().hasBindingProperty(name)) {
static QRegularExpression regularExpressionPattern(
QLatin1String("^qsTr(|Id|anslate)\\(\".*\"\\)$"));
return modelNode().bindingProperty(name).expression().contains(regularExpressionPattern);
}
return false;
}
return false;
}

View File

@@ -213,7 +213,7 @@ TypeName QmlTimelineKeyframeGroup::valueType() const
TypeName typeName;
if (targetNode.isValid() && targetNode.hasMetaInfo())
typeName = targetNode.metaInfo().propertyTypeName(propertyName());
typeName = targetNode.metaInfo().property(propertyName()).propertyTypeName();
if (typeName.startsWith("<cpp>."))
typeName.remove(0, 6);

View File

@@ -223,7 +223,7 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view,
if (!forceNonDefaultProperty.isEmpty()) {
const NodeMetaInfo metaInfo = parentQmlItemNode.modelNode().metaInfo();
if (metaInfo.hasProperty(forceNonDefaultProperty)) {
if (!metaInfo.propertyIsListProperty(forceNonDefaultProperty)
if (!metaInfo.property(forceNonDefaultProperty).isListProperty()
&& parentQmlItemNode.modelNode().hasNodeProperty(forceNonDefaultProperty)) {
parentQmlItemNode.removeProperty(forceNonDefaultProperty);
}
@@ -324,7 +324,7 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view,
const ModelNode parentNode = parentProperty.parentModelNode();
const NodeMetaInfo metaInfo = parentNode.metaInfo();
if (metaInfo.isValid() && !metaInfo.propertyIsListProperty(propertyName)
if (metaInfo.isValid() && !metaInfo.property(propertyName).isListProperty()
&& parentProperty.isNodeProperty()) {
parentNode.removeProperty(propertyName);
}

View File

@@ -337,8 +337,9 @@ bool propertyIsComponentType(const QmlDesigner::NodeAbstractProperty &property,
if (model->metaInfo(type).isSubclassOf("QtQuick.Component") && !isComponentType(type))
return false; //If the type is already a subclass of Component keep it
return property.parentModelNode().isValid() &&
isComponentType(property.parentModelNode().metaInfo().propertyTypeName(property.name()));
return property.parentModelNode().isValid()
&& isComponentType(
property.parentModelNode().metaInfo().property(property.name()).propertyTypeName());
}
QString extractComponentFromQml(const QString &source)

View File

@@ -153,6 +153,7 @@ function(extend_with_qmldesigner_core target_name)
include/componenttextmodifier.h
include/customnotifications.h
include/documentmessage.h
include/enumerationmetainfo.h
include/exception.h
include/forwardview.h
include/imagecacheauxiliarydata.h
@@ -184,6 +185,7 @@ function(extend_with_qmldesigner_core target_name)
include/notimplementedexception.h
include/plaintexteditmodifier.h
include/propertycontainer.h
include/propertymetainfo.h
include/propertynode.h
include/propertyparser.h
include/qmlanchors.h

View File

@@ -266,6 +266,7 @@ Project {
"include/bindingproperty.h",
"include/componenttextmodifier.h",
"include/customnotifications.h",
"include/enumerationmetainfo.h",
"include/exception.h",
"include/forwardview.h",
"include/import.h",
@@ -296,6 +297,7 @@ Project {
"include/notimplementedexception.h",
"include/plaintexteditmodifier.h",
"include/propertycontainer.h",
"include/propertymetainfo.h",
"include/propertynode.h",
"include/propertyparser.h",
"include/qmlanchors.h",

View File

@@ -130,7 +130,7 @@ public:
QSize{300, 300},
QSize{1000, 1000},
ImageCacheCollectorNullImageHandling::DontCaptureNullImage};
TimeStampProvider timeStampProvider;
PreviewTimeStampProvider timeStampProvider;
AsynchronousExplicitImageCache cache{storage};
AsynchronousImageFactory factory{storage, timeStampProvider, collector};
};

View File

@@ -1,5 +1,5 @@
add_qtc_test(tst_qml_testcore
CONDITION TARGET QmlProjectManager
CONDITION TARGET QmlProjectManager AND Qt5_VERSION VERSION_GREATER_EQUAL 6.2.0
DEFINES
QT_CREATOR
QMLDESIGNER_TEST

View File

@@ -4232,6 +4232,17 @@ void tst_TestCore::testCopyModelRewriter2()
QCOMPARE(stripWhiteSpaces(textEdit2.toPlainText()), stripWhiteSpaces(qmlString1));
}
namespace {
bool contains(const QmlDesigner::PropertyMetaInfos &properties, QUtf8StringView propertyName)
{
auto found = std::find_if(properties.begin(), properties.end(), [&](const auto &property) {
return property.name() == propertyName;
});
return found != properties.end();
}
} // namespace
void tst_TestCore::testSubComponentManager()
{
const QString qmlString("import QtQuick 2.15\n"
@@ -4267,7 +4278,7 @@ void tst_TestCore::testSubComponentManager()
subComponentManager->update(QUrl::fromLocalFile(fileName), model->imports());
QVERIFY(model->hasNodeMetaInfo("QtQuick.Rectangle", 2, 15));
QVERIFY(model->metaInfo("QtQuick.Rectangle").propertyNames().contains("border.width"));
QVERIFY(contains(model->metaInfo("QtQuick.Rectangle").properties(), "border.width"));
model->rewriterView()->setTextModifier(&modifier);
@@ -4276,14 +4287,14 @@ void tst_TestCore::testSubComponentManager()
QVERIFY(model->rewriterView()->rootModelNode().isValid());
QVERIFY(model->hasNodeMetaInfo("QtQuick.Rectangle", 2, 15));
QVERIFY(model->metaInfo("QtQuick.Rectangle").propertyNames().contains("border.width"));
QVERIFY(contains(model->metaInfo("QtQuick.Rectangle").properties(), "border.width"));
QVERIFY(model->metaInfo("<cpp>.QQuickPen").isValid());
QSKIP("File components not working TODO", SkipAll);
NodeMetaInfo myButtonMetaInfo = model->metaInfo("MyButton");
QVERIFY(myButtonMetaInfo.isValid());
QVERIFY(myButtonMetaInfo.propertyNames().contains("border.width"));
QVERIFY(contains(myButtonMetaInfo.properties(), "border.width"));
QVERIFY(myButtonMetaInfo.hasProperty("border.width"));
}
@@ -4638,7 +4649,7 @@ void tst_TestCore::testMetaInfoCustomType()
QCOMPARE(propertyChangesInfo.superClasses().size(), 3);
// DeclarativePropertyChanges just has 3 properties
QCOMPARE(propertyChangesInfo.propertyNames().size() - stateOperationInfo.propertyNames().size(), 3);
QCOMPARE(propertyChangesInfo.properties().size() - stateOperationInfo.properties().size(), 3);
QApplication::processEvents();
}
@@ -4656,15 +4667,13 @@ void tst_TestCore::testMetaInfoEnums()
QVERIFY(view->rootModelNode().metaInfo().hasProperty("transformOrigin"));
QVERIFY(view->rootModelNode().metaInfo().propertyIsEnumType("transformOrigin"));
QCOMPARE(view->rootModelNode().metaInfo().propertyTypeName("transformOrigin"), QmlDesigner::TypeName("TransformOrigin"));
QVERIFY(view->rootModelNode().metaInfo().propertyKeysForEnum("transformOrigin").contains(QLatin1String("Bottom")));
QVERIFY(view->rootModelNode().metaInfo().propertyKeysForEnum("transformOrigin").contains(QLatin1String("Top")));
QVERIFY(view->rootModelNode().metaInfo().property("transformOrigin").isEnumType());
QCOMPARE(view->rootModelNode().metaInfo().property("transformOrigin").propertyTypeName(),
QmlDesigner::TypeName("TransformOrigin"));
QVERIFY(view->rootModelNode().metaInfo().propertyIsEnumType("horizontalAlignment"));
QCOMPARE(view->rootModelNode().metaInfo().propertyTypeName("horizontalAlignment"), QmlDesigner::TypeName("HAlignment"));
QVERIFY(view->rootModelNode().metaInfo().propertyKeysForEnum("horizontalAlignment").contains(QLatin1String("AlignLeft")));
QVERIFY(view->rootModelNode().metaInfo().propertyKeysForEnum("horizontalAlignment").contains(QLatin1String("AlignRight")));
QVERIFY(view->rootModelNode().metaInfo().property("horizontalAlignment").isEnumType());
QCOMPARE(view->rootModelNode().metaInfo().property("horizontalAlignment").propertyTypeName(),
QmlDesigner::TypeName("HAlignment"));
QApplication::processEvents();
}
@@ -4743,8 +4752,8 @@ void tst_TestCore::testMetaInfoProperties()
QVERIFY(textNodeMetaInfo.hasProperty("objectName")); // QtQuick.QObject
QVERIFY(!textNodeMetaInfo.hasProperty("bla"));
QVERIFY(textNodeMetaInfo.propertyIsWritable("text"));
QVERIFY(textNodeMetaInfo.propertyIsWritable("x"));
QVERIFY(textNodeMetaInfo.property("text").isWritable());
QVERIFY(textNodeMetaInfo.property("x").isWritable());
QApplication::processEvents();
}
@@ -4761,22 +4770,23 @@ void tst_TestCore::testMetaInfoDotProperties()
QVERIFY(model->hasNodeMetaInfo("QtQuick.Text"));
QVERIFY(model->metaInfo("QtQuick.Rectangle").hasProperty("border"));
QCOMPARE(model->metaInfo("QtQuick.Rectangle").propertyTypeName("border"), QmlDesigner::TypeName("<cpp>.QQuickPen"));
QCOMPARE(model->metaInfo("QtQuick.Rectangle").property("border").propertyTypeName(),
QmlDesigner::TypeName("<cpp>.QQuickPen"));
QCOMPARE(view->rootModelNode().metaInfo().typeName(), QmlDesigner::TypeName("QtQuick.Text"));
QVERIFY(view->rootModelNode().metaInfo().hasProperty("font"));
QVERIFY(view->rootModelNode().metaInfo().hasProperty("font.bold"));
QVERIFY(view->rootModelNode().metaInfo().propertyNames().contains("font.bold"));
QVERIFY(view->rootModelNode().metaInfo().propertyNames().contains("font.pointSize"));
QVERIFY(contains(view->rootModelNode().metaInfo().properties(), "font.bold"));
QVERIFY(contains(view->rootModelNode().metaInfo().properties(), "font.pointSize"));
QVERIFY(view->rootModelNode().metaInfo().hasProperty("font.pointSize"));
ModelNode rectNode(addNodeListChild(view->rootModelNode(), "QtQuick.Rectangle", 2, 0, "data"));
QVERIFY(rectNode.metaInfo().propertyNames().contains("implicitHeight"));
QVERIFY(rectNode.metaInfo().propertyNames().contains("implicitWidth"));
QVERIFY(rectNode.metaInfo().propertyNames().contains("anchors.topMargin"));
QVERIFY(rectNode.metaInfo().propertyNames().contains("border.width"));
QVERIFY(contains(rectNode.metaInfo().properties(), "implicitHeight"));
QVERIFY(contains(rectNode.metaInfo().properties(), "implicitWidth"));
QVERIFY(contains(rectNode.metaInfo().properties(), "anchors.topMargin"));
QVERIFY(contains(rectNode.metaInfo().properties(), "border.width"));
QVERIFY(rectNode.metaInfo().hasProperty("border"));
QVERIFY(rectNode.metaInfo().hasProperty("border.width"));
@@ -4796,20 +4806,20 @@ void tst_TestCore::testMetaInfoListProperties()
QCOMPARE(view->rootModelNode().metaInfo().typeName(), QmlDesigner::TypeName("QtQuick.Item"));
QVERIFY(view->rootModelNode().metaInfo().hasProperty("states"));
QVERIFY(view->rootModelNode().metaInfo().propertyIsListProperty("states"));
QVERIFY(view->rootModelNode().metaInfo().property("states").isListProperty());
QVERIFY(view->rootModelNode().metaInfo().hasProperty("children"));
QVERIFY(view->rootModelNode().metaInfo().propertyIsListProperty("children"));
QVERIFY(view->rootModelNode().metaInfo().property("children").isListProperty());
QVERIFY(view->rootModelNode().metaInfo().hasProperty("data"));
QVERIFY(view->rootModelNode().metaInfo().propertyIsListProperty("data"));
QVERIFY(view->rootModelNode().metaInfo().property("data").isListProperty());
QVERIFY(view->rootModelNode().metaInfo().hasProperty("resources"));
QVERIFY(view->rootModelNode().metaInfo().propertyIsListProperty("resources"));
QVERIFY(view->rootModelNode().metaInfo().property("resources").isListProperty());
QVERIFY(view->rootModelNode().metaInfo().hasProperty("transitions"));
QVERIFY(view->rootModelNode().metaInfo().propertyIsListProperty("transitions"));
QVERIFY(view->rootModelNode().metaInfo().property("transitions").isListProperty());
QVERIFY(view->rootModelNode().metaInfo().hasProperty("transform"));
QVERIFY(view->rootModelNode().metaInfo().propertyIsListProperty("transform"));
QVERIFY(view->rootModelNode().metaInfo().property("transform").isListProperty());
QVERIFY(view->rootModelNode().metaInfo().hasProperty("parent"));
QVERIFY(!view->rootModelNode().metaInfo().propertyIsListProperty("parent"));
QVERIFY(!view->rootModelNode().metaInfo().property("parent").isListProperty());
QApplication::processEvents();
}
@@ -4904,8 +4914,8 @@ void tst_TestCore::testQtQuickControls2()
QVERIFY(rootModelNode.metaInfo().isGraphicalItem());
QVERIFY(rootModelNode.isSubclassOf("QtQuick.Window.Window", -1, -1));
QVERIFY(!rootModelNode.metaInfo().directPropertyNames().contains("visible"));
QVERIFY(rootModelNode.metaInfo().propertyNames().contains("visible"));
QVERIFY(!contains(rootModelNode.metaInfo().localProperties(), "visible"));
QVERIFY(contains(rootModelNode.metaInfo().properties(), "visible"));
QVERIFY(!rootModelNode.allSubModelNodes().isEmpty());
ModelNode button = rootModelNode.allSubModelNodes().first();

View File

@@ -25,12 +25,14 @@
#pragma once
#include "propertymetainfo.h"
#include <QIcon>
#include <QList>
#include <QString>
#include <QVariant>
#include "qmldesignercorelib_global.h"
#include <qmldesignercorelib_global.h>
QT_BEGIN_NAMESPACE
class QDeclarativeContext;
@@ -51,19 +53,14 @@ public:
bool isValid() const { return {}; }
bool isFileComponent() const { return {}; }
bool hasProperty(const PropertyName &) const { return {}; }
PropertyMetaInfos properties() const { return {}; }
PropertyMetaInfos localProperties() const { return {}; }
PropertyMetaInfo property(const PropertyName &) const { return {}; }
PropertyNameList propertyNames() const { return {}; }
PropertyNameList signalNames() const { return {}; }
PropertyNameList directPropertyNames() const { return {}; }
PropertyName defaultPropertyName() const { return "data"; }
bool hasDefaultProperty() const { return {}; }
TypeName propertyTypeName(const PropertyName &) const { return {}; }
bool propertyIsWritable(const PropertyName &) const { return {}; }
bool propertyIsListProperty(const PropertyName &) const { return {}; }
bool propertyIsEnumType(const PropertyName &) const { return {}; }
bool propertyIsPrivate(const PropertyName &) const { return {}; }
QString propertyEnumScope(const PropertyName &) const { return {}; }
QStringList propertyKeysForEnum(const PropertyName &) const { return {}; }
QVariant propertyCastedValue(const PropertyName &, const QVariant &) const { return {}; }
QList<NodeMetaInfo> classHierarchy() const { return {}; }
QList<NodeMetaInfo> superClasses() const { return {}; }

View File

@@ -0,0 +1,69 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <qmldesignercorelib_global.h>
#include <QSharedPointer>
#include <QString>
#include <vector>
namespace QmlDesigner {
class PropertyMetaInfo
{
public:
PropertyMetaInfo() = default;
PropertyMetaInfo(QSharedPointer<class NodeMetaInfoPrivate>, const PropertyName &) {}
~PropertyMetaInfo() {}
const TypeName &propertyTypeName() const
{
static TypeName foo;
return foo;
}
class NodeMetaInfo propertyNodeMetaInfo() const;
bool isWritable() const { return {}; }
bool isListProperty() const { return {}; }
bool isEnumType() const { return {}; }
bool isPrivate() const { return {}; }
bool isPointer() const { return {}; }
QVariant castedValue(const QVariant &) const { return {}; }
PropertyName name() const & { return {}; }
template<typename... TypeName>
bool hasPropertyTypeName(const TypeName &...typeName) const
{
auto propertyTypeName_ = propertyTypeName();
return ((propertyTypeName_ == typeName) && ...);
}
};
using PropertyMetaInfos = std::vector<PropertyMetaInfo>;
} // namespace QmlDesigner