Merge branch 'master' of https://github.com/calamares/calamares into development

This commit is contained in:
Philip Müller 2019-02-26 18:15:19 +01:00
commit afa70e1944
54 changed files with 928 additions and 543 deletions

13
CHANGES
View File

@ -6,16 +6,29 @@ website will have to do for older versions.
# 3.2.5 (unreleased) # # 3.2.5 (unreleased) #
This release contains contributions from (alphabetically by first name): This release contains contributions from (alphabetically by first name):
- Arnaud Ferraris
- Dan Simmons
## Core ## ## 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 ## ## 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 * Python modules: several modules have had translations added. This is
usually only visible when the module runs as part of the *exec* step, usually only visible when the module runs as part of the *exec* step,
when the module's *pretty name* is displayed. In addition, error when the module's *pretty name* is displayed. In addition, error
messages are now translated. messages are now translated.
# 3.2.4 (2019-02-12) # # 3.2.4 (2019-02-12) #
This release contains contributions from (alphabetically by first name): This release contains contributions from (alphabetically by first name):

View File

@ -348,6 +348,7 @@ void
CalamaresApplication::initViewSteps() CalamaresApplication::initViewSteps()
{ {
cDebug() << "STARTUP: loadModules for all modules done"; cDebug() << "STARTUP: loadModules for all modules done";
m_moduleManager->checkRequirements();
if ( Calamares::Branding::instance()->windowMaximize() ) if ( Calamares::Branding::instance()->windowMaximize() )
{ {
m_mainwindow->setWindowFlag( Qt::FramelessWindowHint ); m_mainwindow->setWindowFlag( Qt::FramelessWindowHint );
@ -355,6 +356,7 @@ CalamaresApplication::initViewSteps()
} }
else else
m_mainwindow->show(); m_mainwindow->show();
ProgressTreeModel* m = new ProgressTreeModel( nullptr ); ProgressTreeModel* m = new ProgressTreeModel( nullptr );
ProgressTreeView::instance()->setModel( m ); ProgressTreeView::instance()->setModel( m );
cDebug() << "STARTUP: Window now visible and ProgressTreeView populated"; cDebug() << "STARTUP: Window now visible and ProgressTreeView populated";

View File

@ -5,6 +5,8 @@ set( calamaresui_SOURCES
modulesystem/Module.cpp modulesystem/Module.cpp
modulesystem/ModuleManager.cpp modulesystem/ModuleManager.cpp
modulesystem/ProcessJobModule.cpp modulesystem/ProcessJobModule.cpp
modulesystem/Requirement.cpp
modulesystem/RequirementsChecker.cpp
modulesystem/ViewModule.cpp modulesystem/ViewModule.cpp
utils/CalamaresUtilsGui.cpp utils/CalamaresUtilsGui.cpp

View File

@ -281,4 +281,10 @@ Module::initFrom( const QVariantMap& moduleDescriptor )
m_maybe_emergency = moduleDescriptor[ EMERGENCY ].toBool(); m_maybe_emergency = moduleDescriptor[ EMERGENCY ].toBool();
} }
RequirementsList
Module::checkRequirements()
{
return RequirementsList();
}
} //ns } //ns

View File

@ -1,6 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org> * Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,6 +20,7 @@
#ifndef CALAMARES_MODULE_H #ifndef CALAMARES_MODULE_H
#define CALAMARES_MODULE_H #define CALAMARES_MODULE_H
#include "Requirement.h"
#include "UiDllMacro.h" #include "UiDllMacro.h"
#include <Typedefs.h> #include <Typedefs.h>
@ -178,6 +180,11 @@ public:
*/ */
QVariantMap configurationMap(); QVariantMap configurationMap();
/**
* @brief Check the requirements of this module.
*/
virtual RequirementsList checkRequirements();
protected: protected:
explicit Module(); explicit Module();
virtual void initFrom( const QVariantMap& moduleDescriptor ); virtual void initFrom( const QVariantMap& moduleDescriptor );

View File

@ -21,26 +21,23 @@
#include "ExecutionViewStep.h" #include "ExecutionViewStep.h"
#include "Module.h" #include "Module.h"
#include "utils/Logger.h" #include "RequirementsChecker.h"
#include "utils/YamlUtils.h"
#include "Settings.h" #include "Settings.h"
#include "ViewManager.h" #include "ViewManager.h"
#include "utils/Logger.h"
#include "utils/YamlUtils.h"
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>
#include <QApplication> #include <QApplication>
#include <QDir> #include <QDir>
#include <QTimer> #include <QTimer>
#define MODULE_CONFIG_FILENAME "module.desc"
namespace Calamares namespace Calamares
{ {
ModuleManager* ModuleManager::s_instance = nullptr; ModuleManager* ModuleManager::s_instance = nullptr;
ModuleManager* ModuleManager*
ModuleManager::instance() ModuleManager::instance()
{ {
@ -94,7 +91,7 @@ ModuleManager::doInit()
bool success = currentDir.cd( subdir ); bool success = currentDir.cd( subdir );
if ( success ) if ( success )
{ {
QFileInfo descriptorFileInfo( currentDir.absoluteFilePath( MODULE_CONFIG_FILENAME ) ); QFileInfo descriptorFileInfo( currentDir.absoluteFilePath( QLatin1Literal( "module.desc") ) );
if ( ! ( descriptorFileInfo.exists() && descriptorFileInfo.isReadable() ) ) if ( ! ( descriptorFileInfo.exists() && descriptorFileInfo.isReadable() ) )
{ {
cDebug() << Q_FUNC_INFO << "unreadable file: " 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 QStringList
ModuleManager::checkDependencies() ModuleManager::checkDependencies()
@ -334,8 +351,6 @@ ModuleManager::checkDependencies()
break; break;
} }
} }
if ( somethingWasRemovedBecauseOfUnmetDependencies )
break;
} }
if ( !somethingWasRemovedBecauseOfUnmetDependencies ) if ( !somethingWasRemovedBecauseOfUnmetDependencies )
break; break;
@ -369,4 +384,4 @@ ModuleManager::checkDependencies( const Module& m )
return allRequirementsFound; return allRequirementsFound;
} }
} } // namespace

View File

