diff --git a/src/util/externalcommand.h b/src/util/externalcommand.h --- a/src/util/externalcommand.h +++ b/src/util/externalcommand.h @@ -122,10 +122,16 @@ Q_SIGNALS: void progress(int); void reportSignal(const QVariantMap&); - + + // remove above signals + void newData(); + public Q_SLOTS: void emitProgress(KJob*, unsigned long percent) { emit progress(percent); } void emitReport(const QVariantMap& report) { emit reportSignal(report); } + + void emitNewData(int percent); + void emitNewData(QString& message); private: void setExitCode(int i); diff --git a/src/util/externalcommand.cpp b/src/util/externalcommand.cpp --- a/src/util/externalcommand.cpp +++ b/src/util/externalcommand.cpp @@ -397,6 +397,18 @@ } +void ExternalCommand::emitNewData(int percent) +{ + // emmit signal indicating new data and later connect to that signal + emit newData(); +} + +void ExternalCommand::emitNewData(QString& message) +{ + // emmit signal indicating new data and later connect to that signal + emit newData(); +} + void DBusThread::run() { if (!QDBusConnection::systemBus().registerService(QStringLiteral("org.kde.kpmcore.applicationinterface")) || diff --git a/src/util/externalcommandhelper.h b/src/util/externalcommandhelper.h --- a/src/util/externalcommandhelper.h +++ b/src/util/externalcommandhelper.h @@ -35,6 +35,7 @@ Q_SIGNALS: void progress(int percent); void reportProgress(const QVariantMap& progress); + // remove above signals later on public: bool readData(const QString& sourceDevice, QByteArray& buffer, const qint64 offset, const qint64 size); diff --git a/src/util/externalcommandhelper.cpp b/src/util/externalcommandhelper.cpp --- a/src/util/externalcommandhelper.cpp +++ b/src/util/externalcommandhelper.cpp @@ -58,21 +58,48 @@ if (!QDBusConnection::systemBus().isConnected() || !QDBusConnection::systemBus().registerService(QStringLiteral("org.kde.kpmcore.helperinterface")) || - !QDBusConnection::systemBus().registerObject(QStringLiteral("/Helper"), this, QDBusConnection::ExportAllSlots)) { + !QDBusConnection::systemBus().registerService(QStringLiteral("org.kde.kpmcore.applicationinterface")) || + !QDBusConnection::systemBus().registerObject(QStringLiteral("/Helper"), this, QDBusConnection::ExportAllSlots) || + !QDBusConnection::systemBus().registerObject(QStringLiteral("/Application"), this, QDBusConnection::ExportAllSlots)) { + qDebug() << "Failed to initialize the Helper"; qWarning() << QDBusConnection::systemBus().lastError().message(); - // We have no reason to live when Main GUI app has expired - - qApp->quit(); return app.exec(); } m_loop = std::make_unique(); - emit reportProgress(QVariantMap()); + + /*================Call App slot===================*/ + if (!QDBusConnection::systemBus().isConnected()) { + qWarning() << QDBusConnection::systemBus().lastError().message(); + QTimer::singleShot(1000, this, &QCoreApplication::quit); + return false; + } + + auto interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.applicationinterface"), + QStringLiteral("/Application"), QDBusConnection::systemBus(), this); + interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days + + // We send zero percent new data on initial start-up + QDBusPendingCall pcall = interface->emitNewData(0); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); + QEventLoop loop; + + auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) { + loop.exit(); + + if (watcher->isError()) + qWarning() << watcher->error(); + }; + + connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop); + loop.exec(); + /*================End Call App slot===================*/ // QDBus Service watcher which keeps an eye on the client (Main GUI app) // End the loop and return only once the client has unregistered over the QDBus. @@ -93,7 +120,6 @@ return app.exec(); } - /** Reads the given number of bytes from the sourceDevice into the given buffer. @param sourceDevice device or file to read from @param buffer buffer to store the bytes read in @@ -177,17 +203,39 @@ QByteArray buffer; int percent = 0; + QTime t; - t.start(); - QVariantMap report; + /*================Call App slot===================*/ + if (!QDBusConnection::systemBus().isConnected()) { + qWarning() << QDBusConnection::systemBus().lastError().message(); + QTimer::singleShot(1000, this, &QCoreApplication::quit); + return QVariantMap(); + } + + auto interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.applicationinterface"), + QStringLiteral("/Application"), QDBusConnection::systemBus(), this); + interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days + + // We send report progress as new data to main Application + QDBusPendingCall pcall = interface->emitNewData(xi18nc("@info:progress", "Copying %1 blocks (%2 bytes) from %3 to %4, direction: %5.", blocksToCopy, + sourceLength, readOffset, writeOffset, copyDirection == 1 ? i18nc("direction: left", "left") + : i18nc("direction: right", "right"))); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); + QEventLoop loop; - report[QStringLiteral("report")] = xi18nc("@info:progress", "Copying %1 blocks (%2 bytes) from %3 to %4, direction: %5.", blocksToCopy, - sourceLength, readOffset, writeOffset, copyDirection == 1 ? i18nc("direction: left", "left") - : i18nc("direction: right", "right")); + auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) { + loop.exit(); - emit reportProgress(report); + if (watcher->isError()) + qWarning() << watcher->error(); + }; + + connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop); + loop.exec(); + /*================End Call App slot===================*/ bool rval = true; @@ -206,10 +254,63 @@ if (percent % 5 == 0 && t.elapsed() > 1000) { const qint64 mibsPerSec = (blocksCopied * blockSize / 1024 / 1024) / (t.elapsed() / 1000); const qint64 estSecsLeft = (100 - percent) * t.elapsed() / percent / 1000; - report[QStringLiteral("report")]= xi18nc("@info:progress", "Copying %1 MiB/second, estimated time left: %2", mibsPerSec, QTime(0, 0).addSecs(estSecsLeft).toString()); - emit reportProgress(report); + + /*================Call App slot===================*/ + if (!QDBusConnection::systemBus().isConnected()) { + qWarning() << QDBusConnection::systemBus().lastError().message(); + QTimer::singleShot(1000, this, &QCoreApplication::quit); + return QVariantMap(); + } + + auto interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.applicationinterface"), + QStringLiteral("/Application"), QDBusConnection::systemBus(), this); + interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days + + // We send report progress as new data to main Application + QDBusPendingCall pcall = interface->emitNewData(xi18nc("@info:progress", "Copying %1 MiB/second, estimated time left: %2", mibsPerSec, QTime(0, 0).addSecs(estSecsLeft).toString())); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); + QEventLoop loop; + + auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) { + loop.exit(); + + if (watcher->isError()) + qWarning() << watcher->error(); + }; + + connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop); + loop.exec(); + /*================End Call App slot===================*/ + } - emit progress(percent); + /*================Call App slot===================*/ + if (!QDBusConnection::systemBus().isConnected()) { + qWarning() << QDBusConnection::systemBus().lastError().message(); + QTimer::singleShot(1000, this, &QCoreApplication::quit); + return QVariantMap(); + } + + auto interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.applicationinterface"), + QStringLiteral("/Application"), QDBusConnection::systemBus(), this); + interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days + + // We send report progress as new data to main Application + QDBusPendingCall pcall = interface->emitNewData(percent); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); + QEventLoop loop; + + auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) { + loop.exit(); + + if (watcher->isError()) + qWarning() << watcher->error(); + }; + + connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop); + loop.exec(); + /*================End Call App slot===================*/ } } @@ -221,9 +322,35 @@ const qint64 lastBlockWriteOffset = copyDirection > 0 ? writeOffset + blockSize * blocksCopied : targetFirstByte; report[QStringLiteral("report")]= xi18nc("@info:progress", "Copying remainder of block size %1 from %2 to %3.", lastBlock, lastBlockReadOffset, lastBlockWriteOffset); - - emit reportProgress(report); - + + /*================Call App slot===================*/ + if (!QDBusConnection::systemBus().isConnected()) { + qWarning() << QDBusConnection::systemBus().lastError().message(); + QTimer::singleShot(1000, this, &QCoreApplication::quit); + return QVariantMap(); + } + + auto interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.applicationinterface"), + QStringLiteral("/Application"), QDBusConnection::systemBus(), this); + interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days + + // We send zero percent new data on initial start-up + QDBusPendingCall pcall = interface->emitNewData(xi18nc("@info:progress", "Copying remainder of block size %1 from %2 to %3.", lastBlock, lastBlockReadOffset, lastBlockWriteOffset)); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); + QEventLoop loop; + + auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) { + loop.exit(); + + if (watcher->isError()) + qWarning() << watcher->error(); + }; + + connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop); + loop.exec(); + /*================End Call App slot===================*/ + rval = readData(sourceDevice, buffer, lastBlockReadOffset, lastBlock); if (rval) { @@ -234,15 +361,66 @@ } if (rval) { - emit progress(100); + /*================Call App slot===================*/ + if (!QDBusConnection::systemBus().isConnected()) { + qWarning() << QDBusConnection::systemBus().lastError().message(); + QTimer::singleShot(1000, this, &QCoreApplication::quit); + return QVariantMap(); + } + + auto interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.applicationinterface"), + QStringLiteral("/Application"), QDBusConnection::systemBus(), this); + interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days + + // We send zero percent new data on initial start-up + QDBusPendingCall pcall = interface->emitNewData(100); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); + QEventLoop loop; + + auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) { + loop.exit(); + + if (watcher->isError()) + qWarning() << watcher->error(); + }; + + connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop); + loop.exec(); + /*================End Call App slot===================*/ + bytesWritten += buffer.size(); } } - report[QStringLiteral("report")] = xi18ncp("@info:progress argument 2 is a string such as 7 bytes (localized accordingly)", "Copying 1 block (%2) finished.", "Copying %1 blocks (%2) finished.", blocksCopied, i18np("1 byte", "%1 bytes", bytesWritten)); - - emit reportProgress(report); + /*================Call App slot===================*/ + if (!QDBusConnection::systemBus().isConnected()) { + qWarning() << QDBusConnection::systemBus().lastError().message(); + QTimer::singleShot(1000, this, &QCoreApplication::quit); + return QVariantMap(); + } + auto interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.applicationinterface"), + QStringLiteral("/Application"), QDBusConnection::systemBus(), this); + interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days + + // We send zero percent new data on initial start-up + QDBusPendingCall pcall2 = interface->emitNewData(xi18ncp("@info:progress argument 2 is a string such as 7 bytes (localized accordingly)", "Copying 1 block (%2) finished.", "Copying %1 blocks (%2) finished.", blocksCopied, i18np("1 byte", "%1 bytes", bytesWritten))); + + QDBusPendingCallWatcher *watcher2 = new QDBusPendingCallWatcher(pcall2, this); + QEventLoop loop2; + + auto exitLoop2 = [&] (QDBusPendingCallWatcher *watcher2) { + loop2.exit(); + + if (watcher2->isError()) + qWarning() << watcher2->error(); + }; + + connect(watcher2, &QDBusPendingCallWatcher::finished, exitLoop2); + loop2.exec(); + /*================End Call App slot===================*/ + reply[QStringLiteral("success")] = rval; return reply; }