diff options
Diffstat (limited to 'src/manager-lib/application.cpp')
-rw-r--r-- | src/manager-lib/application.cpp | 385 |
1 files changed, 118 insertions, 267 deletions
diff --git a/src/manager-lib/application.cpp b/src/manager-lib/application.cpp index bc2c7e4f..432cc86e 100644 --- a/src/manager-lib/application.cpp +++ b/src/manager-lib/application.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -43,14 +43,12 @@ #include "application.h" #include "abstractruntime.h" #include "applicationinfo.h" +#include "package.h" #include "exception.h" #include "logging.h" #include <QDebug> -#if defined(Q_OS_UNIX) -# include <signal.h> -#endif /*! \qmltype ApplicationObject @@ -90,9 +88,12 @@ /*! \qmlproperty string ApplicationObject::documentUrl \readonly + \obsolete - This property always returns the default \c documentUrl specified in the manifest file, even if - a different URL was used to start the application. + This was used to distinguish between application aliases, which have been replaced by the + intents mechanism. + + Always returns an empty string. */ /*! \qmlproperty bool ApplicationObject::builtIn @@ -104,22 +105,22 @@ /*! \qmlproperty bool ApplicationObject::alias \readonly + \obsolete - Will return \c true if this ApplicationObject object is an alias to another one. + This was used to distinguish between application aliases, which have been replaced by the + intents mechanism. - \sa nonAliased + Always returns \c false. */ /*! \qmlproperty ApplicationObject ApplicationObject::nonAliased \readonly + \obsolete - If this ApplicationObject is an alias, then you can access the non-alias, base ApplicationObject - via this property, otherwise it contains a reference to itself. This means that if you're interested - in accessing the base application regardless of whether the object at hand is just an alias, you - can always safely refer to this property. + This was used to distinguish between application aliases, which have been replaced by the + intents mechanism. - If you want to know whether this object is an alias or a base ApplicationObject, use - ApplicationObject::alias instead. + Always returns the object itself. */ /*! \qmlproperty list<string> ApplicationObject::capabilities @@ -190,10 +191,7 @@ \qmlproperty string ApplicationObject::codeDir \readonly - The absolute path to the application's installation directory. Please note this directory might - not always be available for applications that were installed onto removable media. - - \sa {Installation Locations} + The absolute path to the application's installation directory. */ /*! \qmlproperty enumeration ApplicationObject::state @@ -272,237 +270,162 @@ QT_BEGIN_NAMESPACE_AM + /////////////////////////////////////////////////////////////////////////////////////////////////// -// AbstractApplication +// Application /////////////////////////////////////////////////////////////////////////////////////////////////// -AbstractApplication::AbstractApplication(AbstractApplicationInfo *info) +Application::Application(ApplicationInfo *info, Package *package) : m_info(info) + , m_package(package) { + Q_ASSERT(info); + Q_ASSERT(package); + + // handle package blocking: all apps have to be stopped and the stop state has to be reported + // back to the package + connect(package, &Package::blockedChanged, this, [this](bool blocked) { + emit blockedChanged(blocked); + if (blocked && (runState() == Am::NotRunning)) + this->package()->applicationStoppedDueToBlock(id()); + else if (blocked) + stop(true); + }); + connect(this, &Application::runStateChanged, this, [this](Am::RunState runState) { + if (isBlocked() && (runState == Am::NotRunning)) + this->package()->applicationStoppedDueToBlock(id()); + }); } -QString AbstractApplication::id() const +bool Application::start(const QString &documentUrl) { - return m_info->id(); + if (requests.startRequested) + return requests.startRequested(documentUrl); + else + return false; } -QUrl AbstractApplication::icon() const +bool Application::debug(const QString &debugWrapper, const QString &documentUrl) { - if (info()->icon().isEmpty()) - return QUrl(); - - auto appInfo = this->nonAliasedInfo(); - QDir dir; - switch (state()) { - default: - case Installed: - dir.setPath(appInfo->manifestDir()); - break; - case BeingInstalled: - case BeingUpdated: - dir.setPath(appInfo->codeDir().absolutePath() + QLatin1Char('+')); - break; - case BeingRemoved: - dir.setPath(appInfo->codeDir().absolutePath() + QLatin1Char('-')); - break; - } - return QUrl::fromLocalFile(dir.absoluteFilePath(info()->icon())); + if (requests.debugRequested) + return requests.debugRequested(debugWrapper, documentUrl); + else + return false; } -QString AbstractApplication::documentUrl() const +void Application::stop(bool forceKill) { - return info()->documentUrl(); + if (requests.stopRequested) + requests.stopRequested(forceKill); } -bool AbstractApplication::isBuiltIn() const +ApplicationInfo *Application::info() const { - return nonAliasedInfo()->isBuiltIn(); + return m_info.data(); } -bool AbstractApplication::isAlias() const +PackageInfo *Application::packageInfo() const { - return info()->isAlias(); + return m_info->packageInfo(); } -QStringList AbstractApplication::capabilities() const +Package *Application::package() const { - return nonAliasedInfo()->capabilities(); + return m_package; } -QStringList AbstractApplication::supportedMimeTypes() const +QString Application::id() const { - return nonAliasedInfo()->supportedMimeTypes(); + return m_info->id(); } -QStringList AbstractApplication::categories() const +bool Application::isBuiltIn() const { - return nonAliasedInfo()->categories(); + return packageInfo()->isBuiltIn(); } -QVariantMap AbstractApplication::applicationProperties() const +QString Application::runtimeName() const { - return info()->applicationProperties(); + return m_info->runtimeName(); } -bool AbstractApplication::supportsApplicationInterface() const +QVariantMap Application::runtimeParameters() const { - return nonAliasedInfo()->supportsApplicationInterface(); + return m_info->runtimeParameters(); } -QString AbstractApplication::version() const +QStringList Application::capabilities() const { - return nonAliasedInfo()->version(); + return m_info->capabilities(); } -QString AbstractApplication::codeDir() const +QStringList Application::categories() const { - switch (state()) { - default: - case Installed: - return nonAliasedInfo()->codeDir().absolutePath(); - case BeingInstalled: - case BeingUpdated: - return nonAliasedInfo()->codeDir().absolutePath() + QLatin1Char('+'); - case BeingRemoved: - return nonAliasedInfo()->codeDir().absolutePath() + QLatin1Char('-'); - } + return package()->categories(); } -QString AbstractApplication::name(const QString &language) const +QUrl Application::icon() const { - return info()->name(language); + return package()->icon(); } -bool AbstractApplication::start(const QString &documentUrl) +QStringList Application::supportedMimeTypes() const { - if (requests.startRequested) - return requests.startRequested(documentUrl); - else - return false; + return info()->supportedMimeTypes(); } -bool AbstractApplication::debug(const QString &debugWrapper, const QString &documentUrl) +QString Application::name() const { - if (requests.debugRequested) - return requests.debugRequested(debugWrapper, documentUrl); - else - return false; + return package()->name(); } -void AbstractApplication::stop(bool forceKill) +QString Application::name(const QString &language) const { - if (requests.stopRequested) - requests.stopRequested(forceKill); + return package()->names().value(language).toString(); } -QVector<AbstractApplication *> AbstractApplication::fromApplicationInfoVector( - QVector<AbstractApplicationInfo *> &appInfoVector) +bool Application::isBlocked() const { - QVector<AbstractApplication *> apps; - - auto findAppWithId = [&apps] (const QString &id) -> AbstractApplication* - { - for (AbstractApplication *app : apps) { - if (app->id() == id) - return app; - } - return nullptr; - }; - - auto extractBaseId = [] (const QString &id) -> QString - { - return id.section(qL1C('@'), 0, 0); - }; - - for (auto *appInfo : appInfoVector) { - QScopedPointer<AbstractApplication> app; - if (appInfo->isAlias()) { - auto *originalApp = findAppWithId(extractBaseId(appInfo->id())); - if (!originalApp) - throw Exception(Error::Parse, "Could not find base app for alias id %2").arg(appInfo->id()); - Q_ASSERT(!originalApp->isAlias()); - app.reset(new ApplicationAlias(static_cast<Application*>(originalApp), - static_cast<ApplicationAliasInfo*>(appInfo))); - } else { - AbstractApplication *otherAbsApp = findAppWithId(appInfo->id()); - if (otherAbsApp) { - // There's already another ApplicationInfo with the same id. It's probably an update for a - // built-in app, in which case we use the same Application instance to hold both - // ApplicationInfo instances. - bool merged = false; - - if (!otherAbsApp->isAlias()) { - auto otherApp = static_cast<Application*>(otherAbsApp); - auto fullAppInfo = static_cast<ApplicationInfo*>(appInfo); - if (otherApp->isBuiltIn() && !fullAppInfo->isBuiltIn() && !otherApp->updatedInfo()) { - otherApp->setUpdatedInfo(static_cast<ApplicationInfo*>(appInfo)); - merged = true; - } else if (!otherApp->isBuiltIn() && fullAppInfo->isBuiltIn() && !otherApp->updatedInfo()) { - auto currentBaseInfo = otherApp->takeBaseInfo(); - otherApp->setBaseInfo(static_cast<ApplicationInfo*>(appInfo)); - otherApp->setUpdatedInfo(currentBaseInfo); - merged = true; - } - } - - if (!merged) - qCWarning(LogSystem).nospace() << "Found a second application with id " - << appInfo->id() << " which is not an update for a built-in one. Ignoring it."; - } else { - app.reset(new Application(static_cast<ApplicationInfo*>(appInfo))); - } - } - - if (!app.isNull()) - apps << app.take(); - } - - return apps; + return package()->isBlocked(); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Application -/////////////////////////////////////////////////////////////////////////////////////////////////// - -Application::Application(ApplicationInfo *info, State initialState) - : AbstractApplication(info) - , m_state(initialState) +QVariantMap Application::applicationProperties() const { + return info()->applicationProperties(); } -void Application::setCurrentRuntime(AbstractRuntime *rt) +bool Application::supportsApplicationInterface() const { - if (m_runtime == rt) - return; - - if (m_runtime) - disconnect(m_runtime, nullptr, this, nullptr); - - m_runtime = rt; - emit runtimeChanged(); + return info()->supportsApplicationInterface(); +} - if (m_runtime) { - connect(m_runtime, &AbstractRuntime::finished, this, &Application::setLastExitCodeAndStatus); - connect(m_runtime, &QObject::destroyed, this, [this]() { - this->setCurrentRuntime(nullptr); - }); - } else - setRunState(Am::NotRunning); +QString Application::codeDir() const +{ + switch (package()->state()) { + default: + case Package::Installed: + return packageInfo()->baseDir().absolutePath(); + case Package::BeingInstalled: + case Package::BeingUpdated: + return packageInfo()->baseDir().absolutePath() + QLatin1Char('+'); + case Package::BeingRemoved: + return packageInfo()->baseDir().absolutePath() + QLatin1Char('-'); + } } -bool Application::isBlocked() const +QString Application::version() const { - return m_blocked.load() == 1; + return packageInfo()->version(); } -bool Application::block() +Application::State Application::state() const { - return m_blocked.testAndSetOrdered(0, 1); + return static_cast<State>(package()->state()); } -bool Application::unblock() +qreal Application::progress() const { - return m_blocked.testAndSetOrdered(1, 0); + return package()->progress(); } void Application::setRunState(Am::RunState runState) @@ -513,24 +436,25 @@ void Application::setRunState(Am::RunState runState) } } -QString Application::runtimeName() const +void Application::setCurrentRuntime(AbstractRuntime *runtime) { - return Application::nonAliasedInfo()->runtimeName(); -} + if (m_runtime == runtime) + return; -QVariantMap Application::runtimeParameters() const -{ - return Application::nonAliasedInfo()->runtimeParameters(); -} + if (m_runtime) + disconnect(m_runtime, nullptr, this, nullptr); -AbstractApplicationInfo *Application::info() const -{ - return m_updatedInfo ? m_updatedInfo.data() : m_info.data(); -} + m_runtime = runtime; + emit runtimeChanged(); -ApplicationInfo *Application::nonAliasedInfo() const -{ - return static_cast<ApplicationInfo*>(Application::info()); + if (m_runtime) { + connect(m_runtime, &AbstractRuntime::finished, this, &Application::setLastExitCodeAndStatus); + connect(m_runtime, &QObject::destroyed, this, [this]() { + this->setCurrentRuntime(nullptr); + }); + } else { + setRunState(Am::NotRunning); + } } void Application::setLastExitCodeAndStatus(int exitCode, Am::ExitStatus exitStatus) @@ -540,88 +464,15 @@ void Application::setLastExitCodeAndStatus(int exitCode, Am::ExitStatus exitStat emit lastExitCodeChanged(); } - Am::ExitStatus newStatus; - if (exitStatus == Am::CrashExit) { -#if defined(Q_OS_UNIX) - newStatus = (exitCode == SIGTERM || exitCode == SIGKILL) ? Am::ForcedExit : Am::CrashExit; -#else - newStatus = Am::CrashExit; -#endif - } else { - newStatus = Am::NormalExit; - } - - if (m_lastExitStatus != newStatus) { - m_lastExitStatus = newStatus; + if (m_lastExitStatus != exitStatus) { + m_lastExitStatus = exitStatus; emit lastExitStatusChanged(); } } -void Application::setBaseInfo(ApplicationInfo *info) -{ - m_info.reset(info); - emit bulkChange(); -} - -ApplicationInfo *Application::takeBaseInfo() -{ - return static_cast<ApplicationInfo*>(m_info.take()); -} - -void Application::setUpdatedInfo(ApplicationInfo* info) -{ - Q_ASSERT(!info || (m_info && info->id() == m_info->id())); - - m_updatedInfo.reset(info); - emit bulkChange(); -} - -void Application::setState(State state) -{ - if (m_state != state) { - m_state = state; - emit stateChanged(m_state); - } -} - -void Application::setProgress(qreal value) -{ - m_progress = value; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// ApplicationAlias -/////////////////////////////////////////////////////////////////////////////////////////////////// - -ApplicationAlias::ApplicationAlias(Application* app, ApplicationAliasInfo* info) - : AbstractApplication(info) - , m_application(app) -{ - connect(m_application, &AbstractApplication::runtimeChanged, this, &AbstractApplication::runtimeChanged); - connect(m_application, &AbstractApplication::lastExitCodeChanged, this, &AbstractApplication::lastExitCodeChanged); - connect(m_application, &AbstractApplication::lastExitStatusChanged, this, &AbstractApplication::lastExitStatusChanged); - connect(m_application, &AbstractApplication::stateChanged, this, &AbstractApplication::stateChanged); - connect(m_application, &AbstractApplication::runStateChanged, this, &AbstractApplication::runStateChanged); -} - -QString ApplicationAlias::runtimeName() const -{ - return m_application->runtimeName(); -} - -QVariantMap ApplicationAlias::runtimeParameters() const -{ - return m_application->runtimeParameters(); -} - -ApplicationInfo *ApplicationAlias::nonAliasedInfo() const -{ - return m_application->nonAliasedInfo(); -} - QT_END_NAMESPACE_AM -QDebug operator<<(QDebug debug, const QT_PREPEND_NAMESPACE_AM(AbstractApplication) *app) +QDebug operator<<(QDebug debug, const QT_PREPEND_NAMESPACE_AM(Application) *app) { debug << "Application Object:"; if (app) |