QmlDesigner: Add "NOT" option to binding editor

* Add "NOT" CheckBox in binding editor if boolean target
* Fix wrong node assignment in binding editor context menu call
* Fix connection editor state iteration source
* Cleanup redundant code

Task-number: QDS-2872
Change-Id: I8780bb1507f991b52aacfb011b889896d74ccb4f
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Henning Gruendl
2020-11-13 10:55:23 +01:00
committed by Henning Gründl
parent 6d5e302157
commit d3ab7a89f9
5 changed files with 104 additions and 80 deletions

View File

@@ -279,10 +279,9 @@ void ActionEditor::prepareConnections()
} }
// States // States
for (const QmlModelState &state : QmlItemNode(m_modelNode).states().allStates()) for (const QmlModelState &state : QmlItemNode(m_modelNode.view()->rootModelNode()).states().allStates())
states.append(state.name()); states.append(state.name());
if (!connections.isEmpty() && !m_dialog.isNull()) if (!connections.isEmpty() && !m_dialog.isNull())
m_dialog->setAllConnections(connections, singletons, states); m_dialog->setAllConnections(connections, singletons, states);
} }

View File

@@ -271,9 +271,7 @@ void BindingEditor::prepareBindings()
} }
if (!bindings.isEmpty() && !m_dialog.isNull()) if (!bindings.isEmpty() && !m_dialog.isNull())
m_dialog->setAllBindings(bindings); m_dialog->setAllBindings(bindings, m_backendValueTypeName);
updateWindowName();
} }
void BindingEditor::updateWindowName() void BindingEditor::updateWindowName()

View File

