diff options
Diffstat (limited to 'installerbuilder/libinstaller/qinstallergui.cpp')
-rw-r--r-- | installerbuilder/libinstaller/qinstallergui.cpp | 1721 |
1 files changed, 1721 insertions, 0 deletions
diff --git a/installerbuilder/libinstaller/qinstallergui.cpp b/installerbuilder/libinstaller/qinstallergui.cpp new file mode 100644 index 000000000..8f34a5a9f --- /dev/null +++ b/installerbuilder/libinstaller/qinstallergui.cpp @@ -0,0 +1,1721 @@ +/************************************************************************** +** +** 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 "qinstallergui.h" + +#include "qinstaller.h" +#include "qinstallerglobal.h" +#include "qinstallercomponent.h" +#include "qinstallercomponentmodel.h" +#include "progresscoordinator.h" +#include "performinstallationform.h" + +#include "common/errors.h" +#include "common/utils.h" +#include "common/installersettings.h" +#include "common/fileutils.h" + +#include <KDToolsCore/KDByteSize> +#include <KDToolsCore/KDSysInfo> + +#include <QtCore/QDir> +#include <QtCore/QDynamicPropertyChangeEvent> +#include <QtCore/QPair> +#include <QtCore/QProcess> +#include <QtCore/QRegExp> +#include <QtCore/QSettings> +#include <QtCore/QTimer> + +#include <QtGui/QApplication> +#include <QtGui/QCheckBox> +#include <QtGui/QDesktopServices> +#include <QtGui/QFileDialog> +#include <QtGui/QGridLayout> +#include <QtGui/QFormLayout> +#include <QtGui/QHBoxLayout> +#include <QtGui/QHeaderView> +#include <QtGui/QGroupBox> +#include <QtGui/QLabel> +#include <QtGui/QLineEdit> +#include <QtGui/QListWidget> +#include <QtGui/QListWidgetItem> +#include <QtGui/QMessageBox> +#include <QtGui/QProgressBar> +#include <QtGui/QPushButton> +#include <QtGui/QRadioButton> +#include <QtGui/QTextBrowser> +#include <QtGui/QTreeWidget> +#include <QtGui/QTreeView> +#include <QtGui/QVBoxLayout> +#include <QtGui/QScrollBar> + +#include <QtScript/QScriptEngine> + +using namespace QInstaller; + +/* +TRANSLATOR QInstaller::Installer; +*/ +/* +TRANSLATOR QInstaller::Gui +*/ +/* +TRANSLATOR QInstaller::Page +*/ +/* +TRANSLATOR QInstaller::IntroductionPage +*/ +/* +TRANSLATOR QInstaller::LicenseAgreementPage +*/ +/* +TRANSLATOR QInstaller::ComponentSelectionPage +*/ +/* +TRANSLATOR QInstaller::TargetDirectoryPage +*/ +/* +TRANSLATOR QInstaller::StartMenuDirectoryPage +*/ +/* +TRANSLATOR QInstaller::ReadyForInstallationPage +*/ +/* +TRANSLATOR QInstaller::PerformInstallationPage +*/ +/* +TRANSLATOR QInstaller::FinishedPage +*/ + + +class DynamicInstallerPage : public Page +{ +public: + explicit DynamicInstallerPage( QWidget* widget, Installer* parent = 0 ) + : Page( parent ), + m_widget( widget ) + { + setObjectName( QLatin1String("Dynamic") + widget->objectName() ); + setPixmap(QWizard::LogoPixmap, logoPixmap()); + setPixmap(QWizard::WatermarkPixmap, QPixmap()); + + setLayout( new QVBoxLayout ); + setTitle( widget->windowTitle() ); + m_widget->setProperty( "complete", true ); + m_widget->setProperty( "final", false ); + widget->installEventFilter( this ); + layout()->addWidget( widget ); + } + + QWidget* widget() const + { + return m_widget; + } + + bool isComplete() const + { + return m_widget->property( "complete" ).toBool(); + } + +protected: + bool eventFilter( QObject* obj, QEvent* event ) + { + if( obj == m_widget ) + { + switch( event->type() ) + { + case QEvent::WindowTitleChange: + setTitle( m_widget->windowTitle() ); + break; + case QEvent::DynamicPropertyChange: + emit completeChanged(); + if( m_widget->property( "final" ).toBool() != isFinalPage() ) + setFinalPage( m_widget->property( "final" ).toBool() ); + break; + default: + break; + } + } + return Page::eventFilter( obj, event ); + } + +private: + QWidget* const m_widget; +}; + +//////////////////////////////////////////////////////////////////// +// +// Gui +// +//////////////////////////////////////////////////////////////////// + + +class Gui::Private +{ +public: + Private() + : autoSwitchPage(true), + modified( false ) + { + + } + + QScriptEngine controlScriptEngine; + QScriptValue controlScript; + bool autoSwitchPage; + bool modified; +}; + +QScriptEngine* Gui::controlScriptEngine() const +{ + return &d->controlScriptEngine; +} + +/*! + \class QInstaller::Gui + Is the "gui" object in a none interactive installation + */ + +Gui::Gui(Installer *installer, QWidget *parent) + : QWizard(parent) + , m_installer( installer ) + , d( new Private ) + , m_introPage( new IntroductionPage( installer ) ) +{ + if ( installer->isInstaller() ) + setWindowTitle(tr("%1 Setup").arg(m_installer->value(QLatin1String( "Title" ) ) ) ); + else + setWindowTitle(tr("%1").arg(m_installer->value(QLatin1String( "maintenanceTitle") ) ) ); + +#ifndef Q_WS_MAC + setWindowIcon( QIcon( m_installer->settings().icon() ) ); + setWizardStyle( QWizard::ModernStyle ); +#else + setPixmap( QWizard::BackgroundPixmap, m_installer->settings().background() ); +#endif + setOption(QWizard::NoBackButtonOnStartPage); + setOption(QWizard::NoBackButtonOnLastPage); +// setOption(QWizard::IndependentPages); + setLayout( new QVBoxLayout( this ) ); + if ( installer->isInstaller() ) + setPage( Installer::Introduction, m_introPage ); + + connect(this, SIGNAL(interrupted()), installer, SLOT(interrupt())); + connect(this, SIGNAL(rejected()), installer, SLOT(setCanceled()) ); + // both queued to show the finished page once everything is done + connect(installer, SIGNAL(installationFinished()), this, + SLOT(showFinishedPage()), Qt::QueuedConnection); + connect(installer, SIGNAL(uninstallationFinished()), this, + SLOT(showFinishedPage()), Qt::QueuedConnection); + + connect( this, SIGNAL( currentIdChanged( int ) ), this, SLOT( slotCurrentPageChanged( int ) ) ); + connect( this, SIGNAL( currentIdChanged( int ) ), m_installer, SIGNAL( currentPageChanged( int ) ) ); + connect( button( QWizard::FinishButton ), SIGNAL( clicked() ), this, SIGNAL( finishButtonClicked() ) ); + connect( this, SIGNAL( finishButtonClicked() ), installer, SIGNAL( finishButtonClicked() ) ); + + // make sure the QUiLoader's retranslateUi is executed first, then the script + connect( this, SIGNAL( languageChanged() ), + installer, SLOT( languageChanged() ), Qt::QueuedConnection ); + + connect( installer, SIGNAL( wizardPageInsertionRequested( QWidget*, Installer::WizardPage ) ), + this, SLOT( wizardPageInsertionRequested( QWidget*, Installer::WizardPage ) ) ); + connect( installer, SIGNAL( wizardPageRemovalRequested( QWidget* ) ), + this, SLOT( wizardPageRemovalRequested( QWidget* ) ) ); + connect( installer, SIGNAL( wizardWidgetInsertionRequested( QWidget*, Installer::WizardPage ) ), + this, SLOT( wizardWidgetInsertionRequested( QWidget*, Installer::WizardPage ) ) ); + connect( installer, SIGNAL( wizardWidgetRemovalRequested( QWidget* ) ), + this, SLOT( wizardWidgetRemovalRequested( QWidget* ) ) ); + connect( installer, SIGNAL( wizardPageVisibilityChangeRequested( bool, int ) ), + this, SLOT( wizardPageVisibilityChangeRequested( bool, int ) ), Qt::QueuedConnection ); + + connect( installer, SIGNAL( setAutomatedPageSwitchEnabled( bool ) ), + this, SLOT( setAutomatedPageSwitchEnabled( bool ) ) ); + +#ifdef Q_WS_MAC + setButtonText( QWizard::BackButton, tr( "Go Back" ) ); + setButtonText( QWizard::NextButton, tr( "Continue" ) ); + setButtonText( QWizard::FinishButton, tr( "Done" ) ); +#else + setButtonText( QWizard::BackButton, tr( "Back" ) ); + setButtonText( QWizard::NextButton, tr( "Next" ) ); + setButtonText( QWizard::FinishButton, tr( "Finish" ) ); +#endif + setButtonText( QWizard::CancelButton, tr( "Cancel" ) ); + + dynamic_cast< QPushButton* >( button( QWizard::NextButton ) )->setDefault( true ); + +#ifdef Q_WS_MAC + resize( sizeHint() * 1.25 ); +#else + resize( sizeHint() ); +#endif +} + +Gui::~Gui() +{ + delete d; +} + +void Gui::setAutomatedPageSwitchEnabled( bool request ) +{ + d->autoSwitchPage = request; +} + + +void Gui::clickButton( int wb, int delay ) +{ + if ( QAbstractButton* b = button( static_cast<QWizard::WizardButton>( wb ) ) ) + QTimer::singleShot( delay, b, SLOT(click()) ); + else { + //TODO we should probably abort immediately here (faulty test script) + verbose() << "Button " << wb << " not found!" << std::endl; + } +} + +/*! + * Loads a script to perform the installation non-interactively. + * + * @throws QInstaller::Error if the script is not readable/cannot be parsed + */ +void Gui::loadControlScript( const QString& scriptPath ) +{ + QFile file( scriptPath ); + if( !file.open( QIODevice::ReadOnly ) ) + throw Error( QObject::tr( "Could not open the requested script file at %1: %2" ).arg( scriptPath, file.errorString() ) ); + + d->controlScriptEngine.globalObject().setProperty( QLatin1String( "installer" ), d->controlScriptEngine.newQObject( m_installer ) ); + d->controlScriptEngine.globalObject().setProperty( QLatin1String( "gui" ), d->controlScriptEngine.newQObject( this ) ); + registerMessageBox( &d->controlScriptEngine ); + +#undef REGISTER_BUTTON +#define REGISTER_BUTTON(x) buttons.setProperty( QLatin1String( #x ), d->controlScriptEngine.newVariant( static_cast<int>( QWizard::x ) ) ); + + QScriptValue buttons = d->controlScriptEngine.newArray(); + REGISTER_BUTTON( BackButton ) + REGISTER_BUTTON( NextButton ) + REGISTER_BUTTON( CommitButton ) + REGISTER_BUTTON( FinishButton ) + REGISTER_BUTTON( CancelButton ) + REGISTER_BUTTON( HelpButton ) + REGISTER_BUTTON( CustomButton1 ) + REGISTER_BUTTON( CustomButton2 ) + REGISTER_BUTTON( CustomButton3 ) + +#undef REGISTER_BUTTON + + d->controlScriptEngine.globalObject().setProperty( QLatin1String( "buttons" ), buttons ); + + d->controlScriptEngine.evaluate( QLatin1String( file.readAll() ), scriptPath ); + if( d->controlScriptEngine.hasUncaughtException() ) { + throw Error( QObject::tr( "Exception while loading the control script %1" ) + .arg(uncaughtExceptionString(&(d->controlScriptEngine)/*, scriptPath*/)) ); + } + + QScriptValue comp = d->controlScriptEngine.evaluate( QLatin1String( "Controller" ) ); + if( d->controlScriptEngine.hasUncaughtException() ) { + throw Error( QObject::tr( "Exception while loading the control script %1" ) + .arg(uncaughtExceptionString(&(d->controlScriptEngine)/*, scriptPath*/)) ); + } + + d->controlScript = comp; + d->controlScript.construct(); + + verbose() << "Loaded control script " << qPrintable(scriptPath) << std::endl; +} + +void Gui::triggerControlScriptForCurrentPage() +{ + slotCurrentPageChanged( currentId() ); +} + +void Gui::slotCurrentPageChanged( int id ) +{ + QMetaObject::invokeMethod( this, "delayedControlScriptExecution", Qt::QueuedConnection, Q_ARG( int, id ) ); +} + +void Gui::callControlScriptMethod( const QString& methodName ) +{ + QScriptValue method = d->controlScript.property( QLatin1String( "prototype" ) ).property( methodName ); + + if ( !method.isValid() ) { + verbose() << "Control script callback " << qPrintable(methodName) << " does not exist." << std::endl; + return; + } + + verbose() << "Calling control script callback " << qPrintable(methodName) << std::endl; + + method.call( d->controlScript ); + + if( d->controlScriptEngine.hasUncaughtException() ) + qCritical() << uncaughtExceptionString(&(d->controlScriptEngine)/*, QLatin1String("control script")*/); + //TODO handle error +} + +void Gui::delayedControlScriptExecution( int id ) +{ + Page* const p = qobject_cast<Page*>( page( id ) ); + if ( !p ) + return; + const QString methodName = p->objectName() + QLatin1String("Callback"); + callControlScriptMethod( methodName ); +} + + +IntroductionPage* Gui::introductionPage() const +{ + return m_introPage; +} + +bool Gui::event( QEvent* event ) +{ + switch( event->type() ) + { + case QEvent::LanguageChange: + emit languageChanged(); + break; + default: + break; + } + return QWizard::event( event ); +} + +void Gui::wizardPageInsertionRequested( QWidget* widget, Installer::WizardPage page ) +{ + // just in case it was already in there... + wizardPageRemovalRequested( widget ); + + // now find a suitable ID lower than page + int p = static_cast< int >( page ) - 1; + while( QWizard::page( p ) != 0 ) + --p; + // ad it + setPage( p, new DynamicInstallerPage( widget, m_installer ) ); +} + +void Gui::wizardPageRemovalRequested( QWidget* widget ) +{ + const QList< int > pages = pageIds(); + for( QList< int >::const_iterator it = pages.begin(); it != pages.end(); ++it ) + { + QWizardPage* const p = page( *it ); + DynamicInstallerPage* const dynamicPage = dynamic_cast< DynamicInstallerPage* >( p ); + if( dynamicPage == 0 ) + continue; + if( dynamicPage->widget() != widget ) + continue; + removePage( *it ); + } +} + +void Gui::wizardWidgetInsertionRequested( QWidget* widget, Installer::WizardPage page ) +{ + Q_ASSERT(widget); + QWizardPage* const p = QWizard::page( page ); + if (p) + p->layout()->addWidget( widget ); +} + +void Gui::wizardWidgetRemovalRequested( QWidget* widget ) +{ + Q_ASSERT(widget); + widget->setParent( 0 ); +} + +void Gui::wizardPageVisibilityChangeRequested( bool visible, int p ) +{ + if( visible && page( p ) == 0 ) + { + setPage( p, defaultPages[ p ] ); + } + else if( !visible && page( p ) != 0 ) + { + defaultPages[ p ] = page( p ); + removePage( p ); + } +} + +QWidget* Gui::pageWidgetByObjectName( const QString& name ) const +{ + const QList<int> ids = pageIds(); + Q_FOREACH( const int i, ids ) { + Page* const p = qobject_cast<Page*>( page( i ) ); + if ( p && p->objectName() == name ) { + // For dynamic pages, return the contained widget (as read from the UI file), not the wrapper page + if ( DynamicInstallerPage* dp = dynamic_cast<DynamicInstallerPage*>( p ) ) + return dp->widget(); + else + return p; + } + } + verbose() << "No page found for object name " << name << std::endl; + return 0; +} + +QWidget* Gui::currentPageWidget() const +{ + return currentPage(); +} + +void Gui::cancelButtonClicked() +{ + const bool doIgnore = m_installer->isInstaller() + ? m_installer->status() == Installer::InstallerCanceledByUser || m_installer->status() == Installer::InstallerSucceeded + : m_installer->status() == Installer::InstallerCanceledByUser; + + //if the user canceled (all modes) or the installation is finished (installer mode only), ignore + //clicks on cancel. + if ( doIgnore ) + return; + + //close the manager without asking if nothing was modified, always ask for the installer + if ( !m_installer->isInstaller() && !d->modified ) { + QDialog::reject(); + return; + } + + Page* const page = qobject_cast< Page* >( currentPage() ); + verbose() << "CANCEL CLICKED" << currentPage() << page << std::endl; + if (page && page->isInterruptible()) { + const QMessageBox::StandardButton bt = MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("cancelInstallation"), + tr("Warning"), + tr("Do you want to abort the %1 process?").arg( m_installer->isUninstaller() ? tr( "uninstallation" ) : tr( "installation" ) ), + QMessageBox::Yes | QMessageBox::No); + if (bt == QMessageBox::Yes) + emit interrupted(); + } else { + const QMessageBox::StandardButton bt = MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("cancelInstallation"), + tr("Warning"), + tr("Do you want to abort the %1 application?").arg( m_installer->isUninstaller() ? tr( "uninstaller" ) : tr( "installer" ) ), + QMessageBox::Yes | QMessageBox::No); + if (bt == QMessageBox::Yes) + QDialog::reject(); + } +} + +void Gui::rejectWithoutPrompt() +{ + m_installer->setCanceled(); + QDialog::reject(); +} + +void Gui::reject() +{ + cancelButtonClicked(); +} +void Gui::setModified( bool value ) +{ + d->modified = value; +} + +void Gui::showFinishedPage() +{ + verbose() << "SHOW FINISHED PAGE" << std::endl; + if (d->autoSwitchPage){ + next(); + }else{ + dynamic_cast< QPushButton* >( button( QWizard::CancelButton ) )->setEnabled( false ); + } +} + +//////////////////////////////////////////////////////////////////// +// +// Page +// +//////////////////////////////////////////////////////////////////// + +Page::Page(Installer *installer) + : m_installer(installer), m_fresh(true), m_complete(true) +{ + setSubTitle( QLatin1String( " " ) ); // otherwise the colors will screw up +} + +Installer *Page::installer() const +{ + return m_installer; +} + +QPixmap Page::watermarkPixmap() const +{ + return QPixmap(m_installer->value( QLatin1String( "WatermarkPixmap" ) ) ); +} + +QPixmap Page::logoPixmap() const +{ + return QPixmap(m_installer->value( QLatin1String( "LogoPixmap" ) ) ); +} + +QString Page::productName() const +{ + return m_installer->value( QLatin1String( "ProductName" ) ); +} + +bool Page::isComplete() const +{ + return m_complete; +} + +void Page::setComplete(bool complete) +{ + m_complete = complete; + emit completeChanged(); + if( wizard() == 0 ) + return; + if( wizard()->button( QWizard::CancelButton ) == 0 ) + return; + if( wizard()->button( QWizard::NextButton ) == 0 ) + return; + if( wizard()->button( QWizard::CancelButton )->hasFocus() ) + wizard()->button( QWizard::NextButton )->setFocus(); +} + +void Page::insertWidget(QWidget *widget, const QString &siblingName, + int offset) +{ + QWidget *sibling = findChild<QWidget *>(siblingName); + QWidget *parent = sibling ? sibling->parentWidget() : 0; + QLayout *layout = parent ? parent->layout() : 0; + QBoxLayout *blayout = qobject_cast<QBoxLayout *>(layout); + //qDebug() << "FOUND: " << sibling << parent << layout << blayout; + if (blayout) { + int index = blayout->indexOf(sibling) + offset; + blayout->insertWidget(index, widget); + } +} + +QWidget *Page::findWidget(const QString &objectName) const +{ + return findChild<QWidget *>(objectName); +} + +void Page::setVisible(bool visible) +{ + QWizardPage::setVisible(visible); + qApp->processEvents(); + //qDebug() << "VISIBLE: " << visible << objectName() << installer(); + if (m_fresh && !visible) { + //qDebug() << "SUPRESSED..."; + m_fresh = false; + return; + } + if (visible) + entering(); + else + leaving(); +} + +int Page::nextId() const +{ + //qDebug() << "NEXTID"; + return QWizardPage::nextId(); +} + +//////////////////////////////////////////////////////////////////// +// +// QInstallerIntroductionPage +// +//////////////////////////////////////////////////////////////////// + +IntroductionPage::IntroductionPage(Installer *inst) + : Page(inst), m_widget(0) +{ + setObjectName( QLatin1String( "IntroductionPage" ) ); + setTitle(tr("Setup - %1").arg(productName())); + setPixmap(QWizard::WatermarkPixmap, watermarkPixmap()); + setSubTitle(QString()); + + m_msgLabel = new QLabel(this); + m_msgLabel->setObjectName( QLatin1String( "MessageLabel" ) ); + m_msgLabel->setWordWrap(true); + m_msgLabel->setText(tr("Welcome to the %1 Setup Wizard.") + .arg(productName())); + + QVBoxLayout *layout = new QVBoxLayout( this ); + setLayout(layout); + layout->addWidget( m_msgLabel ); +} + +void IntroductionPage::setText(const QString &text) +{ + m_msgLabel->setText(text); +} + +void IntroductionPage::setWidget(QWidget *w) +{ + if(m_widget) { + layout()->removeWidget(m_widget); + delete m_widget; + } + m_widget = w; + if(m_widget) { + static_cast<QVBoxLayout*>(layout())->addWidget(m_widget, 1); + } +} + +//////////////////////////////////////////////////////////////////// +// +// LicenseAgreementPage +// +//////////////////////////////////////////////////////////////////// + +LicenseAgreementPage::LicenseAgreementPage(Installer *inst) + : Page(inst) +{ + setTitle(tr("License Agreement")); + setPixmap(QWizard::LogoPixmap, logoPixmap()); + setPixmap(QWizard::WatermarkPixmap, QPixmap()); + setObjectName(QLatin1String("LicenseAgreementPage")); + + QLabel *msgLabel = new QLabel(tr("Please read the following license agreement(s). You must " + "accept the terms contained in these agreement(s) before continuing with the installation.")); + msgLabel->setWordWrap(true); + + QGroupBox *licenseBox = new QGroupBox(this); + licenseBox->setObjectName(QString::fromUtf8("licenseBox")); + + m_licenseListWidget = new QListWidget(licenseBox); + connect(m_licenseListWidget, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), + this, SLOT(currentItemChanged(QListWidgetItem *))); + + QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); + sizePolicy.setHeightForWidth(m_licenseListWidget->sizePolicy().hasHeightForWidth()); + m_licenseListWidget->setSizePolicy(sizePolicy); + + m_textBrowser = new QTextBrowser(licenseBox); + m_textBrowser->setReadOnly(true); + m_textBrowser->setOpenExternalLinks(true); + m_textBrowser->setOpenLinks(false); + connect(m_textBrowser, SIGNAL(anchorClicked(QUrl)), this, SLOT(openLicenseUrl(QUrl))); + + QSizePolicy sizePolicy2(QSizePolicy::Minimum, QSizePolicy::Expanding); + sizePolicy2.setHeightForWidth(m_textBrowser->sizePolicy().hasHeightForWidth()); + m_textBrowser->setSizePolicy(sizePolicy2); + + QHBoxLayout *licenseBoxLayout = new QHBoxLayout(licenseBox); + licenseBoxLayout->addWidget(m_licenseListWidget); + licenseBoxLayout->addWidget(m_textBrowser); + + m_acceptRadioButton = new QRadioButton(this); + QLabel *acceptLabel = new QLabel(tr("I have read and agree to the following terms contained in " + "the license agreements accompanying the Qt SDK and additional items. I agree that my use of " + "the Qt SDK is governed by the terms and conditions contained in these license agreements.")); + acceptLabel->setWordWrap(true); + + m_rejectRadioButton = new QRadioButton(this); + QLabel *rejectLabel = new QLabel(tr("I do not accept the terms and conditions of the above " + "listed license agreements. Please note by checking the box, you must cancel the " + "installation or downloading the Qt SDK and must destroy all copies, or portions thereof, " + "of the Qt SDK in your possessions.")); + rejectLabel->setWordWrap(true); + + QSizePolicy sizePolicy3(QSizePolicy::Preferred, QSizePolicy::Minimum); + sizePolicy3.setHeightForWidth(rejectLabel->sizePolicy().hasHeightForWidth()); + sizePolicy3.setVerticalStretch(0); + sizePolicy3.setHorizontalStretch(0); + + acceptLabel->setSizePolicy(sizePolicy3); + rejectLabel->setSizePolicy(sizePolicy3); + +#if defined(Q_WS_X11) || defined(Q_WS_MAC) + QFont labelFont(font()); + labelFont.setPixelSize(9); + + msgLabel->setFont(labelFont); + acceptLabel->setFont(labelFont); + rejectLabel->setFont(labelFont); +#endif + + QGridLayout *gridLayout = new QGridLayout; + gridLayout->setColumnStretch(1, 1); + gridLayout->addWidget(m_acceptRadioButton, 0, 0); + gridLayout->addWidget(acceptLabel, 0, 1); + gridLayout->addWidget(m_rejectRadioButton, 1, 0); + gridLayout->addWidget(rejectLabel, 1, 1); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addWidget(msgLabel); + layout->addWidget(licenseBox); + layout->addLayout(gridLayout); + + connect(m_acceptRadioButton, SIGNAL(toggled(bool)), this, + SIGNAL(completeChanged())); + connect(m_rejectRadioButton, SIGNAL(toggled(bool)), this, + SIGNAL(completeChanged())); + + m_rejectRadioButton->setChecked(true); +} + +void LicenseAgreementPage::initializePage() +{ + m_licenseListWidget->clear(); + m_textBrowser->setText(QLatin1String("")); + + // TODO: this needs to be fixed once we support several root components + QInstaller::Component *rootComponent = 0; + foreach (QInstaller::Component* root, installer()->components()) { + if (root->isInstalled()) + continue; + + const QHash<QString, QPair<QString, QString> > &hash = root->licenses(); + if (!hash.isEmpty()) { + addLicenseItem(hash); + rootComponent = root; + } + } + + QList<QInstaller::Component*> components = installer()->componentsToInstall(true); + foreach (QInstaller::Component* component, components) { + if (rootComponent != component && !component->isInstalled()) + addLicenseItem(component->licenses()); + } + + if (m_licenseListWidget->count() > 0) + m_licenseListWidget->setCurrentItem(m_licenseListWidget->item(0)); +} + +bool LicenseAgreementPage::isComplete() const +{ + return m_acceptRadioButton->isChecked(); +} + +void LicenseAgreementPage::openLicenseUrl(const QUrl &url) +{ + QDesktopServices::openUrl(url); +} + +void LicenseAgreementPage::currentItemChanged(QListWidgetItem *current) +{ + if (current) + m_textBrowser->setText(current->data(Qt::UserRole).toString()); +} + +void LicenseAgreementPage::addLicenseItem(const QHash<QString, QPair<QString, QString> > &hash) +{ + for (QHash<QString, QPair<QString, QString> >::const_iterator it = hash.begin(); + it != hash.end(); ++it) { + QListWidgetItem *item = new QListWidgetItem(it.key(), m_licenseListWidget); + item->setData(Qt::UserRole, it.value().second); + } +} + +//////////////////////////////////////////////////////////////////// +// +// ComponentSelectionPage +// +//////////////////////////////////////////////////////////////////// + +inline QString unitSizeText(const qint64 size) { + if (size < 10000) + return QString::number(size) + QLatin1Char(' ') + ComponentSelectionPage::tr("Bytes"); + if (size < 1024 * 10000) + return QString::number(size / 1024) + QLatin1Char(' ') + ComponentSelectionPage::tr("kBytes"); + return QString::number(size / 1024 / 1024) + QLatin1Char(' ') + ComponentSelectionPage::tr("MBytes"); +} + +static QString niceSizeText(const QString &str) +{ + const qint64 size = str.toLongLong(); + if( size == 0 ) + return QString(); + + QString msg = ComponentSelectionPage::tr( + "This component will occupy approximately %1 on your harddisk."); + return msg.arg(unitSizeText(size)); +} + +class ComponentSelectionPage::Private : public QObject +{ + Q_OBJECT + +public: + Private(ComponentSelectionPage *qq, Installer *installer) + : q( qq ), + wasshown( false ), + modified( false ), + connected( false ), + m_model( new ComponentModel( installer ) ), + m_installer( installer ), + m_treeView( new QTreeView( q ) ) + { + m_treeView->setObjectName( QLatin1String( "TreeView" ) ); + m_treeView->setMouseTracking(true); + m_treeView->setHeaderHidden( true ); + + m_treeView->setModel( m_model ); + for( int i = 1; i < m_treeView->model()->columnCount(); ++i ) + m_treeView->setColumnHidden( i, true ); + + m_descriptionLabel = new QLabel(q); + m_descriptionLabel->setWordWrap(true); + + m_sizeLabel = new QLabel(q); + m_sizeLabel->setWordWrap(true); + + QVBoxLayout *layout = new QVBoxLayout( q ); + if( !installer->isInstaller() ) + { + QRadioButton* const uninstallAll = new QRadioButton( tr( "Remove all components" ) ); + uninstallAll->setObjectName( QLatin1String("uninstallAllComponentsRB") ); + QRadioButton* const keepChecked = new QRadioButton( installer->isUninstaller() ? tr( "Keep selected components" ) : tr( "Install selected components" ) ); + keepChecked->setObjectName( QLatin1String("keepSelectedComponentsRB") ); + layout->addWidget( uninstallAll ); + layout->addWidget( keepChecked ); + connect( uninstallAll, SIGNAL( toggled( bool ) ), m_treeView, SLOT( setDisabled( bool ) ) ); + connect( uninstallAll, SIGNAL( toggled( bool ) ), m_descriptionLabel, SLOT( setDisabled( bool ) ) ); + connect( uninstallAll, SIGNAL( toggled( bool ) ), m_installer, SLOT( setCompleteUninstallation( bool ) ) ); + connect( uninstallAll, SIGNAL( toggled( bool ) ), q, SIGNAL( completeChanged() ), Qt::QueuedConnection ); + connect( uninstallAll, SIGNAL( toggled( bool ) ), this, SLOT( fullUninstallToggled( bool ) ), Qt::QueuedConnection ); + uninstallAll->setChecked( installer->isUninstaller() ); + keepChecked->setChecked( installer->isPackageManager() ); + m_installer->setCompleteUninstallation( installer->isUninstaller() ); + } + //layout->addWidget(msgLabel); + QHBoxLayout *hlayout = new QHBoxLayout; + hlayout->addWidget(m_treeView, 3); + QVBoxLayout *vlayout = new QVBoxLayout; + vlayout->addWidget(m_descriptionLabel); + vlayout->addWidget(m_sizeLabel); + vlayout->addSpacerItem(new QSpacerItem(1, 1, + QSizePolicy::MinimumExpanding, + QSizePolicy::MinimumExpanding)); + hlayout->addLayout(vlayout, 2); + layout->addLayout(hlayout); + + connect( m_treeView->selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), + this, SLOT( selectionChanged() ) ); + + connect( m_treeView->model(), SIGNAL( dataChanged( QModelIndex, QModelIndex ) ), + q, SIGNAL( completeChanged() ), Qt::QueuedConnection ); + } + +protected Q_SLOTS: + void selectionChanged() + { + const QModelIndex index = m_treeView->currentIndex(); + if( !index.isValid() ) + { + m_descriptionLabel->clear(); + m_sizeLabel->clear(); + return; + } + + m_descriptionLabel->setText( index.data( Qt::ToolTipRole ).toString() ); + if( !m_installer->isUninstaller() ) + m_sizeLabel->setText( niceSizeText( qVariantValue< Component* >( index.data( Qt::UserRole ) )->value( QString::fromLatin1( "UncompressedSize" ) ) ) ); + } + void fullUninstallToggled( bool value ) + { + if ( value ) + { + emit workRequested( value ); + q->setModified( value ); + } + else + { + const QModelIndex index = m_model->index( 0, 0 ); + const QVariant data = m_model->data( index, Qt::CheckStateRole ); + m_model->setData( index, data, Qt::CheckStateRole ); + } + } + +Q_SIGNALS: + void workRequested( bool ); + +public: + ComponentSelectionPage* const q; + + bool wasshown; + bool modified; + bool connected; + ComponentModel* const m_model; + Installer* const m_installer; + QTreeView* const m_treeView; + QLabel *m_descriptionLabel; + QLabel *m_sizeLabel; +}; + +void ComponentSelectionPage::entering() +{ + wizard()->button( QWizard::CancelButton )->setEnabled( true ); + if( !d->connected ) + { + Gui* par = dynamic_cast< Gui* > ( wizard() ); + if ( par ) + { + verbose() << "connect Models" << std::endl; + connect( d->m_model, SIGNAL( workRequested( bool ) ), par, SLOT( setModified( bool ) ), Qt::QueuedConnection ); + connect( d->m_model, SIGNAL( workRequested( bool ) ), this, SLOT( setModified( bool ) ), Qt::QueuedConnection ); + connect( d.get(), SIGNAL( workRequested( bool) ), par, SLOT( setModified( bool ) ), Qt::QueuedConnection ); + connect( d->m_model, SIGNAL( modelReset() ), this, SLOT( modelWasReseted() ), Qt::QueuedConnection ); + d->connected = true; + } + if ( !d->m_installer->isInstaller() ) + setButtonText( QWizard::CancelButton, tr( "Close" ) ); + } +} + +/*! + \class QInstaller::ComponentSelectionPage + On this page the user can select and deselect what he wants to be installed. + */ +ComponentSelectionPage::ComponentSelectionPage( Installer* installer ) + : Page( installer ), + d( new Private( this, installer ) ) +{ + setObjectName( QLatin1String( "ComponentSelectionPage" ) ); + if( !installer->isUninstaller() ) + { + setTitle( tr( "Select Components" ) ); + setSubTitle( tr( "Please select the components you want to install." ) ); + } + else + { + setTitle( tr( "Select Components" ) ); + setSubTitle( tr( "Please select the components you want to uninstall." ) ); + } + setPixmap( QWizard::LogoPixmap, logoPixmap() ); + setPixmap( QWizard::WatermarkPixmap, QPixmap() ); +} + +ComponentSelectionPage::~ComponentSelectionPage() +{ +} + +void ComponentSelectionPage::modelWasReseted() +{ + if( d->m_treeView->model()->rowCount() == 1 ) + { + d->m_treeView->setExpanded( d->m_treeView->model()->index( 0, 0 ), true ); + d->wasshown = true; + } +} + +void ComponentSelectionPage::showEvent( QShowEvent* event ) +{ + if( !d->wasshown && d->m_treeView->model()->rowCount() == 1 ) + { + d->m_treeView->setExpanded( d->m_treeView->model()->index( 0, 0 ), true ); + d->wasshown = true; + } + Page::showEvent( event ); +} + + +/*! + Selects the component with /a id in the component tree. + */ +void ComponentSelectionPage::selectComponent( const QString& id ) { + const QModelIndex idx = d->m_model->findComponent( id ); + if ( !idx.isValid() ) + return; + d->m_model->setData( idx, Qt::Checked ); +} + +/*! + Deselects the component with /a id in the component tree. + */ +void ComponentSelectionPage::deselectComponent( const QString& id ) { + const QModelIndex idx = d->m_model->findComponent( id ); + if ( !idx.isValid() ) + return; + d->m_model->setData( idx, Qt::Unchecked ); +} + +void ComponentSelectionPage::setModified( bool value ) +{ + d->modified = value; + if (d->m_installer->isInstaller() || value) + setButtonText( QWizard::CancelButton, tr( "Cancel" ) ); + else + setButtonText( QWizard::CancelButton, tr( "Close" ) ); +} + +bool ComponentSelectionPage::isComplete() const +{ + // uninstall all + if( !d->m_treeView->isEnabled() ) + return true; + + if( d->m_installer->isPackageManager() ) + { + // at least component should be different from its previous state + if ( d->modified ) + return true; + else + return false; + } + // at least one component needs to be selected for (un)installation + const QList< Component* > components = d->m_installer->components( true ); + for( QList< Component* >::const_iterator it = components.begin(); it != components.end(); ++it ) + { + if( (*it)->isSelected() == d->m_installer->isInstaller() ) + return true; + } + return false; +} + +//////////////////////////////////////////////////////////////////// +// +// TargetDirectoryPage +// +//////////////////////////////////////////////////////////////////// + +TargetDirectoryPage::TargetDirectoryPage(Installer *installer) + : Page(installer) +{ + setObjectName( QLatin1String( "TargetDirectoryPage" ) ); + setTitle(tr("Installation Folder")); + setPixmap(QWizard::LogoPixmap, logoPixmap()); + setPixmap(QWizard::WatermarkPixmap, QPixmap()); + + QLabel *msgLabel = new QLabel(this); + msgLabel->setText(tr("Please specify the folder where %1 " + "will be installed.").arg(productName())); + msgLabel->setWordWrap(true); + msgLabel->setObjectName( QLatin1String( "MessageLabel" ) ); + + m_lineEdit = new QLineEdit(this); + m_lineEdit->setObjectName( QLatin1String("targetDirectoryLE") ); + + QPushButton *browseButton = new QPushButton(this); + browseButton->setObjectName( QLatin1String( "BrowseButton" ) ); + browseButton->setText( tr( "Browse..." ) ); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addWidget(msgLabel); + QHBoxLayout *hlayout = new QHBoxLayout; + hlayout->addWidget(m_lineEdit); + hlayout->addWidget(browseButton); + layout->addLayout(hlayout); + setLayout(layout); + + connect(browseButton, SIGNAL(clicked()), this, SLOT(dirRequested())); + connect(m_lineEdit, SIGNAL(textChanged(QString)), this, + SIGNAL(completeChanged())); +} + +QString TargetDirectoryPage::targetDir() const +{ + return m_lineEdit->text(); +} + +void TargetDirectoryPage::setTargetDir(const QString &dirName) +{ + m_lineEdit->setText(dirName); +} + +void TargetDirectoryPage::initializePage() +{ + QString targetDir = installer()->value( QLatin1String( "TargetDir" ) ); + if( targetDir.isEmpty() ) + { + targetDir = QDir::homePath() + QDir::separator(); + if( targetDir.contains( QLatin1Char( ' ' ) ) ) // prevent spaces in the default target directory + targetDir = QDir::rootPath(); + targetDir += productName().remove( QLatin1Char( ' ' ) ); + } + m_lineEdit->setText( QDir::toNativeSeparators( QDir( targetDir ).absolutePath() ) ); + + Page::initializePage(); +} + +bool TargetDirectoryPage::validatePage() +{ + const QDir dir( targetDir() ); + + if( dir.exists() && dir.entryList( QDir::NoDotAndDotDot ).isEmpty() ) // it exists, but is empty (might be created by the Browse button (getExistingDirectory) + { + return true; + } + else if( dir.exists() && dir.isReadable() ) // it exists, but is not empty + { + if ( dir == QDir::root() ) + { + MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("forbiddenTargetDirectory"), tr( "Error" ), + tr( "As the install directory is completely deleted installing in %1 is forbidden" ).arg( QDir::rootPath() ), + QMessageBox::Ok); + return false; + } + + return MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("overwriteTargetDirectory"), tr( "Warning" ), + tr( "You have selected an existing, non-empty folder for installation.\n" + "Note that it will be completely wiped on uninstallation of this application.\n" + "It is not advisable to install into this folder as installation might fail.\n" + "Do you want to continue?" ), + QMessageBox::Yes | QMessageBox::No ) == QMessageBox::Yes; + } + else + { + return true; + } +} + +void TargetDirectoryPage::entering() +{ +} + +void TargetDirectoryPage::leaving() +{ + installer()->setValue( QLatin1String( "TargetDir" ), targetDir()); +} + +void TargetDirectoryPage::targetDirSelected() +{ +} + +void TargetDirectoryPage::dirRequested() +{ + //qDebug() << "DIR REQUESTED"; + QString newDirName = QFileDialog::getExistingDirectory(this, + tr("Select Installation Folder"), targetDir() + /*, Options options = ShowDirsOnly*/); + if (newDirName.isEmpty() || newDirName == targetDir()) + return; + m_lineEdit->setText( QDir::toNativeSeparators( newDirName ) ); +} + + +// #pragma mark -- StartMenuDirectoryPage + + +StartMenuDirectoryPage::StartMenuDirectoryPage(Installer *installer) + : Page(installer) +{ + setObjectName( QLatin1String( "StartMenuDirectoryPage" ) ); + setTitle(tr("Start Menu shortcuts")); + + setPixmap(QWizard::LogoPixmap, logoPixmap()); + setPixmap(QWizard::WatermarkPixmap, QPixmap()); + + QString msg = tr("Select the Start Menu in which you would like to " + "create the program's shortcuts. You can also enter a name to " + "create a new folder."); + + QLabel *msgLabel = new QLabel(this); + msgLabel->setText(msg); + msgLabel->setWordWrap(true); + msgLabel->setObjectName( QLatin1String( "MessageLabel" ) ); + + m_lineEdit = new QLineEdit(this); + m_lineEdit->setObjectName( QLatin1String( "LineEdit" ) ); + + QString startMenuDir = installer->value( QLatin1String( "StartMenuDir" ) ); + if (startMenuDir.isEmpty()) + startMenuDir = productName(); + m_lineEdit->setText(startMenuDir); + + // grab existing start menu folders + QSettings user(QLatin1String("HKEY_CURRENT_USER\\Software\\Microsoft\\" + "Windows\\CurrentVersion\\Explorer\\User Shell Folders"), + QSettings::NativeFormat); + //User Shell Folders uses %USERPROFILE% + startMenuPath = replaceWindowsEnvironmentVariables( user.value(QLatin1String("Programs"), QString()).toString() ); + installer->setValue( QLatin1String( "DesktopDir" ), replaceWindowsEnvironmentVariables( user.value( QLatin1String( "Desktop" ) ).toString() ) ); + + QDir dir(startMenuPath); // user only dirs + QStringList dirs = dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); + + if (installer->value(QLatin1String("AllUsers")) == QLatin1String( "true" ) ) { + verbose() << "AllUsers set. Using HKEY_LOCAL_MACHINE" << std::endl; + QSettings system(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\" + "Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"), + QSettings::NativeFormat); + startMenuPath = system.value(QLatin1String("Common Programs"), + QString()).toString(); + installer->setValue( QLatin1String( "DesktopDir" ), system.value( QLatin1String( "Desktop" ) ).toString() ); + + dir.setPath(startMenuPath); // system only dirs + dirs += dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); + } + verbose() << "StartMenuPath: " << startMenuPath; + verbose() << "DesktopDir:" << installer->value( QLatin1String("DesktopDir") ) << std::endl; + + m_listWidget = new QListWidget(this); + if (!dirs.isEmpty()) { + dirs.removeDuplicates(); + foreach (const QString &dir, dirs) + new QListWidgetItem(dir, m_listWidget); + } + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addWidget(msgLabel); + layout->addWidget(m_lineEdit); + layout->addWidget(m_listWidget); + + setLayout(layout); + + connect(m_listWidget, SIGNAL(currentItemChanged(QListWidgetItem*, + QListWidgetItem*)), this, SLOT(currentItemChanged(QListWidgetItem*))); +} + +QString +StartMenuDirectoryPage::startMenuDir() const +{ + return m_lineEdit->text(); +} + +void +StartMenuDirectoryPage::setStartMenuDir(const QString &startMenuDir) +{ + m_lineEdit->setText(startMenuDir); +} + +void +StartMenuDirectoryPage::leaving() +{ + installer()->setValue( QLatin1String( "StartMenuDir" ), startMenuPath + QDir::separator() + startMenuDir()); +} + +void +StartMenuDirectoryPage::currentItemChanged(QListWidgetItem* current) +{ + if (current) { + QString dir = current->data(Qt::DisplayRole).toString(); + if (!dir.isEmpty()) + dir += QDir::separator(); + setStartMenuDir(dir + installer()->value( QLatin1String( "StartMenuDir" ) ) ); + } +} + + +//////////////////////////////////////////////////////////////////// +// +// ReadyForInstallationPage +// +//////////////////////////////////////////////////////////////////// + +ReadyForInstallationPage::ReadyForInstallationPage( Installer* installer ) + : Page(installer), + msgLabel( new QLabel ) +{ + setPixmap(QWizard::LogoPixmap, logoPixmap()); + setPixmap(QWizard::WatermarkPixmap, QPixmap()); + + setObjectName( QLatin1String( "ReadyForInstallationPage" ) ); + + msgLabel->setWordWrap( true ); + msgLabel->setObjectName( QLatin1String( "MessageLabel" ) ); + + QLayout *layout = new QVBoxLayout(this); + layout->addWidget(msgLabel); + setLayout(layout); +} + +/*! + \reimp + */ +void ReadyForInstallationPage::initializePage() +{ + setCommitPage( true ); + + if( installer()->isUninstaller() ) + { + setTitle(tr("Ready to Uninstall")); + setButtonText(QWizard::CommitButton, tr("Uninstall")); + msgLabel->setText( tr( "Setup is now ready to begin removing %1 " + "from your computer.\n" + "The program dir %2 will be deleted completely, including " + "all content in that directory!").arg( productName(), + QDir::toNativeSeparators( QDir( installer()->value( QLatin1String( "TargetDir" ) ) ).absolutePath() ) ) ); + } + else if( installer()->isPackageManager() ) + { + setTitle( tr( "Ready to Update Packages" ) ); + setButtonText( QWizard::CommitButton, tr( "Update" ) ); + msgLabel->setText( tr( "Setup is now ready to begin installing the additional components you selected." ) ); + } + else + { + Q_ASSERT(installer()->isInstaller()); + setTitle(tr("Ready to Install")); + setButtonText(QWizard::CommitButton, tr("Install")); + msgLabel->setText(tr("Setup is now ready to begin installing %1 " + "on your computer.").arg(productName())); + } + } + + +/*! + \reimp + */ +void ReadyForInstallationPage::entering() +{ + initializePage(); + + if( installer()->isUninstaller() ) + return; + + const QString target = installer()->value( QLatin1String( "TargetDir" ) ); + + const KDSysInfo::Volume vol = KDSysInfo::Volume::fromPath( target ); + const KDSysInfo::Volume tempVolume = KDSysInfo::Volume::fromPath( QInstaller::generateTemporaryFileName() ); + const bool tempOnSameVolume = vol == tempVolume; + + if ( vol.size().size() == 0 && vol.availableSpace().size() == 0 ) { //there is no better way atm to check this + verbose() << "Could not determine available space on device " << target << ". Continue silently." << std::endl; + return; + } + + const KDByteSize required( installer()->requiredDiskSpace() ); + const KDByteSize tempRequired( installer()->requiredTemporaryDiskSpace() ); + + const KDByteSize available = vol.availableSpace(); + const KDByteSize tempAvailable = tempVolume.availableSpace(); + const KDByteSize realRequiredTempSpace = KDByteSize( 0.1 * tempRequired + tempRequired ); + const KDByteSize realRequiredSpace = KDByteSize( 0.5 * required + required ); + + const bool tempInstFailure = tempOnSameVolume && available < realRequiredSpace + realRequiredTempSpace; + + verbose() << "Disk space check on " << target << ": required=" << required.size() << " available=" << available.size() << " size=" << vol.size().size() << std::endl; + + QString tempString; + if ( tempAvailable < realRequiredTempSpace || tempInstFailure ) + { + if ( tempOnSameVolume ) + { + tempString = tr( "Not enough diskspace to store temporary files and the installation, at least %1 are required" ).arg( unitSizeText(realRequiredTempSpace + realRequiredSpace) ); + } + else + { + tempString = tr( "Not enough diskspace to store temporary files, at least %1 are required" ).arg( unitSizeText(realRequiredTempSpace.size()) ); + } + } + + // error on not enough space + if( available < required || tempInstFailure ) + { + if ( tempOnSameVolume ) + msgLabel->setText( tempString ); + else + msgLabel->setText( tr( "The volume you selected for installation has insufficient space for the selected components.\n\n" + "The installation requires approximately %1." ).arg( required.toString() ) + tempString ); + setCommitPage( false ); + } + // warn for less than 1% of the volume's space being free + else if( available - required < 0.01 * vol.size() ) + { + msgLabel->setText( tr( "The volume you selected for installation seems to have sufficient space for installation,\n" + "but there will not more than 1% of the volume's space available afterwards.\n\n%1" ).arg( msgLabel->text() ) ); + } + // warn for less than 100MB being free + else if( available - required < 100*1024*1024LL ) + { + msgLabel->setText( tr( "The volume you selected for installation seems to have sufficient space for installation,\n" + "but there will not more than 100 MB available afterwards.\n\n%1" ).arg( msgLabel->text() ) ); + } +} + +/*! + \reimp + */ +bool ReadyForInstallationPage::isComplete() const +{ + return isCommitPage(); +} + +/*! + \class QInstaller::PerformInstallationPage + On this page the user can see on a progressbar how far the current installation is. + */ +PerformInstallationPage::PerformInstallationPage(Installer *gui) + : Page(gui), + m_performInstallationForm(new PerformInstallationForm(this)) +{ + setPixmap(QWizard::LogoPixmap, logoPixmap()); + setPixmap(QWizard::WatermarkPixmap, QPixmap()); + + setObjectName( QLatin1String( "PerformInstallationPage" ) ); + setCommitPage(true); + + m_performInstallationForm->setupUi(this); + + m_performInstallationForm->setDetailsWidgetVisible( installer()->isInstaller() || installer()->isPackageManager() ); + connect(ProgressCoordninator::instance(), SIGNAL( detailTextChanged( QString ) ), + m_performInstallationForm, SLOT( appendProgressDetails( QString ) ) ); + connect(ProgressCoordninator::instance(), SIGNAL(detailTextResetNeeded()), + m_performInstallationForm, SLOT(clearDetailsBrowser())); + + connect(m_performInstallationForm, SIGNAL(showDetailsChanged()), + this, SLOT(toggleDetailsWereChanged())); + + connect(installer(), SIGNAL(installationStarted()), + this, SLOT(installationStarted())); + connect(installer(), SIGNAL(uninstallationStarted()), + this, SLOT(installationStarted())); + connect(installer(), SIGNAL(installationFinished()), + this, SLOT(installationFinished())); + connect(installer(), SIGNAL(uninstallationFinished()), + this, SLOT(installationFinished())); + connect( installer(), SIGNAL( titleMessageChanged( QString ) ), + this, SLOT( setTitleMessage( QString ) ) ); + connect( this, SIGNAL( setAutomatedPageSwitchEnabled( bool ) ), + installer(), SIGNAL( setAutomatedPageSwitchEnabled( bool ) ) ); +} + +PerformInstallationPage::~PerformInstallationPage() +{ + delete m_performInstallationForm; +} + +void PerformInstallationPage::entering() +{ + setComplete(false); + + if( installer()->isUninstaller() ) + { + setTitle(tr("Uninstalling %1").arg(installer()->value( QLatin1String( "ProductName" ) ))); + setButtonText(QWizard::CommitButton, tr("Uninstall")); + } + else if( installer()->isPackageManager() ) + { + setTitle( tr( "Updating component configuration of %1" ).arg( installer()->value( QLatin1String( "ProductName" ) ) ) ); + setButtonText( QWizard::CommitButton, tr( "Update" ) ); + } + else + { + Q_ASSERT(installer()->isInstaller()); + setTitle(tr("Installing %1").arg(installer()->value( QLatin1String( "ProductName" ) ))); + setButtonText(QWizard::CommitButton, tr("Install")); + } + m_performInstallationForm->enableDetails(); + emit setAutomatedPageSwitchEnabled( true ); +} + +void PerformInstallationPage::initializePage() +{ + QWizardPage::initializePage(); + if( installer()->isUninstaller() ) + { + wizard()->removePage( QInstaller::Installer::InstallationFinished + 1 ); + wizard()->removePage( QInstaller::Installer::InstallationFinished + 2 ); + setTitle( tr( "Uninstalling %1" ).arg( installer()->value( QLatin1String( "ProductName" ) ) ) ); + m_commitBtnText = tr( "Uninstall" ); + setButtonText( QWizard::CommitButton, m_commitBtnText ); + QTimer::singleShot( 30, installer(), SLOT( runUninstaller() ) ); + } + else if( installer()->isPackageManager() ) + { + setTitle(tr("Updating components of %1").arg( installer()->value( QLatin1String( "ProductName" ) ))); + m_commitBtnText = tr ( "Update" ); + setButtonText( QWizard::CommitButton, m_commitBtnText ); + QTimer::singleShot( 30, installer(), SLOT( runPackageUpdater() ) ); + } + else + { + Q_ASSERT( installer()->isInstaller() ); + setTitle( tr( "Installing %1" ).arg( installer()->value( QLatin1String( "ProductName" ) ) ) ); + m_commitBtnText = tr( "Install" ); + setButtonText( QWizard::CommitButton, m_commitBtnText ); + QTimer::singleShot( 30, installer(), SLOT( runInstaller() ) ); + } +} + +void PerformInstallationPage::installationStarted() +{ + m_performInstallationForm->startUpdateProgress(); +} + +void PerformInstallationPage::installationFinished() +{ + m_performInstallationForm->stopUpdateProgress(); + if (!isAutoSwitching()){ + m_performInstallationForm->scrollDetailsToTheEnd(); + m_performInstallationForm->setDetailsButtonEnabled( false ); + setButtonText( QWizard::NextButton, tr( "Next" ) ); + setButtonText( QWizard::CommitButton, tr( "Next" ) ); + setComplete( true ); + } +} + +bool PerformInstallationPage::isAutoSwitching() const +{ + return !m_performInstallationForm->isShowingDetails(); +} + +void PerformInstallationPage::toggleDetailsWereChanged() +{ + const bool needAutoSwitching = isAutoSwitching(); + setButtonText( QWizard::CommitButton, needAutoSwitching ? m_commitBtnText : tr( "Next" ) ); + emit setAutomatedPageSwitchEnabled( needAutoSwitching ); +} + +void PerformInstallationPage::setTitleMessage( const QString& title ) +{ + setTitle( title ); +} + +//////////////////////////////////////////////////////////////////// +// +// FinishedPage +// +//////////////////////////////////////////////////////////////////// + +FinishedPage::FinishedPage(Installer *installer) + : Page(installer) +{ + //setCommitPage( true ); + setObjectName( QLatin1String( "FinishedPage" ) ); + setTitle(tr("Completing the %1 Setup Wizard").arg(productName())); + setPixmap(QWizard::WatermarkPixmap, watermarkPixmap()); + setSubTitle(QString()); + + m_msgLabel = new QLabel(this); + m_msgLabel->setObjectName( QLatin1String( "MessageLabel" ) ); + m_msgLabel->setWordWrap(true); +#ifdef Q_WS_MAC + m_msgLabel->setText(tr("Click Done to exit the Setup Wizard")); +#else + m_msgLabel->setText(tr("Click Finish to exit the Setup Wizard")); +#endif + + m_runItCheckBox = new QCheckBox(this); + m_runItCheckBox->setObjectName( QLatin1String( "RunItCheckBox" ) ); + m_runItCheckBox->setChecked(true); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addWidget(m_msgLabel); + layout->addWidget(m_runItCheckBox); + setLayout(layout); +} + +void FinishedPage::entering() +{ + if ( wizard()->button( QWizard::BackButton ) ) + wizard()->button( QWizard::BackButton )->setVisible( false ); + if ( installer()->isPackageManager() ) + { + setButtonText( QWizard::CommitButton, QLatin1String( "Finish" ) ); + wizard()->button( QWizard::CommitButton )->disconnect( this ); + connect( wizard()->button( QWizard::CommitButton ), SIGNAL( clicked() ), + this, SLOT( handleFinishClicked() ) ); + Gui* par = dynamic_cast< Gui* > ( wizard() ); + if ( par ) + { + connect( this, SIGNAL( finishClicked() ), par, SIGNAL( finishButtonClicked() ) ); + } + } + verbose() << "FINISHED ENTERING: " << std::endl; + connect( wizard()->button( QWizard::FinishButton ), SIGNAL( clicked() ), + this, SLOT( handleFinishClicked() ) ); + wizard()->setOption(QWizard::NoCancelButton, true); + + if (installer()->status() == Installer::InstallerSucceeded) { + + const QString finishedtext = installer()->value( QLatin1String( "FinishedText" ) ); + if( ! finishedtext.isEmpty() ) + m_msgLabel->setText( finishedtext ); + + if ( ! installer()->value( QLatin1String( "RunProgram" ) ).isEmpty() ) { + m_runItCheckBox->show(); + m_runItCheckBox->setText( installer()->value( QLatin1String( "RunProgramDescription" ), tr( "Run %1 now." ).arg( productName() ) ) ); + return; // job done + } + + } else { + setTitle(tr("The %1 Setup Wizard failed").arg(productName())); + } + m_runItCheckBox->hide(); + m_runItCheckBox->setChecked( false ); +} + +void FinishedPage::initializePage() +{ + setCommitPage( true ); + if ( wizard()->button( QWizard::BackButton ) ) + wizard()->button( QWizard::BackButton )->setVisible( false ); + if ( installer()->isPackageManager() ) + { + setButtonText( QWizard::CommitButton, QLatin1String( "Finish" ) ); + setButtonText( QWizard::NextButton, QLatin1String( "Finish" ) ); + } +} + +void FinishedPage::leaving() +{ + disconnect( wizard(), SIGNAL( customButtonClicked( int ) ), + this, SLOT( handleFinishClicked() ) ); + if ( installer()->isPackageManager() ) + { + disconnect( wizard()->button( QWizard::CommitButton ), SIGNAL( clicked() ), + this, SLOT( handleFinishClicked() ) ); + Gui* par = dynamic_cast< Gui* > ( wizard() ); + if ( par ) + { + disconnect( this, SIGNAL( finishClicked() ), par, SIGNAL( finishButtonClicked() ) ); + } + } +} + +void FinishedPage::handleFinishClicked() +{ + QString program = installer()->value( QLatin1String( "RunProgram" ) ); + if ( !m_runItCheckBox->isChecked() || program.isEmpty() ) + return; + program = installer()->replaceVariables( program ); + verbose() << "STARTING " << program << std::endl; + QProcess::startDetached( program ); +} + +//////////////////////////////////////////////////////////////////// +// +// RestartPage +// +//////////////////////////////////////////////////////////////////// + +RestartPage::RestartPage(Installer *installer) + : Page(installer) +{ + setObjectName( QLatin1String( "RestartPage" ) ); + setTitle(tr("Completing the %1 Setup Wizard").arg( productName() ) ); + setPixmap(QWizard::WatermarkPixmap, watermarkPixmap()); + setSubTitle( QString() ); + setFinalPage( false ); +} + +void RestartPage::entering() +{ + emit restart(); + wizard()->restart(); + if ( wizard()->button( QWizard::FinishButton ) ) + wizard()->button( QWizard::FinishButton )->setVisible( false ); + wizard()->setOption(QWizard::NoCancelButton, false); +} + +void RestartPage::leaving() +{ +} + +#include "qinstallergui.moc" |