QmlDesigner: Split messaging and process for puppets

This will make it easier to implement custom puppets. The new connection
manager will restucture the code and it add a mechanism to capture data
too.

Task-number: QDS-2529
Change-Id: I5d15c3303ef1c9a3e25ba197d350e0d561ce813a
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2020-07-27 18:14:33 +02:00
parent b5d59c75a7
commit e43c7fdb1d
46 changed files with 1738 additions and 835 deletions

View File

@@ -0,0 +1,107 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QMetaType>
#include "imagecontainer.h"
namespace QmlDesigner {
class CapturedDataCommand
{
public:
struct NodeData
{
friend QDataStream &operator<<(QDataStream &out, const NodeData &data)
{
out << data.nodeId;
out << data.contentRect;
out << data.sceneTransform;
out << data.text;
return out;
}
friend QDataStream &operator>>(QDataStream &in, NodeData &data)
{
in >> data.nodeId;
in >> data.contentRect;
in >> data.sceneTransform;
in >> data.text;
return in;
}
qint32 nodeId = -1;
QRectF contentRect;
QTransform sceneTransform;
QString text;
};
struct StateData
{
friend QDataStream &operator<<(QDataStream &out, const StateData &data)
{
out << data.image;
out << data.nodeData;
return out;
}
friend QDataStream &operator>>(QDataStream &in, StateData &data)
{
in >> data.image;
in >> data.nodeData;
return in;
}
ImageContainer image;
QVector<NodeData> nodeData;
};
friend QDataStream &operator<<(QDataStream &out, const CapturedDataCommand &command)
{
out << command.stateData;
return out;
}
friend QDataStream &operator>>(QDataStream &in, CapturedDataCommand &command)
{
in >> command.stateData;
return in;
}
public:
QVector<StateData> stateData;
};
} // namespace QmlDesigner
Q_DECLARE_METATYPE(QmlDesigner::CapturedDataCommand)

View File

@@ -1,69 +1,70 @@
INCLUDEPATH += $$PWD/ INCLUDEPATH += $$PWD
HEADERS += $$PWD/synchronizecommand.h HEADERS += $$PWD/synchronizecommand.h \ \
HEADERS += $$PWD/changepreviewimagesizecommand.h $$PWD/captureddatacommand.h \
HEADERS += $$PWD/changelanguagecommand.h $$PWD/changepreviewimagesizecommand.h \
HEADERS += $$PWD//debugoutputcommand.h $$PWD/changelanguagecommand.h \
HEADERS += $$PWD/endpuppetcommand.h $$PWD//debugoutputcommand.h \
HEADERS += $$PWD/tokencommand.h $$PWD/endpuppetcommand.h \
HEADERS += $$PWD/componentcompletedcommand.h $$PWD/tokencommand.h \
HEADERS += $$PWD/completecomponentcommand.h $$PWD/componentcompletedcommand.h \
HEADERS += $$PWD/statepreviewimagechangedcommand.h $$PWD/completecomponentcommand.h \
HEADERS += $$PWD/childrenchangedcommand.h $$PWD/statepreviewimagechangedcommand.h \
HEADERS += $$PWD/changebindingscommand.h $$PWD/childrenchangedcommand.h \
HEADERS += $$PWD/changefileurlcommand.h $$PWD/changebindingscommand.h \
HEADERS += $$PWD/changeidscommand.h $$PWD/changefileurlcommand.h \
HEADERS += $$PWD/changenodesourcecommand.h $$PWD/changeidscommand.h \
HEADERS += $$PWD/changestatecommand.h $$PWD/changenodesourcecommand.h \
HEADERS += $$PWD/changevaluescommand.h $$PWD/changestatecommand.h \
HEADERS += $$PWD/createscenecommand.h $$PWD/changevaluescommand.h \
HEADERS += $$PWD/clearscenecommand.h $$PWD/createscenecommand.h \
HEADERS += $$PWD/createinstancescommand.h $$PWD/clearscenecommand.h \
HEADERS += $$PWD/informationchangedcommand.h $$PWD/createinstancescommand.h \
HEADERS += $$PWD/pixmapchangedcommand.h $$PWD/informationchangedcommand.h \
HEADERS += $$PWD/removeinstancescommand.h $$PWD/pixmapchangedcommand.h \
HEADERS += $$PWD/removepropertiescommand.h $$PWD/removeinstancescommand.h \
HEADERS += $$PWD/reparentinstancescommand.h $$PWD/removepropertiescommand.h \
HEADERS += $$PWD/valueschangedcommand.h $$PWD/reparentinstancescommand.h \
HEADERS += $$PWD/changeauxiliarycommand.h $$PWD/valueschangedcommand.h \
HEADERS += $$PWD/removesharedmemorycommand.h $$PWD/changeauxiliarycommand.h \
HEADERS += $$PWD/puppetalivecommand.h $$PWD/removesharedmemorycommand.h \
HEADERS += $$PWD/changeselectioncommand.h $$PWD/puppetalivecommand.h \
HEADERS += $$PWD/update3dviewstatecommand.h $$PWD/changeselectioncommand.h \
HEADERS += $$PWD/puppettocreatorcommand.h $$PWD/update3dviewstatecommand.h \
HEADERS += $$PWD/inputeventcommand.h $$PWD/puppettocreatorcommand.h \
HEADERS += $$PWD/view3dactioncommand.h $$PWD/inputeventcommand.h \
$$PWD/view3dactioncommand.h
SOURCES += $$PWD/synchronizecommand.cpp SOURCES += $$PWD/synchronizecommand.cpp \
SOURCES += $$PWD/changepreviewimagesizecommand.cpp $$PWD/changepreviewimagesizecommand.cpp \
SOURCES += $$PWD/changelanguagecommand.cpp $$PWD/changelanguagecommand.cpp \
SOURCES += $$PWD/debugoutputcommand.cpp $$PWD/debugoutputcommand.cpp \
SOURCES += $$PWD/endpuppetcommand.cpp $$PWD/endpuppetcommand.cpp \
SOURCES += $$PWD/tokencommand.cpp $$PWD/tokencommand.cpp \
SOURCES += $$PWD/componentcompletedcommand.cpp $$PWD/componentcompletedcommand.cpp \
SOURCES += $$PWD/completecomponentcommand.cpp $$PWD/completecomponentcommand.cpp \
SOURCES += $$PWD/statepreviewimagechangedcommand.cpp $$PWD/statepreviewimagechangedcommand.cpp \
SOURCES += $$PWD/childrenchangedcommand.cpp $$PWD/childrenchangedcommand.cpp \
SOURCES += $$PWD/changebindingscommand.cpp $$PWD/changebindingscommand.cpp \
SOURCES += $$PWD/changefileurlcommand.cpp $$PWD/changefileurlcommand.cpp \
SOURCES += $$PWD/changeidscommand.cpp $$PWD/changeidscommand.cpp \
SOURCES += $$PWD/changenodesourcecommand.cpp $$PWD/changenodesourcecommand.cpp \
SOURCES += $$PWD/changestatecommand.cpp $$PWD/changestatecommand.cpp \
SOURCES += $$PWD/changevaluescommand.cpp $$PWD/changevaluescommand.cpp \
SOURCES += $$PWD/informationchangedcommand.cpp $$PWD/informationchangedcommand.cpp \
SOURCES += $$PWD/removeinstancescommand.cpp $$PWD/removeinstancescommand.cpp \
SOURCES += $$PWD/removepropertiescommand.cpp $$PWD/removepropertiescommand.cpp \
SOURCES += $$PWD/reparentinstancescommand.cpp $$PWD/reparentinstancescommand.cpp \
SOURCES += $$PWD/valueschangedcommand.cpp $$PWD/valueschangedcommand.cpp \
SOURCES += $$PWD/clearscenecommand.cpp $$PWD/clearscenecommand.cpp \
SOURCES += $$PWD/createinstancescommand.cpp $$PWD/createinstancescommand.cpp \
SOURCES += $$PWD/createscenecommand.cpp $$PWD/createscenecommand.cpp \
SOURCES += $$PWD/pixmapchangedcommand.cpp $$PWD/pixmapchangedcommand.cpp \
SOURCES += $$PWD/changeauxiliarycommand.cpp $$PWD/changeauxiliarycommand.cpp \
SOURCES += $$PWD/removesharedmemorycommand.cpp $$PWD/removesharedmemorycommand.cpp \
SOURCES += $$PWD/puppetalivecommand.cpp $$PWD/puppetalivecommand.cpp \
SOURCES += $$PWD/changeselectioncommand.cpp $$PWD/changeselectioncommand.cpp \
SOURCES += $$PWD/update3dviewstatecommand.cpp $$PWD/update3dviewstatecommand.cpp \
SOURCES += $$PWD/puppettocreatorcommand.cpp $$PWD/puppettocreatorcommand.cpp \
SOURCES += $$PWD/inputeventcommand.cpp $$PWD/inputeventcommand.cpp \
SOURCES += $$PWD/view3dactioncommand.cpp $$PWD/view3dactioncommand.cpp

View File

@@ -35,6 +35,7 @@
#include "nodeinstanceserverinterface.h" #include "nodeinstanceserverinterface.h"
#include "captureddatacommand.h"
#include "changeauxiliarycommand.h" #include "changeauxiliarycommand.h"
#include "changebindingscommand.h" #include "changebindingscommand.h"
#include "changefileurlcommand.h" #include "changefileurlcommand.h"
@@ -84,12 +85,11 @@ constexpr void (QLocalSocket::*LocalSocketErrorFunction)(QLocalSocket::LocalSock
#endif #endif
NodeInstanceClientProxy::NodeInstanceClientProxy(QObject *parent) NodeInstanceClientProxy::NodeInstanceClientProxy(QObject *parent)
: QObject(parent), : QObject(parent)
m_inputIoDevice(nullptr), , m_inputIoDevice(nullptr)
m_outputIoDevice(nullptr), , m_outputIoDevice(nullptr)
m_nodeInstanceServer(nullptr), , m_writeCommandCounter(0)
m_writeCommandCounter(0), , m_synchronizeId(-1)
m_synchronizeId(-1)
{ {
connect(&m_puppetAliveTimer, &QTimer::timeout, this, &NodeInstanceClientProxy::sendPuppetAliveCommand); connect(&m_puppetAliveTimer, &QTimer::timeout, this, &NodeInstanceClientProxy::sendPuppetAliveCommand);
m_puppetAliveTimer.setInterval(2000); m_puppetAliveTimer.setInterval(2000);
@@ -174,7 +174,8 @@ bool compareCommands(const QVariant &command, const QVariant &controlCommand)
else if (command.userType() == debugOutputCommandType) else if (command.userType() == debugOutputCommandType)
return command.value<DebugOutputCommand>() == controlCommand.value<DebugOutputCommand>(); return command.value<DebugOutputCommand>() == controlCommand.value<DebugOutputCommand>();
else if (command.userType() == changeSelectionCommandType) else if (command.userType() == changeSelectionCommandType)
return command.value<ChangeSelectionCommand>() == controlCommand.value<ChangeSelectionCommand>(); return command.value<ChangeSelectionCommand>()
== controlCommand.value<ChangeSelectionCommand>();
} }
return false; return false;
@@ -267,6 +268,11 @@ void NodeInstanceClientProxy::handlePuppetToCreatorCommand(const PuppetToCreator
writeCommand(QVariant::fromValue(command)); writeCommand(QVariant::fromValue(command));
} }
void NodeInstanceClientProxy::capturedData(const CapturedDataCommand &command)
{
writeCommand(QVariant::fromValue(command));
}
void NodeInstanceClientProxy::flush() void NodeInstanceClientProxy::flush()
{ {
} }
@@ -365,12 +371,13 @@ void NodeInstanceClientProxy::sendPuppetAliveCommand()
NodeInstanceServerInterface *NodeInstanceClientProxy::nodeInstanceServer() const NodeInstanceServerInterface *NodeInstanceClientProxy::nodeInstanceServer() const
{ {
return m_nodeInstanceServer; return m_nodeInstanceServer.get();
} }
void NodeInstanceClientProxy::setNodeInstanceServer(NodeInstanceServerInterface *nodeInstanceServer) void NodeInstanceClientProxy::setNodeInstanceServer(
std::unique_ptr<NodeInstanceServerInterface> nodeInstanceServer)
{ {
m_nodeInstanceServer = nodeInstanceServer; m_nodeInstanceServer = std::move(nodeInstanceServer);
} }
void NodeInstanceClientProxy::createInstances(const CreateInstancesCommand &command) void NodeInstanceClientProxy::createInstances(const CreateInstancesCommand &command)

View File

@@ -69,7 +69,7 @@ class NodeInstanceClientProxy : public QObject, public NodeInstanceClientInterfa
Q_OBJECT Q_OBJECT
public: public:
NodeInstanceClientProxy(QObject *parent = nullptr); NodeInstanceClientProxy(QObject *parent);
void informationChanged(const InformationChangedCommand &command) override; void informationChanged(const InformationChangedCommand &command) override;
void valuesChanged(const ValuesChangedCommand &command) override; void valuesChanged(const ValuesChangedCommand &command) override;
@@ -83,6 +83,7 @@ public:
void puppetAlive(const PuppetAliveCommand &command); void puppetAlive(const PuppetAliveCommand &command);
void selectionChanged(const ChangeSelectionCommand &command) override; void selectionChanged(const ChangeSelectionCommand &command) override;
void handlePuppetToCreatorCommand(const PuppetToCreatorCommand &command) override; void handlePuppetToCreatorCommand(const PuppetToCreatorCommand &command) override;
void capturedData(const CapturedDataCommand &capturedData) override;
void flush() override; void flush() override;
void synchronizeWithClientProcess() override; void synchronizeWithClientProcess() override;
@@ -94,7 +95,7 @@ protected:
void writeCommand(const QVariant &command); void writeCommand(const QVariant &command);
void dispatchCommand(const QVariant &command); void dispatchCommand(const QVariant &command);
NodeInstanceServerInterface *nodeInstanceServer() const; NodeInstanceServerInterface *nodeInstanceServer() const;
void setNodeInstanceServer(NodeInstanceServerInterface *nodeInstanceServer); void setNodeInstanceServer(std::unique_ptr<NodeInstanceServerInterface> nodeInstanceServer);
void createInstances(const CreateInstancesCommand &command); void createInstances(const CreateInstancesCommand &command);
void changeFileUrl(const ChangeFileUrlCommand &command); void changeFileUrl(const ChangeFileUrlCommand &command);
@@ -130,7 +131,7 @@ private:
QTimer m_puppetAliveTimer; QTimer m_puppetAliveTimer;
QIODevice *m_inputIoDevice; QIODevice *m_inputIoDevice;
QIODevice *m_outputIoDevice; QIODevice *m_outputIoDevice;
NodeInstanceServerInterface *m_nodeInstanceServer; std::unique_ptr<NodeInstanceServerInterface> m_nodeInstanceServer;
quint32 m_writeCommandCounter; quint32 m_writeCommandCounter;
int m_synchronizeId; int m_synchronizeId;
}; };

View File

@@ -42,6 +42,7 @@ class DebugOutputCommand;
class PuppetAliveCommand; class PuppetAliveCommand;
class ChangeSelectionCommand; class ChangeSelectionCommand;
class PuppetToCreatorCommand; class PuppetToCreatorCommand;
class CapturedDataCommand;
class NodeInstanceClientInterface class NodeInstanceClientInterface
{ {
@@ -57,6 +58,7 @@ public:
virtual void debugOutput(const DebugOutputCommand &command) = 0; virtual void debugOutput(const DebugOutputCommand &command) = 0;
virtual void selectionChanged(const ChangeSelectionCommand &command) = 0; virtual void selectionChanged(const ChangeSelectionCommand &command) = 0;
virtual void handlePuppetToCreatorCommand(const PuppetToCreatorCommand &command) = 0; virtual void handlePuppetToCreatorCommand(const PuppetToCreatorCommand &command) = 0;
virtual void capturedData(const CapturedDataCommand &command) = 0;
virtual void flush() {} virtual void flush() {}
virtual void synchronizeWithClientProcess() {} virtual void synchronizeWithClientProcess() {}

View File

@@ -27,16 +27,17 @@
#include <qmetatype.h> #include <qmetatype.h>
#include "addimportcontainer.h" #include "addimportcontainer.h"
#include "captureddatacommand.h"
#include "changeauxiliarycommand.h" #include "changeauxiliarycommand.h"
#include "changebindingscommand.h" #include "changebindingscommand.h"
#include "changefileurlcommand.h" #include "changefileurlcommand.h"
#include "changeidscommand.h" #include "changeidscommand.h"
#include "changelanguagecommand.h" #include "changelanguagecommand.h"
#include "changenodesourcecommand.h" #include "changenodesourcecommand.h"
#include "changepreviewimagesizecommand.h"
#include "changeselectioncommand.h" #include "changeselectioncommand.h"
#include "changestatecommand.h" #include "changestatecommand.h"
#include "changevaluescommand.h" #include "changevaluescommand.h"
#include "changepreviewimagesizecommand.h"
#include "childrenchangedcommand.h" #include "childrenchangedcommand.h"
#include "clearscenecommand.h" #include "clearscenecommand.h"
#include "completecomponentcommand.h" #include "completecomponentcommand.h"
@@ -219,6 +220,9 @@ void NodeInstanceServerInterface::registerCommands()
qRegisterMetaType<ChangePreviewImageSizeCommand>("ChangePreviewImageSizeCommand"); qRegisterMetaType<ChangePreviewImageSizeCommand>("ChangePreviewImageSizeCommand");
qRegisterMetaTypeStreamOperators<ChangePreviewImageSizeCommand>("ChangePreviewImageSizeCommand"); qRegisterMetaTypeStreamOperators<ChangePreviewImageSizeCommand>("ChangePreviewImageSizeCommand");
qRegisterMetaType<CapturedDataCommand>("CapturedDataCommand");
qRegisterMetaTypeStreamOperators<CapturedDataCommand>("CapturedDataCommand");
} }
} }

