Make the eventlisplugin a part of the qmldesigner plugin

The eventlistplugin enables the user to create custom events (QDS-1760).
It provides a dialog to create and remove a custom event or modify its
properties (id, description, shortcut) and a dialog to connect an
event to one of the flowsignals in order to trigger a transition or
a state change.

Task-number: QDS-4300
Change-Id: Ifffa81650d4898b34a65d7901bcb0df95cc397af
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Knud Dollereder
2021-06-16 13:10:42 +02:00
parent 0c766cf3c5
commit 1a402984da
44 changed files with 2998 additions and 9 deletions

View File

@@ -780,7 +780,27 @@ extend_qtc_plugin(QmlDesigner
detail/treeitemdelegate.cpp detail/treeitemdelegate.h
detail/treemodel.cpp detail/treemodel.h
detail/treeview.cpp detail/treeview.h
detail/utils.cpp detail/utils.h
detail/curveeditorutils.cpp detail/curveeditorutils.h
)
extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/eventlist
SOURCES
eventlistplugin.qrc
eventlistpluginview.cpp eventlistpluginview.h
assigneventdialog.cpp assigneventdialog.h
eventlist.cpp eventlist.h
eventlistactions.cpp eventlistactions.h
eventlistdelegate.cpp eventlistdelegate.h
eventlistdialog.cpp eventlistdialog.h
eventlistview.cpp eventlistview.h
eventlistutils.cpp eventlistutils.h
filterlinewidget.cpp filterlinewidget.h
nodelistdelegate.cpp nodelistdelegate.h
nodelistview.cpp nodelistview.h
nodeselectionmodel.cpp nodeselectionmodel.h
connectsignaldialog.cpp connectsignaldialog.h
shortcutwidget.cpp shortcutwidget.h
)
# Do the file comparison at the end, due to all the extend_qtc_plugin calls

View File

@@ -46,6 +46,7 @@ const char flowEffectCategory[] = "FlowEffect";
const char flowConnectionCategory[] = "FlowConnection";
const char stackedContainerCategory[] = "StackedContainer";
const char genericToolBarCategory[] = "GenericToolBar";
const char eventListCategory[] = "QmlEventList";
const char toFrontCommandId[] = "ToFront";
const char toBackCommandId[] = "ToBack";
@@ -209,6 +210,7 @@ const int priorityGroupCategory = 140;
const int priorityPositionCategory = 130;
const int priorityLayoutCategory = 120;
const int priorityStackedContainerCategory = priorityLayoutCategory;
const int priorityEventListCategory = 105;
const int priorityTopLevelSeperator = 100;
const int priorityCustomActions = 80;
const int priorityRefactoring = 60;

View File

@@ -25,7 +25,7 @@
#include "animationcurve.h"
#include "curvesegment.h"
#include "detail/utils.h"
#include "detail/curveeditorutils.h"
#include <QEasingCurve>
#include <QLineF>

View File

@@ -45,7 +45,7 @@ SOURCES += \
$$PWD/detail/treeitemdelegate.cpp \
$$PWD/detail/treemodel.cpp \
$$PWD/detail/treeview.cpp \
$$PWD/detail/utils.cpp \
$$PWD/detail/curveeditorutils.cpp \
$$PWD/detail/axis.cpp \
$$PWD/keyframe.cpp \
$$PWD/treeitem.cpp

View File

@@ -24,7 +24,7 @@
****************************************************************************/
#include "curvesegment.h"
#include "detail/utils.h"
#include "detail/curveeditorutils.h"
#include <utils/qtcassert.h>
#include <QEasingCurve>

View File

@@ -26,7 +26,7 @@
#include "animationcurve.h"
#include "graphicsscene.h"
#include "keyframeitem.h"
#include "utils.h"
#include "curveeditorutils.h"
#include <QEasingCurve>
#include <QPainter>

View File

@@ -29,7 +29,7 @@
#include "curveitem.h"
#include "navigation2d.h"
#include "treeitem.h"
#include "utils.h"
#include "curveeditorutils.h"
#include <theme.h>
#include <utils/fileutils.h>

View File

@@ -27,7 +27,7 @@
#include "curvesegment.h"
#include "graphicsscene.h"
#include "keyframeitem.h"
#include "utils.h"
#include "curveeditorutils.h"
#include <QPainter>

View File

@@ -0,0 +1,184 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#include "assigneventdialog.h"
#include "eventlist.h"
#include "eventlistdelegate.h"
#include "eventlistview.h"
#include "filterlinewidget.h"
#include "nodelistdelegate.h"
#include "nodelistview.h"
#include "nodeselectionmodel.h"
#include "eventlistutils.h"
#include <QHBoxLayout>
#include <QHeaderView>
#include <QMessageBox>
#include <QSortFilterProxyModel>
#include <QSplitter>
#include <QTableView>
#include <QVBoxLayout>
namespace QmlDesigner {
AssignEventDialog::AssignEventDialog(QWidget *parent)
: QDialog(parent)
, m_nodeTable(new QTableView)
, m_eventTable(new QTableView)
, m_nodeLine(new FilterLineWidget())
, m_eventLine(new FilterLineWidget())
{
setWindowFlag(Qt::Tool, true);
setModal(true);
auto *nodeFilterModel = new QSortFilterProxyModel;
auto *nodeListDelegate = new NodeListDelegate(m_nodeTable);
auto *nodeSelectionModel = new NodeSelectionModel(nodeFilterModel);
m_nodeTable->installEventFilter(new TabWalker(this));
m_nodeTable->setItemDelegate(nodeListDelegate);
m_nodeTable->setModel(nodeFilterModel);
m_nodeTable->setSelectionModel(nodeSelectionModel);
m_nodeTable->setFocusPolicy(Qt::NoFocus);
m_nodeTable->setSelectionMode(QAbstractItemView::SingleSelection);
m_nodeTable->setSelectionBehavior(QAbstractItemView::SelectRows);
m_nodeTable->resizeColumnsToContents();
m_nodeTable->horizontalHeader()->setStretchLastSection(true);
m_nodeTable->verticalHeader()->hide();
polishPalette(m_nodeTable, "#1f75cc");
auto *eventFilterModel = new QSortFilterProxyModel;
auto *eventListDelegate = new EventListDelegate(m_eventTable);
m_eventTable->installEventFilter(new TabWalker(this));
m_eventTable->setItemDelegate(eventListDelegate);
m_eventTable->setFocusPolicy(Qt::NoFocus);
m_eventTable->setSelectionMode(QAbstractItemView::NoSelection);
m_eventTable->setSelectionBehavior(QAbstractItemView::SelectRows);
m_eventTable->setModel(eventFilterModel);
m_eventTable->verticalHeader()->hide();
polishPalette(m_eventTable, QColor("#d87b00"));
auto *nodeBox = new QVBoxLayout;
nodeBox->addWidget(m_nodeLine);
nodeBox->addWidget(m_nodeTable);
QWidget *nodeWidget = new QWidget;
nodeWidget->setLayout(nodeBox);
auto *eventBox = new QVBoxLayout;
eventBox->addWidget(m_eventLine);
eventBox->addWidget(m_eventTable);
auto *eventWidget = new QWidget;
eventWidget->setLayout(eventBox);
auto *splitter = new QSplitter(Qt::Horizontal);
splitter->addWidget(nodeWidget);
splitter->addWidget(eventWidget);
splitter->setStretchFactor(0, 1);
splitter->setStretchFactor(1, 3);
auto *box = new QHBoxLayout;
box->addWidget(splitter);
setLayout(box);
connect(m_nodeLine, &FilterLineWidget::filterChanged, [this](const QString &str) {
if (auto *sm = qobject_cast<NodeSelectionModel *>(m_nodeTable->selectionModel())) {
sm->storeSelection();
if (auto *fm = qobject_cast<QSortFilterProxyModel *>(m_nodeTable->model()))
fm->setFilterFixedString(str);
sm->reselect();
}
});
connect(m_eventLine, &FilterLineWidget::filterChanged, [this](const QString &str) {
if (auto *fm = qobject_cast<QSortFilterProxyModel *>(m_eventTable->model()))
fm->setFilterFixedString(str);
});
connect(eventListDelegate, &EventListDelegate::connectClicked,
[](const QString &id, bool connected) {
if (connected)
EventList::addEventIdToCurrent(id);
else
EventList::removeEventIdFromCurrent(id);
});
}
void AssignEventDialog::initialize(EventList &events)
{
m_nodeLine->clear();
m_eventLine->clear();
if (auto *fm = qobject_cast<QSortFilterProxyModel *>(m_nodeTable->model()))
fm->setSourceModel(events.nodeModel());
if (auto *fm = qobject_cast<QSortFilterProxyModel *>(m_eventTable->model()))
fm->setSourceModel(events.view()->eventListModel());
if (auto *sm = qobject_cast<NodeSelectionModel *>(m_nodeTable->selectionModel())) {
if (m_connection)
sm->disconnect(m_connection);
auto updateEventListView = [this, &events](const QStringList &eventIds) {
auto nonExistent = events.view()->eventListModel()->connectEvents(eventIds);
if (!nonExistent.empty()) {
QString header(tr("Nonexistent events discovered"));
QString msg(tr("The Node references the following nonexistent events:\n"));
for (auto &&id : nonExistent)
msg += id + ", ";
msg.remove(msg.size() - 2, 2);
msg += "\nDo you want to remove these references?";
if (QMessageBox::Yes == QMessageBox::question(this, header, msg)) {
auto *view = events.nodeListView();
view->removeEventIds(view->currentNode(), nonExistent);
view->reset();
if (auto *sm = qobject_cast<NodeSelectionModel *>(m_nodeTable->selectionModel()))
sm->selectNode(view->currentNode());
}
}
m_eventTable->update();
};
m_connection = connect(sm, &NodeSelectionModel::nodeSelected, updateEventListView);
}
m_nodeTable->setColumnHidden(NodeListModel::typeColumn, true);
m_nodeTable->setColumnHidden(NodeListModel::fromColumn, true);
m_nodeTable->setColumnHidden(NodeListModel::toColumn, true);
if (QHeaderView *header = m_eventTable->horizontalHeader()) {
header->setSectionResizeMode(EventListModel::idColumn, QHeaderView::Stretch);
header->setSectionResizeMode(EventListModel::descriptionColumn, QHeaderView::Stretch);
header->setSectionResizeMode(EventListModel::shortcutColumn, QHeaderView::Stretch);
header->resizeSection(EventListModel::connectColumn, 120);
header->setStretchLastSection(false);
}
}
void AssignEventDialog::postShow()
{
if (auto *sm = qobject_cast<NodeSelectionModel *>(m_nodeTable->selectionModel()))
sm->selectNode(EventList::currentNode());
resize(QSize(700, 300));
}
} // namespace QmlDesigner.

