diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp index 9153d4d6a88..7f03b42161b 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp @@ -206,7 +206,9 @@ void BindingEditor::prepareBindings() if (bindingProperty.isValid()) { if (bindingProperty.isDynamic()) { const TypeName dynamicTypeName = bindingProperty.dynamicTypeName(); - if ((dynamicTypeName == m_backendValueTypeName) || variantTypes.contains(dynamicTypeName)) { + if (skipTypeFiltering + || (dynamicTypeName == m_backendValueTypeName) + || variantTypes.contains(dynamicTypeName)) { binding.properties.append(QString::fromUtf8(bindingProperty.name())); } } @@ -216,7 +218,9 @@ void BindingEditor::prepareBindings() if (variantProperty.isValid()) { if (variantProperty.isDynamic()) { const TypeName dynamicTypeName = variantProperty.dynamicTypeName(); - if ((dynamicTypeName == m_backendValueTypeName) || variantTypes.contains(dynamicTypeName)) { + if (skipTypeFiltering + || (dynamicTypeName == m_backendValueTypeName) + || variantTypes.contains(dynamicTypeName)) { binding.properties.append(QString::fromUtf8(variantProperty.name())); } } diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp index 1163af6c58b..00f32a29c57 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp @@ -38,6 +38,11 @@ #include #include +#include + +#include +#include + #include #include #include @@ -47,8 +52,6 @@ #include #include -#include - namespace QmlDesigner { namespace Internal { @@ -57,28 +60,14 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) : QFrame(parent), ui(new Ui::ConnectionViewWidget) { - m_actionEditor = new QmlDesigner::ActionEditor(this); - QObject::connect(m_actionEditor, &QmlDesigner::ActionEditor::accepted, - [&]() { - if (m_actionEditor->hasModelIndex()) { - ConnectionModel *connectionModel = qobject_cast(ui->connectionView->model()); - if (connectionModel->connectionView()->isWidgetEnabled() - && (connectionModel->rowCount() > m_actionEditor->modelIndex().row())) - { - SignalHandlerProperty signalHandler = - connectionModel->signalHandlerPropertyForRow(m_actionEditor->modelIndex().row()); - signalHandler.setSource(m_actionEditor->bindingValue()); - } - m_actionEditor->resetModelIndex(); - } + m_connectonEditor = new QmlDesigner::ActionEditor(this); + m_bindingEditor = new QmlDesigner::BindingEditor(this); + m_dynamicEditor = new QmlDesigner::BindingEditor(this); + + editorForConnection(); + editorForBinding(); + editorForDynamic(); - m_actionEditor->hideWidget(); - }); - QObject::connect(m_actionEditor, &QmlDesigner::ActionEditor::rejected, - [&]() { - m_actionEditor->resetModelIndex(); - m_actionEditor->hideWidget(); - }); setWindowTitle(tr("Connections", "Title of connection view")); ui->setupUi(this); @@ -122,7 +111,9 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) : ConnectionViewWidget::~ConnectionViewWidget() { - delete m_actionEditor; + delete m_connectonEditor; + delete m_bindingEditor; + delete m_dynamicEditor; delete ui; } @@ -150,30 +141,134 @@ void ConnectionViewWidget::setConnectionModel(ConnectionModel *model) void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) { - if (currentTab() != ConnectionTab || ui->connectionView == nullptr) - return; + auto tablePos = [&](QTableView *targetView) { + //adjusting qpoint to the qtableview entrances: + QPoint posInTable(targetView->mapFromGlobal(mapToGlobal(event->pos()))); + posInTable = QPoint(posInTable.x(), posInTable.y() - targetView->horizontalHeader()->height()); + return posInTable; + }; - //adjusting qpoint to the qtableview entrances: - QPoint posInTable(ui->connectionView->mapFromGlobal(mapToGlobal(event->pos()))); - posInTable = QPoint(posInTable.x(), posInTable.y() - ui->connectionView->horizontalHeader()->height()); + switch (currentTab()) { + case ConnectionTab: + if (ui->connectionView != nullptr) { + QTableView *targetView = ui->connectionView; + //making sure that we have source column in our hands: + QModelIndex index = targetView->indexAt(tablePos(targetView)).siblingAtColumn(ConnectionModel::SourceRow); + if (!index.isValid()) + return; - //making sure that we have source column in our hands: - QModelIndex index = ui->connectionView->indexAt(posInTable).siblingAtColumn(ConnectionModel::SourceRow); - if (!index.isValid()) - return; + QMenu menu(this); - QMenu menu(this); + menu.addAction(tr("Open Connection Editor"), [&]() { + if (index.isValid()) { + m_connectonEditor->showWidget(mapToGlobal(event->pos()).x(), mapToGlobal(event->pos()).y()); + m_connectonEditor->setBindingValue(index.data().toString()); + m_connectonEditor->setModelIndex(index); + m_connectonEditor->updateWindowName(); + } + }); - menu.addAction(tr("Open Connection Editor"), [&]() { - if (index.isValid()) { - m_actionEditor->showWidget(mapToGlobal(event->pos()).x(), mapToGlobal(event->pos()).y()); - m_actionEditor->setBindingValue(index.data().toString()); - m_actionEditor->setModelIndex(index); - m_actionEditor->updateWindowName(); + menu.exec(event->globalPos()); } - }); + break; + + case BindingTab: + if (ui->bindingView != nullptr) { + QTableView *targetView = bindingTableView(); + QModelIndex index = targetView->indexAt(tablePos(targetView)).siblingAtColumn(BindingModel::SourcePropertyNameRow); + if (!index.isValid()) + return; + + QMenu menu(this); + + menu.addAction(tr("Open Binding Editor"), [&]() { + if (index.isValid()) { + BindingModel *binModel = qobject_cast(targetView->model()); + ModelNode node = binModel->connectionView()->rootModelNode(); + + BindingProperty property = binModel->bindingPropertyForRow(index.row()); + + if (property.isValid()) { + if (property.isBindingProperty()) { + m_bindingEditor->showWidget(); + m_bindingEditor->setBindingValue(property.expression()); + m_bindingEditor->setModelNode(node); + if (property.isDynamic()) { + m_bindingEditor->setBackendValueTypeName(property.dynamicTypeName()); + } + else { + m_bindingEditor->setBackendValueTypeName(node.metaInfo().propertyTypeName(property.name())); + } + m_bindingEditor->prepareBindings(); + m_bindingEditor->updateWindowName(); + + m_bindingIndex = index; + } + } + } + }); + menu.exec(event->globalPos()); + } + break; + + case DynamicPropertiesTab: + if (ui->dynamicPropertiesView != nullptr) { + QTableView *targetView = dynamicPropertiesTableView(); + QModelIndex index = targetView->indexAt(tablePos(targetView)).siblingAtColumn(DynamicPropertiesModel::PropertyValueRow); + if (!index.isValid()) + return; + + QMenu menu(this); + + menu.addAction(tr("Open Binding Editor"), [&]() { + if (index.isValid()) { + DynamicPropertiesModel *dynPropModel = qobject_cast(targetView->model()); + ModelNode node = dynPropModel->connectionView()->rootModelNode(); + + AbstractProperty abProp = dynPropModel->abstractPropertyForRow(index.row()); + + QString newExpression; + + if (abProp.isValid()) { + if (abProp.isBindingProperty()) { + BindingProperty property = abProp.toBindingProperty(); + newExpression = property.expression(); + } + else if (abProp.isVariantProperty()) { + VariantProperty property = abProp.toVariantProperty(); + newExpression = property.value().toString(); + } + else + return; + + m_dynamicEditor->showWidget(); + m_dynamicEditor->setBindingValue(newExpression); + m_dynamicEditor->setModelNode(node); + m_dynamicEditor->setBackendValueTypeName(abProp.dynamicTypeName()); + m_dynamicEditor->prepareBindings(); + m_dynamicEditor->updateWindowName(); + + m_dynamicIndex = index; + } + } + }); + + menu.addAction(tr("Reset Property"), [&]() { + if (index.isValid()) { + DynamicPropertiesModel *propertiesModel = qobject_cast(dynamicPropertiesTableView()->model()); + + propertiesModel->resetProperty(propertiesModel->abstractPropertyForRow(index.row()).name()); + } + }); + + menu.exec(event->globalPos()); + } + break; + default: + break; + + } - menu.exec(event->globalPos()); } void ConnectionViewWidget::setDynamicPropertiesModel(DynamicPropertiesModel *model) @@ -358,6 +453,112 @@ void ConnectionViewWidget::addButtonClicked() invalidateButtonStatus(); } +void ConnectionViewWidget::editorForConnection() +{ + QObject::connect(m_connectonEditor, &QmlDesigner::ActionEditor::accepted, + [&]() { + if (m_connectonEditor->hasModelIndex()) { + ConnectionModel *connectionModel = qobject_cast(ui->connectionView->model()); + if (connectionModel->connectionView()->isWidgetEnabled() + && (connectionModel->rowCount() > m_connectonEditor->modelIndex().row())) + { + SignalHandlerProperty signalHandler = + connectionModel->signalHandlerPropertyForRow(m_connectonEditor->modelIndex().row()); + signalHandler.setSource(m_connectonEditor->bindingValue()); + } + m_connectonEditor->resetModelIndex(); + } + + m_connectonEditor->hideWidget(); + }); + QObject::connect(m_connectonEditor, &QmlDesigner::ActionEditor::rejected, + [&]() { + m_connectonEditor->resetModelIndex(); + m_connectonEditor->hideWidget(); + }); +} + +void ConnectionViewWidget::editorForBinding() +{ + QObject::connect(m_bindingEditor, &QmlDesigner::BindingEditor::accepted, + [&]() { + BindingModel *bindingModel = qobject_cast(bindingTableView()->model()); + QString newValue = m_bindingEditor->bindingValue().trimmed(); + + if (m_bindingIndex.isValid()) { + if (bindingModel->connectionView()->isWidgetEnabled() + && (bindingModel->rowCount() > m_bindingIndex.row())) + { + BindingProperty property = bindingModel->bindingPropertyForRow(m_bindingIndex.row()); + + if (property.isValid()) { + if (property.isBindingProperty()) { + if (property.isDynamic()) { + property.setDynamicTypeNameAndExpression(property.dynamicTypeName(), newValue); + } + else { + property.setExpression(newValue); + } + } + } + } + } + + m_bindingIndex = QModelIndex(); + m_bindingEditor->hideWidget(); + }); + QObject::connect(m_bindingEditor, &QmlDesigner::BindingEditor::rejected, + [&]() { + m_bindingIndex = QModelIndex(); //invalidating index + m_bindingEditor->hideWidget(); + }); +} + +void ConnectionViewWidget::editorForDynamic() +{ + QObject::connect(m_dynamicEditor, &QmlDesigner::BindingEditor::accepted, + [&]() { + DynamicPropertiesModel *propertiesModel = qobject_cast(dynamicPropertiesTableView()->model()); + QString newValue = m_dynamicEditor->bindingValue().trimmed(); + + if (m_dynamicIndex.isValid()) { + if (propertiesModel->connectionView()->isWidgetEnabled() + && (propertiesModel->rowCount() > m_dynamicIndex.row())) + { + AbstractProperty abProp = propertiesModel->abstractPropertyForRow(m_dynamicIndex.row()); + + if (abProp.isValid()) { + if (abProp.isBindingProperty()) { + BindingProperty property = abProp.toBindingProperty(); + property.setDynamicTypeNameAndExpression(property.dynamicTypeName(), newValue); + } + + //if it's a variant property, then we remove it and replace with binding + else if (abProp.isVariantProperty()) { + VariantProperty property = abProp.toVariantProperty(); + PropertyName name = property.name(); + TypeName type = property.dynamicTypeName(); + QVariant value = newValue; + + BindingProperty newProperty = propertiesModel->replaceVariantWithBinding(name); + if (newProperty.isValid()) { + newProperty.setDynamicTypeNameAndExpression(type, newValue); + } + } + } + } + } + + m_dynamicIndex = QModelIndex(); + m_dynamicEditor->hideWidget(); + }); + QObject::connect(m_dynamicEditor, &QmlDesigner::BindingEditor::rejected, + [&]() { + m_dynamicIndex = QModelIndex(); //invalidating index + m_dynamicEditor->hideWidget(); + }); +} + void ConnectionViewWidget::bindingTableViewSelectionChanged(const QModelIndex ¤t, const QModelIndex & /*previous*/) { if (currentTab() == BindingTab) { diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h index d69d0de2801..68319e16b5c 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h +++ b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h @@ -40,6 +40,7 @@ namespace QmlDesigner { namespace Ui { class ConnectionViewWidget; } class ActionEditor; +class BindingEditor; namespace Internal { @@ -99,9 +100,19 @@ private: void removeButtonClicked(); void addButtonClicked(); + //methods to prepare editors + void editorForConnection(); + void editorForBinding(); + void editorForDynamic(); + private: Ui::ConnectionViewWidget *ui; - QmlDesigner::ActionEditor *m_actionEditor; + QmlDesigner::ActionEditor *m_connectonEditor; //editor for connections in connection view + QmlDesigner::BindingEditor *m_bindingEditor; //editor for properties in binding view + QmlDesigner::BindingEditor *m_dynamicEditor; //editor for properties in dynamic view + + QModelIndex m_bindingIndex; + QModelIndex m_dynamicIndex; }; } // namespace Internal diff --git a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp index 0a08e5c8839..cdbc1ee7312 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp @@ -137,6 +137,84 @@ void DynamicPropertiesModel::resetModel() endResetModel(); } + +//Method creates dynamic BindingProperty with the same name and type as old VariantProperty +//Value copying is optional +BindingProperty DynamicPropertiesModel::replaceVariantWithBinding(const PropertyName &name, bool copyValue) +{ + if (connectionView()->selectedModelNodes().count() == 1) { + const ModelNode modelNode = connectionView()->selectedModelNodes().constFirst(); + if (modelNode.isValid()) { + if (modelNode.hasVariantProperty(name)) { + try { + VariantProperty vprop = modelNode.variantProperty(name); + TypeName oldType = vprop.dynamicTypeName(); + QVariant oldValue = vprop.value(); + + modelNode.removeProperty(name); + + BindingProperty bprop = modelNode.bindingProperty(name); + if (bprop.isValid()) { + if (copyValue) + bprop.setDynamicTypeNameAndExpression(oldType, oldValue.toString()); + return bprop; + } + } catch (RewritingException &e) { + m_exceptionError = e.description(); + QTimer::singleShot(200, this, &DynamicPropertiesModel::handleException); + } + } + } + } else { + qWarning() << "DynamicPropertiesModel::replaceVariantWithBinding: no selected nodes"; + } + + return BindingProperty(); +} + + +//Finds selected property, and changes it to empty value (QVariant()) +//If it's a BindingProperty, then replaces it with empty VariantProperty +void DynamicPropertiesModel::resetProperty(const PropertyName &name) +{ + if (connectionView()->selectedModelNodes().count() == 1) { + const ModelNode modelNode = connectionView()->selectedModelNodes().constFirst(); + if (modelNode.isValid()) { + if (modelNode.hasProperty(name)) { + try { + AbstractProperty abProp = modelNode.property(name); + + if (abProp.isVariantProperty()) { + VariantProperty property = abProp.toVariantProperty(); + QVariant newValue = convertVariantForTypeName(QVariant("none.none"), property.dynamicTypeName()); + property.setDynamicTypeNameAndValue(property.dynamicTypeName(), + newValue); + } + else if (abProp.isBindingProperty()) { + BindingProperty property = abProp.toBindingProperty(); + TypeName oldType = property.dynamicTypeName(); + + //removing old property, to create the new one with the same name: + modelNode.removeProperty(name); + + VariantProperty newProperty = modelNode.variantProperty(name); + QVariant newValue = convertVariantForTypeName(QVariant("none.none"), oldType); + newProperty.setDynamicTypeNameAndValue(oldType, + newValue); + } + + } catch (RewritingException &e) { + m_exceptionError = e.description(); + QTimer::singleShot(200, this, &DynamicPropertiesModel::handleException); + } + } + } + } + else { + qWarning() << "DynamicPropertiesModel::resetProperty: no selected nodes"; + } +} + void DynamicPropertiesModel::bindingPropertyChanged(const BindingProperty &bindingProperty) { if (!bindingProperty.isDynamic()) @@ -211,9 +289,21 @@ ConnectionView *DynamicPropertiesModel::connectionView() const return m_connectionView; } +AbstractProperty DynamicPropertiesModel::abstractPropertyForRow(int rowNumber) const +{ + const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt(); + const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2).toString(); + + ModelNode modelNode = connectionView()->modelNodeForInternalId(internalId); + + if (modelNode.isValid()) + return modelNode.property(targetPropertyName.toUtf8()); + + return AbstractProperty(); +} + BindingProperty DynamicPropertiesModel::bindingPropertyForRow(int rowNumber) const { - const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt(); const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2).toString(); diff --git a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h index e0c9617feda..1d71c1230e0 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h +++ b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h @@ -55,6 +55,7 @@ public: void selectionChanged(const QList &selectedNodes); ConnectionView *connectionView() const; + AbstractProperty abstractPropertyForRow(int rowNumber) const; BindingProperty bindingPropertyForRow(int rowNumber) const; VariantProperty variantPropertyForRow(int rowNumber) const; QStringList possibleTargetProperties(const BindingProperty &bindingProperty) const; @@ -65,6 +66,9 @@ public: void addDynamicPropertyForCurrentNode(); void resetModel(); + BindingProperty replaceVariantWithBinding(const PropertyName &name, bool copyValue = false); + void resetProperty(const PropertyName &name); + protected: void addProperty(const QVariant &propertyValue, const QString &propertyType,