diff options
Diffstat (limited to 'src/libs/installer/qprocesswrapper.cpp')
-rw-r--r-- | src/libs/installer/qprocesswrapper.cpp | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/src/libs/installer/qprocesswrapper.cpp b/src/libs/installer/qprocesswrapper.cpp new file mode 100644 index 000000000..e15168fac --- /dev/null +++ b/src/libs/installer/qprocesswrapper.cpp @@ -0,0 +1,413 @@ +/************************************************************************** +** +** This file is part of Installer Framework +** +** Copyright (c) 2010-2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "qprocesswrapper.h" + +#include "fsengineclient.h" +#include "templates.cpp" + +#include <QtCore/QThread> + +#include <QtNetwork/QTcpSocket> + +// -- QProcessWrapper::Private + +class QProcessWrapper::Private +{ +public: + Private(QProcessWrapper *qq) + : q(qq), + ignoreTimer(false), + socket(0) + {} + + bool createSocket() + { + if (!FSEngineClientHandler::instance().isActive()) + return false; + if (socket != 0 && socket->state() == static_cast< int >(QAbstractSocket::ConnectedState)) + return true; + if (socket != 0) + delete socket; + socket = new QTcpSocket; + + if (!FSEngineClientHandler::instance().connect(socket)) + return false; + stream.setDevice(socket); + stream.setVersion(QDataStream::Qt_4_2); + + stream << QString::fromLatin1("createQProcess"); + socket->flush(); + stream.device()->waitForReadyRead(-1); + quint32 test; + stream >> test; + stream.device()->readAll(); + + q->startTimer(250); + + return true; + } + + class TimerBlocker + { + public: + explicit TimerBlocker(const QProcessWrapper *wrapper) + : w(const_cast<QProcessWrapper *>(wrapper)) + { + w->d->ignoreTimer = true; + } + + ~TimerBlocker() + { + w->d->ignoreTimer = false; + } + + private: + QProcessWrapper *const w; + }; + +private: + QProcessWrapper *const q; + +public: + bool ignoreTimer; + + QProcess process; + mutable QTcpSocket *socket; + mutable QDataStream stream; +}; + + +// -- QProcessWrapper + +QProcessWrapper::QProcessWrapper(QObject *parent) + : QObject(parent), + d(new Private(this)) +{ + connect(&d->process, SIGNAL(bytesWritten(qint64)), SIGNAL(bytesWritten(qint64))); + connect(&d->process, SIGNAL(aboutToClose()), SIGNAL(aboutToClose())); + connect(&d->process, SIGNAL(readChannelFinished()), SIGNAL(readChannelFinished())); + connect(&d->process, SIGNAL(error(QProcess::ProcessError)), SIGNAL(error(QProcess::ProcessError))); + connect(&d->process, SIGNAL(readyReadStandardOutput()), SIGNAL(readyReadStandardOutput())); + connect(&d->process, SIGNAL(readyReadStandardError()), SIGNAL(readyReadStandardError())); + connect(&d->process, SIGNAL(finished(int)), SIGNAL(finished(int))); + connect(&d->process, SIGNAL(finished(int,QProcess::ExitStatus)), SIGNAL(finished(int,QProcess::ExitStatus))); + connect(&d->process, SIGNAL(readyRead()), SIGNAL(readyRead())); + connect(&d->process, SIGNAL(started()), SIGNAL(started())); + connect(&d->process, SIGNAL(stateChanged(QProcess::ProcessState)), SIGNAL(stateChanged(QProcess::ProcessState))); +} + +QProcessWrapper::~QProcessWrapper() +{ + if (d->socket != 0) { + d->stream << QString::fromLatin1("destroyQProcess"); + d->socket->flush(); + quint32 result; + d->stream >> result; + + if (QThread::currentThread() == d->socket->thread()) { + d->socket->close(); + delete d->socket; + } else { + d->socket->deleteLater(); + } + } + delete d; +} + +void QProcessWrapper::timerEvent(QTimerEvent *event) +{ + Q_UNUSED(event) + + if (d->ignoreTimer) + return; + + QList<QVariant> receivedSignals; + { + const Private::TimerBlocker blocker(this); + + d->stream << QString::fromLatin1("getQProcessSignals"); + d->socket->flush(); + d->stream.device()->waitForReadyRead(-1); + quint32 test; + d->stream >> test; + d->stream >> receivedSignals; + d->stream.device()->readAll(); + } + + while (!receivedSignals.isEmpty()) { + const QString name = receivedSignals.takeFirst().toString(); + if (name == QLatin1String("started")) { + emit started(); + } else if (name == QLatin1String("readyRead")) { + emit readyRead(); + } else if (name == QLatin1String("stateChanged")) { + const QProcess::ProcessState newState = + static_cast<QProcess::ProcessState> (receivedSignals.takeFirst().toInt()); + emit stateChanged(newState); + } else if (name == QLatin1String("finished")) { + const int exitCode = receivedSignals.takeFirst().toInt(); + const QProcess::ExitStatus exitStatus = + static_cast<QProcess::ExitStatus> (receivedSignals.takeFirst().toInt()); + emit finished(exitCode); + emit finished(exitCode, exitStatus); + } + } +} + +bool startDetached(const QString &program, const QStringList &args, const QString &workingDirectory, + qint64 *pid); + +bool QProcessWrapper::startDetached(const QString &program, const QStringList &arguments, + const QString &workingDirectory, qint64 *pid) +{ + QProcessWrapper w; + if (w.d->createSocket()) { + const QPair<bool, qint64> result = callRemoteMethod<QPair<bool, qint64> >(w.d->stream, + QLatin1String("QProcess::startDetached"), program, arguments, workingDirectory); + if (pid != 0) + *pid = result.second; + return result.first; + } + return ::startDetached(program, arguments, workingDirectory, pid); +} + +bool QProcessWrapper::startDetached(const QString &program, const QStringList &arguments) +{ + return startDetached(program, arguments, QDir::currentPath()); +} + +bool QProcessWrapper::startDetached(const QString &program) +{ + return startDetached(program, QStringList()); +} + +void QProcessWrapper::setProcessChannelMode(QProcessWrapper::ProcessChannelMode mode) +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) { + callRemoteVoidMethod(d->stream, QLatin1String("QProcess::setProcessChannelMode"), + static_cast<QProcess::ProcessChannelMode>(mode)); + } else { + d->process.setProcessChannelMode(static_cast<QProcess::ProcessChannelMode>(mode)); + } +} + +/*! + Cancels the process. This methods tries to terminate the process + gracefully by calling QProcess::terminate. After 10 seconds, the process gets killed. + */ +void QProcessWrapper::cancel() +{ + if (state() == QProcessWrapper::Running) + terminate(); + + if (!waitForFinished(10000)) + kill(); +} + +void QProcessWrapper::setReadChannel(QProcessWrapper::ProcessChannel chan) +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) { + callRemoteVoidMethod(d->stream, QLatin1String("QProcess::setReadChannel"), + static_cast<QProcess::ProcessChannel>(chan)); + } else { + d->process.setReadChannel(static_cast<QProcess::ProcessChannel>(chan)); + } +} + +bool QProcessWrapper::waitForFinished(int msecs) +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + return callRemoteMethod<bool>(d->stream, QLatin1String("QProcess::waitForFinished"), msecs); + return d->process.waitForFinished(msecs); +} + +bool QProcessWrapper::waitForStarted(int msecs) +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + return callRemoteMethod<bool>(d->stream, QLatin1String("QProcess::waitForStarted"), msecs); + return d->process.waitForStarted(msecs); +} + +qint64 QProcessWrapper::write(const QByteArray &data) +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + return callRemoteMethod<qint64>(d->stream, QLatin1String("QProcess::write"), data); + return d->process.write(data); +} + +void QProcessWrapper::closeWriteChannel() +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + callRemoteVoidMethod<void>(d->stream, QLatin1String("QProcess::closeWriteChannel")); + else + d->process.closeWriteChannel(); +} + +int QProcessWrapper::exitCode() const +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + return callRemoteMethod<int>(d->stream, QLatin1String("QProcess::exitCode")); + return static_cast< int>(d->process.exitCode()); +} + +QProcessWrapper::ExitStatus QProcessWrapper::exitStatus() const +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + return callRemoteMethod<QProcessWrapper::ExitStatus>(d->stream, QLatin1String("QProcess::exitStatus")); + return static_cast< QProcessWrapper::ExitStatus>(d->process.exitStatus()); +} + +void QProcessWrapper::kill() +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + callRemoteVoidMethod<void>(d->stream, QLatin1String("QProcess::kill")); + else + d->process.kill(); +} + +QByteArray QProcessWrapper::readAll() +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + return callRemoteMethod<QByteArray>(d->stream, QLatin1String("QProcess::readAll")); + return d->process.readAll(); +} + +QByteArray QProcessWrapper::readAllStandardOutput() +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + return callRemoteMethod<QByteArray>(d->stream, QLatin1String("QProcess::readAllStandardOutput")); + return d->process.readAllStandardOutput(); +} + +void QProcessWrapper::start(const QString ¶m1, const QStringList ¶m2, QIODevice::OpenMode param3) +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + callRemoteVoidMethod(d->stream, QLatin1String("QProcess::start"), param1, param2, param3); + else + d->process.start(param1, param2, param3); +} + +void QProcessWrapper::start(const QString ¶m1) +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + callRemoteVoidMethod(d->stream, QLatin1String("QProcess::start"), param1); + else + d->process.start(param1); +} + +QProcessWrapper::ProcessState QProcessWrapper::state() const +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + return callRemoteMethod<QProcessWrapper::ProcessState>(d->stream, QLatin1String("QProcess::state")); + return static_cast< QProcessWrapper::ProcessState>(d->process.state()); +} + +void QProcessWrapper::terminate() +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + callRemoteVoidMethod<void>(d->stream, QLatin1String("QProcess::terminate")); + else + d->process.terminate(); +} + +QProcessWrapper::ProcessChannel QProcessWrapper::readChannel() const +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) { + return callRemoteMethod<QProcessWrapper::ProcessChannel>(d->stream, + QLatin1String("QProcess::readChannel")); + } + return static_cast< QProcessWrapper::ProcessChannel>(d->process.readChannel()); +} + +QProcessWrapper::ProcessChannelMode QProcessWrapper::processChannelMode() const +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) { + return callRemoteMethod<QProcessWrapper::ProcessChannelMode>(d->stream, + QLatin1String("QProcess::processChannelMode")); + } + return static_cast< QProcessWrapper::ProcessChannelMode>(d->process.processChannelMode()); +} + +QString QProcessWrapper::workingDirectory() const +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + return callRemoteMethod<QString>(d->stream, QLatin1String("QProcess::workingDirectory")); + return static_cast< QString>(d->process.workingDirectory()); +} + +void QProcessWrapper::setEnvironment(const QStringList ¶m1) +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + callRemoteVoidMethod(d->stream, QLatin1String("QProcess::setEnvironment"), param1); + else + d->process.setEnvironment(param1); +} + +#ifdef Q_OS_WIN +void QProcessWrapper::setNativeArguments(const QString ¶m1) +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + callRemoteVoidMethod(d->stream, QLatin1String("QProcess::setNativeArguments"), param1); + else + d->process.setNativeArguments(param1); +} +#endif + +void QProcessWrapper::setWorkingDirectory(const QString ¶m1) +{ + const Private::TimerBlocker blocker(this); + if (d->createSocket()) + callRemoteVoidMethod(d->stream, QLatin1String("QProcess::setWorkingDirectory"), param1); + else + d->process.setWorkingDirectory(param1); +} |