View File

@@ -0,0 +1,52 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#pragma once
#include <QDialog>
QT_FORWARD_DECLARE_CLASS(QTableView)
namespace QmlDesigner {
class EventList;
class FilterLineWidget;
class AssignEventDialog : public QDialog
{
Q_OBJECT
public:
AssignEventDialog(QWidget *parent = nullptr);
void initialize(EventList &events);
void postShow();
private:
QTableView *m_nodeTable;
QTableView *m_eventTable;
FilterLineWidget *m_nodeLine;
FilterLineWidget *m_eventLine;
QMetaObject::Connection m_connection;
};
} // namespace QmlDesigner.

View File

@@ -0,0 +1,136 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#include "connectsignaldialog.h"
#include "eventlist.h"
#include "eventlistdelegate.h"
#include "eventlistview.h"
#include "filterlinewidget.h"
#include "nodelistview.h"
#include "eventlistutils.h"
#include <QHeaderView>
#include <QSortFilterProxyModel>
#include <QTableView>
#include <QVBoxLayout>
namespace QmlDesigner {
QString eventListToSource(const QStringList &events)
{
if (events.empty())
return QString("{}");
QString source("{\n");
for (auto &&event : events)
source += QString("EventSystem.triggerEvent(\"") + event + QString("\")\n");
source += "}";
return source;
}
QStringList eventListFromSource(const QString &source)
{
QStringList out;
for (auto &&substr : source.split("\n", Qt::SkipEmptyParts)) {
auto trimmed = substr.trimmed();
if (trimmed.startsWith("EventSystem.triggerEvent("))
out << trimmed.section('\"', 1, 1);
}
return out;
}
ConnectSignalDialog::ConnectSignalDialog(QWidget *parent)
: QDialog(parent)
, m_table(new QTableView)
, m_filter(new FilterLineWidget())
, m_property()
{
setWindowFlag(Qt::Tool, true);
setModal(true);
auto *filterModel = new QSortFilterProxyModel;
auto *delegate = new EventListDelegate(m_table);
m_table->installEventFilter(new TabWalker(this));
m_table->setItemDelegate(delegate);
m_table->setModel(filterModel);
m_table->setFocusPolicy(Qt::NoFocus);
m_table->setSelectionMode(QAbstractItemView::NoSelection);
m_table->setSelectionBehavior(QAbstractItemView::SelectRows);
m_table->verticalHeader()->hide();
polishPalette(m_table, QColor("#d87b00"));
auto *box = new QVBoxLayout;
box->addWidget(m_filter);
box->addWidget(m_table);
setLayout(box);
connect(m_filter, &FilterLineWidget::filterChanged, [this](const QString &str) {
if (auto *fm = qobject_cast<QSortFilterProxyModel *>(m_table->model()))
fm->setFilterFixedString(str);
});
connect(delegate,
&EventListDelegate::connectClicked,
[this, filterModel](const QString &, bool) {
if (m_property.isValid()) {
if (const auto *m = qobject_cast<const EventListModel *>(
filterModel->sourceModel())) {
QString source = eventListToSource(m->connectedEvents());
EventList::setSignalSource(m_property, source);
}
}
});
}
void ConnectSignalDialog::initialize(EventList &events, const SignalHandlerProperty &signal)
{
m_filter->clear();
auto *eventModel = events.view()->eventListModel();
if (!eventModel)
return;
if (auto *fm = qobject_cast<QSortFilterProxyModel *>(m_table->model()))
fm->setSourceModel(eventModel);
m_property = signal;
if (m_property.isValid()) {
QString title = QString::fromUtf8(m_property.name());
setWindowTitle(title);
eventModel->connectEvents(eventListFromSource(m_property.source()));
}
if (QHeaderView *header = m_table->horizontalHeader()) {
header->setSectionResizeMode(EventListModel::idColumn, QHeaderView::Stretch);
header->setSectionResizeMode(EventListModel::descriptionColumn, QHeaderView::Stretch);
header->setSectionResizeMode(EventListModel::shortcutColumn, QHeaderView::Stretch);
header->resizeSection(EventListModel::connectColumn, 120);
header->setStretchLastSection(false);
}
}
QSize ConnectSignalDialog::sizeHint() const
{
return QSize(522, 270);
}
} // namespace QmlDesigner.

View File

@@ -0,0 +1,51 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#pragma once
#include "signalhandlerproperty.h"
#include <QDialog>
QT_FORWARD_DECLARE_CLASS(QTableView)
namespace QmlDesigner {
class EventList;
class FilterLineWidget;
class ConnectSignalDialog : public QDialog
{
Q_OBJECT
public:
ConnectSignalDialog(QWidget *parent = nullptr);
void initialize(EventList &events, const SignalHandlerProperty &signal);
protected:
QSize sizeHint() const override;
private:
QTableView *m_table;
FilterLineWidget *m_filter;
SignalHandlerProperty m_property;
};
} // namespace QmlDesigner.

View File

@@ -0,0 +1,230 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#include "eventlist.h"
#include "eventlistpluginview.h"
#include "eventlistview.h"
#include "nodelistview.h"
#include "bindingproperty.h"
#include "metainfo.h"
#include "projectexplorer/project.h"
#include "projectexplorer/session.h"
#include "qmldesignerplugin.h"
#include "signalhandlerproperty.h"
#include "utils/fileutils.h"
#include "utils/qtcassert.h"
#include "variantproperty.h"
#include <QDirIterator>
#include <QStandardItemModel>
namespace QmlDesigner {
Utils::FilePath projectFilePath()
{
if (auto *doc = QmlDesignerPlugin::instance()->documentManager().currentDesignDocument()) {
if (auto *proj = ProjectExplorer::SessionManager::projectForFile(doc->fileName()))
return proj->projectDirectory();
}
return Utils::FilePath();
}
static Utils::FilePath findFile(const Utils::FilePath &path, const QString &fileName)
{
QDirIterator it(path.toString(), QDirIterator::Subdirectories);
while (it.hasNext()) {
QFileInfo file(it.next());
if (file.isDir())
continue;
if (file.fileName() == fileName)
return Utils::FilePath::fromFileInfo(file);
}
return {};
}
NodeListView *EventList::st_nodeView = nullptr;
void EventList::setNodeProperties(AbstractView *view)
{
st_nodeView = new NodeListView(view);
}
void EventList::selectNode(int internalId)
{
if (st_nodeView)
st_nodeView->selectNode(internalId);
}
int EventList::currentNode()
{
if (st_nodeView)
return st_nodeView->currentNode();
return -1;
}
bool EventList::hasEventListModel()
{
Utils::FilePath projectPath = projectFilePath();
if (projectPath.isEmpty())
return false;
Utils::FilePath path = findFile(projectPath, "EventListModel.qml");
return path.exists();
}
void EventList::addEventIdToCurrent(const QString &eventId)
{
int iid = currentNode();
if (st_nodeView && iid >= 0)
st_nodeView->addEventId(iid, eventId);
}
void EventList::removeEventIdFromCurrent(const QString &eventId)
{
int iid = currentNode();
if (st_nodeView && iid >= 0)
st_nodeView->removeEventIds(iid, {eventId});
}
QString EventList::setNodeId(int internalId, const QString &id)
{
if (st_nodeView)
return st_nodeView->setNodeId(internalId, id);
return QString();
}
QStandardItemModel *EventList::nodeModel()
{
if (st_nodeView)
return st_nodeView->itemModel();
return nullptr;
}
NodeListView *EventList::nodeListView()
{
return st_nodeView;
}
ModelNode EventList::modelNode(const QString &id)
{
if (st_nodeView)
return st_nodeView->modelNodeForId(id);
return ModelNode();
}
void EventList::setSignalSource(SignalHandlerProperty &prop, const QString &source)
{
if (st_nodeView) {
QmlDesigner::Import import =
QmlDesigner::Import::createLibraryImport("QtQuick.Studio.EventSystem", "1.0");
if (!st_nodeView->model()->hasImport(import, true, true)) {
try {
st_nodeView->model()->changeImports({import}, {});
} catch (const QmlDesigner::Exception &) {
QTC_ASSERT(false, return );
}
}
if (source == "{}") {
if (ModelNode node = prop.parentModelNode(); node.isValid()) {
st_nodeView->executeInTransaction("EventList::removeProperty",
[&]() { node.removeProperty(prop.name()); });
}
}
else {
st_nodeView->executeInTransaction("EventList::setSource",
[&]() { prop.setSource(source); });
}
}
}
EventList::EventList()
: m_model(nullptr)
, m_eventView(nullptr)
, m_path()
{}
Model *EventList::model() const
{
return m_model;
}
EventListView *EventList::view() const
{
return m_eventView;
}
QString EventList::read() const
{
if (!m_path.exists())
return QString();
Utils::FileReader reader;
QTC_ASSERT(reader.fetch(m_path), return QString());
return QString::fromUtf8(reader.data());
}
void EventList::initialize(EventListPluginView *parent)
{
Utils::FilePath projectPath = projectFilePath();
QTC_ASSERT(!projectPath.isEmpty(), return );
m_path = findFile(projectPath, "EventListModel.qml");
if (!m_model) {
QByteArray unqualifiedTypeName = "ListModel";
auto metaInfo = parent->model()->metaInfo(unqualifiedTypeName);
QByteArray fullTypeName = metaInfo.typeName();
int minorVersion = metaInfo.minorVersion();
int majorVersion = metaInfo.majorVersion();
m_model = Model::create(fullTypeName, majorVersion, minorVersion);
m_model->setParent(parent);
}
if (!m_eventView) {
m_eventView = new EventListView(m_model);
m_model->attachView(m_eventView);
}
}
void EventList::write(const QString &text)
{
if (!m_path.exists())
return;
Utils::FileSaver writer(m_path);
writer.write(text.toUtf8());
writer.finalize();
}
} // namespace QmlDesigner.

