mirror of
https://github.com/QuasarApp/installer-framework.git
synced 2025-04-29 15:04:32 +00:00
1104 lines
42 KiB
C++
1104 lines
42 KiB
C++
|
/**************************************************************************
|
||
|
**
|
||
|
** This file is part of Qt SDK**
|
||
|
**
|
||
|
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).*
|
||
|
**
|
||
|
** Contact: Nokia Corporation qt-info@nokia.com**
|
||
|
**
|
||
|
** No Commercial Usage
|
||
|
**
|
||
|
** This file contains pre-release code and may not be distributed.
|
||
|
** You may use this file in accordance with the terms and conditions
|
||
|
** contained in the Technology Preview License Agreement accompanying
|
||
|
** this package.
|
||
|
**
|
||
|
** 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.
|
||
|
**
|
||
|
** If you are unsure which license is appropriate for your use, please contact
|
||
|
** (qt-info@nokia.com).
|
||
|
**
|
||
|
**************************************************************************/
|
||
|
#include "qinstallercomponent.h"
|
||
|
#include "qinstallerglobal.h"
|
||
|
#include "messageboxhandler.h"
|
||
|
|
||
|
#include "common/errors.h"
|
||
|
|
||
|
#include "lib7z_facade.h"
|
||
|
|
||
|
#include <KDUpdater/Update>
|
||
|
#include <KDUpdater/UpdateOperation>
|
||
|
#include <KDUpdater/UpdateOperationFactory>
|
||
|
|
||
|
#include <QApplication>
|
||
|
#include <QDesktopServices>
|
||
|
#include <QDir>
|
||
|
#include <QDirIterator>
|
||
|
#include <QHash>
|
||
|
#include <QMessageBox>
|
||
|
#include <QtCore/QPair>
|
||
|
#include <QScriptEngine>
|
||
|
#include <QScriptValue>
|
||
|
#include <QTextStream>
|
||
|
#include <QTranslator>
|
||
|
#include <QUiLoader>
|
||
|
|
||
|
#include <memory>
|
||
|
|
||
|
#include "common/utils.h"
|
||
|
#include "fsengineclient.h"
|
||
|
|
||
|
using namespace QInstaller;
|
||
|
|
||
|
/*
|
||
|
TRANSLATOR QInstaller::Component
|
||
|
*/
|
||
|
|
||
|
/*!
|
||
|
\class QInstaller::Component
|
||
|
Component describes a component within the installer.
|
||
|
*/
|
||
|
|
||
|
class QInstaller::Component::Private
|
||
|
{
|
||
|
QInstaller::Component* const q;
|
||
|
public:
|
||
|
Private( Installer* installer, QInstaller::Component* qq )
|
||
|
: q( qq ),
|
||
|
m_installer( installer ),
|
||
|
m_parent( 0 ),
|
||
|
m_offsetInInstaller( 0 ),
|
||
|
autoCreateOperations( true ),
|
||
|
operationsCreated( false ),
|
||
|
removeBeforeUpdate( true ),
|
||
|
enabled( true ),
|
||
|
isCheckedFromUpdater( false ),
|
||
|
m_newlyInstalled ( false ),
|
||
|
operationsCreatedSuccessfully( true ),
|
||
|
minimumProgressOperation(0),
|
||
|
m_licenseOperation(0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
static QMap< const Component*, Qt::CheckState > cachedCheckStates;
|
||
|
|
||
|
Installer *m_installer;
|
||
|
QHash<QString,QString> m_vars;
|
||
|
QList< Component* > m_components;
|
||
|
QList< KDUpdater::UpdateOperation* > operations;
|
||
|
|
||
|
QList< QPair< QString, bool > > pathesForUninstallation;
|
||
|
|
||
|
QMap< QString, QWidget* > userInterfaces;
|
||
|
|
||
|
QUrl repositoryUrl;
|
||
|
QStringList downloadableArchives;
|
||
|
QStringList stopProcessForUpdateRequests;
|
||
|
|
||
|
Component* m_parent;
|
||
|
|
||
|
// filled before intaller runs
|
||
|
qint64 m_offsetInInstaller;
|
||
|
|
||
|
bool autoCreateOperations;
|
||
|
bool operationsCreated;
|
||
|
|
||
|
bool removeBeforeUpdate;
|
||
|
|
||
|
bool enabled;
|
||
|
bool isCheckedFromUpdater;
|
||
|
|
||
|
bool m_newlyInstalled;
|
||
|
|
||
|
bool operationsCreatedSuccessfully;
|
||
|
|
||
|
QScriptEngine scriptEngine;
|
||
|
QScriptValue scriptComponent;
|
||
|
|
||
|
QHash< QString, bool > unexistingScriptMethods;
|
||
|
|
||
|
void init();
|
||
|
void setSelectedOnComponentList(const QList<Component*> &componentList,
|
||
|
bool selected, RunModes runMode, SelectMode selectMode);
|
||
|
KDUpdater::UpdateOperation* minimumProgressOperation;
|
||
|
|
||
|
// < display name, < file name, file content > >
|
||
|
QHash<QString, QPair<QString, QString> > m_licenses;
|
||
|
KDUpdater::UpdateOperation *m_licenseOperation;
|
||
|
};
|
||
|
|
||
|
QMap< const Component*, Qt::CheckState > Component::Private::cachedCheckStates;
|
||
|
|
||
|
void Component::Private::init()
|
||
|
{
|
||
|
// register translation stuff
|
||
|
scriptEngine.installTranslatorFunctions();
|
||
|
|
||
|
// register QMessageBox::StandardButton enum in the script connection
|
||
|
registerMessageBox( &scriptEngine );
|
||
|
|
||
|
// register QDesktopServices in the script cennoction
|
||
|
QScriptValue desktopServices = scriptEngine.newArray();
|
||
|
desktopServices.setProperty( QLatin1String( "DesktopLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::DesktopLocation ) ) );
|
||
|
desktopServices.setProperty( QLatin1String( "DocumentsLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::DocumentsLocation ) ) );
|
||
|
desktopServices.setProperty( QLatin1String( "FontsLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::FontsLocation ) ) );
|
||
|
desktopServices.setProperty( QLatin1String( "ApplicationsLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::ApplicationsLocation ) ) );
|
||
|
desktopServices.setProperty( QLatin1String( "MusicLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::MusicLocation ) ) );
|
||
|
desktopServices.setProperty( QLatin1String( "MoviesLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::MoviesLocation ) ) );
|
||
|
desktopServices.setProperty( QLatin1String( "PicturesLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::PicturesLocation ) ) );
|
||
|
desktopServices.setProperty( QLatin1String( "TempLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::TempLocation ) ) );
|
||
|
desktopServices.setProperty( QLatin1String( "HomeLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::HomeLocation ) ) );
|
||
|
desktopServices.setProperty( QLatin1String( "DataLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::DataLocation ) ) );
|
||
|
desktopServices.setProperty( QLatin1String( "CacheLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::CacheLocation ) ) );
|
||
|
|
||
|
desktopServices.setProperty( QLatin1String( "openUrl" ), scriptEngine.newFunction( qDesktopServicesOpenUrl ) );
|
||
|
desktopServices.setProperty( QLatin1String( "displayName" ), scriptEngine.newFunction( qDesktopServicesDisplayName ) );
|
||
|
desktopServices.setProperty( QLatin1String( "storageLocation" ), scriptEngine.newFunction( qDesktopServicesStorageLocation ) );
|
||
|
scriptEngine.globalObject().setProperty( QLatin1String( "QDesktopServices" ), desktopServices );
|
||
|
|
||
|
// register ::WizardPage enum in the script connection
|
||
|
QScriptValue qinstaller = scriptEngine.newArray();
|
||
|
qinstaller.setProperty( QLatin1String( "Introduction" ), scriptEngine.newVariant( static_cast< int >( Installer::Introduction ) ) );
|
||
|
qinstaller.setProperty( QLatin1String( "LicenseCheck" ), scriptEngine.newVariant( static_cast< int >( Installer::LicenseCheck ) ) );
|
||
|
qinstaller.setProperty( QLatin1String( "TargetDirectory" ), scriptEngine.newVariant( static_cast< int >( Installer::TargetDirectory ) ) );
|
||
|
qinstaller.setProperty( QLatin1String( "ComponentSelection" ), scriptEngine.newVariant( static_cast< int >( Installer::ComponentSelection ) ) );
|
||
|
qinstaller.setProperty( QLatin1String( "StartMenuSelection" ), scriptEngine.newVariant( static_cast< int >( Installer::StartMenuSelection ) ) );
|
||
|
qinstaller.setProperty( QLatin1String( "ReadyForInstallation" ), scriptEngine.newVariant( static_cast< int >( Installer::ReadyForInstallation ) ) );
|
||
|
qinstaller.setProperty( QLatin1String( "PerformInstallation" ), scriptEngine.newVariant( static_cast< int >( Installer::PerformInstallation ) ) );
|
||
|
qinstaller.setProperty( QLatin1String( "InstallationFinished" ), scriptEngine.newVariant( static_cast< int >( Installer::InstallationFinished ) ) );
|
||
|
qinstaller.setProperty( QLatin1String( "End" ), scriptEngine.newVariant( static_cast< int >( Installer::End ) ) );
|
||
|
|
||
|
// register ::Status enum in the script connection
|
||
|
qinstaller.setProperty( QLatin1String( "InstallerUnfinished" ), scriptEngine.newVariant( static_cast< int >( Installer::InstallerUnfinished ) ) );
|
||
|
qinstaller.setProperty( QLatin1String( "InstallerCanceledByUser" ), scriptEngine.newVariant( static_cast< int >( Installer::InstallerCanceledByUser ) ) );
|
||
|
qinstaller.setProperty( QLatin1String( "InstallerFailed" ), scriptEngine.newVariant( static_cast< int >( Installer::InstallerFailed ) ) );
|
||
|
qinstaller.setProperty( QLatin1String( "InstallerSucceeded" ), scriptEngine.newVariant( static_cast< int >( Installer::InstallerSucceeded ) ) );
|
||
|
|
||
|
scriptEngine.globalObject().setProperty( QLatin1String( "QInstaller" ), qinstaller );
|
||
|
|
||
|
scriptEngine.globalObject().setProperty( QLatin1String( "component" ), scriptEngine.newQObject( q ) );
|
||
|
QScriptValue installerObject = scriptEngine.newQObject( m_installer );
|
||
|
installerObject.setProperty( QLatin1String( "componentByName" ), scriptEngine.newFunction( qInstallerComponentByName, 1 ) );
|
||
|
scriptEngine.globalObject().setProperty( QLatin1String( "installer" ), installerObject );
|
||
|
}
|
||
|
|
||
|
void Component::Private::setSelectedOnComponentList(const QList<Component*> &componentList,
|
||
|
bool selected, RunModes runMode, SelectMode selectMode)
|
||
|
{
|
||
|
for( QList< Component* >::const_iterator it = componentList.begin(); it != componentList.end(); ++it )
|
||
|
{
|
||
|
Component* const comp = *it;
|
||
|
if( !comp->isSelected( runMode ) )
|
||
|
comp->setSelected( selected, runMode, selectMode );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Constructor. Creates a new Component inside of \a installer.
|
||
|
*/
|
||
|
Component::Component(Installer *installer)
|
||
|
: d(new Component::Private( installer, this ) )
|
||
|
{
|
||
|
d->init();
|
||
|
}
|
||
|
|
||
|
Component::Component( KDUpdater::Update* update, Installer* installer )
|
||
|
: d( new Private( installer, this ) ) {
|
||
|
Q_ASSERT( update );
|
||
|
d->init();
|
||
|
setValue( QLatin1String( "Name" ), update->data( QLatin1String( "Name" ) ).toString() );
|
||
|
setValue( QLatin1String( "DisplayName" ), update->data( QLatin1String( "DisplayName" ) ).toString() );
|
||
|
setValue( QLatin1String( "Description" ), update->data( QLatin1String( "Description" ) ).toString() );
|
||
|
setValue( QLatin1String( "UncompressedSize" ), QString::number( update->uncompressedSize() ) );
|
||
|
setValue( QLatin1String( "Version" ), update->data( QLatin1String( "Version" ) ).toString() );
|
||
|
setValue( QLatin1String( "Dependencies" ), update->data( QLatin1String( "Dependencies" ) ).toString() );
|
||
|
setValue( QLatin1String( "Virtual" ), update->data( QLatin1String( "Virtual" ) ).toString() );
|
||
|
setValue( QLatin1String( "SortingPriority" ), update->data( QLatin1String( "SortingPriority" ) ).toString() );
|
||
|
setValue( QLatin1String( "InstallPriority" ), update->data( QLatin1String( "InstallPriority" ) ).toString() );
|
||
|
setValue( QLatin1String( "AutoSelectOn" ), update->data( QLatin1String( "AutoSelectOn" ) ).toString() );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Destroys the Component.
|
||
|
*/
|
||
|
Component::~Component()
|
||
|
{
|
||
|
if( parentComponent() != 0 )
|
||
|
d->m_parent->d->m_components.removeAll( this );
|
||
|
|
||
|
if (!d->m_newlyInstalled)
|
||
|
qDeleteAll(d->operations);
|
||
|
|
||
|
qDeleteAll( d->m_components );
|
||
|
delete d;
|
||
|
}
|
||
|
|
||
|
void Component::markAsPerformedInstallation()
|
||
|
{
|
||
|
d->m_newlyInstalled = true;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\property Component::removeBeforeUpdate
|
||
|
Specifies wheter this component gets removed by the installer system before it gets updated.
|
||
|
Get this property's value by using %removeBeforeUpdate(), and set it
|
||
|
using %setRemoveBeforeUpdate(). The default value is true.
|
||
|
*/
|
||
|
bool Component::removeBeforeUpdate() const
|
||
|
{
|
||
|
return d->removeBeforeUpdate;
|
||
|
}
|
||
|
|
||
|
void Component::setRemoveBeforeUpdate( bool removeBeforeUpdate )
|
||
|
{
|
||
|
d->removeBeforeUpdate = removeBeforeUpdate;
|
||
|
}
|
||
|
|
||
|
QList<Component*> Component::dependees() const
|
||
|
{
|
||
|
return d->m_installer->dependees( this );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Returns a key/value based hash of all variables set for this component.
|
||
|
*/
|
||
|
QHash<QString,QString> Component::variables() const
|
||
|
{
|
||
|
return d->m_vars;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Returns the value of variable name \a key. If \a key is not known yet, \a defaultValue is returned.
|
||
|
*/
|
||
|
QString Component::value(const QString &key,
|
||
|
const QString &defaultValue) const
|
||
|
{
|
||
|
return d->m_vars.value(key, defaultValue);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Sets the value of the variable with \a key to \a value.
|
||
|
*/
|
||
|
void Component::setValue(const QString &key, const QString &value)
|
||
|
{
|
||
|
if( d->m_vars[ key ] == value )
|
||
|
return;
|
||
|
|
||
|
d->m_vars[ key ] = value;
|
||
|
emit valueChanged( key, value );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Returnst the installer this component belongs to.
|
||
|
*/
|
||
|
Installer* Component::installer() const
|
||
|
{
|
||
|
return d->m_installer;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Returns the parent of this component. If this component is com.nokia.sdk.qt, its
|
||
|
parent is com.nokia.sdk, as far as this exists.
|
||
|
*/
|
||
|
Component* Component::parentComponent( RunModes runMode ) const
|
||
|
{
|
||
|
if ( runMode == UpdaterMode )
|
||
|
return 0;
|
||
|
else
|
||
|
return d->m_parent;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Appends \a component as a child of this component. If \a component already has a parent,
|
||
|
it is removed from the previous parent.
|
||
|
*/
|
||
|
void Component::appendComponent( Component* component )
|
||
|
{
|
||
|
d->m_components.append( component );
|
||
|
if( component->parentComponent() != 0 )
|
||
|
component->d->m_parent->d->m_components.removeAll( component );
|
||
|
component->d->m_parent = this;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Returns a list of child components. If \a recursive is set to true, the returned list
|
||
|
contains not only the direct children, but all ancestors.
|
||
|
*/
|
||
|
QList< Component* > Component::components( bool recursive, RunModes runMode ) const
|
||
|
{
|
||
|
if ( runMode == UpdaterMode )
|
||
|
return QList < Component* >();
|
||
|
if( !recursive )
|
||
|
return d->m_components;
|
||
|
|
||
|
QList< Component* > result;
|
||
|
for( QList< Component* >::const_iterator it = d->m_components.begin(); it != d->m_components.end(); ++it )
|
||
|
{
|
||
|
result.append( *it );
|
||
|
result += (*it)->components( true );
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Contains this component's name (unique identifier).
|
||
|
*/
|
||
|
QString Component::name() const
|
||
|
{
|
||
|
return value( QLatin1String( "Name" ) );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Contains this component's display name (as visible to the user).
|
||
|
*/
|
||
|
QString Component::displayName() const
|
||
|
{
|
||
|
return value( QLatin1String( "DisplayName" ) );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Loads the script at \a fileName into this component's script engine.
|
||
|
The installer and all its components as well as other useful stuff are being exported into the script.
|
||
|
Read \link componentscripting Component Scripting \endlink for details.
|
||
|
\throws Error when either the script at \a fileName couldn't be opened, or the QScriptEngine couldn't evaluate the script.
|
||
|
*/
|
||
|
void Component::loadComponentScript( const QString& fileName )
|
||
|
{
|
||
|
QFile file( fileName );
|
||
|
if( !file.open( QIODevice::ReadOnly ) )
|
||
|
throw Error( QObject::tr( "Could not open the requested script file at %1: %2" ).arg( fileName, file.errorString() ) );
|
||
|
d->scriptEngine.evaluate( QLatin1String( file.readAll() ), fileName );
|
||
|
if( d->scriptEngine.hasUncaughtException() ) {
|
||
|
throw Error( QObject::tr( "Exception while loading the component script %1" )
|
||
|
.arg(uncaughtExceptionString(&(d->scriptEngine)/*, QFileInfo(file).absoluteFilePath()*/)) );
|
||
|
}
|
||
|
|
||
|
const QList< Component* > components = d->m_installer->components( true );
|
||
|
QScriptValue comps = d->scriptEngine.newArray( components.count() );
|
||
|
for( int i = 0; i < components.count(); ++i ) {
|
||
|
comps.setProperty( i, d->scriptEngine.newQObject( components[ i ] ) );
|
||
|
}
|
||
|
d->scriptEngine.globalObject().property( QLatin1String( "installer" ) ).setProperty( QLatin1String( "components" ), comps );
|
||
|
|
||
|
QScriptValue comp = d->scriptEngine.evaluate( QLatin1String( "Component" ) );
|
||
|
if( !d->scriptEngine.hasUncaughtException() )
|
||
|
{
|
||
|
d->scriptComponent = comp;
|
||
|
d->scriptComponent.construct();
|
||
|
}
|
||
|
|
||
|
emit loaded();
|
||
|
languageChanged();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\internal
|
||
|
Calls the script method \link retranslateUi() \endlink, if any. This is done whenever a QTranslator file is being loaded.
|
||
|
*/
|
||
|
void Component::languageChanged()
|
||
|
{
|
||
|
callScriptMethod( QLatin1String( "retranslateUi" ) );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Tries to call the method with \a name within the script and returns the result.
|
||
|
If the method doesn't exist, an invalid result is returned. If the method has an uncaught exception, its string
|
||
|
representation is thrown as an Error exception.
|
||
|
\note The method is not called, if the current script context is the same method, to avoid infinite recursion.
|
||
|
*/
|
||
|
QScriptValue Component::callScriptMethod( const QString& methodName, const QScriptValueList& arguments )
|
||
|
{
|
||
|
if( !d->unexistingScriptMethods.value( methodName, true ) )
|
||
|
return QScriptValue();
|
||
|
|
||
|
// don't allow such a recursion
|
||
|
if( d->scriptEngine.currentContext()->backtrace().first().startsWith( methodName ) )
|
||
|
return QScriptValue();
|
||
|
|
||
|
QScriptValue method = d->scriptComponent.property( QString::fromLatin1( "prototype" ) ).property( methodName );
|
||
|
|
||
|
if( !method.isValid() ) // this marks the method to be called not any longer
|
||
|
d->unexistingScriptMethods[ methodName ] = false;
|
||
|
|
||
|
const QScriptValue result = method.call( d->scriptComponent, arguments );
|
||
|
|
||
|
if( !result.isValid() )
|
||
|
return result;
|
||
|
|
||
|
if( d->scriptEngine.hasUncaughtException() )
|
||
|
throw Error( uncaughtExceptionString(&(d->scriptEngine)/*, name()*/) );
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Loads the translations matching the name filters \a qms inside \a directory.
|
||
|
Only translations with a \link QFileInfo::baseName() baseName \endlink matching the
|
||
|
current locales \link QLocale::name() name \endlink are loaded.
|
||
|
Read \ref componenttranslation for details.
|
||
|
*/
|
||
|
void Component::loadTranslations( const QDir& directory, const QStringList& qms )
|
||
|
{
|
||
|
QDirIterator it( directory.path(), qms, QDir::Files );
|
||
|
while( it.hasNext() )
|
||
|
{
|
||
|
const QString filename = it.next();
|
||
|
if( QFileInfo( filename ).baseName().toLower() != QLocale().name().toLower() )
|
||
|
continue;
|
||
|
|
||
|
std::auto_ptr<QTranslator> translator( new QTranslator( this ) );
|
||
|
if( !translator->load( filename ) )
|
||
|
throw Error( tr( "Could not open the requested translation file at %1" ).arg( filename ) );
|
||
|
qApp->installTranslator( translator.release() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Loads the user interface files matching the name filters \a uis inside \a directory.
|
||
|
The loaded interface can be accessed via userInterfaces by using the class name set in the ui file.
|
||
|
Read \ref componentuserinterfaces for details.
|
||
|
*/
|
||
|
void Component::loadUserInterfaces( const QDir& directory, const QStringList& uis )
|
||
|
{
|
||
|
if( QApplication::type() == QApplication::Tty )
|
||
|
return;
|
||
|
|
||
|
QDirIterator it( directory.path(), uis, QDir::Files );
|
||
|
while( it.hasNext() )
|
||
|
{
|
||
|
QFile file( it.next() );
|
||
|
if( !file.open( QIODevice::ReadOnly ) )
|
||
|
throw Error( tr( "Could not open the requested UI file at %1: %2" ).arg( it.fileName(), file.errorString() ) );
|
||
|
|
||
|
static QUiLoader loader;
|
||
|
loader.setTranslationEnabled( true );
|
||
|
loader.setLanguageChangeEnabled( true );
|
||
|
QWidget* const w = loader.load( &file );
|
||
|
d->userInterfaces[ w->objectName() ] = w;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Component::loadLicenses(const QString &directory, const QHash<QString, QVariant> &licenseHash)
|
||
|
{
|
||
|
QHash<QString, QVariant>::const_iterator it;
|
||
|
for (it = licenseHash.begin(); it != licenseHash.end(); ++it) {
|
||
|
const QString &fileName = it.value().toString();
|
||
|
QFile file(directory + fileName);
|
||
|
if(!file.open(QIODevice::ReadOnly)) {
|
||
|
throw Error(tr("Could not open the requested license file at %1: %2" ).arg(fileName,
|
||
|
file.errorString()));
|
||
|
}
|
||
|
d->m_licenses.insert(it.key(), qMakePair(fileName, QTextStream(&file).readAll()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Contains a list of all user interface class names known to this component.
|
||
|
*/
|
||
|
QStringList Component::userInterfaces() const
|
||
|
{
|
||
|
return d->userInterfaces.keys();
|
||
|
}
|
||
|
|
||
|
QHash<QString, QPair<QString, QString> > Component::licenses() const
|
||
|
{
|
||
|
return d->m_licenses;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Returns the QWidget created for class \a name.
|
||
|
*/
|
||
|
QWidget* Component::userInterface( const QString& name ) const
|
||
|
{
|
||
|
return d->userInterfaces.value( name );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Creates all operations needed to install this component's \a path.
|
||
|
\a path is a full qualified filename including the component's name.
|
||
|
This metods gets called from Component::createOperationsForArchive.
|
||
|
You can override this method by providing a method with the same name in the component script.
|
||
|
\note If you call this method from a script, it won't call the scripts method with the same name.
|
||
|
\note RSA signature files are omitted by this method.
|
||
|
|
||
|
The default implemention is recursively creating Copy and Mkdir operations for all files
|
||
|
and folders within \a path.
|
||
|
*/
|
||
|
void Component::createOperationsForPath( const QString& path )
|
||
|
{
|
||
|
const QFileInfo fi( path );
|
||
|
|
||
|
// don't copy over a signature
|
||
|
if( fi.suffix() == QLatin1String( "sig" ) && QFileInfo( fi.dir(), fi.completeBaseName() ).exists() )
|
||
|
return;
|
||
|
|
||
|
// the script can override this method
|
||
|
if( callScriptMethod( QLatin1String( "createOperationsForPath" ), QScriptValueList() << path ).isValid() )
|
||
|
return;
|
||
|
|
||
|
static const QString zipPrefix = QString::fromLatin1( "7z://installer://" );
|
||
|
static const QString prefix = QString::fromLatin1( "installer://" );
|
||
|
QString target;
|
||
|
if ( path.startsWith( zipPrefix ) ) { // if the path is an archive, remove the archive file name from the target path
|
||
|
target = path.mid( zipPrefix.length() + name().length() + 1 ); // + 1 for the /
|
||
|
const int nextSlash = target.indexOf( QLatin1Char('/') );
|
||
|
if ( nextSlash != -1 )
|
||
|
target = target.mid( nextSlash );
|
||
|
else
|
||
|
target.clear();
|
||
|
target.prepend(QLatin1String("@TargetDir@"));
|
||
|
}
|
||
|
else
|
||
|
target = QString::fromLatin1( "@TargetDir@%1" ).arg( path.mid( prefix.length() + name().length() ) );
|
||
|
static const QString copy = QString::fromLatin1( "Copy" );
|
||
|
static const QString mkdir = QString::fromLatin1( "Mkdir" );
|
||
|
if( fi.isFile() )
|
||
|
{
|
||
|
addOperation( copy, fi.filePath(), target );
|
||
|
}
|
||
|
else if( fi.isDir() )
|
||
|
{
|
||
|
qApp->processEvents();
|
||
|
addOperation( mkdir, target );
|
||
|
QDirIterator it( fi.filePath() );
|
||
|
while( it.hasNext() )
|
||
|
createOperationsForPath( it.next() );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Creates all operations needed to install this component's \a archive.
|
||
|
This metods gets called from Component::createOperations.
|
||
|
You can override this method by providing a method with the same name in the component script.
|
||
|
\note If you call this method from a script, it won't call the scripts method with the same name.
|
||
|
|
||
|
The default implementation calls createOperationsForPath for everything contained in the archive.
|
||
|
If \a archive is a compressed archive known to the installer system, an Extract operation is created, instead.
|
||
|
*/
|
||
|
void Component::createOperationsForArchive( const QString& archive )
|
||
|
{
|
||
|
// the script can override this method
|
||
|
if( callScriptMethod( QLatin1String( "createOperationsForArchive" ), QScriptValueList() << archive ).isValid() )
|
||
|
return;
|
||
|
|
||
|
const QFileInfo fi( QString::fromLatin1( "installer://%1/%2").arg( name(), archive ) );
|
||
|
const bool isZip = Lib7z::isSupportedArchive( fi.filePath() );
|
||
|
|
||
|
if( !isZip )
|
||
|
createOperationsForPath( fi.filePath() );
|
||
|
else
|
||
|
// archives get completely extracted per default (if the script isn't doing other stuff)
|
||
|
addOperation( QLatin1String( "Extract" ), fi.filePath(), QLatin1String( "@TargetDir@" ) );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Creates all operations needed to install this component.
|
||
|
You can override this method by providing a method with the same name in the component script.
|
||
|
\note If you call this method from a script, it won't call the scripts method with the same name.
|
||
|
|
||
|
The default implementation calls createOperationsForArchive for all archives in this component.
|
||
|
*/
|
||
|
void Component::createOperations()
|
||
|
{
|
||
|
// the script can override this method
|
||
|
if( callScriptMethod( QLatin1String( "createOperations" ) ).isValid() )
|
||
|
{
|
||
|
d->operationsCreated = true;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const QDir dir( QString::fromLatin1( "installer://%1/" ).arg( name() ) );
|
||
|
const QStringList archives = dir.entryList();
|
||
|
for( QStringList::const_iterator it = archives.begin(); it != archives.end(); ++it )
|
||
|
createOperationsForArchive( *it );
|
||
|
|
||
|
d->operationsCreated = true;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Registers the file or directory at \a path for being removed when this component gets uninstalled.
|
||
|
In case of a directory, this will be recursive.
|
||
|
If \a wipe is set to true, the directory will also be deleted if it contains changes done by the user
|
||
|
after installation.
|
||
|
*/
|
||
|
void Component::registerPathForUninstallation( const QString& path, bool wipe )
|
||
|
{
|
||
|
d->pathesForUninstallation.append( qMakePair( path, wipe ) );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Returns the list of pathes previously registered for uninstallation with #registerPathForUninstallation.
|
||
|
*/
|
||
|
QList< QPair< QString, bool > > Component::pathesForUninstallation() const
|
||
|
{
|
||
|
return d->pathesForUninstallation;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Contains the names of all archives known to this component. This does not contain archives added
|
||
|
with #addDownloadableArchive.
|
||
|
*/
|
||
|
QStringList Component::archives() const
|
||
|
{
|
||
|
return QDir( QString::fromLatin1( "installer://%1/" ).arg( name() ) ).entryList();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Adds the archive \a path to this component. This can only be called when this component was downloaded from
|
||
|
an online repository. When adding \a path, it will be downloaded from the repository when the installation starts.
|
||
|
Read \ref sec_repogen for details.
|
||
|
\sa fromOnlineRepository
|
||
|
*/
|
||
|
void Component::addDownloadableArchive( const QString& path )
|
||
|
{
|
||
|
Q_ASSERT( isFromOnlineRepository() );
|
||
|
const QString versionPrefix = value( QLatin1String( "Version" ) );
|
||
|
verbose() << "addDownloadable " << path << std::endl;
|
||
|
d->downloadableArchives.append( versionPrefix + path );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Removes the archive \a path previously added via addDownloadableArchive from this component. This can oly be
|
||
|
called when this component was downloaded from an online repository. Read \ref sec_repogen for details.
|
||
|
*/
|
||
|
void Component::removeDownloadableArchive( const QString& path )
|
||
|
{
|
||
|
Q_ASSERT( isFromOnlineRepository() );
|
||
|
d->downloadableArchives.removeAll( path );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Returns the archives to be downloaded from the online repository before installation.
|
||
|
*/
|
||
|
QStringList Component::downloadableArchives() const
|
||
|
{
|
||
|
return d->downloadableArchives;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Adds a request for quitting the process @p process before installing/updating/uninstalling the
|
||
|
* component.
|
||
|
*/
|
||
|
void Component::addStopProcessForUpdateRequest( const QString& process )
|
||
|
{
|
||
|
d->stopProcessForUpdateRequests.append( process );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Removes the request for quitting the process @p process again.
|
||
|
*/
|
||
|
void Component::removeStopProcessForUpdateRequest( const QString& process )
|
||
|
{
|
||
|
d->stopProcessForUpdateRequests.removeAll( process );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Convenience: Add/remove request depending on @p requested (add if @p true, remove if @p false).
|
||
|
*/
|
||
|
void Component::setStopProcessForUpdateRequest( const QString& process, bool requested )
|
||
|
{
|
||
|
if ( requested )
|
||
|
addStopProcessForUpdateRequest( process );
|
||
|
else
|
||
|
removeStopProcessForUpdateRequest( process );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* The list of processes this component needs to be closed before installing/updating/uninstalling
|
||
|
*/
|
||
|
QStringList Component::stopProcessForUpdateRequests() const
|
||
|
{
|
||
|
return d->stopProcessForUpdateRequests;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Returns the operations needed to install this component. If autoCreateOperations is true, createOperations
|
||
|
is called, if no operations have been auto-created yet.
|
||
|
*/
|
||
|
QList< KDUpdater::UpdateOperation* > Component::operations() const
|
||
|
{
|
||
|
if (d->autoCreateOperations && !d->operationsCreated) {
|
||
|
const_cast< Component* >( this )->createOperations();
|
||
|
|
||
|
if (!d->minimumProgressOperation) {
|
||
|
d->minimumProgressOperation = KDUpdater::UpdateOperationFactory::instance()
|
||
|
.create(QLatin1String("MinimumProgress"));
|
||
|
d->operations.append(d->minimumProgressOperation);
|
||
|
}
|
||
|
|
||
|
if (!d->m_licenses.isEmpty()) {
|
||
|
d->m_licenseOperation = KDUpdater::UpdateOperationFactory::instance()
|
||
|
.create(QLatin1String("License"));
|
||
|
d->m_licenseOperation->setValue(QLatin1String("installer"),
|
||
|
QVariant::fromValue(d->m_installer));
|
||
|
|
||
|
QVariantMap licenses;
|
||
|
const QList<QPair<QString, QString> > values = d->m_licenses.values();
|
||
|
for (int i = 0; i < values.count(); ++i)
|
||
|
licenses.insert(values.at(i).first, values.at(i).second);
|
||
|
d->m_licenseOperation->setValue(QLatin1String("licenses"), licenses);
|
||
|
d->operations.append(d->m_licenseOperation);
|
||
|
}
|
||
|
}
|
||
|
return d->operations;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Adds \a operation to the list of operations needed to install this component.
|
||
|
*/
|
||
|
void Component::addOperation( KDUpdater::UpdateOperation* operation )
|
||
|
{
|
||
|
d->operations.append( operation );
|
||
|
if( FSEngineClientHandler::instance()->isActive() )
|
||
|
operation->setValue( QLatin1String( "admin" ), true );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Adds \a operation to the list of operations needed to install this component. \a operation
|
||
|
is executed with elevated rights.
|
||
|
*/
|
||
|
void Component::addElevatedOperation( KDUpdater::UpdateOperation* operation )
|
||
|
{
|
||
|
addOperation( operation );
|
||
|
operation->setValue( QLatin1String( "admin" ), true );
|
||
|
}
|
||
|
|
||
|
bool Component::operationsCreatedSuccessfully() const
|
||
|
{
|
||
|
return d->operationsCreatedSuccessfully;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Creates and adds an installation operation for \a operation. Add any number of \a parameter1, \a parameter2, \a parameter3, \a parameter4, \a parameter5 and \a parameter6
|
||
|
The contents of the parameters get variables like "@TargetDir@" replaced with their values, if contained.
|
||
|
\sa installeroperations
|
||
|
*/
|
||
|
bool Component::addOperation( const QString& operation, const QString& parameter1, const QString& parameter2, const QString& parameter3, const QString& parameter4, const QString& parameter5, const QString& parameter6, const QString& parameter7, const QString& parameter8, const QString& parameter9, const QString& parameter10 )
|
||
|
{
|
||
|
KDUpdater::UpdateOperation* const op = KDUpdater::UpdateOperationFactory::instance().create( operation );
|
||
|
if( op == 0 )
|
||
|
{
|
||
|
const QMessageBox::StandardButton button = MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(),
|
||
|
QLatin1String( "operationDoesNotExistError" ), tr( "Error" ),
|
||
|
tr( "Error: Operation %1 does not exist" ).arg( operation ),
|
||
|
QMessageBox::Abort | QMessageBox::Ignore );
|
||
|
if ( button == QMessageBox::Abort )
|
||
|
{
|
||
|
d->operationsCreatedSuccessfully = false;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
if ( op->name() == QLatin1String( "Delete" ) )
|
||
|
op->setValue( QLatin1String( "performUndo" ), false );
|
||
|
op->setValue( QLatin1String( "installer" ), qVariantFromValue( d->m_installer ) );
|
||
|
|
||
|
QStringList arguments;
|
||
|
if( !parameter1.isNull() )
|
||
|
arguments.append( parameter1 );
|
||
|
if( !parameter2.isNull() )
|
||
|
arguments.append( parameter2 );
|
||
|
if( !parameter3.isNull() )
|
||
|
arguments.append( parameter3 );
|
||
|
if( !parameter4.isNull() )
|
||
|
arguments.append( parameter4 );
|
||
|
if( !parameter5.isNull() )
|
||
|
arguments.append( parameter5 );
|
||
|
if( !parameter6.isNull() )
|
||
|
arguments.append( parameter6 );
|
||
|
if( !parameter7.isNull() )
|
||
|
arguments.append( parameter7 );
|
||
|
if( !parameter8.isNull() )
|
||
|
arguments.append( parameter8 );
|
||
|
if( !parameter9.isNull() )
|
||
|
arguments.append( parameter9 );
|
||
|
if( !parameter10.isNull() )
|
||
|
arguments.append( parameter10 );
|
||
|
op->setArguments( d->m_installer->replaceVariables( arguments ) );
|
||
|
|
||
|
addOperation( op );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Creates and adds an installation operation for \a operation. Add any number of \a parameter1, \a parameter2, \a parameter3, \a parameter4, \a parameter5 and \a parameter6
|
||
|
The contents of the parameters get variables like "@TargetDir@" replaced with their values, if contained. \a operation is executed with
|
||
|
elevated rights.
|
||
|
\sa installeroperations
|
||
|
*/
|
||
|
bool Component::addElevatedOperation( const QString& operation, const QString& parameter1, const QString& parameter2, const QString& parameter3, const QString& parameter4, const QString& parameter5, const QString& parameter6, const QString& parameter7, const QString& parameter8, const QString& parameter9, const QString& parameter10 )
|
||
|
{
|
||
|
KDUpdater::UpdateOperation* const op = KDUpdater::UpdateOperationFactory::instance().create( operation );
|
||
|
if( op == 0 )
|
||
|
return false;
|
||
|
|
||
|
op->setValue( QLatin1String( "installer" ), qVariantFromValue( d->m_installer ) );
|
||
|
|
||
|
QStringList arguments;
|
||
|
if( !parameter1.isNull() )
|
||
|
arguments.append( parameter1 );
|
||
|
if( !parameter2.isNull() )
|
||
|
arguments.append( parameter2 );
|
||
|
if( !parameter3.isNull() )
|
||
|
arguments.append( parameter3 );
|
||
|
if( !parameter4.isNull() )
|
||
|
arguments.append( parameter4 );
|
||
|
if( !parameter5.isNull() )
|
||
|
arguments.append( parameter5 );
|
||
|
if( !parameter6.isNull() )
|
||
|
arguments.append( parameter6 );
|
||
|
if( !parameter7.isNull() )
|
||
|
arguments.append( parameter7 );
|
||
|
if( !parameter8.isNull() )
|
||
|
arguments.append( parameter8 );
|
||
|
if( !parameter9.isNull() )
|
||
|
arguments.append( parameter9 );
|
||
|
if( !parameter10.isNull() )
|
||
|
arguments.append( parameter10 );
|
||
|
op->setArguments( d->m_installer->replaceVariables( arguments ) );
|
||
|
|
||
|
addElevatedOperation( op );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*!
|
||
|
Specifies wheter operations should be automatically created when the installation starts. This would be done by calling #createOperations.
|
||
|
If you set this to false, it's completely up to the component's script to create all operations.
|
||
|
*/
|
||
|
bool Component::autoCreateOperations() const
|
||
|
{
|
||
|
return d->autoCreateOperations;
|
||
|
}
|
||
|
|
||
|
void Component::setAutoCreateOperations( bool autoCreateOperations )
|
||
|
{
|
||
|
d->autoCreateOperations = autoCreateOperations;
|
||
|
}
|
||
|
|
||
|
Qt::CheckState Component::checkState( RunModes runMode ) const
|
||
|
{
|
||
|
if ( runMode == UpdaterMode )
|
||
|
return d->isCheckedFromUpdater ? Qt::Checked : Qt::Unchecked;
|
||
|
const QMap< const Component*, Qt::CheckState >::const_iterator it = Private::cachedCheckStates.find( this );
|
||
|
if( it != Private::cachedCheckStates.end() )
|
||
|
return *it;
|
||
|
const Qt::CheckState state = componentCheckState( this, runMode );
|
||
|
Private::cachedCheckStates[ this ] = state;
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\property Component::selected
|
||
|
Specifies wheter this component is selected for installation.
|
||
|
Get this property's value by using %isSelected(), and set it
|
||
|
using %setSelected().
|
||
|
*/
|
||
|
bool Component::isSelected( RunModes runMode ) const
|
||
|
{
|
||
|
const Qt::CheckState state = checkState( runMode );
|
||
|
return state != Qt::Unchecked;
|
||
|
}
|
||
|
|
||
|
//SelectMode means:
|
||
|
//NormalSelectMode - dependency errors and selectionChanged SIGNAL are emitted
|
||
|
//InitializeComponentTreeSelectMode - no dependency errors(maybe some components are not ready initialized),
|
||
|
// no selectionChanged SIGNAL needed and no recursion
|
||
|
void Component::setSelected(bool selected, RunModes runMode, SelectMode selectMode)
|
||
|
{
|
||
|
if ( runMode == UpdaterMode )
|
||
|
{
|
||
|
verbose() << "Update selection" << std::endl;
|
||
|
QStringList missingNames;
|
||
|
d->m_installer->dependencies( this, &missingNames );
|
||
|
|
||
|
if ( !missingNames.isEmpty() )
|
||
|
{
|
||
|
const QString missingPackages = missingNames.join( QLatin1String( " " ) );
|
||
|
if ( selectMode == NormalSelectMode ) {
|
||
|
MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(),
|
||
|
QLatin1String( "DependenciesMissingError" ), tr( "Dependencies Missing" ),
|
||
|
tr( "The following required packages could not be found : %1!" ).arg( missingPackages ),
|
||
|
QMessageBox::Ok );
|
||
|
}
|
||
|
verbose() << "Error occured missing dependencies" << missingPackages << std::endl;
|
||
|
return;
|
||
|
} else {
|
||
|
verbose() << "No Error occured" << std::endl;
|
||
|
}
|
||
|
const Qt::CheckState previousState = checkState( UpdaterMode );
|
||
|
const Qt::CheckState newState = selected ? Qt::Checked : Qt::Unchecked;
|
||
|
d->isCheckedFromUpdater = selected;
|
||
|
// we have to select all dependees as well
|
||
|
if ( selected )
|
||
|
{
|
||
|
verbose() << "Update selected for " << name() <<std::endl;
|
||
|
const QList< Component* > dependees = d->m_installer->missingDependencies( this );
|
||
|
d->setSelectedOnComponentList(dependees, true, runMode, selectMode);
|
||
|
}
|
||
|
if( !selected )
|
||
|
{
|
||
|
// if it got deselected, we have to deselect all dependees as well
|
||
|
verbose() << "Update deselected" << name() << std::endl;
|
||
|
const QList< Component* > dependees = d->m_installer->dependees( this );
|
||
|
d->setSelectedOnComponentList(dependees, false, runMode, selectMode);
|
||
|
}
|
||
|
//we need selectedChanged even it is not in the NormalSelectMode to check the running processes from script side
|
||
|
//for installpart it is working because we are selecting the components in the script as well
|
||
|
//TODO: change this ^ behaviour in scripts and code
|
||
|
if( /*selectMode == NormalSelectMode && */newState != previousState )
|
||
|
QMetaObject::invokeMethod( this, "selectedChanged", Qt::QueuedConnection, Q_ARG( bool, newState == Qt::Checked ) );
|
||
|
|
||
|
} else {
|
||
|
QMap< Component*, Qt::CheckState > previousStates;
|
||
|
const QList< Component* > allComponents = d->m_installer->components( true );
|
||
|
for( QList< Component* >::const_iterator it = allComponents.begin(); it != allComponents.end(); ++it )
|
||
|
previousStates[ *it ] = (*it)->checkState();
|
||
|
|
||
|
setValue( QString::fromLatin1( "WantedState" ), selected ? QString::fromLatin1( "Installed" ) : QString::fromLatin1( "Uninstalled" ) );
|
||
|
Private::cachedCheckStates.clear();
|
||
|
|
||
|
if ( selected )
|
||
|
{
|
||
|
verbose() << "Update selected for " << name() << std::endl;
|
||
|
const QList< Component* > dependees = d->m_installer->missingDependencies( this );
|
||
|
d->setSelectedOnComponentList(dependees, true, runMode, selectMode);
|
||
|
}
|
||
|
|
||
|
if( !selected )
|
||
|
{
|
||
|
// if it got deselected, we have to deselect all dependees as well
|
||
|
const QList< Component* > dependees = d->m_installer->dependees( this );
|
||
|
d->setSelectedOnComponentList(dependees, false, runMode, selectMode);
|
||
|
}
|
||
|
|
||
|
// and all children
|
||
|
if ( selectMode == NormalSelectMode )
|
||
|
{
|
||
|
const QList< Component* > children = components( true );
|
||
|
for( QList< Component* >::const_iterator it = children.begin(); it != children.end(); ++it )
|
||
|
{
|
||
|
Component* const comp = *it;
|
||
|
comp->setValue( QString::fromLatin1( "WantedState" ), selected ? QString::fromLatin1( "Installed" ) : QString::fromLatin1( "Uninstalled" ) );
|
||
|
}
|
||
|
|
||
|
//now all needed components are selected so we can emit the signals
|
||
|
for( QList< Component* >::const_iterator it = allComponents.begin(); it != allComponents.end(); ++it )
|
||
|
{
|
||
|
const Qt::CheckState newCheckState = (*it)->checkState();
|
||
|
if( previousStates[ *it ] != newCheckState )
|
||
|
QMetaObject::invokeMethod( *it, "selectedChanged", Qt::QueuedConnection, Q_ARG( bool, newCheckState == Qt::Checked ) );
|
||
|
//emit (*it)->selectedChanged( state == Qt::Checked );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Contains this component dependencies.
|
||
|
* Read \ref componentdependencies for details.
|
||
|
*/
|
||
|
QStringList Component::dependencies() const
|
||
|
{
|
||
|
return value( QLatin1String( "Dependencies" ) ).split( QLatin1Char( ',' ) );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Determines if the component is installed
|
||
|
*/
|
||
|
bool Component::isInstalled() const
|
||
|
{
|
||
|
return QLatin1String( "Installed" ) == value( QLatin1String( "CurrentState" ) );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Determines if the user wants to install the component
|
||
|
*/
|
||
|
bool Component::installationRequested() const
|
||
|
{
|
||
|
return ( QLatin1String( "Installed" ) == value( QLatin1String( "WantedState" ) ) && ( !isInstalled() || isSelected( UpdaterMode ) ) );
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Determines if the user wants to install the component
|
||
|
*/
|
||
|
bool Component::uninstallationRequested() const
|
||
|
{
|
||
|
return QLatin1String( "Uninstalled" ) == value( QLatin1String( "WantedState" ) ) && isInstalled();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Determines if the component was installed recently
|
||
|
*/
|
||
|
bool Component::wasInstalled() const
|
||
|
{
|
||
|
return QLatin1String( "Uninstalled" ) == value( QLatin1String( "PreviousState" ) ) && isInstalled();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Determines if the component was removed recently
|
||
|
*/
|
||
|
bool Component::wasUninstalled() const
|
||
|
{
|
||
|
return QLatin1String( "Installed" ) == value( QLatin1String( "PreviousState" ) ) && !isInstalled();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Determines if the components installations status can be changed.
|
||
|
*/
|
||
|
bool Component::isEnabled() const
|
||
|
{
|
||
|
return d->enabled;
|
||
|
}
|
||
|
/*!
|
||
|
* Enables oder disables ability to change the components installations status.
|
||
|
*/
|
||
|
void Component::setEnabled( bool enabled )
|
||
|
{
|
||
|
d->enabled = enabled;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* \property Component::fromOnlineRepository
|
||
|
* Determines wheter this component has been loaded from an online repository.
|
||
|
* Get this property's value by usinng %isFromOnlineRepository.
|
||
|
* \sa addDownloadableArchive
|
||
|
*/
|
||
|
bool Component::isFromOnlineRepository() const
|
||
|
{
|
||
|
return !repositoryUrl().isEmpty();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Contains the repository Url this component is downloaded from.
|
||
|
* When this component is not downloaded from an online repository, returns an empty #QUrl.
|
||
|
*/
|
||
|
QUrl Component::repositoryUrl() const
|
||
|
{
|
||
|
return d->repositoryUrl;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\internal
|
||
|
Sets this components #repositoryUrl.
|
||
|
*/
|
||
|
void Component::setRepositoryUrl( const QUrl& url )
|
||
|
{
|
||
|
d->repositoryUrl = url;
|
||
|
}
|