forked from qt-creator/qt-creator
QmlDesigner: Add signal list dialog
* Add signal list dialog, delegate and view * Add context menu entry on items which have a trigger signal * Add specific model node operations * Add qml Connections util class * Add utility functions to signal handler property * Fix property processing in node meta info * Fix source code in connection editor and navigator Task-number: QDS-3138 Change-Id: I362ceef230efdb14f2050995b1693937e5e73c41 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
committed by
Henning Gründl
parent
306cadc643
commit
bebd70573e
@@ -497,6 +497,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
include/qmlmodelnodefacade.h
|
||||
include/qmlobjectnode.h
|
||||
include/qmlstate.h
|
||||
include/qmlconnections.h
|
||||
include/qmltimeline.h
|
||||
include/qmltimelinekeyframegroup.h
|
||||
include/removebasestateexception.h
|
||||
@@ -578,6 +579,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
model/qmlmodelnodefacade.cpp
|
||||
model/qmlobjectnode.cpp
|
||||
model/qmlstate.cpp
|
||||
model/qmlconnections.cpp
|
||||
model/qmltextgenerator.cpp model/qmltextgenerator.h
|
||||
model/qmltimeline.cpp
|
||||
model/qmltimelinekeyframegroup.cpp
|
||||
@@ -620,6 +622,9 @@ extend_qtc_plugin(QmlDesigner
|
||||
bindingeditordialog.cpp bindingeditordialog.h
|
||||
bindingeditorwidget.cpp bindingeditorwidget.h
|
||||
connectionvisitor.cpp connectionvisitor.h
|
||||
signallist.cpp signallist.h
|
||||
signallistdialog.cpp signallistdialog.h
|
||||
signallistdelegate.cpp signallistdelegate.h
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
|
@@ -5,6 +5,9 @@ HEADERS += $$PWD/actioneditordialog.h
|
||||
HEADERS += $$PWD/bindingeditordialog.h
|
||||
HEADERS += $$PWD/bindingeditorwidget.h
|
||||
HEADERS += $$PWD/connectionvisitor.h
|
||||
HEADERS += $$PWD/signallist.h
|
||||
HEADERS += $$PWD/signallistdialog.h
|
||||
HEADERS += $$PWD/signallistdelegate.h
|
||||
|
||||
SOURCES += $$PWD/bindingeditor.cpp
|
||||
SOURCES += $$PWD/actioneditor.cpp
|
||||
@@ -13,3 +16,6 @@ SOURCES += $$PWD/actioneditordialog.cpp
|
||||
SOURCES += $$PWD/bindingeditordialog.cpp
|
||||
SOURCES += $$PWD/bindingeditorwidget.cpp
|
||||
SOURCES += $$PWD/connectionvisitor.cpp
|
||||
SOURCES += $$PWD/signallist.cpp
|
||||
SOURCES += $$PWD/signallistdialog.cpp
|
||||
SOURCES += $$PWD/signallistdelegate.cpp
|
||||
|
328
src/plugins/qmldesigner/components/bindingeditor/signallist.cpp
Normal file
328
src/plugins/qmldesigner/components/bindingeditor/signallist.cpp
Normal file
@@ -0,0 +1,328 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "signallist.h"
|
||||
|
||||
#include "signallistdelegate.h"
|
||||
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <metainfo.h>
|
||||
|
||||
#include <variantproperty.h>
|
||||
#include <bindingproperty.h>
|
||||
#include <signalhandlerproperty.h>
|
||||
#include <qmldesignerconstants.h>
|
||||
#include <qmlitemnode.h>
|
||||
#include <nodeabstractproperty.h>
|
||||
|
||||
#include <QStandardItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QTableView>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
SignalListModel::SignalListModel(QObject *parent)
|
||||
: QStandardItemModel(0, 3, parent)
|
||||
{
|
||||
setHeaderData(TargetColumn, Qt::Horizontal, tr("Item ID"));
|
||||
setHeaderData(SignalColumn, Qt::Horizontal, tr("Signal"));
|
||||
setHeaderData(ButtonColumn, Qt::Horizontal, "");
|
||||
}
|
||||
|
||||
void SignalListModel::setConnected(int row, bool connected)
|
||||
{
|
||||
for (int col = 0; col < columnCount(); ++col) {
|
||||
QModelIndex idx = index(row, col);
|
||||
setData(idx, connected, ConnectedRole);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SignalListFilterModel::SignalListFilterModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool SignalListFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||
{
|
||||
QModelIndex targetIndex = sourceModel()->index(sourceRow, SignalListModel::TargetColumn, sourceParent);
|
||||
QModelIndex signalIndex = sourceModel()->index(sourceRow, SignalListModel::SignalColumn, sourceParent);
|
||||
|
||||
return (sourceModel()->data(targetIndex).toString().contains(filterRegExp())
|
||||
|| sourceModel()->data(signalIndex).toString().contains(filterRegExp()));
|
||||
}
|
||||
|
||||
|
||||
PropertyNameList SignalList::st_mouseSignals = { "clicked", "doubleClicked", "pressAndHold",
|
||||
"pressed", "released", "wheel" };
|
||||
|
||||
SignalList::SignalList(QObject *)
|
||||
: m_dialog(QPointer<SignalListDialog>())
|
||||
, m_model(new SignalListModel(this))
|
||||
, m_modelNode()
|
||||
{
|
||||
}
|
||||
|
||||
SignalList::~SignalList()
|
||||
{
|
||||
hideWidget();
|
||||
}
|
||||
|
||||
void SignalList::prepareDialog()
|
||||
{
|
||||
m_dialog = new SignalListDialog(Core::ICore::dialogParent());
|
||||
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
m_dialog->initialize(m_model);
|
||||
m_dialog->setWindowTitle(tr("Signal List for ") + m_modelNode.validId());
|
||||
|
||||
auto *delegate = static_cast<SignalListDelegate *>(m_dialog->tableView()->itemDelegate());
|
||||
connect(delegate, &SignalListDelegate::connectClicked, this, &SignalList::connectClicked);
|
||||
}
|
||||
|
||||
void SignalList::showWidget()
|
||||
{
|
||||
prepareDialog();
|
||||
m_dialog->show();
|
||||
m_dialog->raise();
|
||||
}
|
||||
|
||||
void SignalList::hideWidget()
|
||||
{
|
||||
if (m_dialog)
|
||||
m_dialog->close();
|
||||
|
||||
m_dialog = nullptr;
|
||||
}
|
||||
|
||||
SignalList* SignalList::showWidget(const ModelNode &modelNode)
|
||||
{
|
||||
auto signalList = new SignalList();
|
||||
signalList->setModelNode(modelNode);
|
||||
signalList->prepareSignals();
|
||||
signalList->showWidget();
|
||||
|
||||
connect(signalList->m_dialog, &QDialog::destroyed,
|
||||
[signalList]() { signalList->deleteLater(); } );
|
||||
|
||||
return signalList;
|
||||
}
|
||||
|
||||
void SignalList::setModelNode(const ModelNode &modelNode)
|
||||
{
|
||||
if (modelNode.isValid())
|
||||
m_modelNode = modelNode;
|
||||
}
|
||||
|
||||
void SignalList::prepareSignals()
|
||||
{
|
||||
if (!m_modelNode.isValid())
|
||||
return;
|
||||
|
||||
AbstractView *view = m_modelNode.view();
|
||||
QList<QmlConnections> connections = getAssociatedConnections(view->allModelNodes());
|
||||
|
||||
for (ModelNode &node : 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 (st_mouseSignals.contains(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 (st_mouseSignals.contains(signal))
|
||||
appendSignalToModel(connections, node, signal, property);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SignalList::connectClicked(const QModelIndex &modelIndex)
|
||||
{
|
||||
auto proxyModel = static_cast<const SignalListFilterModel *>(modelIndex.model());
|
||||
QModelIndex mappedModelIndex = proxyModel->mapToSource(modelIndex);
|
||||
bool connected = mappedModelIndex.data(SignalListModel::ConnectedRole).toBool();
|
||||
|
||||
if (!connected)
|
||||
addConnection(mappedModelIndex);
|
||||
else
|
||||
removeConnection(mappedModelIndex);
|
||||
}
|
||||
|
||||
void SignalList::appendSignalToModel(const QList<QmlConnections> &connections,
|
||||
ModelNode &node,
|
||||
const PropertyName &signal,
|
||||
const PropertyName &property)
|
||||
{
|
||||
QStandardItem *idItem = new QStandardItem();
|
||||
QString id(node.validId());
|
||||
if (!property.isEmpty())
|
||||
id += "." + QString::fromLatin1(property);
|
||||
|
||||
idItem->setData(id, Qt::DisplayRole);
|
||||
|
||||
QStandardItem *signalItem = new QStandardItem();
|
||||
signalItem->setData(signal, Qt::DisplayRole);
|
||||
|
||||
QStandardItem *buttonItem = new QStandardItem();
|
||||
|
||||
idItem->setData(false, SignalListModel::ConnectedRole);
|
||||
signalItem->setData(false, SignalListModel::ConnectedRole);
|
||||
buttonItem->setData(false, SignalListModel::ConnectedRole);
|
||||
|
||||
for (const QmlConnections &connection : connections) {
|
||||
if (connection.target() == id) {
|
||||
for (const SignalHandlerProperty &property : connection.signalProperties()) {
|
||||
auto signalWithoutPrefix = SignalHandlerProperty::prefixRemoved(property.name());
|
||||
if (signalWithoutPrefix == signal) {
|
||||
buttonItem->setData(connection.modelNode().internalId(),
|
||||
SignalListModel::ConnectionsInternalIdRole);
|
||||
|
||||
idItem->setData(true, SignalListModel::ConnectedRole);
|
||||
signalItem->setData(true, SignalListModel::ConnectedRole);
|
||||
buttonItem->setData(true, SignalListModel::ConnectedRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_model->appendRow({idItem, signalItem, buttonItem});
|
||||
}
|
||||
|
||||
void SignalList::addConnection(const QModelIndex &modelIndex)
|
||||
{
|
||||
const QModelIndex targetModelIndex = modelIndex.siblingAtColumn(SignalListModel::TargetColumn);
|
||||
const QModelIndex signalModelIndex = modelIndex.siblingAtColumn(SignalListModel::SignalColumn);
|
||||
const QModelIndex buttonModelIndex = modelIndex.siblingAtColumn(SignalListModel::ButtonColumn);
|
||||
const PropertyName signalName = m_model->data(signalModelIndex,
|
||||
Qt::DisplayRole).toByteArray();
|
||||
|
||||
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_CONNECTION_ADDED);
|
||||
|
||||
AbstractView *view = m_modelNode.view();
|
||||
const ModelNode rootModelNode = view->rootModelNode();
|
||||
|
||||
if (rootModelNode.isValid() && rootModelNode.metaInfo().isValid()) {
|
||||
NodeMetaInfo nodeMetaInfo = view->model()->metaInfo("QtQuick.Connections");
|
||||
if (nodeMetaInfo.isValid()) {
|
||||
view->executeInTransaction("ConnectionModel::addConnection", [=, &rootModelNode](){
|
||||
ModelNode newNode = view->createModelNode("QtQuick.Connections",
|
||||
nodeMetaInfo.majorVersion(),
|
||||
nodeMetaInfo.minorVersion());
|
||||
const QString source = m_modelNode.validId() + ".trigger()";
|
||||
|
||||
if (QmlItemNode::isValidQmlItemNode(m_modelNode))
|
||||
m_modelNode.nodeAbstractProperty("data").reparentHere(newNode);
|
||||
else
|
||||
rootModelNode.nodeAbstractProperty(rootModelNode.metaInfo().defaultPropertyName()).reparentHere(newNode);
|
||||
|
||||
const QString expression = m_model->data(targetModelIndex, Qt::DisplayRole).toString();
|
||||
newNode.bindingProperty("target").setExpression(expression);
|
||||
newNode.signalHandlerProperty(SignalHandlerProperty::prefixAdded(signalName)).setSource(source);
|
||||
|
||||
m_model->setConnected(modelIndex.row(), true);
|
||||
m_model->setData(buttonModelIndex, newNode.internalId(), SignalListModel::ConnectionsInternalIdRole);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SignalList::removeConnection(const QModelIndex &modelIndex)
|
||||
{
|
||||
const QModelIndex signalModelIndex = modelIndex.siblingAtColumn(SignalListModel::SignalColumn);
|
||||
const QModelIndex buttonModelIndex = modelIndex.siblingAtColumn(SignalListModel::ButtonColumn);
|
||||
const PropertyName signalName = m_model->data(signalModelIndex,
|
||||
Qt::DisplayRole).toByteArray();
|
||||
const int connectionInternalId = m_model->data(buttonModelIndex,
|
||||
SignalListModel::ConnectionsInternalIdRole).toInt();
|
||||
|
||||
AbstractView *view = m_modelNode.view();
|
||||
const ModelNode connectionModelNode = view->modelNodeForInternalId(connectionInternalId);
|
||||
SignalHandlerProperty targetSignal;
|
||||
|
||||
if (connectionModelNode.isValid())
|
||||
targetSignal = connectionModelNode.signalHandlerProperty(signalName);
|
||||
|
||||
ModelNode node = targetSignal.parentModelNode();
|
||||
if (node.isValid()) {
|
||||
view->executeInTransaction("ConnectionModel::removeConnection", [=, &node](){
|
||||
QList<SignalHandlerProperty> allSignals = node.signalProperties();
|
||||
if (allSignals.size() > 1) {
|
||||
const auto targetSignalWithPrefix = SignalHandlerProperty::prefixAdded(targetSignal.name());
|
||||
for (const SignalHandlerProperty &signal : allSignals)
|
||||
if (signal.name() == targetSignalWithPrefix)
|
||||
node.removeProperty(targetSignalWithPrefix);
|
||||
} else {
|
||||
node.destroy();
|
||||
}
|
||||
m_model->setConnected(modelIndex.row(), false);
|
||||
m_model->setData(buttonModelIndex, QVariant(), SignalListModel::ConnectionsInternalIdRole);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
QList<QmlConnections> SignalList::getAssociatedConnections(const QList<ModelNode> &nodes)
|
||||
{
|
||||
return Utils::transform<QList<QmlConnections>>(Utils::filtered(nodes, [this](const ModelNode &node) {
|
||||
const QmlConnections connection(node);
|
||||
if (!connection.isValid())
|
||||
return false;
|
||||
|
||||
for (const SignalHandlerProperty &property : connection.signalProperties()) {
|
||||
auto signalWithoutPrefix = SignalHandlerProperty::prefixRemoved(property.name());
|
||||
const QStringList sourceComponents = property.source().split(".");
|
||||
QString sourceId;
|
||||
QString sourceProperty;
|
||||
if (sourceComponents.size() > 1) {
|
||||
sourceId = sourceComponents[0];
|
||||
sourceProperty = sourceComponents[1];
|
||||
}
|
||||
|
||||
if (st_mouseSignals.contains(signalWithoutPrefix)
|
||||
&& sourceId == m_modelNode.validId()
|
||||
&& sourceProperty == "trigger()")
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}), [](const ModelNode &node) {
|
||||
return QmlConnections(node);
|
||||
});
|
||||
}
|
||||
|
||||
} // QmlDesigner namespace
|
108
src/plugins/qmldesigner/components/bindingeditor/signallist.h
Normal file
108
src/plugins/qmldesigner/components/bindingeditor/signallist.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 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 <bindingeditor/signallistdialog.h>
|
||||
#include <qmldesignercorelib_global.h>
|
||||
#include <modelnode.h>
|
||||
#include <qmlconnections.h>
|
||||
|
||||
#include <QtQml>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class SignalListModel : public QStandardItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ColumnRoles : unsigned int {
|
||||
TargetColumn = 0,
|
||||
SignalColumn = 1,
|
||||
ButtonColumn = 2
|
||||
};
|
||||
enum UserRoles : unsigned int {
|
||||
ConnectionsInternalIdRole = Qt::UserRole + 1,
|
||||
ConnectedRole
|
||||
};
|
||||
|
||||
SignalListModel(QObject *parent = nullptr);
|
||||
|
||||
void setConnected(int row, bool connected);
|
||||
};
|
||||
|
||||
class SignalListFilterModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SignalListFilterModel(QObject *parent = nullptr);
|
||||
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
};
|
||||
|
||||
class SignalList : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SignalList(QObject *parent = nullptr);
|
||||
~SignalList();
|
||||
|
||||
static SignalList* showWidget(const ModelNode &modelNode);
|
||||
|
||||
void setModelNode(const ModelNode &modelNode);
|
||||
void connectClicked(const QModelIndex &modelIndex);
|
||||
|
||||
private:
|
||||
void prepareDialog();
|
||||
void showWidget();
|
||||
void hideWidget();
|
||||
|
||||
void prepareSignals();
|
||||
|
||||
void appendSignalToModel(const QList<QmlConnections> &connections,
|
||||
ModelNode &node,
|
||||
const PropertyName &signal,
|
||||
const PropertyName &property = "");
|
||||
|
||||
void addConnection(const QModelIndex &modelIndex);
|
||||
void removeConnection(const QModelIndex &modelIndex);
|
||||
|
||||
QList<QmlConnections> getAssociatedConnections(const QList<ModelNode> &nodes);
|
||||
|
||||
private:
|
||||
static PropertyNameList st_mouseSignals;
|
||||
|
||||
QPointer<SignalListDialog> m_dialog;
|
||||
SignalListModel *m_model;
|
||||
ModelNode m_modelNode;
|
||||
};
|
||||
|
||||
} // QmlDesigner namespace
|
@@ -0,0 +1,95 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "signallistdelegate.h"
|
||||
|
||||
#include "signallist.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionButton>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
SignalListDelegate::SignalListDelegate(QObject *parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
{}
|
||||
|
||||
QWidget *SignalListDelegate::createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
if (index.column() == SignalListModel::ButtonColumn)
|
||||
return nullptr;
|
||||
|
||||
return QStyledItemDelegate::createEditor(parent, option, index);
|
||||
}
|
||||
|
||||
QRect connectButtonRect(const QStyleOptionViewItem &option)
|
||||
{
|
||||
return option.rect.adjusted(3, 3, -3, -3);
|
||||
}
|
||||
|
||||
void SignalListDelegate::paint(QPainter *painter,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
const bool connected = index.data(SignalListModel::ConnectedRole).toBool();
|
||||
if (connected) {
|
||||
QStyleOptionViewItem opt(option);
|
||||
opt.state = QStyle::State_Selected;
|
||||
QStyledItemDelegate::paint(painter, opt, index);
|
||||
if (index.column() != SignalListModel::ButtonColumn)
|
||||
return;
|
||||
}
|
||||
if (index.column() == SignalListModel::ButtonColumn) {
|
||||
QStyleOptionButton button;
|
||||
button.rect = connectButtonRect(option);
|
||||
button.text = connected ? tr("Release") : tr("Connect");
|
||||
button.state = QStyle::State_Enabled;
|
||||
QApplication::style()->drawControl(QStyle::CE_PushButton, &button, painter);
|
||||
return;
|
||||
}
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
}
|
||||
|
||||
bool SignalListDelegate::editorEvent(QEvent *event,
|
||||
QAbstractItemModel *model,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index)
|
||||
{
|
||||
Q_UNUSED(model)
|
||||
|
||||
if (index.column() == SignalListModel::ButtonColumn
|
||||
&& event->type() == QEvent::MouseButtonRelease) {
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
if (connectButtonRect(option).contains(mouseEvent->pos()))
|
||||
emit connectClicked(index);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // QmlDesigner namespace
|
@@ -0,0 +1,54 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 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 <QStyledItemDelegate>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class SignalListDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
signals:
|
||||
void connectClicked(const QModelIndex &modelIndex) const;
|
||||
|
||||
public:
|
||||
SignalListDelegate(QObject *parent = nullptr);
|
||||
|
||||
QWidget *createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
void paint(QPainter *painter,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
bool editorEvent(QEvent *event,
|
||||
QAbstractItemModel *model,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) override;
|
||||
};
|
||||
|
||||
} // QmlDesigner namespace
|
@@ -0,0 +1,132 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "signallistdialog.h"
|
||||
|
||||
#include "signallist.h"
|
||||
#include "signallistdelegate.h"
|
||||
|
||||
#include <qmldesignerplugin.h>
|
||||
|
||||
#include <theme.h>
|
||||
#include <utils/fancylineedit.h>
|
||||
#include <utils/stylehelper.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QStandardItemModel>
|
||||
#include <QPainter>
|
||||
#include <QTableView>
|
||||
#include <QHeaderView>
|
||||
#include <QVBoxLayout>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
QWidget *createFilterWidget(Utils::FancyLineEdit *lineEdit)
|
||||
{
|
||||
const QString unicode = Theme::getIconUnicode(Theme::Icon::search);
|
||||
const QString fontName = "qtds_propertyIconFont.ttf";
|
||||
QIcon icon = Utils::StyleHelper::getIconFromIconFont(fontName, unicode, 28, 28);
|
||||
auto *label = new QLabel;
|
||||
label->setPixmap(icon.pixmap(QSize(24, 24)));
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
lineEdit->setPlaceholderText(QObject::tr("<Filter>", "Library search input hint text"));
|
||||
lineEdit->setDragEnabled(false);
|
||||
lineEdit->setMinimumWidth(75);
|
||||
lineEdit->setTextMargins(0, 0, 20, 0);
|
||||
lineEdit->setFiltering(true);
|
||||
auto *box = new QHBoxLayout;
|
||||
box->addWidget(label);
|
||||
box->addWidget(lineEdit);
|
||||
auto *widget = new QWidget;
|
||||
widget->setLayout(box);
|
||||
return widget;
|
||||
}
|
||||
|
||||
void modifyPalette(QTableView *view, const QColor &selectionColor)
|
||||
{
|
||||
QPalette p = view->palette();
|
||||
p.setColor(QPalette::AlternateBase, p.color(QPalette::Base).lighter(120));
|
||||
p.setColor(QPalette::Highlight, selectionColor);
|
||||
view->setPalette(p);
|
||||
view->setAlternatingRowColors(true);
|
||||
}
|
||||
|
||||
|
||||
SignalListDialog::SignalListDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_table(new QTableView())
|
||||
, m_searchLine(new Utils::FancyLineEdit())
|
||||
{
|
||||
auto *signalListDelegate = new SignalListDelegate(m_table);
|
||||
m_table->setItemDelegate(signalListDelegate);
|
||||
m_table->setFocusPolicy(Qt::NoFocus);
|
||||
m_table->setSelectionMode(QAbstractItemView::NoSelection);
|
||||
m_table->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
m_table->verticalHeader()->hide();
|
||||
|
||||
modifyPalette(m_table, QColor("#d87b00"));
|
||||
|
||||
auto *layout = new QVBoxLayout;
|
||||
layout->addWidget(createFilterWidget(m_searchLine));
|
||||
layout->addWidget(m_table);
|
||||
setLayout(layout);
|
||||
|
||||
setWindowFlag(Qt::Tool, true);
|
||||
setModal(true);
|
||||
resize(600, 480);
|
||||
}
|
||||
|
||||
SignalListDialog::~SignalListDialog()
|
||||
{
|
||||
}
|
||||
|
||||
void SignalListDialog::initialize(QStandardItemModel *model)
|
||||
{
|
||||
m_searchLine->clear();
|
||||
|
||||
auto *proxyModel = new SignalListFilterModel(this);
|
||||
proxyModel->setSourceModel(model);
|
||||
m_table->setModel(proxyModel);
|
||||
|
||||
QHeaderView *header = m_table->horizontalHeader();
|
||||
header->setSectionResizeMode(SignalListModel::TargetColumn, QHeaderView::Stretch);
|
||||
header->setSectionResizeMode(SignalListModel::SignalColumn, QHeaderView::Stretch);
|
||||
header->resizeSection(SignalListModel::ButtonColumn, 120);
|
||||
header->setStretchLastSection(false);
|
||||
|
||||
auto eventFilterFun = [this](const QString &str) {
|
||||
if (auto *fm = qobject_cast<SignalListFilterModel *>(m_table->model()))
|
||||
fm->setFilterFixedString(str);
|
||||
};
|
||||
connect(m_searchLine, &Utils::FancyLineEdit::filterChanged, eventFilterFun);
|
||||
}
|
||||
|
||||
QTableView *SignalListDialog::tableView() const
|
||||
{
|
||||
return m_table;
|
||||
}
|
||||
|
||||
} // QmlDesigner namespace
|
@@ -0,0 +1,58 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 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 <QDialog>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QStandardItemModel;
|
||||
class QTableView;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Utils {
|
||||
class FancyLineEdit;
|
||||
}
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class SignalListDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SignalListDialog(QWidget *parent = nullptr);
|
||||
~SignalListDialog() override;
|
||||
|
||||
void initialize(QStandardItemModel *model);
|
||||
|
||||
QTableView *tableView() const;
|
||||
|
||||
private:
|
||||
QTableView *m_table;
|
||||
Utils::FancyLineEdit *m_searchLine;
|
||||
};
|
||||
|
||||
} // QmlDesigner namespace
|
@@ -89,6 +89,8 @@ const char fitRootToScreenCommandId[] = "FitRootToScreen";
|
||||
const char fitSelectionToScreenCommandId[] = "FitSelectionToScreen";
|
||||
const char editAnnotationCommandId[] = "EditAnnotation";
|
||||
|
||||
const char openSignalDialogCommandId[] = "OpenSignalDialog";
|
||||
|
||||
const char selectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Selection");
|
||||
const char flowConnectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Connect");
|
||||
const char selectEffectDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select Effect");
|
||||
@@ -128,6 +130,8 @@ const char addSignalHandlerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContext
|
||||
const char moveToComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Move Component into Separate File");
|
||||
const char editAnnotationDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Annotation");
|
||||
|
||||
const char openSignalDialogDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Open Signal Dialog");
|
||||
|
||||
const char setIdDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Set Id");
|
||||
|
||||
const char resetZDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset z Property");
|
||||
|
@@ -564,6 +564,7 @@ const char yProperty[] = "y";
|
||||
const char zProperty[] = "z";
|
||||
const char widthProperty[] = "width";
|
||||
const char heightProperty[] = "height";
|
||||
const char triggerSlot[] = "trigger";
|
||||
|
||||
using namespace SelectionContextFunctors;
|
||||
|
||||
@@ -644,6 +645,14 @@ bool selectionNotEmptyAndHasXorYProperty(const SelectionContext &context)
|
||||
&& selectionHasProperty1or2(context, xProperty, yProperty);
|
||||
}
|
||||
|
||||
bool singleSelectionAndHasSlotTrigger(const SelectionContext &context)
|
||||
{
|
||||
if (!singleSelection(context))
|
||||
return false;
|
||||
|
||||
return selectionHasSlot(context, triggerSlot);
|
||||
}
|
||||
|
||||
bool singleSelectionAndInQtQuickLayout(const SelectionContext &context)
|
||||
{
|
||||
if (!singleSelection(context))
|
||||
@@ -1384,6 +1393,16 @@ void DesignerActionManager::createDefaultDesignerActions()
|
||||
addDesignerAction(new ChangeStyleAction());
|
||||
|
||||
addDesignerAction(new EditListModelAction);
|
||||
|
||||
addDesignerAction(new ModelNodeContextMenuAction(
|
||||
openSignalDialogCommandId,
|
||||
openSignalDialogDisplayName,
|
||||
{},
|
||||
rootCategory,
|
||||
QKeySequence(),
|
||||
66,
|
||||
&openSignalDialog,
|
||||
&singleSelectionAndHasSlotTrigger));
|
||||
}
|
||||
|
||||
void DesignerActionManager::createDefaultAddResourceHandler()
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include "abstractactiongroup.h"
|
||||
#include "qmlitemnode.h"
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <nodemetainfo.h>
|
||||
|
||||
#include <coreplugin/actionmanager/command.h>
|
||||
|
||||
@@ -80,12 +81,24 @@ inline bool singleSelectionNotRoot(const SelectionContext &selectionState)
|
||||
|
||||
inline bool selectionHasProperty(const SelectionContext &selectionState, const char *property)
|
||||
{
|
||||
foreach (const ModelNode &modelNode, selectionState.selectedModelNodes())
|
||||
for (const ModelNode &modelNode : selectionState.selectedModelNodes())
|
||||
if (modelNode.hasProperty(PropertyName(property)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool selectionHasSlot(const SelectionContext &selectionState, const char *property)
|
||||
{
|
||||
for (const ModelNode &modelNode : selectionState.selectedModelNodes()) {
|
||||
for (const PropertyName &slotName : modelNode.metaInfo().slotNames()) {
|
||||
if (slotName == property)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool singleSelectedItem(const SelectionContext &selectionState)
|
||||
{
|
||||
QmlItemNode itemNode(selectionState.currentSingleSelectedNode());
|
||||
@@ -94,7 +107,6 @@ inline bool singleSelectedItem(const SelectionContext &selectionState)
|
||||
|
||||
bool selectionHasSameParent(const SelectionContext &selectionState);
|
||||
bool selectionIsComponent(const SelectionContext &selectionState);
|
||||
bool selectionIsComponent(const SelectionContext &selectionState);
|
||||
bool singleSelectionItemIsAnchored(const SelectionContext &selectionState);
|
||||
bool singleSelectionItemIsNotAnchored(const SelectionContext &selectionState);
|
||||
|
||||
|
@@ -87,6 +87,8 @@
|
||||
#include <functional>
|
||||
#include <cmath>
|
||||
|
||||
#include <bindingeditor/signallist.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
const PropertyName auxDataString("anchors_");
|
||||
@@ -1550,6 +1552,14 @@ QVariant previewImageDataForImageNode(const ModelNode &modelNode)
|
||||
return {};
|
||||
}
|
||||
|
||||
void openSignalDialog(const SelectionContext &selectionContext)
|
||||
{
|
||||
if (!selectionContext.view() || !selectionContext.hasSingleSelectedModelNode())
|
||||
return;
|
||||
|
||||
SignalList::showWidget(selectionContext.currentSingleSelectedNode());
|
||||
}
|
||||
|
||||
} // namespace ModelNodeOperations
|
||||
|
||||
} //QmlDesigner
|
||||
|
@@ -86,6 +86,8 @@ void mergeWithTemplate(const SelectionContext &selectionContext);
|
||||
void removeGroup(const SelectionContext &selectionContext);
|
||||
void editAnnotation(const SelectionContext &selectionContext);
|
||||
|
||||
void openSignalDialog(const SelectionContext &selectionContext);
|
||||
|
||||
// ModelNodePreviewImageOperations
|
||||
QVariant previewImageDataForGenericNode(const ModelNode &modelNode);
|
||||
QVariant previewImageDataForImageNode(const ModelNode &modelNode);
|
||||
|
@@ -49,9 +49,9 @@ namespace {
|
||||
QStringList propertyNameListToStringList(const QmlDesigner::PropertyNameList &propertyNameList)
|
||||
{
|
||||
QStringList stringList;
|
||||
for (const QmlDesigner::PropertyName &propertyName : propertyNameList) {
|
||||
for (const QmlDesigner::PropertyName &propertyName : propertyNameList)
|
||||
stringList << QString::fromUtf8(propertyName);
|
||||
}
|
||||
|
||||
stringList.removeDuplicates();
|
||||
return stringList;
|
||||
}
|
||||
|
@@ -133,8 +133,6 @@ static QRect drawText(QPainter *painter,
|
||||
int iconOffset)
|
||||
{
|
||||
QString displayString = modelIndex.data(Qt::DisplayRole).toString();
|
||||
QPoint displayStringOffset;
|
||||
int width = 0;
|
||||
|
||||
// Check text length does not exceed available space
|
||||
const int extraSpace = 12 + iconOffset;
|
||||
@@ -142,10 +140,8 @@ static QRect drawText(QPainter *painter,
|
||||
displayString = styleOption.fontMetrics.elidedText(displayString,
|
||||
Qt::ElideMiddle,
|
||||
styleOption.rect.width() - extraSpace);
|
||||
displayStringOffset = QPoint(5 + iconOffset, -5 - delegateMargin);
|
||||
|
||||
width = styleOption.fontMetrics.horizontalAdvance(displayString);
|
||||
|
||||
const QPoint displayStringOffset = QPoint(5 + iconOffset, -5 - delegateMargin);
|
||||
const int width = styleOption.fontMetrics.horizontalAdvance(displayString);
|
||||
const QPoint textPosition = styleOption.rect.bottomLeft() + displayStringOffset;
|
||||
painter->drawText(textPosition, displayString);
|
||||
|
||||
|
@@ -69,6 +69,7 @@ SOURCES += $$PWD/model/abstractview.cpp \
|
||||
$$PWD/model/qmlmodelnodefacade.cpp \
|
||||
$$PWD/model/qmlobjectnode.cpp \
|
||||
$$PWD/model/qmlanchors.cpp \
|
||||
$$PWD/model/qmlconnections.cpp \
|
||||
$$PWD/rewritertransaction.cpp \
|
||||
$$PWD/model/rewriteaction.cpp \
|
||||
$$PWD/model/modelnodepositionstorage.cpp \
|
||||
@@ -151,6 +152,7 @@ HEADERS += $$PWD/include/qmldesignercorelib_global.h \
|
||||
$$PWD/include/forwardview.h \
|
||||
$$PWD/include/qmlobjectnode.h \
|
||||
$$PWD/include/qmlanchors.h \
|
||||
$$PWD/include/qmlconnections.h \
|
||||
$$PWD/rewritertransaction.h \
|
||||
$$PWD/model/rewriteaction.h \
|
||||
$$PWD/include/modelnodepositionstorage.h \
|
||||
|
@@ -0,0 +1,57 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 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 "qmlmodelnodefacade.h"
|
||||
|
||||
#include <signalhandlerproperty.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class QMLDESIGNERCORE_EXPORT QmlConnections : public QmlModelNodeFacade
|
||||
{
|
||||
friend class StatesEditorView;
|
||||
|
||||
public:
|
||||
QmlConnections();
|
||||
QmlConnections(const ModelNode &modelNode);
|
||||
|
||||
bool isValid() const override;
|
||||
static bool isValidQmlConnections(const ModelNode &modelNode);
|
||||
void destroy();
|
||||
|
||||
QString target() const;
|
||||
void setTarget(const QString &target);
|
||||
|
||||
ModelNode getTargetNode() const;
|
||||
|
||||
QList<SignalHandlerProperty> signalProperties() const;
|
||||
|
||||
static ModelNode createQmlConnections(AbstractView *view);
|
||||
};
|
||||
|
||||
} //QmlDesigner
|
@@ -43,6 +43,9 @@ public:
|
||||
SignalHandlerProperty();
|
||||
SignalHandlerProperty(const SignalHandlerProperty &property, AbstractView *view);
|
||||
|
||||
static PropertyName prefixAdded(const PropertyName &propertyName);
|
||||
static PropertyName prefixRemoved(const PropertyName &propertyName);
|
||||
|
||||
protected:
|
||||
SignalHandlerProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view);
|
||||
};
|
||||
|
@@ -82,7 +82,7 @@ using PropertyInfo = QPair<PropertyName, TypeName>;
|
||||
|
||||
QVector<PropertyInfo> getObjectTypes(const ObjectValue *ov, const ContextPtr &context, bool local = false, int rec = 0);
|
||||
|
||||
static TypeName resolveTypeName(const ASTPropertyReference *ref, const ContextPtr &context, QVector<PropertyInfo> &dotProperties)
|
||||
static TypeName resolveTypeName(const ASTPropertyReference *ref, const ContextPtr &context, QVector<PropertyInfo> &dotProperties)
|
||||
{
|
||||
TypeName type = "unknown";
|
||||
|
||||
@@ -295,7 +295,7 @@ public:
|
||||
const TypeName type = resolveTypeName(ref, m_context, dotProperties);
|
||||
m_properties.append({propertyName, type});
|
||||
if (!dotProperties.isEmpty()) {
|
||||
foreach (const PropertyInfo &propertyInfo, dotProperties) {
|
||||
for (const PropertyInfo &propertyInfo : qAsConst(dotProperties)) {
|
||||
PropertyName dotName = propertyInfo.first;
|
||||
TypeName type = propertyInfo.second;
|
||||
dotName = propertyName + '.' + dotName;
|
||||
@@ -303,7 +303,6 @@ public:
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if (const CppComponentValue * cppComponentValue = value_cast<CppComponentValue>(value)) {
|
||||
TypeName qualifiedTypeName = qualifiedTypeNameForContext(cppComponentValue,
|
||||
m_context->viewerContext(), *m_context->snapshot().importDependencies()).toUtf8();
|
||||
@@ -311,13 +310,13 @@ public:
|
||||
} else {
|
||||
TypeId typeId;
|
||||
TypeName typeName = typeId(value).toUtf8();
|
||||
if (typeName == "number") {
|
||||
if (value->asIntValue()) {
|
||||
typeName = "int";
|
||||
} else {
|
||||
typeName = "real";
|
||||
}
|
||||
}
|
||||
|
||||
if (typeName == "Function")
|
||||
return processSlot(name, value);
|
||||
|
||||
if (typeName == "number")
|
||||
typeName = value->asIntValue() ? "int" : "real";
|
||||
|
||||
m_properties.append({propertyName, typeName});
|
||||
}
|
||||
}
|
||||
@@ -488,7 +487,7 @@ PropertyNameList getSignals(const ObjectValue *objectValue, const ContextPtr &co
|
||||
QList<const ObjectValue *> objects = prototypeIterator.all();
|
||||
|
||||
if (!local) {
|
||||
foreach (const ObjectValue *prototype, objects)
|
||||
for (const ObjectValue *prototype : objects)
|
||||
signalList.append(getSignals(prototype, context, true));
|
||||
}
|
||||
|
||||
@@ -507,6 +506,9 @@ PropertyNameList getSlots(const ObjectValue *objectValue, const ContextPtr &cont
|
||||
PropertyMemberProcessor processor(context);
|
||||
objectValue->processMembers(&processor);
|
||||
|
||||
if (const ASTObjectValue *astObjectValue = objectValue->asAstObjectValue())
|
||||
astObjectValue->processMembers(&processor);
|
||||
|
||||
slotList.append(processor.slotList());
|
||||
|
||||
PrototypeIterator prototypeIterator(objectValue, context);
|
||||
@@ -534,6 +536,7 @@ QVector<PropertyInfo> getObjectTypes(const ObjectValue *objectValue, const Conte
|
||||
|
||||
PropertyMemberProcessor processor(context);
|
||||
objectValue->processMembers(&processor);
|
||||
|
||||
const auto props = processor.properties();
|
||||
|
||||
for (const PropertyInfo &property : props) {
|
||||
|
130
src/plugins/qmldesigner/designercore/model/qmlconnections.cpp
Normal file
130
src/plugins/qmldesigner/designercore/model/qmlconnections.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmlconnections.h"
|
||||
|
||||
#include <metainfo.h>
|
||||
#include <abstractview.h>
|
||||
#include <bindingproperty.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
QmlConnections::QmlConnections()
|
||||
{
|
||||
}
|
||||
|
||||
QmlConnections::QmlConnections(const ModelNode &modelNode)
|
||||
: QmlModelNodeFacade(modelNode)
|
||||
{
|
||||
}
|
||||
|
||||
bool QmlConnections::isValid() const
|
||||
{
|
||||
return isValidQmlConnections(modelNode());
|
||||
}
|
||||
|
||||
bool QmlConnections::isValidQmlConnections(const ModelNode &modelNode)
|
||||
{
|
||||
return isValidQmlModelNodeFacade(modelNode)
|
||||
&& modelNode.metaInfo().isValid()
|
||||
&& (modelNode.type() == "Connections"
|
||||
|| modelNode.type() == "QtQuick.Connections"
|
||||
|| modelNode.type() == "Qt.Connections"
|
||||
|| modelNode.type() == "QtQml.Connections");
|
||||
}
|
||||
|
||||
/*!
|
||||
Removes connections node.
|
||||
*/
|
||||
void QmlConnections::destroy()
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
modelNode().destroy();
|
||||
}
|
||||
|
||||
QString QmlConnections::target() const
|
||||
{
|
||||
if (modelNode().isValid()) {
|
||||
const BindingProperty bindingproperty = modelNode().bindingProperty("target");
|
||||
if (bindingproperty.isValid())
|
||||
return bindingproperty.expression();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
void QmlConnections::setTarget(const QString &target)
|
||||
{
|
||||
modelNode().bindingProperty("target").setExpression(target);
|
||||
}
|
||||
|
||||
ModelNode QmlConnections::getTargetNode() const
|
||||
{
|
||||
ModelNode result;
|
||||
|
||||
if (!modelNode().isValid())
|
||||
return result;
|
||||
|
||||
const BindingProperty bindingProperty = modelNode().bindingProperty("target");
|
||||
const QString bindExpression = bindingProperty.expression();
|
||||
|
||||
if (bindingProperty.isValid()) {
|
||||
AbstractView *view = modelNode().view();
|
||||
if (bindExpression.contains(".")) {
|
||||
QStringList substr = bindExpression.split(".");
|
||||
const QString itemId = substr.constFirst();
|
||||
if (substr.size() > 1) {
|
||||
const ModelNode aliasParent = view->modelNodeForId(itemId);
|
||||
substr.removeFirst(); // remove id, only alias pieces left
|
||||
const QString aliasBody = substr.join(".");
|
||||
if (aliasParent.isValid() && aliasParent.hasBindingProperty(aliasBody.toUtf8())) {
|
||||
const BindingProperty binding = aliasParent.bindingProperty(aliasBody.toUtf8());
|
||||
if (binding.isValid() && view->hasId(binding.expression()))
|
||||
result = view->modelNodeForId(binding.expression());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = view->modelNodeForId(bindExpression);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<SignalHandlerProperty> QmlConnections::signalProperties() const
|
||||
{
|
||||
return modelNode().signalProperties();
|
||||
}
|
||||
|
||||
ModelNode QmlConnections::createQmlConnections(AbstractView *view)
|
||||
{
|
||||
NodeMetaInfo nodeMetaInfo = view->model()->metaInfo("QtQuick.Connections");
|
||||
return view->createModelNode("QtQuick.Connections",
|
||||
nodeMetaInfo.majorVersion(),
|
||||
nodeMetaInfo.minorVersion());
|
||||
}
|
||||
|
||||
} // QmlDesigner
|
@@ -40,13 +40,11 @@ SignalHandlerProperty::SignalHandlerProperty(const SignalHandlerProperty &proper
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SignalHandlerProperty::SignalHandlerProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view)
|
||||
: AbstractProperty(propertyName, internalNode, model, view)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void SignalHandlerProperty::setSource(const QString &source)
|
||||
{
|
||||
Internal::WriteLocker locker(model());
|
||||
@@ -83,4 +81,30 @@ QString SignalHandlerProperty::source() const
|
||||
return QString();
|
||||
}
|
||||
|
||||
PropertyName SignalHandlerProperty::prefixAdded(const PropertyName &propertyName)
|
||||
{
|
||||
QString nameAsString = QString::fromUtf8(propertyName);
|
||||
if (nameAsString.startsWith("on"))
|
||||
return propertyName;
|
||||
|
||||
QChar firstChar = nameAsString.at(0).toUpper();
|
||||
nameAsString[0] = firstChar;
|
||||
nameAsString.prepend("on");
|
||||
|
||||
return nameAsString.toLatin1();
|
||||
}
|
||||
|
||||
PropertyName SignalHandlerProperty::prefixRemoved(const PropertyName &propertyName)
|
||||
{
|
||||
QString nameAsString = QString::fromUtf8(propertyName);
|
||||
if (!nameAsString.startsWith("on"))
|
||||
return propertyName;
|
||||
|
||||
nameAsString.remove(0, 2);
|
||||
QChar firstChar = nameAsString.at(0).toLower();
|
||||
nameAsString[0] = firstChar;
|
||||
|
||||
return nameAsString.toLatin1();
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -302,6 +302,7 @@ Project {
|
||||
"include/qmlmodelnodefacade.h",
|
||||
"include/qmlobjectnode.h",
|
||||
"include/qmlstate.h",
|
||||
"include/qmlconnections.h",
|
||||
"include/removebasestateexception.h",
|
||||
"include/documentmessage.h",
|
||||
"include/rewriterview.h",
|
||||
@@ -391,6 +392,7 @@ Project {
|
||||
"model/qmlmodelnodefacade.cpp",
|
||||
"model/qmlobjectnode.cpp",
|
||||
"model/qmlstate.cpp",
|
||||
"model/qmlconnections.cpp",
|
||||
"model/qmltextgenerator.cpp",
|
||||
"model/qmltextgenerator.h",
|
||||
"model/rewriteaction.cpp",
|
||||
@@ -739,6 +741,12 @@ Project {
|
||||
"bindingeditor/bindingeditorwidget.h",
|
||||
"bindingeditor/connectionvisitor.cpp",
|
||||
"bindingeditor/connectionvisitor.h",
|
||||
"bindingeditor/signallist.cpp",
|
||||
"bindingeditor/signallist.h",
|
||||
"bindingeditor/signallistdialog.cpp",
|
||||
"bindingeditor/signallistdialog.h",
|
||||
"bindingeditor/signallistdelegate.cpp",
|
||||
"bindingeditor/signallistdelegate.h",
|
||||
"colortool/colortool.cpp",
|
||||
"colortool/colortool.h",
|
||||
"connectioneditor/addnewbackenddialog.h",
|
||||
|
Reference in New Issue
Block a user