View File

@@ -0,0 +1,75 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#pragma once
#include "modelnode.h"
#include "utils/fileutils.h"
#include <unordered_set>
#include <QDialog>
QT_FORWARD_DECLARE_CLASS(QStandardItemModel)
namespace QmlDesigner {
class Model;
class NodeListView;
class EventListView;
class EventListPluginView;
class EventList
{
public:
static int currentNode();
static bool hasEventListModel();
static bool connectedToCurrent(const QString &eventId);
static void addEventIdToCurrent(const QString &eventId);
static void removeEventIdFromCurrent(const QString &eventId);
static void setNodeProperties(AbstractView *view);
static void selectNode(int internalId);
static QString setNodeId(int internalId, const QString &id);
static QStandardItemModel *nodeModel();
static NodeListView *nodeListView();
static ModelNode modelNode(const QString &id);
static void setSignalSource(SignalHandlerProperty &prop, const QString &source);
EventList();
Model *model() const;
EventListView *view() const;
QString read() const;
void initialize(EventListPluginView *parent);
void write(const QString &text);
private:
static NodeListView *st_nodeView;
Model *m_model;
EventListView *m_eventView;
Utils::FilePath m_path;
};
} // namespace QmlDesigner.

View File

@@ -0,0 +1,110 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#include "eventlistactions.h"
#include "eventlist.h"
#include <theme.h>
#include "metainfo.h"
#include <utils/utilsicons.h>
#include <utils/stylehelper.h>
namespace QmlDesigner {
inline bool eventListEnabled(const SelectionContext &)
{
return EventList::hasEventListModel();
}
QIcon eventListIconFromIconFont(Theme::Icon iconType)
{
const QColor enabledColor(Theme::getColor(Theme::IconsBaseColor));
const QColor disabledColor(Theme::getColor(Theme::IconsDisabledColor));
const QString unicode = Theme::getIconUnicode(iconType);
const QString fontName = "qtds_propertyIconFont.ttf";
const auto enabledHelper = Utils::StyleHelper::IconFontHelper(
unicode, enabledColor, QSize(28, 28), QIcon::Normal);
const auto disabledHelper = Utils::StyleHelper::IconFontHelper(
unicode, disabledColor, QSize(28, 28), QIcon::Disabled);
return Utils::StyleHelper::getIconFromIconFont(fontName, {enabledHelper, disabledHelper});
}
static QIcon editEventListIcon()
{
return eventListIconFromIconFont(Theme::Icon::edit);
}
static void handleAction(const SelectionContext &) {}
EventListAction::EventListAction()
: ModelNodeAction("EventList",
QObject::tr("Show Event List"),
editEventListIcon(),
QObject::tr("Show Event List"),
ComponentCoreConstants::eventListCategory,
QKeySequence("Alt+e"),
230,
&handleAction,
&eventListEnabled)
{}
static QIcon assignEventListIcon()
{
return eventListIconFromIconFont(Theme::Icon::assign);
}
static void handleAssignEventActionOperation(const SelectionContext &context)
{
EventList::setNodeProperties(context.view());
}
AssignEventEditorAction::AssignEventEditorAction()
: ModelNodeAction("AssignEventEditor",
QObject::tr("Assign Events to Actions"),
assignEventListIcon(),
QObject::tr("Assign Events to Actions"),
ComponentCoreConstants::eventListCategory,
QKeySequence("Alt+a"),
220,
&handleAssignEventActionOperation,
&eventListEnabled)
{}
ConnectSignalAction::ConnectSignalAction()
: ModelNodeContextMenuAction("ConnectSignalEditor",
QObject::tr("Connect Signal to Event"),
assignEventListIcon(),
ComponentCoreConstants::eventListCategory,
QKeySequence(),
210,
&handleAssignEventActionOperation)
{}
ModelNodeContextMenuAction::TargetView ConnectSignalAction::targetView() const
{
return TargetView::ConnectionEditor;
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,47 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#pragma once
#include <modelnodecontextmenu_helper.h>
namespace QmlDesigner {
class EventListAction : public ModelNodeAction
{
public:
EventListAction();
};
class AssignEventEditorAction : public ModelNodeAction
{
public:
AssignEventEditorAction();
};
class ConnectSignalAction : public ModelNodeContextMenuAction
{
public:
ConnectSignalAction();
TargetView targetView() const override;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,205 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#include "eventlistdelegate.h"
#include "eventlist.h"
#include "eventlistview.h"
#include "nodelistview.h"
#include "qnamespace.h"
#include "shortcutwidget.h"
#include "eventlistutils.h"
#include <QApplication>
#include <QLineEdit>
#include <QPainter>
#include <QStyleOptionButton>
#include <QTableView>
#include <QMouseEvent>
namespace QmlDesigner {
EventListDelegate::EventListDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{}
QWidget *EventListDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (index.column() == EventListModel::shortcutColumn) {
auto *editor = new ShortcutWidget(parent);
connect(editor, &ShortcutWidget::done, this, &EventListDelegate::commitAndClose);
connect(editor, &ShortcutWidget::cancel, this, &EventListDelegate::close);
return editor;
} else if (index.column() == EventListModel::connectColumn) {
return nullptr;
}
return QStyledItemDelegate::createEditor(parent, option, index);
}
void EventListDelegate::setModelData(QWidget *editor,
QAbstractItemModel *model,
const QModelIndex &index) const
{
if (index.column() == EventListModel::idColumn) {
if (auto *edit = qobject_cast<QLineEdit *>(editor)) {
QString name = edit->text();
QString unique = uniqueName(model, name);
if (name != unique) {
name = unique;
edit->setText(unique);
}
emit eventIdChanged(model->data(index, Qt::DisplayRole).toString(), name);
}
} else if (index.column() == EventListModel::shortcutColumn) {
if (auto *edit = qobject_cast<ShortcutWidget *>(editor)) {
auto idIndex = model->index(index.row(), EventListModel::idColumn, index.parent());
if (idIndex.isValid()) {
emit shortcutChanged(model->data(idIndex, Qt::DisplayRole).toString(), edit->text());
model->setData(index, edit->text(), Qt::DisplayRole);
return;
}
}
} else if (index.column() == EventListModel::descriptionColumn) {
if (auto *edit = qobject_cast<QLineEdit *>(editor)) {
auto idIndex = model->index(index.row(), EventListModel::idColumn, index.parent());
if (idIndex.isValid()) {
auto id = model->data(idIndex, Qt::DisplayRole).toString();
emit descriptionChanged(id, edit->text());
}
}
}
QStyledItemDelegate::setModelData(editor, model, index);
}
bool EventListDelegate::hasConnectionColumn(QObject *parent)
{
if (auto *table = qobject_cast<QTableView *>(parent))
return !table->isColumnHidden(EventListModel::connectColumn);
return false;
}
QRect EventListDelegate::connectButtonRect(const QStyleOptionViewItem &option)
{
return option.rect.adjusted(3, 3, -3, -3);
}
void EventListDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (hasConnectionColumn(parent())) {
bool connected = index.data(EventListModel::connectedRole).toBool();
if (connected) {
QStyleOptionViewItem opt(option);
opt.state = QStyle::State_Selected;
QStyledItemDelegate::paint(painter, opt, index);
if (index.column() != EventListModel::connectColumn)
return;
}
if (index.column() == EventListModel::connectColumn) {
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 EventListDelegate::editorEvent(QEvent *event,
QAbstractItemModel *model,
const QStyleOptionViewItem &option,
const QModelIndex &index)
{
if (index.column() == EventListModel::connectColumn) {
if (event->type() == QEvent::MouseButtonRelease) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (connectButtonRect(option).contains(mouseEvent->pos())) {
if (QModelIndex sib = index.siblingAtColumn(EventListModel::idColumn); sib.isValid()) {
auto id = sib.data().toString();
bool connected = index.data(EventListModel::connectedRole).toBool();
for (int c = 0; c < model->columnCount(); ++c) {
auto id = model->index(index.row(), c, index.parent());
model->setData(id, !connected, EventListModel::connectedRole);
}
emit connectClicked(id, !connected);
return true;
}
}
}
}
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
bool EventListDelegate::eventFilter(QObject *editor, QEvent *event)
{
if (auto *edit = qobject_cast<ShortcutWidget *>(editor)) {
if (event->type() == QEvent::KeyPress) {
edit->recordKeysequence(static_cast<QKeyEvent *>(event));
return true;
}
if (event->type() == QEvent::FocusOut) {
if (!edit->containsFocus())
edit->reset();
}
} else {
if (event->type() == QEvent::KeyPress) {
int key = static_cast<QKeyEvent *>(event)->key();
if (key == Qt::Key_Tab || key == Qt::Key_Backtab)
return false;
}
}
return QStyledItemDelegate::eventFilter(editor, event);
}
QSize EventListDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.column() == EventListModel::connectColumn) {
QSize size = QStyledItemDelegate::sizeHint(option, index);
size.rwidth() = 20;
return size;
}
return QStyledItemDelegate::sizeHint(option, index);
}
void EventListDelegate::commitAndClose()
{
if (auto *editor = qobject_cast<ShortcutWidget *>(sender())) {
emit commitData(editor);
emit closeEditor(editor);
}
}
void EventListDelegate::close()
{
if (auto *editor = qobject_cast<ShortcutWidget *>(sender()))
emit closeEditor(editor);
}
} // namespace QmlDesigner.

View File

@@ -0,0 +1,67 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#pragma once
#include <QStyledItemDelegate>
namespace QmlDesigner {
class EventListDelegate : public QStyledItemDelegate
{
Q_OBJECT
signals:
void eventIdChanged(const QString &from, const QString &to) const;
void shortcutChanged(const QString &from, const QString &to) const;
void descriptionChanged(const QString &id, const QString &text) const;
void connectClicked(const QString &id, bool connected) const;
public:
EventListDelegate(QObject *parent = nullptr);
QWidget *createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model, 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;
protected:
bool eventFilter(QObject *editor, QEvent *event) override;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
private:
void close();
void commitAndClose();
static bool hasConnectionColumn(QObject *parent);
static QRect connectButtonRect(const QStyleOptionViewItem &option);
};
} // namespace QmlDesigner.

View File

@@ -0,0 +1,151 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#include "eventlistdialog.h"
#include "eventlist.h"
#include "eventlistdelegate.h"
#include "eventlistview.h"
#include "filterlinewidget.h"
#include "nodelistview.h"
#include "qmldesignerplugin.h"
#include "eventlistutils.h"
#include "utils/utilsicons.h"
#include <QHBoxLayout>
#include <QHeaderView>
#include <QPlainTextEdit>
#include <QSortFilterProxyModel>
#include <QTableView>
#include <QToolBar>
#include <QVBoxLayout>
namespace QmlDesigner {
EventListDialog::EventListDialog(QWidget *parent)
: QDialog(parent)
, m_delegate(new EventListDelegate)
, m_modifier(nullptr)
, m_rewriter(nullptr)
, m_table(new QTableView)
, m_addAction(nullptr)
, m_removeAction(nullptr)
, m_textEdit(new QPlainTextEdit)
{
setModal(true);
setWindowFlag(Qt::Tool, true);
m_modifier = new NotIndentingTextEditModifier(m_textEdit);
m_textEdit->hide();
m_table->installEventFilter(new TabWalker(this));
m_table->setItemDelegate(m_delegate);
m_table->setModel(new QSortFilterProxyModel);
m_table->setFocusPolicy(Qt::NoFocus);
m_table->setSelectionBehavior(QAbstractItemView::SelectRows);
m_table->horizontalHeader()->setStretchLastSection(true);
m_table->resizeColumnsToContents();
auto *toolbar = new QToolBar;
m_addAction = toolbar->addAction(Utils::Icons::PLUS_TOOLBAR.icon(), tr("Add Event"));
m_removeAction = toolbar->addAction(Utils::Icons::MINUS.icon(), tr("Remove Selected Events"));
auto *filterWidget = new FilterLineWidget;
toolbar->addWidget(filterWidget);
auto *tableLayout = new QVBoxLayout;
tableLayout->setSpacing(0);
tableLayout->addWidget(toolbar);
tableLayout->addWidget(m_table);
auto *box = new QHBoxLayout;
box->addLayout(tableLayout);
setLayout(box);
connect(filterWidget, &FilterLineWidget::filterChanged, [this](const QString &str) {
if (auto *fm = qobject_cast<QSortFilterProxyModel *>(m_table->model()))
fm->setFilterFixedString(str);
});
}
void EventListDialog::initialize(EventList &events)
{
m_textEdit->setPlainText(events.read());
if (!m_rewriter) {
Model *model = events.model();
m_modifier->setParent(model);
m_rewriter = new RewriterView(QmlDesigner::RewriterView::Validate, model);
m_rewriter->setTextModifier(m_modifier);
m_rewriter->setCheckSemanticErrors(false);
model->attachView(m_rewriter);
if (auto *fm = qobject_cast<QSortFilterProxyModel *>(m_table->model())) {
fm->setSourceModel(events.view()->eventListModel());
}
connect(m_addAction, &QAction::triggered, [this, &events]() {
Event event;
event.eventId = uniqueName(events.view()->eventListModel(), "event");
events.view()->addEvent(event);
events.write(m_textEdit->toPlainText());
});
connect(m_removeAction, &QAction::triggered, [this, &events]() {
for (auto index : m_table->selectionModel()->selectedRows()) {
QString eventId = index.data(Qt::DisplayRole).toString();
events.view()->removeEvent(eventId);
}
events.write(m_textEdit->toPlainText());
});
connect(m_delegate,
&EventListDelegate::eventIdChanged,
[this, &events](const QString &oldId, const QString &newId) {
events.view()->renameEvent(oldId, newId);
events.write(m_textEdit->toPlainText());
});
connect(m_delegate,
&EventListDelegate::shortcutChanged,
[this, &events](const QString &id, const QString &text) {
events.view()->setShortcut(id, text);
events.write(m_textEdit->toPlainText());
});
connect(m_delegate,
&EventListDelegate::descriptionChanged,
[this, &events](const QString &id, const QString &text) {
events.view()->setDescription(id, text);
events.write(m_textEdit->toPlainText());
});
}
m_table->setColumnHidden(EventListModel::connectColumn, true);
}
void EventListDialog::closeEvent(QCloseEvent *event)
{
Q_UNUSED(event);
if (auto *view = EventList::nodeListView())
view->reset();
}
} // namespace QmlDesigner.

View File

@@ -0,0 +1,57 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#pragma once
#include <QDialog>
QT_FORWARD_DECLARE_CLASS(QPlainTextEdit)
QT_FORWARD_DECLARE_CLASS(QTableView)
namespace QmlDesigner {
class EventList;
class EventListDelegate;
class RewriterView;
class NotIndentingTextEditModifier;
class EventListDialog : public QDialog
{
Q_OBJECT
public:
EventListDialog(QWidget *parent = nullptr);
void initialize(EventList &events);
protected:
void closeEvent(QCloseEvent *event) override;
private:
EventListDelegate *m_delegate;
NotIndentingTextEditModifier *m_modifier;
RewriterView *m_rewriter;
QTableView *m_table;
QAction *m_addAction;
QAction *m_removeAction;
QPlainTextEdit *m_textEdit;
};
} // namespace QmlDesigner.

View File

@@ -0,0 +1 @@
MetaInfo {}

View File

@@ -0,0 +1,35 @@
QT *= qml quick core
VPATH += $$PWD
SOURCES += $$PWD/eventlist.cpp \
$$PWD/eventlistview.cpp \
$$PWD/eventlistpluginview.cpp \
$$PWD/eventlistactions.cpp \
$$PWD/eventlistdialog.cpp \
$$PWD/eventlistdelegate.cpp \
$$PWD/filterlinewidget.cpp \
$$PWD/nodelistview.cpp \
$$PWD/nodelistdelegate.cpp \
$$PWD/nodeselectionmodel.cpp \
$$PWD/assigneventdialog.cpp \
$$PWD/shortcutwidget.cpp \
$$PWD/connectsignaldialog.cpp \
$$PWD/eventlistutils.cpp
HEADERS += $$PWD/eventlist.h \
$$PWD/eventlistpluginview.h \
$$PWD/eventlistview.h \
$$PWD/eventlistactions.h \
$$PWD/eventlistdialog.h \
$$PWD/eventlistdelegate.h \
$$PWD/filterlinewidget.h \
$$PWD/nodelistview.h \
$$PWD/nodelistdelegate.h \
$$PWD/nodeselectionmodel.h \
$$PWD/assigneventdialog.h \
$$PWD/shortcutwidget.h \
$$PWD/connectsignaldialog.h \
$$PWD/eventlistutils.h
RESOURCES += $$PWD/eventlistplugin.qrc

View File

@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/eventlistplugin">
<file>eventlistplugin.metainfo</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,114 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#include "eventlistpluginview.h"
#include "assigneventdialog.h"
#include "connectsignaldialog.h"
#include "eventlistactions.h"
#include "eventlistdialog.h"
#include "signalhandlerproperty.h"
#include <coreplugin/icore.h>
#include <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginspec.h>
#include <qmldesignerplugin.h>
#include <componentcore/componentcore_constants.h>
namespace QmlDesigner {
SignalHandlerProperty signalPropertyFromAction(ActionInterface *interface)
{
if (auto data = interface->action()->data(); data.isValid()) {
QMap<QString, QVariant> mapping = data.value<QMap<QString, QVariant>>();
ModelNode node = EventList::modelNode(mapping["ModelNode"].toString());
PropertyName signal = mapping["Signal"].toString().toUtf8();
for (auto &&child : node.directSubModelNodes()) {
if (auto prop = child.signalHandlerProperty(signal); prop.exists())
return prop;
}
}
return SignalHandlerProperty();
}
EventListPluginView::EventListPluginView(QObject* parent)
: AbstractView(parent)
, m_eventlist()
, m_eventListDialog(nullptr)
, m_assigner(nullptr)
, m_signalConnector(nullptr)
{ }
void EventListPluginView::registerActions()
{
DesignerActionManager &designerActionManager = QmlDesignerPlugin::instance()->designerActionManager();
designerActionManager.addDesignerAction(new ActionGroup(tr("Event List"),
ComponentCoreConstants::eventListCategory,
ComponentCoreConstants::priorityEventListCategory,
&SelectionContextFunctors::always,
&SelectionContextFunctors::always));
auto eventListAction = new EventListAction();
connect(eventListAction->defaultAction(), &QAction::triggered, [this]() {
if (!m_eventListDialog)
m_eventListDialog = new EventListDialog(Core::ICore::dialogParent());
m_eventlist.initialize(this);
m_eventListDialog->initialize(m_eventlist);
m_eventListDialog->show();
});
designerActionManager.addDesignerAction(eventListAction);
auto assignEventAction = new AssignEventEditorAction();
connect(assignEventAction->defaultAction(), &QAction::triggered, [this]() {
if (!m_assigner)
m_assigner = new AssignEventDialog(Core::ICore::dialogParent());
if (!m_eventListDialog)
m_eventListDialog = new EventListDialog(Core::ICore::dialogParent());
m_eventlist.initialize(this);
m_eventListDialog->initialize(m_eventlist);
m_assigner->initialize(m_eventlist);
m_assigner->show();
m_assigner->postShow();
});
designerActionManager.addDesignerAction(assignEventAction);
auto *connectSignalAction = new ConnectSignalAction();
connect(connectSignalAction->defaultAction(), &QAction::triggered, [this, connectSignalAction]() {
if (!m_signalConnector)
m_signalConnector = new ConnectSignalDialog(Core::ICore::dialogParent());
if (!m_eventListDialog)
m_eventListDialog = new EventListDialog(Core::ICore::dialogParent());
m_eventlist.initialize(this);
m_eventListDialog->initialize(m_eventlist);
if (auto signal = signalPropertyFromAction(connectSignalAction); signal.isValid()) {
m_signalConnector->initialize(m_eventlist, signal);
m_signalConnector->show();
}
});
designerActionManager.addDesignerAction(connectSignalAction);
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,50 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#pragma once
#include "eventlist.h"
#include <abstractview.h>
namespace QmlDesigner {
class EventListDialog;
class AssignEventDialog;
class ConnectSignalDialog;
class EventListPluginView : public AbstractView
{
Q_OBJECT
public:
EventListPluginView(QObject* parent = nullptr);
~EventListPluginView() override = default;
void registerActions();
private:
EventList m_eventlist;
EventListDialog *m_eventListDialog = nullptr;
AssignEventDialog *m_assigner = nullptr;
ConnectSignalDialog *m_signalConnector = nullptr;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,145 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#include "eventlistutils.h"
#include <QApplication>
#include <QKeyEvent>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QTableView>
namespace QmlDesigner {
TabWalker::TabWalker(QObject *parent)
: QObject(parent)
{}
bool TabWalker::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyPress) {
auto *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Tab || keyEvent->key() == Qt::Key_Backtab) {
keyEvent->accept();
int mapped = keyEvent->key() == Qt::Key_Tab ? Qt::Key_Down : Qt::Key_Up;
int modifiers = keyEvent->nativeModifiers() & (~Qt::ShiftModifier);
QApplication::postEvent(obj,
new QKeyEvent(QEvent::KeyPress,
mapped,
static_cast<Qt::KeyboardModifier>(modifiers),
keyEvent->nativeScanCode(),
keyEvent->nativeVirtualKey(),
keyEvent->nativeModifiers(),
keyEvent->text(),
keyEvent->isAutoRepeat(),
keyEvent->count()));
return true;
}
}
return QObject::eventFilter(obj, event);
}
QStandardItemModel *sourceModel(QAbstractItemModel *model)
{
if (auto *proxy = qobject_cast<QSortFilterProxyModel *>(model))
return sourceModel(proxy->sourceModel());
return qobject_cast<QStandardItemModel *>(model);
}
QString uniqueName(QAbstractItemModel *model, const QString &base)
{
if (auto *m = sourceModel(model)) {
QList<QStandardItem *> items = m->findItems(base);
if (items.empty())
return base;
int idx = 0;
while (true) {
QString tmp = base + QString::number(idx++);
items = m->findItems(tmp);
if (items.empty())
return tmp;
}
}
return QString();
}
std::string toString(AbstractView::PropertyChangeFlags flags)
{
if (flags == 0)
return std::string("NoAdditionalChanges");
std::string out;
if ((flags & AbstractView::NoAdditionalChanges) != 0)
out += "NoAdditionalChanges ";
if ((flags & AbstractView::PropertiesAdded) != 0) {
if (!out.empty())
out += "| ";
out += "PropertiesAdded ";
}
if ((flags & AbstractView::EmptyPropertiesRemoved) != 0) {
if (!out.empty())
out += "| ";
out += "EmptyPropertiesRemoved ";
}
return out;
}
void polishPalette(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);
}
void printPropertyType(const ModelNode &node, const PropertyName &name)
{
std::string sname = name.toStdString();
auto prop = node.property(name);
if (prop.isNodeProperty())
printf("Property %s is a node-property\n", sname.c_str());
if (prop.isVariantProperty())
printf("Property %s is a variant-property\n", sname.c_str());
if (prop.isNodeListProperty())
printf("Property %s is a node-list-property\n", sname.c_str());
if (prop.isNodeAbstractProperty())
printf("Property %s is a node-abstract-property\n", sname.c_str());
if (prop.isBindingProperty())
printf("Property %s is a binding-property\n", sname.c_str());
if (prop.isSignalHandlerProperty())
printf("Property %s is a signal-handler-property\n", sname.c_str());
}
} // namespace QmlDesigner.

View File

@@ -0,0 +1,49 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#pragma once
#include "abstractview.h"
#include <string>
QT_FORWARD_DECLARE_CLASS(QAbstractItemModel)
QT_FORWARD_DECLARE_CLASS(QTableView)
namespace QmlDesigner {
class TabWalker : public QObject
{
Q_OBJECT
public:
TabWalker(QObject *parent = nullptr);
bool eventFilter(QObject *obj, QEvent *event) override;
};
QString uniqueName(QAbstractItemModel *model, const QString &base);
std::string toString(AbstractView::PropertyChangeFlags flags);
void polishPalette(QTableView *view, const QColor &selectionColor);
void printPropertyType(const ModelNode &node, const PropertyName &name);
} // namespace QmlDesigner.

View File

@@ -0,0 +1,198 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#include "eventlistview.h"
#include "assigneventdialog.h"
#include "connectsignaldialog.h"
#include "eventlistactions.h"
#include "eventlistdialog.h"
#include "nodelistproperty.h"
#include "nodeproperty.h"
#include "variantproperty.h"
#include <coreplugin/icore.h>
#include <componentcore/componentcore_constants.h>
#include <QPushButton>
#include <QStandardItemModel>
namespace QmlDesigner {
EventListModel::EventListModel(QObject *parent)
: QStandardItemModel(0, 4, parent)
{
setHeaderData(idColumn, Qt::Horizontal, tr("Event ID"));
setHeaderData(shortcutColumn, Qt::Horizontal, tr("Shortcut"));
setHeaderData(descriptionColumn, Qt::Horizontal, tr("Description"));
setHeaderData(connectColumn, Qt::Horizontal, tr(""));
}
QStringList EventListModel::connectedEvents() const
{
QStringList out;
for (int row = 0; row < rowCount(); ++row) {
if (auto idx = index(row, EventListModel::idColumn); idx.isValid()) {
if (idx.data(EventListModel::connectedRole).toBool())
out << idx.data().toString();
}
}
return out;
}
QStringList EventListModel::connectEvents(const QStringList &eventIds)
{
auto out = eventIds;
for (int row = 0; row < rowCount(); ++row) {
auto nameIndex = index(row, EventListModel::idColumn);
bool connected = out.removeOne(nameIndex.data().toString());
for (int col = 0; col < columnCount(); col++)
setData(index(row, col), connected, EventListModel::connectedRole);
}
return out;
}
EventListView::EventListView(QObject *parent)
: AbstractView(parent)
, m_eventlist()
, m_model(new EventListModel(this))
{}
EventListView::~EventListView() {}
void EventListView::nodeRemoved(const ModelNode &removedNode,
const NodeAbstractProperty &parentProperty,
PropertyChangeFlags propertyChange)
{
AbstractView::nodeRemoved(removedNode, parentProperty, propertyChange);
reset();
}
void EventListView::nodeReparented(const ModelNode &node,
const NodeAbstractProperty &newPropertyParent,
const NodeAbstractProperty &oldPropertyParent,
PropertyChangeFlags propertyChange)
{
AbstractView::nodeReparented(node, newPropertyParent, oldPropertyParent, propertyChange);
reset();
}
EventListModel *EventListView::eventListModel() const
{
return m_model;
}
void EventListView::addEvent(const Event &event)
{
executeInTransaction("EventListView::addEvent", [=]() {
QByteArray unqualifiedTypeName = "ListElement";
auto metaInfo = model()->metaInfo(unqualifiedTypeName);
QByteArray fullTypeName = metaInfo.typeName();
int minorVersion = metaInfo.minorVersion();
int majorVersion = metaInfo.majorVersion();
ModelNode eventNode = createModelNode(fullTypeName, majorVersion, minorVersion);
eventNode.variantProperty("eventId").setValue(event.eventId);
if (!event.shortcut.isEmpty())
eventNode.variantProperty("shortcut").setValue(event.shortcut);
if (!event.description.isEmpty())
eventNode.variantProperty("eventDescription").setValue(event.description);
rootModelNode().defaultNodeListProperty().reparentHere(eventNode);
});
}
void EventListView::removeEvent(const QString &eventId)
{
executeInTransaction("EventListView::removeEvent", [=]() {
for (auto node : rootModelNode().defaultNodeListProperty().toModelNodeList()) {
if (node.variantProperty("eventId").value().toString() == eventId) {
node.destroy();
return;
}
}
});
}
void EventListView::renameEvent(const QString &oldId, const QString &newId)
{
executeInTransaction("EventListView::renameEvent", [=]() {
for (auto node : rootModelNode().defaultNodeListProperty().toModelNodeList()) {
if (node.variantProperty("eventId").value().toString() == oldId) {
node.variantProperty("eventId").setValue(newId);
return;
}
}
});
}
void EventListView::setShortcut(const QString &id, const QString &text)
{
executeInTransaction("EventListView::setShortcut", [=]() {
for (auto node : rootModelNode().defaultNodeListProperty().toModelNodeList()) {
if (node.variantProperty("eventId").value().toString() == id) {
node.variantProperty("shortcut").setValue(text);
return;
}
}
});
}
void EventListView::setDescription(const QString &id, const QString &text)
{
executeInTransaction("EventListView::setDescription", [=]() {
for (auto node : rootModelNode().defaultNodeListProperty().toModelNodeList()) {
if (node.variantProperty("eventId").value().toString() == id) {
node.variantProperty("eventDescription").setValue(text);
return;
}
}
});
}
void EventListView::reset()
{
auto setData = [this](int row, int column, const QVariant &data) {
QModelIndex idx = m_model->index(row, column, QModelIndex());
m_model->setData(idx, data);
};
if (rootModelNode().isValid()) {
m_model->removeRows(0, m_model->rowCount(QModelIndex()), QModelIndex());
for (auto itemNode : rootModelNode().directSubModelNodes()) {
int row = m_model->rowCount();
if (m_model->insertRows(row, 1, QModelIndex())) {
QVariant eventId = itemNode.variantProperty("eventId").value();
QVariant eventShortcut = itemNode.variantProperty("shortcut").value();
QVariant eventDescription = itemNode.variantProperty("eventDescription").value();
setData(row, EventListModel::idColumn, eventId);
setData(row, EventListModel::shortcutColumn, eventShortcut);
setData(row, EventListModel::descriptionColumn, eventDescription);
}
}
}
}
} // namespace QmlDesigner.

View File

@@ -0,0 +1,98 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#pragma once
#include "eventlist.h"
#include <abstractview.h>
#include <QStandardItemModel>
namespace QmlDesigner {
struct Event
{
QString eventId;
QString shortcut;
QString description;
};
class EventListModel : public QStandardItemModel
{
Q_OBJECT
public:
enum Columns {
idColumn = 0,
descriptionColumn = 1,
shortcutColumn = 2,
connectColumn = 3
};
enum Roles : unsigned int {
connectedRole = Qt::UserRole + 1,
};
EventListModel(QObject *parent = nullptr);
QStringList connectedEvents() const;
QStringList connectEvents(const QStringList &eventIds);
};
class EventListDialog;
class AssignEventDialog;
class ConnectSignalDialog;
class EventListView : public AbstractView
{
Q_OBJECT
public:
explicit EventListView(QObject *parent = nullptr);
~EventListView() override;
void nodeRemoved(const ModelNode &removedNode,
const NodeAbstractProperty &parentProperty,
PropertyChangeFlags propertyChange) override;
void nodeReparented(const ModelNode &node,
const NodeAbstractProperty &newPropertyParent,
const NodeAbstractProperty &oldPropertyParent,
PropertyChangeFlags propertyChange) override;
EventListModel *eventListModel() const;
void addEvent(const Event &event);
void removeEvent(const QString &name);
void renameEvent(const QString &oldId, const QString &newId);
void setShortcut(const QString &id, const QString &text);
void setDescription(const QString &id, const QString &text);
private:
void reset();
EventList m_eventlist;
EventListModel *m_model;
};
} // namespace QmlDesigner.

View File

@@ -0,0 +1,64 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#include "filterlinewidget.h"
#include <theme.h>
#include <utils/fancylineedit.h>
#include <utils/stylehelper.h>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
namespace QmlDesigner {
FilterLineWidget::FilterLineWidget(QWidget *parent)
: QWidget(parent)
, m_edit(new Utils::FancyLineEdit())
{
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(18, 18)));
label->setAlignment(Qt::AlignCenter);
m_edit->setPlaceholderText(QObject::tr("<Filter>", "Library search input hint text"));
m_edit->setDragEnabled(false);
m_edit->setMinimumWidth(75);
m_edit->setTextMargins(0, 0, 20, 0);
m_edit->setFiltering(true);
auto *box = new QHBoxLayout;
box->addWidget(label);
box->addWidget(m_edit);
setLayout(box);
connect(m_edit, &Utils::FancyLineEdit::filterChanged, this, &FilterLineWidget::filterChanged);
}
void FilterLineWidget::clear()
{
m_edit->clear();
}
} // namespace QmlDesigner.

View File

@@ -0,0 +1,47 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#pragma once
#include <QWidget>
namespace Utils {
class FancyLineEdit;
}
namespace QmlDesigner {
class FilterLineWidget : public QWidget
{
Q_OBJECT
signals:
void filterChanged(const QString &filter);
public:
FilterLineWidget(QWidget *parent = nullptr);
void clear();
private:
Utils::FancyLineEdit *m_edit;
};
} // namespace QmlDesigner.

View File

@@ -0,0 +1,86 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#include "nodelistdelegate.h"
#include "eventlist.h"
#include "eventlistview.h"
#include "nodelistview.h"
#include "qnamespace.h"
#include "shortcutwidget.h"
#include "eventlistutils.h"
#include <QApplication>
#include <QFocusEvent>
#include <QLineEdit>
#include <QPainter>
#include <QPushButton>
#include <QSortFilterProxyModel>
#include <QStyleOptionButton>
namespace QmlDesigner {
NodeListDelegate::NodeListDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{}
void NodeListDelegate::setModelData(QWidget *editor,
QAbstractItemModel *model,
const QModelIndex &index) const
{
if (index.column() == NodeListModel::idColumn) {
if (auto *edit = qobject_cast<QLineEdit *>(editor)) {
QVariant iidVariant = index.data(NodeListModel::internalIdRole);
if (iidVariant.isValid()) {
QString verifiedId = EventList::setNodeId(iidVariant.toInt(), edit->text());
if (!verifiedId.isNull())
edit->setText(verifiedId);
else
edit->setText("");
}
}
}
QStyledItemDelegate::setModelData(editor, model, index);
}
bool NodeListDelegate::eventFilter(QObject *editor, QEvent *event)
{
if (event->type() == QEvent::KeyPress) {
int key = static_cast<QKeyEvent *>(event)->key();
if (key == Qt::Key_Tab || key == Qt::Key_Backtab)
return false;
}
return QStyledItemDelegate::eventFilter(editor, event);
}
void NodeListDelegate::commitAndClose()
{
if (auto *editor = qobject_cast<ShortcutWidget *>(sender())) {
emit commitData(editor);
emit closeEditor(editor);
}
}
void NodeListDelegate::close()
{
if (auto *editor = qobject_cast<ShortcutWidget *>(sender()))
emit closeEditor(editor);
}
} // namespace QmlDesigner.

View File

@@ -0,0 +1,43 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#pragma once
#include <QStyledItemDelegate>
namespace QmlDesigner {
class NodeListDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
NodeListDelegate(QObject *parent = nullptr);
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
protected:
bool eventFilter(QObject *editor, QEvent *event) override;
private:
void close();
void commitAndClose();
};
} // namespace QmlDesigner.

