nodeinstanceserverproxy.cpp 10.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#include "nodeinstanceserverproxy.h"

#include <QLocalServer>
#include <QLocalSocket>
#include <QProcess>
#include <QCoreApplication>
#include <QUuid>

#include "propertyabstractcontainer.h"
#include "propertyvaluecontainer.h"
#include "propertybindingcontainer.h"
#include "instancecontainer.h"
#include "createinstancescommand.h"
#include "createscenecommand.h"
#include "changevaluescommand.h"
#include "changebindingscommand.h"
#include "changefileurlcommand.h"
#include "removeinstancescommand.h"
#include "clearscenecommand.h"
#include "removepropertiescommand.h"
#include "reparentinstancescommand.h"
#include "changeidscommand.h"
#include "changestatecommand.h"
24
#include "addimportcommand.h"
25
#include "completecomponentcommand.h"
26 27 28 29

#include "informationchangedcommand.h"
#include "pixmapchangedcommand.h"
#include "valueschangedcommand.h"
30
#include "childrenchangedcommand.h"
31 32
#include "imagecontainer.h"
#include "statepreviewimagechangedcommand.h"
33
#include "componentcompletedcommand.h"
34

35 36
#include "synchronizecommand.h"

37 38 39 40 41
#include "nodeinstanceview.h"
#include "nodeinstanceclientproxy.h"

namespace QmlDesigner {

42
NodeInstanceServerProxy::NodeInstanceServerProxy(NodeInstanceView *nodeInstanceView, RunModus runModus)
43 44 45
    : NodeInstanceServerInterface(nodeInstanceView),
      m_localServer(new QLocalServer(this)),
      m_nodeInstanceView(nodeInstanceView),
46
      m_firstBlockSize(0),
47 48 49
      m_secondBlockSize(0),
      m_runModus(runModus),
      m_synchronizeId(-1)
50 51 52 53
{
   QString socketToken(QUuid::createUuid().toString());

   m_localServer->listen(socketToken);
54 55
   m_localServer->setMaxPendingConnections(2);

Marco Bubke's avatar
Marco Bubke committed
56 57 58
   QString applicationPath =  QCoreApplication::applicationDirPath();
   if (runModus == TestModus)
       applicationPath += "/../../../../../bin";
59 60 61 62 63
#ifdef Q_OS_MACX
   applicationPath += "/qmlpuppet.app/Contents/MacOS";
#endif
   applicationPath += "/qmlpuppet";

64
   m_qmlPuppetEditorProcess = new QProcess;
65
   connect(m_qmlPuppetEditorProcess.data(), SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(processFinished(int,QProcess::ExitStatus)));
66
   connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), m_qmlPuppetEditorProcess.data(), SLOT(kill()));
67 68 69
   bool fowardQmlpuppetOutput = !qgetenv("FORWARD_QMLPUPPET_OUTPUT").isEmpty();
   if (fowardQmlpuppetOutput)
       m_qmlPuppetEditorProcess->setProcessChannelMode(QProcess::ForwardedChannels);
70
   m_qmlPuppetEditorProcess->start(applicationPath, QStringList() << socketToken << "editormode" << "-graphicssystem raster");
71

72
   if (runModus == NormalModus) {
73
       m_qmlPuppetPreviewProcess = new QProcess;
74
       connect(m_qmlPuppetPreviewProcess.data(), SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(processFinished(int,QProcess::ExitStatus)));
75
       connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), m_qmlPuppetPreviewProcess.data(), SLOT(kill()));
76 77
       if (fowardQmlpuppetOutput)
           m_qmlPuppetPreviewProcess->setProcessChannelMode(QProcess::ForwardedChannels);
78 79
       m_qmlPuppetPreviewProcess->start(applicationPath, QStringList() << socketToken << "previewmode" << "-graphicssystem raster");
   }
80 81

   connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(deleteLater()));
82 83

   m_qmlPuppetEditorProcess->waitForStarted();
84

85 86
   connect(m_qmlPuppetEditorProcess.data(), SIGNAL(finished(int)), m_qmlPuppetEditorProcess.data(),SLOT(deleteLater()));

87 88
   if (runModus == NormalModus) {
       m_qmlPuppetPreviewProcess->waitForStarted();
89
       connect(m_qmlPuppetPreviewProcess.data(), SIGNAL(finished(int)), m_qmlPuppetPreviewProcess.data(),SLOT(deleteLater()));
90
   }
