diff options
Diffstat (limited to 'installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesinfo.cpp')
-rw-r--r-- | installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesinfo.cpp | 511 |
1 files changed, 511 insertions, 0 deletions
diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesinfo.cpp b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesinfo.cpp new file mode 100644 index 000000000..14a765a5b --- /dev/null +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatesourcesinfo.cpp @@ -0,0 +1,511 @@ +/**************************************************************************** +** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB. All rights reserved. +** +** This file is part of the KD Tools library. +** +** Licensees holding valid commercial KD Tools licenses may use this file in +** accordance with the KD Tools Commercial License Agreement provided with +** the Software. +** +** +** This file may be distributed and/or modified under the terms of the +** GNU Lesser General Public License version 2 and version 3 as published by the +** Free Software Foundation and appearing in the file LICENSE.LGPL included. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** Contact info@kdab.com if any conditions of this licensing are not +** clear to you. +** +**********************************************************************/ + +#include "kdupdaterupdatesourcesinfo.h" +#include "kdupdaterapplication.h" + +#include <QDomElement> +#include <QDomDocument> +#include <QDomText> +#include <QDomCDATASection> +#include <QFileInfo> +#include <QFile> +#include <QTextStream> + + +/*! + \ingroup kdupdater + \class KDUpdater::UpdateSourcesInfo kdupdaterupdatesourcesinfo.h KDUpdaterUpdateSourcesInfo + \brief Provides access to information about the update sources set for the application. + + An update source is a repository that contains updates applicable for the application. + Applications can download updates from the update source and install them locally. + + Each application can have one or more update sources from which it can download updates. + Information about update source is stored in a file called UpdateSources.xml. This class helps + access and modify the UpdateSources.xml file. + + The complete file name of the UpdateSources.xml file can be specified via the \ref setFileName() + method. The class then parses the XML file and makes available information contained in + that XML file through an easy to use API. You can + + \li Get update sources information via the \ref updateSourceInfoCount() and \ref updateSourceInfo() + methods. + \li You can add/remove/change update source information via the \ref addUpdateSourceInfo(), + \ref removeUpdateSource(), \ref setUpdateSourceAt() methods. + + The class emits appropriate signals to inform listeners about changes in the update application. +*/ + +/*! \enum UpdateSourcesInfo::Error + * Error codes related to retrieving update sources + */ + +/*! \var UpdateSourcesInfo::Error UpdateSourcesInfo::NoError + * No error occurred + */ + +/*! \var UpdateSourcesInfo::Error UpdateSourcesInfo::NotYetReadError + * The package information was not parsed yet from the XML file + */ + +/*! \var UpdateSourcesInfo::Error UpdateSourcesInfo::CouldNotReadSourceFileError + * the specified update source file could not be read (does not exist or not readable) + */ + +/*! \var UpdateSourcesInfo::Error UpdateSourcesInfo::InvalidXmlError + * The source file contains invalid XML. + */ + +/*! \var UpdateSourcesInfo::Error UpdateSourcesInfo::InvalidContentError + * The source file contains valid XML, but does not match the expected format for source descriptions + */ + +/*! \var UpdateSourcesInfo::Error UpdateSourcesInfo::CouldNotSaveChangesError + * Changes made to the object could be saved back to the source file + */ + +namespace KDUpdater +{ +struct UpdateSourceInfoPriorityHigherThan +{ + bool operator()( const UpdateSourceInfo& lhs, const UpdateSourceInfo& rhs ) const + { + return lhs.priority > rhs.priority; + } +}; +} + +struct KDUpdater::UpdateSourcesInfo::UpdateSourcesInfoData +{ + UpdateSourcesInfoData( UpdateSourcesInfo* qq ) : + q( qq ), + error(UpdateSourcesInfo::NotYetReadError), + application(0), + modified(false) + {} + + UpdateSourcesInfo* q; + + QString errorMessage; + UpdateSourcesInfo::Error error; + KDUpdater::Application* application; + bool modified; + QString fileName; + QList<KDUpdater::UpdateSourceInfo> updateSourceInfoList; + + void addUpdateSourceFrom( const QDomElement & element ); + void addChildElement( QDomDocument & doc, QDomElement & parentE, const QString & tagName, const QString & text, bool htmlText=false ); + void setInvalidContentError( const QString& detail ); + void clearError(); + void saveChanges(); +}; + +void KDUpdater::UpdateSourcesInfo::UpdateSourcesInfoData::setInvalidContentError(const QString& detail) +{ + error = UpdateSourcesInfo::InvalidContentError; + errorMessage = tr("%1 contains invalid content: %2").arg(fileName, detail); +} + +void KDUpdater::UpdateSourcesInfo::UpdateSourcesInfoData::clearError() +{ + error = UpdateSourcesInfo::NoError; + errorMessage.clear(); +} + +/*! + \internal +*/ +KDUpdater::UpdateSourcesInfo::UpdateSourcesInfo(Application* application) + : QObject(application), + d( new KDUpdater::UpdateSourcesInfo::UpdateSourcesInfoData( this ) ) +{ + d->application = application; +} + +/*! + \internal +*/ +KDUpdater::UpdateSourcesInfo::~UpdateSourcesInfo() +{ + d->saveChanges(); + delete d; +} + +/*! + Returns a pointer to the update application for which this class manages update sources. +*/ +KDUpdater::Application* KDUpdater::UpdateSourcesInfo::application() const +{ + return d->application; +} + +/*! + \internal +*/ +bool KDUpdater::UpdateSourcesInfo::isValid() const +{ + return d->error == NoError; +} + +/*! + returns a human-readable description of the error + */ +QString KDUpdater::UpdateSourcesInfo::errorString() const +{ + return d->errorMessage; +} + +/*! + returns the last error + */ +KDUpdater::UpdateSourcesInfo::Error KDUpdater::UpdateSourcesInfo::error() const +{ + return d->error; +} + +bool KDUpdater::UpdateSourcesInfo::isModified() const +{ + return d->modified; +} + +void KDUpdater::UpdateSourcesInfo::setModified(bool modified) +{ + d->modified = modified; +} + +/*! + Sets the complete file name of the UpdateSources.xml file. The function also issues a call + to refresh() to reload package information from the XML file. + + \sa KDUpdater::Application::setUpdateSourcesXMLFileName() +*/ +void KDUpdater::UpdateSourcesInfo::setFileName(const QString& fileName) +{ + if( d->fileName == fileName ) + return; + + d->fileName = fileName; + refresh(); // load new file +} + +/*! + Returns the name of the UpdateSources.xml file that this class referred to. +*/ +QString KDUpdater::UpdateSourcesInfo::fileName() const +{ + return d->fileName; +} + +/*! + Returns the number of update source info structures contained in this class. +*/ +int KDUpdater::UpdateSourcesInfo::updateSourceInfoCount() const +{ + return d->updateSourceInfoList.count(); +} + +/*! + Returns the update source info structure at \c index. If an invalid index is passed + the function returns a dummy constructor. +*/ +KDUpdater::UpdateSourceInfo KDUpdater::UpdateSourcesInfo::updateSourceInfo(int index) const +{ + if( index < 0 || index >= d->updateSourceInfoList.count() ) + return KDUpdater::UpdateSourceInfo(); + + return d->updateSourceInfoList[index]; +} + +/*! + Adds an update source info to this class. Upon successful addition, the class emits a + \ref updateSourceInfoAdded() signal. +*/ +void KDUpdater::UpdateSourcesInfo::addUpdateSourceInfo(const KDUpdater::UpdateSourceInfo& info) +{ + if( d->updateSourceInfoList.contains( info ) ) + return; + d->updateSourceInfoList.push_back( info ); + qSort( d->updateSourceInfoList.begin(), d->updateSourceInfoList.end(), KDUpdater::UpdateSourceInfoPriorityHigherThan() ); + emit updateSourceInfoAdded(info); + d->modified = true; +} + +/*! + Removes an update source info from this class. Upon successful removal, the class emits a + \ref updateSourceInfoRemoved() signal. +*/ +void KDUpdater::UpdateSourcesInfo::removeUpdateSourceInfo(const KDUpdater::UpdateSourceInfo& info) +{ + if( !d->updateSourceInfoList.contains(info) ) + return; + d->updateSourceInfoList.removeAll(info); + emit updateSourceInfoRemoved(info); + d->modified = true; +} + +/*! + Removes an update source info at \index in this class. Upon successful removal, the class emits a + \ref updateSourceInfoRemoved() signal. +*/ +void KDUpdater::UpdateSourcesInfo::removeUpdateSourceInfoAt(int index) +{ + if( index < 0 || index >= d->updateSourceInfoList.count() ) + return; + KDUpdater::UpdateSourceInfo info = d->updateSourceInfoList[index]; + d->updateSourceInfoList.removeAt(index); + emit updateSourceInfoRemoved(info); + d->modified = true; +} + +/*! + Changes the update source info at \c index to \c info. If \c index is equal to the number of + source info structures in this class (\ref updateSourceInfoCount()) then \c info is appended; + otherwise the existing info at \c index will be changed. + + Depending on what the function does \ref updateSourceInfoAdded() or \ref updateSourceInfoChanged() + signal is emitted. +*/ +void KDUpdater::UpdateSourcesInfo::setUpdateSourceInfoAt(int index, const KDUpdater::UpdateSourceInfo& info) +{ + if( index < 0 || index > d->updateSourceInfoList.count() ) + return; + + if( index == d->updateSourceInfoList.count() ) + { + d->updateSourceInfoList.append(info); + emit updateSourceInfoAdded(info); + } + else + { + KDUpdater::UpdateSourceInfo oldInfo = d->updateSourceInfoList[index]; + if( info == oldInfo ) + return; + + d->updateSourceInfoList[index] = info; + emit updateSourceInfoChanged(info, oldInfo); + } + d->modified = true; +} + +/*! + This slot reloads the update source information from UpdateSources.xml. +*/ +void KDUpdater::UpdateSourcesInfo::refresh() +{ + d->saveChanges(); // save changes done in the previous file + d->updateSourceInfoList.clear(); + + QFile file( d->fileName ); + + // if the file does not exist then we just skip the reading + if( !file.exists() ) + { + d->clearError(); + emit reset(); + return; + } + + // Open the XML file + if( !file.open(QFile::ReadOnly) ) + { + d->errorMessage = tr("Could not read \"%1\"").arg(d->fileName); + d->error = CouldNotReadSourceFileError; + emit reset(); + return; + } + + QDomDocument doc; + QString parseErrorMessage; + int parseErrorLine; + int parseErrorColumn; + if( !doc.setContent( &file, &parseErrorMessage, &parseErrorLine, &parseErrorColumn ) ) + { + d->error = InvalidXmlError; + d->errorMessage = tr("XML Parse error in %1 at %2, %3: %4") + .arg( d->fileName, + QString::number( parseErrorLine ), + QString::number( parseErrorColumn ), + parseErrorMessage ); + emit reset(); + return; + } + + // Now parse the XML file. + QDomElement rootE = doc.documentElement(); + if( rootE.tagName() != QLatin1String( "UpdateSources" ) ) + { + d->setInvalidContentError(tr("Root element %1 unexpected, should be \"UpdateSources\"").arg(rootE.tagName())); + emit reset(); + 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( "UpdateSource" ) ) + d->addUpdateSourceFrom(childNodeE); + } + + d->clearError(); + emit reset(); +} + +void KDUpdater::UpdateSourcesInfo::UpdateSourcesInfoData::saveChanges() +{ + if( !modified || fileName.isEmpty() ) + return; + + const bool hadSaveError = error == UpdateSourcesInfo::CouldNotSaveChangesError; + + QDomDocument doc; + + QDomElement rootE = doc.createElement( QLatin1String( "UpdateSources") ); + doc.appendChild(rootE); + + for(int i=0; i<updateSourceInfoList.count(); i++) + { + KDUpdater::UpdateSourceInfo info = updateSourceInfoList[i]; + + QDomElement infoE = doc.createElement( QLatin1String( "UpdateSource" ) ); + rootE.appendChild(infoE); + addChildElement(doc, infoE, QLatin1String( "Name" ), info.name); + addChildElement(doc, infoE, QLatin1String( "Title" ), info.title); + addChildElement(doc, infoE, QLatin1String( "Description" ), info.description, + (info.description.length() && info.description[0] == QLatin1Char( '<' ) ) ); + addChildElement(doc, infoE, QLatin1String( "Url" ), info.url.toString()); + } + + QFile file( fileName ); + if ( !file.open( QFile::WriteOnly ) ) + { + error = UpdateSourcesInfo::CouldNotSaveChangesError; + errorMessage = tr("Could not save changes to \"%1\": %2").arg(fileName, file.errorString()); + return; + } + + QTextStream stream( &file ); + doc.save( stream, 2 ); + stream.flush(); + file.close(); + + if ( file.error() != QFile::NoError ) + { + error = UpdateSourcesInfo::CouldNotSaveChangesError; + errorMessage = tr("Could not save changes to \"%1\": %2").arg(fileName, file.errorString()); + return; + } + + //if there was a write error before, clear the error, as the write was successful now + if ( hadSaveError ) + clearError(); + + modified = false; +} + +void KDUpdater::UpdateSourcesInfo::UpdateSourcesInfoData::addUpdateSourceFrom( const QDomElement & element ) +{ + if( element.tagName() != QLatin1String( "UpdateSource" ) ) + return; + + QDomNodeList childNodes = element.childNodes(); + if(!childNodes.count()) + return; + + KDUpdater::UpdateSourceInfo info; + + 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( "Url" ) ) + info.url = childNodeE.text(); + } + + this->updateSourceInfoList.append(info); +} + +void KDUpdater::UpdateSourcesInfo::UpdateSourcesInfoData::addChildElement( QDomDocument & doc, QDomElement & parentE, const QString & tagName, const QString & text, bool htmlText ) +{ + QDomElement childE = doc.createElement(tagName); + parentE.appendChild(childE); + + if( htmlText ) + { + QDomCDATASection textE = doc.createCDATASection(text); + childE.appendChild(textE); + } + else + { + QDomText textE = doc.createTextNode(text); + childE.appendChild(textE); + } +} + +/*! + \ingroup kdupdater + \struct KDUpdater::UpdateSourceInfo kdupdaterupdatesourcesinfo.h KDUpdaterUpdateSourcesInfo + \brief Describes a single update source + + An update source is a repository that contains updates applicable for the application. + This structure describes a single update source in terms of name, title, description, url and priority. +*/ + +/*! + \var QString KDUpdater::UpdateSourceInfo::name +*/ + +/*! + \var QString KDUpdater::UpdateSourceInfo::title +*/ + +/*! + \var QString KDUpdater::UpdateSourceInfo::description +*/ + +/*! + \var QUrl KDUpdater::UpdateSourceInfo::url +*/ + +/*! + \var QUrl KDUpdater::UpdateSourceInfo::priority +*/ + +bool KDUpdater::operator==( const UpdateSourceInfo & lhs, const UpdateSourceInfo & rhs ) +{ + return (lhs.name == rhs.name) && (lhs.title == rhs.title) && + (lhs.description == rhs.description) && (lhs.url == rhs.url); +} |