View File

@@ -0,0 +1,246 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#include "nodelistview.h"
#include "eventlist.h"
#include "bindingproperty.h"
#include "nodemetainfo.h"
#include "utils/qtcassert.h"
#include "variantproperty.h"
#include <QStandardItemModel>
#include <theme.h>
#include <utils/stylehelper.h>
namespace QmlDesigner {
QStringList eventIdsFromVariant(const QVariant &val)
{
QStringList eventIds = val.toString().split(",", Qt::SkipEmptyParts);
for (QString &str : eventIds)
str = str.trimmed();
return eventIds;
}
QVariant eventIdsToVariant(const QStringList &eventIds)
{
if (eventIds.empty())
return QVariant();
return QVariant(eventIds.join(", "));
}
NodeListModel::NodeListModel(QObject *parent)
: QStandardItemModel(0, 4, parent)
{
setHeaderData(idColumn, Qt::Horizontal, tr("Id"));
setHeaderData(typeColumn, Qt::Horizontal, tr("Type"));
setHeaderData(fromColumn, Qt::Horizontal, tr("From"));
setHeaderData(toColumn, Qt::Horizontal, tr("To"));
setSortRole(internalIdRole);
}
NodeListView::NodeListView(AbstractView *parent)
: AbstractView(parent)
, m_itemModel(new NodeListModel(this))
{
parent->model()->attachView(this);
reset();
}
NodeListView::~NodeListView() {}
QStandardItemModel *NodeListView::itemModel() const
{
return m_itemModel;
}
int NodeListView::currentNode() const
{
ModelNode node = firstSelectedModelNode();
if (node.isValid())
return node.internalId();
return -1;
}
void NodeListView::selectNode(int internalId)
{
ModelNode node = modelNodeForInternalId(internalId);
if (node.isValid()) {
clearSelectedModelNodes();
selectModelNode(node);
}
}
QModelIndex indexByInternalId(QAbstractItemModel *model, int id)
{
constexpr int count = 1;
auto ids = model->match(model->index(0, NodeListModel::idColumn),
NodeListModel::internalIdRole,
id,
count,
Qt::MatchExactly);
if (ids.size() == count)
return ids.first();
return QModelIndex();
}
bool NodeListView::addEventId(int nodeId, const QString &event)
{
if (auto node = compatibleModelNode(nodeId); node.isValid()) {
QStringList events;
if (node.hasProperty("eventIds"))
events = eventIdsFromVariant(node.variantProperty("eventIds").value());
events.push_back(event);
return setEventIds(node, events);
}
return false;
}
bool NodeListView::removeEventIds(int nodeId, const QStringList &eventIds)
{
if (auto node = compatibleModelNode(nodeId); node.isValid()) {
QStringList events = eventIdsFromVariant(node.variantProperty("eventIds").value());
for (auto &&remove : eventIds)
Q_UNUSED(events.removeOne(remove));
return setEventIds(node, events);
}
return false;
}
QString NodeListView::setNodeId(int internalId, const QString &id)
{
ModelNode node = modelNodeForInternalId(internalId);
if (node.isValid()) {
QString newId = generateNewId(id);
node.setIdWithRefactoring(newId);
return newId;
}
return QString();
}
bool supported(const ModelNode &node)
{
if (!node.isValid())
return false;
const NodeMetaInfo metaInfo = node.metaInfo();
if (!metaInfo.isValid())
return false;
return metaInfo.hasProperty("eventIds");
}
static QIcon flowTypeIconFromFont(const TypeName &type)
{
QString unicode = Theme::getIconUnicode(Theme::Icon::edit);
const QString fontName = "qtds_propertyIconFont.ttf";
if (type == "FlowView.FlowTransition")
unicode = Theme::getIconUnicode(Theme::Icon::flowTransition);
else if (type == "FlowView.FlowActionArea")
unicode = Theme::getIconUnicode(Theme::Icon::flowAction);
else if (type == "FlowView.FlowWildcard")
unicode = Theme::getIconUnicode(Theme::Icon::wildcard);
return Utils::StyleHelper::getIconFromIconFont(fontName, unicode, 28, 28);
}
void NodeListView::reset()
{
auto setData = [this](int row, int column, const QVariant &data, int role = Qt::EditRole) {
QModelIndex idx = m_itemModel->index(row, column, QModelIndex());
m_itemModel->setData(idx, data, role);
};
m_itemModel->removeRows(0, m_itemModel->rowCount(QModelIndex()), QModelIndex());
for (auto &&node : allModelNodes()) {
if (supported(node)) {
int row = m_itemModel->rowCount();
if (m_itemModel->insertRows(row, 1, QModelIndex())) {
int iid = node.internalId();
auto eventIds = eventIdsFromVariant(node.variantProperty("eventIds").value());
setData(row, NodeListModel::idColumn, node.id());
setData(row,
NodeListModel::idColumn,
flowTypeIconFromFont(node.type()),
Qt::DecorationRole);
setData(row, NodeListModel::idColumn, iid, NodeListModel::internalIdRole);
setData(row, NodeListModel::idColumn, eventIds, NodeListModel::eventIdsRole);
setData(row, NodeListModel::typeColumn, node.type());
setData(row, NodeListModel::fromColumn, node.bindingProperty("from").expression());
setData(row, NodeListModel::toColumn, node.bindingProperty("to").expression());
}
}
}
m_itemModel->sort(0);
}
ModelNode NodeListView::compatibleModelNode(int nodeId)
{
if (auto node = modelNodeForInternalId(nodeId); node.isValid()) {
QTC_ASSERT(node.metaInfo().isValid(), return ModelNode());
QTC_ASSERT(node.metaInfo().hasProperty("eventIds"), return ModelNode());
return node;
}
return ModelNode();
}
bool setEventIdsInModelNode(AbstractView *view, const ModelNode &node, const QStringList &events)
{
if (events.empty()) {
if (node.hasProperty("eventIds")) {
return view->executeInTransaction("NodeListView::setEventIds",
[=]() { node.removeProperty("eventIds"); });
}
} else {
QStringList copy(events);
Q_UNUSED(copy.removeDuplicates());
QString value = events.join(", ");
return view->executeInTransaction("NodeListView::setEventIds", [=]() {
node.variantProperty("eventIds").setValue(value);
});
}
return false;
}
bool NodeListView::setEventIds(const ModelNode &node, const QStringList &events)
{
bool result = setEventIdsInModelNode(this, node, events);
auto modelIndex = indexByInternalId(m_itemModel, node.internalId());
if (modelIndex.isValid() && result) {
m_itemModel->setData(modelIndex, events, NodeListModel::eventIdsRole);
return true;
}
return false;
}
} // namespace QmlDesigner.

