Implement notification of Remote IO

master
Jeremy Hu 2019-03-17 23:34:12 +09:30
parent ceeccc7211
commit 283df87c51
6 changed files with 500 additions and 35 deletions

View File

@ -2128,21 +2128,21 @@ void Document::setPartXmirrorState(QUuid partId, bool mirrored)
emit skeletonChanged();
}
void Document::setPartZmirrorState(QUuid partId, bool mirrored)
{
auto part = partMap.find(partId);
if (part == partMap.end()) {
qDebug() << "Part not found:" << partId;
return;
}
if (part->second.zMirrored == mirrored)
return;
part->second.zMirrored = mirrored;
part->second.dirty = true;
settleOrigin();
emit partZmirrorStateChanged(partId);
emit skeletonChanged();
}
//void Document::setPartZmirrorState(QUuid partId, bool mirrored)
//{
// auto part = partMap.find(partId);
// if (part == partMap.end()) {
// qDebug() << "Part not found:" << partId;
// return;
// }
// if (part->second.zMirrored == mirrored)
// return;
// part->second.zMirrored = mirrored;
// part->second.dirty = true;
// settleOrigin();
// emit partZmirrorStateChanged(partId);
// emit skeletonChanged();
//}
void Document::setPartDeformThickness(QUuid partId, float thickness)
{

View File

@ -384,9 +384,9 @@ signals:
void turnaroundChanged();
void editModeChanged();
void skeletonChanged();
void resultSkeletonChanged();
//void resultSkeletonChanged();
void resultTextureChanged();
void resultBakedTextureChanged();
//void resultBakedTextureChanged();
void postProcessedResultChanged();
void resultRigChanged();
void rigChanged();
@ -395,7 +395,7 @@ signals:
void partSubdivStateChanged(QUuid partId);
void partDisableStateChanged(QUuid partId);
void partXmirrorStateChanged(QUuid partId);
void partZmirrorStateChanged(QUuid partId);
//void partZmirrorStateChanged(QUuid partId);
void partDeformThicknessChanged(QUuid partId);
void partDeformWidthChanged(QUuid partId);
void partRoundStateChanged(QUuid partId);
@ -550,7 +550,7 @@ public slots:
void setPartSubdivState(QUuid partId, bool subdived);
void setPartDisableState(QUuid partId, bool disabled);
void setPartXmirrorState(QUuid partId, bool mirrored);
void setPartZmirrorState(QUuid partId, bool mirrored);
//void setPartZmirrorState(QUuid partId, bool mirrored);
void setPartDeformThickness(QUuid partId, float thickness);
void setPartDeformWidth(QUuid partId, float width);
void setPartRoundState(QUuid partId, bool rounded);

View File

@ -61,6 +61,11 @@ const std::map<DocumentWindow *, QUuid> &DocumentWindow::documentWindows()
return g_documentWindows;
}
Document *DocumentWindow::document()
{
return m_document;
}
void DocumentWindow::showAcknowlegements()
{
if (!g_acknowlegementsWidget) {
@ -1353,7 +1358,7 @@ void DocumentWindow::showExportPreview()
connect(m_document, &Document::resultMeshChanged, m_exportPreviewWidget, &ExportPreviewWidget::checkSpinner);
connect(m_document, &Document::exportReady, m_exportPreviewWidget, &ExportPreviewWidget::checkSpinner);
connect(m_document, &Document::resultTextureChanged, m_exportPreviewWidget, &ExportPreviewWidget::updateTexturePreview);
connect(m_document, &Document::resultBakedTextureChanged, m_exportPreviewWidget, &ExportPreviewWidget::updateTexturePreview);
//connect(m_document, &Document::resultBakedTextureChanged, m_exportPreviewWidget, &ExportPreviewWidget::updateTexturePreview);
registerDialog(m_exportPreviewWidget);
}
m_exportPreviewWidget->show();

View File

@ -27,6 +27,7 @@ signals:
public:
DocumentWindow();
~DocumentWindow();
Document *document();
static DocumentWindow *createDocumentWindow();
static const std::map<DocumentWindow *, QUuid> &documentWindows();
static void showAcknowlegements();

View File

@ -14,6 +14,17 @@ RemoteIoConnection::RemoteIoConnection(QTcpSocket *tcpSocket) :
m_commandHandlers["listwindow"] = &RemoteIoConnection::commandListWindow;
m_commandHandlers["selectwindow"] = &RemoteIoConnection::commandSelectWindow;
m_commandHandlers["undo"] = &RemoteIoConnection::commandUndo;
m_commandHandlers["redo"] = &RemoteIoConnection::commandRedo;
m_commandHandlers["paste"] = &RemoteIoConnection::commandPaste;
m_commandHandlers["removenode"] = &RemoteIoConnection::commandRemoveNode;
m_commandHandlers["removeedge"] = &RemoteIoConnection::commandRemoveEdge;
m_commandHandlers["removepart"] = &RemoteIoConnection::commandRemovePart;
m_commandHandlers["addnode"] = &RemoteIoConnection::commandAddNode;
if (!DocumentWindow::documentWindows().empty()) {
connectDocumentWindow(DocumentWindow::documentWindows().begin()->first);
}
}
RemoteIoConnection::~RemoteIoConnection()
@ -41,12 +52,16 @@ void RemoteIoConnection::handleRead()
}
QString errorMessage;
auto response = findHandler->second(this, -1 == parametersBegin ? QByteArray() : command.mid(parametersBegin), &errorMessage);
QByteArray fullResponse;
if (errorMessage.isEmpty())
m_tcpSocket->write(QByteArray("+OK\r\n").toHex());
fullResponse += QByteArray("+OK\r\n");
else
m_tcpSocket->write(("-" + errorMessage + "\r\n").toUtf8().toHex());
m_tcpSocket->write(response.toHex());
m_tcpSocket->write(0);
fullResponse += ("-" + errorMessage + "\r\n").toUtf8();
fullResponse += response;
fullResponse = fullResponse.toHex();
fullResponse.append((char)0);
m_tcpSocket->write(fullResponse);
}
}
@ -64,7 +79,7 @@ QString RemoteIoConnection::nameFromCommand(const QByteArray &command, int *para
if (isWhitespace(command[i])) {
int nameEnd = i;
if (nullptr != parametersBegin) {
while (isWhitespace(command[i]))
while (i < command.size() && isWhitespace(command[i]))
++i;
if (i < command.size())
*parametersBegin = i;
@ -92,6 +107,26 @@ QByteArray RemoteIoConnection::nextCommandFromCache()
return QByteArray();
}
QString RemoteIoConnection::nextParameter(const QByteArray &parameters, int *offset)
{
if (*offset >= parameters.size())
return QString();
for (int i = *offset; i < parameters.size(); ++i) {
if (isWhitespace(parameters[i])) {
int parameterEnd = i;
auto parameter = parameters.mid(*offset, parameterEnd);
while (i < parameters.size() && isWhitespace(parameters[i]))
++i;
*offset = i;
return parameter;
}
}
auto parameter = parameters.mid(*offset);
*offset = parameters.size();
return parameter;
}
QByteArray RemoteIoConnection::commandListWindow(const QByteArray &parameters, QString *errorMessage)
{
Q_UNUSED(parameters);
@ -104,11 +139,284 @@ QByteArray RemoteIoConnection::commandListWindow(const QByteArray &parameters, Q
return response;
}
void RemoteIoConnection::respondEventWithId(const QString &eventName, const QUuid &id)
{
QByteArray fullResponse = QString("#%1 %2\r\n").arg(eventName).arg(id.toString()).toUtf8();
fullResponse = fullResponse.toHex();
fullResponse.append((char)0);
m_tcpSocket->write(fullResponse);
}
void RemoteIoConnection::respondEvent(const QString &eventName)
{
QByteArray fullResponse = QString("#%1\r\n").arg(eventName).toUtf8();
fullResponse = fullResponse.toHex();
fullResponse.append((char)0);
m_tcpSocket->write(fullResponse);
}
void RemoteIoConnection::connectDocumentSignals()
{
if (nullptr == m_currentDocumentWindow)
return;
auto document = m_currentDocumentWindow->document();
m_documentConnections << connect(document, &Document::nodeAdded, this, [&](QUuid nodeId) {
respondEventWithId("nodeadded", nodeId);
});
m_documentConnections << connect(document, &Document::partAdded, this, [&](QUuid partId) {
respondEventWithId("partadded", partId);
});
m_documentConnections << connect(document, &Document::edgeAdded, this, [&](QUuid edgeId) {
respondEventWithId("edgeadded", edgeId);
});
m_documentConnections << connect(document, &Document::partRemoved, this, [&](QUuid partId) {
respondEventWithId("partremoved", partId);
});
m_documentConnections << connect(document, &Document::componentNameChanged, this, [&](QUuid componentId) {
respondEventWithId("componentnamechanged", componentId);
});
m_documentConnections << connect(document, &Document::componentChildrenChanged, this, [&](QUuid componentId) {
respondEventWithId("componentchildrenchanged", componentId);
});
m_documentConnections << connect(document, &Document::componentRemoved, this, [&](QUuid componentId) {
respondEventWithId("componentremoved", componentId);
});
m_documentConnections << connect(document, &Document::componentAdded, this, [&](QUuid componentId) {
respondEventWithId("componentadded", componentId);
});
m_documentConnections << connect(document, &Document::componentExpandStateChanged, this, [&](QUuid componentId) {
respondEventWithId("componentexpandstatechanged", componentId);
});
m_documentConnections << connect(document, &Document::nodeRemoved, this, [&](QUuid nodeId) {
respondEventWithId("noderemoved", nodeId);
});
m_documentConnections << connect(document, &Document::edgeRemoved, this, [&](QUuid edgeId) {
respondEventWithId("edgeremoved", edgeId);
});
m_documentConnections << connect(document, &Document::nodeRadiusChanged, this, [&](QUuid nodeId) {
respondEventWithId("noderadiuschanged", nodeId);
});
m_documentConnections << connect(document, &Document::nodeBoneMarkChanged, this, [&](QUuid nodeId) {
respondEventWithId("nodebonemarkchanged", nodeId);
});
m_documentConnections << connect(document, &Document::nodeOriginChanged, this, [&](QUuid nodeId) {
respondEventWithId("nodeoriginchanged", nodeId);
});
m_documentConnections << connect(document, &Document::edgeChanged, this, [&](QUuid edgeId) {
respondEventWithId("edgechanged", edgeId);
});
m_documentConnections << connect(document, &Document::partPreviewChanged, this, [&](QUuid partId) {
respondEventWithId("partpreviewchanged", partId);
});
m_documentConnections << connect(document, &Document::resultMeshChanged, this, [&]() {
respondEvent("resultmeshchanged");
});
m_documentConnections << connect(document, &Document::turnaroundChanged, this, [&]() {
respondEvent("turnaroundchanged");
});
m_documentConnections << connect(document, &Document::editModeChanged, this, [&]() {
respondEvent("editmodechanged");
});
m_documentConnections << connect(document, &Document::skeletonChanged, this, [&]() {
respondEvent("skeletonchanged");
});
m_documentConnections << connect(document, &Document::resultTextureChanged, this, [&]() {
respondEvent("resulttexturechanged");
});
m_documentConnections << connect(document, &Document::postProcessedResultChanged, this, [&]() {
respondEvent("postprocessedresultchanged");
});
m_documentConnections << connect(document, &Document::resultRigChanged, this, [&]() {
respondEvent("resultrigchanged");
});
m_documentConnections << connect(document, &Document::rigChanged, this, [&]() {
respondEvent("rigchanged");
});
m_documentConnections << connect(document, &Document::partLockStateChanged, this, [&](QUuid partId) {
respondEventWithId("partlockstatechanged", partId);
});
m_documentConnections << connect(document, &Document::partVisibleStateChanged, this, [&](QUuid partId) {
respondEventWithId("partvisiblestatechanged", partId);
});
m_documentConnections << connect(document, &Document::partSubdivStateChanged, this, [&](QUuid partId) {
respondEventWithId("partsubdivstatechanged", partId);
});
m_documentConnections << connect(document, &Document::partDisableStateChanged, this, [&](QUuid partId) {
respondEventWithId("partdisablestatechanged", partId);
});
m_documentConnections << connect(document, &Document::partXmirrorStateChanged, this, [&](QUuid partId) {
respondEventWithId("partxmirrorstatechanged", partId);
});
m_documentConnections << connect(document, &Document::partDeformThicknessChanged, this, [&](QUuid partId) {
respondEventWithId("partdeformthicknesschanged", partId);
});
m_documentConnections << connect(document, &Document::partDeformWidthChanged, this, [&](QUuid partId) {
respondEventWithId("partdeformwidthchanged", partId);
});
m_documentConnections << connect(document, &Document::partRoundStateChanged, this, [&](QUuid partId) {
respondEventWithId("partroundstatechanged", partId);
});
m_documentConnections << connect(document, &Document::partColorStateChanged, this, [&](QUuid partId) {
respondEventWithId("partcolorstatechanged", partId);
});
m_documentConnections << connect(document, &Document::partCutRotationChanged, this, [&](QUuid partId) {
respondEventWithId("partcutrotationchanged", partId);
});
m_documentConnections << connect(document, &Document::partCutTemplateChanged, this, [&](QUuid partId) {
respondEventWithId("partcuttemplatechanged", partId);
});
m_documentConnections << connect(document, &Document::partMaterialIdChanged, this, [&](QUuid partId) {
respondEventWithId("partmaterialidchanged", partId);
});
m_documentConnections << connect(document, &Document::partChamferStateChanged, this, [&](QUuid partId) {
respondEventWithId("partchamferstatechanged", partId);
});
m_documentConnections << connect(document, &Document::componentCombineModeChanged, this, [&](QUuid componentId) {
respondEventWithId("componentcombinemodechanged", componentId);
});
m_documentConnections << connect(document, &Document::cleanup, this, [&]() {
respondEvent("cleanup");
});
m_documentConnections << connect(document, &Document::originChanged, this, [&]() {
respondEvent("originchanged");
});
m_documentConnections << connect(document, &Document::xlockStateChanged, this, [&]() {
respondEvent("xlockstatechanged");
});
m_documentConnections << connect(document, &Document::ylockStateChanged, this, [&]() {
respondEvent("ylockstatechanged");
});
m_documentConnections << connect(document, &Document::zlockStateChanged, this, [&]() {
respondEvent("zlockstatechanged");
});
m_documentConnections << connect(document, &Document::radiusLockStateChanged, this, [&]() {
respondEvent("radiuslockstatechanged");
});
m_documentConnections << connect(document, &Document::checkPart, this, [&](QUuid partId) {
respondEventWithId("checkpart", partId);
});
m_documentConnections << connect(document, &Document::partChecked, this, [&](QUuid partId) {
respondEventWithId("partchecked", partId);
});
m_documentConnections << connect(document, &Document::partUnchecked, this, [&]() {
respondEvent("partunchecked");
});
m_documentConnections << connect(document, &Document::enableBackgroundBlur, this, [&]() {
respondEvent("enablebackgroundblur");
});
m_documentConnections << connect(document, &Document::disableBackgroundBlur, this, [&]() {
respondEvent("disablebackgroundblur");
});
m_documentConnections << connect(document, &Document::exportReady, this, [&]() {
respondEvent("exportready");
});
m_documentConnections << connect(document, &Document::uncheckAll, this, [&]() {
respondEvent("uncheckall");
});
m_documentConnections << connect(document, &Document::checkNode, this, [&](QUuid nodeId) {
respondEventWithId("checknode", nodeId);
});
m_documentConnections << connect(document, &Document::checkEdge, this, [&](QUuid edgeId) {
respondEventWithId("checkedge", edgeId);
});
m_documentConnections << connect(document, &Document::optionsChanged, this, [&]() {
respondEvent("optionschanged");
});
m_documentConnections << connect(document, &Document::rigTypeChanged, this, [&]() {
respondEvent("rigtypechanged");
});
m_documentConnections << connect(document, &Document::posesChanged, this, [&]() {
respondEvent("poseschanged");
});
m_documentConnections << connect(document, &Document::motionsChanged, this, [&]() {
respondEvent("motionschanged");
});
m_documentConnections << connect(document, &Document::poseAdded, this, [&](QUuid poseId) {
respondEventWithId("poseadded", poseId);
});
m_documentConnections << connect(document, &Document::poseRemoved, this, [&](QUuid poseId) {
respondEventWithId("poseremoved", poseId);
});
m_documentConnections << connect(document, &Document::poseListChanged, this, [&]() {
respondEvent("poselistchanged");
});
m_documentConnections << connect(document, &Document::poseNameChanged, this, [&](QUuid poseId) {
respondEventWithId("posenamechanged", poseId);
});
m_documentConnections << connect(document, &Document::poseFramesChanged, this, [&](QUuid poseId) {
respondEventWithId("poseframeschanged", poseId);
});
m_documentConnections << connect(document, &Document::poseTurnaroundImageIdChanged, this, [&](QUuid poseId) {
respondEventWithId("poseturnaroundimageidchanged", poseId);
});
m_documentConnections << connect(document, &Document::posePreviewChanged, this, [&](QUuid poseId) {
respondEventWithId("posepreviewchanged", poseId);
});
m_documentConnections << connect(document, &Document::motionAdded, this, [&](QUuid motionId) {
respondEventWithId("motionadded", motionId);
});
m_documentConnections << connect(document, &Document::motionRemoved, this, [&](QUuid motionId) {
respondEventWithId("motionremoved", motionId);
});
m_documentConnections << connect(document, &Document::motionListChanged, this, [&]() {
respondEvent("motionlistchanged");
});
m_documentConnections << connect(document, &Document::motionNameChanged, this, [&](QUuid motionId) {
respondEventWithId("motionnamechanged", motionId);
});
m_documentConnections << connect(document, &Document::motionClipsChanged, this, [&](QUuid motionId) {
respondEventWithId("motionclipschanged", motionId);
});
m_documentConnections << connect(document, &Document::motionPreviewChanged, this, [&](QUuid motionId) {
respondEventWithId("motionpreviewchanged", motionId);
});
m_documentConnections << connect(document, &Document::motionResultChanged, this, [&](QUuid motionId) {
respondEventWithId("motionresultchanged", motionId);
});
m_documentConnections << connect(document, &Document::materialAdded, this, [&](QUuid materialId) {
respondEventWithId("materialadded", materialId);
});
m_documentConnections << connect(document, &Document::materialRemoved, this, [&](QUuid materialId) {
respondEventWithId("materialremoved", materialId);
});
m_documentConnections << connect(document, &Document::materialListChanged, this, [&]() {
respondEvent("materiallistchanged");
});
m_documentConnections << connect(document, &Document::materialNameChanged, this, [&](QUuid materialId) {
respondEventWithId("materialnamechanged", materialId);
});
m_documentConnections << connect(document, &Document::materialLayersChanged, this, [&](QUuid materialId) {
respondEventWithId("materiallayerschanged", materialId);
});
m_documentConnections << connect(document, &Document::materialPreviewChanged, this, [&](QUuid materialId) {
respondEventWithId("materialpreviewchanged", materialId);
});
m_documentConnections << connect(document, &Document::meshGenerating, this, [&]() {
respondEvent("meshgenerating");
});
m_documentConnections << connect(document, &Document::postProcessing, this, [&]() {
respondEvent("postprocessing");
});
m_documentConnections << connect(document, &Document::textureGenerating, this, [&]() {
respondEvent("texturegenerating");
});
m_documentConnections << connect(document, &Document::textureChanged, this, [&]() {
respondEvent("texturechanged");
});
}
void RemoteIoConnection::disconnectDocumentSignals()
{
for (const auto &it: m_documentConnections) {
disconnect(it);
}
m_documentConnections.clear();
}
QByteArray RemoteIoConnection::commandSelectWindow(const QByteArray &parameters, QString *errorMessage)
{
Q_UNUSED(parameters);
Q_UNUSED(errorMessage);
QByteArray response;
if (parameters.isEmpty()) {
*errorMessage = "Must specify window id";
@ -122,16 +430,152 @@ QByteArray RemoteIoConnection::commandSelectWindow(const QByteArray &parameters,
for (const auto &it: DocumentWindow::documentWindows()) {
if (it.second == windowId) {
qDebug() << "Remote io select window:" << it.second;
m_currentDocumentWindow = it.first;
connect(m_currentDocumentWindow, &DocumentWindow::uninialized, this, [&]() {
if (sender() == m_currentDocumentWindow) {
m_currentDocumentWindow = nullptr;
qDebug() << "Selected window destroyed";
}
});
connectDocumentWindow(it.first);
return QByteArray();
}
}
*errorMessage = "Window id not found:" + QString(parameters);
return QByteArray();
}
void RemoteIoConnection::connectDocumentWindow(DocumentWindow *window)
{
if (m_currentDocumentWindow == window)
return;
disconnectDocumentSignals();
m_currentDocumentWindow = window;
if (nullptr != m_currentDocumentWindow) {
connect(m_currentDocumentWindow, &DocumentWindow::uninialized, this, [&]() {
if (sender() == m_currentDocumentWindow) {
m_currentDocumentWindow = nullptr;
qDebug() << "Selected window destroyed";
}
});
connectDocumentSignals();
}
}
#define COMMAND_PRECHECK() do { \
if (nullptr == m_currentDocumentWindow) { \
*errorMessage = "No window selected"; \
return QByteArray(); \
} \
} while (false)
QByteArray RemoteIoConnection::commandUndo(const QByteArray &parameters, QString *errorMessage)
{
COMMAND_PRECHECK();
m_currentDocumentWindow->document()->undo();
return QByteArray();
}
QByteArray RemoteIoConnection::commandRedo(const QByteArray &parameters, QString *errorMessage)
{
COMMAND_PRECHECK();
m_currentDocumentWindow->document()->redo();
return QByteArray();
}
QByteArray RemoteIoConnection::commandPaste(const QByteArray &parameters, QString *errorMessage)
{
COMMAND_PRECHECK();
m_currentDocumentWindow->document()->paste();
return QByteArray();
}
QByteArray RemoteIoConnection::commandRemoveNode(const QByteArray &parameters, QString *errorMessage)
{
COMMAND_PRECHECK();
if (parameters.isEmpty()) {
*errorMessage = "Must specify node id";
return QByteArray();
}
QUuid nodeId = QUuid(QString(parameters));
if (nodeId.isNull()) {
*errorMessage = "Node id is invalid:" + QString(parameters);
return QByteArray();
}
m_currentDocumentWindow->document()->removeNode(nodeId);
return QByteArray();
}
QByteArray RemoteIoConnection::commandRemoveEdge(const QByteArray &parameters, QString *errorMessage)
{
COMMAND_PRECHECK();
if (parameters.isEmpty()) {
*errorMessage = "Must specify edge id";
return QByteArray();
}
QUuid edgeId = QUuid(QString(parameters));
if (edgeId.isNull()) {
*errorMessage = "Edge id is invalid:" + QString(parameters);
return QByteArray();
}
m_currentDocumentWindow->document()->removeEdge(edgeId);
return QByteArray();
}
QByteArray RemoteIoConnection::commandRemovePart(const QByteArray &parameters, QString *errorMessage)
{
COMMAND_PRECHECK();
if (parameters.isEmpty()) {
*errorMessage = "Must specify part id";
return QByteArray();
}
QUuid partId = QUuid(QString(parameters));
if (partId.isNull()) {
*errorMessage = "Part id is invalid:" + QString(parameters);
return QByteArray();
}
m_currentDocumentWindow->document()->removePart(partId);
return QByteArray();
}
QByteArray RemoteIoConnection::commandAddNode(const QByteArray &parameters, QString *errorMessage)
{
COMMAND_PRECHECK();
// float x, float y, float z, float radius, QUuid fromNodeId
int offset = 0;
auto xString = nextParameter(parameters, &offset);
if (xString.isEmpty()) {
*errorMessage = "Must specify x parameter";
return QByteArray();
}
float x = xString.toFloat();
auto yString = nextParameter(parameters, &offset);
if (yString.isEmpty()) {
*errorMessage = "Must specify y parameter";
return QByteArray();
}
float y = yString.toFloat();
auto zString = nextParameter(parameters, &offset);
if (zString.isEmpty()) {
*errorMessage = "Must specify z parameter";
return QByteArray();
}
float z = zString.toFloat();
auto radiusString = nextParameter(parameters, &offset);
if (radiusString.isEmpty()) {
*errorMessage = "Must specify radius parameter";
return QByteArray();
}
float radius = radiusString.toFloat();
auto fromNodeIdString = nextParameter(parameters, &offset);
QUuid fromNodeId = QUuid(fromNodeIdString);
m_currentDocumentWindow->document()->addNode(x, y, z, radius, fromNodeId);
return QByteArray();
}

View File

@ -5,6 +5,7 @@
#include <vector>
#include <QByteArray>
#include <map>
#include <QList>
#include "documentwindow.h"
class RemoteIoConnection;
@ -26,13 +27,27 @@ private:
QByteArray m_receiveCache;
DocumentWindow *m_currentDocumentWindow = nullptr;
std::map<QString, CommandHandler> m_commandHandlers;
QList<QMetaObject::Connection> m_documentConnections;
QByteArray nextCommandFromCache();
QString nameFromCommand(const QByteArray &command, int *parametersBegin=nullptr);
QString nextParameter(const QByteArray &parameters, int *offset);
bool isWhitespace(char c);
void connectDocumentSignals();
void disconnectDocumentSignals();
void connectDocumentWindow(DocumentWindow *window);
void respondEventWithId(const QString &eventName, const QUuid &id);
void respondEvent(const QString &eventName);
QByteArray commandListWindow(const QByteArray &parameters, QString *errorMessage);
QByteArray commandSelectWindow(const QByteArray &parameters, QString *errorMessage);
QByteArray commandUndo(const QByteArray &parameters, QString *errorMessage);
QByteArray commandRedo(const QByteArray &parameters, QString *errorMessage);
QByteArray commandPaste(const QByteArray &parameters, QString *errorMessage);
QByteArray commandRemoveNode(const QByteArray &parameters, QString *errorMessage);
QByteArray commandRemoveEdge(const QByteArray &parameters, QString *errorMessage);
QByteArray commandRemovePart(const QByteArray &parameters, QString *errorMessage);
QByteArray commandAddNode(const QByteArray &parameters, QString *errorMessage);
};
#endif