forked from qt-creator/qt-creator
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:
@@ -505,6 +505,12 @@ extend_qtc_plugin(QmlDesigner
|
||||
puppetbuildprogressdialog.cpp puppetbuildprogressdialog.h puppetbuildprogressdialog.ui
|
||||
puppetcreator.cpp puppetcreator.h
|
||||
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
|
||||
|
||||
@@ -86,7 +86,7 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
|
||||
|
||||
if (!isCancelled()) {
|
||||
// Wait for icon generation processes to finish
|
||||
if (m_qmlPuppetProcesses.isEmpty()) {
|
||||
if (m_qmlPuppetProcesses.empty()) {
|
||||
finalizeQuick3DImport();
|
||||
} else {
|
||||
m_qmlPuppetCount = m_qmlPuppetProcesses.size();
|
||||
@@ -186,10 +186,12 @@ void ItemLibraryAssetImporter::processFinished(int exitCode, QProcess::ExitStatu
|
||||
|
||||
auto process = qobject_cast<QProcess *>(sender());
|
||||
if (process) {
|
||||
m_qmlPuppetProcesses.remove(process);
|
||||
process->deleteLater();
|
||||
m_qmlPuppetProcesses.erase(
|
||||
std::remove_if(m_qmlPuppetProcesses.begin(),
|
||||
m_qmlPuppetProcesses.end(),
|
||||
[&](const auto &entry) { return entry.get() == process; }));
|
||||
const QString progressTitle = tr("Generating icons.");
|
||||
if (m_qmlPuppetProcesses.isEmpty()) {
|
||||
if (m_qmlPuppetProcesses.empty()) {
|
||||
notifyProgress(100, progressTitle);
|
||||
finalizeQuick3DImport();
|
||||
} else {
|
||||
@@ -215,7 +217,6 @@ void ItemLibraryAssetImporter::reset()
|
||||
m_tempDir = new QTemporaryDir;
|
||||
m_importFiles.clear();
|
||||
m_overwrittenImports.clear();
|
||||
qDeleteAll(m_qmlPuppetProcesses);
|
||||
m_qmlPuppetProcesses.clear();
|
||||
m_qmlPuppetCount = 0;
|
||||
#endif
|
||||
@@ -498,16 +499,21 @@ bool ItemLibraryAssetImporter::generateComponentIcon(int size, const QString &ic
|
||||
puppetCreator.createQml2PuppetExecutableIfMissing();
|
||||
QStringList puppetArgs;
|
||||
puppetArgs << "--rendericon" << QString::number(size) << iconFile << iconSource;
|
||||
QProcess *process = puppetCreator.createPuppetProcess(
|
||||
"custom", {}, this, "", SLOT(processFinished(int, QProcess::ExitStatus)), puppetArgs);
|
||||
QProcessUniquePointer process = puppetCreator.createPuppetProcess(
|
||||
"custom",
|
||||
{},
|
||||
this,
|
||||
std::function<void()>(),
|
||||
[&](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
processFinished(exitCode, exitStatus);
|
||||
},
|
||||
puppetArgs);
|
||||
|
||||
if (process->waitForStarted(5000)) {
|
||||
connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
process, &QProcess::deleteLater);
|
||||
m_qmlPuppetProcesses << process;
|
||||
m_qmlPuppetProcesses.push_back(std::move(process));
|
||||
return true;
|
||||
} else {
|
||||
delete process;
|
||||
process.reset();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -24,14 +24,16 @@
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "import.h"
|
||||
|
||||
#include <qprocessuniqueptr.h>
|
||||
|
||||
#include <QSet>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qstringlist.h>
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qjsonobject.h>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qprocess.h>
|
||||
|
||||
#include "import.h"
|
||||
#include <QtCore/qstringlist.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QSSGAssetImportManager;
|
||||
@@ -99,7 +101,7 @@ private:
|
||||
bool m_cancelled = false;
|
||||
QString m_importPath;
|
||||
QTemporaryDir *m_tempDir = nullptr;
|
||||
QSet<QProcess *> m_qmlPuppetProcesses;
|
||||
std::vector<QProcessUniquePointer> m_qmlPuppetProcesses;
|
||||
int m_qmlPuppetCount = 0;
|
||||
};
|
||||
} // QmlDesigner
|
||||
|
||||
@@ -62,6 +62,7 @@ class RemovePropertiesCommand;
|
||||
class CompleteComponentCommand;
|
||||
class InformationContainer;
|
||||
class TokenCommand;
|
||||
class ConnectionManagerInterface;
|
||||
|
||||
class QMLDESIGNERCORE_EXPORT NodeInstanceView : public AbstractView, public NodeInstanceClientInterface
|
||||
{
|
||||
@@ -72,7 +73,7 @@ class QMLDESIGNERCORE_EXPORT NodeInstanceView : public AbstractView, public Node
|
||||
public:
|
||||
using Pointer = QWeakPointer<NodeInstanceView>;
|
||||
|
||||
explicit NodeInstanceView(QObject *parent = nullptr, NodeInstanceServerInterface::RunModus runModus = NodeInstanceServerInterface::NormalModus);
|
||||
explicit NodeInstanceView(ConnectionManagerInterface &connectionManager);
|
||||
~NodeInstanceView() override;
|
||||
|
||||
void modelAttached(Model *model) override;
|
||||
@@ -94,7 +95,7 @@ public:
|
||||
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 nodeSourceChanged(const ModelNode &modelNode, const QString &newNodeSource) override;
|
||||
|
||||
void capturedData(const CapturedDataCommand &capturedData) override;
|
||||
void currentStateChanged(const ModelNode &node) override;
|
||||
|
||||
QList<NodeInstance> instances() const;
|
||||
@@ -142,6 +143,7 @@ protected:
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
private: // functions
|
||||
std::unique_ptr<NodeInstanceServerProxy> createNodeInstanceServerProxy();
|
||||
void activateState(const NodeInstance &instance);
|
||||
void activateBaseState();
|
||||
|
||||
@@ -161,9 +163,8 @@ private: // functions
|
||||
void setStateInstance(const NodeInstance &stateInstance);
|
||||
void clearStateInstance();
|
||||
|
||||
NodeInstanceServerInterface *nodeInstanceServer() const;
|
||||
QMultiHash<ModelNode, InformationName> informationChanged(const QVector<InformationContainer> &containerVector);
|
||||
|
||||
QMultiHash<ModelNode, InformationName> informationChanged(
|
||||
const QVector<InformationContainer> &containerVector);
|
||||
|
||||
CreateSceneCommand createCreateSceneCommand();
|
||||
ClearSceneCommand createClearSceneCommand() const;
|
||||
@@ -196,16 +197,15 @@ private: // functions
|
||||
// puppet to creator command handlers
|
||||
void handlePuppetKeyPress(int key, Qt::KeyboardModifiers modifiers);
|
||||
|
||||
private:
|
||||
NodeInstance m_rootNodeInstance;
|
||||
NodeInstance m_activeStateInstance;
|
||||
|
||||
QHash<ModelNode, NodeInstance> m_nodeInstanceHash;
|
||||
QHash<ModelNode, QImage> m_statePreviewImage;
|
||||
|
||||
QPointer<NodeInstanceServerProxy> m_nodeInstanceServer;
|
||||
ConnectionManagerInterface &m_connectionManager;
|
||||
std::unique_ptr<NodeInstanceServerProxy> m_nodeInstanceServer;
|
||||
QImage m_baseStatePreviewImage;
|
||||
QElapsedTimer m_lastCrashTime;
|
||||
NodeInstanceServerInterface::RunModus m_runModus;
|
||||
ProjectExplorer::Target *m_currentTarget = nullptr;
|
||||
int m_restartProcessTimerId;
|
||||
RewriterTransaction m_puppetTransaction;
|
||||
|
||||
@@ -122,7 +122,7 @@ private: // functions
|
||||
QList<QPointer<AbstractView>> standardViews() const;
|
||||
|
||||
private: // variables
|
||||
ViewManagerData *d;
|
||||
std::unique_ptr<ViewManagerData> d;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1,14 +1,25 @@
|
||||
INCLUDEPATH += $$PWD/
|
||||
|
||||
HEADERS += $$PWD/../include/nodeinstance.h
|
||||
HEADERS += $$PWD/nodeinstanceserverproxy.h
|
||||
HEADERS += $$PWD/puppetcreator.h
|
||||
HEADERS += $$PWD/puppetbuildprogressdialog.h
|
||||
HEADERS += $$PWD/../include/nodeinstance.h \
|
||||
$$PWD/baseconnectionmanager.h \
|
||||
$$PWD/capturingconnectionmanager.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/nodeinstance.cpp
|
||||
SOURCES += $$PWD/nodeinstanceview.cpp
|
||||
SOURCES += $$PWD/puppetcreator.cpp
|
||||
SOURCES += $$PWD/puppetbuildprogressdialog.cpp
|
||||
SOURCES += $$PWD/nodeinstanceserverproxy.cpp \
|
||||
$$PWD/baseconnectionmanager.cpp \
|
||||
$$PWD/capturingconnectionmanager.cpp \
|
||||
$$PWD/connectionmanager.cpp \
|
||||
$$PWD/connectionmanagerinterface.cpp \
|
||||
$$PWD/interactiveconnectionmanager.cpp \
|
||||
$$PWD/nodeinstance.cpp \
|
||||
$$PWD/nodeinstanceview.cpp \
|
||||
$$PWD/puppetcreator.cpp \
|
||||
$$PWD/puppetbuildprogressdialog.cpp
|
||||
|
||||
FORMS += $$PWD/puppetbuildprogressdialog.ui
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "nodeinstanceserverproxy.h"
|
||||
|
||||
#include "connectionmanagerinterface.h"
|
||||
#include "puppetcreator.h"
|
||||
|
||||
#include <changeauxiliarycommand.h>
|
||||
@@ -60,218 +61,55 @@
|
||||
#include <valueschangedcommand.h>
|
||||
#include <view3dactioncommand.h>
|
||||
|
||||
#include <nodeinstanceview.h>
|
||||
#include <import.h>
|
||||
#include <nodeinstanceview.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/icore.h>
|
||||
#include <projectexplorer/kit.h>
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <qtsupport/baseqtversion.h>
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
#include <qtsupport/qtsupportconstants.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QLocalServer>
|
||||
#include <QLocalSocket>
|
||||
#include <QLoggingCategory>
|
||||
#include <QProcess>
|
||||
#include <QCoreApplication>
|
||||
#include <QUuid>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QTimer>
|
||||
#include <QTextStream>
|
||||
#include <QMessageBox>
|
||||
#include <QProcess>
|
||||
#include <QTextStream>
|
||||
#include <QTimer>
|
||||
#include <QUuid>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
static Q_LOGGING_CATEGORY(instanceViewBenchmark, "qtc.nodeinstances.init", QtWarningMsg);
|
||||
|
||||
NodeInstanceServerProxy::NodeInstanceServerProxy(NodeInstanceView *nodeInstanceView,
|
||||
RunModus runModus,
|
||||
ProjectExplorer::Target *target)
|
||||
: NodeInstanceServerInterface(nodeInstanceView),
|
||||
m_localServer(new QLocalServer(this)),
|
||||
m_nodeInstanceView(nodeInstanceView),
|
||||
m_runModus(runModus)
|
||||
ProjectExplorer::Target *target,
|
||||
ConnectionManagerInterface &connectionManager)
|
||||
: m_nodeInstanceView(nodeInstanceView)
|
||||
, m_connectionManager{connectionManager}
|
||||
|
||||
{
|
||||
if (instanceViewBenchmark().isInfoEnabled())
|
||||
m_benchmarkTimer.start();
|
||||
|
||||
QString socketToken(QUuid::createUuid().toString());
|
||||
m_localServer->listen(socketToken);
|
||||
m_localServer->setMaxPendingConnections(3);
|
||||
m_connectionManager.setUp(this, qrcMappingString(), target);
|
||||
|
||||
PuppetCreator puppetCreator(target, nodeInstanceView->model());
|
||||
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
|
||||
qCInfo(instanceViewBenchmark) << "puppets setup:" << m_benchmarkTimer.elapsed();
|
||||
}
|
||||
|
||||
NodeInstanceServerProxy::~NodeInstanceServerProxy()
|
||||
{
|
||||
m_destructing = true;
|
||||
|
||||
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);
|
||||
}
|
||||
m_connectionManager.shutDown();
|
||||
}
|
||||
|
||||
void NodeInstanceServerProxy::dispatchCommand(const QVariant &command, PuppetStreamType puppetStreamType)
|
||||
void NodeInstanceServerProxy::dispatchCommand(const QVariant &command)
|
||||
{
|
||||
static const int informationChangedCommandType = QMetaType::type("InformationChangedCommand");
|
||||
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 statePreviewImageChangedCommandType = QMetaType::type("StatePreviewImageChangedCommand");
|
||||
static const int componentCompletedCommandType = QMetaType::type("ComponentCompletedCommand");
|
||||
static const int synchronizeCommandType = QMetaType::type("SynchronizeCommand");
|
||||
static const int tokenCommandType = QMetaType::type("TokenCommand");
|
||||
static const int debugOutputCommandType = QMetaType::type("DebugOutputCommand");
|
||||
static const int puppetAliveCommandType = QMetaType::type("PuppetAliveCommand");
|
||||
static const int changeSelectionCommandType = QMetaType::type("ChangeSelectionCommand");
|
||||
static const int puppetToCreatorCommand = QMetaType::type("PuppetToCreatorCommand");
|
||||
|
||||
if (m_destructing)
|
||||
return;
|
||||
static const int puppetToCreatorCommandType = QMetaType::type("PuppetToCreatorCommand");
|
||||
|
||||
qCInfo(instanceViewBenchmark) << "dispatching command" << command.userType() << command.typeName();
|
||||
if (command.userType() == informationChangedCommandType) {
|
||||
@@ -311,13 +144,8 @@ void NodeInstanceServerProxy::dispatchCommand(const QVariant &command, PuppetStr
|
||||
nodeInstanceClient()->debugOutput(command.value<DebugOutputCommand>());
|
||||
} else if (command.userType() == changeSelectionCommandType) {
|
||||
nodeInstanceClient()->selectionChanged(command.value<ChangeSelectionCommand>());
|
||||
} else if (command.userType() == puppetToCreatorCommand) {
|
||||
} else if (command.userType() == puppetToCreatorCommandType) {
|
||||
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 {
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
@@ -327,33 +155,13 @@ void NodeInstanceServerProxy::dispatchCommand(const QVariant &command, PuppetStr
|
||||
|
||||
NodeInstanceClientInterface *NodeInstanceServerProxy::nodeInstanceClient() const
|
||||
{
|
||||
return m_nodeInstanceView.data();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return m_nodeInstanceView;
|
||||
}
|
||||
|
||||
QString NodeInstanceServerProxy::qrcMappingString() const
|
||||
{
|
||||
if (m_nodeInstanceView && m_nodeInstanceView.data()->model()) {
|
||||
RewriterView *rewriterView = m_nodeInstanceView.data()->model()->rewriterView();
|
||||
if (m_nodeInstanceView && m_nodeInstanceView->model()) {
|
||||
RewriterView *rewriterView = m_nodeInstanceView->model()->rewriterView();
|
||||
if (rewriterView) {
|
||||
QString mappingString;
|
||||
|
||||
@@ -374,265 +182,9 @@ QString NodeInstanceServerProxy::qrcMappingString() const
|
||||
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)
|
||||
{
|
||||
writeCommandToIODecive(command, m_firstSocket.data(), m_writeCommandCounter);
|
||||
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";
|
||||
m_connectionManager.writeCommand(command);
|
||||
}
|
||||
|
||||
void NodeInstanceServerProxy::createInstances(const CreateInstancesCommand &command)
|
||||
|
||||
@@ -48,21 +48,17 @@ namespace QmlDesigner {
|
||||
class NodeInstanceClientInterface;
|
||||
class NodeInstanceView;
|
||||
class NodeInstanceClientProxy;
|
||||
class ConnectionManagerInterface;
|
||||
|
||||
class NodeInstanceServerProxy : public NodeInstanceServerInterface
|
||||
{
|
||||
friend class BaseConnectionManager;
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum PuppetStreamType {
|
||||
FirstPuppetStream,
|
||||
SecondPuppetStream,
|
||||
ThirdPuppetStream,
|
||||
};
|
||||
|
||||
explicit NodeInstanceServerProxy(NodeInstanceView *nodeInstanceView,
|
||||
RunModus runModus,
|
||||
ProjectExplorer::Target *target);
|
||||
ProjectExplorer::Target *target,
|
||||
ConnectionManagerInterface &connectionManager);
|
||||
~NodeInstanceServerProxy() override;
|
||||
void createInstances(const CreateInstancesCommand &command) override;
|
||||
void changeFileUrl(const ChangeFileUrlCommand &command) override;
|
||||
@@ -88,52 +84,22 @@ public:
|
||||
void changeLanguage(const ChangeLanguageCommand &command) override;
|
||||
void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override;
|
||||
|
||||
NodeInstanceView *nodeInstanceView() const { return m_nodeInstanceView; }
|
||||
|
||||
QString qrcMappingString() const;
|
||||
|
||||
protected:
|
||||
void writeCommand(const QVariant &command);
|
||||
void dispatchCommand(const QVariant &command, PuppetStreamType puppetStreamType);
|
||||
void dispatchCommand(const QVariant &command);
|
||||
NodeInstanceClientInterface *nodeInstanceClient() const;
|
||||
void puppetAlive(PuppetStreamType puppetStreamType);
|
||||
QString qrcMappingString() const;
|
||||
|
||||
signals:
|
||||
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:
|
||||
QFile m_captureFileForTest;
|
||||
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;
|
||||
NodeInstanceView *m_nodeInstanceView{};
|
||||
QElapsedTimer m_benchmarkTimer;
|
||||
bool m_destructing = false;
|
||||
ConnectionManagerInterface &m_connectionManager;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "abstractproperty.h"
|
||||
#include "bindingproperty.h"
|
||||
#include "captureddatacommand.h"
|
||||
#include "changeauxiliarycommand.h"
|
||||
#include "changebindingscommand.h"
|
||||
#include "changefileurlcommand.h"
|
||||
@@ -41,6 +42,7 @@
|
||||
#include "clearscenecommand.h"
|
||||
#include "completecomponentcommand.h"
|
||||
#include "componentcompletedcommand.h"
|
||||
#include "connectionmanagerinterface.h"
|
||||
#include "createinstancescommand.h"
|
||||
#include "createscenecommand.h"
|
||||
#include "debugoutputcommand.h"
|
||||
@@ -124,11 +126,10 @@ namespace QmlDesigner {
|
||||
|
||||
\sa ~NodeInstanceView, setRenderOffScreen()
|
||||
*/
|
||||
NodeInstanceView::NodeInstanceView(QObject *parent, NodeInstanceServerInterface::RunModus runModus)
|
||||
: AbstractView(parent),
|
||||
m_baseStatePreviewImage(QSize(100, 100), QImage::Format_ARGB32),
|
||||
m_runModus(runModus),
|
||||
m_restartProcessTimerId(0)
|
||||
NodeInstanceView::NodeInstanceView(ConnectionManagerInterface &connectionManager)
|
||||
: m_connectionManager(connectionManager)
|
||||
, m_baseStatePreviewImage(QSize(100, 100), QImage::Format_ARGB32)
|
||||
, m_restartProcessTimerId(0)
|
||||
{
|
||||
m_baseStatePreviewImage.fill(0xFFFFFF);
|
||||
}
|
||||
@@ -140,7 +141,6 @@ NodeInstanceView::NodeInstanceView(QObject *parent, NodeInstanceServerInterface:
|
||||
NodeInstanceView::~NodeInstanceView()
|
||||
{
|
||||
removeAllInstanceNodeRelationships();
|
||||
delete nodeInstanceServer();
|
||||
m_currentTarget = nullptr;
|
||||
}
|
||||
|
||||
@@ -191,14 +191,16 @@ bool static parentTakesOverRendering(const ModelNode &modelNode)
|
||||
void NodeInstanceView::modelAttached(Model *model)
|
||||
{
|
||||
AbstractView::modelAttached(model);
|
||||
auto server = new NodeInstanceServerProxy(this, m_runModus, m_currentTarget);
|
||||
m_nodeInstanceServer = server;
|
||||
m_nodeInstanceServer = createNodeInstanceServerProxy();
|
||||
m_lastCrashTime.start();
|
||||
connect(server, &NodeInstanceServerProxy::processCrashed, this, &NodeInstanceView::handleCrash);
|
||||
connect(m_nodeInstanceServer.get(),
|
||||
&NodeInstanceServerProxy::processCrashed,
|
||||
this,
|
||||
&NodeInstanceView::handleCrash);
|
||||
|
||||
if (!isSkippedRootNode(rootModelNode())) {
|
||||
nodeInstanceServer()->createScene(createCreateSceneCommand());
|
||||
nodeInstanceServer()->changeSelection(createChangeSelectionCommand(model->selectedNodes(this)));
|
||||
m_nodeInstanceServer->createScene(createCreateSceneCommand());
|
||||
m_nodeInstanceServer->changeSelection(createChangeSelectionCommand(model->selectedNodes(this)));
|
||||
}
|
||||
|
||||
ModelNode stateNode = currentStateNode();
|
||||
@@ -206,15 +208,14 @@ void NodeInstanceView::modelAttached(Model *model)
|
||||
NodeInstance newStateInstance = instanceForModelNode(stateNode);
|
||||
activateState(newStateInstance);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void NodeInstanceView::modelAboutToBeDetached(Model * model)
|
||||
{
|
||||
removeAllInstanceNodeRelationships();
|
||||
if (nodeInstanceServer()) {
|
||||
nodeInstanceServer()->clearScene(createClearSceneCommand());
|
||||
delete nodeInstanceServer();
|
||||
if (m_nodeInstanceServer) {
|
||||
m_nodeInstanceServer->clearScene(createClearSceneCommand());
|
||||
m_nodeInstanceServer.reset();
|
||||
}
|
||||
m_statePreviewImage.clear();
|
||||
m_baseStatePreviewImage = QImage();
|
||||
@@ -274,15 +275,18 @@ void NodeInstanceView::restartProcess()
|
||||
killTimer(m_restartProcessTimerId);
|
||||
|
||||
if (model()) {
|
||||
delete nodeInstanceServer();
|
||||
m_nodeInstanceServer.reset();
|
||||
m_nodeInstanceServer = createNodeInstanceServerProxy();
|
||||
|
||||
auto server = new NodeInstanceServerProxy(this, m_runModus, m_currentTarget);
|
||||
m_nodeInstanceServer = server;
|
||||
connect(server, &NodeInstanceServerProxy::processCrashed, this, &NodeInstanceView::handleCrash);
|
||||
connect(m_nodeInstanceServer.get(),
|
||||
&NodeInstanceServerProxy::processCrashed,
|
||||
this,
|
||||
&NodeInstanceView::handleCrash);
|
||||
|
||||
if (!isSkippedRootNode(rootModelNode())) {
|
||||
nodeInstanceServer()->createScene(createCreateSceneCommand());
|
||||
nodeInstanceServer()->changeSelection(createChangeSelectionCommand(model()->selectedNodes(this)));
|
||||
m_nodeInstanceServer->createScene(createCreateSceneCommand());
|
||||
m_nodeInstanceServer->changeSelection(
|
||||
createChangeSelectionCommand(model()->selectedNodes(this)));
|
||||
}
|
||||
|
||||
ModelNode stateNode = currentStateNode();
|
||||
@@ -313,17 +317,19 @@ void NodeInstanceView::nodeCreated(const ModelNode &createdNode)
|
||||
propertyList.append(createdNode.variantProperty("y"));
|
||||
updatePosition(propertyList);
|
||||
|
||||
nodeInstanceServer()->createInstances(createCreateInstancesCommand({instance}));
|
||||
nodeInstanceServer()->changePropertyValues(createChangeValueCommand(createdNode.variantProperties()));
|
||||
nodeInstanceServer()->completeComponent(createComponentCompleteCommand({instance}));
|
||||
m_nodeInstanceServer->createInstances(createCreateInstancesCommand({instance}));
|
||||
m_nodeInstanceServer->changePropertyValues(
|
||||
createChangeValueCommand(createdNode.variantProperties()));
|
||||
m_nodeInstanceServer->completeComponent(createComponentCompleteCommand({instance}));
|
||||
}
|
||||
|
||||
/*! Notifies the view that \a removedNode will be removed.
|
||||
*/
|
||||
void NodeInstanceView::nodeAboutToBeRemoved(const ModelNode &removedNode)
|
||||
{
|
||||
nodeInstanceServer()->removeInstances(createRemoveInstancesCommand(removedNode));
|
||||
nodeInstanceServer()->removeSharedMemory(createRemoveSharedMemoryCommand("Image", removedNode.internalId()));
|
||||
m_nodeInstanceServer->removeInstances(createRemoveInstancesCommand(removedNode));
|
||||
m_nodeInstanceServer->removeSharedMemory(
|
||||
createRemoveSharedMemoryCommand("Image", removedNode.internalId()));
|
||||
removeInstanceAndSubInstances(removedNode);
|
||||
}
|
||||
|
||||
@@ -343,11 +349,10 @@ void NodeInstanceView::resetHorizontalAnchors(const ModelNode &modelNode)
|
||||
valueList.append(modelNode.variantProperty("width"));
|
||||
|
||||
if (!valueList.isEmpty())
|
||||
nodeInstanceServer()->changePropertyValues(createChangeValueCommand(valueList));
|
||||
m_nodeInstanceServer->changePropertyValues(createChangeValueCommand(valueList));
|
||||
|
||||
if (!bindingList.isEmpty())
|
||||
nodeInstanceServer()->changePropertyBindings(createChangeBindingCommand(bindingList));
|
||||
|
||||
m_nodeInstanceServer->changePropertyBindings(createChangeBindingCommand(bindingList));
|
||||
}
|
||||
|
||||
void NodeInstanceView::resetVerticalAnchors(const ModelNode &modelNode)
|
||||
@@ -366,10 +371,10 @@ void NodeInstanceView::resetVerticalAnchors(const ModelNode &modelNode)
|
||||
valueList.append(modelNode.variantProperty("height"));
|
||||
|
||||
if (!valueList.isEmpty())
|
||||
nodeInstanceServer()->changePropertyValues(createChangeValueCommand(valueList));
|
||||
m_nodeInstanceServer->changePropertyValues(createChangeValueCommand(valueList));
|
||||
|
||||
if (!bindingList.isEmpty())
|
||||
nodeInstanceServer()->changePropertyBindings(createChangeBindingCommand(bindingList));
|
||||
m_nodeInstanceServer->changePropertyBindings(createChangeBindingCommand(bindingList));
|
||||
}
|
||||
|
||||
void NodeInstanceView::propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList)
|
||||
@@ -388,10 +393,10 @@ void NodeInstanceView::propertiesAboutToBeRemoved(const QList<AbstractProperty>&
|
||||
RemoveInstancesCommand removeInstancesCommand = createRemoveInstancesCommand(nodeList);
|
||||
|
||||
if (!removeInstancesCommand.instanceIds().isEmpty())
|
||||
nodeInstanceServer()->removeInstances(removeInstancesCommand);
|
||||
m_nodeInstanceServer->removeInstances(removeInstancesCommand);
|
||||
|
||||
nodeInstanceServer()->removeSharedMemory(createRemoveSharedMemoryCommand("Image", nodeList));
|
||||
nodeInstanceServer()->removeProperties(createRemovePropertiesCommand(nonNodePropertyList));
|
||||
m_nodeInstanceServer->removeSharedMemory(createRemoveSharedMemoryCommand("Image", nodeList));
|
||||
m_nodeInstanceServer->removeProperties(createRemovePropertiesCommand(nonNodePropertyList));
|
||||
|
||||
foreach (const AbstractProperty &property, propertyList) {
|
||||
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*/)
|
||||
{
|
||||
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*/)
|
||||
{
|
||||
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
|
||||
@@ -476,20 +481,21 @@ void NodeInstanceView::nodeReparented(const ModelNode &node, const NodeAbstractP
|
||||
{
|
||||
if (!isSkippedNode(node)) {
|
||||
updateChildren(newPropertyParent);
|
||||
nodeInstanceServer()->reparentInstances(createReparentInstancesCommand(node, newPropertyParent, oldPropertyParent));
|
||||
m_nodeInstanceServer->reparentInstances(
|
||||
createReparentInstancesCommand(node, newPropertyParent, oldPropertyParent));
|
||||
}
|
||||
}
|
||||
|
||||
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*/)
|
||||
{
|
||||
if (hasInstanceForModelNode(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*/)
|
||||
@@ -531,16 +537,16 @@ void NodeInstanceView::auxiliaryDataChanged(const ModelNode &node,
|
||||
if (value.isValid() || name == "invisible") {
|
||||
PropertyValueContainer container(instance.instanceId(), name, value, TypeName());
|
||||
ChangeAuxiliaryCommand changeAuxiliaryCommand({container});
|
||||
nodeInstanceServer()->changeAuxiliaryValues(changeAuxiliaryCommand);
|
||||
m_nodeInstanceServer->changeAuxiliaryValues(changeAuxiliaryCommand);
|
||||
} else {
|
||||
if (node.hasVariantProperty(name)) {
|
||||
PropertyValueContainer container(instance.instanceId(), name, node.variantProperty(name).value(), TypeName());
|
||||
ChangeValuesCommand changeValueCommand({container});
|
||||
nodeInstanceServer()->changePropertyValues(changeValueCommand);
|
||||
m_nodeInstanceServer->changePropertyValues(changeValueCommand);
|
||||
} else if (node.hasBindingProperty(name)) {
|
||||
PropertyBindingContainer container(instance.instanceId(), name, node.bindingProperty(name).expression(), TypeName());
|
||||
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();
|
||||
if (auto multiLanguageAspect = QmlProjectManager::QmlMultiLanguageAspect::current(m_currentTarget))
|
||||
multiLanguageAspect->setCurrentLocale(languageAsString);
|
||||
nodeInstanceServer()->changeLanguage({languageAsString});
|
||||
m_nodeInstanceServer->changeLanguage({languageAsString});
|
||||
} 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)) {
|
||||
NodeInstance instance = instanceForModelNode(node);
|
||||
ChangeNodeSourceCommand changeNodeSourceCommand(instance.instanceId(), newNodeSource);
|
||||
nodeInstanceServer()->changeNodeSource(changeNodeSourceCommand);
|
||||
m_nodeInstanceServer->changeNodeSource(changeNodeSourceCommand);
|
||||
}
|
||||
}
|
||||
|
||||
void NodeInstanceView::capturedData(const CapturedDataCommand &) {}
|
||||
|
||||
void NodeInstanceView::currentStateChanged(const ModelNode &node)
|
||||
{
|
||||
NodeInstance newStateInstance = instanceForModelNode(node);
|
||||
@@ -790,12 +798,6 @@ void NodeInstanceView::updatePosition(const QList<VariantProperty> &propertyList
|
||||
emitInstanceInformationsChange(informationChangeHash);
|
||||
}
|
||||
|
||||
NodeInstanceServerInterface *NodeInstanceView::nodeInstanceServer() const
|
||||
{
|
||||
return m_nodeInstanceServer.data();
|
||||
}
|
||||
|
||||
|
||||
NodeInstance NodeInstanceView::loadNode(const ModelNode &node)
|
||||
{
|
||||
NodeInstance instance(NodeInstance::create(node));
|
||||
@@ -810,12 +812,12 @@ NodeInstance NodeInstanceView::loadNode(const ModelNode &node)
|
||||
|
||||
void NodeInstanceView::activateState(const NodeInstance &instance)
|
||||
{
|
||||
nodeInstanceServer()->changeState(ChangeStateCommand(instance.instanceId()));
|
||||
m_nodeInstanceServer->changeState(ChangeStateCommand(instance.instanceId()));
|
||||
}
|
||||
|
||||
void NodeInstanceView::activateBaseState()
|
||||
{
|
||||
nodeInstanceServer()->changeState(ChangeStateCommand(-1));
|
||||
m_nodeInstanceServer->changeState(ChangeStateCommand(-1));
|
||||
}
|
||||
|
||||
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())
|
||||
emitInstancePropertyChange(valuePropertyChangeList);
|
||||
@@ -1456,7 +1459,7 @@ void NodeInstanceView::sendToken(const QString &token, int number, const QVector
|
||||
foreach (const ModelNode &node, nodeVector)
|
||||
instanceIdVector.append(node.internalId());
|
||||
|
||||
nodeInstanceServer()->token(TokenCommand(token, number, instanceIdVector));
|
||||
m_nodeInstanceServer->token(TokenCommand(token, number, instanceIdVector));
|
||||
}
|
||||
|
||||
void NodeInstanceView::selectionChanged(const ChangeSelectionCommand &command)
|
||||
@@ -1471,7 +1474,7 @@ void NodeInstanceView::selectionChanged(const ChangeSelectionCommand &command)
|
||||
void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand &command)
|
||||
{
|
||||
if (command.type() == PuppetToCreatorCommand::Edit3DToolState) {
|
||||
if (!m_nodeInstanceServer.isNull()) {
|
||||
if (m_nodeInstanceServer) {
|
||||
auto data = qvariant_cast<QVariantList>(command.data());
|
||||
if (data.size() == 3) {
|
||||
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,
|
||||
const QList<ModelNode> & /*lastSelectedNodeList*/)
|
||||
{
|
||||
nodeInstanceServer()->changeSelection(createChangeSelectionCommand(selectedNodeList));
|
||||
m_nodeInstanceServer->changeSelection(createChangeSelectionCommand(selectedNodeList));
|
||||
}
|
||||
|
||||
void NodeInstanceView::sendInputEvent(QInputEvent *e) const
|
||||
{
|
||||
nodeInstanceServer()->inputEvent(InputEventCommand(e));
|
||||
m_nodeInstanceServer->inputEvent(InputEventCommand(e));
|
||||
}
|
||||
|
||||
void NodeInstanceView::view3DAction(const View3DActionCommand &command)
|
||||
{
|
||||
nodeInstanceServer()->view3DAction(command);
|
||||
m_nodeInstanceServer->view3DAction(command);
|
||||
}
|
||||
|
||||
void NodeInstanceView::edit3DViewResized(const QSize &size) const
|
||||
{
|
||||
nodeInstanceServer()->update3DViewState(Update3dViewStateCommand(size));
|
||||
m_nodeInstanceServer->update3DViewState(Update3dViewStateCommand(size));
|
||||
}
|
||||
|
||||
void NodeInstanceView::timerEvent(QTimerEvent *event)
|
||||
|
||||
@@ -176,39 +176,46 @@ PuppetCreator::PuppetCreator(ProjectExplorer::Target *target, const Model *model
|
||||
{
|
||||
}
|
||||
|
||||
QProcess *PuppetCreator::createPuppetProcess(const QString &puppetMode,
|
||||
const QString &socketToken,
|
||||
QObject *handlerObject,
|
||||
const char *outputSlot,
|
||||
const char *finishSlot,
|
||||
const QStringList &customOptions) const
|
||||
QProcessUniquePointer PuppetCreator::createPuppetProcess(
|
||||
const QString &puppetMode,
|
||||
const QString &socketToken,
|
||||
QObject *handlerObject,
|
||||
std::function<void()> processOutputCallback,
|
||||
std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
|
||||
const QStringList &customOptions) const
|
||||
{
|
||||
return puppetProcess(qml2PuppetPath(m_availablePuppetType),
|
||||
qmlPuppetDirectory(m_availablePuppetType),
|
||||
puppetMode,
|
||||
socketToken,
|
||||
handlerObject,
|
||||
outputSlot,
|
||||
finishSlot,
|
||||
processOutputCallback,
|
||||
processFinishCallback,
|
||||
customOptions);
|
||||
}
|
||||
|
||||
|
||||
QProcess *PuppetCreator::puppetProcess(const QString &puppetPath,
|
||||
const QString &workingDirectory,
|
||||
const QString &puppetMode,
|
||||
const QString &socketToken,
|
||||
QObject *handlerObject,
|
||||
const char *outputSlot,
|
||||
const char *finishSlot,
|
||||
const QStringList &customOptions) const
|
||||
QProcessUniquePointer PuppetCreator::puppetProcess(
|
||||
const QString &puppetPath,
|
||||
const QString &workingDirectory,
|
||||
const QString &puppetMode,
|
||||
const QString &socketToken,
|
||||
QObject *handlerObject,
|
||||
std::function<void()> processOutputCallback,
|
||||
std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
|
||||
const QStringList &customOptions) const
|
||||
{
|
||||
auto puppetProcess = new QProcess;
|
||||
QProcessUniquePointer puppetProcess{new QProcess};
|
||||
puppetProcess->setObjectName(puppetMode);
|
||||
puppetProcess->setProcessEnvironment(processEnvironment());
|
||||
|
||||
QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, puppetProcess, &QProcess::kill);
|
||||
QObject::connect(puppetProcess, SIGNAL(finished(int,QProcess::ExitStatus)), handlerObject, finishSlot);
|
||||
QObject::connect(QCoreApplication::instance(),
|
||||
&QCoreApplication::aboutToQuit,
|
||||
puppetProcess.get(),
|
||||
&QProcess::kill);
|
||||
QObject::connect(puppetProcess.get(),
|
||||
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||
handlerObject,
|
||||
processFinishCallback);
|
||||
|
||||
#ifndef QMLDESIGNER_TEST
|
||||
QString forwardOutput = m_designerSettings.value(DesignerSettingsKey::
|
||||
@@ -218,7 +225,7 @@ QProcess *PuppetCreator::puppetProcess(const QString &puppetPath,
|
||||
#endif
|
||||
if (forwardOutput == puppetMode || forwardOutput == "all") {
|
||||
puppetProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||
QObject::connect(puppetProcess, SIGNAL(readyRead()), handlerObject, outputSlot);
|
||||
QObject::connect(puppetProcess.get(), &QProcess::readyRead, handlerObject, processOutputCallback);
|
||||
}
|
||||
puppetProcess->setWorkingDirectory(workingDirectory);
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "qprocessuniqueptr.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
@@ -53,12 +55,13 @@ public:
|
||||
|
||||
void createQml2PuppetExecutableIfMissing();
|
||||
|
||||
QProcess *createPuppetProcess(const QString &puppetMode,
|
||||
const QString &socketToken,
|
||||
QObject *handlerObject,
|
||||
const char *outputSlot,
|
||||
const char *finishSlot,
|
||||
const QStringList &customOptions = {}) const;
|
||||
QProcessUniquePointer createPuppetProcess(
|
||||
const QString &puppetMode,
|
||||
const QString &socketToken,
|
||||
QObject *handlerObject,
|
||||
std::function<void()> processOutputCallback,
|
||||
std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
|
||||
const QStringList &customOptions = {}) const;
|
||||
|
||||
void setQrcMappingString(const QString qrcMapping);
|
||||
|
||||
@@ -82,14 +85,14 @@ protected:
|
||||
|
||||
bool checkPuppetIsReady(const QString &puppetPath) const;
|
||||
bool qtIsSupported() const;
|
||||
QProcess *puppetProcess(const QString &puppetPath,
|
||||
const QString &workingDirectory,
|
||||
const QString &puppetMode,
|
||||
const QString &socketToken,
|
||||
QObject *handlerObject,
|
||||
const char *outputSlot,
|
||||
const char *finishSlot,
|
||||
const QStringList &customOptions) const;
|
||||
QProcessUniquePointer puppetProcess(const QString &puppetPath,
|
||||
const QString &workingDirectory,
|
||||
const QString &puppetMode,
|
||||
const QString &socketToken,
|
||||
QObject *handlerObject,
|
||||
std::function<void()> processOutputCallback,
|
||||
std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
|
||||
const QStringList &customOptions) const;
|
||||
|
||||
QProcessEnvironment processEnvironment() const;
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -27,23 +27,24 @@
|
||||
|
||||
#ifndef QMLDESIGNER_TEST
|
||||
|
||||
#include <componentaction.h>
|
||||
#include <designmodewidget.h>
|
||||
#include <crumblebar.h>
|
||||
#include <abstractview.h>
|
||||
#include <rewriterview.h>
|
||||
#include <nodeinstanceview.h>
|
||||
#include <itemlibraryview.h>
|
||||
#include <navigatorview.h>
|
||||
#include <stateseditorview.h>
|
||||
#include <componentaction.h>
|
||||
#include <componentview.h>
|
||||
#include <crumblebar.h>
|
||||
#include <debugview.h>
|
||||
#include <designeractionmanagerview.h>
|
||||
#include <designmodewidget.h>
|
||||
#include <edit3dview.h>
|
||||
#include <formeditorview.h>
|
||||
#include <texteditorview.h>
|
||||
#include <propertyeditorview.h>
|
||||
#include <componentview.h>
|
||||
#include <debugview.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 <utils/algorithm.h>
|
||||
@@ -59,10 +60,11 @@ static Q_LOGGING_CATEGORY(viewBenchmark, "qtc.viewmanager.attach", QtWarningMsg)
|
||||
class ViewManagerData
|
||||
{
|
||||
public:
|
||||
InteractiveConnectionManager connectionManager;
|
||||
QmlModelState savedState;
|
||||
Internal::DebugView debugView;
|
||||
DesignerActionManagerView designerActionManagerView;
|
||||
NodeInstanceView nodeInstanceView;
|
||||
NodeInstanceView nodeInstanceView{connectionManager};
|
||||
ComponentView componentView;
|
||||
Edit3DView edit3DView;
|
||||
FormEditorView formEditorView;
|
||||
@@ -81,7 +83,7 @@ static CrumbleBar *crumbleBar() {
|
||||
}
|
||||
|
||||
ViewManager::ViewManager()
|
||||
: d(new ViewManagerData)
|
||||
: d(std::make_unique<ViewManagerData>())
|
||||
{
|
||||
d->formEditorView.setGotoErrorCallback([this](int line, int column) {
|
||||
d->textEditorView.gotoCursorPosition(line, column);
|
||||
@@ -92,10 +94,9 @@ ViewManager::ViewManager()
|
||||
|
||||
ViewManager::~ViewManager()
|
||||
{
|
||||
foreach (const QPointer<AbstractView> &view, d->additionalViews)
|
||||
for (const QPointer<AbstractView> &view : d->additionalViews)
|
||||
delete view.data();
|
||||
|
||||
delete d;
|
||||
}
|
||||
|
||||
DesignDocument *ViewManager::currentDesignDocument() const
|
||||
|
||||
@@ -321,6 +321,17 @@ Project {
|
||||
"instances/puppetdialog.cpp",
|
||||
"instances/puppetdialog.h",
|
||||
"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/metainfo.cpp",
|
||||
"metainfo/metainforeader.cpp",
|
||||
|
||||
Reference in New Issue
Block a user