View File

@@ -0,0 +1,74 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#pragma once
#include <abstractview.h>
#include <QStandardItemModel>
namespace QmlDesigner {
class NodeListModel : public QStandardItemModel
{
Q_OBJECT
public:
enum Columns : unsigned int {
idColumn = 0,
typeColumn = 1,
fromColumn = 2,
toColumn = 3
};
enum Roles : unsigned int {
internalIdRole = Qt::UserRole + 1,
eventIdsRole = Qt::UserRole + 2
};
NodeListModel(QObject *parent = nullptr);
};
class NodeListView : public AbstractView
{
Q_OBJECT
public:
explicit NodeListView(AbstractView *parent);
~NodeListView() override;
int currentNode() const;
QStandardItemModel *itemModel() const;
void reset();
void selectNode(int internalId);
bool addEventId(int nodeId, const QString &event);
bool removeEventIds(int nodeId, const QStringList &events);
QString setNodeId(int internalId, const QString &id);
private:
ModelNode compatibleModelNode(int nodeId);
bool setEventIds(const ModelNode &node, const QStringList &events);
QStandardItemModel *m_itemModel;
};
} // namespace QmlDesigner.

View File

@@ -0,0 +1,91 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#include "nodeselectionmodel.h"
#include "eventlist.h"
#include "nodelistview.h"
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
namespace QmlDesigner {
NodeSelectionModel::NodeSelectionModel(QAbstractItemModel *model)
: QItemSelectionModel(model)
{}
void NodeSelectionModel::select(const QItemSelection &selection,
QItemSelectionModel::SelectionFlags command)
{
QItemSelectionModel::select(selection, command);
for (auto &&modelIndex : selection.indexes()) {
if (modelIndex.column() == NodeListModel::idColumn) {
int id = modelIndex.data(NodeListModel::internalIdRole).toInt();
EventList::selectNode(id);
emit nodeSelected(modelIndex.data(NodeListModel::eventIdsRole).toStringList());
}
}
}
QList<int> NodeSelectionModel::selectedNodes() const
{
QList<int> out;
for (auto index : selectedRows())
out.push_back(index.data(NodeListModel::internalIdRole).toInt());
return out;
}
void NodeSelectionModel::selectNode(int nodeId)
{
if (nodeId < 0) {
clearSelection();
return;
}
if (auto *model = qobject_cast<QAbstractItemModel *>(this->model())) {
auto start = model->index(0, 0);
auto indexes = model->match(start,
NodeListModel::internalIdRole,
QString::number(nodeId),
1,
Qt::MatchExactly);
for (auto index : indexes)
QItemSelectionModel::select(index, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
}
}
void NodeSelectionModel::storeSelection()
{
if (const auto *proxyModel = qobject_cast<const QSortFilterProxyModel *>(model())) {
if (hasSelection())
m_stored = proxyModel->mapSelectionToSource(selection());
}
}
void NodeSelectionModel::reselect()
{
if (const auto *proxyModel = qobject_cast<const QSortFilterProxyModel *>(model()))
select(proxyModel->mapSelectionFromSource(m_stored),
QItemSelectionModel::Select | QItemSelectionModel::Rows);
}
} // namespace QmlDesigner.

View File

@@ -0,0 +1,49 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#pragma once
#include <QItemSelectionModel>
namespace QmlDesigner {
class NodeSelectionModel : public QItemSelectionModel
{
Q_OBJECT
signals:
void nodeSelected(const QStringList &events);
public:
NodeSelectionModel(QAbstractItemModel *model);
void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) override;
QList<int> selectedNodes() const;
void selectNode(int nodeId);
void storeSelection();
void reselect();
private:
QItemSelection m_stored;
};
} // namespace QmlDesigner.

