summaryrefslogtreecommitdiffstats
path: root/src/libs/kdtools/localpackagehub.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/kdtools/localpackagehub.cpp')
-rw-r--r--src/libs/kdtools/localpackagehub.cpp536
1 files changed, 536 insertions, 0 deletions
diff --git a/src/libs/kdtools/localpackagehub.cpp b/src/libs/kdtools/localpackagehub.cpp
new file mode 100644
index 000000000..dc5ea32c7
--- /dev/null
+++ b/src/libs/kdtools/localpackagehub.cpp
@@ -0,0 +1,536 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "localpackagehub.h"
+#include "globals.h"
+#include "constants.h"
+
+#include <QDomDocument>
+#include <QDomElement>
+#include <QFileInfo>
+
+using namespace KDUpdater;
+using namespace QInstaller;
+
+/*!
+ \inmodule kdupdater
+ \class KDUpdater::LocalPackageHub
+ \brief The LocalPackageHub class provides access to information about packages installed on the
+ application side.
+
+ This class parses the \e {installation information} XML file specified via the setFileName()
+ method and provides access to the information defined within the file through an API. You can:
+ \list
+ \li Get the application name via the applicationName() method.
+ \li Get the application version via the applicationVersion() method.
+ \li Get information about the number of packages installed and their meta-data via the
+ packageInfoCount() and packageInfo() methods.
+ \endlist
+*/
+
+/*!
+ \enum LocalPackageHub::Error
+ Error codes related to retrieving information about installed packages:
+
+ \value NoError No error occurred.
+ \value NotYetReadError The installation information was not parsed yet from the
+ XML file.
+ \value CouldNotReadPackageFileError The specified installation information file could not be
+ read (does not exist or is not readable).
+ \value InvalidXmlError The installation information file contains invalid XML.
+ \value InvalidContentError The installation information file contains valid XML, but
+ does not match the expected format for package
+ descriptions.
+*/
+
+struct LocalPackageHub::PackagesInfoData
+{
+ PackagesInfoData() :
+ error(LocalPackageHub::NotYetReadError),
+ modified(false)
+ {}
+ QString errorMessage;
+ LocalPackageHub::Error error;
+ QString fileName;
+ QString applicationName;
+ QString applicationVersion;
+ bool modified;
+
+ QMap<QString, LocalPackage> m_packageInfoMap;
+
+ void addPackageFrom(const QDomElement &packageE);
+ void setInvalidContentError(const QString &detail);
+};
+
+void LocalPackageHub::PackagesInfoData::setInvalidContentError(const QString &detail)
+{
+ error = LocalPackageHub::InvalidContentError;
+ errorMessage = tr("%1 contains invalid content: %2").arg(fileName, detail);
+}
+
+/*!
+ Constructs a local package hub. To fully setup the class you have to call setFileName().
+
+ \sa setFileName
+*/
+LocalPackageHub::LocalPackageHub()
+ : d(new PackagesInfoData())
+{
+}
+
+/*!
+ Destructor
+*/
+LocalPackageHub::~LocalPackageHub()
+{
+ writeToDisk();
+ delete d;
+}
+
+/*!
+ Returns \c true if LocalPackageHub is valid; otherwise returns \c false. You
+ can use the errorString() method to receive a descriptive error message.
+*/
+bool LocalPackageHub::isValid() const
+{
+ return d->error <= NotYetReadError;
+}
+
+/*!
+ Returns a list of all local installed packages.
+*/
+QStringList LocalPackageHub::packageNames() const
+{
+ return d->m_packageInfoMap.keys();
+}
+
+/*!
+ Returns a human-readable description of the last error that occurred.
+*/
+QString LocalPackageHub::errorString() const
+{
+ return d->errorMessage;
+}
+
+/*!
+ Returns the error that was found during the processing of the installation information XML file.
+ If no error was found, returns NoError.
+*/
+LocalPackageHub::Error LocalPackageHub::error() const
+{
+ return d->error;
+}
+
+/*!
+ Sets the complete file name of the installation information XML file to \a fileName. The function
+ also issues a call to refresh() to reload installation information from the XML file.
+*/
+void LocalPackageHub::setFileName(const QString &fileName)
+{
+ if (d->fileName == fileName)
+ return;
+
+ d->fileName = fileName;
+ refresh();
+}
+
+/*!
+ Returns the name of the installation information XML file that this class refers to.
+*/
+QString LocalPackageHub::fileName() const
+{
+ return d->fileName;
+}
+
+/*!
+ Sets the application name to \a name. By default, this is the name specified in the
+ \c <ApplicationName> element of the installation information XML file.
+*/
+void LocalPackageHub::setApplicationName(const QString &name)
+{
+ d->applicationName = name;
+}
+
+/*!
+ Returns the application name.
+*/
+QString LocalPackageHub::applicationName() const
+{
+ return d->applicationName;
+}
+
+/*!
+ Sets the application version to \a version. By default, this is the version specified in the
+ \c <ApplicationVersion> element of the installation information XML file.
+*/
+void LocalPackageHub::setApplicationVersion(const QString &version)
+{
+ d->applicationVersion = version;
+}
+
+/*!
+ Returns the application version.
+*/
+QString LocalPackageHub::applicationVersion() const
+{
+ return d->applicationVersion;
+}
+
+/*!
+ Returns the number of KDUpdater::LocalPackage objects contained in this class.
+*/
+int LocalPackageHub::packageInfoCount() const
+{
+ return d->m_packageInfoMap.count();
+}
+
+/*!
+ Returns the package info structure whose name is \a pkgName. If no such package was found, this
+ function returns a \l{default-constructed value}.
+*/
+LocalPackage LocalPackageHub::packageInfo(const QString &pkgName) const
+{
+ return d->m_packageInfoMap.value(pkgName);
+}
+
+/*!
+ Returns all package info structures.
+*/
+QList<LocalPackage> LocalPackageHub::packageInfos() const
+{
+ return d->m_packageInfoMap.values();
+}
+
+/*!
+ Re-reads the installation information XML file and updates itself. Changes to applicationName()
+ and applicationVersion() are lost after this function returns. The function emits a reset()
+ signal after completion.
+*/
+void LocalPackageHub::refresh()
+{
+ // First clear internal variables
+ d->applicationName.clear();
+ d->applicationVersion.clear();
+ d->m_packageInfoMap.clear();
+ d->modified = false;
+
+ QFile file(d->fileName);
+
+ // if the file does not exist then we just skip the reading
+ if (!file.exists()) {
+ d->error = NotYetReadError;
+ d->errorMessage = tr("The file %1 does not exist.").arg(d->fileName);
+ return;
+ }
+
+ // Open Packages.xml
+ if (!file.open(QFile::ReadOnly)) {
+ d->error = CouldNotReadPackageFileError;
+ d->errorMessage = tr("Cannot open %1.").arg(d->fileName);
+ return;
+ }
+
+ // Parse the XML document
+ QDomDocument doc;
+ QString parseErrorMessage;
+ int parseErrorLine;
+ int parseErrorColumn;
+ if (!doc.setContent(&file, &parseErrorMessage, &parseErrorLine, &parseErrorColumn)) {
+ d->error = InvalidXmlError;
+ d->errorMessage = tr("Parse error in %1 at %2, %3: %4")
+ .arg(d->fileName,
+ QString::number(parseErrorLine),
+ QString::number(parseErrorColumn),
+ parseErrorMessage);
+ return;
+ }
+ file.close();
+
+ // Now populate information from the XML file.
+ QDomElement rootE = doc.documentElement();
+ if (rootE.tagName() != QLatin1String("Packages")) {
+ d->setInvalidContentError(tr("Root element %1 unexpected, should be 'Packages'.")
+ .arg(rootE.tagName()));
+ return;
+ }
+
+ QDomNodeList childNodes = rootE.childNodes();
+ for (int i = 0; i < childNodes.count(); i++) {
+ QDomNode childNode = childNodes.item(i);
+ QDomElement childNodeE = childNode.toElement();
+ if (childNodeE.isNull())
+ continue;
+
+ if (childNodeE.tagName() == QLatin1String("ApplicationName"))
+ d->applicationName = childNodeE.text();
+ else if (childNodeE.tagName() == QLatin1String("ApplicationVersion"))
+ d->applicationVersion = childNodeE.text();
+ else if (childNodeE.tagName() == QLatin1String("Package"))
+ d->addPackageFrom(childNodeE);
+ }
+
+ d->error = NoError;
+ d->errorMessage.clear();
+}
+
+/*!
+ Marks the package specified by \a name as installed. Sets the values of
+ \a version,
+ \a title,
+ \a description,
+ \a dependencies,
+ \a autoDependencies,
+ \a forcedInstallation,
+ \a virtualComp,
+ \a uncompressedSize,
+ \a inheritVersionFrom,
+ and \a checkable for the package.
+*/
+void LocalPackageHub::addPackage(const QString &name,
+ const QString &version,
+ const QString &title,
+ const QString &description,
+ const QStringList &dependencies,
+ const QStringList &autoDependencies,
+ bool forcedInstallation,
+ bool virtualComp,
+ quint64 uncompressedSize,
+ const QString &inheritVersionFrom,
+ bool checkable)
+{
+ // TODO: This somewhat unexpected, remove?
+ if (d->m_packageInfoMap.contains(name)) {
+ // TODO: What about the other fields, update?
+ d->m_packageInfoMap[name].version = version;
+ d->m_packageInfoMap[name].lastUpdateDate = QDate::currentDate();
+ } else {
+ LocalPackage info;
+ info.name = name;
+ info.version = version;
+ info.inheritVersionFrom = inheritVersionFrom;
+ info.installDate = QDate::currentDate();
+ info.title = title;
+ info.description = description;
+ info.dependencies = dependencies;
+ info.autoDependencies = autoDependencies;
+ info.forcedInstallation = forcedInstallation;
+ info.virtualComp = virtualComp;
+ info.uncompressedSize = uncompressedSize;
+ info.checkable = checkable;
+ d->m_packageInfoMap.insert(name, info);
+ }
+ d->modified = true;
+}
+
+/*!
+ Removes the package specified by \a name. Returns \c false if the package is not found.
+*/
+bool LocalPackageHub::removePackage(const QString &name)
+{
+ if (d->m_packageInfoMap.remove(name) <= 0)
+ return false;
+
+ d->modified = true;
+ return true;
+}
+
+static void addTextChildHelper(QDomNode *node,
+ const QString &tag,
+ const QString &text,
+ const QString &attributeName = QString(),
+ const QString &attributeValue = QString())
+{
+ QDomElement domElement = node->ownerDocument().createElement(tag);
+ QDomText domText = node->ownerDocument().createTextNode(text);
+
+ domElement.appendChild(domText);
+ if (!attributeName.isEmpty())
+ domElement.setAttribute(attributeName, attributeValue);
+ node->appendChild(domElement);
+}
+
+/*!
+ Writes the installation information file to disk.
+*/
+void LocalPackageHub::writeToDisk()
+{
+ if (d->modified && (!d->m_packageInfoMap.isEmpty() || QFile::exists(d->fileName))) {
+ QDomDocument doc;
+ QDomElement root = doc.createElement(QLatin1String("Packages")) ;
+ doc.appendChild(root);
+
+ addTextChildHelper(&root, QLatin1String("ApplicationName"), d->applicationName);
+ addTextChildHelper(&root, QLatin1String("ApplicationVersion"), d->applicationVersion);
+
+ Q_FOREACH (const LocalPackage &info, d->m_packageInfoMap) {
+ QDomElement package = doc.createElement(QLatin1String("Package"));
+
+ addTextChildHelper(&package, QLatin1String("Name"), info.name);
+ addTextChildHelper(&package, QLatin1String("Title"), info.title);
+ addTextChildHelper(&package, QLatin1String("Description"), info.description);
+ if (info.inheritVersionFrom.isEmpty())
+ addTextChildHelper(&package, QLatin1String("Version"), info.version);
+ else
+ addTextChildHelper(&package, QLatin1String("Version"), info.version,
+ QLatin1String("inheritVersionFrom"), info.inheritVersionFrom);
+ addTextChildHelper(&package, QLatin1String("LastUpdateDate"), info.lastUpdateDate
+ .toString(Qt::ISODate));
+ addTextChildHelper(&package, QLatin1String("InstallDate"), info.installDate
+ .toString(Qt::ISODate));
+ addTextChildHelper(&package, QLatin1String("Size"),
+ QString::number(info.uncompressedSize));
+
+ if (info.dependencies.count())
+ addTextChildHelper(&package, scDependencies, info.dependencies.join(QLatin1String(",")));
+ if (info.autoDependencies.count())
+ addTextChildHelper(&package, scAutoDependOn, info.autoDependencies.join(QLatin1String(",")));
+ if (info.forcedInstallation)
+ addTextChildHelper(&package, QLatin1String("ForcedInstallation"), QLatin1String("true"));
+ if (info.virtualComp)
+ addTextChildHelper(&package, QLatin1String("Virtual"), QLatin1String("true"));
+ if (info.checkable)
+ addTextChildHelper(&package, QLatin1String("Checkable"), QLatin1String("true"));
+
+ root.appendChild(package);
+ }
+
+ // Open Packages.xml
+ QFile file(d->fileName);
+ if (!file.open(QFile::WriteOnly))
+ return;
+
+ file.write(doc.toByteArray(4));
+ file.close();
+ d->modified = false;
+ }
+}
+
+void LocalPackageHub::PackagesInfoData::addPackageFrom(const QDomElement &packageE)
+{
+ if (packageE.isNull())
+ return;
+
+ QDomNodeList childNodes = packageE.childNodes();
+ if (childNodes.count() == 0)
+ return;
+
+ LocalPackage info;
+ info.forcedInstallation = false;
+ info.virtualComp = false;
+ info.checkable = false;
+ for (int i = 0; i < childNodes.count(); i++) {
+ QDomNode childNode = childNodes.item(i);
+ QDomElement childNodeE = childNode.toElement();
+ if (childNodeE.isNull())
+ continue;
+
+ if (childNodeE.tagName() == QLatin1String("Name"))
+ info.name = childNodeE.text();
+ else if (childNodeE.tagName() == QLatin1String("Title"))
+ info.title = childNodeE.text();
+ else if (childNodeE.tagName() == QLatin1String("Description"))
+ info.description = childNodeE.text();
+ else if (childNodeE.tagName() == QLatin1String("Version")) {
+ info.version = childNodeE.text();
+ info.inheritVersionFrom = childNodeE.attribute(QLatin1String("inheritVersionFrom"));
+ }
+ else if (childNodeE.tagName() == QLatin1String("Virtual"))
+ info.virtualComp = childNodeE.text().toLower() == QLatin1String("true") ? true : false;
+ else if (childNodeE.tagName() == QLatin1String("Size"))
+ info.uncompressedSize = childNodeE.text().toULongLong();
+ else if (childNodeE.tagName() == QLatin1String("Dependencies")) {
+ info.dependencies = childNodeE.text().split(QInstaller::commaRegExp(),
+ QString::SkipEmptyParts);
+ } else if (childNodeE.tagName() == QLatin1String("AutoDependOn")) {
+ info.autoDependencies = childNodeE.text().split(QInstaller::commaRegExp(),
+ QString::SkipEmptyParts);
+ } else if (childNodeE.tagName() == QLatin1String("ForcedInstallation"))
+ info.forcedInstallation = childNodeE.text().toLower() == QLatin1String( "true" ) ? true : false;
+ else if (childNodeE.tagName() == QLatin1String("LastUpdateDate"))
+ info.lastUpdateDate = QDate::fromString(childNodeE.text(), Qt::ISODate);
+ else if (childNodeE.tagName() == QLatin1String("InstallDate"))
+ info.installDate = QDate::fromString(childNodeE.text(), Qt::ISODate);
+ else if (childNodeE.tagName() == QLatin1String("Checkable"))
+ info.checkable = childNodeE.text().toLower() == QLatin1String("true") ? true : false;
+ }
+ m_packageInfoMap.insert(info.name, info);
+}
+
+/*!
+ Clears the installed package list.
+*/
+void LocalPackageHub::clearPackageInfos()
+{
+ d->m_packageInfoMap.clear();
+ d->modified = true;
+}
+
+/*!
+ \inmodule kdupdater
+ \class KDUpdater::LocalPackage
+ \brief The LocalPackage class describes a single installed package in the application.
+
+ This class contains information about a single installed package in the application. The
+ information contained in this class corresponds to the information described by the <Package>
+ XML element in the installation information XML file.
+*/
+
+/*!
+ \variable LocalPackage::name
+ \brief The name of the package.
+*/
+
+/*!
+ \variable LocalPackage::pixmap
+*/
+
+/*!
+ \variable LocalPackage::title
+*/
+
+/*!
+ \variable LocalPackage::description
+*/
+
+/*!
+ \variable LocalPackage::version
+*/
+
+/*!
+ \variable LocalPackage::lastUpdateDate
+*/
+
+/*!
+ \variable LocalPackage::installDate
+*/