diff --git a/CHANGES b/CHANGES index b0a823883..d68a66816 100644 --- a/CHANGES +++ b/CHANGES @@ -6,16 +6,29 @@ website will have to do for older versions. # 3.2.5 (unreleased) # This release contains contributions from (alphabetically by first name): + - Arnaud Ferraris + - Dan Simmons ## Core ## + * View modules (in C++) can now perform their own requirements-checking + to see if installation makes sense. This expands upon the existing + requirements checks in the welcome module (RAM, disk space, ..). + The checks have been made asynchronous, so that responsiveness during + requirements-checking is improved and the user has better feedback. + ## Modules ## + * *Partition* module: it is now possible to build without libparted. Since + KPMCore may not need this library anymore, it is a dependency that will + be dropped as soon as it is feasible. Add `-DCMAKE_DISABLE_FIND_PACKAGE_LIBPARTED=ON` + to the CMake flags to do so. * Python modules: several modules have had translations added. This is usually only visible when the module runs as part of the *exec* step, when the module's *pretty name* is displayed. In addition, error messages are now translated. + # 3.2.4 (2019-02-12) # This release contains contributions from (alphabetically by first name): diff --git a/src/calamares/CalamaresApplication.cpp b/src/calamares/CalamaresApplication.cpp index f668722fd..c9a171fd2 100644 --- a/src/calamares/CalamaresApplication.cpp +++ b/src/calamares/CalamaresApplication.cpp @@ -348,6 +348,7 @@ void CalamaresApplication::initViewSteps() { cDebug() << "STARTUP: loadModules for all modules done"; + m_moduleManager->checkRequirements(); if ( Calamares::Branding::instance()->windowMaximize() ) { m_mainwindow->setWindowFlag( Qt::FramelessWindowHint ); @@ -355,6 +356,7 @@ CalamaresApplication::initViewSteps() } else m_mainwindow->show(); + ProgressTreeModel* m = new ProgressTreeModel( nullptr ); ProgressTreeView::instance()->setModel( m ); cDebug() << "STARTUP: Window now visible and ProgressTreeView populated"; diff --git a/src/libcalamaresui/CMakeLists.txt b/src/libcalamaresui/CMakeLists.txt index 79598d514..99531e5ff 100644 --- a/src/libcalamaresui/CMakeLists.txt +++ b/src/libcalamaresui/CMakeLists.txt @@ -5,6 +5,8 @@ set( calamaresui_SOURCES modulesystem/Module.cpp modulesystem/ModuleManager.cpp modulesystem/ProcessJobModule.cpp + modulesystem/Requirement.cpp + modulesystem/RequirementsChecker.cpp modulesystem/ViewModule.cpp utils/CalamaresUtilsGui.cpp diff --git a/src/libcalamaresui/modulesystem/Module.cpp b/src/libcalamaresui/modulesystem/Module.cpp index ef629ac4d..20e0517ea 100644 --- a/src/libcalamaresui/modulesystem/Module.cpp +++ b/src/libcalamaresui/modulesystem/Module.cpp @@ -281,4 +281,10 @@ Module::initFrom( const QVariantMap& moduleDescriptor ) m_maybe_emergency = moduleDescriptor[ EMERGENCY ].toBool(); } +RequirementsList +Module::checkRequirements() +{ + return RequirementsList(); +} + } //ns diff --git a/src/libcalamaresui/modulesystem/Module.h b/src/libcalamaresui/modulesystem/Module.h index f89c9eedb..218270825 100644 --- a/src/libcalamaresui/modulesystem/Module.h +++ b/src/libcalamaresui/modulesystem/Module.h @@ -1,6 +1,7 @@ /* === This file is part of Calamares - === * * Copyright 2014-2015, Teo Mrnjavac + * Copyright 2017, Adriaan de Groot * * Calamares is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +20,7 @@ #ifndef CALAMARES_MODULE_H #define CALAMARES_MODULE_H +#include "Requirement.h" #include "UiDllMacro.h" #include @@ -178,6 +180,11 @@ public: */ QVariantMap configurationMap(); + /** + * @brief Check the requirements of this module. + */ + virtual RequirementsList checkRequirements(); + protected: explicit Module(); virtual void initFrom( const QVariantMap& moduleDescriptor ); diff --git a/src/libcalamaresui/modulesystem/ModuleManager.cpp b/src/libcalamaresui/modulesystem/ModuleManager.cpp index 86d97d2db..d3705729c 100644 --- a/src/libcalamaresui/modulesystem/ModuleManager.cpp +++ b/src/libcalamaresui/modulesystem/ModuleManager.cpp @@ -21,26 +21,23 @@ #include "ExecutionViewStep.h" #include "Module.h" -#include "utils/Logger.h" -#include "utils/YamlUtils.h" +#include "RequirementsChecker.h" #include "Settings.h" #include "ViewManager.h" +#include "utils/Logger.h" +#include "utils/YamlUtils.h" + #include #include #include #include -#define MODULE_CONFIG_FILENAME "module.desc" - namespace Calamares { - - ModuleManager* ModuleManager::s_instance = nullptr; - ModuleManager* ModuleManager::instance() { @@ -94,7 +91,7 @@ ModuleManager::doInit() bool success = currentDir.cd( subdir ); if ( success ) { - QFileInfo descriptorFileInfo( currentDir.absoluteFilePath( MODULE_CONFIG_FILENAME ) ); + QFileInfo descriptorFileInfo( currentDir.absoluteFilePath( QLatin1Literal( "module.desc") ) ); if ( ! ( descriptorFileInfo.exists() && descriptorFileInfo.isReadable() ) ) { cDebug() << Q_FUNC_INFO << "unreadable file: " @@ -307,6 +304,26 @@ ModuleManager::loadModules() } ); } +void +ModuleManager::checkRequirements() +{ + cDebug() << "Checking module requirements .."; + + QVector< Module* > modules( m_loadedModulesByInstanceKey.count() ); + int count = 0; + for (const auto& module : m_loadedModulesByInstanceKey ) + { + modules[count++] = module; + } + + RequirementsChecker *rq = new RequirementsChecker( modules, this ); + connect( rq, &RequirementsChecker::requirementsResult, this, &ModuleManager::requirementsResult ); + connect( rq, &RequirementsChecker::requirementsComplete, this, &ModuleManager::requirementsComplete ); + connect( rq, &RequirementsChecker::requirementsProgress, this, &ModuleManager::requirementsProgress ); + connect( rq, &RequirementsChecker::done, rq, &RequirementsChecker::deleteLater ); + + QTimer::singleShot( 0, rq, &RequirementsChecker::run ); +} QStringList ModuleManager::checkDependencies() @@ -334,8 +351,6 @@ ModuleManager::checkDependencies() break; } } - if ( somethingWasRemovedBecauseOfUnmetDependencies ) - break; } if ( !somethingWasRemovedBecauseOfUnmetDependencies ) break; @@ -369,4 +384,4 @@ ModuleManager::checkDependencies( const Module& m ) return allRequirementsFound; } -} +} // namespace diff --git a/src/libcalamaresui/modulesystem/ModuleManager.h b/src/libcalamaresui/modulesystem/ModuleManager.h index a0edc2528..689d61a77 100644 --- a/src/libcalamaresui/modulesystem/ModuleManager.h +++ b/src/libcalamaresui/modulesystem/ModuleManager.h @@ -20,6 +20,7 @@ #ifndef MODULELOADER_H #define MODULELOADER_H +#include "Requirement.h" #include "Typedefs.h" #include @@ -30,6 +31,7 @@ namespace Calamares { class Module; +struct RequirementEntry; // from Requirement.h /** * @brief The ModuleManager class is a singleton which manages Calamares modules. @@ -81,10 +83,20 @@ public: */ void loadModules(); + /** + * @brief Starts asynchronous requirements checking for each module. + * When this is done, the signal modulesChecked is emitted. + */ + void checkRequirements(); + signals: void initDone(); void modulesLoaded(); /// All of the modules were loaded successfully void modulesFailed( QStringList ); /// .. or not + // Below, see RequirementsChecker documentation + void requirementsComplete( bool ); + void requirementsResult( RequirementsList ); + void requirementsProgress( const QString& ); private slots: void doInit(); diff --git a/src/modules/welcome/checker/CheckItemWidget.h b/src/libcalamaresui/modulesystem/Requirement.cpp similarity index 58% rename from src/modules/welcome/checker/CheckItemWidget.h rename to src/libcalamaresui/modulesystem/Requirement.cpp index d2224c694..3347a2ae8 100644 --- a/src/modules/welcome/checker/CheckItemWidget.h +++ b/src/libcalamaresui/modulesystem/Requirement.cpp @@ -1,6 +1,5 @@ -/* === This file is part of Calamares - === +/* === This file is part of Calamares - === * - * Copyright 2014-2015, Teo Mrnjavac * Copyright 2017, Adriaan de Groot * * Calamares is free software: you can redistribute it and/or modify @@ -16,23 +15,5 @@ * You should have received a copy of the GNU General Public License * along with Calamares. If not, see . */ +#include "Requirement.h" -#ifndef CHECKITEMWIDGET_H -#define CHECKITEMWIDGET_H - -#include - -class CheckItemWidget : public QWidget -{ - Q_OBJECT -public: - explicit CheckItemWidget( bool checked, bool required, - QWidget* parent = nullptr ); - - void setText( const QString& text ); -private: - QLabel* m_textLabel; - QLabel* m_iconLabel; -}; - -#endif // CHECKITEMWIDGET_H diff --git a/src/libcalamaresui/modulesystem/Requirement.h b/src/libcalamaresui/modulesystem/Requirement.h new file mode 100644 index 000000000..396fe852b --- /dev/null +++ b/src/libcalamaresui/modulesystem/Requirement.h @@ -0,0 +1,67 @@ +/* === This file is part of Calamares - === + * + * Copyright 2017, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ +#ifndef CALAMARES_REQUIREMENT_H +#define CALAMARES_REQUIREMENT_H + +#include +#include +#include + +#include + +namespace Calamares +{ + +/** + * An indication of a requirement, which is checked in preparation + * for system installation. An entry has a name and some explanation functions + * (functions, because they need to respond to translations). + * + * A requirement can be *satisfied* or not. + * A requirement can be optional (i.e. a "good to have") or mandatory. + * + * Requirements which are not satisfied, and also mandatory, will prevent the + * installation from proceeding. + */ +struct RequirementEntry +{ + using TextFunction = std::function< QString() >; + + /// @brief name of this requirement; not shown to user and used as ID + QString name; + + /// @brief Detailed description of this requirement, for use in user-visible lists + TextFunction enumerationText; + + /// @brief User-visible string to show that the requirement is not met, short form + TextFunction negatedText; + + bool satisfied; + bool mandatory; + + /// @brief Convenience to check if this entry should be shown in details dialog + bool hasDetails() const { return !enumerationText().isEmpty(); } +}; + +using RequirementsList = QList< RequirementEntry >; + +} // namespace Calamares + +Q_DECLARE_METATYPE(Calamares::RequirementEntry) + +#endif diff --git a/src/libcalamaresui/modulesystem/RequirementsChecker.cpp b/src/libcalamaresui/modulesystem/RequirementsChecker.cpp new file mode 100644 index 000000000..c7f4625eb --- /dev/null +++ b/src/libcalamaresui/modulesystem/RequirementsChecker.cpp @@ -0,0 +1,154 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#include "RequirementsChecker.h" + +#include "Module.h" +#include "Requirement.h" + +#include "utils/Logger.h" + +#include + +#include +#include +#include +#include + + +namespace Calamares +{ + +static void +registerMetatypes() +{ + static bool done = false; + + if ( !done ) + { + qRegisterMetaType< RequirementEntry >( "RequirementEntry" ); + // It's sensitive to the names of types in parameters; in particular + // althrough QList is the same as RequirementsList, + // because we *name* the type as RequirementsList in the parameters, + // we need to register that (as well). Here, be safe and register + // both names. + qRegisterMetaType< QList< RequirementEntry > >( "QList" ); + qRegisterMetaType< RequirementsList >( "RequirementsList" ); + done = true; + } +} + +static void +check( Module * const &m, RequirementsChecker *c ) +{ + RequirementsList l = m->checkRequirements(); + if ( l.count() > 0 ) + c->addCheckedRequirements( l ); + c->requirementsProgress( QObject::tr( "Requirements checking for module %1 is complete." ).arg( m->name() ) ); +} + +RequirementsChecker::RequirementsChecker( QVector< Module* > modules, QObject* parent ) + : QObject( parent ) + , m_modules( std::move( modules ) ) + , m_progressTimer( nullptr ) + , m_progressTimeouts( 0 ) +{ + m_watchers.reserve( m_modules.count() ); + m_collectedRequirements.reserve( m_modules.count() ); + + registerMetatypes(); +} + +RequirementsChecker::~RequirementsChecker() +{ +} + +void +RequirementsChecker::run() +{ + m_progressTimer = new QTimer( this ); + connect( m_progressTimer, &QTimer::timeout, this, &RequirementsChecker::reportProgress ); + m_progressTimer->start( 1200 ); // msec + + for (const auto& module : m_modules ) + { + Watcher *watcher = new Watcher( this ); + watcher->setFuture( QtConcurrent::run( check, module, this ) ); + m_watchers.append( watcher ); + connect( watcher, &Watcher::finished, this, &RequirementsChecker::finished ); + } + + QTimer::singleShot( 0, this, &RequirementsChecker::finished ); +} + +void +RequirementsChecker::finished() +{ + if ( std::all_of( m_watchers.cbegin(), m_watchers.cend(), []( const Watcher *w ) { return w && w->isFinished(); } ) ) + { + cDebug() << "All requirements have been checked."; + + if ( m_progressTimer ) + m_progressTimer->stop(); + + bool acceptable = true; + int count = 0; + for ( const auto& r : m_collectedRequirements ) + { + if ( r.mandatory && !r.satisfied ) + { + cDebug() << " .. requirement" << count << r.name << "is not satisfied."; + acceptable = false; + } + ++count; + } + + emit requirementsComplete( acceptable ); + QTimer::singleShot(0, this, &RequirementsChecker::done ); + } +} + +void +RequirementsChecker::addCheckedRequirements( RequirementsList l ) +{ + static QMutex addMutex; + { + QMutexLocker lock( &addMutex ); + m_collectedRequirements.append( l ); + } + cDebug() << "Added" << l.count() << "requirement results"; + emit requirementsResult( l ); +} + +void +RequirementsChecker::reportProgress() +{ + m_progressTimeouts++; + + auto remaining = std::count_if( m_watchers.cbegin(), m_watchers.cend(), []( const Watcher *w ) { return w && !w->isFinished(); } ); + if ( remaining > 0 ) + { + QString waiting = tr( "Waiting for %n module(s).", "", remaining ); + QString elapsed = tr( "(%n second(s))", "", m_progressTimeouts * m_progressTimer->interval() / 1000 ); + emit requirementsProgress( waiting + QString( " " ) + elapsed ); + } + else + emit requirementsProgress( tr( "System-requirements checking is complete." ) ); +} + +} diff --git a/src/libcalamaresui/modulesystem/RequirementsChecker.h b/src/libcalamaresui/modulesystem/RequirementsChecker.h new file mode 100644 index 000000000..6e681971c --- /dev/null +++ b/src/libcalamaresui/modulesystem/RequirementsChecker.h @@ -0,0 +1,87 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ +#ifndef CALAMARES_REQUIREMENTSCHECKER_H +#define CALAMARES_REQUIREMENTSCHECKER_H + +#include "Requirement.h" + +#include +#include +#include +#include + + +namespace Calamares +{ + +class Module; + +/** @brief A manager-class that checks all the module requirements + * + * Asynchronously checks the requirements for each module, and + * emits progress signals as appropriate. + */ +class RequirementsChecker : public QObject +{ + Q_OBJECT + +public: + RequirementsChecker( QVector< Module* > modules, QObject* parent = nullptr ); + virtual ~RequirementsChecker() override; + +public slots: + /// @brief Start checking all the requirements + void run(); + + /// @brief Called when requirements are reported by a module + void addCheckedRequirements( RequirementsList ); + + /// @brief Called when all requirements have been checked + void finished(); + + /// @brief Called periodically while requirements are being checked + void reportProgress(); + +signals: + /// @brief Human-readable progress message + void requirementsProgress( const QString& ); + /// @brief Requirements from a single module + void requirementsResult( RequirementsList ); + /** @brief When all requirements are collected + * + * The argument indicates if all mandatory requirements are satisfied. + */ + void requirementsComplete( bool ); + /// @brief Emitted after requirementsComplete + void done(); + +private: + QVector< Module* > m_modules; + + using Watcher = QFutureWatcher< void >; + QVector< Watcher* > m_watchers; + + RequirementsList m_collectedRequirements; + + QTimer *m_progressTimer; + unsigned m_progressTimeouts; +} ; + +} + +#endif diff --git a/src/libcalamaresui/modulesystem/ViewModule.cpp b/src/libcalamaresui/modulesystem/ViewModule.cpp index 473ec6457..e24014621 100644 --- a/src/libcalamaresui/modulesystem/ViewModule.cpp +++ b/src/libcalamaresui/modulesystem/ViewModule.cpp @@ -132,4 +132,10 @@ ViewModule::~ViewModule() delete m_loader; } +RequirementsList +ViewModule::checkRequirements() +{ + return m_viewStep->checkRequirements(); +} + } // namespace Calamares diff --git a/src/libcalamaresui/modulesystem/ViewModule.h b/src/libcalamaresui/modulesystem/ViewModule.h index 735a19a81..7813130d0 100644 --- a/src/libcalamaresui/modulesystem/ViewModule.h +++ b/src/libcalamaresui/modulesystem/ViewModule.h @@ -39,6 +39,8 @@ public: void loadSelf() override; JobList jobs() const override; + RequirementsList checkRequirements() override; + protected: void initFrom( const QVariantMap& moduleDescriptor ) override; diff --git a/src/libcalamaresui/viewpages/ViewStep.cpp b/src/libcalamaresui/viewpages/ViewStep.cpp index c6acb5208..8a76a05ce 100644 --- a/src/libcalamaresui/viewpages/ViewStep.cpp +++ b/src/libcalamaresui/viewpages/ViewStep.cpp @@ -52,6 +52,14 @@ void ViewStep::onLeave() {} +void +ViewStep::next() +{} + +void +ViewStep::back() +{} + void ViewStep::setModuleInstanceKey( const QString& instanceKey ) @@ -66,4 +74,10 @@ ViewStep::setConfigurationMap( const QVariantMap& configurationMap ) Q_UNUSED( configurationMap ); } + +RequirementsList ViewStep::checkRequirements() +{ + return RequirementsList(); +} + } diff --git a/src/libcalamaresui/viewpages/ViewStep.h b/src/libcalamaresui/viewpages/ViewStep.h index f10d29b96..0010f407e 100644 --- a/src/libcalamaresui/viewpages/ViewStep.h +++ b/src/libcalamaresui/viewpages/ViewStep.h @@ -22,6 +22,7 @@ #include +#include "modulesystem/Requirement.h" #include "../UiDllMacro.h" #include "Typedefs.h" @@ -68,13 +69,39 @@ public: //TODO: we might want to make this a QSharedPointer virtual QWidget* widget() = 0; - virtual void next() = 0; - virtual void back() = 0; + /** + * @brief Multi-page support, go next + * + * Multi-page view steps need to manage the content visible in the widget + * themselves. This method is called when the user clicks the *next* + * button, and should switch to the next of the multiple-pages. It needs + * to be consistent with both isNextEnabled() and isAtEnd(). + * + * In particular: when isAtEnd() returns false, next() is called when + * the user clicks the button and a new page should be shown by this + * view step. When isAtEnd() returns true, clicking the button will + * switch to the next view step in sequence, rather than a next page + * in the current view step. + */ + virtual void next(); + /// @brief Multi-page support, go back + virtual void back(); + /// @brief Can the user click *next* with currently-filled-in data? virtual bool isNextEnabled() const = 0; + /// @brief Can the user click *previous* with currently-filled-in data? virtual bool isBackEnabled() const = 0; + /** + * @brief Multi-page support, switch to previous view step? + * + * For a multi-page view step, this indicates that the first (beginning) + * page is showing. Clicking *previous* when at the beginning of a view + * step, switches to the previous step, not the previous page of the + * current view step. + */ virtual bool isAtBeginning() const = 0; + /// @brief Multi-page support, switch to next view step? virtual bool isAtEnd() const = 0; /** @@ -91,6 +118,12 @@ public: */ virtual void onLeave(); + /** + * @brief Jobs needed to run this viewstep + * + * When a ViewStep is listed in the exec section, its jobs are executed instead. + * This function returns that list of jobs; an empty list is ok. + */ virtual JobList jobs() const = 0; void setModuleInstanceKey( const QString& instanceKey ); @@ -101,9 +134,18 @@ public: virtual void setConfigurationMap( const QVariantMap& configurationMap ); + /** + * @brief Can this module proceed, on this machine? + * + * This is called asynchronously at startup, and returns a list of + * the requirements that the module has checked, and their status. + * See Calamares::RequirementEntry for details. + */ + virtual RequirementsList checkRequirements(); + signals: + /// @brief Tells the viewmanager to enable the *next* button according to @p status void nextStatusChanged( bool status ); - void done(); /* Emitted when the viewstep thinks it needs more space than is currently * available for display. @p enlarge is the requested additional space, diff --git a/src/modules/finished/FinishedViewStep.cpp b/src/modules/finished/FinishedViewStep.cpp index 3b807f69c..8457aa4cd 100644 --- a/src/modules/finished/FinishedViewStep.cpp +++ b/src/modules/finished/FinishedViewStep.cpp @@ -67,18 +67,6 @@ FinishedViewStep::widget() } -void -FinishedViewStep::next() -{ - emit done(); -} - - -void -FinishedViewStep::back() -{} - - bool FinishedViewStep::isNextEnabled() const { diff --git a/src/modules/finished/FinishedViewStep.h b/src/modules/finished/FinishedViewStep.h index 393527053..b1af598c7 100644 --- a/src/modules/finished/FinishedViewStep.h +++ b/src/modules/finished/FinishedViewStep.h @@ -40,9 +40,6 @@ public: QWidget* widget() override; - void next() override; - void back() override; - bool isNextEnabled() const override; bool isBackEnabled() const override; diff --git a/src/modules/interactiveterminal/InteractiveTerminalViewStep.cpp b/src/modules/interactiveterminal/InteractiveTerminalViewStep.cpp index 2559ea635..d57eb7d05 100644 --- a/src/modules/interactiveterminal/InteractiveTerminalViewStep.cpp +++ b/src/modules/interactiveterminal/InteractiveTerminalViewStep.cpp @@ -53,18 +53,6 @@ InteractiveTerminalViewStep::widget() } -void -InteractiveTerminalViewStep::next() -{ - emit done(); -} - - -void -InteractiveTerminalViewStep::back() -{} - - bool InteractiveTerminalViewStep::isNextEnabled() const { diff --git a/src/modules/interactiveterminal/InteractiveTerminalViewStep.h b/src/modules/interactiveterminal/InteractiveTerminalViewStep.h index 3d5862935..55486691d 100644 --- a/src/modules/interactiveterminal/InteractiveTerminalViewStep.h +++ b/src/modules/interactiveterminal/InteractiveTerminalViewStep.h @@ -41,9 +41,6 @@ public: QWidget* widget() override; - void next() override; - void back() override; - bool isNextEnabled() const override; bool isBackEnabled() const override; diff --git a/src/modules/keyboard/KeyboardViewStep.cpp b/src/modules/keyboard/KeyboardViewStep.cpp index 053266059..40a5385a3 100644 --- a/src/modules/keyboard/KeyboardViewStep.cpp +++ b/src/modules/keyboard/KeyboardViewStep.cpp @@ -65,19 +65,6 @@ KeyboardViewStep::widget() } -void -KeyboardViewStep::next() -{ - //TODO: actually save those settings somewhere - emit done(); -} - - -void -KeyboardViewStep::back() -{} - - bool KeyboardViewStep::isNextEnabled() const { diff --git a/src/modules/keyboard/KeyboardViewStep.h b/src/modules/keyboard/KeyboardViewStep.h index 46a52a524..a5bdd579e 100644 --- a/src/modules/keyboard/KeyboardViewStep.h +++ b/src/modules/keyboard/KeyboardViewStep.h @@ -42,9 +42,6 @@ public: QWidget* widget() override; - void next() override; - void back() override; - bool isNextEnabled() const override; bool isBackEnabled() const override; diff --git a/src/modules/license/LicenseViewStep.cpp b/src/modules/license/LicenseViewStep.cpp index 41ca02a7e..96a7b8660 100644 --- a/src/modules/license/LicenseViewStep.cpp +++ b/src/modules/license/LicenseViewStep.cpp @@ -59,18 +59,6 @@ LicenseViewStep::widget() } -void -LicenseViewStep::next() -{ - emit done(); -} - - -void -LicenseViewStep::back() -{} - - bool LicenseViewStep::isNextEnabled() const { diff --git a/src/modules/license/LicenseViewStep.h b/src/modules/license/LicenseViewStep.h index cf7b2bc15..a4fabc8e1 100644 --- a/src/modules/license/LicenseViewStep.h +++ b/src/modules/license/LicenseViewStep.h @@ -42,9 +42,6 @@ public: QWidget* widget() override; - void next() override; - void back() override; - bool isNextEnabled() const override; bool isBackEnabled() const override; diff --git a/src/modules/locale/LocaleViewStep.cpp b/src/modules/locale/LocaleViewStep.cpp index 4a6eb229a..a7dc432f8 100644 --- a/src/modules/locale/LocaleViewStep.cpp +++ b/src/modules/locale/LocaleViewStep.cpp @@ -190,18 +190,6 @@ LocaleViewStep::widget() } -void -LocaleViewStep::next() -{ - emit done(); -} - - -void -LocaleViewStep::back() -{} - - bool LocaleViewStep::isNextEnabled() const { diff --git a/src/modules/locale/LocaleViewStep.h b/src/modules/locale/LocaleViewStep.h index 8006bc616..3f5c91621 100644 --- a/src/modules/locale/LocaleViewStep.h +++ b/src/modules/locale/LocaleViewStep.h @@ -45,9 +45,6 @@ public: QWidget* widget() override; - void next() override; - void back() override; - bool isNextEnabled() const override; bool isBackEnabled() const override; diff --git a/src/modules/netinstall/NetInstallViewStep.cpp b/src/modules/netinstall/NetInstallViewStep.cpp index 6dd824b32..3c4fa5e58 100644 --- a/src/modules/netinstall/NetInstallViewStep.cpp +++ b/src/modules/netinstall/NetInstallViewStep.cpp @@ -69,18 +69,6 @@ NetInstallViewStep::widget() } -void -NetInstallViewStep::next() -{ - emit done(); -} - - -void -NetInstallViewStep::back() -{} - - bool NetInstallViewStep::isNextEnabled() const { diff --git a/src/modules/netinstall/NetInstallViewStep.h b/src/modules/netinstall/NetInstallViewStep.h index ee53f61ce..b07d3f96d 100644 --- a/src/modules/netinstall/NetInstallViewStep.h +++ b/src/modules/netinstall/NetInstallViewStep.h @@ -42,9 +42,6 @@ public: QWidget* widget() override; - void next() override; - void back() override; - bool isNextEnabled() const override; bool isBackEnabled() const override; diff --git a/src/modules/partition/gui/ChoicePage.cpp b/src/modules/partition/gui/ChoicePage.cpp index 21783c251..9d86a32a1 100644 --- a/src/modules/partition/gui/ChoicePage.cpp +++ b/src/modules/partition/gui/ChoicePage.cpp @@ -882,11 +882,6 @@ ChoicePage::updateDeviceStatePreview() PartitionModel* model = new PartitionModel( m_beforePartitionBarsView ); model->init( deviceBefore, m_core->osproberEntries() ); - // The QObject parents tree is meaningful for memory management here, - // see qDeleteAll above. - deviceBefore->setParent( model ); // Can't reparent across threads - model->setParent( m_beforePartitionBarsView ); - m_beforePartitionBarsView->setModel( model ); m_beforePartitionLabelsView->setModel( model ); diff --git a/src/modules/partition/gui/PartitionViewStep.cpp b/src/modules/partition/gui/PartitionViewStep.cpp index 3c71302e0..6fc8b0129 100644 --- a/src/modules/partition/gui/PartitionViewStep.cpp +++ b/src/modules/partition/gui/PartitionViewStep.cpp @@ -60,6 +60,8 @@ #include #include +#include // For sleep(3) + PartitionViewStep::PartitionViewStep( QObject* parent ) : Calamares::ViewStep( parent ) , m_core( nullptr ) @@ -213,8 +215,8 @@ PartitionViewStep::createSummaryWidget() const else // multiple disk previews! { diskInfoLabel->setText( tr( "Disk %1 (%2)" ) - .arg( info.deviceNode ) - .arg( info.deviceName ) ); + .arg( info.deviceNode ) + .arg( info.deviceName ) ); } formLayout->addRow( diskInfoLabel ); @@ -223,9 +225,9 @@ PartitionViewStep::createSummaryWidget() const QVBoxLayout* field; PartitionBarsView::NestedPartitionsMode mode = Calamares::JobQueue::instance()->globalStorage()-> - value( "drawNestedPartitions" ).toBool() ? - PartitionBarsView::DrawNestedPartitions : - PartitionBarsView::NoNestedPartitions; + value( "drawNestedPartitions" ).toBool() ? + PartitionBarsView::DrawNestedPartitions : + PartitionBarsView::NoNestedPartitions; preview = new PartitionBarsView; preview->setNestedPartitionsMode( mode ); previewLabels = new PartitionLabelsView; @@ -263,7 +265,7 @@ PartitionViewStep::createSummaryWidget() const foreach ( const Calamares::job_ptr& job, jobs() ) { if ( !job->prettyDescription().isEmpty() ) - jobsLines.append( job->prettyDescription() ); + jobsLines.append( job->prettyDescription() ); } if ( !jobsLines.isEmpty() ) { @@ -292,25 +294,8 @@ PartitionViewStep::next() if ( m_core->isDirty() ) m_manualPartitionPage->onRevertClicked(); } - else if ( m_choicePage->currentChoice() == ChoicePage::Erase ) - { - emit done(); - return; - } - else if ( m_choicePage->currentChoice() == ChoicePage::Alongside ) - { - emit done(); - return; - } - else if ( m_choicePage->currentChoice() == ChoicePage::Replace ) - { - emit done(); - return; - } cDebug() << "Choice applied: " << m_choicePage->currentChoice(); - return; } - emit done(); } @@ -360,8 +345,8 @@ PartitionViewStep::isAtEnd() const if ( m_choicePage == m_widget->currentWidget() ) { if ( m_choicePage->currentChoice() == ChoicePage::Erase || - m_choicePage->currentChoice() == ChoicePage::Replace || - m_choicePage->currentChoice() == ChoicePage::Alongside ) + m_choicePage->currentChoice() == ChoicePage::Replace || + m_choicePage->currentChoice() == ChoicePage::Alongside ) return true; return false; } @@ -374,7 +359,7 @@ PartitionViewStep::onActivate() { // if we're coming back to PVS from the next VS if ( m_widget->currentWidget() == m_choicePage && - m_choicePage->currentChoice() == ChoicePage::Alongside ) + m_choicePage->currentChoice() == ChoicePage::Alongside ) { m_choicePage->applyActionChoice( ChoicePage::Alongside ); // m_choicePage->reset(); @@ -397,7 +382,7 @@ PartitionViewStep::onLeave() if ( PartUtils::isEfiSystem() ) { QString espMountPoint = Calamares::JobQueue::instance()->globalStorage()-> - value( "efiSystemPartition").toString(); + value( "efiSystemPartition" ).toString(); Partition* esp = m_core->findPartitionByMountPoint( espMountPoint ); QString message; @@ -452,7 +437,7 @@ PartitionViewStep::onLeave() // If the root partition is encrypted, and there's a separate boot // partition which is not encrypted if ( root_p->fileSystem().type() == FileSystem::Luks && - boot_p->fileSystem().type() != FileSystem::Luks ) + boot_p->fileSystem().type() != FileSystem::Luks ) { message = tr( "Boot partition not encrypted" ); description = tr( "A separate boot partition was set up together with " @@ -601,17 +586,18 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap ) // Now that we have the config, we load the PartitionCoreModule in the background // because it could take a while. Then when it's done, we can set up the widgets // and remove the spinner. - QFutureWatcher< void >* watcher = new QFutureWatcher< void >(); - connect( watcher, &QFutureWatcher< void >::finished, - this, [ this, watcher, choices ] + m_future = new QFutureWatcher< void >(); + connect( m_future, &QFutureWatcher< void >::finished, + this, [ this ] { continueLoading(); - watcher->deleteLater(); + this->m_future->deleteLater(); + this->m_future = nullptr; } ); QFuture< void > future = - QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule ); - watcher->setFuture( future ); + QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule ); + m_future->setFuture( future ); if ( configurationMap.contains( "partitionLayout" ) ) { @@ -630,5 +616,24 @@ PartitionViewStep::jobs() const return m_core->jobs(); } +Calamares::RequirementsList +PartitionViewStep::checkRequirements() +{ + if ( m_future ) + m_future->waitForFinished(); + + Calamares::RequirementsList l; + l.append( + { + QLatin1Literal( "partitions" ), + []{ return tr( "has at least one disk device available." ); }, + []{ return tr( "There are no partitons to install on." ); }, + m_core->deviceModel()->rowCount() > 0, // satisfied + true // required + } ); + + return l; +} + CALAMARES_PLUGIN_FACTORY_DEFINITION( PartitionViewStepFactory, registerPlugin(); ) diff --git a/src/modules/partition/gui/PartitionViewStep.h b/src/modules/partition/gui/PartitionViewStep.h index f23108316..47f8fa127 100644 --- a/src/modules/partition/gui/PartitionViewStep.h +++ b/src/modules/partition/gui/PartitionViewStep.h @@ -36,6 +36,8 @@ class PartitionPage; class PartitionCoreModule; class QStackedWidget; +template class QFutureWatcher; + /** * The starting point of the module. Instantiates PartitionCoreModule, * ChoicePage and PartitionPage, then connects them. @@ -69,6 +71,8 @@ public: QList< Calamares::job_ptr > jobs() const override; + Calamares::RequirementsList checkRequirements() override; + private: void initPartitionCoreModule(); void continueLoading(); @@ -79,6 +83,7 @@ private: PartitionPage* m_manualPartitionPage; QWidget* m_waitingWidget; + QFutureWatcher* m_future; QSet< PartitionActions::Choices::SwapChoice > m_swapChoices; }; diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp index ef319bde4..5525f36fc 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.cpp +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.cpp @@ -76,18 +76,6 @@ PlasmaLnfViewStep::widget() } -void -PlasmaLnfViewStep::next() -{ - emit done(); -} - - -void -PlasmaLnfViewStep::back() -{} - - bool PlasmaLnfViewStep::isNextEnabled() const { diff --git a/src/modules/plasmalnf/PlasmaLnfViewStep.h b/src/modules/plasmalnf/PlasmaLnfViewStep.h index b9a6b72e6..01db17821 100644 --- a/src/modules/plasmalnf/PlasmaLnfViewStep.h +++ b/src/modules/plasmalnf/PlasmaLnfViewStep.h @@ -41,9 +41,6 @@ public: QWidget* widget() override; - void next() override; - void back() override; - bool isNextEnabled() const override; bool isBackEnabled() const override; diff --git a/src/modules/summary/SummaryViewStep.cpp b/src/modules/summary/SummaryViewStep.cpp index 4f60a3c4f..6835b2b05 100644 --- a/src/modules/summary/SummaryViewStep.cpp +++ b/src/modules/summary/SummaryViewStep.cpp @@ -51,18 +51,6 @@ SummaryViewStep::widget() } -void -SummaryViewStep::next() -{ - emit done(); -} - - -void -SummaryViewStep::back() -{} - - bool SummaryViewStep::isNextEnabled() const { diff --git a/src/modules/summary/SummaryViewStep.h b/src/modules/summary/SummaryViewStep.h index 9aff35cd0..88f177a4d 100644 --- a/src/modules/summary/SummaryViewStep.h +++ b/src/modules/summary/SummaryViewStep.h @@ -40,9 +40,6 @@ public: QWidget* widget() override; - void next() override; - void back() override; - bool isNextEnabled() const override; bool isBackEnabled() const override; diff --git a/src/modules/tracking/TrackingViewStep.cpp b/src/modules/tracking/TrackingViewStep.cpp index 417e10fc0..304e2a971 100644 --- a/src/modules/tracking/TrackingViewStep.cpp +++ b/src/modules/tracking/TrackingViewStep.cpp @@ -67,18 +67,6 @@ TrackingViewStep::widget() } -void -TrackingViewStep::next() -{ - emit done(); -} - - -void -TrackingViewStep::back() -{} - - bool TrackingViewStep::isNextEnabled() const { diff --git a/src/modules/tracking/TrackingViewStep.h b/src/modules/tracking/TrackingViewStep.h index dc3ae823e..aaaf3bbae 100644 --- a/src/modules/tracking/TrackingViewStep.h +++ b/src/modules/tracking/TrackingViewStep.h @@ -43,9 +43,6 @@ public: QWidget* widget() override; - void next() override; - void back() override; - bool isNextEnabled() const override; bool isBackEnabled() const override; diff --git a/src/modules/users/UsersViewStep.cpp b/src/modules/users/UsersViewStep.cpp index 8ff7b0e7b..3b1e6a5ad 100644 --- a/src/modules/users/UsersViewStep.cpp +++ b/src/modules/users/UsersViewStep.cpp @@ -61,18 +61,6 @@ UsersViewStep::widget() } -void -UsersViewStep::next() -{ - emit done(); -} - - -void -UsersViewStep::back() -{} - - bool UsersViewStep::isNextEnabled() const { diff --git a/src/modules/users/UsersViewStep.h b/src/modules/users/UsersViewStep.h index 81b80bced..a1995497c 100644 --- a/src/modules/users/UsersViewStep.h +++ b/src/modules/users/UsersViewStep.h @@ -43,9 +43,6 @@ public: QWidget* widget() override; - void next() override; - void back() override; - bool isNextEnabled() const override; bool isBackEnabled() const override; diff --git a/src/modules/webview/WebViewStep.cpp b/src/modules/webview/WebViewStep.cpp index 1db7c8e41..50c270b09 100644 --- a/src/modules/webview/WebViewStep.cpp +++ b/src/modules/webview/WebViewStep.cpp @@ -72,18 +72,6 @@ WebViewStep::widget() } -void -WebViewStep::next() -{ - emit done(); -} - - -void -WebViewStep::back() -{} - - bool WebViewStep::isNextEnabled() const { diff --git a/src/modules/webview/WebViewStep.h b/src/modules/webview/WebViewStep.h index 6430cdcf1..c588318fa 100644 --- a/src/modules/webview/WebViewStep.h +++ b/src/modules/webview/WebViewStep.h @@ -50,8 +50,6 @@ public: QWidget* widget() override; - void next() override; - void back() override; void onActivate() override; bool isNextEnabled() const override; diff --git a/src/modules/welcome/CMakeLists.txt b/src/modules/welcome/CMakeLists.txt index a520aa080..f627db032 100644 --- a/src/modules/welcome/CMakeLists.txt +++ b/src/modules/welcome/CMakeLists.txt @@ -15,9 +15,10 @@ endif() include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui ) set( CHECKER_SOURCES - checker/CheckItemWidget.cpp - checker/CheckerWidget.cpp - checker/RequirementsChecker.cpp + checker/CheckerContainer.cpp + checker/ResultWidget.cpp + checker/ResultsListWidget.cpp + checker/GeneralRequirements.cpp ${PARTMAN_SRC} ) diff --git a/src/modules/welcome/WelcomePage.cpp b/src/modules/welcome/WelcomePage.cpp index 8ffb153bf..d4ae6c47a 100644 --- a/src/modules/welcome/WelcomePage.cpp +++ b/src/modules/welcome/WelcomePage.cpp @@ -22,10 +22,12 @@ #include "ui_WelcomePage.h" #include "CalamaresVersion.h" -#include "checker/RequirementsChecker.h" +#include "checker/CheckerContainer.h" #include "utils/Logger.h" #include "utils/CalamaresUtilsGui.h" #include "utils/Retranslator.h" + +#include "modulesystem/ModuleManager.h" #include "ViewManager.h" #include @@ -39,11 +41,14 @@ #include "Branding.h" -WelcomePage::WelcomePage( RequirementsChecker* requirementsChecker, QWidget* parent ) +WelcomePage::WelcomePage( QWidget* parent ) : QWidget( parent ) , ui( new Ui::WelcomePage ) - , m_requirementsChecker( requirementsChecker ) + , m_checkingWidget( new CheckerContainer( this ) ) { + connect( Calamares::ModuleManager::instance(), &Calamares::ModuleManager::requirementsResult, m_checkingWidget, &CheckerContainer::requirementsChecked ); + connect( Calamares::ModuleManager::instance(), &Calamares::ModuleManager::requirementsComplete, m_checkingWidget, &CheckerContainer::requirementsComplete ); + connect( Calamares::ModuleManager::instance(), &Calamares::ModuleManager::requirementsProgress, m_checkingWidget, &CheckerContainer::requirementsProgress ); ui->setupUi( this ); ui->verticalLayout->insertSpacing( 1, CalamaresUtils::defaultFontHeight() * 2 ); @@ -102,7 +107,7 @@ WelcomePage::WelcomePage( RequirementsChecker* requirementsChecker, QWidget* par mb.exec(); } ); - ui->verticalLayout->insertWidget( 3, m_requirementsChecker->widget() ); + ui->verticalLayout->insertWidget( 3, m_checkingWidget); } @@ -277,3 +282,8 @@ WelcomePage::focusInEvent( QFocusEvent* e ) ui->languageWidget->setFocus(); e->accept(); } + +bool WelcomePage::verdict() const +{ + return m_checkingWidget->verdict(); +} diff --git a/src/modules/welcome/WelcomePage.h b/src/modules/welcome/WelcomePage.h index cf187aecb..65b619c79 100644 --- a/src/modules/welcome/WelcomePage.h +++ b/src/modules/welcome/WelcomePage.h @@ -26,26 +26,27 @@ namespace Ui class WelcomePage; } -class RequirementsChecker; +class CheckerContainer; class WelcomePage : public QWidget { Q_OBJECT public: - explicit WelcomePage( RequirementsChecker* requirementsChecker, - QWidget* parent = nullptr ); + explicit WelcomePage( QWidget* parent = nullptr ); void setUpLinks( bool showSupportUrl, bool showKnownIssuesUrl, bool showReleaseNotesUrl ); + bool verdict() const; + protected: void focusInEvent( QFocusEvent* e ) override; //choose the child widget to focus private: void initLanguages(); Ui::WelcomePage* ui; - RequirementsChecker* m_requirementsChecker; + CheckerContainer* m_checkingWidget; }; #endif // WELCOMEPAGE_H diff --git a/src/modules/welcome/WelcomeViewStep.cpp b/src/modules/welcome/WelcomeViewStep.cpp index 86740fb3d..88b5f6324 100644 --- a/src/modules/welcome/WelcomeViewStep.cpp +++ b/src/modules/welcome/WelcomeViewStep.cpp @@ -20,9 +20,10 @@ #include "WelcomeViewStep.h" #include "WelcomePage.h" -#include "checker/RequirementsChecker.h" -#include "utils/Logger.h" +#include "checker/GeneralRequirements.h" +#include "modulesystem/ModuleManager.h" +#include "utils/Logger.h" #include @@ -30,12 +31,10 @@ CALAMARES_PLUGIN_FACTORY_DEFINITION( WelcomeViewStepFactory, registerPluginverdict(); + return m_widget->verdict(); } @@ -100,10 +87,10 @@ WelcomeViewStep::isAtEnd() const } -QList< Calamares::job_ptr > +Calamares::JobList WelcomeViewStep::jobs() const { - return QList< Calamares::job_ptr >(); + return Calamares::JobList(); } @@ -135,3 +122,7 @@ WelcomeViewStep::setConfigurationMap( const QVariantMap& configurationMap ) "module configuration."; } +Calamares::RequirementsList WelcomeViewStep::checkRequirements() +{ + return m_requirementsChecker->checkRequirements(); +} diff --git a/src/modules/welcome/WelcomeViewStep.h b/src/modules/welcome/WelcomeViewStep.h index 34b84c29f..937cad246 100644 --- a/src/modules/welcome/WelcomeViewStep.h +++ b/src/modules/welcome/WelcomeViewStep.h @@ -21,6 +21,7 @@ #include +#include #include #include @@ -29,7 +30,7 @@ #include class WelcomePage; -class RequirementsChecker; +class GeneralRequirements; class PLUGINDLLEXPORT WelcomeViewStep : public Calamares::ViewStep { @@ -43,23 +44,21 @@ public: QWidget* widget() override; - void next() override; - void back() override; - bool isNextEnabled() const override; bool isBackEnabled() const override; bool isAtBeginning() const override; bool isAtEnd() const override; - QList< Calamares::job_ptr > jobs() const override; + Calamares::JobList jobs() const override; void setConfigurationMap( const QVariantMap& configurationMap ) override; + Calamares::RequirementsList checkRequirements() override; + private: WelcomePage* m_widget; - - RequirementsChecker* m_requirementsChecker; + GeneralRequirements* m_requirementsChecker; }; CALAMARES_PLUGIN_FACTORY_DECLARATION( WelcomeViewStepFactory ) diff --git a/src/modules/welcome/checker/CheckerContainer.cpp b/src/modules/welcome/checker/CheckerContainer.cpp new file mode 100644 index 000000000..0524bddb0 --- /dev/null +++ b/src/modules/welcome/checker/CheckerContainer.cpp @@ -0,0 +1,83 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014-2017, Teo Mrnjavac + * Copyright 2017, 2019, Adriaan de Groot + * Copyright 2017, Gabriel Craciunescu + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +/* Based on code extracted from RequirementsChecker.cpp */ + +#include "CheckerContainer.h" + +#include "ResultsListWidget.h" + +#include "utils/CalamaresUtilsGui.h" +#include "utils/Logger.h" +#include "utils/Retranslator.h" +#include "widgets/WaitingWidget.h" + +CheckerContainer::CheckerContainer( QWidget* parent ) + : QWidget( parent ) + , m_waitingWidget( new WaitingWidget( QString(), this ) ) + , m_checkerWidget( nullptr ) + , m_verdict( false ) +{ + QBoxLayout* mainLayout = new QHBoxLayout; + setLayout( mainLayout ); + CalamaresUtils::unmarginLayout( mainLayout ); + + mainLayout->addWidget( m_waitingWidget ); + CALAMARES_RETRANSLATE( + if ( m_waitingWidget ) + m_waitingWidget->setText( tr( "Gathering system information..." ) ); + ) +} + +CheckerContainer::~CheckerContainer() +{ + delete m_waitingWidget; + delete m_checkerWidget; +} + +void CheckerContainer::requirementsComplete( bool ok ) +{ + + layout()->removeWidget( m_waitingWidget ); + m_waitingWidget->deleteLater(); + m_waitingWidget = nullptr; // Don't delete in destructor + + m_checkerWidget = new ResultsListWidget( this ); + m_checkerWidget->init( m_requirements ); + layout()->addWidget( m_checkerWidget ); + + m_verdict = ok; +} + +void CheckerContainer::requirementsChecked(const Calamares::RequirementsList& l) +{ + m_requirements.append( l ); +} + +void CheckerContainer::requirementsProgress(const QString& message) +{ + if ( m_waitingWidget ) + m_waitingWidget->setText( message ); +} + +bool CheckerContainer::verdict() const +{ + return m_verdict; +} diff --git a/src/modules/welcome/checker/CheckerContainer.h b/src/modules/welcome/checker/CheckerContainer.h new file mode 100644 index 000000000..e50b362a2 --- /dev/null +++ b/src/modules/welcome/checker/CheckerContainer.h @@ -0,0 +1,64 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014-2017, Teo Mrnjavac + * Copyright 2017, Adriaan de Groot + * Copyright 2017, Gabriel Craciunescu + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +/* Based on code extracted from RequirementsChecker.cpp */ + +#ifndef CHECKERCONTAINER_H +#define CHECKERCONTAINER_H + +#include + +#include "modulesystem/Requirement.h" + +class ResultsListWidget; +class WaitingWidget; + +/** + * A widget that collects requirements results; until the results are + * all in, displays a spinner / waiting widget. Then it switches to + * a (list) diplay of the results, plus some explanation of the + * overall state of the entire list of results. + */ +class CheckerContainer : public QWidget +{ + Q_OBJECT +public: + explicit CheckerContainer( QWidget* parent = nullptr ); + virtual ~CheckerContainer(); + + bool verdict() const; + +public slots: + void requirementsChecked( const Calamares::RequirementsList& ); + + /** @brief All the requirements are complete, switch to list view */ + void requirementsComplete( bool ); + + void requirementsProgress( const QString& message ); + +protected: + WaitingWidget *m_waitingWidget; + ResultsListWidget *m_checkerWidget; + + Calamares::RequirementsList m_requirements; + bool m_verdict; +} ; + +#endif diff --git a/src/modules/welcome/checker/RequirementsChecker.cpp b/src/modules/welcome/checker/GeneralRequirements.cpp similarity index 52% rename from src/modules/welcome/checker/RequirementsChecker.cpp rename to src/modules/welcome/checker/GeneralRequirements.cpp index a5255058d..4fcd8129d 100644 --- a/src/modules/welcome/checker/RequirementsChecker.cpp +++ b/src/modules/welcome/checker/GeneralRequirements.cpp @@ -18,11 +18,12 @@ * along with Calamares. If not, see . */ -#include "RequirementsChecker.h" +#include "GeneralRequirements.h" -#include "CheckerWidget.h" +#include "CheckerContainer.h" #include "partman_devices.h" +#include "modulesystem/Requirement.h" #include "widgets/WaitingWidget.h" #include "utils/CalamaresUtilsGui.h" #include "utils/Logger.h" @@ -30,6 +31,7 @@ #include "utils/CalamaresUtilsSystem.h" #include "utils/Units.h" + #include "JobQueue.h" #include "GlobalStorage.h" @@ -51,166 +53,113 @@ #include //geteuid -RequirementsChecker::RequirementsChecker( QObject* parent ) +GeneralRequirements::GeneralRequirements( QObject* parent ) : QObject( parent ) - , m_widget( new QWidget() ) , m_requiredStorageGB( -1 ) , m_requiredRamGB( -1 ) - , m_actualWidget( new CheckerWidget() ) - , m_verdict( false ) { - QBoxLayout* mainLayout = new QHBoxLayout; - m_widget->setLayout( mainLayout ); - CalamaresUtils::unmarginLayout( mainLayout ); +} - WaitingWidget* waitingWidget = new WaitingWidget( QString() ); - mainLayout->addWidget( waitingWidget ); - CALAMARES_RETRANSLATE( waitingWidget->setText( tr( "Gathering system information..." ) ); ) +Calamares::RequirementsList GeneralRequirements::checkRequirements() +{ + QSize availableSize = qApp->desktop()->availableGeometry().size(); - QSize availableSize = qApp->desktop()->availableGeometry( m_widget ).size(); + bool enoughStorage = false; + bool enoughRam = false; + bool hasPower = false; + bool hasInternet = false; + bool isRoot = false; + bool enoughScreen = (availableSize.width() >= CalamaresUtils::windowMinimumWidth) && (availableSize.height() >= CalamaresUtils::windowMinimumHeight); - QTimer* timer = new QTimer; - timer->setSingleShot( true ); - connect( timer, &QTimer::timeout, - [=]() + qint64 requiredStorageB = CalamaresUtils::GiBtoBytes(m_requiredStorageGB); + cDebug() << "Need at least storage bytes:" << requiredStorageB; + if ( m_entriesToCheck.contains( "storage" ) ) + enoughStorage = checkEnoughStorage( requiredStorageB ); + + qint64 requiredRamB = CalamaresUtils::GiBtoBytes(m_requiredRamGB); + cDebug() << "Need at least ram bytes:" << requiredRamB; + if ( m_entriesToCheck.contains( "ram" ) ) + enoughRam = checkEnoughRam( requiredRamB ); + + if ( m_entriesToCheck.contains( "power" ) ) + hasPower = checkHasPower(); + + if ( m_entriesToCheck.contains( "internet" ) ) + hasInternet = checkHasInternet(); + + if ( m_entriesToCheck.contains( "root" ) ) + isRoot = checkIsRoot(); + + using TR = Logger::DebugRow; + cDebug() << "GeneralRequirements output:" + << TR("enoughStorage", enoughStorage) + << TR("enoughRam", enoughRam) + << TR("hasPower", hasPower) + << TR("hasInternet", hasInternet) + << TR("isRoot", isRoot); + + Calamares::RequirementsList checkEntries; + foreach ( const QString& entry, m_entriesToCheck ) { - bool enoughStorage = false; - bool enoughRam = false; - bool hasPower = false; - bool hasInternet = false; - bool isRoot = false; - bool enoughScreen = (availableSize.width() >= CalamaresUtils::windowMinimumWidth) && (availableSize.height() >= CalamaresUtils::windowMinimumHeight); - - qint64 requiredStorageB = CalamaresUtils::GiBtoBytes(m_requiredStorageGB); - cDebug() << "Need at least storage bytes:" << requiredStorageB; - if ( m_entriesToCheck.contains( "storage" ) ) - enoughStorage = checkEnoughStorage( requiredStorageB ); - - qint64 requiredRamB = CalamaresUtils::GiBtoBytes(m_requiredRamGB); - cDebug() << "Need at least ram bytes:" << requiredRamB; - if ( m_entriesToCheck.contains( "ram" ) ) - enoughRam = checkEnoughRam( requiredRamB ); - - if ( m_entriesToCheck.contains( "power" ) ) - hasPower = checkHasPower(); - - if ( m_entriesToCheck.contains( "internet" ) ) - hasInternet = checkHasInternet(); - - if ( m_entriesToCheck.contains( "root" ) ) - isRoot = checkIsRoot(); - - using TR = Logger::DebugRow; - - cDebug() << "RequirementsChecker output:" - << TR("enoughStorage", enoughStorage) - << TR("enoughRam", enoughRam) - << TR("hasPower", hasPower) - << TR("hasInternet", hasInternet) - << TR("isRoot", isRoot); - - QList< PrepareEntry > checkEntries; - foreach ( const QString& entry, m_entriesToCheck ) - { - if ( entry == "storage" ) - checkEntries.append( { - entry, - [this]{ return tr( "has at least %1 GB available drive space" ) - .arg( m_requiredStorageGB ); }, - [this]{ return tr( "There is not enough drive space. At least %1 GB is required." ) - .arg( m_requiredStorageGB ); }, - enoughStorage, - m_entriesToRequire.contains( entry ) - } ); - else if ( entry == "ram" ) - checkEntries.append( { - entry, - [this]{ return tr( "has at least %1 GB working memory" ) - .arg( m_requiredRamGB ); }, - [this]{ return tr( "The system does not have enough working memory. At least %1 GB is required." ) - .arg( m_requiredRamGB ); }, - enoughRam, - m_entriesToRequire.contains( entry ) - } ); - else if ( entry == "power" ) - checkEntries.append( { - entry, - [this]{ return tr( "is plugged in to a power source" ); }, - [this]{ return tr( "The system is not plugged in to a power source." ); }, - hasPower, - m_entriesToRequire.contains( entry ) - } ); - else if ( entry == "internet" ) - checkEntries.append( { - entry, - [this]{ return tr( "is connected to the Internet" ); }, - [this]{ return tr( "The system is not connected to the Internet." ); }, - hasInternet, - m_entriesToRequire.contains( entry ) - } ); - else if ( entry == "root" ) - checkEntries.append( { - entry, - [this]{ return QString(); }, //we hide it - [this]{ return tr( "The installer is not running with administrator rights." ); }, - isRoot, - m_entriesToRequire.contains( entry ) - } ); - else if ( entry == "screen" ) - checkEntries.append( { - entry, - [this]{ return QString(); }, // we hide it - [this]{ return tr( "The screen is too small to display the installer." ); }, - enoughScreen, - false - } ); - } - - m_actualWidget->init( checkEntries ); - m_widget->layout()->removeWidget( waitingWidget ); - waitingWidget->deleteLater(); - m_actualWidget->setParent( m_widget ); - m_widget->layout()->addWidget( m_actualWidget ); - - bool canGoNext = true; - foreach ( const PrepareEntry& entry, checkEntries ) - { - if ( !entry.checked && entry.required ) - { - canGoNext = false; - break; - } - } - m_verdict = canGoNext; - emit verdictChanged( m_verdict ); - - if ( canGoNext ) - detectFirmwareType(); - - timer->deleteLater(); - } ); - timer->start( 0 ); - - emit verdictChanged( true ); -} - - -RequirementsChecker::~RequirementsChecker() -{ - if ( m_widget && m_widget->parent() == nullptr ) - m_widget->deleteLater(); -} - - -QWidget* -RequirementsChecker::widget() const -{ - return m_widget; + if ( entry == "storage" ) + checkEntries.append( { + entry, + [this]{ return tr( "has at least %1 GB available drive space" ) + .arg( m_requiredStorageGB ); }, + [this]{ return tr( "There is not enough drive space. At least %1 GB is required." ) + .arg( m_requiredStorageGB ); }, + enoughStorage, + m_entriesToRequire.contains( entry ) + } ); + else if ( entry == "ram" ) + checkEntries.append( { + entry, + [this]{ return tr( "has at least %1 GB working memory" ) + .arg( m_requiredRamGB ); }, + [this]{ return tr( "The system does not have enough working memory. At least %1 GB is required." ) + .arg( m_requiredRamGB ); }, + enoughRam, + m_entriesToRequire.contains( entry ) + } ); + else if ( entry == "power" ) + checkEntries.append( { + entry, + [this]{ return tr( "is plugged in to a power source" ); }, + [this]{ return tr( "The system is not plugged in to a power source." ); }, + hasPower, + m_entriesToRequire.contains( entry ) + } ); + else if ( entry == "internet" ) + checkEntries.append( { + entry, + [this]{ return tr( "is connected to the Internet" ); }, + [this]{ return tr( "The system is not connected to the Internet." ); }, + hasInternet, + m_entriesToRequire.contains( entry ) + } ); + else if ( entry == "root" ) + checkEntries.append( { + entry, + [this]{ return QString(); }, //we hide it + [this]{ return tr( "The installer is not running with administrator rights." ); }, + isRoot, + m_entriesToRequire.contains( entry ) + } ); + else if ( entry == "screen" ) + checkEntries.append( { + entry, + [this]{ return QString(); }, // we hide it + [this]{ return tr( "The screen is too small to display the installer." ); }, + enoughScreen, + false + } ); + } + return checkEntries; } void -RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap ) +GeneralRequirements::setConfigurationMap( const QVariantMap& configurationMap ) { bool incompleteConfiguration = false; @@ -222,7 +171,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap ) } else { - cWarning() << "RequirementsChecker entry 'check' is incomplete."; + cWarning() << "GeneralRequirements entry 'check' is incomplete."; incompleteConfiguration = true; } @@ -234,14 +183,25 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap ) } else { - cWarning() << "RequirementsChecker entry 'required' is incomplete."; + cWarning() << "GeneralRequirements entry 'required' is incomplete."; incompleteConfiguration = true; } +#ifdef WITHOUT_LIBPARTED + if ( m_entriesToCheck.contains( "storage" ) || m_entriesToRequire.contains( "storage" ) ) + { + // Warn, but also drop the required bit because otherwise installation + // will be impossible (because the check always returns false). + cWarning() << "GeneralRequirements checks 'storage' but libparted is disabled."; + m_entriesToCheck.removeAll( "storage" ); + m_entriesToRequire.removeAll( "storage" ); + } +#endif + // Help out with consistency, but don't fix for ( const auto& r : m_entriesToRequire ) if ( !m_entriesToCheck.contains( r ) ) - cWarning() << "RequirementsChecker requires" << r << "but does not check it."; + cWarning() << "GeneralRequirements requires" << r << "but does not check it."; if ( configurationMap.contains( "requiredStorage" ) && ( configurationMap.value( "requiredStorage" ).type() == QVariant::Double || @@ -251,7 +211,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap ) m_requiredStorageGB = configurationMap.value( "requiredStorage" ).toDouble( &ok ); if ( !ok ) { - cWarning() << "RequirementsChecker entry 'requiredStorage' is invalid."; + cWarning() << "GeneralRequirements entry 'requiredStorage' is invalid."; m_requiredStorageGB = 3.; } @@ -259,7 +219,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap ) } else { - cWarning() << "RequirementsChecker entry 'requiredStorage' is missing."; + cWarning() << "GeneralRequirements entry 'requiredStorage' is missing."; m_requiredStorageGB = 3.; incompleteConfiguration = true; } @@ -272,14 +232,14 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap ) m_requiredRamGB = configurationMap.value( "requiredRam" ).toDouble( &ok ); if ( !ok ) { - cWarning() << "RequirementsChecker entry 'requiredRam' is invalid."; + cWarning() << "GeneralRequirements entry 'requiredRam' is invalid."; m_requiredRamGB = 1.; incompleteConfiguration = true; } } else { - cWarning() << "RequirementsChecker entry 'requiredRam' is missing."; + cWarning() << "GeneralRequirements entry 'requiredRam' is missing."; m_requiredRamGB = 1.; incompleteConfiguration = true; } @@ -291,7 +251,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap ) if ( m_checkHasInternetUrl.isEmpty() || !QUrl( m_checkHasInternetUrl ).isValid() ) { - cWarning() << "RequirementsChecker entry 'internetCheckUrl' is invalid in welcome.conf" << m_checkHasInternetUrl + cWarning() << "GeneralRequirements entry 'internetCheckUrl' is invalid in welcome.conf" << m_checkHasInternetUrl << "reverting to default (http://example.com)."; m_checkHasInternetUrl = "http://example.com"; incompleteConfiguration = true; @@ -299,7 +259,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap ) } else { - cWarning() << "RequirementsChecker entry 'internetCheckUrl' is undefined in welcome.conf," + cWarning() << "GeneralRequirements entry 'internetCheckUrl' is undefined in welcome.conf," "reverting to default (http://example.com)."; m_checkHasInternetUrl = "http://example.com"; @@ -308,24 +268,17 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap ) if ( incompleteConfiguration ) { - cWarning() << "RequirementsChecker configuration map:" << Logger::DebugMap( configurationMap ); + cWarning() << "GeneralRequirements configuration map:" << Logger::DebugMap( configurationMap ); } } bool -RequirementsChecker::verdict() const -{ - return m_verdict; -} - - -bool -RequirementsChecker::checkEnoughStorage( qint64 requiredSpace ) +GeneralRequirements::checkEnoughStorage( qint64 requiredSpace ) { #ifdef WITHOUT_LIBPARTED Q_UNUSED( requiredSpace ); - cWarning() << "RequirementsChecker is configured without libparted."; + cWarning() << "GeneralRequirements is configured without libparted."; return false; #else return check_big_enough( requiredSpace ); @@ -334,7 +287,7 @@ RequirementsChecker::checkEnoughStorage( qint64 requiredSpace ) bool -RequirementsChecker::checkEnoughRam( qint64 requiredRam ) +GeneralRequirements::checkEnoughRam( qint64 requiredRam ) { // Ignore the guesstimate-factor; we get an under-estimate // which is probably the usable RAM for programs. @@ -344,7 +297,7 @@ RequirementsChecker::checkEnoughRam( qint64 requiredRam ) bool -RequirementsChecker::checkBatteryExists() +GeneralRequirements::checkBatteryExists() { const QFileInfo basePath( "/sys/class/power_supply" ); @@ -370,7 +323,7 @@ RequirementsChecker::checkBatteryExists() bool -RequirementsChecker::checkHasPower() +GeneralRequirements::checkHasPower() { const QString UPOWER_SVC_NAME( "org.freedesktop.UPower" ); const QString UPOWER_INTF_NAME( "org.freedesktop.UPower" ); @@ -401,10 +354,10 @@ RequirementsChecker::checkHasPower() bool -RequirementsChecker::checkHasInternet() +GeneralRequirements::checkHasInternet() { // default to true in the QNetworkAccessManager::UnknownAccessibility case - QNetworkAccessManager qnam( this ); + QNetworkAccessManager qnam; bool hasInternet = qnam.networkAccessible() == QNetworkAccessManager::Accessible; if ( !hasInternet && qnam.networkAccessible() == QNetworkAccessManager::UnknownAccessibility ) @@ -425,14 +378,14 @@ RequirementsChecker::checkHasInternet() bool -RequirementsChecker::checkIsRoot() +GeneralRequirements::checkIsRoot() { return !geteuid(); } void -RequirementsChecker::detectFirmwareType() +GeneralRequirements::detectFirmwareType() { QString fwType = QFile::exists( "/sys/firmware/efi/efivars" ) ? "efi" : "bios"; Calamares::JobQueue::instance()->globalStorage()->insert( "firmwareType", fwType ); diff --git a/src/modules/welcome/checker/RequirementsChecker.h b/src/modules/welcome/checker/GeneralRequirements.h similarity index 53% rename from src/modules/welcome/checker/RequirementsChecker.h rename to src/modules/welcome/checker/GeneralRequirements.h index ceb4eb209..0e3e341b0 100644 --- a/src/modules/welcome/checker/RequirementsChecker.h +++ b/src/modules/welcome/checker/GeneralRequirements.h @@ -17,52 +17,23 @@ * along with Calamares. If not, see . */ -#ifndef REQUIREMENTSCHECKER_H -#define REQUIREMENTSCHECKER_H +#ifndef GENERALREQUIREMENTS_H +#define GENERALREQUIREMENTS_H #include #include -#include +#include "modulesystem/Requirement.h" -class CheckerWidget; -class QWidget; - -/** - * An indication of a requirement, which is checked in preparation - * for system installation. An entry has a name and some explanation, - * as well as three meaningful states: - * - checked = true, the requirement is met (green) - * - checked = false, the requirement is not met - * - required = false, warn about it (yellow), no failure - * - required = true, prohibit installation (red) - */ -struct PrepareEntry -{ - QString name; - std::function< QString() > enumerationText; //Partial string, inserted in a - //list of requirements to satisfy. - std::function< QString() > negatedText; //Complete sentence about this requirement - //not having been met. - bool checked; - bool required; -}; - -class RequirementsChecker : public QObject +class GeneralRequirements : public QObject { Q_OBJECT public: - explicit RequirementsChecker( QObject* parent = nullptr ); - virtual ~RequirementsChecker(); - - QWidget* widget() const; + explicit GeneralRequirements( QObject* parent = nullptr ); void setConfigurationMap( const QVariantMap& configurationMap ); - bool verdict() const; - -signals: - void verdictChanged( bool ); + Calamares::RequirementsList checkRequirements(); private: QStringList m_entriesToCheck; @@ -76,13 +47,9 @@ private: bool checkIsRoot(); void detectFirmwareType(); - QWidget* m_widget; qreal m_requiredStorageGB; qreal m_requiredRamGB; QString m_checkHasInternetUrl; - - CheckerWidget* m_actualWidget; - bool m_verdict; }; #endif // REQUIREMENTSCHECKER_H diff --git a/src/modules/welcome/checker/CheckItemWidget.cpp b/src/modules/welcome/checker/ResultWidget.cpp similarity index 66% rename from src/modules/welcome/checker/CheckItemWidget.cpp rename to src/modules/welcome/checker/ResultWidget.cpp index ef0905100..3c3af62d4 100644 --- a/src/modules/welcome/checker/CheckItemWidget.cpp +++ b/src/modules/welcome/checker/ResultWidget.cpp @@ -1,7 +1,7 @@ /* === This file is part of Calamares - === * * Copyright 2014-2015, Teo Mrnjavac - * Copyright 2017, Adriaan de Groot + * Copyright 2017, 2019, Adriaan de Groot * * Calamares is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ * along with Calamares. If not, see . */ -#include "CheckItemWidget.h" +#include "ResultWidget.h" #include "utils/CalamaresUtilsGui.h" #include "utils/Logger.h" @@ -26,14 +26,15 @@ static inline void setCondition( QLabel* label, CalamaresUtils::ImageType t ) { - label->setPixmap( CalamaresUtils::defaultPixmap( t, - CalamaresUtils::Original, - QSize( label->height(), label->height() ) ) ); + label->setPixmap( + CalamaresUtils::defaultPixmap( t, + CalamaresUtils::Original, + QSize( label->height(), label->height() ) ) ); } -CheckItemWidget::CheckItemWidget( bool checked, - bool required, - QWidget* parent ) +ResultWidget::ResultWidget( bool satisfied, + bool required, + QWidget* parent ) : QWidget( parent ) { QBoxLayout* mainLayout = new QHBoxLayout; @@ -46,19 +47,17 @@ CheckItemWidget::CheckItemWidget( bool checked, mainLayout->addWidget( m_textLabel ); m_textLabel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); - if ( checked ) - // Condition is satisfied + if ( satisfied ) setCondition( m_iconLabel, CalamaresUtils::StatusOk ); + else if ( required ) + setCondition( m_iconLabel, CalamaresUtils::StatusError ); else - if ( required ) - setCondition( m_iconLabel, CalamaresUtils::StatusError ); - else - setCondition( m_iconLabel, CalamaresUtils::StatusWarning ); + setCondition( m_iconLabel, CalamaresUtils::StatusWarning ); } void -CheckItemWidget::setText( const QString& text ) +ResultWidget::setText( const QString& text ) { m_textLabel->setText( text ); } diff --git a/src/modules/welcome/checker/ResultWidget.h b/src/modules/welcome/checker/ResultWidget.h new file mode 100644 index 000000000..d842339ef --- /dev/null +++ b/src/modules/welcome/checker/ResultWidget.h @@ -0,0 +1,51 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014-2015, Teo Mrnjavac + * Copyright 2017, 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +#ifndef CHECKER_RESULTWIDGET_H +#define CHECKER_RESULTWIDGET_H + +#include + +/** + * @brief Displays the results of a single check. + * + * Widget to insert into a ResultListWidget to display an iconic status + * (warning or failure when the check is not satisfied) along with + * descriptive test. + */ +class ResultWidget : public QWidget +{ + Q_OBJECT +public: + /** + * @brief Create widget with results of a check. + * + * Use setText() to set up the text of the widget. + */ + explicit ResultWidget( bool satisfied, bool required, + QWidget* parent = nullptr ); + + /// @brief Set the displayed description of the check. + void setText( const QString& text ); +private: + QLabel* m_textLabel; + QLabel* m_iconLabel; +}; + +#endif // CHECKER_RESULTWIDGET_H diff --git a/src/modules/welcome/checker/CheckerWidget.cpp b/src/modules/welcome/checker/ResultsListWidget.cpp similarity index 83% rename from src/modules/welcome/checker/CheckerWidget.cpp rename to src/modules/welcome/checker/ResultsListWidget.cpp index 07a612a9f..5908e4bf5 100644 --- a/src/modules/welcome/checker/CheckerWidget.cpp +++ b/src/modules/welcome/checker/ResultsListWidget.cpp @@ -1,7 +1,7 @@ /* === This file is part of Calamares - === * * Copyright 2014-2015, Teo Mrnjavac - * Copyright 2017, Adriaan de Groot + * Copyright 2017, 2019, Adriaan de Groot * * Calamares is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,9 +17,9 @@ * along with Calamares. If not, see . */ -#include "CheckerWidget.h" +#include "ResultsListWidget.h" -#include "CheckItemWidget.h" +#include "ResultWidget.h" #include "Branding.h" #include "utils/CalamaresUtilsGui.h" @@ -33,7 +33,7 @@ #include -CheckerWidget::CheckerWidget( QWidget* parent ) +ResultsListWidget::ResultsListWidget( QWidget* parent ) : QWidget( parent ) { setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); @@ -53,25 +53,23 @@ CheckerWidget::CheckerWidget( QWidget* parent ) void -CheckerWidget::init( const QList< PrepareEntry >& checkEntries ) +ResultsListWidget::init( const Calamares::RequirementsList& checkEntries ) { bool allChecked = true; bool requirementsSatisfied = true; - for ( const PrepareEntry& entry : checkEntries ) + for ( const auto& entry : checkEntries ) { - if ( !entry.checked ) + if ( !entry.satisfied ) { - CheckItemWidget* ciw = new CheckItemWidget( entry.checked, entry.required ); + ResultWidget* ciw = new ResultWidget( entry.satisfied, entry.mandatory ); CALAMARES_RETRANSLATE( ciw->setText( entry.negatedText() ); ) m_entriesLayout->addWidget( ciw ); ciw->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); allChecked = false; - if ( entry.required ) - { + if ( entry.mandatory ) requirementsSatisfied = false; - } ciw->setAutoFillBackground( true ); QPalette pal( ciw->palette() ); pal.setColor( QPalette::Background, Qt::white ); @@ -97,7 +95,7 @@ CheckerWidget::init( const QList< PrepareEntry >& checkEntries ) "requirements for installing %1.
" "Installation cannot continue. " "Details..." ) - .arg( *Calamares::Branding::ShortVersionedName ) ); + .arg( *Calamares::Branding::ShortVersionedName ) ); ) textLabel->setOpenExternalLinks( false ); connect( textLabel, &QLabel::linkActivated, @@ -114,7 +112,7 @@ CheckerWidget::init( const QList< PrepareEntry >& checkEntries ) "recommended requirements for installing %1.
" "Installation can continue, but some features " "might be disabled." ) - .arg( *Calamares::Branding::ShortVersionedName ) ); + .arg( *Calamares::Branding::ShortVersionedName ) ); ) } } @@ -122,16 +120,16 @@ CheckerWidget::init( const QList< PrepareEntry >& checkEntries ) if ( allChecked && requirementsSatisfied ) { if ( !Calamares::Branding::instance()-> - imagePath( Calamares::Branding::ProductWelcome ).isEmpty() ) + imagePath( Calamares::Branding::ProductWelcome ).isEmpty() ) { QPixmap theImage = QPixmap( Calamares::Branding::instance()-> - imagePath( Calamares::Branding::ProductWelcome ) ); + imagePath( Calamares::Branding::ProductWelcome ) ); if ( !theImage.isNull() ) { QLabel* imageLabel; if ( Calamares::Branding::instance()->welcomeExpandingLogo() ) { - FixedAspectRatioLabel *p = new FixedAspectRatioLabel; + FixedAspectRatioLabel* p = new FixedAspectRatioLabel; p->setPixmap( theImage ); imageLabel = p; } @@ -155,14 +153,12 @@ CheckerWidget::init( const QList< PrepareEntry >& checkEntries ) ) } else - { m_mainLayout->addStretch(); - } } void -CheckerWidget::showDetailsDialog( const QList< PrepareEntry >& checkEntries ) +ResultsListWidget::showDetailsDialog( const Calamares::RequirementsList& checkEntries ) { QDialog* detailsDialog = new QDialog( this ); QBoxLayout* mainLayout = new QVBoxLayout; @@ -177,12 +173,12 @@ CheckerWidget::showDetailsDialog( const QList< PrepareEntry >& checkEntries ) CalamaresUtils::unmarginLayout( entriesLayout ); mainLayout->addLayout( entriesLayout ); - for ( const PrepareEntry& entry : checkEntries ) + for ( const auto& entry : checkEntries ) { - if ( entry.enumerationText().isEmpty() ) + if ( !entry.hasDetails() ) continue; - CheckItemWidget* ciw = new CheckItemWidget( entry.checked, entry.required ); + ResultWidget* ciw = new ResultWidget( entry.satisfied, entry.mandatory ); CALAMARES_RETRANSLATE( ciw->setText( entry.enumerationText() ); ) entriesLayout->addWidget( ciw ); ciw->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); @@ -194,8 +190,8 @@ CheckerWidget::showDetailsDialog( const QList< PrepareEntry >& checkEntries ) } QDialogButtonBox* buttonBox = new QDialogButtonBox( QDialogButtonBox::Close, - Qt::Horizontal, - this ); + Qt::Horizontal, + this ); mainLayout->addWidget( buttonBox ); detailsDialog->setModal( true ); diff --git a/src/modules/welcome/checker/CheckerWidget.h b/src/modules/welcome/checker/ResultsListWidget.h similarity index 68% rename from src/modules/welcome/checker/CheckerWidget.h rename to src/modules/welcome/checker/ResultsListWidget.h index 8081e4ee4..3be02b0d0 100644 --- a/src/modules/welcome/checker/CheckerWidget.h +++ b/src/modules/welcome/checker/ResultsListWidget.h @@ -1,6 +1,7 @@ /* === This file is part of Calamares - === * * Copyright 2014-2015, Teo Mrnjavac + * Copyright 2019, Adriaan de Groot * * Calamares is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,28 +17,28 @@ * along with Calamares. If not, see . */ -#ifndef CHECKERWIDGET_H -#define CHECKERWIDGET_H +#ifndef CHECKER_RESULTSLISTWIDGET_H +#define CHECKER_RESULTSLISTWIDGET_H -#include "RequirementsChecker.h" +#include "modulesystem/Requirement.h" #include #include -class CheckerWidget : public QWidget +class ResultsListWidget : public QWidget { Q_OBJECT public: - explicit CheckerWidget( QWidget* parent = nullptr ); + explicit ResultsListWidget( QWidget* parent = nullptr ); - void init( const QList< PrepareEntry >& checkEntries ); + void init( const Calamares::RequirementsList& checkEntries ); private: - void showDetailsDialog( const QList< PrepareEntry >& checkEntries ); + void showDetailsDialog( const Calamares::RequirementsList& checkEntries ); QBoxLayout* m_mainLayout; QBoxLayout* m_entriesLayout; int m_paddingSize; }; -#endif // CHECKERWIDGET_H +#endif // CHECKER_RESULTSLISTWIDGET_H diff --git a/src/modules/welcome/welcome.conf b/src/modules/welcome/welcome.conf index b7ce5cfcd..52492ffef 100644 --- a/src/modules/welcome/welcome.conf +++ b/src/modules/welcome/welcome.conf @@ -1,18 +1,37 @@ +# Configuration for the welcome module. The welcome page +# displays some information from the branding file. +# Which parts it displays can be configured through +# the show* variables. +# +# In addition to displaying the welcome page, this module +# can check requirements for installation. --- +# Display settings for various buttons on the welcome page. showSupportUrl: true showKnownIssuesUrl: true showReleaseNotesUrl: true +# Requirements checking. These are general, generic, things +# that are checked. They may not match with the actual requirements +# imposed by other modules in the system. requirements: + # Amount of available disk, in GB. Floating-point is allowed here. + # Note that this does not account for *usable* disk, so it is possible + # to pass this requirement, yet have no space to install to. requiredStorage: 5.5 + + # Amount of available RAM, in GB. Floating-point is allowed here. requiredRam: 1.0 + + # To check for internet connectivity, Calamares does a HTTP GET + # on this URL; on success (e.g. HTTP code 200) internet is OK. internetCheckUrl: http://google.com # List conditions to check. Each listed condition will be # probed in some way, and yields true or false according to # the host system satisfying the condition. # - # This sample file lists all the conditions that are know. + # This sample file lists all the conditions that are known. check: - storage - ram @@ -20,7 +39,7 @@ requirements: - internet - root - screen - # List conditions that must be satisfied (from the list + # List conditions that **must** be satisfied (from the list # of conditions, above) for installation to proceed. # If any of these conditions are not met, the user cannot # continue past the welcome page.