View File

@@ -0,0 +1,114 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#include "shortcutwidget.h"
#include <QApplication>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QResizeEvent>
namespace QmlDesigner {
ShortcutWidget::ShortcutWidget(QWidget *parent)
: QWidget(parent)
, m_text(new QLineEdit)
, m_button(new QPushButton("R"))
, m_key({{0, 0, 0, 0}})
, m_keyNum(0)
{
connect(m_button, &QPushButton::pressed, this, &ShortcutWidget::done);
auto *box = new QHBoxLayout;
box->setContentsMargins(0, 0, 0, 0);
box->setSpacing(0);
box->addWidget(m_text);
box->addWidget(m_button);
setLayout(box);
m_text->setReadOnly(true);
m_text->setFocusPolicy(Qt::NoFocus);
}
bool ShortcutWidget::containsFocus() const
{
if (auto *fw = QApplication::focusWidget())
if (fw->parentWidget() == this)
return true;
return false;
}
QString ShortcutWidget::text() const
{
return m_text->text();
}
void ShortcutWidget::reset()
{
emit cancel();
}
void ShortcutWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
int width = event->size().width();
m_text->setFixedWidth(width * 3 / 4);
m_button->setFixedWidth(width / 4);
}
// Forked from qt-creator/shortcutsettings.cpp
static int translateModifiers(Qt::KeyboardModifiers state, const QString &text)
{
int result = 0;
// The shift modifier only counts when it is not used to type a symbol
// that is only reachable using the shift key anyway
if ((state & Qt::ShiftModifier)
&& (text.isEmpty() || !text.at(0).isPrint() || text.at(0).isLetterOrNumber()
|| text.at(0).isSpace()))
result |= Qt::SHIFT;
if (state & Qt::ControlModifier)
result |= Qt::CTRL;
if (state & Qt::MetaModifier)
result |= Qt::META;
if (state & Qt::AltModifier)
result |= Qt::ALT;
return result;
}
void ShortcutWidget::recordKeysequence(QKeyEvent *event)
{
int nextKey = event->key();
if (m_keyNum > 3 || nextKey == Qt::Key_Control || nextKey == Qt::Key_Shift
|| nextKey == Qt::Key_Meta || nextKey == Qt::Key_Alt) {
return;
}
nextKey |= translateModifiers(event->modifiers(), event->text());
m_key[m_keyNum] = nextKey;
m_keyNum++;
event->accept();
auto sequence = QKeySequence(m_key[0], m_key[1], m_key[2], m_key[3]);
m_text->setText(sequence.toString());
}
} // namespace QmlDesigner.