View File

@@ -60,11 +60,6 @@ class NodeInstanceServerInterface : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
enum RunModus {
NormalModus,
TestModus // No preview images and synchronized
};
explicit NodeInstanceServerInterface(QObject *parent = nullptr); explicit NodeInstanceServerInterface(QObject *parent = nullptr);
virtual void createInstances(const CreateInstancesCommand &command) = 0; virtual void createInstances(const CreateInstancesCommand &command) = 0;

View File

@@ -5,52 +5,54 @@ versionAtLeast(QT_VERSION, 5.15.0):qtHaveModule(quick3d) {
DEFINES *= QUICK3D_MODULE DEFINES *= QUICK3D_MODULE
} }
HEADERS += $$PWD/qt5nodeinstanceserver.h HEADERS += $$PWD/qt5nodeinstanceserver.h \
HEADERS += $$PWD/qt5testnodeinstanceserver.h $$PWD/qt5capturenodeinstanceserver.h \
HEADERS += $$PWD/qt5informationnodeinstanceserver.h $$PWD/qt5testnodeinstanceserver.h \
HEADERS += $$PWD/qt5rendernodeinstanceserver.h $$PWD/qt5informationnodeinstanceserver.h \
HEADERS += $$PWD/qt5previewnodeinstanceserver.h $$PWD/qt5rendernodeinstanceserver.h \
HEADERS += $$PWD/qt5nodeinstanceclientproxy.h $$PWD/qt5previewnodeinstanceserver.h \
HEADERS += $$PWD/quickitemnodeinstance.h $$PWD/qt5nodeinstanceclientproxy.h \
HEADERS += $$PWD/behaviornodeinstance.h $$PWD/quickitemnodeinstance.h \
HEADERS += $$PWD/dummycontextobject.h $$PWD/behaviornodeinstance.h \
HEADERS += $$PWD/childrenchangeeventfilter.h $$PWD/dummycontextobject.h \
HEADERS += $$PWD/componentnodeinstance.h $$PWD/childrenchangeeventfilter.h \
HEADERS += $$PWD/dummynodeinstance.h $$PWD/componentnodeinstance.h \
HEADERS += $$PWD/nodeinstanceserver.h $$PWD/dummynodeinstance.h \
HEADERS += $$PWD/nodeinstancesignalspy.h $$PWD/nodeinstanceserver.h \
HEADERS += $$PWD/objectnodeinstance.h $$PWD/nodeinstancesignalspy.h \
HEADERS += $$PWD/qmlpropertychangesnodeinstance.h $$PWD/objectnodeinstance.h \
HEADERS += $$PWD/qmlstatenodeinstance.h $$PWD/qmlpropertychangesnodeinstance.h \
HEADERS += $$PWD/qmltransitionnodeinstance.h $$PWD/qmlstatenodeinstance.h \
HEADERS += $$PWD/servernodeinstance.h $$PWD/qmltransitionnodeinstance.h \
HEADERS += $$PWD/anchorchangesnodeinstance.h $$PWD/servernodeinstance.h \
HEADERS += $$PWD/positionernodeinstance.h $$PWD/anchorchangesnodeinstance.h \
HEADERS += $$PWD/layoutnodeinstance.h $$PWD/positionernodeinstance.h \
HEADERS += $$PWD/qt3dpresentationnodeinstance.h $$PWD/layoutnodeinstance.h \
HEADERS += $$PWD/quick3dnodeinstance.h $$PWD/qt3dpresentationnodeinstance.h \
$$PWD/quick3dnodeinstance.h
SOURCES += $$PWD/qt5nodeinstanceserver.cpp SOURCES += $$PWD/qt5nodeinstanceserver.cpp \
SOURCES += $$PWD/qt5testnodeinstanceserver.cpp $$PWD/qt5capturenodeinstanceserver.cpp \
SOURCES += $$PWD/qt5informationnodeinstanceserver.cpp $$PWD/qt5testnodeinstanceserver.cpp \
SOURCES += $$PWD/qt5rendernodeinstanceserver.cpp $$PWD/qt5informationnodeinstanceserver.cpp \
SOURCES += $$PWD/qt5previewnodeinstanceserver.cpp $$PWD/qt5rendernodeinstanceserver.cpp \
SOURCES += $$PWD/qt5nodeinstanceclientproxy.cpp $$PWD/qt5previewnodeinstanceserver.cpp \
SOURCES += $$PWD/quickitemnodeinstance.cpp $$PWD/qt5nodeinstanceclientproxy.cpp \
SOURCES += $$PWD/behaviornodeinstance.cpp $$PWD/quickitemnodeinstance.cpp \
SOURCES += $$PWD/dummycontextobject.cpp $$PWD/behaviornodeinstance.cpp \
SOURCES += $$PWD/childrenchangeeventfilter.cpp $$PWD/dummycontextobject.cpp \
SOURCES += $$PWD/componentnodeinstance.cpp $$PWD/childrenchangeeventfilter.cpp \
SOURCES += $$PWD/dummynodeinstance.cpp $$PWD/componentnodeinstance.cpp \
SOURCES += $$PWD/nodeinstanceserver.cpp $$PWD/dummynodeinstance.cpp \
SOURCES += $$PWD/nodeinstancesignalspy.cpp $$PWD/nodeinstanceserver.cpp \
SOURCES += $$PWD/objectnodeinstance.cpp $$PWD/nodeinstancesignalspy.cpp \
SOURCES += $$PWD/qmlpropertychangesnodeinstance.cpp $$PWD/objectnodeinstance.cpp \
SOURCES += $$PWD/qmlstatenodeinstance.cpp $$PWD/qmlpropertychangesnodeinstance.cpp \
SOURCES += $$PWD/qmltransitionnodeinstance.cpp $$PWD/qmlstatenodeinstance.cpp \
SOURCES += $$PWD/servernodeinstance.cpp $$PWD/qmltransitionnodeinstance.cpp \
SOURCES += $$PWD/anchorchangesnodeinstance.cpp $$PWD/servernodeinstance.cpp \
SOURCES += $$PWD/positionernodeinstance.cpp $$PWD/anchorchangesnodeinstance.cpp \
SOURCES += $$PWD/layoutnodeinstance.cpp $$PWD/positionernodeinstance.cpp \
SOURCES += $$PWD/qt3dpresentationnodeinstance.cpp $$PWD/layoutnodeinstance.cpp \
SOURCES += $$PWD/quick3dnodeinstance.cpp $$PWD/qt3dpresentationnodeinstance.cpp \
$$PWD/quick3dnodeinstance.cpp

View File

@@ -179,6 +179,8 @@ NodeInstanceServer::NodeInstanceServer(NodeInstanceClientInterface *nodeInstance
m_childrenChangeEventFilter(new Internal::ChildrenChangeEventFilter(this)), m_childrenChangeEventFilter(new Internal::ChildrenChangeEventFilter(this)),
m_nodeInstanceClient(nodeInstanceClient) m_nodeInstanceClient(nodeInstanceClient)
{ {
m_idInstances.reserve(1000);
qmlRegisterType<DummyContextObject>("QmlDesigner", 1, 0, "DummyContextObject"); qmlRegisterType<DummyContextObject>("QmlDesigner", 1, 0, "DummyContextObject");
connect(m_childrenChangeEventFilter.data(), &Internal::ChildrenChangeEventFilter::childrenChanged, this, &NodeInstanceServer::emitParentChanged); connect(m_childrenChangeEventFilter.data(), &Internal::ChildrenChangeEventFilter::childrenChanged, this, &NodeInstanceServer::emitParentChanged);
@@ -226,8 +228,8 @@ ServerNodeInstance NodeInstanceServer::instanceForId(qint32 id) const
if (id < 0) if (id < 0)
return ServerNodeInstance(); return ServerNodeInstance();
Q_ASSERT(m_idInstanceHash.contains(id)); Q_ASSERT(m_idInstances.size() > id);
return m_idInstanceHash.value(id); return m_idInstances[id];
} }
bool NodeInstanceServer::hasInstanceForId(qint32 id) const bool NodeInstanceServer::hasInstanceForId(qint32 id) const
@@ -235,7 +237,7 @@ bool NodeInstanceServer::hasInstanceForId(qint32 id) const
if (id < 0) if (id < 0)
return false; return false;
return m_idInstanceHash.contains(id) && m_idInstanceHash.value(id).isValid(); return m_idInstances.size() > id && m_idInstances[id].isValid();
} }
ServerNodeInstance NodeInstanceServer::instanceForObject(QObject *object) const ServerNodeInstance NodeInstanceServer::instanceForObject(QObject *object) const
@@ -790,7 +792,7 @@ void NodeInstanceServer::removeAllInstanceRelationships()
instance.makeInvalid(); instance.makeInvalid();
} }
m_idInstanceHash.clear(); m_idInstances.clear();
m_objectInstanceHash.clear(); m_objectInstanceHash.clear();
} }
@@ -1243,10 +1245,11 @@ void NodeInstanceServer::notifyPropertyChange(qint32 instanceid, const PropertyN
void NodeInstanceServer::insertInstanceRelationship(const ServerNodeInstance &instance) void NodeInstanceServer::insertInstanceRelationship(const ServerNodeInstance &instance)
{ {
Q_ASSERT(instance.isValid()); Q_ASSERT(instance.isValid());
Q_ASSERT(!m_idInstanceHash.contains(instance.instanceId()));
Q_ASSERT(!m_objectInstanceHash.contains(instance.internalObject())); Q_ASSERT(!m_objectInstanceHash.contains(instance.internalObject()));
m_objectInstanceHash.insert(instance.internalObject(), instance); m_objectInstanceHash.insert(instance.internalObject(), instance);
m_idInstanceHash.insert(instance.instanceId(), instance); if (instance.instanceId() >= m_idInstances.size())
m_idInstances.resize(instance.instanceId() + 1);
m_idInstances[instance.instanceId()] = instance;
} }
void NodeInstanceServer::removeInstanceRelationsip(qint32 instanceId) void NodeInstanceServer::removeInstanceRelationsip(qint32 instanceId)
@@ -1255,7 +1258,7 @@ void NodeInstanceServer::removeInstanceRelationsip(qint32 instanceId)
ServerNodeInstance instance = instanceForId(instanceId); ServerNodeInstance instance = instanceForId(instanceId);
if (instance.isValid()) if (instance.isValid())
instance.setId(QString()); instance.setId(QString());
m_idInstanceHash.remove(instanceId); m_idInstances[instanceId] = ServerNodeInstance{};
m_objectInstanceHash.remove(instance.internalObject()); m_objectInstanceHash.remove(instance.internalObject());
instance.makeInvalid(); instance.makeInvalid();
} }
@@ -1383,8 +1386,8 @@ void NodeInstanceServer::removeInstanceRelationsipForDeletedObject(QObject *obje
ServerNodeInstance instance = instanceForObject(object); ServerNodeInstance instance = instanceForObject(object);
m_objectInstanceHash.remove(object); m_objectInstanceHash.remove(object);
if (m_idInstanceHash.contains(instance.instanceId())) if (instance.instanceId() >= 0 && m_idInstances.size() > instance.instanceId())
m_idInstanceHash.remove(instance.instanceId()); m_idInstances[instance.instanceId()] = ServerNodeInstance{};
} }
} }

View File

@@ -160,6 +160,8 @@ public:
ServerNodeInstance instanceForObject(QObject *object) const; ServerNodeInstance instanceForObject(QObject *object) const;
bool hasInstanceForObject(QObject *object) const; bool hasInstanceForObject(QObject *object) const;
const QVector<ServerNodeInstance> &nodeInstances() const { return m_idInstances; }
virtual QQmlEngine *engine() const = 0; virtual QQmlEngine *engine() const = 0;
QQmlContext *context() const; QQmlContext *context() const;
@@ -272,7 +274,7 @@ private:
void setupOnlyWorkingImports(const QStringList &workingImportStatementList); void setupOnlyWorkingImports(const QStringList &workingImportStatementList);
ServerNodeInstance m_rootNodeInstance; ServerNodeInstance m_rootNodeInstance;
ServerNodeInstance m_activeStateInstance; ServerNodeInstance m_activeStateInstance;
QHash<qint32, ServerNodeInstance> m_idInstanceHash; QVector<ServerNodeInstance> m_idInstances;
QHash<QObject*, ServerNodeInstance> m_objectInstanceHash; QHash<QObject*, ServerNodeInstance> m_objectInstanceHash;
QMultiHash<QString, ObjectPropertyPair> m_fileSystemWatcherHash; QMultiHash<QString, ObjectPropertyPair> m_fileSystemWatcherHash;
QList<QPair<QString, QPointer<QObject> > > m_dummyObjectList; QList<QPair<QString, QPointer<QObject> > > m_dummyObjectList;

View File

@@ -0,0 +1,105 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qt5capturenodeinstanceserver.h"
#include "servernodeinstance.h"
#include <captureddatacommand.h>
#include <createscenecommand.h>
#include <nodeinstanceclientinterface.h>
#include <QImage>
#include <QQuickView>
namespace QmlDesigner {
namespace {
QImage renderPreviewImage(ServerNodeInstance rootNodeInstance)
{
rootNodeInstance.updateDirtyNodeRecursive();
QSize previewImageSize = rootNodeInstance.boundingRect().size().toSize();
QImage previewImage = rootNodeInstance.renderPreviewImage(previewImageSize);
return previewImage;
}
CapturedDataCommand::StateData collectStateData(ServerNodeInstance rootNodeInstance,
const QVector<ServerNodeInstance> &nodeInstances,
qint32 stateInstanceId)
{
CapturedDataCommand::StateData stateData;
stateData.image = ImageContainer(stateInstanceId,
QmlDesigner::renderPreviewImage(rootNodeInstance),
stateInstanceId);
for (const ServerNodeInstance &instance : nodeInstances) {
auto textProperty = instance.property("text");
if (!textProperty.isNull() && instance.holdsGraphical()) {
CapturedDataCommand::NodeData nodeData;
nodeData.nodeId = instance.instanceId();
nodeData.contentRect = instance.contentItemBoundingRect();
nodeData.sceneTransform = instance.sceneTransform();
nodeData.text = textProperty.toString();
stateData.nodeData.push_back(std::move(nodeData));
}
}
return stateData;
}
} // namespace
void Qt5CaptureNodeInstanceServer::collectItemChangesAndSendChangeCommands()
{
static bool inFunction = false;
if (!rootNodeInstance().holdsGraphical())
return;
if (!inFunction) {
inFunction = true;
DesignerSupport::polishItems(quickView());
QVector<CapturedDataCommand::StateData> stateDatas;
stateDatas.push_back(collectStateData(rootNodeInstance(), nodeInstances(), 0));
for (ServerNodeInstance stateInstance : rootNodeInstance().stateInstances()) {
stateInstance.activateState();
stateDatas.push_back(
collectStateData(rootNodeInstance(), nodeInstances(), stateInstance.instanceId()));
stateInstance.deactivateState();
}
nodeInstanceClient()->capturedData(CapturedDataCommand{stateDatas});
slowDownRenderTimer();
inFunction = false;
}
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,45 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <qt5previewnodeinstanceserver.h>
namespace QmlDesigner {
class Qt5CaptureNodeInstanceServer : public Qt5PreviewNodeInstanceServer
{
public:
explicit Qt5CaptureNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient)
: Qt5PreviewNodeInstanceServer(nodeInstanceClient)
{}
protected:
void collectItemChangesAndSendChangeCommands() override;
private:
};
} // namespace QmlDesigner

View File

@@ -27,6 +27,7 @@
#include <QCoreApplication> #include <QCoreApplication>
#include "qt5capturenodeinstanceserver.h"
#include "qt5informationnodeinstanceserver.h" #include "qt5informationnodeinstanceserver.h"
#include "qt5previewnodeinstanceserver.h" #include "qt5previewnodeinstanceserver.h"
#include "qt5rendernodeinstanceserver.h" #include "qt5rendernodeinstanceserver.h"
@@ -37,7 +38,7 @@
#if defined(Q_OS_UNIX) #if defined(Q_OS_UNIX)
#include <unistd.h> #include <unistd.h>
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
#include <windows.h> #include <Windows.h>
#endif #endif
namespace QmlDesigner { namespace QmlDesigner {
@@ -57,18 +58,21 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) :
DesignerSupport::activateDesignerWindowManager(); DesignerSupport::activateDesignerWindowManager();
if (QCoreApplication::arguments().at(1) == QLatin1String("--readcapturedstream")) { if (QCoreApplication::arguments().at(1) == QLatin1String("--readcapturedstream")) {
qputenv("DESIGNER_DONT_USE_SHARED_MEMORY", "1"); qputenv("DESIGNER_DONT_USE_SHARED_MEMORY", "1");
setNodeInstanceServer(new Qt5TestNodeInstanceServer(this)); setNodeInstanceServer(std::make_unique<Qt5TestNodeInstanceServer>(this));
initializeCapturedStream(QCoreApplication::arguments().at(2)); initializeCapturedStream(QCoreApplication::arguments().at(2));
readDataStream(); readDataStream();
QCoreApplication::exit(); QCoreApplication::exit();
} else if (QCoreApplication::arguments().at(2) == QLatin1String("previewmode")) { } else if (QCoreApplication::arguments().at(2) == QLatin1String("previewmode")) {
setNodeInstanceServer(new Qt5PreviewNodeInstanceServer(this)); setNodeInstanceServer(std::make_unique<Qt5PreviewNodeInstanceServer>(this));
initializeSocket(); initializeSocket();
} else if (QCoreApplication::arguments().at(2) == QLatin1String("editormode")) { } else if (QCoreApplication::arguments().at(2) == QLatin1String("editormode")) {
setNodeInstanceServer(new Qt5InformationNodeInstanceServer(this)); setNodeInstanceServer(std::make_unique<Qt5InformationNodeInstanceServer>(this));
initializeSocket(); initializeSocket();
} else if (QCoreApplication::arguments().at(2) == QLatin1String("rendermode")) { } else if (QCoreApplication::arguments().at(2) == QLatin1String("rendermode")) {
setNodeInstanceServer(new Qt5RenderNodeInstanceServer(this)); setNodeInstanceServer(std::make_unique<Qt5RenderNodeInstanceServer>(this));
initializeSocket();
} else if (QCoreApplication::arguments().at(2) == QLatin1String("capturemode")) {
setNodeInstanceServer(std::make_unique<Qt5CaptureNodeInstanceServer>(this));
initializeSocket(); initializeSocket();
} }
} }