@@ -37,6 +37,7 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QComboBox> #include <QComboBox>
#include <QCheckBox>
#include <QPlainTextEdit> #include <QPlainTextEdit>
namespace QmlDesigner { namespace QmlDesigner {
@@ -50,6 +51,8 @@ BindingEditorDialog::BindingEditorDialog(QWidget *parent)
this, &BindingEditorDialog::itemIDChanged); this, &BindingEditorDialog::itemIDChanged);
QObject::connect(m_comboBoxProperty, QOverload<int>::of(&QComboBox::currentIndexChanged), QObject::connect(m_comboBoxProperty, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &BindingEditorDialog::propertyIDChanged); this, &BindingEditorDialog::propertyIDChanged);
QObject::connect(m_checkBoxNot, QOverload<int>::of(&QCheckBox::stateChanged),
this, &BindingEditorDialog::checkBoxChanged);
} }
BindingEditorDialog::~BindingEditorDialog() BindingEditorDialog::~BindingEditorDialog()
@@ -58,7 +61,12 @@ BindingEditorDialog::~BindingEditorDialog()
void BindingEditorDialog::adjustProperties() void BindingEditorDialog::adjustProperties()
{ {
const QString expression = editorValue(); QString expression = editorValue().trimmed();
m_checkBoxNot->setChecked(expression.startsWith("!"));
if (m_checkBoxNot->isChecked())
expression.remove(0, 1);
QString item; QString item;
QString property; QString property;
QStringList expressionElements = expression.split("."); QStringList expressionElements = expression.split(".");
@@ -94,12 +102,14 @@ void BindingEditorDialog::adjustProperties()
m_comboBoxProperty->setCurrentText(property); m_comboBoxProperty->setCurrentText(property);
} }
void BindingEditorDialog::setAllBindings(QList<BindingOption> bindings) void BindingEditorDialog::setAllBindings(const QList<BindingOption> &bindings, const TypeName &type)
{ {
m_lock = true; m_lock = true;
m_bindings = bindings; m_bindings = bindings;
m_type = type;
setupComboBoxes(); setupComboBoxes();
setupCheckBox();
adjustProperties(); adjustProperties();
m_lock = false; m_lock = false;
@@ -109,11 +119,15 @@ void BindingEditorDialog::setupUIComponents()
{ {
m_comboBoxItem = new QComboBox(this); m_comboBoxItem = new QComboBox(this);
m_comboBoxProperty = new QComboBox(this); m_comboBoxProperty = new QComboBox(this);
m_checkBoxNot = new QCheckBox(this);
m_checkBoxNot->setText(tr("NOT"));
m_checkBoxNot->setVisible(false);
m_checkBoxNot->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
m_checkBoxNot->setToolTip(tr("Invert the boolean expression."));
m_comboBoxLayout->addWidget(m_comboBoxItem); m_comboBoxLayout->addWidget(m_comboBoxItem);
m_comboBoxLayout->addWidget(m_comboBoxProperty); m_comboBoxLayout->addWidget(m_comboBoxProperty);
m_comboBoxLayout->addWidget(m_checkBoxNot);
//this->resize(660, 240);
} }
void BindingEditorDialog::setupComboBoxes() void BindingEditorDialog::setupComboBoxes()
@@ -125,6 +139,12 @@ void BindingEditorDialog::setupComboBoxes()
m_comboBoxItem->addItem(bind.item); m_comboBoxItem->addItem(bind.item);
} }
void BindingEditorDialog::setupCheckBox()
{
const bool visible = (m_type == "bool");
m_checkBoxNot->setVisible(visible);
}
void BindingEditorDialog::itemIDChanged(int itemID) void BindingEditorDialog::itemIDChanged(int itemID)
{ {
const QString previousProperty = m_comboBoxProperty->currentText(); const QString previousProperty = m_comboBoxProperty->currentText();
@@ -148,12 +168,31 @@ void BindingEditorDialog::propertyIDChanged(int propertyID)
const int itemID = m_comboBoxItem->currentIndex(); const int itemID = m_comboBoxItem->currentIndex();
if (!m_lock) if (!m_lock)
if (!m_comboBoxProperty->currentText().isEmpty() && (m_comboBoxProperty->currentText() != undefinedString)) if (!m_comboBoxProperty->currentText().isEmpty() && (m_comboBoxProperty->currentText() != undefinedString)) {
setEditorValue(m_comboBoxItem->itemText(itemID) + "." + m_comboBoxProperty->itemText(propertyID)); QString expression = m_comboBoxItem->itemText(itemID) + "." + m_comboBoxProperty->itemText(propertyID);
if (m_checkBoxNot->isChecked())
expression.prepend("!");
setEditorValue(expression);
}
const int undefinedProperty = m_comboBoxProperty->findText(undefinedString); const int undefinedProperty = m_comboBoxProperty->findText(undefinedString);
if ((undefinedProperty != -1) && (m_comboBoxProperty->itemText(propertyID) != undefinedString)) if ((undefinedProperty != -1) && (m_comboBoxProperty->itemText(propertyID) != undefinedString))
m_comboBoxProperty->removeItem(undefinedProperty); m_comboBoxProperty->removeItem(undefinedProperty);
} }
void BindingEditorDialog::checkBoxChanged(int state)
{
if (m_lock)
return;
QString expression = editorValue().trimmed();
if (state == Qt::Checked)
expression.prepend("!");
else
expression.remove(0, 1);
setEditorValue(expression);
}
} // QmlDesigner namespace } // QmlDesigner namespace

View File

@@ -30,6 +30,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QComboBox; class QComboBox;
class QCheckBox;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace QmlDesigner { namespace QmlDesigner {
@@ -56,21 +57,25 @@ public:
void adjustProperties() override; void adjustProperties() override;
void setAllBindings(QList<BindingOption> bindings); void setAllBindings(const QList<BindingOption> &bindings, const TypeName &type);
private: private:
void setupUIComponents(); void setupUIComponents();
void setupComboBoxes(); void setupComboBoxes();
void setupCheckBox();
public slots: public slots:
void itemIDChanged(int); void itemIDChanged(int);
void propertyIDChanged(int); void propertyIDChanged(int);
void checkBoxChanged(int);
private: private:
QComboBox *m_comboBoxItem = nullptr; QComboBox *m_comboBoxItem = nullptr;
QComboBox *m_comboBoxProperty = nullptr; QComboBox *m_comboBoxProperty = nullptr;
QCheckBox *m_checkBoxNot = nullptr;
QList<BindingOption> m_bindings; QList<BindingOption> m_bindings;
TypeName m_type;
}; };
} }