View File

@@ -0,0 +1,57 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd
** All rights reserved.
** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
**
** This file is part of the Qt Event List module.
**
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** If you have questions regarding the use of this file, please use
** contact form at http://www.qt.io/contact-us
**
******************************************************************************/
#pragma once
#include <array>
#include <QWidget>
QT_FORWARD_DECLARE_CLASS(QLineEdit)
QT_FORWARD_DECLARE_CLASS(QPushButton)
namespace QmlDesigner {
class ShortcutWidget : public QWidget
{
Q_OBJECT
signals:
void done();
void cancel();
public:
ShortcutWidget(QWidget *parent = nullptr);
bool containsFocus() const;
QString text() const;
void reset();
void recordKeysequence(QKeyEvent *event);
protected:
void resizeEvent(QResizeEvent *event) override;
private:
QLineEdit *m_text;
QPushButton *m_button;
std::array<int, 4> m_key;
int m_keyNum = 0;
};
} // namespace QmlDesigner.

View File

@@ -43,6 +43,7 @@
#include <texttool/texttool.h>
#include <timelineeditor/timelineview.h>
#include <transitioneditor/transitioneditorview.h>
#include <eventlist/eventlistpluginview.h>
#include <pathtool/pathtool.h>
#include <qmljseditor/qmljseditor.h>
@@ -254,6 +255,10 @@ bool QmlDesignerPlugin::delayedInitialize()
auto curveEditorView = new QmlDesigner::CurveEditorView;
d->viewManager.registerViewTakingOwnership(curveEditorView);
auto eventlistView = new QmlDesigner::EventListPluginView;
d->viewManager.registerViewTakingOwnership(eventlistView);
eventlistView->registerActions();
}
auto transitionEditorView = new QmlDesigner::TransitionEditorView;