@ -20,6 +20,7 @@
#ifndef MODULELOADER_H #ifndef MODULELOADER_H
#define MODULELOADER_H #define MODULELOADER_H
#include "Requirement.h"
#include "Typedefs.h" #include "Typedefs.h"
#include <QObject> #include <QObject>
@ -30,6 +31,7 @@ namespace Calamares
{ {
class Module; class Module;
struct RequirementEntry; // from Requirement.h
/** /**
* @brief The ModuleManager class is a singleton which manages Calamares modules. * @brief The ModuleManager class is a singleton which manages Calamares modules.
@ -81,10 +83,20 @@ public:
*/ */
void loadModules(); void loadModules();
/**
* @brief Starts asynchronous requirements checking for each module.
* When this is done, the signal modulesChecked is emitted.
*/
void checkRequirements();
signals: signals:
void initDone(); void initDone();
void modulesLoaded(); /// All of the modules were loaded successfully void modulesLoaded(); /// All of the modules were loaded successfully
void modulesFailed( QStringList ); /// .. or not void modulesFailed( QStringList ); /// .. or not
// Below, see RequirementsChecker documentation
void requirementsComplete( bool );
void requirementsResult( RequirementsList );
void requirementsProgress( const QString& );
private slots: private slots:
void doInit(); void doInit();

View File

@ -1,6 +1,5 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <http://github.com/calamares> ===
* *
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org> * Copyright 2017, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * 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 * You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Requirement.h"
#ifndef CHECKITEMWIDGET_H
#define CHECKITEMWIDGET_H
#include <QLabel>
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

View File

@ -0,0 +1,67 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2017, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef CALAMARES_REQUIREMENT_H
#define CALAMARES_REQUIREMENT_H
#include <QList>
#include <QMetaType>
#include <QString>
#include <functional>
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

View File

@ -0,0 +1,154 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "RequirementsChecker.h"
#include "Module.h"
#include "Requirement.h"
#include "utils/Logger.h"
#include <algorithm>
#include <QtConcurrent/QtConcurrent>
#include <QFuture>
#include <QFutureWatcher>
#include <QTimer>
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<RequirementEntry> 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<RequirementEntry>" );
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 <i>%1</i> 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." ) );
}
}

View File

@ -0,0 +1,87 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef CALAMARES_REQUIREMENTSCHECKER_H
#define CALAMARES_REQUIREMENTSCHECKER_H
#include "Requirement.h"
#include <QFutureWatcher>
#include <QObject>
#include <QTimer>
#include <QVector>
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

View File

@ -132,4 +132,10 @@ ViewModule::~ViewModule()
delete m_loader; delete m_loader;
} }
RequirementsList
ViewModule::checkRequirements()
{
return m_viewStep->checkRequirements();
}
} // namespace Calamares } // namespace Calamares

View File

@ -39,6 +39,8 @@ public:
void loadSelf() override; void loadSelf() override;
JobList jobs() const override; JobList jobs() const override;
RequirementsList checkRequirements() override;
protected: protected:
void initFrom( const QVariantMap& moduleDescriptor ) override; void initFrom( const QVariantMap& moduleDescriptor ) override;

View File

@ -52,6 +52,14 @@ void
ViewStep::onLeave() ViewStep::onLeave()
{} {}
void
ViewStep::next()
{}
void
ViewStep::back()
{}
void void
ViewStep::setModuleInstanceKey( const QString& instanceKey ) ViewStep::setModuleInstanceKey( const QString& instanceKey )
@ -66,4 +74,10 @@ ViewStep::setConfigurationMap( const QVariantMap& configurationMap )
Q_UNUSED( configurationMap ); Q_UNUSED( configurationMap );
} }
RequirementsList ViewStep::checkRequirements()
{
return RequirementsList();
}
} }

View File