91 92 93 94 95 96

   if (!m_localServer->hasPendingConnections())
       m_localServer->waitForNewConnection(-1);

   m_firstSocket = m_localServer->nextPendingConnection();
   connect(m_firstSocket.data(), SIGNAL(readyRead()), this, SLOT(readFirstDataStream()));
97

98 99 100
   if (runModus == NormalModus) {
       if (!m_localServer->hasPendingConnections())
           m_localServer->waitForNewConnection(-1);
101

102 103 104
       m_secondSocket = m_localServer->nextPendingConnection();
       connect(m_secondSocket.data(), SIGNAL(readyRead()), this, SLOT(readSecondDataStream()));
   }
105

106 107 108 109 110
   m_localServer->close();
}

NodeInstanceServerProxy::~NodeInstanceServerProxy()
{
111 112
    disconnect(this, SLOT(processFinished(int,QProcess::ExitStatus)));

113 114 115 116 117 118
    if (m_firstSocket)
        m_firstSocket->close();

    if (m_secondSocket)
        m_secondSocket->close();

119

120
    if (m_qmlPuppetEditorProcess)
121 122
        m_qmlPuppetEditorProcess->kill();

123
    if (m_qmlPuppetPreviewProcess)
124
        m_qmlPuppetPreviewProcess->kill();
125 126 127 128 129 130 131
}

void NodeInstanceServerProxy::dispatchCommand(const QVariant &command)
{
    static const int informationChangedCommandType = QMetaType::type("InformationChangedCommand");
    static const int valuesChangedCommandType = QMetaType::type("ValuesChangedCommand");
    static const int pixmapChangedCommandType = QMetaType::type("PixmapChangedCommand");
132
    static const int childrenChangedCommandType = QMetaType::type("ChildrenChangedCommand");
133
    static const int statePreviewImageChangedCommandType = QMetaType::type("StatePreviewImageChangedCommand");
134
    static const int componentCompletedCommandType = QMetaType::type("ComponentCompletedCommand");
135
    static const int synchronizeCommandType = QMetaType::type("SynchronizeCommand");
136 137 138 139 140 141 142

    if (command.userType() ==  informationChangedCommandType)
        nodeInstanceClient()->informationChanged(command.value<InformationChangedCommand>());
    else if (command.userType() ==  valuesChangedCommandType)
        nodeInstanceClient()->valuesChanged(command.value<ValuesChangedCommand>());
    else if (command.userType() ==  pixmapChangedCommandType)
        nodeInstanceClient()->pixmapChanged(command.value<PixmapChangedCommand>());
143 144
    else if (command.userType() == childrenChangedCommandType)
        nodeInstanceClient()->childrenChanged(command.value<ChildrenChangedCommand>());
145 146
    else if (command.userType() == statePreviewImageChangedCommandType)
        nodeInstanceClient()->statePreviewImagesChanged(command.value<StatePreviewImageChangedCommand>());
147 148
    else if (command.userType() == componentCompletedCommandType)
        nodeInstanceClient()->componentCompleted(command.value<ComponentCompletedCommand>());
149 150 151 152
    else if (command.userType() == synchronizeCommandType) {
        SynchronizeCommand synchronizeCommand = command.value<SynchronizeCommand>();
        m_synchronizeId = synchronizeCommand.synchronizeId();
    }  else
153 154 155 156 157 158 159 160
        Q_ASSERT(false);
}

NodeInstanceClientInterface *NodeInstanceServerProxy::nodeInstanceClient() const
{
    return m_nodeInstanceView.data();
}

161
static void writeCommandToSocket(const QVariant &command, QLocalSocket *socket)
162
{
163 164 165 166 167 168 169 170 171 172
    if(socket) {
        QByteArray block;
        QDataStream out(&block, QIODevice::WriteOnly);
        out << quint32(0);
        out << command;
        out.device()->seek(0);
        out << quint32(block.size() - sizeof(quint32));

        socket->write(block);
    }
173 174 175 176 177 178
}