View File

@@ -35,6 +35,7 @@ include(components/richtexteditor/richtexteditor.pri)
include(components/transitioneditor/transitioneditor.pri)
include(components/listmodeleditor/listmodeleditor.pri)
include(components/previewtooltip/previewtooltipbackend.pri)
include(components/eventlist/eventlistplugin.pri)
BUILD_PUPPET_IN_CREATOR_BINPATH = $$(BUILD_PUPPET_IN_CREATOR_BINPATH)
!isEmpty(BUILD_PUPPET_IN_CREATOR_BINPATH) {

View File

@@ -51,6 +51,7 @@ Project {
"components/integration",
"components/propertyeditor",
"components/edit3d",
"components/eventlist",
"components/formeditor",
"components/itemlibrary",
"components/navigator",
@@ -841,8 +842,37 @@ Project {
"curveeditor/detail/treemodel.h",
"curveeditor/detail/treeview.cpp",
"curveeditor/detail/treeview.h",
"curveeditor/detail/utils.cpp",
"curveeditor/detail/utils.h",
"curveeditor/detail/curveeditorutils.cpp",
"curveeditor/detail/curveeditorutils.h",
"eventlist/assigneventdialog.cpp",
"eventlist/assigneventdialog.h",
"eventlist/connectsignaldialog.cpp",
"eventlist/connectsignaldialog.h",
"eventlist/eventlist.cpp",
"eventlist/eventlist.h",
"eventlist/eventlistactions.cpp",
"eventlist/eventlistactions.h",
"eventlist/eventlistdelegate.cpp",
"eventlist/eventlistdelegate.h",
"eventlist/eventlistdialog.cpp",
"eventlist/eventlistdialog.h",
"eventlist/eventlistplugin.qrc",
"eventlist/eventlistpluginview.cpp",
"eventlist/eventlistpluginview.h",
"eventlist/eventlistutils.cpp",
"eventlist/eventlistutils.h",
"eventlist/eventlistview.cpp",
"eventlist/eventlistview.h",
"eventlist/filterlinewidget.cpp",
"eventlist/filterlinewidget.h",
"eventlist/nodelistdelegate.cpp",
"eventlist/nodelistdelegate.h",
"eventlist/nodelistview.cpp",
"eventlist/nodelistview.h",
"eventlist/nodeselectionmodel.cpp",
"eventlist/nodeselectionmodel.h",
"eventlist/shortcutwidget.cpp",
"eventlist/shortcutwidget.h",
"pathtool/controlpoint.cpp",
"pathtool/controlpoint.h",
"pathtool/cubicsegment.cpp",