@ -22,6 +22,7 @@
#include <QObject> #include <QObject>
#include "modulesystem/Requirement.h"
#include "../UiDllMacro.h" #include "../UiDllMacro.h"
#include "Typedefs.h" #include "Typedefs.h"
@ -68,13 +69,39 @@ public:
//TODO: we might want to make this a QSharedPointer //TODO: we might want to make this a QSharedPointer
virtual QWidget* widget() = 0; 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; virtual bool isNextEnabled() const = 0;
/// @brief Can the user click *previous* with currently-filled-in data?
virtual bool isBackEnabled() const = 0; 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; virtual bool isAtBeginning() const = 0;
/// @brief Multi-page support, switch to next view step?
virtual bool isAtEnd() const = 0; virtual bool isAtEnd() const = 0;
/** /**
@ -91,6 +118,12 @@ public:
*/ */
virtual void onLeave(); 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; virtual JobList jobs() const = 0;
void setModuleInstanceKey( const QString& instanceKey ); void setModuleInstanceKey( const QString& instanceKey );
@ -101,9 +134,18 @@ public:
virtual void setConfigurationMap( const QVariantMap& configurationMap ); 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: signals:
/// @brief Tells the viewmanager to enable the *next* button according to @p status
void nextStatusChanged( bool status ); void nextStatusChanged( bool status );
void done();
/* Emitted when the viewstep thinks it needs more space than is currently /* Emitted when the viewstep thinks it needs more space than is currently
* available for display. @p enlarge is the requested additional space, * available for display. @p enlarge is the requested additional space,

View File

@ -67,18 +67,6 @@ FinishedViewStep::widget()
} }
void
FinishedViewStep::next()
{
emit done();
}
void
FinishedViewStep::back()
{}
bool bool
FinishedViewStep::isNextEnabled() const FinishedViewStep::isNextEnabled() const
{ {

View File

@ -40,9 +40,6 @@ public:
QWidget* widget() override; QWidget* widget() override;
void next() override;
void back() override;
bool isNextEnabled() const override; bool isNextEnabled() const override;
bool isBackEnabled() const override; bool isBackEnabled() const override;

View File

@ -53,18 +53,6 @@ InteractiveTerminalViewStep::widget()
} }
void
InteractiveTerminalViewStep::next()
{
emit done();
}
void
InteractiveTerminalViewStep::back()
{}
bool bool
InteractiveTerminalViewStep::isNextEnabled() const InteractiveTerminalViewStep::isNextEnabled() const
{ {

View File

@ -41,9 +41,6 @@ public:
QWidget* widget() override; QWidget* widget() override;
void next() override;
void back() override;
bool isNextEnabled() const override; bool isNextEnabled() const override;
bool isBackEnabled() const override; bool isBackEnabled() const override;

View File

@ -65,19 +65,6 @@ KeyboardViewStep::widget()
} }
void
KeyboardViewStep::next()
{
//TODO: actually save those settings somewhere
emit done();
}
void
KeyboardViewStep::back()
{}
bool bool
KeyboardViewStep::isNextEnabled() const KeyboardViewStep::isNextEnabled() const
{ {

View File

@ -42,9 +42,6 @@ public:
QWidget* widget() override; QWidget* widget() override;
void next() override;
void back() override;
bool isNextEnabled() const override; bool isNextEnabled() const override;
bool isBackEnabled() const override; bool isBackEnabled() const override;

View File

@ -59,18 +59,6 @@ LicenseViewStep::widget()
} }
void
LicenseViewStep::next()
{
emit done();
}
void
LicenseViewStep::back()
{}
bool bool
LicenseViewStep::isNextEnabled() const LicenseViewStep::isNextEnabled() const
{ {

View File

@ -42,9 +42,6 @@ public:
QWidget* widget() override; QWidget* widget() override;
void next() override;
void back() override;
bool isNextEnabled() const override; bool isNextEnabled() const override;
bool isBackEnabled() const override; bool isBackEnabled() const override;

View File

@ -190,18 +190,6 @@ LocaleViewStep::widget()
} }
void
LocaleViewStep::next()
{
emit done();
}
void
LocaleViewStep::back()
{}
bool bool
LocaleViewStep::isNextEnabled() const LocaleViewStep::isNextEnabled() const
{ {

View File

@ -45,9 +45,6 @@ public:
QWidget* widget() override; QWidget* widget() override;
void next() override;
void back() override;
bool isNextEnabled() const override; bool isNextEnabled() const override;
bool isBackEnabled() const override; bool isBackEnabled() const override;

View File

@ -69,18 +69,6 @@ NetInstallViewStep::widget()
} }
void
NetInstallViewStep::next()
{
emit done();
}
void
NetInstallViewStep::back()
{}
bool bool
NetInstallViewStep::isNextEnabled() const NetInstallViewStep::isNextEnabled() const
{ {

View File

@ -42,9 +42,6 @@ public:
QWidget* widget() override; QWidget* widget() override;
void next() override;
void back() override;
bool isNextEnabled() const override; bool isNextEnabled() const override;
bool isBackEnabled() const override; bool isBackEnabled() const override;

View File

@ -882,11 +882,6 @@ ChoicePage::updateDeviceStatePreview()
PartitionModel* model = new PartitionModel( m_beforePartitionBarsView ); PartitionModel* model = new PartitionModel( m_beforePartitionBarsView );
model->init( deviceBefore, m_core->osproberEntries() ); 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_beforePartitionBarsView->setModel( model );
m_beforePartitionLabelsView->setModel( model ); m_beforePartitionLabelsView->setModel( model );

View File

@ -60,6 +60,8 @@
#include <QtConcurrent/QtConcurrent> #include <QtConcurrent/QtConcurrent>
#include <QFutureWatcher> #include <QFutureWatcher>
#include <unistd.h> // For sleep(3)
PartitionViewStep::PartitionViewStep( QObject* parent ) PartitionViewStep::PartitionViewStep( QObject* parent )
: Calamares::ViewStep( parent ) : Calamares::ViewStep( parent )
, m_core( nullptr ) , m_core( nullptr )
@ -213,8 +215,8 @@ PartitionViewStep::createSummaryWidget() const
else // multiple disk previews! else // multiple disk previews!
{ {
diskInfoLabel->setText( tr( "Disk <strong>%1</strong> (%2)" ) diskInfoLabel->setText( tr( "Disk <strong>%1</strong> (%2)" )
.arg( info.deviceNode ) .arg( info.deviceNode )
.arg( info.deviceName ) ); .arg( info.deviceName ) );
} }
formLayout->addRow( diskInfoLabel ); formLayout->addRow( diskInfoLabel );
@ -223,9 +225,9 @@ PartitionViewStep::createSummaryWidget() const
QVBoxLayout* field; QVBoxLayout* field;
PartitionBarsView::NestedPartitionsMode mode = Calamares::JobQueue::instance()->globalStorage()-> PartitionBarsView::NestedPartitionsMode mode = Calamares::JobQueue::instance()->globalStorage()->
value( "drawNestedPartitions" ).toBool() ? value( "drawNestedPartitions" ).toBool() ?
PartitionBarsView::DrawNestedPartitions : PartitionBarsView::DrawNestedPartitions :
PartitionBarsView::NoNestedPartitions; PartitionBarsView::NoNestedPartitions;
preview = new PartitionBarsView; preview = new PartitionBarsView;
preview->setNestedPartitionsMode( mode ); preview->setNestedPartitionsMode( mode );
previewLabels = new PartitionLabelsView; previewLabels = new PartitionLabelsView;
@ -263,7 +265,7 @@ PartitionViewStep::createSummaryWidget() const
foreach ( const Calamares::job_ptr& job, jobs() ) foreach ( const Calamares::job_ptr& job, jobs() )
{ {
if ( !job->prettyDescription().isEmpty() ) if ( !job->prettyDescription().isEmpty() )
jobsLines.append( job->prettyDescription() ); jobsLines.append( job->prettyDescription() );
} }
if ( !jobsLines.isEmpty() ) if ( !jobsLines.isEmpty() )
{ {
@ -292,25 +294,8 @@ PartitionViewStep::next()
if ( m_core->isDirty() ) if ( m_core->isDirty() )
m_manualPartitionPage->onRevertClicked(); 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(); 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 == m_widget->currentWidget() )
{ {
if ( m_choicePage->currentChoice() == ChoicePage::Erase || if ( m_choicePage->currentChoice() == ChoicePage::Erase ||
m_choicePage->currentChoice() == ChoicePage::Replace || m_choicePage->currentChoice() == ChoicePage::Replace ||
m_choicePage->currentChoice() == ChoicePage::Alongside ) m_choicePage->currentChoice() == ChoicePage::Alongside )
return true; return true;
return false; return false;
} }
@ -374,7 +359,7 @@ PartitionViewStep::onActivate()
{ {
// if we're coming back to PVS from the next VS // if we're coming back to PVS from the next VS
if ( m_widget->currentWidget() == m_choicePage && if ( m_widget->currentWidget() == m_choicePage &&
m_choicePage->currentChoice() == ChoicePage::Alongside ) m_choicePage->currentChoice() == ChoicePage::Alongside )
{ {
m_choicePage->applyActionChoice( ChoicePage::Alongside ); m_choicePage->applyActionChoice( ChoicePage::Alongside );
// m_choicePage->reset(); // m_choicePage->reset();
@ -397,7 +382,7 @@ PartitionViewStep::onLeave()
if ( PartUtils::isEfiSystem() ) if ( PartUtils::isEfiSystem() )
{ {
QString espMountPoint = Calamares::JobQueue::instance()->globalStorage()-> QString espMountPoint = Calamares::JobQueue::instance()->globalStorage()->
value( "efiSystemPartition").toString(); value( "efiSystemPartition" ).toString();
Partition* esp = m_core->findPartitionByMountPoint( espMountPoint ); Partition* esp = m_core->findPartitionByMountPoint( espMountPoint );
QString message; QString message;
@ -452,7 +437,7 @@ PartitionViewStep::onLeave()
// If the root partition is encrypted, and there's a separate boot // If the root partition is encrypted, and there's a separate boot
// partition which is not encrypted // partition which is not encrypted
if ( root_p->fileSystem().type() == FileSystem::Luks && 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" ); message = tr( "Boot partition not encrypted" );
description = tr( "A separate boot partition was set up together with " 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 // 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 // because it could take a while. Then when it's done, we can set up the widgets
// and remove the spinner. // and remove the spinner.
QFutureWatcher< void >* watcher = new QFutureWatcher< void >(); m_future = new QFutureWatcher< void >();
connect( watcher, &QFutureWatcher< void >::finished, connect( m_future, &QFutureWatcher< void >::finished,
this, [ this, watcher, choices ] this, [ this ]
{ {
continueLoading(); continueLoading();
watcher->deleteLater(); this->m_future->deleteLater();
this->m_future = nullptr;
} ); } );
QFuture< void > future = QFuture< void > future =
QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule ); QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule );
watcher->setFuture( future ); m_future->setFuture( future );
if ( configurationMap.contains( "partitionLayout" ) ) if ( configurationMap.contains( "partitionLayout" ) )
{ {
@ -630,5 +616,24 @@ PartitionViewStep::jobs() const
return m_core->jobs(); 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<PartitionViewStep>(); ) CALAMARES_PLUGIN_FACTORY_DEFINITION( PartitionViewStepFactory, registerPlugin<PartitionViewStep>(); )

View File

@ -36,6 +36,8 @@ class PartitionPage;
class PartitionCoreModule; class PartitionCoreModule;
class QStackedWidget; class QStackedWidget;
template<typename T> class QFutureWatcher;
/** /**
* The starting point of the module. Instantiates PartitionCoreModule, * The starting point of the module. Instantiates PartitionCoreModule,
* ChoicePage and PartitionPage, then connects them. * ChoicePage and PartitionPage, then connects them.
@ -69,6 +71,8 @@ public:
QList< Calamares::job_ptr > jobs() const override; QList< Calamares::job_ptr > jobs() const override;
Calamares::RequirementsList checkRequirements() override;
private: private:
void initPartitionCoreModule(); void initPartitionCoreModule();
void continueLoading(); void continueLoading();
@ -79,6 +83,7 @@ private:
PartitionPage* m_manualPartitionPage; PartitionPage* m_manualPartitionPage;
QWidget* m_waitingWidget; QWidget* m_waitingWidget;
QFutureWatcher<void>* m_future;
QSet< PartitionActions::Choices::SwapChoice > m_swapChoices; QSet< PartitionActions::Choices::SwapChoice > m_swapChoices;
}; };

View File

@ -76,18 +76,6 @@ PlasmaLnfViewStep::widget()
} }
void
PlasmaLnfViewStep::next()
{
emit done();
}
void
PlasmaLnfViewStep::back()
{}
bool bool
PlasmaLnfViewStep::isNextEnabled() const PlasmaLnfViewStep::isNextEnabled() const
{ {

View File

@ -41,9 +41,6 @@ public:
QWidget* widget() override; QWidget* widget() override;
void next() override;
void back() override;
bool isNextEnabled() const override; bool isNextEnabled() const override;
bool isBackEnabled() const override; bool isBackEnabled() const override;

View File

@ -51,18 +51,6 @@ SummaryViewStep::widget()
} }
void
SummaryViewStep::next()
{
emit done();
}
void
SummaryViewStep::back()
{}
bool bool
SummaryViewStep::isNextEnabled() const SummaryViewStep::isNextEnabled() const
{ {

View File

@ -40,9 +40,6 @@ public:
QWidget* widget() override; QWidget* widget() override;
void next() override;
void back() override;
bool isNextEnabled() const override; bool isNextEnabled() const override;
bool isBackEnabled() const override; bool isBackEnabled() const override;

View File

@ -67,18 +67,6 @@ TrackingViewStep::widget()
} }
void
TrackingViewStep::next()
{
emit done();
}
void
TrackingViewStep::back()
{}
bool bool
TrackingViewStep::isNextEnabled() const TrackingViewStep::isNextEnabled() const
{ {

View File

@ -43,9 +43,6 @@ public:
QWidget* widget() override; QWidget* widget() override;
void next() override;
void back() override;
bool isNextEnabled() const override; bool isNextEnabled() const override;
bool isBackEnabled() const override; bool isBackEnabled() const override;

View File

@ -61,18 +61,6 @@ UsersViewStep::widget()
} }
void
UsersViewStep::next()
{
emit done();
}
void
UsersViewStep::back()
{}
bool bool
UsersViewStep::isNextEnabled() const UsersViewStep::isNextEnabled() const
{ {

View File

@ -43,9 +43,6 @@ public:
QWidget* widget() override; QWidget* widget() override;
void next() override;
void back() override;
bool isNextEnabled() const override; bool isNextEnabled() const override;
bool isBackEnabled() const override; bool isBackEnabled() const override;

View File

@ -72,18 +72,6 @@ WebViewStep::widget()
} }
void
WebViewStep::next()
{
emit done();
}
void
WebViewStep::back()
{}
bool bool
WebViewStep::isNextEnabled() const WebViewStep::isNextEnabled() const
{ {

View File

@ -50,8 +50,6 @@ public:
QWidget* widget() override; QWidget* widget() override;
void next() override;
void back() override;
void onActivate() override; void onActivate() override;
bool isNextEnabled() const override; bool isNextEnabled() const override;

View File

@ -15,9 +15,10 @@ endif()
include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui ) include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui )
set( CHECKER_SOURCES set( CHECKER_SOURCES
checker/CheckItemWidget.cpp checker/CheckerContainer.cpp
checker/CheckerWidget.cpp checker/ResultWidget.cpp
checker/RequirementsChecker.cpp checker/ResultsListWidget.cpp
checker/GeneralRequirements.cpp
${PARTMAN_SRC} ${PARTMAN_SRC}
) )

View File

@ -22,10 +22,12 @@
#include "ui_WelcomePage.h" #include "ui_WelcomePage.h"
#include "CalamaresVersion.h" #include "CalamaresVersion.h"
#include "checker/RequirementsChecker.h" #include "checker/CheckerContainer.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/CalamaresUtilsGui.h" #include "utils/CalamaresUtilsGui.h"
#include "utils/Retranslator.h" #include "utils/Retranslator.h"
#include "modulesystem/ModuleManager.h"
#include "ViewManager.h" #include "ViewManager.h"
#include <QApplication> #include <QApplication>
@ -39,11 +41,14 @@
#include "Branding.h" #include "Branding.h"
WelcomePage::WelcomePage( RequirementsChecker* requirementsChecker, QWidget* parent ) WelcomePage::WelcomePage( QWidget* parent )
: QWidget( parent ) : QWidget( parent )
, ui( new Ui::WelcomePage ) , 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->setupUi( this );
ui->verticalLayout->insertSpacing( 1, CalamaresUtils::defaultFontHeight() * 2 ); ui->verticalLayout->insertSpacing( 1, CalamaresUtils::defaultFontHeight() * 2 );
@ -102,7 +107,7 @@ WelcomePage::WelcomePage( RequirementsChecker* requirementsChecker, QWidget* par
mb.exec(); 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(); ui->languageWidget->setFocus();
e->accept(); e->accept();
} }
bool WelcomePage::verdict() const
{
return m_checkingWidget->verdict();
}

View File

@ -26,26 +26,27 @@ namespace Ui
class WelcomePage; class WelcomePage;
} }
class RequirementsChecker; class CheckerContainer;
class WelcomePage : public QWidget class WelcomePage : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit WelcomePage( RequirementsChecker* requirementsChecker, explicit WelcomePage( QWidget* parent = nullptr );
QWidget* parent = nullptr );
void setUpLinks( bool showSupportUrl, void setUpLinks( bool showSupportUrl,
bool showKnownIssuesUrl, bool showKnownIssuesUrl,
bool showReleaseNotesUrl ); bool showReleaseNotesUrl );
bool verdict() const;
protected: protected:
void focusInEvent( QFocusEvent* e ) override; //choose the child widget to focus void focusInEvent( QFocusEvent* e ) override; //choose the child widget to focus
private: private:
void initLanguages(); void initLanguages();
Ui::WelcomePage* ui; Ui::WelcomePage* ui;
RequirementsChecker* m_requirementsChecker; CheckerContainer* m_checkingWidget;
}; };
#endif // WELCOMEPAGE_H #endif // WELCOMEPAGE_H

View File

@ -20,9 +20,10 @@
#include "WelcomeViewStep.h" #include "WelcomeViewStep.h"
#include "WelcomePage.h" #include "WelcomePage.h"
#include "checker/RequirementsChecker.h" #include "checker/GeneralRequirements.h"
#include "utils/Logger.h"
#include "modulesystem/ModuleManager.h"
#include "utils/Logger.h"
#include <QVariant> #include <QVariant>
@ -30,12 +31,10 @@ CALAMARES_PLUGIN_FACTORY_DEFINITION( WelcomeViewStepFactory, registerPlugin<Welc
WelcomeViewStep::WelcomeViewStep( QObject* parent ) WelcomeViewStep::WelcomeViewStep( QObject* parent )
: Calamares::ViewStep( parent ) : Calamares::ViewStep( parent )
, m_requirementsChecker( new RequirementsChecker( this ) ) , m_requirementsChecker( new GeneralRequirements( this ) )
{ {
emit nextStatusChanged( true ); connect( Calamares::ModuleManager::instance(), &Calamares::ModuleManager::requirementsComplete, this, &WelcomeViewStep::nextStatusChanged );
m_widget = new WelcomePage( m_requirementsChecker ); m_widget = new WelcomePage();
connect( m_requirementsChecker, &RequirementsChecker::verdictChanged,
this, &WelcomeViewStep::nextStatusChanged );
} }
@ -60,22 +59,10 @@ WelcomeViewStep::widget()
} }
void
WelcomeViewStep::next()
{
emit done();
}
void
WelcomeViewStep::back()
{}
bool bool
WelcomeViewStep::isNextEnabled() const WelcomeViewStep::isNextEnabled() const
{ {
return m_requirementsChecker->verdict(); return m_widget->verdict();
} }
@ -100,10 +87,10 @@ WelcomeViewStep::isAtEnd() const
} }
QList< Calamares::job_ptr > Calamares::JobList
WelcomeViewStep::jobs() const WelcomeViewStep::jobs() const
{ {
return QList< Calamares::job_ptr >(); return Calamares::JobList();
} }
@ -135,3 +122,7 @@ WelcomeViewStep::setConfigurationMap( const QVariantMap& configurationMap )
"module configuration."; "module configuration.";
} }
Calamares::RequirementsList WelcomeViewStep::checkRequirements()
{
return m_requirementsChecker->checkRequirements();
}

View File

@ -21,6 +21,7 @@
#include <QObject> #include <QObject>
#include <modulesystem/Requirement.h>
#include <utils/PluginFactory.h> #include <utils/PluginFactory.h>
#include <viewpages/ViewStep.h> #include <viewpages/ViewStep.h>
@ -29,7 +30,7 @@
#include <QVariantMap> #include <QVariantMap>
class WelcomePage; class WelcomePage;
class RequirementsChecker; class GeneralRequirements;
class PLUGINDLLEXPORT WelcomeViewStep : public Calamares::ViewStep class PLUGINDLLEXPORT WelcomeViewStep : public Calamares::ViewStep
{ {
@ -43,23 +44,21 @@ public:
QWidget* widget() override; QWidget* widget() override;
void next() override;
void back() override;
bool isNextEnabled() const override; bool isNextEnabled() const override;
bool isBackEnabled() const override; bool isBackEnabled() const override;
bool isAtBeginning() const override; bool isAtBeginning() const override;
bool isAtEnd() const override; bool isAtEnd() const override;
QList< Calamares::job_ptr > jobs() const override; Calamares::JobList jobs() const override;
void setConfigurationMap( const QVariantMap& configurationMap ) override; void setConfigurationMap( const QVariantMap& configurationMap ) override;
Calamares::RequirementsList checkRequirements() override;
private: private:
WelcomePage* m_widget; WelcomePage* m_widget;
GeneralRequirements* m_requirementsChecker;
RequirementsChecker* m_requirementsChecker;
}; };
CALAMARES_PLUGIN_FACTORY_DECLARATION( WelcomeViewStepFactory ) CALAMARES_PLUGIN_FACTORY_DECLARATION( WelcomeViewStepFactory )

View File

@ -0,0 +1,83 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2014-2017, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, 2019, Adriaan de Groot <groot@kde.org>
* Copyright 2017, Gabriel Craciunescu <crazy@frugalware.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
/* 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;
}

View File

@ -0,0 +1,64 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2014-2017, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* Copyright 2017, Gabriel Craciunescu <crazy@frugalware.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
/* Based on code extracted from RequirementsChecker.cpp */
#ifndef CHECKERCONTAINER_H
#define CHECKERCONTAINER_H
#include <QWidget>
#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

