1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "dynamicpropertiesmodel.h"
27
28 #include "connectionview.h"
29
30 #include <nodemetainfo.h>
31 #include <nodeproperty.h>
32 #include <variantproperty.h>
33 #include <bindingproperty.h>
34 #include <rewritingexception.h>
35 #include <rewritertransaction.h>
36 #include <qmldesignerplugin.h>
37 #include <qmldesignerconstants.h>
38
39 #include <utils/fileutils.h>
40
41 #include <QMessageBox>
42 #include <QTimer>
43 #include <QUrl>
44
45 namespace {
46
compareVariantProperties(const QmlDesigner::VariantProperty & variantProperty01,const QmlDesigner::VariantProperty & variantProperty02)47 bool compareVariantProperties(const QmlDesigner::VariantProperty &variantProperty01, const QmlDesigner::VariantProperty &variantProperty02)
48 {
49 if (variantProperty01.parentModelNode() != variantProperty02.parentModelNode())
50 return false;
51 if (variantProperty01.name() != variantProperty02.name())
52 return false;
53 return true;
54 }
55
idOrTypeNameForNode(const QmlDesigner::ModelNode & modelNode)56 QString idOrTypeNameForNode(const QmlDesigner::ModelNode &modelNode)
57 {
58 QString idLabel = modelNode.id();
59 if (idLabel.isEmpty())
60 idLabel = modelNode.simplifiedTypeName();
61
62 return idLabel;
63 }
64
unusedProperty(const QmlDesigner::ModelNode & modelNode)65 QmlDesigner::PropertyName unusedProperty(const QmlDesigner::ModelNode &modelNode)
66 {
67 QmlDesigner::PropertyName propertyName = "property";
68 int i = 0;
69 if (modelNode.metaInfo().isValid()) {
70 while (true) {
71 const QmlDesigner::PropertyName currentPropertyName = propertyName + QString::number(i).toLatin1();
72 if (!modelNode.hasProperty(currentPropertyName) && !modelNode.metaInfo().hasProperty(currentPropertyName))
73 return currentPropertyName;
74 i++;
75 }
76 }
77
78 return propertyName;
79 }
80
convertVariantForTypeName(const QVariant & variant,const QmlDesigner::TypeName & typeName)81 QVariant convertVariantForTypeName(const QVariant &variant, const QmlDesigner::TypeName &typeName)
82 {
83 QVariant returnValue = variant;
84
85 if (typeName == "int") {
86 bool ok;
87 returnValue = variant.toInt(&ok);
88 if (!ok)
89 returnValue = 0;
90 } else if (typeName == "real") {
91 bool ok;
92 returnValue = variant.toReal(&ok);
93 if (!ok)
94 returnValue = 0.0;
95
96 } else if (typeName == "string") {
97 returnValue = variant.toString();
98
99 } else if (typeName == "bool") {
100 returnValue = variant.toBool();
101 } else if (typeName == "url") {
102 returnValue = variant.toUrl();
103 } else if (typeName == "color") {
104 if (QColor::isValidColor(variant.toString())) {
105 returnValue = variant.toString();
106 } else {
107 returnValue = QColor(Qt::black);
108 }
109 } else if (typeName == "Item") {
110 returnValue = 0;
111 }
112
113 return returnValue;
114 }
115
116 } //internal namespace
117
118 namespace QmlDesigner {
119
120 namespace Internal {
121
DynamicPropertiesModel(ConnectionView * parent)122 DynamicPropertiesModel::DynamicPropertiesModel(ConnectionView *parent)
123 : QStandardItemModel(parent)
124 , m_connectionView(parent)
125 {
126 connect(this, &QStandardItemModel::dataChanged, this, &DynamicPropertiesModel::handleDataChanged);
127 }
128
resetModel()129 void DynamicPropertiesModel::resetModel()
130 {
131 beginResetModel();
132 clear();
133 setHorizontalHeaderLabels(
134 QStringList({tr("Item"), tr("Property"), tr("Property Type"), tr("Property Value")}));
135
136 if (connectionView()->isAttached()) {
137 for (const ModelNode &modelNode : connectionView()->selectedModelNodes())
138 addModelNode(modelNode);
139 }
140
141 endResetModel();
142 }
143
144
145 //Method creates dynamic BindingProperty with the same name and type as old VariantProperty
146 //Value copying is optional
replaceVariantWithBinding(const PropertyName & name,bool copyValue)147 BindingProperty DynamicPropertiesModel::replaceVariantWithBinding(const PropertyName &name, bool copyValue)
148 {
149 if (connectionView()->selectedModelNodes().count() == 1) {
150 const ModelNode modelNode = connectionView()->selectedModelNodes().constFirst();
151 if (modelNode.isValid()) {
152 if (modelNode.hasVariantProperty(name)) {
153 try {
154 VariantProperty vprop = modelNode.variantProperty(name);
155 TypeName oldType = vprop.dynamicTypeName();
156 QVariant oldValue = vprop.value();
157
158 modelNode.removeProperty(name);
159
160 BindingProperty bprop = modelNode.bindingProperty(name);
161 if (bprop.isValid()) {
162 if (copyValue)
163 bprop.setDynamicTypeNameAndExpression(oldType, oldValue.toString());
164 return bprop;
165 }
166 } catch (RewritingException &e) {
167 m_exceptionError = e.description();
168 QTimer::singleShot(200, this, &DynamicPropertiesModel::handleException);
169 }
170 }
171 }
172 } else {
173 qWarning() << "DynamicPropertiesModel::replaceVariantWithBinding: no selected nodes";
174 }
175
176 return BindingProperty();
177 }
178
179
180 //Finds selected property, and changes it to empty value (QVariant())
181 //If it's a BindingProperty, then replaces it with empty VariantProperty
resetProperty(const PropertyName & name)182 void DynamicPropertiesModel::resetProperty(const PropertyName &name)
183 {
184 if (connectionView()->selectedModelNodes().count() == 1) {
185 const ModelNode modelNode = connectionView()->selectedModelNodes().constFirst();
186 if (modelNode.isValid()) {
187 if (modelNode.hasProperty(name)) {
188 try {
189 AbstractProperty abProp = modelNode.property(name);
190
191 if (abProp.isVariantProperty()) {
192 VariantProperty property = abProp.toVariantProperty();
193 QVariant newValue = convertVariantForTypeName(QVariant("none.none"), property.dynamicTypeName());
194 property.setDynamicTypeNameAndValue(property.dynamicTypeName(),
195 newValue);
196 }
197 else if (abProp.isBindingProperty()) {
198 BindingProperty property = abProp.toBindingProperty();
199 TypeName oldType = property.dynamicTypeName();
200
201 //removing old property, to create the new one with the same name:
202 modelNode.removeProperty(name);
203
204 VariantProperty newProperty = modelNode.variantProperty(name);
205 QVariant newValue = convertVariantForTypeName(QVariant("none.none"), oldType);
206 newProperty.setDynamicTypeNameAndValue(oldType,
207 newValue);
208 }
209
210 } catch (RewritingException &e) {
211 m_exceptionError = e.description();
212 QTimer::singleShot(200, this, &DynamicPropertiesModel::handleException);
213 }
214 }
215 }
216 }
217 else {
218 qWarning() << "DynamicPropertiesModel::resetProperty: no selected nodes";
219 }
220 }
221
bindingPropertyChanged(const BindingProperty & bindingProperty)222 void DynamicPropertiesModel::bindingPropertyChanged(const BindingProperty &bindingProperty)
223 {
224 if (!bindingProperty.isDynamic())
225 return;
226
227 m_handleDataChanged = false;
228
229 QList<ModelNode> selectedNodes = connectionView()->selectedModelNodes();
230 if (!selectedNodes.contains(bindingProperty.parentModelNode()))
231 return;
232 if (!m_lock) {
233 int rowNumber = findRowForBindingProperty(bindingProperty);
234
235 if (rowNumber == -1) {
236 addBindingProperty(bindingProperty);
237 } else {
238 updateBindingProperty(rowNumber);
239 }
240 }
241
242 m_handleDataChanged = true;
243 }
244
variantPropertyChanged(const VariantProperty & variantProperty)245 void DynamicPropertiesModel::variantPropertyChanged(const VariantProperty &variantProperty)
246 {
247 if (!variantProperty.isDynamic())
248 return;
249
250 m_handleDataChanged = false;
251
252 QList<ModelNode> selectedNodes = connectionView()->selectedModelNodes();
253 if (!selectedNodes.contains(variantProperty.parentModelNode()))
254 return;
255 if (!m_lock) {
256 int rowNumber = findRowForVariantProperty(variantProperty);
257
258 if (rowNumber == -1) {
259 addVariantProperty(variantProperty);
260 } else {
261 updateVariantProperty(rowNumber);
262 }
263 }
264
265 m_handleDataChanged = true;
266 }
267
bindingRemoved(const BindingProperty & bindingProperty)268 void DynamicPropertiesModel::bindingRemoved(const BindingProperty &bindingProperty)
269 {
270 m_handleDataChanged = false;
271
272 QList<ModelNode> selectedNodes = connectionView()->selectedModelNodes();
273 if (!selectedNodes.contains(bindingProperty.parentModelNode()))
274 return;
275 if (!m_lock) {
276 int rowNumber = findRowForBindingProperty(bindingProperty);
277 removeRow(rowNumber);
278 }
279
280 m_handleDataChanged = true;
281 }
282
selectionChanged(const QList<ModelNode> & selectedNodes)283 void DynamicPropertiesModel::selectionChanged(const QList<ModelNode> &selectedNodes)
284 {
285 Q_UNUSED(selectedNodes)
286 m_handleDataChanged = false;
287 resetModel();
288 m_handleDataChanged = true;
289 }
290
connectionView() const291 ConnectionView *DynamicPropertiesModel::connectionView() const
292 {
293 return m_connectionView;
294 }
295
abstractPropertyForRow(int rowNumber) const296 AbstractProperty DynamicPropertiesModel::abstractPropertyForRow(int rowNumber) const
297 {
298 const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt();
299 const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2).toString();
300
301 ModelNode modelNode = connectionView()->modelNodeForInternalId(internalId);
302
303 if (modelNode.isValid())
304 return modelNode.property(targetPropertyName.toUtf8());
305
306 return AbstractProperty();
307 }
308
bindingPropertyForRow(int rowNumber) const309 BindingProperty DynamicPropertiesModel::bindingPropertyForRow(int rowNumber) const
310 {
311 const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt();
312 const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2).toString();
313
314 ModelNode modelNode = connectionView()->modelNodeForInternalId(internalId);
315
316 if (modelNode.isValid())
317 return modelNode.bindingProperty(targetPropertyName.toUtf8());
318
319 return BindingProperty();
320 }
321
variantPropertyForRow(int rowNumber) const322 VariantProperty DynamicPropertiesModel::variantPropertyForRow(int rowNumber) const
323 {
324 const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt();
325 const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2).toString();
326
327 ModelNode modelNode = connectionView()->modelNodeForInternalId(internalId);
328
329 if (modelNode.isValid())
330 return modelNode.variantProperty(targetPropertyName.toUtf8());
331
332 return VariantProperty();
333 }
334
possibleTargetProperties(const BindingProperty & bindingProperty) const335 QStringList DynamicPropertiesModel::possibleTargetProperties(const BindingProperty &bindingProperty) const
336 {
337 const ModelNode modelNode = bindingProperty.parentModelNode();
338
339 if (!modelNode.isValid()) {
340 qWarning() << " BindingModel::possibleTargetPropertiesForRow invalid model node";
341 return QStringList();
342 }
343
344 NodeMetaInfo metaInfo = modelNode.metaInfo();
345
346 if (metaInfo.isValid()) {
347 QStringList possibleProperties;
348 foreach (const PropertyName &propertyName, metaInfo.propertyNames()) {
349 if (metaInfo.propertyIsWritable(propertyName))
350 possibleProperties << QString::fromUtf8(propertyName);
351 }
352
353 return possibleProperties;
354 }
355
356 return QStringList();
357 }
358
addDynamicPropertyForCurrentNode()359 void DynamicPropertiesModel::addDynamicPropertyForCurrentNode()
360 {
361 QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_PROPERTY_ADDED);
362
363 if (connectionView()->selectedModelNodes().count() == 1) {
364 const ModelNode modelNode = connectionView()->selectedModelNodes().constFirst();
365 if (modelNode.isValid()) {
366 try {
367 modelNode.variantProperty(unusedProperty(modelNode)).setDynamicTypeNameAndValue("string", QLatin1String("none.none"));
368 } catch (RewritingException &e) {
369 m_exceptionError = e.description();
370 QTimer::singleShot(200, this, &DynamicPropertiesModel::handleException);
371 }
372 }
373 } else {
374 qWarning() << " BindingModel::addBindingForCurrentNode not one node selected";
375 }
376 }
377
possibleSourceProperties(const BindingProperty & bindingProperty) const378 QStringList DynamicPropertiesModel::possibleSourceProperties(const BindingProperty &bindingProperty) const
379 {
380 const QString expression = bindingProperty.expression();
381 const QStringList stringlist = expression.split(QLatin1String("."));
382
383 PropertyName typeName;
384
385 if (bindingProperty.parentModelNode().metaInfo().isValid()) {
386 typeName = bindingProperty.parentModelNode().metaInfo().propertyTypeName(bindingProperty.name());
387 } else {
388 qWarning() << " BindingModel::possibleSourcePropertiesForRow no meta info for target node";
389 }
390
391 const QString &id = stringlist.constFirst();
392
393 ModelNode modelNode = getNodeByIdOrParent(id, bindingProperty.parentModelNode());
394
395 if (!modelNode.isValid()) {
396 qWarning() << " BindingModel::possibleSourcePropertiesForRow invalid model node";
397 return QStringList();
398 }
399
400 NodeMetaInfo metaInfo = modelNode.metaInfo();
401
402 if (metaInfo.isValid()) {
403 QStringList possibleProperties;
404 foreach (const PropertyName &propertyName, metaInfo.propertyNames()) {
405 if (metaInfo.propertyTypeName(propertyName) == typeName) //### todo proper check
406 possibleProperties << QString::fromUtf8(propertyName);
407 }
408 return possibleProperties;
409 } else {
410 qWarning() << " BindingModel::possibleSourcePropertiesForRow no meta info for source node";
411 }
412
413 return QStringList();
414 }
415
deleteDynamicPropertyByRow(int rowNumber)416 void DynamicPropertiesModel::deleteDynamicPropertyByRow(int rowNumber)
417 {
418 BindingProperty bindingProperty = bindingPropertyForRow(rowNumber);
419 if (bindingProperty.isValid()) {
420 bindingProperty.parentModelNode().removeProperty(bindingProperty.name());
421 }
422
423 VariantProperty variantProperty = variantPropertyForRow(rowNumber);
424
425 if (variantProperty.isValid()) {
426 variantProperty.parentModelNode().removeProperty(variantProperty.name());
427 }
428
429 resetModel();
430 }
431
addProperty(const QVariant & propertyValue,const QString & propertyType,const AbstractProperty & abstractProperty)432 void DynamicPropertiesModel::addProperty(const QVariant &propertyValue,
433 const QString &propertyType,
434 const AbstractProperty &abstractProperty)
435 {
436 QList<QStandardItem*> items;
437
438 QStandardItem *idItem;
439 QStandardItem *propertyNameItem;
440 QStandardItem *propertyTypeItem;
441 QStandardItem *propertyValueItem;
442
443 idItem = new QStandardItem(idOrTypeNameForNode(abstractProperty.parentModelNode()));
444 updateCustomData(idItem, abstractProperty);
445
446 propertyNameItem = new QStandardItem(QString::fromUtf8(abstractProperty.name()));
447
448 items.append(idItem);
449 items.append(propertyNameItem);
450
451
452 propertyTypeItem = new QStandardItem(propertyType);
453 items.append(propertyTypeItem);
454
455 propertyValueItem = new QStandardItem();
456 propertyValueItem->setData(propertyValue, Qt::DisplayRole);
457 items.append(propertyValueItem);
458
459 appendRow(items);
460 }
461
addBindingProperty(const BindingProperty & property)462 void DynamicPropertiesModel::addBindingProperty(const BindingProperty &property)
463 {
464 QVariant value = property.expression();
465 QString type = QString::fromLatin1(property.dynamicTypeName());
466 addProperty(value, type, property);
467 }
468
addVariantProperty(const VariantProperty & property)469 void DynamicPropertiesModel::addVariantProperty(const VariantProperty &property)
470 {
471 QVariant value = property.value();
472 QString type = QString::fromLatin1(property.dynamicTypeName());
473 addProperty(value, type, property);
474 }
475
updateBindingProperty(int rowNumber)476 void DynamicPropertiesModel::updateBindingProperty(int rowNumber)
477 {
478 BindingProperty bindingProperty = bindingPropertyForRow(rowNumber);
479
480 if (bindingProperty.isValid()) {
481 QString propertyName = QString::fromUtf8(bindingProperty.name());
482 updateDisplayRole(rowNumber, PropertyNameRow, propertyName);
483 QString value = bindingProperty.expression();
484 QString type = QString::fromUtf8(bindingProperty.dynamicTypeName());
485 updateDisplayRole(rowNumber, PropertyTypeRow, type);
486 updateDisplayRole(rowNumber, PropertyValueRow, value);
487 }
488 }
489
updateVariantProperty(int rowNumber)490 void DynamicPropertiesModel::updateVariantProperty(int rowNumber)
491 {
492 VariantProperty variantProperty = variantPropertyForRow(rowNumber);
493
494 if (variantProperty.isValid()) {
495 QString propertyName = QString::fromUtf8(variantProperty.name());
496 updateDisplayRole(rowNumber, PropertyNameRow, propertyName);
497 QVariant value = variantProperty.value();
498 QString type = QString::fromUtf8(variantProperty.dynamicTypeName());
499 updateDisplayRole(rowNumber, PropertyTypeRow, type);
500
501 updateDisplayRoleFromVariant(rowNumber, PropertyValueRow, value);
502 }
503 }
504
addModelNode(const ModelNode & modelNode)505 void DynamicPropertiesModel::addModelNode(const ModelNode &modelNode)
506 {
507 foreach (const BindingProperty &bindingProperty, modelNode.bindingProperties()) {
508 if (bindingProperty.isDynamic())
509 addBindingProperty(bindingProperty);
510 }
511
512 foreach (const VariantProperty &variantProperty, modelNode.variantProperties()) {
513 if (variantProperty.isDynamic())
514 addVariantProperty(variantProperty);
515 }
516 }
517
updateValue(int row)518 void DynamicPropertiesModel::updateValue(int row)
519 {
520 BindingProperty bindingProperty = bindingPropertyForRow(row);
521
522 if (bindingProperty.isBindingProperty()) {
523 const QString expression = data(index(row, PropertyValueRow)).toString();
524
525 RewriterTransaction transaction = connectionView()->beginRewriterTransaction(QByteArrayLiteral("DynamicPropertiesModel::updateValue"));
526 try {
527 bindingProperty.setDynamicTypeNameAndExpression(bindingProperty.dynamicTypeName(), expression);
528 transaction.commit(); //committing in the try block
529 } catch (Exception &e) {
530 m_exceptionError = e.description();
531 QTimer::singleShot(200, this, &DynamicPropertiesModel::handleException);
532 }
533 return;
534 }
535
536 VariantProperty variantProperty = variantPropertyForRow(row);
537
538 if (variantProperty.isVariantProperty()) {
539 const QVariant value = data(index(row, PropertyValueRow));
540
541 RewriterTransaction transaction = connectionView()->beginRewriterTransaction(QByteArrayLiteral("DynamicPropertiesModel::updateValue"));
542 try {
543 variantProperty.setDynamicTypeNameAndValue(variantProperty.dynamicTypeName(), value);
544 transaction.commit(); //committing in the try block
545 } catch (Exception &e) {
546 m_exceptionError = e.description();
547 QTimer::singleShot(200, this, &DynamicPropertiesModel::handleException);
548 }
549 }
550 }
551
updatePropertyName(int rowNumber)552 void DynamicPropertiesModel::updatePropertyName(int rowNumber)
553 {
554 const PropertyName newName = data(index(rowNumber, PropertyNameRow)).toString().toUtf8();
555 if (newName.isEmpty()) {
556 qWarning() << "DynamicPropertiesModel::updatePropertyName invalid property name";
557 return;
558 }
559
560 BindingProperty bindingProperty = bindingPropertyForRow(rowNumber);
561
562 ModelNode targetNode = bindingProperty.parentModelNode();
563
564 if (bindingProperty.isBindingProperty()) {
565 connectionView()->executeInTransaction("DynamicPropertiesModel::updatePropertyName", [bindingProperty, newName, &targetNode](){
566 const QString expression = bindingProperty.expression();
567 const PropertyName dynamicPropertyType = bindingProperty.dynamicTypeName();
568
569 targetNode.bindingProperty(newName).setDynamicTypeNameAndExpression(dynamicPropertyType, expression);
570 targetNode.removeProperty(bindingProperty.name());
571 });
572
573 updateCustomData(rowNumber, targetNode.bindingProperty(newName));
574 return;
575 }
576
577 VariantProperty variantProperty = variantPropertyForRow(rowNumber);
578
579 if (variantProperty.isVariantProperty()) {
580 const QVariant value = variantProperty.value();
581 const PropertyName dynamicPropertyType = variantProperty.dynamicTypeName();
582 ModelNode targetNode = variantProperty.parentModelNode();
583
584 connectionView()->executeInTransaction("DynamicPropertiesModel::updatePropertyName", [=](){
585 targetNode.variantProperty(newName).setDynamicTypeNameAndValue(dynamicPropertyType, value);
586 targetNode.removeProperty(variantProperty.name());
587 });
588
589 updateCustomData(rowNumber, targetNode.variantProperty(newName));
590 }
591 }
592
updatePropertyType(int rowNumber)593 void DynamicPropertiesModel::updatePropertyType(int rowNumber)
594 {
595
596 const TypeName newType = data(index(rowNumber, PropertyTypeRow)).toString().toLatin1();
597
598 if (newType.isEmpty()) {
599 qWarning() << "DynamicPropertiesModel::updatePropertyName invalid property type";
600 return;
601 }
602
603 BindingProperty bindingProperty = bindingPropertyForRow(rowNumber);
604
605 if (bindingProperty.isBindingProperty()) {
606 const QString expression = bindingProperty.expression();
607 const PropertyName propertyName = bindingProperty.name();
608 ModelNode targetNode = bindingProperty.parentModelNode();
609
610 connectionView()->executeInTransaction("DynamicPropertiesModel::updatePropertyType", [=](){
611 targetNode.removeProperty(bindingProperty.name());
612 targetNode.bindingProperty(propertyName).setDynamicTypeNameAndExpression(newType, expression);
613 });
614
615 updateCustomData(rowNumber, targetNode.bindingProperty(propertyName));
616 return;
617 }
618
619 VariantProperty variantProperty = variantPropertyForRow(rowNumber);
620
621 if (variantProperty.isVariantProperty()) {
622 const QVariant value = variantProperty.value();
623 ModelNode targetNode = variantProperty.parentModelNode();
624 const PropertyName propertyName = variantProperty.name();
625
626 connectionView()->executeInTransaction("DynamicPropertiesModel::updatePropertyType", [=](){
627 targetNode.removeProperty(variantProperty.name());
628 if (newType == "alias") { //alias properties have to be bindings
629 targetNode.bindingProperty(propertyName).setDynamicTypeNameAndExpression(newType, QLatin1String("none.none"));
630 } else {
631 targetNode.variantProperty(propertyName).setDynamicTypeNameAndValue(newType, convertVariantForTypeName(value, newType));
632 }
633 });
634
635 updateCustomData(rowNumber, targetNode.variantProperty(propertyName));
636
637 if (variantProperty.isVariantProperty()) {
638 updateVariantProperty(rowNumber);
639 } else if (bindingProperty.isBindingProperty()) {
640 updateBindingProperty(rowNumber);
641 }
642 }
643 }
644
getNodeByIdOrParent(const QString & id,const ModelNode & targetNode) const645 ModelNode DynamicPropertiesModel::getNodeByIdOrParent(const QString &id, const ModelNode &targetNode) const
646 {
647 ModelNode modelNode;
648
649 if (id != QLatin1String("parent")) {
650 modelNode = connectionView()->modelNodeForId(id);
651 } else {
652 if (targetNode.hasParentProperty()) {
653 modelNode = targetNode.parentProperty().parentModelNode();
654 }
655 }
656 return modelNode;
657 }
658
updateCustomData(QStandardItem * item,const AbstractProperty & property)659 void DynamicPropertiesModel::updateCustomData(QStandardItem *item, const AbstractProperty &property)
660 {
661 item->setData(property.parentModelNode().internalId(), Qt::UserRole + 1);
662 item->setData(property.name(), Qt::UserRole + 2);
663 }
664
updateCustomData(int row,const AbstractProperty & property)665 void DynamicPropertiesModel::updateCustomData(int row, const AbstractProperty &property)
666 {
667 QStandardItem* idItem = item(row, 0);
668 updateCustomData(idItem, property);
669 }
670
findRowForBindingProperty(const BindingProperty & bindingProperty) const671 int DynamicPropertiesModel::findRowForBindingProperty(const BindingProperty &bindingProperty) const
672 {
673 for (int i=0; i < rowCount(); i++) {
674 if (compareBindingProperties(bindingPropertyForRow(i), bindingProperty))
675 return i;
676 }
677 //not found
678 return -1;
679 }
680
findRowForVariantProperty(const VariantProperty & variantProperty) const681 int DynamicPropertiesModel::findRowForVariantProperty(const VariantProperty &variantProperty) const
682 {
683 for (int i=0; i < rowCount(); i++) {
684 if (compareVariantProperties(variantPropertyForRow(i), variantProperty))
685 return i;
686 }
687 //not found
688 return -1;
689 }
690
getExpressionStrings(const BindingProperty & bindingProperty,QString * sourceNode,QString * sourceProperty)691 bool DynamicPropertiesModel::getExpressionStrings(const BindingProperty &bindingProperty, QString *sourceNode, QString *sourceProperty)
692 {
693 //### todo we assume no expressions yet
694
695 const QString expression = bindingProperty.expression();
696
697 if (true) {
698 const QStringList stringList = expression.split(QLatin1String("."));
699
700 *sourceNode = stringList.constFirst();
701
702 QString propertyName;
703
704 for (int i=1; i < stringList.count(); i++) {
705 propertyName += stringList.at(i);
706 if (i != stringList.count() - 1)
707 propertyName += QLatin1String(".");
708 }
709 *sourceProperty = propertyName;
710 }
711 return true;
712 }
713
updateDisplayRole(int row,int columns,const QString & string)714 void DynamicPropertiesModel::updateDisplayRole(int row, int columns, const QString &string)
715 {
716 QModelIndex modelIndex = index(row, columns);
717 if (data(modelIndex).toString() != string)
718 setData(modelIndex, string);
719 }
720
updateDisplayRoleFromVariant(int row,int columns,const QVariant & variant)721 void DynamicPropertiesModel::updateDisplayRoleFromVariant(int row, int columns, const QVariant &variant)
722 {
723 QModelIndex modelIndex = index(row, columns);
724 if (data(modelIndex) != variant)
725 setData(modelIndex, variant);
726 }
727
728
handleDataChanged(const QModelIndex & topLeft,const QModelIndex & bottomRight)729 void DynamicPropertiesModel::handleDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
730 {
731 if (!m_handleDataChanged)
732 return;
733
734 if (topLeft != bottomRight) {
735 qWarning() << "BindingModel::handleDataChanged multi edit?";
736 return;
737 }
738
739 m_lock = true;
740
741 int currentColumn = topLeft.column();
742 int currentRow = topLeft.row();
743
744 switch (currentColumn) {
745 case TargetModelNodeRow: {
746 //updating user data
747 } break;
748 case PropertyNameRow: {
749 updatePropertyName(currentRow);
750 } break;
751 case PropertyTypeRow: {
752 updatePropertyType(currentRow);
753 } break;
754 case PropertyValueRow: {
755 updateValue(currentRow);
756 } break;
757
758 default: qWarning() << "BindingModel::handleDataChanged column" << currentColumn;
759 }
760
761 m_lock = false;
762 }
763
handleException()764 void DynamicPropertiesModel::handleException()
765 {
766 QMessageBox::warning(nullptr, tr("Error"), m_exceptionError);
767 resetModel();
768 }
769
770 } // namespace Internal
771
772 } // namespace QmlDesigner
773