View File

@@ -142,9 +142,9 @@ void ConnectionViewWidget::setConnectionModel(ConnectionModel *model)
void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event) void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event)
{ {
auto tablePos = [&](QTableView *targetView) { auto tablePos = [&](QTableView *targetView) {
//adjusting qpoint to the qtableview entrances: // adjusting qpoint to the qtableview entrances:
QPoint posInTable(targetView->mapFromGlobal(mapToGlobal(event->pos()))); QPoint posInTable(targetView->mapFromGlobal(mapToGlobal(event->pos())));
posInTable = QPoint(posInTable.x(), posInTable.y() - targetView->horizontalHeader()->height()); posInTable.ry() -= targetView->horizontalHeader()->height();
return posInTable; return posInTable;
}; };
@@ -152,24 +152,24 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event)
case ConnectionTab: case ConnectionTab:
if (ui->connectionView != nullptr) { if (ui->connectionView != nullptr) {
QTableView *targetView = ui->connectionView; QTableView *targetView = ui->connectionView;
//making sure that we have source column in our hands: // making sure that we have source column in our hands:
QModelIndex index = targetView->indexAt(tablePos(targetView)).siblingAtColumn(ConnectionModel::SourceRow); const QModelIndex index = targetView->indexAt(tablePos(targetView)).siblingAtColumn(ConnectionModel::SourceRow);
if (!index.isValid()) if (!index.isValid())
return; return;
QMenu menu(this); QMenu menu(this);
menu.addAction(tr("Open Connection Editor"), [&]() { menu.addAction(tr("Open Connection Editor"), [&]() {
if (index.isValid()) { auto *connectionModel = qobject_cast<ConnectionModel *>(targetView->model());
auto *connectionModel = qobject_cast<ConnectionModel *>(targetView->model()); const SignalHandlerProperty property = connectionModel->signalHandlerPropertyForRow(index.row());
ModelNode node = connectionModel->connectionView()->rootModelNode(); const ModelNode node = property.parentModelNode();
m_connectionEditor->showWidget();
m_connectionEditor->setConnectionValue(index.data().toString()); m_connectionEditor->showWidget();
m_connectionEditor->setModelIndex(index); m_connectionEditor->setConnectionValue(index.data().toString());
m_connectionEditor->setModelNode(node); m_connectionEditor->setModelIndex(index);
m_connectionEditor->prepareConnections(); m_connectionEditor->setModelNode(node);
m_connectionEditor->updateWindowName(); m_connectionEditor->prepareConnections();
} m_connectionEditor->updateWindowName();
}); });
menu.exec(event->globalPos()); menu.exec(event->globalPos());
@@ -179,37 +179,31 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event)
case BindingTab: case BindingTab:
if (ui->bindingView != nullptr) { if (ui->bindingView != nullptr) {
QTableView *targetView = bindingTableView(); QTableView *targetView = bindingTableView();
QModelIndex index = targetView->indexAt(tablePos(targetView)).siblingAtColumn(BindingModel::SourcePropertyNameRow); const QModelIndex index = targetView->indexAt(tablePos(targetView)).siblingAtColumn(BindingModel::SourcePropertyNameRow);
if (!index.isValid()) if (!index.isValid())
return; return;
QMenu menu(this); QMenu menu(this);
menu.addAction(tr("Open Binding Editor"), [&]() { menu.addAction(tr("Open Binding Editor"), [&]() {
if (index.isValid()) { BindingModel *bindingModel = qobject_cast<BindingModel*>(targetView->model());
BindingModel *binModel = qobject_cast<BindingModel*>(targetView->model()); const BindingProperty property = bindingModel->bindingPropertyForRow(index.row());
ModelNode node = binModel->connectionView()->rootModelNode();
BindingProperty property = binModel->bindingPropertyForRow(index.row()); if (!property.isValid() || !property.isBindingProperty())
return;
if (property.isValid()) { const ModelNode node = property.parentModelNode();
if (property.isBindingProperty()) { const TypeName typeName = property.isDynamic() ? property.dynamicTypeName()
m_bindingEditor->showWidget(); : node.metaInfo().propertyTypeName(property.name());
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; m_bindingEditor->showWidget();
} m_bindingEditor->setBindingValue(property.expression());
} m_bindingEditor->setModelNode(node);
} m_bindingEditor->setBackendValueTypeName(typeName);
m_bindingEditor->prepareBindings();
m_bindingEditor->updateWindowName();
m_bindingIndex = index;
}); });
menu.exec(event->globalPos()); menu.exec(event->globalPos());
} }
@@ -218,51 +212,40 @@ void ConnectionViewWidget::contextMenuEvent(QContextMenuEvent *event)
case DynamicPropertiesTab: case DynamicPropertiesTab:
if (ui->dynamicPropertiesView != nullptr) { if (ui->dynamicPropertiesView != nullptr) {
QTableView *targetView = dynamicPropertiesTableView(); QTableView *targetView = dynamicPropertiesTableView();
QModelIndex index = targetView->indexAt(tablePos(targetView)).siblingAtColumn(DynamicPropertiesModel::PropertyValueRow); const QModelIndex index = targetView->indexAt(tablePos(targetView)).siblingAtColumn(DynamicPropertiesModel::PropertyValueRow);
if (!index.isValid()) if (!index.isValid())
return; return;
DynamicPropertiesModel *propertiesModel = qobject_cast<DynamicPropertiesModel *>(targetView->model());
QMenu menu(this); QMenu menu(this);
menu.addAction(tr("Open Binding Editor"), [&]() { menu.addAction(tr("Open Binding Editor"), [&]() {
if (index.isValid()) { AbstractProperty abstractProperty = propertiesModel->abstractPropertyForRow(index.row());
DynamicPropertiesModel *dynPropModel = qobject_cast<DynamicPropertiesModel*>(targetView->model()); if (!abstractProperty.isValid())
ModelNode node = dynPropModel->connectionView()->rootModelNode(); return;
AbstractProperty abProp = dynPropModel->abstractPropertyForRow(index.row()); const ModelNode node = abstractProperty.parentModelNode();
QString newExpression;
QString newExpression; if (abstractProperty.isBindingProperty())
newExpression = abstractProperty.toBindingProperty().expression();
else if (abstractProperty.isVariantProperty())
newExpression = abstractProperty.toVariantProperty().value().toString();
else
return;
if (abProp.isValid()) { m_dynamicEditor->showWidget();
if (abProp.isBindingProperty()) { m_dynamicEditor->setBindingValue(newExpression);
BindingProperty property = abProp.toBindingProperty(); m_dynamicEditor->setModelNode(node);
newExpression = property.expression(); m_dynamicEditor->setBackendValueTypeName(abstractProperty.dynamicTypeName());
} m_dynamicEditor->prepareBindings();
else if (abProp.isVariantProperty()) { m_dynamicEditor->updateWindowName();
VariantProperty property = abProp.toVariantProperty();
newExpression = property.value().toString();
}
else
return;
m_dynamicEditor->showWidget(); m_dynamicIndex = index;
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"), [&]() { menu.addAction(tr("Reset Property"), [&]() {
if (index.isValid()) { propertiesModel->resetProperty(propertiesModel->abstractPropertyForRow(index.row()).name());
DynamicPropertiesModel *propertiesModel = qobject_cast<DynamicPropertiesModel *>(dynamicPropertiesTableView()->model());
propertiesModel->resetProperty(propertiesModel->abstractPropertyForRow(index.row()).name());
}
}); });
menu.exec(event->globalPos()); menu.exec(event->globalPos());