void NodeInstanceServerProxy::writeCommand(const QVariant &command)
{
    writeCommandToSocket(command, m_firstSocket.data());
    writeCommandToSocket(command, m_secondSocket.data());
179 180 181 182 183 184 185 186 187 188 189 190 191 192

    if (m_runModus == TestModus) {
        static int synchronizeId = 0;
        synchronizeId++;
        SynchronizeCommand synchronizeCommand(synchronizeId);

        writeCommandToSocket(QVariant::fromValue(synchronizeCommand), m_firstSocket.data());

        while(m_firstSocket->waitForReadyRead()) {
                readFirstDataStream();
                if (m_synchronizeId == synchronizeId)
                    return;
        }
    }
193 194
}

195
void NodeInstanceServerProxy::processFinished(int /*exitCode*/, QProcess::ExitStatus exitStatus)
196
{
197 198 199 200
    if (m_firstSocket)
        m_firstSocket->close();
    if (m_secondSocket)
        m_secondSocket->close();
201 202
    if (exitStatus == QProcess::CrashExit)
        emit processCrashed();
203 204
}

205

206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
void NodeInstanceServerProxy::readFirstDataStream()
{
    QList<QVariant> commandList;

    while (!m_firstSocket->atEnd()) {
        if (m_firstSocket->bytesAvailable() < int(sizeof(quint32)))
            break;

        QDataStream in(m_firstSocket.data());

        if (m_firstBlockSize == 0) {
            in >> m_firstBlockSize;
        }

        if (m_firstSocket->bytesAvailable() < m_firstBlockSize)
            break;

        QVariant command;
        in >> command;
        m_firstBlockSize = 0;

        commandList.append(command);
    }

    foreach (const QVariant &command, commandList) {
        dispatchCommand(command);
    }
}

void NodeInstanceServerProxy::readSecondDataStream()
236 237 238
{
    QList<QVariant> commandList;

239 240
    while (!m_secondSocket->atEnd()) {
        if (m_secondSocket->bytesAvailable() < int(sizeof(quint32)))
241 242
            break;

243
        QDataStream in(m_secondSocket.data());
244

245 246
        if (m_secondBlockSize == 0) {
            in >> m_secondBlockSize;
247 248
        }

249
        if (m_secondSocket->bytesAvailable() < m_secondBlockSize)
250 251 252 253
            break;

        QVariant command;
        in >> command;
254
        m_secondBlockSize = 0;
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318

        commandList.append(command);
    }

    foreach (const QVariant &command, commandList) {
        dispatchCommand(command);
    }
}

void NodeInstanceServerProxy::createInstances(const CreateInstancesCommand &command)
{
    writeCommand(QVariant::fromValue(command));
}

void NodeInstanceServerProxy::changeFileUrl(const ChangeFileUrlCommand &command)
{
    writeCommand(QVariant::fromValue(command));
}

void NodeInstanceServerProxy::createScene(const CreateSceneCommand &command)
{
    writeCommand(QVariant::fromValue(command));
}

void NodeInstanceServerProxy::clearScene(const ClearSceneCommand &command)
{
    writeCommand(QVariant::fromValue(command));
}

void NodeInstanceServerProxy::removeInstances(const RemoveInstancesCommand &command)
{
    writeCommand(QVariant::fromValue(command));
}

void NodeInstanceServerProxy::removeProperties(const RemovePropertiesCommand &command)
{
    writeCommand(QVariant::fromValue(command));
}

void NodeInstanceServerProxy::changePropertyBindings(const ChangeBindingsCommand &command)
{
    writeCommand(QVariant::fromValue(command));
}

void NodeInstanceServerProxy::changePropertyValues(const ChangeValuesCommand &command)
{
    writeCommand(QVariant::fromValue(command));
}

void NodeInstanceServerProxy::reparentInstances(const ReparentInstancesCommand &command)
{
    writeCommand(QVariant::fromValue(command));
}

void NodeInstanceServerProxy::changeIds(const ChangeIdsCommand &command)
{
    writeCommand(QVariant::fromValue(command));
}

void NodeInstanceServerProxy::changeState(const ChangeStateCommand &command)
{
    writeCommand(QVariant::fromValue(command));
}

319 320 321 322
void NodeInstanceServerProxy::addImport(const AddImportCommand &command)
{
    writeCommand(QVariant::fromValue(command));
}
323 324 325 326 327

void NodeInstanceServerProxy::completeComponent(const CompleteComponentCommand &command)
{
    writeCommand(QVariant::fromValue(command));
}
328
} // namespace QmlDesigner