View File

@@ -84,7 +84,8 @@ void Qt5PreviewNodeInstanceServer::collectItemChangesAndSendChangeCommands()
instance.deactivateState(); instance.deactivateState();
} }
nodeInstanceClient()->statePreviewImagesChanged(StatePreviewImageChangedCommand(imageContainerVector)); nodeInstanceClient()->statePreviewImagesChanged(
StatePreviewImageChangedCommand(imageContainerVector));
slowDownRenderTimer(); slowDownRenderTimer();
inFunction = false; inFunction = false;

View File

@@ -71,6 +71,7 @@ class ServerNodeInstance
friend class Qt5InformationNodeInstanceServer; friend class Qt5InformationNodeInstanceServer;
friend class Qt5NodeInstanceServer; friend class Qt5NodeInstanceServer;
friend class Qt5PreviewNodeInstanceServer; friend class Qt5PreviewNodeInstanceServer;
friend class Qt5CaptureNodeInstanceServer;
friend class Qt5TestNodeInstanceServer; friend class Qt5TestNodeInstanceServer;
friend class QHash<qint32, ServerNodeInstance>; friend class QHash<qint32, ServerNodeInstance>;
friend uint qHash(const ServerNodeInstance &instance); friend uint qHash(const ServerNodeInstance &instance);
@@ -169,6 +170,8 @@ public:
static bool isSubclassOf(QObject *object, const QByteArray &superTypeName); static bool isSubclassOf(QObject *object, const QByteArray &superTypeName);
void setModifiedFlag(bool b); void setModifiedFlag(bool b);
void updateDirtyNodeRecursive();
bool holdsGraphical() const;
private: // functions private: // functions
ServerNodeInstance(const QSharedPointer<Internal::ObjectNodeInstance> &abstractInstance); ServerNodeInstance(const QSharedPointer<Internal::ObjectNodeInstance> &abstractInstance);
@@ -195,7 +198,6 @@ private: // functions
void setDeleteHeldInstance(bool deleteInstance); void setDeleteHeldInstance(bool deleteInstance);
void reparent(const ServerNodeInstance &oldParentInstance, const PropertyName &oldParentProperty, const ServerNodeInstance &newParentInstance, const PropertyName &newParentProperty); void reparent(const ServerNodeInstance &oldParentInstance, const PropertyName &oldParentProperty, const ServerNodeInstance &newParentInstance, const PropertyName &newParentProperty);
void setId(const QString &id); void setId(const QString &id);
static QSharedPointer<Internal::ObjectNodeInstance> createInstance(QObject *objectToBeWrapped); static QSharedPointer<Internal::ObjectNodeInstance> createInstance(QObject *objectToBeWrapped);
@@ -204,10 +206,6 @@ private: // functions
void setNodeSource(const QString &source); void setNodeSource(const QString &source);
bool holdsGraphical() const;
void updateDirtyNodeRecursive();
QObject *internalObject() const; // should be not used outside of the nodeinstances!!!! QObject *internalObject() const; // should be not used outside of the nodeinstances!!!!
private: // variables private: // variables

View File

@@ -505,6 +505,12 @@ extend_qtc_plugin(QmlDesigner
puppetbuildprogressdialog.cpp puppetbuildprogressdialog.h puppetbuildprogressdialog.ui puppetbuildprogressdialog.cpp puppetbuildprogressdialog.h puppetbuildprogressdialog.ui
puppetcreator.cpp puppetcreator.h puppetcreator.cpp puppetcreator.h
puppetdialog.cpp puppetdialog.h puppetdialog.ui puppetdialog.cpp puppetdialog.h puppetdialog.ui
connectionmanagerinterface.cpp connectionmanagerinterface.h
baseconnectionmanager.cpp baseconnectionmanager.h
connectionmanager.cpp connectionmanager.h
capturingconnectionmanager.cpp capturingconnectionmanager.h
interactiveconnectionmanager.cpp interactiveconnectionmanager.h
qprocessuniqueptr.h
) )
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner

View File

