bool DesignerExternalEditor::startEditor(const QString &fileName, QString *errorMessage) { EditorLaunchData data; // Find the editor binary if (!getEditorLaunchData(fileName, &QtSupport::BaseQtVersion::designerCommand, QLatin1String(designerBinaryC), QStringList(), false, &data, errorMessage)) { return false; } // Known one? const ProcessCache::iterator it = m_processCache.find(data.binary); if (it != m_processCache.end()) { // Process is known, write to its socket to cause it to open the file if (debug) qDebug() << Q_FUNC_INFO << "\nWriting to socket:" << data.binary << fileName; QTcpSocket *socket = it.value(); if (!socket->write(fileName.toUtf8() + '\n')) { *errorMessage = tr("Qt Designer is not responding (%1).").arg(socket->errorString()); return false; } return true; } // No process yet. Create socket & launch the process QTcpServer server; if (!server.listen(QHostAddress::LocalHost)) { *errorMessage = tr("Unable to create server socket: %1").arg(server.errorString()); return false; } const quint16 port = server.serverPort(); if (debug) qDebug() << Q_FUNC_INFO << "\nLaunching server:" << port << data.binary << fileName; // Start first one with file and socket as '-client port file' // Wait for the socket listening data.arguments.push_front(QString::number(port)); data.arguments.push_front(QLatin1String("-client")); if (!startEditorProcess(data, errorMessage)) return false; // Set up signal mapper to track process termination via socket if (!m_terminationMapper) { m_terminationMapper = new QSignalMapper(this); connect(m_terminationMapper, SIGNAL(mapped(QString)), this, SLOT(processTerminated(QString))); } // Insert into cache if socket is created, else try again next time if (server.waitForNewConnection(3000)) { QTcpSocket *socket = server.nextPendingConnection(); socket->setParent(this); m_processCache.insert(data.binary, socket); m_terminationMapper->setMapping(socket, data.binary); connect(socket, SIGNAL(disconnected()), m_terminationMapper, SLOT(map())); connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), m_terminationMapper, SLOT(map())); } return true; }
void DesignerExternalEditor::processTerminated(const QString &binary) { const ProcessCache::iterator it = m_processCache.find(binary); if (it == m_processCache.end()) return; // Make sure socket is closed and cleaned, remove from cache QTcpSocket *socket = it.value(); m_processCache.erase(it); // Note that closing will cause the slot to be retriggered if (debug) qDebug() << Q_FUNC_INFO << '\n' << binary << socket->state(); if (socket->state() == QAbstractSocket::ConnectedState) socket->close(); socket->deleteLater(); }