View File

@ -18,11 +18,12 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "RequirementsChecker.h" #include "GeneralRequirements.h"
#include "CheckerWidget.h" #include "CheckerContainer.h"
#include "partman_devices.h" #include "partman_devices.h"
#include "modulesystem/Requirement.h"
#include "widgets/WaitingWidget.h" #include "widgets/WaitingWidget.h"
#include "utils/CalamaresUtilsGui.h" #include "utils/CalamaresUtilsGui.h"
#include "utils/Logger.h" #include "utils/Logger.h"
@ -30,6 +31,7 @@
#include "utils/CalamaresUtilsSystem.h" #include "utils/CalamaresUtilsSystem.h"
#include "utils/Units.h" #include "utils/Units.h"
#include "JobQueue.h" #include "JobQueue.h"
#include "GlobalStorage.h" #include "GlobalStorage.h"
@ -51,166 +53,113 @@
#include <unistd.h> //geteuid #include <unistd.h> //geteuid
RequirementsChecker::RequirementsChecker( QObject* parent ) GeneralRequirements::GeneralRequirements( QObject* parent )
: QObject( parent ) : QObject( parent )
, m_widget( new QWidget() )
, m_requiredStorageGB( -1 ) , m_requiredStorageGB( -1 )
, m_requiredRamGB( -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() ); Calamares::RequirementsList GeneralRequirements::checkRequirements()
mainLayout->addWidget( waitingWidget ); {
CALAMARES_RETRANSLATE( waitingWidget->setText( tr( "Gathering system information..." ) ); ) 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; qint64 requiredStorageB = CalamaresUtils::GiBtoBytes(m_requiredStorageGB);
timer->setSingleShot( true ); cDebug() << "Need at least storage bytes:" << requiredStorageB;
connect( timer, &QTimer::timeout, 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<const char *, bool>;
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; if ( entry == "storage" )
bool enoughRam = false; checkEntries.append( {
bool hasPower = false; entry,
bool hasInternet = false; [this]{ return tr( "has at least %1 GB available drive space" )
bool isRoot = false; .arg( m_requiredStorageGB ); },
bool enoughScreen = (availableSize.width() >= CalamaresUtils::windowMinimumWidth) && (availableSize.height() >= CalamaresUtils::windowMinimumHeight); [this]{ return tr( "There is not enough drive space. At least %1 GB is required." )
.arg( m_requiredStorageGB ); },
qint64 requiredStorageB = CalamaresUtils::GiBtoBytes(m_requiredStorageGB); enoughStorage,
cDebug() << "Need at least storage bytes:" << requiredStorageB; m_entriesToRequire.contains( entry )
if ( m_entriesToCheck.contains( "storage" ) ) } );
enoughStorage = checkEnoughStorage( requiredStorageB ); else if ( entry == "ram" )
checkEntries.append( {
qint64 requiredRamB = CalamaresUtils::GiBtoBytes(m_requiredRamGB); entry,
cDebug() << "Need at least ram bytes:" << requiredRamB; [this]{ return tr( "has at least %1 GB working memory" )
if ( m_entriesToCheck.contains( "ram" ) ) .arg( m_requiredRamGB ); },
enoughRam = checkEnoughRam( requiredRamB ); [this]{ return tr( "The system does not have enough working memory. At least %1 GB is required." )
.arg( m_requiredRamGB ); },
if ( m_entriesToCheck.contains( "power" ) ) enoughRam,
hasPower = checkHasPower(); m_entriesToRequire.contains( entry )
} );
if ( m_entriesToCheck.contains( "internet" ) ) else if ( entry == "power" )
hasInternet = checkHasInternet(); checkEntries.append( {
entry,
if ( m_entriesToCheck.contains( "root" ) ) [this]{ return tr( "is plugged in to a power source" ); },
isRoot = checkIsRoot(); [this]{ return tr( "The system is not plugged in to a power source." ); },
hasPower,
using TR = Logger::DebugRow<const char *, bool>; m_entriesToRequire.contains( entry )
} );
cDebug() << "RequirementsChecker output:" else if ( entry == "internet" )
<< TR("enoughStorage", enoughStorage) checkEntries.append( {
<< TR("enoughRam", enoughRam) entry,
<< TR("hasPower", hasPower) [this]{ return tr( "is connected to the Internet" ); },
<< TR("hasInternet", hasInternet) [this]{ return tr( "The system is not connected to the Internet." ); },
<< TR("isRoot", isRoot); hasInternet,
m_entriesToRequire.contains( entry )
QList< PrepareEntry > checkEntries; } );
foreach ( const QString& entry, m_entriesToCheck ) else if ( entry == "root" )
{ checkEntries.append( {
if ( entry == "storage" ) entry,
checkEntries.append( { [this]{ return QString(); }, //we hide it
entry, [this]{ return tr( "The installer is not running with administrator rights." ); },
[this]{ return tr( "has at least %1 GB available drive space" ) isRoot,
.arg( m_requiredStorageGB ); }, m_entriesToRequire.contains( entry )
[this]{ return tr( "There is not enough drive space. At least %1 GB is required." ) } );
.arg( m_requiredStorageGB ); }, else if ( entry == "screen" )
enoughStorage, checkEntries.append( {
m_entriesToRequire.contains( entry ) entry,
} ); [this]{ return QString(); }, // we hide it
else if ( entry == "ram" ) [this]{ return tr( "The screen is too small to display the installer." ); },
checkEntries.append( { enoughScreen,
entry, false
[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." ) return checkEntries;
.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;
} }
void void
RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap ) GeneralRequirements::setConfigurationMap( const QVariantMap& configurationMap )
{ {
bool incompleteConfiguration = false; bool incompleteConfiguration = false;
@ -222,7 +171,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
} }
else else
{ {
cWarning() << "RequirementsChecker entry 'check' is incomplete."; cWarning() << "GeneralRequirements entry 'check' is incomplete.";
incompleteConfiguration = true; incompleteConfiguration = true;
} }
@ -234,14 +183,25 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
} }
else else
{ {
cWarning() << "RequirementsChecker entry 'required' is incomplete."; cWarning() << "GeneralRequirements entry 'required' is incomplete.";
incompleteConfiguration = true; 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 // Help out with consistency, but don't fix
for ( const auto& r : m_entriesToRequire ) for ( const auto& r : m_entriesToRequire )
if ( !m_entriesToCheck.contains( r ) ) 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" ) && if ( configurationMap.contains( "requiredStorage" ) &&
( configurationMap.value( "requiredStorage" ).type() == QVariant::Double || ( configurationMap.value( "requiredStorage" ).type() == QVariant::Double ||
@ -251,7 +211,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
m_requiredStorageGB = configurationMap.value( "requiredStorage" ).toDouble( &ok ); m_requiredStorageGB = configurationMap.value( "requiredStorage" ).toDouble( &ok );
if ( !ok ) if ( !ok )
{ {
cWarning() << "RequirementsChecker entry 'requiredStorage' is invalid."; cWarning() << "GeneralRequirements entry 'requiredStorage' is invalid.";
m_requiredStorageGB = 3.; m_requiredStorageGB = 3.;
} }
@ -259,7 +219,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
} }
else else
{ {
cWarning() << "RequirementsChecker entry 'requiredStorage' is missing."; cWarning() << "GeneralRequirements entry 'requiredStorage' is missing.";
m_requiredStorageGB = 3.; m_requiredStorageGB = 3.;
incompleteConfiguration = true; incompleteConfiguration = true;
} }
@ -272,14 +232,14 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
m_requiredRamGB = configurationMap.value( "requiredRam" ).toDouble( &ok ); m_requiredRamGB = configurationMap.value( "requiredRam" ).toDouble( &ok );
if ( !ok ) if ( !ok )
{ {
cWarning() << "RequirementsChecker entry 'requiredRam' is invalid."; cWarning() << "GeneralRequirements entry 'requiredRam' is invalid.";
m_requiredRamGB = 1.; m_requiredRamGB = 1.;
incompleteConfiguration = true; incompleteConfiguration = true;
} }
} }
else else
{ {
cWarning() << "RequirementsChecker entry 'requiredRam' is missing."; cWarning() << "GeneralRequirements entry 'requiredRam' is missing.";
m_requiredRamGB = 1.; m_requiredRamGB = 1.;
incompleteConfiguration = true; incompleteConfiguration = true;
} }
@ -291,7 +251,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
if ( m_checkHasInternetUrl.isEmpty() || if ( m_checkHasInternetUrl.isEmpty() ||
!QUrl( m_checkHasInternetUrl ).isValid() ) !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)."; << "reverting to default (http://example.com).";
m_checkHasInternetUrl = "http://example.com"; m_checkHasInternetUrl = "http://example.com";
incompleteConfiguration = true; incompleteConfiguration = true;
@ -299,7 +259,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
} }
else 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)."; "reverting to default (http://example.com).";
m_checkHasInternetUrl = "http://example.com"; m_checkHasInternetUrl = "http://example.com";
@ -308,24 +268,17 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
if ( incompleteConfiguration ) if ( incompleteConfiguration )
{ {
cWarning() << "RequirementsChecker configuration map:" << Logger::DebugMap( configurationMap ); cWarning() << "GeneralRequirements configuration map:" << Logger::DebugMap( configurationMap );
} }
} }
bool bool
RequirementsChecker::verdict() const GeneralRequirements::checkEnoughStorage( qint64 requiredSpace )
{
return m_verdict;
}
bool
RequirementsChecker::checkEnoughStorage( qint64 requiredSpace )
{ {
#ifdef WITHOUT_LIBPARTED #ifdef WITHOUT_LIBPARTED
Q_UNUSED( requiredSpace ); Q_UNUSED( requiredSpace );
cWarning() << "RequirementsChecker is configured without libparted."; cWarning() << "GeneralRequirements is configured without libparted.";
return false; return false;
#else #else
return check_big_enough( requiredSpace ); return check_big_enough( requiredSpace );
@ -334,7 +287,7 @@ RequirementsChecker::checkEnoughStorage( qint64 requiredSpace )
bool bool
RequirementsChecker::checkEnoughRam( qint64 requiredRam ) GeneralRequirements::checkEnoughRam( qint64 requiredRam )
{ {
// Ignore the guesstimate-factor; we get an under-estimate // Ignore the guesstimate-factor; we get an under-estimate
// which is probably the usable RAM for programs. // which is probably the usable RAM for programs.
@ -344,7 +297,7 @@ RequirementsChecker::checkEnoughRam( qint64 requiredRam )
bool bool
RequirementsChecker::checkBatteryExists() GeneralRequirements::checkBatteryExists()
{ {
const QFileInfo basePath( "/sys/class/power_supply" ); const QFileInfo basePath( "/sys/class/power_supply" );
@ -370,7 +323,7 @@ RequirementsChecker::checkBatteryExists()
bool bool
RequirementsChecker::checkHasPower() GeneralRequirements::checkHasPower()
{ {
const QString UPOWER_SVC_NAME( "org.freedesktop.UPower" ); const QString UPOWER_SVC_NAME( "org.freedesktop.UPower" );
const QString UPOWER_INTF_NAME( "org.freedesktop.UPower" ); const QString UPOWER_INTF_NAME( "org.freedesktop.UPower" );
@ -401,10 +354,10 @@ RequirementsChecker::checkHasPower()
bool bool
RequirementsChecker::checkHasInternet() GeneralRequirements::checkHasInternet()
{ {
// default to true in the QNetworkAccessManager::UnknownAccessibility case // default to true in the QNetworkAccessManager::UnknownAccessibility case
QNetworkAccessManager qnam( this ); QNetworkAccessManager qnam;
bool hasInternet = qnam.networkAccessible() == QNetworkAccessManager::Accessible; bool hasInternet = qnam.networkAccessible() == QNetworkAccessManager::Accessible;
if ( !hasInternet && qnam.networkAccessible() == QNetworkAccessManager::UnknownAccessibility ) if ( !hasInternet && qnam.networkAccessible() == QNetworkAccessManager::UnknownAccessibility )
@ -425,14 +378,14 @@ RequirementsChecker::checkHasInternet()
bool bool
RequirementsChecker::checkIsRoot() GeneralRequirements::checkIsRoot()
{ {
return !geteuid(); return !geteuid();
} }
void void
RequirementsChecker::detectFirmwareType() GeneralRequirements::detectFirmwareType()
{ {
QString fwType = QFile::exists( "/sys/firmware/efi/efivars" ) ? "efi" : "bios"; QString fwType = QFile::exists( "/sys/firmware/efi/efivars" ) ? "efi" : "bios";
Calamares::JobQueue::instance()->globalStorage()->insert( "firmwareType", fwType ); Calamares::JobQueue::instance()->globalStorage()->insert( "firmwareType", fwType );

View File

@ -17,52 +17,23 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef REQUIREMENTSCHECKER_H #ifndef GENERALREQUIREMENTS_H
#define REQUIREMENTSCHECKER_H #define GENERALREQUIREMENTS_H
#include <QObject> #include <QObject>
#include <QStringList> #include <QStringList>
#include <functional> #include "modulesystem/Requirement.h"
class CheckerWidget; class GeneralRequirements : public QObject
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
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit RequirementsChecker( QObject* parent = nullptr ); explicit GeneralRequirements( QObject* parent = nullptr );
virtual ~RequirementsChecker();
QWidget* widget() const;
void setConfigurationMap( const QVariantMap& configurationMap ); void setConfigurationMap( const QVariantMap& configurationMap );
bool verdict() const; Calamares::RequirementsList checkRequirements();
signals:
void verdictChanged( bool );
private: private:
QStringList m_entriesToCheck; QStringList m_entriesToCheck;
@ -76,13 +47,9 @@ private:
bool checkIsRoot(); bool checkIsRoot();
void detectFirmwareType(); void detectFirmwareType();
QWidget* m_widget;
qreal m_requiredStorageGB; qreal m_requiredStorageGB;
qreal m_requiredRamGB; qreal m_requiredRamGB;
QString m_checkHasInternetUrl; QString m_checkHasInternetUrl;
CheckerWidget* m_actualWidget;
bool m_verdict;
}; };
#endif // REQUIREMENTSCHECKER_H #endif // REQUIREMENTSCHECKER_H

View File

@ -1,7 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org> * Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org> * Copyright 2017, 2019, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -17,7 +17,7 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "CheckItemWidget.h" #include "ResultWidget.h"
#include "utils/CalamaresUtilsGui.h" #include "utils/CalamaresUtilsGui.h"
#include "utils/Logger.h" #include "utils/Logger.h"
@ -26,14 +26,15 @@
static inline void setCondition( QLabel* label, CalamaresUtils::ImageType t ) static inline void setCondition( QLabel* label, CalamaresUtils::ImageType t )
{ {
label->setPixmap( CalamaresUtils::defaultPixmap( t, label->setPixmap(
CalamaresUtils::Original, CalamaresUtils::defaultPixmap( t,
QSize( label->height(), label->height() ) ) ); CalamaresUtils::Original,
QSize( label->height(), label->height() ) ) );
} }
CheckItemWidget::CheckItemWidget( bool checked, ResultWidget::ResultWidget( bool satisfied,
bool required, bool required,
QWidget* parent ) QWidget* parent )
: QWidget( parent ) : QWidget( parent )
{ {
QBoxLayout* mainLayout = new QHBoxLayout; QBoxLayout* mainLayout = new QHBoxLayout;
@ -46,19 +47,17 @@ CheckItemWidget::CheckItemWidget( bool checked,
mainLayout->addWidget( m_textLabel ); mainLayout->addWidget( m_textLabel );
m_textLabel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); m_textLabel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
if ( checked ) if ( satisfied )
// Condition is satisfied
setCondition( m_iconLabel, CalamaresUtils::StatusOk ); setCondition( m_iconLabel, CalamaresUtils::StatusOk );
else if ( required )
setCondition( m_iconLabel, CalamaresUtils::StatusError );
else else
if ( required ) setCondition( m_iconLabel, CalamaresUtils::StatusWarning );
setCondition( m_iconLabel, CalamaresUtils::StatusError );
else
setCondition( m_iconLabel, CalamaresUtils::StatusWarning );
} }
void void
CheckItemWidget::setText( const QString& text ) ResultWidget::setText( const QString& text )
{ {
m_textLabel->setText( text ); m_textLabel->setText( text );
} }

View File

@ -0,0 +1,51 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, 2019, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef CHECKER_RESULTWIDGET_H
#define CHECKER_RESULTWIDGET_H
#include <QLabel>
/**
* @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

View File

@ -1,7 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org> * Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org> * Copyright 2017, 2019, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -17,9 +17,9 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "CheckerWidget.h" #include "ResultsListWidget.h"
#include "CheckItemWidget.h" #include "ResultWidget.h"
#include "Branding.h" #include "Branding.h"
#include "utils/CalamaresUtilsGui.h" #include "utils/CalamaresUtilsGui.h"
@ -33,7 +33,7 @@
#include <QLabel> #include <QLabel>
CheckerWidget::CheckerWidget( QWidget* parent ) ResultsListWidget::ResultsListWidget( QWidget* parent )
: QWidget( parent ) : QWidget( parent )
{ {
setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
@ -53,25 +53,23 @@ CheckerWidget::CheckerWidget( QWidget* parent )
void void
CheckerWidget::init( const QList< PrepareEntry >& checkEntries ) ResultsListWidget::init( const Calamares::RequirementsList& checkEntries )
{ {
bool allChecked = true; bool allChecked = true;
bool requirementsSatisfied = 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() ); ) CALAMARES_RETRANSLATE( ciw->setText( entry.negatedText() ); )
m_entriesLayout->addWidget( ciw ); m_entriesLayout->addWidget( ciw );
ciw->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); ciw->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
allChecked = false; allChecked = false;
if ( entry.required ) if ( entry.mandatory )
{
requirementsSatisfied = false; requirementsSatisfied = false;
}
ciw->setAutoFillBackground( true ); ciw->setAutoFillBackground( true );
QPalette pal( ciw->palette() ); QPalette pal( ciw->palette() );
pal.setColor( QPalette::Background, Qt::white ); pal.setColor( QPalette::Background, Qt::white );
@ -97,7 +95,7 @@ CheckerWidget::init( const QList< PrepareEntry >& checkEntries )
"requirements for installing %1.<br/>" "requirements for installing %1.<br/>"
"Installation cannot continue. " "Installation cannot continue. "
"<a href=\"#details\">Details...</a>" ) "<a href=\"#details\">Details...</a>" )
.arg( *Calamares::Branding::ShortVersionedName ) ); .arg( *Calamares::Branding::ShortVersionedName ) );
) )
textLabel->setOpenExternalLinks( false ); textLabel->setOpenExternalLinks( false );
connect( textLabel, &QLabel::linkActivated, connect( textLabel, &QLabel::linkActivated,
@ -114,7 +112,7 @@ CheckerWidget::init( const QList< PrepareEntry >& checkEntries )
"recommended requirements for installing %1.<br/>" "recommended requirements for installing %1.<br/>"
"Installation can continue, but some features " "Installation can continue, but some features "
"might be disabled." ) "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 ( allChecked && requirementsSatisfied )
{ {
if ( !Calamares::Branding::instance()-> if ( !Calamares::Branding::instance()->
imagePath( Calamares::Branding::ProductWelcome ).isEmpty() ) imagePath( Calamares::Branding::ProductWelcome ).isEmpty() )
{ {
QPixmap theImage = QPixmap( Calamares::Branding::instance()-> QPixmap theImage = QPixmap( Calamares::Branding::instance()->
imagePath( Calamares::Branding::ProductWelcome ) ); imagePath( Calamares::Branding::ProductWelcome ) );
if ( !theImage.isNull() ) if ( !theImage.isNull() )
{ {
QLabel* imageLabel; QLabel* imageLabel;
if ( Calamares::Branding::instance()->welcomeExpandingLogo() ) if ( Calamares::Branding::instance()->welcomeExpandingLogo() )
{ {
FixedAspectRatioLabel *p = new FixedAspectRatioLabel; FixedAspectRatioLabel* p = new FixedAspectRatioLabel;
p->setPixmap( theImage ); p->setPixmap( theImage );
imageLabel = p; imageLabel = p;
} }
@ -155,14 +153,12 @@ CheckerWidget::init( const QList< PrepareEntry >& checkEntries )
) )
} }
else else
{
m_mainLayout->addStretch(); m_mainLayout->addStretch();
}
} }
void void
CheckerWidget::showDetailsDialog( const QList< PrepareEntry >& checkEntries ) ResultsListWidget::showDetailsDialog( const Calamares::RequirementsList& checkEntries )
{ {
QDialog* detailsDialog = new QDialog( this ); QDialog* detailsDialog = new QDialog( this );
QBoxLayout* mainLayout = new QVBoxLayout; QBoxLayout* mainLayout = new QVBoxLayout;
@ -177,12 +173,12 @@ CheckerWidget::showDetailsDialog( const QList< PrepareEntry >& checkEntries )
CalamaresUtils::unmarginLayout( entriesLayout ); CalamaresUtils::unmarginLayout( entriesLayout );
mainLayout->addLayout( entriesLayout ); mainLayout->addLayout( entriesLayout );
for ( const PrepareEntry& entry : checkEntries ) for ( const auto& entry : checkEntries )
{ {
if ( entry.enumerationText().isEmpty() ) if ( !entry.hasDetails() )
continue; continue;
CheckItemWidget* ciw = new CheckItemWidget( entry.checked, entry.required ); ResultWidget* ciw = new ResultWidget( entry.satisfied, entry.mandatory );
CALAMARES_RETRANSLATE( ciw->setText( entry.enumerationText() ); ) CALAMARES_RETRANSLATE( ciw->setText( entry.enumerationText() ); )
entriesLayout->addWidget( ciw ); entriesLayout->addWidget( ciw );
ciw->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); ciw->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
@ -194,8 +190,8 @@ CheckerWidget::showDetailsDialog( const QList< PrepareEntry >& checkEntries )
} }
QDialogButtonBox* buttonBox = new QDialogButtonBox( QDialogButtonBox::Close, QDialogButtonBox* buttonBox = new QDialogButtonBox( QDialogButtonBox::Close,
Qt::Horizontal, Qt::Horizontal,
this ); this );
mainLayout->addWidget( buttonBox ); mainLayout->addWidget( buttonBox );
detailsDialog->setModal( true ); detailsDialog->setModal( true );

View File

@ -1,6 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org> * Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2019, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -16,28 +17,28 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef CHECKERWIDGET_H #ifndef CHECKER_RESULTSLISTWIDGET_H
#define CHECKERWIDGET_H #define CHECKER_RESULTSLISTWIDGET_H
#include "RequirementsChecker.h" #include "modulesystem/Requirement.h"
#include <QBoxLayout> #include <QBoxLayout>
#include <QWidget> #include <QWidget>
class CheckerWidget : public QWidget class ResultsListWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit CheckerWidget( QWidget* parent = nullptr ); explicit ResultsListWidget( QWidget* parent = nullptr );
void init( const QList< PrepareEntry >& checkEntries ); void init( const Calamares::RequirementsList& checkEntries );
private: private:
void showDetailsDialog( const QList< PrepareEntry >& checkEntries ); void showDetailsDialog( const Calamares::RequirementsList& checkEntries );
QBoxLayout* m_mainLayout; QBoxLayout* m_mainLayout;
QBoxLayout* m_entriesLayout; QBoxLayout* m_entriesLayout;
int m_paddingSize; int m_paddingSize;
}; };
#endif // CHECKERWIDGET_H #endif // CHECKER_RESULTSLISTWIDGET_H

View File

@ -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 showSupportUrl: true
showKnownIssuesUrl: true showKnownIssuesUrl: true
showReleaseNotesUrl: 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: 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 requiredStorage: 5.5
# Amount of available RAM, in GB. Floating-point is allowed here.
requiredRam: 1.0 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 internetCheckUrl: http://google.com
# List conditions to check. Each listed condition will be # List conditions to check. Each listed condition will be
# probed in some way, and yields true or false according to # probed in some way, and yields true or false according to
# the host system satisfying the condition. # 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: check:
- storage - storage
- ram - ram
@ -20,7 +39,7 @@ requirements:
- internet - internet
- root - root
- screen - 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. # of conditions, above) for installation to proceed.
# If any of these conditions are not met, the user cannot # If any of these conditions are not met, the user cannot
# continue past the welcome page. # continue past the welcome page.