@@ -86,7 +86,7 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
if (!isCancelled()) { if (!isCancelled()) {
// Wait for icon generation processes to finish // Wait for icon generation processes to finish
if (m_qmlPuppetProcesses.isEmpty()) { if (m_qmlPuppetProcesses.empty()) {
finalizeQuick3DImport(); finalizeQuick3DImport();
} else { } else {
m_qmlPuppetCount = m_qmlPuppetProcesses.size(); m_qmlPuppetCount = m_qmlPuppetProcesses.size();
@@ -186,10 +186,12 @@ void ItemLibraryAssetImporter::processFinished(int exitCode, QProcess::ExitStatu
auto process = qobject_cast<QProcess *>(sender()); auto process = qobject_cast<QProcess *>(sender());
if (process) { if (process) {
m_qmlPuppetProcesses.remove(process); m_qmlPuppetProcesses.erase(
process->deleteLater(); std::remove_if(m_qmlPuppetProcesses.begin(),
m_qmlPuppetProcesses.end(),
[&](const auto &entry) { return entry.get() == process; }));
const QString progressTitle = tr("Generating icons."); const QString progressTitle = tr("Generating icons.");
if (m_qmlPuppetProcesses.isEmpty()) { if (m_qmlPuppetProcesses.empty()) {
notifyProgress(100, progressTitle); notifyProgress(100, progressTitle);
finalizeQuick3DImport(); finalizeQuick3DImport();
} else { } else {
@@ -215,7 +217,6 @@ void ItemLibraryAssetImporter::reset()
m_tempDir = new QTemporaryDir; m_tempDir = new QTemporaryDir;
m_importFiles.clear(); m_importFiles.clear();
m_overwrittenImports.clear(); m_overwrittenImports.clear();
qDeleteAll(m_qmlPuppetProcesses);
m_qmlPuppetProcesses.clear(); m_qmlPuppetProcesses.clear();
m_qmlPuppetCount = 0; m_qmlPuppetCount = 0;
#endif #endif
@@ -498,16 +499,21 @@ bool ItemLibraryAssetImporter::generateComponentIcon(int size, const QString &ic
puppetCreator.createQml2PuppetExecutableIfMissing(); puppetCreator.createQml2PuppetExecutableIfMissing();
QStringList puppetArgs; QStringList puppetArgs;
puppetArgs << "--rendericon" << QString::number(size) << iconFile << iconSource; puppetArgs << "--rendericon" << QString::number(size) << iconFile << iconSource;
QProcess *process = puppetCreator.createPuppetProcess( QProcessUniquePointer process = puppetCreator.createPuppetProcess(
"custom", {}, this, "", SLOT(processFinished(int, QProcess::ExitStatus)), puppetArgs); "custom",
{},
this,
std::function<void()>(),
[&](int exitCode, QProcess::ExitStatus exitStatus) {
processFinished(exitCode, exitStatus);
},
puppetArgs);
if (process->waitForStarted(5000)) { if (process->waitForStarted(5000)) {
connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), m_qmlPuppetProcesses.push_back(std::move(process));
process, &QProcess::deleteLater);
m_qmlPuppetProcesses << process;
return true; return true;
} else { } else {
delete process; process.reset();
} }
} }
return false; return false;

View File

@@ -24,14 +24,16 @@
****************************************************************************/ ****************************************************************************/
#pragma once #pragma once
#include "import.h"
#include <qprocessuniqueptr.h>
#include <QSet> #include <QSet>
#include <QtCore/qobject.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qhash.h> #include <QtCore/qhash.h>
#include <QtCore/qjsonobject.h> #include <QtCore/qjsonobject.h>
#include <QtCore/qobject.h>
#include <QtCore/qprocess.h> #include <QtCore/qprocess.h>
#include <QtCore/qstringlist.h>
#include "import.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QSSGAssetImportManager; class QSSGAssetImportManager;
@@ -99,7 +101,7 @@ private:
bool m_cancelled = false; bool m_cancelled = false;
QString m_importPath; QString m_importPath;
QTemporaryDir *m_tempDir = nullptr; QTemporaryDir *m_tempDir = nullptr;
QSet<QProcess *> m_qmlPuppetProcesses; std::vector<QProcessUniquePointer> m_qmlPuppetProcesses;
int m_qmlPuppetCount = 0; int m_qmlPuppetCount = 0;
}; };
} // QmlDesigner } // QmlDesigner

View File

@@ -62,6 +62,7 @@ class RemovePropertiesCommand;
class CompleteComponentCommand; class CompleteComponentCommand;
class InformationContainer; class InformationContainer;
class TokenCommand; class TokenCommand;
class ConnectionManagerInterface;
class QMLDESIGNERCORE_EXPORT NodeInstanceView : public AbstractView, public NodeInstanceClientInterface class QMLDESIGNERCORE_EXPORT NodeInstanceView : public AbstractView, public NodeInstanceClientInterface
{ {
@@ -72,7 +73,7 @@ class QMLDESIGNERCORE_EXPORT NodeInstanceView : public AbstractView, public Node
public: public:
using Pointer = QWeakPointer<NodeInstanceView>; using Pointer = QWeakPointer<NodeInstanceView>;
explicit NodeInstanceView(QObject *parent = nullptr, NodeInstanceServerInterface::RunModus runModus = NodeInstanceServerInterface::NormalModus); explicit NodeInstanceView(ConnectionManagerInterface &connectionManager);
~NodeInstanceView() override; ~NodeInstanceView() override;
void modelAttached(Model *model) override; void modelAttached(Model *model) override;
@@ -94,7 +95,7 @@ public:
void auxiliaryDataChanged(const ModelNode &node, const PropertyName &name, const QVariant &data) override; void auxiliaryDataChanged(const ModelNode &node, const PropertyName &name, const QVariant &data) override;
void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override; void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
void nodeSourceChanged(const ModelNode &modelNode, const QString &newNodeSource) override; void nodeSourceChanged(const ModelNode &modelNode, const QString &newNodeSource) override;
void capturedData(const CapturedDataCommand &capturedData) override;
void currentStateChanged(const ModelNode &node) override; void currentStateChanged(const ModelNode &node) override;
QList<NodeInstance> instances() const; QList<NodeInstance> instances() const;
@@ -142,6 +143,7 @@ protected:
void timerEvent(QTimerEvent *event) override; void timerEvent(QTimerEvent *event) override;
private: // functions private: // functions
std::unique_ptr<NodeInstanceServerProxy> createNodeInstanceServerProxy();
void activateState(const NodeInstance &instance); void activateState(const NodeInstance &instance);
void activateBaseState(); void activateBaseState();
@@ -161,9 +163,8 @@ private: // functions
void setStateInstance(const NodeInstance &stateInstance); void setStateInstance(const NodeInstance &stateInstance);
void clearStateInstance(); void clearStateInstance();
NodeInstanceServerInterface *nodeInstanceServer() const; QMultiHash<ModelNode, InformationName> informationChanged(
QMultiHash<ModelNode, InformationName> informationChanged(const QVector<InformationContainer> &containerVector); const QVector<InformationContainer> &containerVector);
CreateSceneCommand createCreateSceneCommand(); CreateSceneCommand createCreateSceneCommand();
ClearSceneCommand createClearSceneCommand() const; ClearSceneCommand createClearSceneCommand() const;
@@ -196,16 +197,15 @@ private: // functions
// puppet to creator command handlers // puppet to creator command handlers
void handlePuppetKeyPress(int key, Qt::KeyboardModifiers modifiers); void handlePuppetKeyPress(int key, Qt::KeyboardModifiers modifiers);
private:
NodeInstance m_rootNodeInstance; NodeInstance m_rootNodeInstance;
NodeInstance m_activeStateInstance; NodeInstance m_activeStateInstance;
QHash<ModelNode, NodeInstance> m_nodeInstanceHash; QHash<ModelNode, NodeInstance> m_nodeInstanceHash;
QHash<ModelNode, QImage> m_statePreviewImage; QHash<ModelNode, QImage> m_statePreviewImage;
ConnectionManagerInterface &m_connectionManager;
QPointer<NodeInstanceServerProxy> m_nodeInstanceServer; std::unique_ptr<NodeInstanceServerProxy> m_nodeInstanceServer;
QImage m_baseStatePreviewImage; QImage m_baseStatePreviewImage;
QElapsedTimer m_lastCrashTime; QElapsedTimer m_lastCrashTime;
NodeInstanceServerInterface::RunModus m_runModus;
ProjectExplorer::Target *m_currentTarget = nullptr; ProjectExplorer::Target *m_currentTarget = nullptr;
int m_restartProcessTimerId; int m_restartProcessTimerId;
RewriterTransaction m_puppetTransaction; RewriterTransaction m_puppetTransaction;

View File

@@ -122,7 +122,7 @@ private: // functions
QList<QPointer<AbstractView>> standardViews() const; QList<QPointer<AbstractView>> standardViews() const;
private: // variables private: // variables
ViewManagerData *d; std::unique_ptr<ViewManagerData> d;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -0,0 +1,126 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "baseconnectionmanager.h"
#include "endpuppetcommand.h"
#include "nodeinstanceserverproxy.h"
#include "nodeinstanceview.h"
#include <QLocalSocket>
namespace QmlDesigner {
void BaseConnectionManager::setUp(NodeInstanceServerProxy *nodeInstanceServerProxy,
const QString &,
ProjectExplorer::Target *)
{
m_nodeInstanceServerProxy = nodeInstanceServerProxy;
m_isActive = true;
}
void BaseConnectionManager::shutDown()
{
m_isActive = false;
writeCommand(QVariant::fromValue(EndPuppetCommand()));
m_nodeInstanceServerProxy = nullptr;
}
bool BaseConnectionManager::isActive() const
{
return m_isActive;
}
void BaseConnectionManager::showCannotConnectToPuppetWarningAndSwitchToEditMode() {}
void BaseConnectionManager::processFinished()
{
processFinished(-1, QProcess::CrashExit);
}
void BaseConnectionManager::writeCommandToIODevice(const QVariant &command,
QIODevice *ioDevice,
unsigned int commandCounter)
{
if (ioDevice) {
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_8);
out << quint32(0);
out << quint32(commandCounter);
out << command;
out.device()->seek(0);
out << quint32(static_cast<unsigned long long>(block.size()) - sizeof(quint32));
ioDevice->write(block);
}
}
void BaseConnectionManager::dispatchCommand(const QVariant &command, Connection &)
{
if (!isActive())
return;
m_nodeInstanceServerProxy->dispatchCommand(command);
}
void BaseConnectionManager::readDataStream(Connection &connection)
{
QList<QVariant> commandList;
while (!connection.socket->atEnd()) {
if (connection.socket->bytesAvailable() < int(sizeof(quint32)))
break;
QDataStream in(connection.socket.get());
in.setVersion(QDataStream::Qt_4_8);
if (connection.blockSize == 0)
in >> connection.blockSize;
if (connection.socket->bytesAvailable() < connection.blockSize)
break;
quint32 commandCounter = 0;
in >> commandCounter;
bool commandLost = !((connection.lastReadCommandCounter == 0 && commandCounter == 0)
|| (connection.lastReadCommandCounter + 1 == commandCounter));
if (commandLost)
qDebug() << "server command lost: " << connection.lastReadCommandCounter << commandCounter;
connection.lastReadCommandCounter = commandCounter;
QVariant command;
in >> command;
connection.blockSize = 0;
commandList.append(command);
}
for (const QVariant &command : commandList)
dispatchCommand(command, connection);
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,76 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "connectionmanagerinterface.h"
#include <QProcess>
QT_BEGIN_NAMESPACE
class QLocalSocket;
QT_END_NAMESPACE
namespace ProjectExplorer {
class Target;
}
namespace QmlDesigner {
class AbstractView;
class NodeInstanceServerProxy;
class QMLDESIGNERCORE_EXPORT BaseConnectionManager : public QObject, public ConnectionManagerInterface
{
Q_OBJECT
public:
BaseConnectionManager() = default;
void setUp(NodeInstanceServerProxy *nodeInstanceServerProxy,
const QString &qrcMappingString,
ProjectExplorer::Target *target) override;
void shutDown() override;
bool isActive() const;
protected:
void dispatchCommand(const QVariant &command, Connection &connection) override;
virtual void showCannotConnectToPuppetWarningAndSwitchToEditMode();
using ConnectionManagerInterface::processFinished;
void processFinished();
void writeCommandToIODevice(const QVariant &command,
QIODevice *ioDevice,
unsigned int commandCounter);
void readDataStream(Connection &connection);
NodeInstanceServerProxy *nodeInstanceServerProxy() const { return m_nodeInstanceServerProxy; }
private:
NodeInstanceServerProxy *m_nodeInstanceServerProxy{};
bool m_isActive = false;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,61 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "capturingconnectionmanager.h"
#include <coreplugin/messagebox.h>
namespace QmlDesigner {
void CapturingConnectionManager::setUp(NodeInstanceServerProxy *nodeInstanceServerProxy,
const QString &qrcMappingString,
ProjectExplorer::Target *target)
{
InteractiveConnectionManager::setUp(nodeInstanceServerProxy, qrcMappingString, target);
int indexOfCapturePuppetStream = QCoreApplication::arguments().indexOf(
"-capture-puppet-stream");
if (indexOfCapturePuppetStream > 0) {
m_captureFileForTest.setFileName(
QCoreApplication::arguments().at(indexOfCapturePuppetStream + 1));
bool isOpen = m_captureFileForTest.open(QIODevice::WriteOnly);
qDebug() << "file is open: " << isOpen;
}
}
void CapturingConnectionManager::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
if (m_captureFileForTest.isOpen()) {
m_captureFileForTest.close();
Core::AsynchronousMessageBox::warning(
tr("QML Emulation Layer (QML Puppet) Crashed"),
tr("You are recording a puppet stream and the emulations layer crashed. "
"It is recommended to reopen the Qt Quick Designer and start again."));
}
InteractiveConnectionManager::processFinished(exitCode, exitStatus);
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,46 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <interactiveconnectionmanager.h>
namespace QmlDesigner {
class CapturingConnectionManager : public InteractiveConnectionManager
{
public:
void setUp(NodeInstanceServerProxy *nodeInstanceServerProxy,
const QString &qrcMappingString,
ProjectExplorer::Target *target) override;
void processFinished(int exitCode, QProcess::ExitStatus exitStatus) override;
private:
QFile m_captureFileForTest;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,177 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "connectionmanager.h"
#include "endpuppetcommand.h"
#include "nodeinstanceserverproxy.h"
#include "nodeinstanceview.h"
#include "puppetcreator.h"
#ifndef QMLDESIGNER_TEST
#include <qmldesignerplugin.h>
#endif
#include <projectexplorer/target.h>
#include <QLocalServer>
#include <QLocalSocket>
#include <QUuid>
namespace QmlDesigner {
ConnectionManager::ConnectionManager() = default;
ConnectionManager::~ConnectionManager() = default;
void ConnectionManager::setUp(NodeInstanceServerProxy *nodeInstanceServerProxy,
const QString &qrcMappingString,
ProjectExplorer::Target *target)
{
BaseConnectionManager::setUp(nodeInstanceServerProxy, qrcMappingString, target);
m_localServer = std::make_unique<QLocalServer>();
QString socketToken(QUuid::createUuid().toString());
m_localServer->listen(socketToken);
m_localServer->setMaxPendingConnections(3);
NodeInstanceView *nodeInstanceView = nodeInstanceServerProxy->nodeInstanceView();
PuppetCreator puppetCreator(target, nodeInstanceView->model());
puppetCreator.setQrcMappingString(qrcMappingString);
puppetCreator.createQml2PuppetExecutableIfMissing();
for (Connection &connection : m_connections) {
connection.qmlPuppetProcess = puppetCreator.createPuppetProcess(
connection.mode,
socketToken,
nodeInstanceView,
[&] { printProcessOutput(connection.qmlPuppetProcess.get(), connection.name); },
[&](int exitCode, QProcess::ExitStatus exitStatus) {
processFinished(exitCode, exitStatus);
});
const int second = 1000;
int waitConstant = 8 * second;
if (!connection.qmlPuppetProcess->waitForStarted(waitConstant)) {
closeSocketsAndKillProcesses();
showCannotConnectToPuppetWarningAndSwitchToEditMode();
return;
}
waitConstant /= 2;
bool connectedToPuppet = true;
if (!m_localServer->hasPendingConnections())
connectedToPuppet = m_localServer->waitForNewConnection(waitConstant);
if (connectedToPuppet) {
connection.socket.reset(m_localServer->nextPendingConnection());
QObject::connect(connection.socket.get(), &QIODevice::readyRead, [&] {
readDataStream(connection);
});
} else {
closeSocketsAndKillProcesses();
showCannotConnectToPuppetWarningAndSwitchToEditMode();
return;
}
}
m_localServer->close();
connect(this,
&ConnectionManager::processCrashed,
nodeInstanceServerProxy,
&NodeInstanceServerProxy::processCrashed);
}
void ConnectionManager::shutDown()
{
BaseConnectionManager::shutDown();
closeSocketsAndKillProcesses();
m_localServer.reset();
for (Connection &connection : m_connections)
connection.clear();
}
void ConnectionManager::writeCommand(const QVariant &command)
{
for (Connection &connection : m_connections)
writeCommandToIODevice(command, connection.socket.get(), m_writeCommandCounter);
m_writeCommandCounter++;
}
void ConnectionManager::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
auto finishedProcess = qobject_cast<QProcess *>(sender());
if (finishedProcess)
qWarning() << "Process" << (exitStatus == QProcess::CrashExit ? "crashed:" : "finished:")
<< finishedProcess->arguments() << "exitCode:" << exitCode;
else
qWarning() << "Process" << (exitStatus == QProcess::CrashExit ? "crashed:" : "finished:")
<< sender() << "exitCode:" << exitCode;
writeCommand(QVariant::fromValue(EndPuppetCommand()));
closeSocketsAndKillProcesses();
if (exitStatus == QProcess::CrashExit)
emit processCrashed();
}
void ConnectionManager::closeSocketsAndKillProcesses()
{
for (Connection &connection : m_connections) {
if (connection.socket) {
disconnect(connection.socket.get());
disconnect(connection.qmlPuppetProcess.get());
connection.socket->waitForBytesWritten(1000);
connection.socket->abort();
}
if (connection.qmlPuppetProcess) {
QTimer::singleShot(3000, connection.qmlPuppetProcess.get(), &QProcess::terminate);
QTimer::singleShot(6000, connection.qmlPuppetProcess.get(), &QProcess::kill);
}
connection.clear();
}
}
void ConnectionManager::printProcessOutput(QProcess *process, const QString &connectionName)
{
while (process && process->canReadLine()) {
QByteArray line = process->readLine();
line.chop(1);
qDebug().nospace() << connectionName << " Puppet: " << line;
}
qDebug() << "\n";
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,77 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "baseconnectionmanager.h"
#include "nodeinstanceserverinterface.h"
#include <QElapsedTimer>
#include <QFile>
#include <QProcess>
QT_BEGIN_NAMESPACE
class QLocalServer;
class QLocalSocket;
QT_END_NAMESPACE
namespace QmlDesigner {
class QMLDESIGNERCORE_EXPORT ConnectionManager : public BaseConnectionManager
{
Q_OBJECT
public:
ConnectionManager();
~ConnectionManager() override;
enum PuppetStreamType { FirstPuppetStream, SecondPuppetStream, ThirdPuppetStream };
void setUp(NodeInstanceServerProxy *nodeInstanceServerProxy,
const QString &qrcMappingString,
ProjectExplorer::Target *target) override;
void shutDown() override;
void writeCommand(const QVariant &command) override;
signals:
void processCrashed();
protected:
using BaseConnectionManager::processFinished;
void processFinished(int exitCode, QProcess::ExitStatus exitStatus) override;
private:
void printProcessOutput(QProcess *process, const QString &connectionName);
void closeSocketsAndKillProcesses();
protected:
std::vector<Connection> m_connections;
quint32 m_writeCommandCounter = 0;
private:
std::unique_ptr<QLocalServer> m_localServer;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,54 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "connectionmanagerinterface.h"
#include <QLocalSocket>
#include <QProcess>
namespace QmlDesigner {
ConnectionManagerInterface::~ConnectionManagerInterface() = default;
ConnectionManagerInterface::Connection::~Connection() = default;
ConnectionManagerInterface::Connection::Connection(const QString &name, const QString &mode)
: name{name}
, mode{mode}
, timer{std::make_unique<QTimer>()}
{}
ConnectionManagerInterface::Connection::Connection(Connection &&connection) = default;
void ConnectionManagerInterface::Connection::clear()
{
qmlPuppetProcess.reset();
socket.reset();
blockSize = 0;
lastReadCommandCounter = 0;
timer->stop();
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,80 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qprocessuniqueptr.h"
#include <qmldesignercorelib_global.h>
QT_BEGIN_NAMESPACE
class QLocalSocket;
QT_END_NAMESPACE
namespace ProjectExplorer {
class Target;
}
namespace QmlDesigner {
class NodeInstanceServerProxy;
class QMLDESIGNERCORE_EXPORT ConnectionManagerInterface
{
public:
class QMLDESIGNERCORE_EXPORT Connection final
{
public:
Connection(const QString &name, const QString &mode);
Connection(Connection &&connection);
~Connection();
void clear();
public:
QString name;
QString mode;
QProcessUniquePointer qmlPuppetProcess;
std::unique_ptr<QLocalSocket> socket;
quint32 blockSize = 0;
quint32 lastReadCommandCounter = 0;
std::unique_ptr<QTimer> timer;
};
virtual ~ConnectionManagerInterface();
virtual void setUp(NodeInstanceServerProxy *nodeInstanceServerProxy,
const QString &qrcMappingString,
ProjectExplorer::Target *target)
= 0;
virtual void shutDown() = 0;
virtual void writeCommand(const QVariant &command) = 0;
protected:
virtual void dispatchCommand(const QVariant &command, Connection &connection) = 0;
virtual void processFinished(int exitCode, QProcess::ExitStatus exitStatus) = 0;
};
} // namespace QmlDesigner

View File

@@ -1,14 +1,25 @@
INCLUDEPATH += $$PWD/ INCLUDEPATH += $$PWD/
HEADERS += $$PWD/../include/nodeinstance.h HEADERS += $$PWD/../include/nodeinstance.h \
HEADERS += $$PWD/nodeinstanceserverproxy.h $$PWD/baseconnectionmanager.h \
HEADERS += $$PWD/puppetcreator.h $$PWD/capturingconnectionmanager.h \
HEADERS += $$PWD/puppetbuildprogressdialog.h $$PWD/connectionmanager.h \
$$PWD/connectionmanagerinterface.h \
$$PWD/interactiveconnectionmanager.h \
$$PWD/nodeinstanceserverproxy.h \
$$PWD/puppetcreator.h \
$$PWD/puppetbuildprogressdialog.h \
$$PWD/qprocessuniqueptr.h
SOURCES += $$PWD/nodeinstanceserverproxy.cpp SOURCES += $$PWD/nodeinstanceserverproxy.cpp \
SOURCES += $$PWD/nodeinstance.cpp $$PWD/baseconnectionmanager.cpp \
SOURCES += $$PWD/nodeinstanceview.cpp $$PWD/capturingconnectionmanager.cpp \
SOURCES += $$PWD/puppetcreator.cpp $$PWD/connectionmanager.cpp \
SOURCES += $$PWD/puppetbuildprogressdialog.cpp $$PWD/connectionmanagerinterface.cpp \
$$PWD/interactiveconnectionmanager.cpp \
$$PWD/nodeinstance.cpp \
$$PWD/nodeinstanceview.cpp \
$$PWD/puppetcreator.cpp \
$$PWD/puppetbuildprogressdialog.cpp
FORMS += $$PWD/puppetbuildprogressdialog.ui FORMS += $$PWD/puppetbuildprogressdialog.ui

View File

@@ -0,0 +1,109 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "interactiveconnectionmanager.h"
#include "nodeinstanceserverproxy.h"
#include "nodeinstanceview.h"
#include <qmldesignerplugin.h>
#include <coreplugin/messagebox.h>
#include <QLocalSocket>
namespace QmlDesigner {
InteractiveConnectionManager::InteractiveConnectionManager()
{
m_connections.emplace_back("Editor", "editormode");
m_connections.emplace_back("Render", "rendermode");
m_connections.emplace_back("Preview", "previewmode");
}
void InteractiveConnectionManager::setUp(NodeInstanceServerProxy *nodeInstanceServerProxy,
const QString &qrcMappingString,
ProjectExplorer::Target *target)
{
ConnectionManager::setUp(nodeInstanceServerProxy, qrcMappingString, target);
DesignerSettings settings = QmlDesignerPlugin::instance()->settings();
int timeOutTime = settings.value(DesignerSettingsKey::PUPPET_KILL_TIMEOUT).toInt();
for (Connection &connection : m_connections)
connection.timer->setInterval(timeOutTime);
if (QmlDesignerPlugin::instance()
->settings()
.value(DesignerSettingsKey::DEBUG_PUPPET)
.toString()
.isEmpty()) {
for (Connection &connection : m_connections) {
QObject::connect(connection.timer.get(), &QTimer::timeout, [&]() {
puppetTimeout(connection);
});
}
}
}
void InteractiveConnectionManager::showCannotConnectToPuppetWarningAndSwitchToEditMode()
{
Core::AsynchronousMessageBox::warning(
tr("Cannot Connect to QML Emulation Layer (QML Puppet)"),
tr("The executable of the QML emulation layer (QML Puppet) may not be responding. "
"Switching to another kit might help."));
QmlDesignerPlugin::instance()->switchToTextModeDeferred();
nodeInstanceServerProxy()->nodeInstanceView()->emitDocumentMessage(
tr("Cannot Connect to QML Emulation Layer (QML Puppet)"));
}
void InteractiveConnectionManager::dispatchCommand(const QVariant &command, Connection &connection)
{
static const int puppetAliveCommandType = QMetaType::type("PuppetAliveCommand");
if (command.userType() == puppetAliveCommandType) {
puppetAlive(connection);
} else {
BaseConnectionManager::dispatchCommand(command, connection);
}
}
void InteractiveConnectionManager::puppetTimeout(Connection &connection)
{
if (connection.socket && connection.socket->waitForReadyRead(10)) {
connection.timer->stop();
connection.timer->start();
return;
}
processFinished();
}
void InteractiveConnectionManager::puppetAlive(Connection &connection)
{
connection.timer->stop();
connection.timer->start();
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,51 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "connectionmanager.h"
namespace QmlDesigner {
class InteractiveConnectionManager : public ConnectionManager
{
public:
InteractiveConnectionManager();
void setUp(NodeInstanceServerProxy *nodeInstanceServerProxy,
const QString &qrcMappingString,
ProjectExplorer::Target *target) override;
void showCannotConnectToPuppetWarningAndSwitchToEditMode() override;
protected:
void dispatchCommand(const QVariant &command, Connection &connection) override;
private:
void puppetTimeout(Connection &connection);
void puppetAlive(Connection &connection);
};
} // namespace QmlDesigner

View File

@@ -25,6 +25,7 @@
#include "nodeinstanceserverproxy.h" #include "nodeinstanceserverproxy.h"
#include "connectionmanagerinterface.h"
#include "puppetcreator.h" #include "puppetcreator.h"
#include <changeauxiliarycommand.h> #include <changeauxiliarycommand.h>
@@ -60,218 +61,55 @@
#include <valueschangedcommand.h> #include <valueschangedcommand.h>
#include <view3dactioncommand.h> #include <view3dactioncommand.h>
#include <nodeinstanceview.h>
#include <import.h> #include <import.h>
#include <nodeinstanceview.h>
#include <rewriterview.h> #include <rewriterview.h>
#ifndef QMLDESIGNER_TEST
#include <qmldesignerplugin.h>
#endif
#include <coreplugin/icore.h>
#include <utils/hostosinfo.h>
#include <coreplugin/messagebox.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
#include <projectexplorer/kit.h> #include <projectexplorer/kit.h>
#include <qtsupport/qtkitinformation.h> #include <utils/hostosinfo.h>
#include <qtsupport/baseqtversion.h> #include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtsupportconstants.h> #include <qtsupport/qtsupportconstants.h>
#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QLocalServer> #include <QLocalServer>
#include <QLocalSocket> #include <QLocalSocket>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QProcess>
#include <QCoreApplication>
#include <QUuid>
#include <QFileInfo>
#include <QDir>
#include <QTimer>
#include <QTextStream>
#include <QMessageBox> #include <QMessageBox>
#include <QProcess>
#include <QTextStream>
#include <QTimer>
#include <QUuid>
namespace QmlDesigner { namespace QmlDesigner {
static Q_LOGGING_CATEGORY(instanceViewBenchmark, "qtc.nodeinstances.init", QtWarningMsg) static Q_LOGGING_CATEGORY(instanceViewBenchmark, "qtc.nodeinstances.init", QtWarningMsg);
void NodeInstanceServerProxy::showCannotConnectToPuppetWarningAndSwitchToEditMode()
{
#ifndef QMLDESIGNER_TEST
Core::AsynchronousMessageBox::warning(tr("Cannot Connect to QML Emulation Layer (QML Puppet)"),
tr("The executable of the QML emulation layer (QML Puppet) may not be responding. "
"Switching to another kit might help."));
QmlDesignerPlugin::instance()->switchToTextModeDeferred();
m_nodeInstanceView->emitDocumentMessage(tr("Cannot Connect to QML Emulation Layer (QML Puppet)"));
#endif
}
NodeInstanceServerProxy::NodeInstanceServerProxy(NodeInstanceView *nodeInstanceView, NodeInstanceServerProxy::NodeInstanceServerProxy(NodeInstanceView *nodeInstanceView,
RunModus runModus, ProjectExplorer::Target *target,
ProjectExplorer::Target *target) ConnectionManagerInterface &connectionManager)
: NodeInstanceServerInterface(nodeInstanceView), : m_nodeInstanceView(nodeInstanceView)
m_localServer(new QLocalServer(this)), , m_connectionManager{connectionManager}
m_nodeInstanceView(nodeInstanceView),
m_runModus(runModus)
{ {
if (instanceViewBenchmark().isInfoEnabled()) if (instanceViewBenchmark().isInfoEnabled())
m_benchmarkTimer.start(); m_benchmarkTimer.start();
QString socketToken(QUuid::createUuid().toString()); m_connectionManager.setUp(this, qrcMappingString(), target);
m_localServer->listen(socketToken);
m_localServer->setMaxPendingConnections(3);
PuppetCreator puppetCreator(target, nodeInstanceView->model()); qCInfo(instanceViewBenchmark) << "puppets setup:" << m_benchmarkTimer.elapsed();
puppetCreator.setQrcMappingString(qrcMappingString());
puppetCreator.createQml2PuppetExecutableIfMissing();
m_qmlPuppetEditorProcess = puppetCreator.createPuppetProcess("editormode",
socketToken,
this,
SLOT(printEditorProcessOutput()),
SLOT(processFinished(int,QProcess::ExitStatus)));
if (runModus == NormalModus) {
m_qmlPuppetRenderProcess = puppetCreator.createPuppetProcess("rendermode",
socketToken,
this,
SLOT(printRenderProcessOutput()),
SLOT(processFinished(int,QProcess::ExitStatus)));
m_qmlPuppetPreviewProcess = puppetCreator.createPuppetProcess("previewmode",
socketToken,
this,
SLOT(printPreviewProcessOutput()),
SLOT(processFinished(int,QProcess::ExitStatus)));
}
const int second = 1000;
const int waitConstant = 8 * second;
if (m_qmlPuppetEditorProcess->waitForStarted(waitConstant)) {
connect(m_qmlPuppetEditorProcess.data(), QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
m_qmlPuppetEditorProcess.data(), &QProcess::deleteLater);
qCInfo(instanceViewBenchmark) << "puppets started:" << m_benchmarkTimer.elapsed();
if (runModus == NormalModus) {
m_qmlPuppetPreviewProcess->waitForStarted(waitConstant / 2);
connect(m_qmlPuppetPreviewProcess.data(), QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
m_qmlPuppetPreviewProcess.data(), &QProcess::deleteLater);
m_qmlPuppetRenderProcess->waitForStarted(waitConstant / 2);
connect(m_qmlPuppetRenderProcess.data(), QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
m_qmlPuppetRenderProcess.data(), &QProcess::deleteLater);
}
bool connectedToPuppet = true;
if (!m_localServer->hasPendingConnections())
connectedToPuppet = m_localServer->waitForNewConnection(waitConstant / 4);
if (connectedToPuppet) {
m_firstSocket = m_localServer->nextPendingConnection();
connect(m_firstSocket.data(), &QIODevice::readyRead, this,
&NodeInstanceServerProxy::readFirstDataStream);
if (runModus == NormalModus) {
if (!m_localServer->hasPendingConnections())
connectedToPuppet = m_localServer->waitForNewConnection(waitConstant / 4);
if (connectedToPuppet) {
m_secondSocket = m_localServer->nextPendingConnection();
connect(m_secondSocket.data(), &QIODevice::readyRead, this, &NodeInstanceServerProxy::readSecondDataStream);
if (!m_localServer->hasPendingConnections())
connectedToPuppet = m_localServer->waitForNewConnection(waitConstant / 4);
qCInfo(instanceViewBenchmark) << "puppets connected:" << m_benchmarkTimer.elapsed();
if (connectedToPuppet) {
m_thirdSocket = m_localServer->nextPendingConnection();
connect(m_thirdSocket.data(), &QIODevice::readyRead, this, &NodeInstanceServerProxy::readThirdDataStream);
} else {
showCannotConnectToPuppetWarningAndSwitchToEditMode();
}
} else {
showCannotConnectToPuppetWarningAndSwitchToEditMode();
}
}
} else {
showCannotConnectToPuppetWarningAndSwitchToEditMode();
}
} else {
showCannotConnectToPuppetWarningAndSwitchToEditMode();
}
m_localServer->close();
int indexOfCapturePuppetStream = QCoreApplication::arguments().indexOf("-capture-puppet-stream");
if (indexOfCapturePuppetStream > 0) {
m_captureFileForTest.setFileName(QCoreApplication::arguments().at(indexOfCapturePuppetStream + 1));
bool isOpen = m_captureFileForTest.open(QIODevice::WriteOnly);
qDebug() << "file is open: " << isOpen;
}
#ifndef QMLDESIGNER_TEST
DesignerSettings settings = QmlDesignerPlugin::instance()->settings();
int timeOutTime = settings.value(DesignerSettingsKey::PUPPET_KILL_TIMEOUT).toInt();
m_firstTimer.setInterval(timeOutTime);
m_secondTimer.setInterval(timeOutTime);
m_thirdTimer.setInterval(timeOutTime);
if (QmlDesignerPlugin::instance()->settings().value(DesignerSettingsKey::
DEBUG_PUPPET).toString().isEmpty()) {
connect(&m_firstTimer, &QTimer::timeout, this,
[this](){ NodeInstanceServerProxy::puppetTimeout(FirstPuppetStream); });
connect(&m_secondTimer, &QTimer::timeout, this,
[this](){ NodeInstanceServerProxy::puppetTimeout(SecondPuppetStream); });
connect(&m_thirdTimer, &QTimer::timeout, this,
[this](){ NodeInstanceServerProxy::puppetTimeout(ThirdPuppetStream); });
}
#endif
} }
NodeInstanceServerProxy::~NodeInstanceServerProxy() NodeInstanceServerProxy::~NodeInstanceServerProxy()
{ {
m_destructing = true; m_connectionManager.shutDown();
disconnect(this, SLOT(processFinished(int,QProcess::ExitStatus)));
writeCommand(QVariant::fromValue(EndPuppetCommand()));
if (m_firstSocket) {
m_firstSocket->waitForBytesWritten(1000);
m_firstSocket->abort();
}
if (m_secondSocket) {
m_secondSocket->waitForBytesWritten(1000);
m_secondSocket->abort();
}
if (m_thirdSocket) {
m_thirdSocket->waitForBytesWritten(1000);
m_thirdSocket->abort();
}
if (m_qmlPuppetEditorProcess) {
QTimer::singleShot(3000, m_qmlPuppetEditorProcess.data(), &QProcess::terminate);
QTimer::singleShot(6000, m_qmlPuppetEditorProcess.data(), &QProcess::kill);
}
if (m_qmlPuppetPreviewProcess) {
QTimer::singleShot(3000, m_qmlPuppetPreviewProcess.data(), &QProcess::terminate);
QTimer::singleShot(6000, m_qmlPuppetPreviewProcess.data(), &QProcess::kill);
}
if (m_qmlPuppetRenderProcess) {
QTimer::singleShot(3000, m_qmlPuppetRenderProcess.data(), &QProcess::terminate);
QTimer::singleShot(6000, m_qmlPuppetRenderProcess.data(), &QProcess::kill);
}
} }
void NodeInstanceServerProxy::dispatchCommand(const QVariant &command, PuppetStreamType puppetStreamType) void NodeInstanceServerProxy::dispatchCommand(const QVariant &command)
{ {
static const int informationChangedCommandType = QMetaType::type("InformationChangedCommand"); static const int informationChangedCommandType = QMetaType::type("InformationChangedCommand");
static const int valuesChangedCommandType = QMetaType::type("ValuesChangedCommand"); static const int valuesChangedCommandType = QMetaType::type("ValuesChangedCommand");
@@ -280,15 +118,10 @@ void NodeInstanceServerProxy::dispatchCommand(const QVariant &command, PuppetStr
static const int childrenChangedCommandType = QMetaType::type("ChildrenChangedCommand"); static const int childrenChangedCommandType = QMetaType::type("ChildrenChangedCommand");
static const int statePreviewImageChangedCommandType = QMetaType::type("StatePreviewImageChangedCommand"); static const int statePreviewImageChangedCommandType = QMetaType::type("StatePreviewImageChangedCommand");
static const int componentCompletedCommandType = QMetaType::type("ComponentCompletedCommand"); static const int componentCompletedCommandType = QMetaType::type("ComponentCompletedCommand");
static const int synchronizeCommandType = QMetaType::type("SynchronizeCommand");
static const int tokenCommandType = QMetaType::type("TokenCommand"); static const int tokenCommandType = QMetaType::type("TokenCommand");
static const int debugOutputCommandType = QMetaType::type("DebugOutputCommand"); static const int debugOutputCommandType = QMetaType::type("DebugOutputCommand");
static const int puppetAliveCommandType = QMetaType::type("PuppetAliveCommand");
static const int changeSelectionCommandType = QMetaType::type("ChangeSelectionCommand"); static const int changeSelectionCommandType = QMetaType::type("ChangeSelectionCommand");
static const int puppetToCreatorCommand = QMetaType::type("PuppetToCreatorCommand"); static const int puppetToCreatorCommandType = QMetaType::type("PuppetToCreatorCommand");
if (m_destructing)
return;
qCInfo(instanceViewBenchmark) << "dispatching command" << command.userType() << command.typeName(); qCInfo(instanceViewBenchmark) << "dispatching command" << command.userType() << command.typeName();
if (command.userType() == informationChangedCommandType) { if (command.userType() == informationChangedCommandType) {
@@ -311,13 +144,8 @@ void NodeInstanceServerProxy::dispatchCommand(const QVariant &command, PuppetStr
nodeInstanceClient()->debugOutput(command.value<DebugOutputCommand>()); nodeInstanceClient()->debugOutput(command.value<DebugOutputCommand>());
} else if (command.userType() == changeSelectionCommandType) { } else if (command.userType() == changeSelectionCommandType) {
nodeInstanceClient()->selectionChanged(command.value<ChangeSelectionCommand>()); nodeInstanceClient()->selectionChanged(command.value<ChangeSelectionCommand>());
} else if (command.userType() == puppetToCreatorCommand) { } else if (command.userType() == puppetToCreatorCommandType) {
nodeInstanceClient()->handlePuppetToCreatorCommand(command.value<PuppetToCreatorCommand>()); nodeInstanceClient()->handlePuppetToCreatorCommand(command.value<PuppetToCreatorCommand>());
} else if (command.userType() == puppetAliveCommandType) {
puppetAlive(puppetStreamType);
} else if (command.userType() == synchronizeCommandType) {
SynchronizeCommand synchronizeCommand = command.value<SynchronizeCommand>();
m_synchronizeId = synchronizeCommand.synchronizeId();
} else { } else {
Q_ASSERT(false); Q_ASSERT(false);
} }
@@ -327,33 +155,13 @@ void NodeInstanceServerProxy::dispatchCommand(const QVariant &command, PuppetStr
NodeInstanceClientInterface *NodeInstanceServerProxy::nodeInstanceClient() const NodeInstanceClientInterface *NodeInstanceServerProxy::nodeInstanceClient() const
{ {
return m_nodeInstanceView.data(); return m_nodeInstanceView;
}
void NodeInstanceServerProxy::puppetAlive(NodeInstanceServerProxy::PuppetStreamType puppetStreamType)
{
switch (puppetStreamType) {
case FirstPuppetStream:
m_firstTimer.stop();
m_firstTimer.start();
break;
case SecondPuppetStream:
m_secondTimer.stop();
m_secondTimer.start();
break;
case ThirdPuppetStream:
m_thirdTimer.stop();
m_thirdTimer.start();
break;
default:
break;
}
} }
QString NodeInstanceServerProxy::qrcMappingString() const QString NodeInstanceServerProxy::qrcMappingString() const
{ {
if (m_nodeInstanceView && m_nodeInstanceView.data()->model()) { if (m_nodeInstanceView && m_nodeInstanceView->model()) {
RewriterView *rewriterView = m_nodeInstanceView.data()->model()->rewriterView(); RewriterView *rewriterView = m_nodeInstanceView->model()->rewriterView();
if (rewriterView) { if (rewriterView) {
QString mappingString; QString mappingString;
@@ -374,265 +182,9 @@ QString NodeInstanceServerProxy::qrcMappingString() const
return QString(); return QString();
} }
void NodeInstanceServerProxy::processFinished()
{
processFinished(-1, QProcess::CrashExit);
}
void NodeInstanceServerProxy::puppetTimeout(PuppetStreamType puppetStreamType)
{
switch (puppetStreamType) {
case FirstPuppetStream:
if (m_firstSocket->waitForReadyRead(10)) {
m_firstTimer.stop();
m_firstTimer.start();
return;
}
break;
case SecondPuppetStream:
if (m_secondSocket->waitForReadyRead(10)) {
m_secondTimer.stop();
m_secondTimer.start();
return;
}
break;
case ThirdPuppetStream:
if (m_thirdSocket->waitForReadyRead(10)) {
m_thirdTimer.stop();
m_thirdTimer.start();
return;
}
break;
default:
break;
}
processFinished();
}
static void writeCommandToIODecive(const QVariant &command, QIODevice *ioDevice, unsigned int commandCounter)
{
if (ioDevice) {
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_8);
out << quint32(0);
out << quint32(commandCounter);
out << command;
out.device()->seek(0);
out << quint32(block.size() - sizeof(quint32));
ioDevice->write(block);
}
}
void NodeInstanceServerProxy::writeCommand(const QVariant &command) void NodeInstanceServerProxy::writeCommand(const QVariant &command)
{ {
writeCommandToIODecive(command, m_firstSocket.data(), m_writeCommandCounter); m_connectionManager.writeCommand(command);
writeCommandToIODecive(command, m_secondSocket.data(), m_writeCommandCounter);
writeCommandToIODecive(command, m_thirdSocket.data(), m_writeCommandCounter);
if (m_captureFileForTest.isWritable()) {
qDebug() << "Write stream to file: " << m_captureFileForTest.fileName();
writeCommandToIODecive(command, &m_captureFileForTest, m_writeCommandCounter);
qDebug() << "\twrite file: " << m_captureFileForTest.pos();
}
m_writeCommandCounter++;
if (m_runModus == TestModus) {
static int synchronizeId = 0;
synchronizeId++;
SynchronizeCommand synchronizeCommand(synchronizeId);
writeCommandToIODecive(QVariant::fromValue(synchronizeCommand), m_firstSocket.data(), m_writeCommandCounter);
m_writeCommandCounter++;
while (m_firstSocket->waitForReadyRead(100)) {
readFirstDataStream();
if (m_synchronizeId == synchronizeId)
return;
}
}
}
void NodeInstanceServerProxy::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
auto finishedProcess = qobject_cast<QProcess*>(sender());
if (finishedProcess)
qWarning() << "Process" << (exitStatus == QProcess::CrashExit ? "crashed:" : "finished:") << finishedProcess->arguments() << "exitCode:" << exitCode;
else
qWarning() << "Process" << (exitStatus == QProcess::CrashExit ? "crashed:" : "finished:") << sender() << "exitCode:" << exitCode;
if (m_captureFileForTest.isOpen()) {
m_captureFileForTest.close();
Core::AsynchronousMessageBox::warning(tr("QML Emulation Layer (QML Puppet) Crashed"),
tr("You are recording a puppet stream and the emulations layer crashed. "
"It is recommended to reopen the Qt Quick Designer and start again."));
}
writeCommand(QVariant::fromValue(EndPuppetCommand()));
if (m_firstSocket) {
m_firstSocket->waitForBytesWritten(1000);
m_firstSocket->abort();
}
if (m_secondSocket) {
m_secondSocket->waitForBytesWritten(1000);
m_secondSocket->abort();
}
if (m_thirdSocket) {
m_thirdSocket->waitForBytesWritten(1000);
m_thirdSocket->abort();
}
if (exitStatus == QProcess::CrashExit)
emit processCrashed();
}
void NodeInstanceServerProxy::readFirstDataStream()
{
QList<QVariant> commandList;
while (!m_firstSocket->atEnd()) {
if (m_firstSocket->bytesAvailable() < int(sizeof(quint32)))
break;
QDataStream in(m_firstSocket.data());
in.setVersion(QDataStream::Qt_4_8);
if (m_firstBlockSize == 0)
in >> m_firstBlockSize;
if (m_firstSocket->bytesAvailable() < m_firstBlockSize)
break;
quint32 commandCounter;
in >> commandCounter;
bool commandLost = !((m_firstLastReadCommandCounter == 0 && commandCounter == 0) || (m_firstLastReadCommandCounter + 1 == commandCounter));
if (commandLost)
qDebug() << "server command lost: " << m_firstLastReadCommandCounter << commandCounter;
m_firstLastReadCommandCounter = commandCounter;
QVariant command;
in >> command;
m_firstBlockSize = 0;
commandList.append(command);
}
foreach (const QVariant &command, commandList) {
dispatchCommand(command, FirstPuppetStream);
}
}
void NodeInstanceServerProxy::readSecondDataStream()
{
QList<QVariant> commandList;
while (!m_secondSocket->atEnd()) {
if (m_secondSocket->bytesAvailable() < int(sizeof(quint32)))
break;
QDataStream in(m_secondSocket.data());
in.setVersion(QDataStream::Qt_4_8);
if (m_secondBlockSize == 0)
in >> m_secondBlockSize;
if (m_secondSocket->bytesAvailable() < m_secondBlockSize)
break;
quint32 commandCounter;
in >> commandCounter;
bool commandLost = !((m_secondLastReadCommandCounter == 0 && commandCounter == 0) || (m_secondLastReadCommandCounter + 1 == commandCounter));
if (commandLost)
qDebug() << "server command lost: " << m_secondLastReadCommandCounter << commandCounter;
m_secondLastReadCommandCounter = commandCounter;
QVariant command;
in >> command;
m_secondBlockSize = 0;
commandList.append(command);
}
foreach (const QVariant &command, commandList) {
dispatchCommand(command, SecondPuppetStream);
}
}
void NodeInstanceServerProxy::readThirdDataStream()
{
QList<QVariant> commandList;
while (!m_thirdSocket->atEnd()) {
if (m_thirdSocket->bytesAvailable() < int(sizeof(quint32)))
break;
QDataStream in(m_thirdSocket.data());
in.setVersion(QDataStream::Qt_4_8);
if (m_thirdBlockSize == 0)
in >> m_thirdBlockSize;
if (m_thirdSocket->bytesAvailable() < m_thirdBlockSize)
break;
quint32 commandCounter;
in >> commandCounter;
bool commandLost = !((m_thirdLastReadCommandCounter == 0 && commandCounter == 0) || (m_thirdLastReadCommandCounter + 1 == commandCounter));
if (commandLost)
qDebug() << "server command lost: " << m_thirdLastReadCommandCounter << commandCounter;
m_thirdLastReadCommandCounter = commandCounter;
QVariant command;
in >> command;
m_thirdBlockSize = 0;
commandList.append(command);
}
foreach (const QVariant &command, commandList) {
dispatchCommand(command, ThirdPuppetStream);
}
}
void NodeInstanceServerProxy::printEditorProcessOutput()
{
while (m_qmlPuppetEditorProcess && m_qmlPuppetEditorProcess->canReadLine()) {
QByteArray line = m_qmlPuppetEditorProcess->readLine();
line.chop(1);
qDebug().nospace() << "Editor Puppet: " << line;
}
qDebug() << "\n";
}
void NodeInstanceServerProxy::printPreviewProcessOutput()
{
while (m_qmlPuppetPreviewProcess && m_qmlPuppetPreviewProcess->canReadLine()) {
QByteArray line = m_qmlPuppetPreviewProcess->readLine();
line.chop(1);
qDebug().nospace() << "Preview Puppet: " << line;
}
qDebug() << "\n";
}
void NodeInstanceServerProxy::printRenderProcessOutput()
{
while (m_qmlPuppetRenderProcess && m_qmlPuppetRenderProcess->canReadLine()) {
QByteArray line = m_qmlPuppetRenderProcess->readLine();
line.chop(1);
qDebug().nospace() << "Render Puppet: " << line;
}
qDebug() << "\n";
} }
void NodeInstanceServerProxy::createInstances(const CreateInstancesCommand &command) void NodeInstanceServerProxy::createInstances(const CreateInstancesCommand &command)

View File

@@ -48,21 +48,17 @@ namespace QmlDesigner {
class NodeInstanceClientInterface; class NodeInstanceClientInterface;
class NodeInstanceView; class NodeInstanceView;
class NodeInstanceClientProxy; class NodeInstanceClientProxy;
class ConnectionManagerInterface;
class NodeInstanceServerProxy : public NodeInstanceServerInterface class NodeInstanceServerProxy : public NodeInstanceServerInterface
{ {
friend class BaseConnectionManager;
Q_OBJECT Q_OBJECT
public: public:
enum PuppetStreamType {
FirstPuppetStream,
SecondPuppetStream,
ThirdPuppetStream,
};
explicit NodeInstanceServerProxy(NodeInstanceView *nodeInstanceView, explicit NodeInstanceServerProxy(NodeInstanceView *nodeInstanceView,
RunModus runModus, ProjectExplorer::Target *target,
ProjectExplorer::Target *target); ConnectionManagerInterface &connectionManager);
~NodeInstanceServerProxy() override; ~NodeInstanceServerProxy() override;
void createInstances(const CreateInstancesCommand &command) override; void createInstances(const CreateInstancesCommand &command) override;
void changeFileUrl(const ChangeFileUrlCommand &command) override; void changeFileUrl(const ChangeFileUrlCommand &command) override;
@@ -88,52 +84,22 @@ public:
void changeLanguage(const ChangeLanguageCommand &command) override; void changeLanguage(const ChangeLanguageCommand &command) override;
void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override; void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override;
NodeInstanceView *nodeInstanceView() const { return m_nodeInstanceView; }
QString qrcMappingString() const;
protected: protected:
void writeCommand(const QVariant &command); void writeCommand(const QVariant &command);
void dispatchCommand(const QVariant &command, PuppetStreamType puppetStreamType); void dispatchCommand(const QVariant &command);
NodeInstanceClientInterface *nodeInstanceClient() const; NodeInstanceClientInterface *nodeInstanceClient() const;
void puppetAlive(PuppetStreamType puppetStreamType);
QString qrcMappingString() const;
signals: signals:
void processCrashed(); void processCrashed();
private slots:
void processFinished();
void puppetTimeout(PuppetStreamType puppetStreamType);
void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
void readFirstDataStream();
void readSecondDataStream();
void readThirdDataStream();
void printEditorProcessOutput();
void printPreviewProcessOutput();
void printRenderProcessOutput();
void showCannotConnectToPuppetWarningAndSwitchToEditMode();
private: private:
QFile m_captureFileForTest; NodeInstanceView *m_nodeInstanceView{};
QTimer m_firstTimer;
QTimer m_secondTimer;
QTimer m_thirdTimer;
QPointer<QLocalServer> m_localServer;
QPointer<QLocalSocket> m_firstSocket;
QPointer<QLocalSocket> m_secondSocket;
QPointer<QLocalSocket> m_thirdSocket;
QPointer<NodeInstanceView> m_nodeInstanceView;
QPointer<QProcess> m_qmlPuppetEditorProcess;
QPointer<QProcess> m_qmlPuppetPreviewProcess;
QPointer<QProcess> m_qmlPuppetRenderProcess;
quint32 m_firstBlockSize = 0;
quint32 m_secondBlockSize = 0;
quint32 m_thirdBlockSize = 0;
quint32 m_writeCommandCounter = 0;
quint32 m_firstLastReadCommandCounter = 0;
quint32 m_secondLastReadCommandCounter = 0;
quint32 m_thirdLastReadCommandCounter = 0;
RunModus m_runModus;
int m_synchronizeId = -1;
QElapsedTimer m_benchmarkTimer; QElapsedTimer m_benchmarkTimer;
bool m_destructing = false; ConnectionManagerInterface &m_connectionManager;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -27,6 +27,7 @@
#include "abstractproperty.h" #include "abstractproperty.h"
#include "bindingproperty.h" #include "bindingproperty.h"
#include "captureddatacommand.h"
#include "changeauxiliarycommand.h" #include "changeauxiliarycommand.h"
#include "changebindingscommand.h" #include "changebindingscommand.h"
#include "changefileurlcommand.h" #include "changefileurlcommand.h"
@@ -41,6 +42,7 @@
#include "clearscenecommand.h" #include "clearscenecommand.h"
#include "completecomponentcommand.h" #include "completecomponentcommand.h"
#include "componentcompletedcommand.h" #include "componentcompletedcommand.h"
#include "connectionmanagerinterface.h"
#include "createinstancescommand.h" #include "createinstancescommand.h"
#include "createscenecommand.h" #include "createscenecommand.h"
#include "debugoutputcommand.h" #include "debugoutputcommand.h"
@@ -124,11 +126,10 @@ namespace QmlDesigner {
\sa ~NodeInstanceView, setRenderOffScreen() \sa ~NodeInstanceView, setRenderOffScreen()
*/ */
NodeInstanceView::NodeInstanceView(QObject *parent, NodeInstanceServerInterface::RunModus runModus) NodeInstanceView::NodeInstanceView(ConnectionManagerInterface &connectionManager)
: AbstractView(parent), : m_connectionManager(connectionManager)
m_baseStatePreviewImage(QSize(100, 100), QImage::Format_ARGB32), , m_baseStatePreviewImage(QSize(100, 100), QImage::Format_ARGB32)
m_runModus(runModus), , m_restartProcessTimerId(0)
m_restartProcessTimerId(0)
{ {
m_baseStatePreviewImage.fill(0xFFFFFF); m_baseStatePreviewImage.fill(0xFFFFFF);
} }
@@ -140,7 +141,6 @@ NodeInstanceView::NodeInstanceView(QObject *parent, NodeInstanceServerInterface:
NodeInstanceView::~NodeInstanceView() NodeInstanceView::~NodeInstanceView()
{ {
removeAllInstanceNodeRelationships(); removeAllInstanceNodeRelationships();
delete nodeInstanceServer();
m_currentTarget = nullptr; m_currentTarget = nullptr;
} }
@@ -191,14 +191,16 @@ bool static parentTakesOverRendering(const ModelNode &modelNode)
void NodeInstanceView::modelAttached(Model *model) void NodeInstanceView::modelAttached(Model *model)
{ {
AbstractView::modelAttached(model); AbstractView::modelAttached(model);
auto server = new NodeInstanceServerProxy(this, m_runModus, m_currentTarget); m_nodeInstanceServer = createNodeInstanceServerProxy();
m_nodeInstanceServer = server;
m_lastCrashTime.start(); m_lastCrashTime.start();
connect(server, &NodeInstanceServerProxy::processCrashed, this, &NodeInstanceView::handleCrash); connect(m_nodeInstanceServer.get(),
&NodeInstanceServerProxy::processCrashed,
this,
&NodeInstanceView::handleCrash);
if (!isSkippedRootNode(rootModelNode())) { if (!isSkippedRootNode(rootModelNode())) {
nodeInstanceServer()->createScene(createCreateSceneCommand()); m_nodeInstanceServer->createScene(createCreateSceneCommand());
nodeInstanceServer()->changeSelection(createChangeSelectionCommand(model->selectedNodes(this))); m_nodeInstanceServer->changeSelection(createChangeSelectionCommand(model->selectedNodes(this)));
} }
ModelNode stateNode = currentStateNode(); ModelNode stateNode = currentStateNode();
@@ -206,15 +208,14 @@ void NodeInstanceView::modelAttached(Model *model)
NodeInstance newStateInstance = instanceForModelNode(stateNode); NodeInstance newStateInstance = instanceForModelNode(stateNode);
activateState(newStateInstance); activateState(newStateInstance);
} }
} }
void NodeInstanceView::modelAboutToBeDetached(Model * model) void NodeInstanceView::modelAboutToBeDetached(Model * model)
{ {
removeAllInstanceNodeRelationships(); removeAllInstanceNodeRelationships();
if (nodeInstanceServer()) { if (m_nodeInstanceServer) {
nodeInstanceServer()->clearScene(createClearSceneCommand()); m_nodeInstanceServer->clearScene(createClearSceneCommand());
delete nodeInstanceServer(); m_nodeInstanceServer.reset();
} }
m_statePreviewImage.clear(); m_statePreviewImage.clear();
m_baseStatePreviewImage = QImage(); m_baseStatePreviewImage = QImage();
@@ -274,15 +275,18 @@ void NodeInstanceView::restartProcess()
killTimer(m_restartProcessTimerId); killTimer(m_restartProcessTimerId);
if (model()) { if (model()) {
delete nodeInstanceServer(); m_nodeInstanceServer.reset();
m_nodeInstanceServer = createNodeInstanceServerProxy();
auto server = new NodeInstanceServerProxy(this, m_runModus, m_currentTarget); connect(m_nodeInstanceServer.get(),
m_nodeInstanceServer = server; &NodeInstanceServerProxy::processCrashed,
connect(server, &NodeInstanceServerProxy::processCrashed, this, &NodeInstanceView::handleCrash); this,
&NodeInstanceView::handleCrash);
if (!isSkippedRootNode(rootModelNode())) { if (!isSkippedRootNode(rootModelNode())) {
nodeInstanceServer()->createScene(createCreateSceneCommand()); m_nodeInstanceServer->createScene(createCreateSceneCommand());
nodeInstanceServer()->changeSelection(createChangeSelectionCommand(model()->selectedNodes(this))); m_nodeInstanceServer->changeSelection(
createChangeSelectionCommand(model()->selectedNodes(this)));
} }
ModelNode stateNode = currentStateNode(); ModelNode stateNode = currentStateNode();
@@ -313,17 +317,19 @@ void NodeInstanceView::nodeCreated(const ModelNode &createdNode)
propertyList.append(createdNode.variantProperty("y")); propertyList.append(createdNode.variantProperty("y"));
updatePosition(propertyList); updatePosition(propertyList);
nodeInstanceServer()->createInstances(createCreateInstancesCommand({instance})); m_nodeInstanceServer->createInstances(createCreateInstancesCommand({instance}));
nodeInstanceServer()->changePropertyValues(createChangeValueCommand(createdNode.variantProperties())); m_nodeInstanceServer->changePropertyValues(
nodeInstanceServer()->completeComponent(createComponentCompleteCommand({instance})); createChangeValueCommand(createdNode.variantProperties()));
m_nodeInstanceServer->completeComponent(createComponentCompleteCommand({instance}));
} }
/*! Notifies the view that \a removedNode will be removed. /*! Notifies the view that \a removedNode will be removed.
*/ */
void NodeInstanceView::nodeAboutToBeRemoved(const ModelNode &removedNode) void NodeInstanceView::nodeAboutToBeRemoved(const ModelNode &removedNode)
{ {
nodeInstanceServer()->removeInstances(createRemoveInstancesCommand(removedNode)); m_nodeInstanceServer->removeInstances(createRemoveInstancesCommand(removedNode));
nodeInstanceServer()->removeSharedMemory(createRemoveSharedMemoryCommand("Image", removedNode.internalId())); m_nodeInstanceServer->removeSharedMemory(
createRemoveSharedMemoryCommand("Image", removedNode.internalId()));
removeInstanceAndSubInstances(removedNode); removeInstanceAndSubInstances(removedNode);
} }
@@ -343,11 +349,10 @@ void NodeInstanceView::resetHorizontalAnchors(const ModelNode &modelNode)
valueList.append(modelNode.variantProperty("width")); valueList.append(modelNode.variantProperty("width"));
if (!valueList.isEmpty()) if (!valueList.isEmpty())
nodeInstanceServer()->changePropertyValues(createChangeValueCommand(valueList)); m_nodeInstanceServer->changePropertyValues(createChangeValueCommand(valueList));
if (!bindingList.isEmpty()) if (!bindingList.isEmpty())
nodeInstanceServer()->changePropertyBindings(createChangeBindingCommand(bindingList)); m_nodeInstanceServer->changePropertyBindings(createChangeBindingCommand(bindingList));
} }
void NodeInstanceView::resetVerticalAnchors(const ModelNode &modelNode) void NodeInstanceView::resetVerticalAnchors(const ModelNode &modelNode)
@@ -366,10 +371,10 @@ void NodeInstanceView::resetVerticalAnchors(const ModelNode &modelNode)
valueList.append(modelNode.variantProperty("height")); valueList.append(modelNode.variantProperty("height"));
if (!valueList.isEmpty()) if (!valueList.isEmpty())
nodeInstanceServer()->changePropertyValues(createChangeValueCommand(valueList)); m_nodeInstanceServer->changePropertyValues(createChangeValueCommand(valueList));
if (!bindingList.isEmpty()) if (!bindingList.isEmpty())
nodeInstanceServer()->changePropertyBindings(createChangeBindingCommand(bindingList)); m_nodeInstanceServer->changePropertyBindings(createChangeBindingCommand(bindingList));
} }
void NodeInstanceView::propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList) void NodeInstanceView::propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList)
@@ -388,10 +393,10 @@ void NodeInstanceView::propertiesAboutToBeRemoved(const QList<AbstractProperty>&
RemoveInstancesCommand removeInstancesCommand = createRemoveInstancesCommand(nodeList); RemoveInstancesCommand removeInstancesCommand = createRemoveInstancesCommand(nodeList);
if (!removeInstancesCommand.instanceIds().isEmpty()) if (!removeInstancesCommand.instanceIds().isEmpty())
nodeInstanceServer()->removeInstances(removeInstancesCommand); m_nodeInstanceServer->removeInstances(removeInstancesCommand);
nodeInstanceServer()->removeSharedMemory(createRemoveSharedMemoryCommand("Image", nodeList)); m_nodeInstanceServer->removeSharedMemory(createRemoveSharedMemoryCommand("Image", nodeList));
nodeInstanceServer()->removeProperties(createRemovePropertiesCommand(nonNodePropertyList)); m_nodeInstanceServer->removeProperties(createRemovePropertiesCommand(nonNodePropertyList));
foreach (const AbstractProperty &property, propertyList) { foreach (const AbstractProperty &property, propertyList) {
const PropertyName &name = property.name(); const PropertyName &name = property.name();
@@ -445,7 +450,7 @@ void NodeInstanceView::nodeTypeChanged(const ModelNode &, const TypeName &, int,
void NodeInstanceView::bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags /*propertyChange*/) void NodeInstanceView::bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags /*propertyChange*/)
{ {
nodeInstanceServer()->changePropertyBindings(createChangeBindingCommand(propertyList)); m_nodeInstanceServer->changePropertyBindings(createChangeBindingCommand(propertyList));
} }
/*! /*!
@@ -460,7 +465,7 @@ void NodeInstanceView::bindingPropertiesChanged(const QList<BindingProperty>& pr
void NodeInstanceView::variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags /*propertyChange*/) void NodeInstanceView::variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags /*propertyChange*/)
{ {
updatePosition(propertyList); updatePosition(propertyList);
nodeInstanceServer()->changePropertyValues(createChangeValueCommand(propertyList)); m_nodeInstanceServer->changePropertyValues(createChangeValueCommand(propertyList));
} }
/*! /*!
Notifies the view that the property parent of the model node \a node has Notifies the view that the property parent of the model node \a node has
@@ -476,20 +481,21 @@ void NodeInstanceView::nodeReparented(const ModelNode &node, const NodeAbstractP
{ {
if (!isSkippedNode(node)) { if (!isSkippedNode(node)) {
updateChildren(newPropertyParent); updateChildren(newPropertyParent);
nodeInstanceServer()->reparentInstances(createReparentInstancesCommand(node, newPropertyParent, oldPropertyParent)); m_nodeInstanceServer->reparentInstances(
createReparentInstancesCommand(node, newPropertyParent, oldPropertyParent));
} }
} }
void NodeInstanceView::fileUrlChanged(const QUrl &/*oldUrl*/, const QUrl &newUrl) void NodeInstanceView::fileUrlChanged(const QUrl &/*oldUrl*/, const QUrl &newUrl)
{ {
nodeInstanceServer()->changeFileUrl(createChangeFileUrlCommand(newUrl)); m_nodeInstanceServer->changeFileUrl(createChangeFileUrlCommand(newUrl));
} }
void NodeInstanceView::nodeIdChanged(const ModelNode& node, const QString& /*newId*/, const QString& /*oldId*/) void NodeInstanceView::nodeIdChanged(const ModelNode& node, const QString& /*newId*/, const QString& /*oldId*/)
{ {
if (hasInstanceForModelNode(node)) { if (hasInstanceForModelNode(node)) {
NodeInstance instance = instanceForModelNode(node); NodeInstance instance = instanceForModelNode(node);
nodeInstanceServer()->changeIds(createChangeIdsCommand({instance})); m_nodeInstanceServer->changeIds(createChangeIdsCommand({instance}));
} }
} }
@@ -512,7 +518,7 @@ void NodeInstanceView::nodeOrderChanged(const NodeListProperty & listProperty,
} }
} }
nodeInstanceServer()->reparentInstances(ReparentInstancesCommand(containerList)); m_nodeInstanceServer->reparentInstances(ReparentInstancesCommand(containerList));
} }
void NodeInstanceView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/) void NodeInstanceView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/)
@@ -531,16 +537,16 @@ void NodeInstanceView::auxiliaryDataChanged(const ModelNode &node,
if (value.isValid() || name == "invisible") { if (value.isValid() || name == "invisible") {
PropertyValueContainer container(instance.instanceId(), name, value, TypeName()); PropertyValueContainer container(instance.instanceId(), name, value, TypeName());
ChangeAuxiliaryCommand changeAuxiliaryCommand({container}); ChangeAuxiliaryCommand changeAuxiliaryCommand({container});
nodeInstanceServer()->changeAuxiliaryValues(changeAuxiliaryCommand); m_nodeInstanceServer->changeAuxiliaryValues(changeAuxiliaryCommand);
} else { } else {
if (node.hasVariantProperty(name)) { if (node.hasVariantProperty(name)) {
PropertyValueContainer container(instance.instanceId(), name, node.variantProperty(name).value(), TypeName()); PropertyValueContainer container(instance.instanceId(), name, node.variantProperty(name).value(), TypeName());
ChangeValuesCommand changeValueCommand({container}); ChangeValuesCommand changeValueCommand({container});
nodeInstanceServer()->changePropertyValues(changeValueCommand); m_nodeInstanceServer->changePropertyValues(changeValueCommand);
} else if (node.hasBindingProperty(name)) { } else if (node.hasBindingProperty(name)) {
PropertyBindingContainer container(instance.instanceId(), name, node.bindingProperty(name).expression(), TypeName()); PropertyBindingContainer container(instance.instanceId(), name, node.bindingProperty(name).expression(), TypeName());
ChangeBindingsCommand changeValueCommand({container}); ChangeBindingsCommand changeValueCommand({container});
nodeInstanceServer()->changePropertyBindings(changeValueCommand); m_nodeInstanceServer->changePropertyBindings(changeValueCommand);
} }
} }
} }
@@ -548,9 +554,9 @@ void NodeInstanceView::auxiliaryDataChanged(const ModelNode &node,
const QString languageAsString = value.toString(); const QString languageAsString = value.toString();
if (auto multiLanguageAspect = QmlProjectManager::QmlMultiLanguageAspect::current(m_currentTarget)) if (auto multiLanguageAspect = QmlProjectManager::QmlMultiLanguageAspect::current(m_currentTarget))
multiLanguageAspect->setCurrentLocale(languageAsString); multiLanguageAspect->setCurrentLocale(languageAsString);
nodeInstanceServer()->changeLanguage({languageAsString}); m_nodeInstanceServer->changeLanguage({languageAsString});
} else if (node.isRootNode() && name == "previewSize@Internal") { } else if (node.isRootNode() && name == "previewSize@Internal") {
nodeInstanceServer()->changePreviewImageSize(value.toSize()); m_nodeInstanceServer->changePreviewImageSize(value.toSize());
} }
} }
@@ -565,10 +571,12 @@ void NodeInstanceView::nodeSourceChanged(const ModelNode &node, const QString &
if (hasInstanceForModelNode(node)) { if (hasInstanceForModelNode(node)) {
NodeInstance instance = instanceForModelNode(node); NodeInstance instance = instanceForModelNode(node);
ChangeNodeSourceCommand changeNodeSourceCommand(instance.instanceId(), newNodeSource); ChangeNodeSourceCommand changeNodeSourceCommand(instance.instanceId(), newNodeSource);
nodeInstanceServer()->changeNodeSource(changeNodeSourceCommand); m_nodeInstanceServer->changeNodeSource(changeNodeSourceCommand);
} }
} }
void NodeInstanceView::capturedData(const CapturedDataCommand &) {}
void NodeInstanceView::currentStateChanged(const ModelNode &node) void NodeInstanceView::currentStateChanged(const ModelNode &node)
{ {
NodeInstance newStateInstance = instanceForModelNode(node); NodeInstance newStateInstance = instanceForModelNode(node);
@@ -790,12 +798,6 @@ void NodeInstanceView::updatePosition(const QList<VariantProperty> &propertyList
emitInstanceInformationsChange(informationChangeHash); emitInstanceInformationsChange(informationChangeHash);
} }
NodeInstanceServerInterface *NodeInstanceView::nodeInstanceServer() const
{
return m_nodeInstanceServer.data();
}
NodeInstance NodeInstanceView::loadNode(const ModelNode &node) NodeInstance NodeInstanceView::loadNode(const ModelNode &node)
{ {
NodeInstance instance(NodeInstance::create(node)); NodeInstance instance(NodeInstance::create(node));
@@ -810,12 +812,12 @@ NodeInstance NodeInstanceView::loadNode(const ModelNode &node)
void NodeInstanceView::activateState(const NodeInstance &instance) void NodeInstanceView::activateState(const NodeInstance &instance)
{ {
nodeInstanceServer()->changeState(ChangeStateCommand(instance.instanceId())); m_nodeInstanceServer->changeState(ChangeStateCommand(instance.instanceId()));
} }
void NodeInstanceView::activateBaseState() void NodeInstanceView::activateBaseState()
{ {
nodeInstanceServer()->changeState(ChangeStateCommand(-1)); m_nodeInstanceServer->changeState(ChangeStateCommand(-1));
} }
void NodeInstanceView::removeRecursiveChildRelationship(const ModelNode &removedNode) void NodeInstanceView::removeRecursiveChildRelationship(const ModelNode &removedNode)
@@ -1248,7 +1250,8 @@ void NodeInstanceView::valuesChanged(const ValuesChangedCommand &command)
} }
} }
nodeInstanceServer()->removeSharedMemory(createRemoveSharedMemoryCommand(QStringLiteral("Values"), command.keyNumber())); m_nodeInstanceServer->removeSharedMemory(
createRemoveSharedMemoryCommand(QStringLiteral("Values"), command.keyNumber()));
if (!valuePropertyChangeList.isEmpty()) if (!valuePropertyChangeList.isEmpty())
emitInstancePropertyChange(valuePropertyChangeList); emitInstancePropertyChange(valuePropertyChangeList);
@@ -1456,7 +1459,7 @@ void NodeInstanceView::sendToken(const QString &token, int number, const QVector
foreach (const ModelNode &node, nodeVector) foreach (const ModelNode &node, nodeVector)
instanceIdVector.append(node.internalId()); instanceIdVector.append(node.internalId());
nodeInstanceServer()->token(TokenCommand(token, number, instanceIdVector)); m_nodeInstanceServer->token(TokenCommand(token, number, instanceIdVector));
} }
void NodeInstanceView::selectionChanged(const ChangeSelectionCommand &command) void NodeInstanceView::selectionChanged(const ChangeSelectionCommand &command)
@@ -1471,7 +1474,7 @@ void NodeInstanceView::selectionChanged(const ChangeSelectionCommand &command)
void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand &command) void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand &command)
{ {
if (command.type() == PuppetToCreatorCommand::Edit3DToolState) { if (command.type() == PuppetToCreatorCommand::Edit3DToolState) {
if (!m_nodeInstanceServer.isNull()) { if (m_nodeInstanceServer) {
auto data = qvariant_cast<QVariantList>(command.data()); auto data = qvariant_cast<QVariantList>(command.data());
if (data.size() == 3) { if (data.size() == 3) {
QString qmlId = data[0].toString(); QString qmlId = data[0].toString();
@@ -1488,25 +1491,30 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand
} }
} }
std::unique_ptr<NodeInstanceServerProxy> NodeInstanceView::createNodeInstanceServerProxy()
{
return std::make_unique<NodeInstanceServerProxy>(this, m_currentTarget, m_connectionManager);
}
void NodeInstanceView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList, void NodeInstanceView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
const QList<ModelNode> & /*lastSelectedNodeList*/) const QList<ModelNode> & /*lastSelectedNodeList*/)
{ {
nodeInstanceServer()->changeSelection(createChangeSelectionCommand(selectedNodeList)); m_nodeInstanceServer->changeSelection(createChangeSelectionCommand(selectedNodeList));
} }
void NodeInstanceView::sendInputEvent(QInputEvent *e) const void NodeInstanceView::sendInputEvent(QInputEvent *e) const
{ {
nodeInstanceServer()->inputEvent(InputEventCommand(e)); m_nodeInstanceServer->inputEvent(InputEventCommand(e));
} }
void NodeInstanceView::view3DAction(const View3DActionCommand &command) void NodeInstanceView::view3DAction(const View3DActionCommand &command)
{ {
nodeInstanceServer()->view3DAction(command); m_nodeInstanceServer->view3DAction(command);
} }
void NodeInstanceView::edit3DViewResized(const QSize &size) const void NodeInstanceView::edit3DViewResized(const QSize &size) const
{ {
nodeInstanceServer()->update3DViewState(Update3dViewStateCommand(size)); m_nodeInstanceServer->update3DViewState(Update3dViewStateCommand(size));
} }
void NodeInstanceView::timerEvent(QTimerEvent *event) void NodeInstanceView::timerEvent(QTimerEvent *event)

View File

@@ -176,39 +176,46 @@ PuppetCreator::PuppetCreator(ProjectExplorer::Target *target, const Model *model
{ {
} }
QProcess *PuppetCreator::createPuppetProcess(const QString &puppetMode, QProcessUniquePointer PuppetCreator::createPuppetProcess(
const QString &socketToken, const QString &puppetMode,
QObject *handlerObject, const QString &socketToken,
const char *outputSlot, QObject *handlerObject,
const char *finishSlot, std::function<void()> processOutputCallback,
const QStringList &customOptions) const std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
const QStringList &customOptions) const
{ {
return puppetProcess(qml2PuppetPath(m_availablePuppetType), return puppetProcess(qml2PuppetPath(m_availablePuppetType),
qmlPuppetDirectory(m_availablePuppetType), qmlPuppetDirectory(m_availablePuppetType),
puppetMode, puppetMode,
socketToken, socketToken,
handlerObject, handlerObject,
outputSlot, processOutputCallback,
finishSlot, processFinishCallback,
customOptions); customOptions);
} }
QProcessUniquePointer PuppetCreator::puppetProcess(
QProcess *PuppetCreator::puppetProcess(const QString &puppetPath, const QString &puppetPath,
const QString &workingDirectory, const QString &workingDirectory,
const QString &puppetMode, const QString &puppetMode,
const QString &socketToken, const QString &socketToken,
QObject *handlerObject, QObject *handlerObject,
const char *outputSlot, std::function<void()> processOutputCallback,
const char *finishSlot, std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
const QStringList &customOptions) const const QStringList &customOptions) const
{ {
auto puppetProcess = new QProcess; QProcessUniquePointer puppetProcess{new QProcess};
puppetProcess->setObjectName(puppetMode); puppetProcess->setObjectName(puppetMode);
puppetProcess->setProcessEnvironment(processEnvironment()); puppetProcess->setProcessEnvironment(processEnvironment());
QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, puppetProcess, &QProcess::kill); QObject::connect(QCoreApplication::instance(),
QObject::connect(puppetProcess, SIGNAL(finished(int,QProcess::ExitStatus)), handlerObject, finishSlot); &QCoreApplication::aboutToQuit,
puppetProcess.get(),
&QProcess::kill);
QObject::connect(puppetProcess.get(),
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
handlerObject,
processFinishCallback);
#ifndef QMLDESIGNER_TEST #ifndef QMLDESIGNER_TEST
QString forwardOutput = m_designerSettings.value(DesignerSettingsKey:: QString forwardOutput = m_designerSettings.value(DesignerSettingsKey::
@@ -218,7 +225,7 @@ QProcess *PuppetCreator::puppetProcess(const QString &puppetPath,
#endif #endif
if (forwardOutput == puppetMode || forwardOutput == "all") { if (forwardOutput == puppetMode || forwardOutput == "all") {
puppetProcess->setProcessChannelMode(QProcess::MergedChannels); puppetProcess->setProcessChannelMode(QProcess::MergedChannels);
QObject::connect(puppetProcess, SIGNAL(readyRead()), handlerObject, outputSlot); QObject::connect(puppetProcess.get(), &QProcess::readyRead, handlerObject, processOutputCallback);
} }
puppetProcess->setWorkingDirectory(workingDirectory); puppetProcess->setWorkingDirectory(workingDirectory);

View File

@@ -25,6 +25,8 @@
#pragma once #pragma once
#include "qprocessuniqueptr.h"
#include <QString> #include <QString>
#include <QProcessEnvironment> #include <QProcessEnvironment>
@@ -53,12 +55,13 @@ public:
void createQml2PuppetExecutableIfMissing(); void createQml2PuppetExecutableIfMissing();
QProcess *createPuppetProcess(const QString &puppetMode, QProcessUniquePointer createPuppetProcess(
const QString &socketToken, const QString &puppetMode,
QObject *handlerObject, const QString &socketToken,
const char *outputSlot, QObject *handlerObject,
const char *finishSlot, std::function<void()> processOutputCallback,
const QStringList &customOptions = {}) const; std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
const QStringList &customOptions = {}) const;
void setQrcMappingString(const QString qrcMapping); void setQrcMappingString(const QString qrcMapping);
@@ -82,14 +85,14 @@ protected:
bool checkPuppetIsReady(const QString &puppetPath) const; bool checkPuppetIsReady(const QString &puppetPath) const;
bool qtIsSupported() const; bool qtIsSupported() const;
QProcess *puppetProcess(const QString &puppetPath, QProcessUniquePointer puppetProcess(const QString &puppetPath,
const QString &workingDirectory, const QString &workingDirectory,
const QString &puppetMode, const QString &puppetMode,
const QString &socketToken, const QString &socketToken,
QObject *handlerObject, QObject *handlerObject,
const char *outputSlot, std::function<void()> processOutputCallback,
const char *finishSlot, std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
const QStringList &customOptions) const; const QStringList &customOptions) const;
QProcessEnvironment processEnvironment() const; QProcessEnvironment processEnvironment() const;

View File

@@ -0,0 +1,53 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QProcess>
#include <memory>
namespace QmlDesigner {
class QProcessUniquePointerDeleter
{
public:
void operator()(QProcess *process)
{
process->disconnect();
QObject::connect(process,
QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
process,
&QProcess::deleteLater);
process->terminate();
process->deleteLater();
}
};
using QProcessUniquePointer = std::unique_ptr<QProcess, QProcessUniquePointerDeleter>;
} // namespace QmlDesigner

View File

@@ -27,23 +27,24 @@
#ifndef QMLDESIGNER_TEST #ifndef QMLDESIGNER_TEST
#include <componentaction.h>
#include <designmodewidget.h>
#include <crumblebar.h>
#include <abstractview.h> #include <abstractview.h>
#include <rewriterview.h> #include <componentaction.h>
#include <nodeinstanceview.h> #include <componentview.h>
#include <itemlibraryview.h> #include <crumblebar.h>
#include <navigatorview.h> #include <debugview.h>
#include <stateseditorview.h> #include <designeractionmanagerview.h>
#include <designmodewidget.h>
#include <edit3dview.h> #include <edit3dview.h>
#include <formeditorview.h> #include <formeditorview.h>
#include <texteditorview.h>
#include <propertyeditorview.h>
#include <componentview.h>
#include <debugview.h>
#include <importmanagerview.h> #include <importmanagerview.h>
#include <designeractionmanagerview.h> #include <interactiveconnectionmanager.h>
#include <itemlibraryview.h>
#include <navigatorview.h>
#include <nodeinstanceview.h>
#include <propertyeditorview.h>
#include <rewriterview.h>
#include <stateseditorview.h>
#include <texteditorview.h>
#include <qmldesignerplugin.h> #include <qmldesignerplugin.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
@@ -59,10 +60,11 @@ static Q_LOGGING_CATEGORY(viewBenchmark, "qtc.viewmanager.attach", QtWarningMsg)
class ViewManagerData class ViewManagerData
{ {
public: public:
InteractiveConnectionManager connectionManager;
QmlModelState savedState; QmlModelState savedState;
Internal::DebugView debugView; Internal::DebugView debugView;
DesignerActionManagerView designerActionManagerView; DesignerActionManagerView designerActionManagerView;
NodeInstanceView nodeInstanceView; NodeInstanceView nodeInstanceView{connectionManager};
ComponentView componentView; ComponentView componentView;
Edit3DView edit3DView; Edit3DView edit3DView;
FormEditorView formEditorView; FormEditorView formEditorView;
@@ -81,7 +83,7 @@ static CrumbleBar *crumbleBar() {
} }
ViewManager::ViewManager() ViewManager::ViewManager()
: d(new ViewManagerData) : d(std::make_unique<ViewManagerData>())
{ {
d->formEditorView.setGotoErrorCallback([this](int line, int column) { d->formEditorView.setGotoErrorCallback([this](int line, int column) {
d->textEditorView.gotoCursorPosition(line, column); d->textEditorView.gotoCursorPosition(line, column);
@@ -92,10 +94,9 @@ ViewManager::ViewManager()
ViewManager::~ViewManager() ViewManager::~ViewManager()
{ {
foreach (const QPointer<AbstractView> &view, d->additionalViews) for (const QPointer<AbstractView> &view : d->additionalViews)
delete view.data(); delete view.data();
delete d;
} }
DesignDocument *ViewManager::currentDesignDocument() const DesignDocument *ViewManager::currentDesignDocument() const

View File

@@ -321,6 +321,17 @@ Project {
"instances/puppetdialog.cpp", "instances/puppetdialog.cpp",
"instances/puppetdialog.h", "instances/puppetdialog.h",
"instances/puppetdialog.ui", "instances/puppetdialog.ui",
"instances/connectionmanagerinterface.cpp",
"instances/connectionmanagerinterface.h",
"instances/baseconnectionmanager.cpp ",
"instances/baseconnectionmanager.h",
"instances/connectionmanager.cpp",
"instances/connectionmanager.h",
"instances/capturingconnectionmanager.cpp",
"instances/capturingconnectionmanager.h",
"instances/interactiveconnectionmanager.cpp",
"instances/interactiveconnectionmanager.h",
"instances/qprocessuniqueptr.h",
"metainfo/itemlibraryinfo.cpp", "metainfo/itemlibraryinfo.cpp",
"metainfo/metainfo.cpp", "metainfo/metainfo.cpp",
"metainfo/metainforeader.cpp", "metainfo/metainforeader.cpp",

View File

@@ -52,6 +52,7 @@ extend_qtc_executable(qml2puppet
inputeventcommand.cpp inputeventcommand.h inputeventcommand.cpp inputeventcommand.h
view3dactioncommand.cpp view3dactioncommand.h view3dactioncommand.cpp view3dactioncommand.h
valueschangedcommand.cpp valueschangedcommand.cpp
captureddatacommand.cpp captureddatacommand.h
) )
extend_qtc_executable(qml2puppet extend_qtc_executable(qml2puppet
@@ -156,6 +157,7 @@ extend_qtc_executable(qml2puppet
quick3dnodeinstance.cpp quick3dnodeinstance.h quick3dnodeinstance.cpp quick3dnodeinstance.h
quickitemnodeinstance.cpp quickitemnodeinstance.h quickitemnodeinstance.cpp quickitemnodeinstance.h
servernodeinstance.cpp servernodeinstance.h servernodeinstance.cpp servernodeinstance.h
qt5capturenodeinstanceserver.cpp qt5capturenodeinstanceserver.h
) )
extend_qtc_executable(qml2puppet extend_qtc_executable(qml2puppet

View File

@@ -107,6 +107,8 @@ QtcTool {
"commands/inputeventcommand.h", "commands/inputeventcommand.h",
"commands/view3dactioncommand.cpp", "commands/view3dactioncommand.cpp",
"commands/view3dactioncommand.h", "commands/view3dactioncommand.h",
"commands/captureddatacommand.cpp",
"commands/captureddatacommand.h",
"container/addimportcontainer.cpp", "container/addimportcontainer.cpp",
"container/addimportcontainer.h", "container/addimportcontainer.h",
"container/idcontainer.cpp", "container/idcontainer.cpp",
@@ -207,6 +209,8 @@ QtcTool {
"instances/qt5testnodeinstanceserver.h", "instances/qt5testnodeinstanceserver.h",
"instances/servernodeinstance.cpp", "instances/servernodeinstance.cpp",
"instances/servernodeinstance.h", "instances/servernodeinstance.h",
"instances/qt5capturenodeinstanceserver.cpp",
"instances/qt5capturenodeinstanceserver.h",
"editor3d/generalhelper.cpp", "editor3d/generalhelper.cpp",
"editor3d/generalhelper.h", "editor3d/generalhelper.h",
"editor3d/mousearea3d.cpp", "editor3d/mousearea3d.cpp",

View File

@@ -17,4 +17,5 @@ add_qtc_test(tst_qml_testcore
../testview.cpp ../testview.h ../testview.cpp ../testview.h
testrewriterview.cpp testrewriterview.h testrewriterview.cpp testrewriterview.h
tst_testcore.cpp tst_testcore.h tst_testcore.cpp tst_testcore.h
../testconnectionmanager.cpp ../testconnectionmanager.h
) )

View File

@@ -60,11 +60,13 @@ TEMPLATE = app
SOURCES += \ SOURCES += \
../testview.cpp \ ../testview.cpp \
testrewriterview.cpp \ testrewriterview.cpp \
tst_testcore.cpp tst_testcore.cpp \
../testconnectionmanager.cpp
HEADERS += \ HEADERS += \
../testview.h \ ../testview.h \
testrewriterview.h \ testrewriterview.h \
tst_testcore.h tst_testcore.h \
../testconnectionmanager.h
RESOURCES += ../data/testfiles.qrc RESOURCES += ../data/testfiles.qrc

View File

@@ -46,11 +46,12 @@
#include <stylesheetmerger.h> #include <stylesheetmerger.h>
#include <QDebug> #include <QDebug>
#include "../testconnectionmanager.h"
#include "../testview.h" #include "../testview.h"
#include <variantproperty.h>
#include <abstractproperty.h> #include <abstractproperty.h>
#include <bindingproperty.h> #include <bindingproperty.h>
#include <nodeproperty.h> #include <nodeproperty.h>
#include <variantproperty.h>
#include <nodelistproperty.h> #include <nodelistproperty.h>
#include <nodeabstractproperty.h> #include <nodeabstractproperty.h>
@@ -1999,8 +2000,9 @@ void tst_TestCore::testModelRemoveNode()
QVERIFY(view.data()); QVERIFY(view.data());
model->attachView(view.data()); model->attachView(view.data());
NodeInstanceView *nodeInstanceView = new NodeInstanceView(model.data(), NodeInstanceServerInterface::TestModus); TestConnectionManager connectionManager;
model->attachView(nodeInstanceView); NodeInstanceView nodeInstanceView{connectionManager};
model->attachView(&nodeInstanceView);
QCOMPARE(view->rootModelNode().directSubModelNodes().count(), 0); QCOMPARE(view->rootModelNode().directSubModelNodes().count(), 0);
@@ -2051,7 +2053,7 @@ void tst_TestCore::testModelRemoveNode()
childNode = view->createModelNode("QtQuick.Item", 1, 1); childNode = view->createModelNode("QtQuick.Item", 1, 1);
childNode.destroy(); childNode.destroy();
model->detachView(nodeInstanceView); model->detachView(&nodeInstanceView);
} }
void tst_TestCore::reparentingNode() void tst_TestCore::reparentingNode()
@@ -6140,17 +6142,21 @@ void tst_TestCore::testInstancesAttachToExistingModel()
// Attach NodeInstanceView // Attach NodeInstanceView
QScopedPointer<NodeInstanceView> instanceView(new NodeInstanceView(0, NodeInstanceServerInterface::TestModus)); TestConnectionManager connectionManager;
QVERIFY(instanceView.data());
model->attachView(instanceView.data());
NodeInstance rootInstance = instanceView->instanceForModelNode(rootNode); NodeInstanceView instanceView{connectionManager};
NodeInstance rectangleInstance = instanceView->instanceForModelNode(rectangleNode);
model->attachView(&instanceView);
NodeInstance rootInstance = instanceView.instanceForModelNode(rootNode);
NodeInstance rectangleInstance = instanceView.instanceForModelNode(rectangleNode);
QVERIFY(rootInstance.isValid()); QVERIFY(rootInstance.isValid());
QVERIFY(rectangleInstance.isValid()); QVERIFY(rectangleInstance.isValid());
QCOMPARE(QVariant(100), rectangleInstance.property("width")); QCOMPARE(QVariant(100), rectangleInstance.property("width"));
QVERIFY(rootInstance.instanceId() >= 0); QVERIFY(rootInstance.instanceId() >= 0);
QVERIFY(rectangleInstance.instanceId() >= 0); QVERIFY(rectangleInstance.instanceId() >= 0);
model->detachView(&instanceView);
} }
void tst_TestCore::testQmlModelAddMultipleStates() void tst_TestCore::testQmlModelAddMultipleStates()

View File

@@ -0,0 +1,72 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "testconnectionmanager.h"
#include "synchronizecommand.h"
#include <QLocalSocket>
namespace QmlDesigner {
TestConnectionManager::TestConnectionManager()
{
m_connections.emplace_back("Editor", "editormode");
}
void TestConnectionManager::writeCommand(const QVariant &command)
{
TestConnectionManager::writeCommand(command);
m_writeCommandCounter++;
static int synchronizeId = 0;
synchronizeId++;
SynchronizeCommand synchronizeCommand(synchronizeId);
QLocalSocket *socket = m_connections.front().socket.get();
writeCommandToIODevice(QVariant::fromValue(synchronizeCommand), socket, m_writeCommandCounter);
m_writeCommandCounter++;
while (socket->waitForReadyRead(100)) {
readDataStream(m_connections.front());
if (m_synchronizeId == synchronizeId)
return;
}
}
void TestConnectionManager::dispatchCommand(const QVariant &command, Connection &connection)
{
static const int synchronizeCommandType = QMetaType::type("SynchronizeCommand");
if (command.userType() == synchronizeCommandType) {
SynchronizeCommand synchronizeCommand = command.value<SynchronizeCommand>();
m_synchronizeId = synchronizeCommand.synchronizeId();
} else {
ConnectionManager::dispatchCommand(command, connection);
}
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,56 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <connectionmanager.h>
#include <QFile>
#include <QPointer>
#include <QProcess>
#include <QTimer>
QT_BEGIN_NAMESPACE
class QLocalServer;
class QLocalSocket;
QT_END_NAMESPACE
namespace QmlDesigner {
class TestConnectionManager final : public ConnectionManager
{
public:
TestConnectionManager();
void writeCommand(const QVariant &command) override;
protected:
void dispatchCommand(const QVariant &command, Connection &connection) override;
private:
int m_synchronizeId = -1;
};
} // namespace QmlDesigner