Merge branch 'development' into 3.2.x-stable
This commit is contained in:
commit
693ea79704
31
CHANGES
31
CHANGES
@ -3,6 +3,36 @@ contributors are listed. Note that Calamares does not have a historical
|
||||
changelog -- this log starts with version 3.2.0. The release notes on the
|
||||
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
|
||||
- Gabriel Craciunescu
|
||||
|
||||
## 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 ##
|
||||
|
||||
* *Bootloader* module: a serious bug introduced in 3.2.4 which prevents
|
||||
succesful boot after installation on EFI machines, has been repaired.
|
||||
(Thanks to Gabriel)
|
||||
* *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):
|
||||
@ -66,6 +96,7 @@ This release contains contributions from (alphabetically by first name):
|
||||
the installation media to the target stystem. This can be used, for instance,
|
||||
for block-level-identical installations.
|
||||
|
||||
|
||||
# 3.2.3 (2019-01-09) #
|
||||
|
||||
This release contains contributions from (alphabetically by first name):
|
||||
|
@ -75,8 +75,8 @@ set( CALAMARES_DESCRIPTION_SUMMARY
|
||||
|
||||
set( CALAMARES_VERSION_MAJOR 3 )
|
||||
set( CALAMARES_VERSION_MINOR 2 )
|
||||
set( CALAMARES_VERSION_PATCH 4 )
|
||||
set( CALAMARES_VERSION_RC 0 )
|
||||
set( CALAMARES_VERSION_PATCH 5 )
|
||||
set( CALAMARES_VERSION_RC 1 )
|
||||
|
||||
|
||||
### Transifex (languages) info
|
||||
@ -240,7 +240,7 @@ include( CMakeColors )
|
||||
|
||||
### DEPENDENCIES
|
||||
#
|
||||
find_package( Qt5 ${QT_VERSION} CONFIG REQUIRED Core Gui Widgets LinguistTools Svg Quick QuickWidgets )
|
||||
find_package( Qt5 ${QT_VERSION} CONFIG REQUIRED Concurrent Core Gui Widgets LinguistTools Svg Quick QuickWidgets )
|
||||
find_package( YAMLCPP ${YAMLCPP_VERSION} REQUIRED )
|
||||
if( INSTALL_POLKIT )
|
||||
find_package( PolkitQt5-1 REQUIRED )
|
||||
|
@ -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";
|
||||
|
@ -2,7 +2,7 @@
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2014, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2017-2018, 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -68,9 +68,9 @@ logLevel()
|
||||
}
|
||||
|
||||
static void
|
||||
log( const char* msg, unsigned int debugLevel, bool toDisk = true )
|
||||
log( const char* msg, unsigned int debugLevel )
|
||||
{
|
||||
if ( toDisk || debugLevel < s_threshold )
|
||||
if ( true )
|
||||
{
|
||||
QMutexLocker lock( &s_mutex );
|
||||
|
||||
|
@ -51,7 +51,7 @@ struct NamedEnumTable
|
||||
*
|
||||
* static const NamedEnumTable<Colors> c{ {"red", Colors::Red } };
|
||||
*/
|
||||
NamedEnumTable( const std::initializer_list< pair_t >& v ) : table( v ) { /* static_assert( v.size() > 0 ); */ };
|
||||
NamedEnumTable( const std::initializer_list< pair_t >& v ) : table( v ) { /* static_assert( v.size() > 0 ); */ }
|
||||
|
||||
/** @brief Find a name @p s in the table.
|
||||
*
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||
*
|
||||
* Copyright 2017, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com>
|
||||
*
|
||||
* Calamares is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -24,10 +25,16 @@
|
||||
namespace CalamaresUtils
|
||||
{
|
||||
|
||||
/** User defined literals, 1_KiB is 1 KibiByte (= 2^10 bytes) */
|
||||
constexpr qint64 operator ""_KiB( unsigned long long m )
|
||||
{
|
||||
return qint64(m) * 1024;
|
||||
}
|
||||
|
||||
/** User defined literals, 1_MiB is 1 MibiByte (= 2^20 bytes) */
|
||||
constexpr qint64 operator ""_MiB( unsigned long long m )
|
||||
{
|
||||
return qint64(m) * 1024 * 1024;
|
||||
return operator ""_KiB(m) * 1024;
|
||||
}
|
||||
|
||||
/** User defined literals, 1_GiB is 1 GibiByte (= 2^30 bytes) */
|
||||
@ -36,6 +43,11 @@ constexpr qint64 operator ""_GiB( unsigned long long m )
|
||||
return operator ""_MiB(m) * 1024;
|
||||
}
|
||||
|
||||
constexpr qint64 KiBtoBytes( unsigned long long m )
|
||||
{
|
||||
return operator ""_KiB( m );
|
||||
}
|
||||
|
||||
constexpr qint64 MiBtoBytes( unsigned long long m )
|
||||
{
|
||||
return operator ""_MiB( m );
|
||||
@ -46,7 +58,12 @@ constexpr qint64 GiBtoBytes( unsigned long long m )
|
||||
return operator ""_GiB( m );
|
||||
}
|
||||
|
||||
constexpr qint64 MiBToBytes( double m )
|
||||
constexpr qint64 KiBtoBytes( double m )
|
||||
{
|
||||
return qint64(m * 1024);
|
||||
}
|
||||
|
||||
constexpr qint64 MiBtoBytes( double m )
|
||||
{
|
||||
return qint64(m * 1024 * 1024);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -281,4 +281,10 @@ Module::initFrom( const QVariantMap& moduleDescriptor )
|
||||
m_maybe_emergency = moduleDescriptor[ EMERGENCY ].toBool();
|
||||
}
|
||||
|
||||
RequirementsList
|
||||
Module::checkRequirements()
|
||||
{
|
||||
return RequirementsList();
|
||||
}
|
||||
|
||||
} //ns
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||
*
|
||||
* 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
|
||||
* 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 <Typedefs.h>
|
||||
@ -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 );
|
||||
|
@ -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 <yaml-cpp/yaml.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QTimer>
|
||||
|
||||
#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
|
||||
|
@ -20,6 +20,7 @@
|
||||
#ifndef MODULELOADER_H
|
||||
#define MODULELOADER_H
|
||||
|
||||
#include "Requirement.h"
|
||||
#include "Typedefs.h"
|
||||
|
||||
#include <QObject>
|
||||
@ -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();
|
||||
|
@ -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>
|
||||
*
|
||||
* 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 <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
|
67
src/libcalamaresui/modulesystem/Requirement.h
Normal file
67
src/libcalamaresui/modulesystem/Requirement.h
Normal 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
|
154
src/libcalamaresui/modulesystem/RequirementsChecker.cpp
Normal file
154
src/libcalamaresui/modulesystem/RequirementsChecker.cpp
Normal 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." ) );
|
||||
}
|
||||
|
||||
}
|
87
src/libcalamaresui/modulesystem/RequirementsChecker.h
Normal file
87
src/libcalamaresui/modulesystem/RequirementsChecker.h
Normal 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
|
@ -132,4 +132,10 @@ ViewModule::~ViewModule()
|
||||
delete m_loader;
|
||||
}
|
||||
|
||||
RequirementsList
|
||||
ViewModule::checkRequirements()
|
||||
{
|
||||
return m_viewStep->checkRequirements();
|
||||
}
|
||||
|
||||
} // namespace Calamares
|
||||
|
@ -39,6 +39,8 @@ public:
|
||||
void loadSelf() override;
|
||||
JobList jobs() const override;
|
||||
|
||||
RequirementsList checkRequirements() override;
|
||||
|
||||
protected:
|
||||
void initFrom( const QVariantMap& moduleDescriptor ) override;
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#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,
|
||||
|
@ -8,27 +8,28 @@ Each Calamares module lives in its own directory.
|
||||
|
||||
All modules are installed in `$DESTDIR/lib/calamares/modules`.
|
||||
|
||||
# Module types
|
||||
|
||||
There are two types of Calamares module:
|
||||
There are two **types** of Calamares module:
|
||||
* viewmodule, for user-visible modules. These may be in C++, or PythonQt.
|
||||
* jobmodule, for not-user-visible modules. These may be done in C++,
|
||||
Python, or as external processes.
|
||||
|
||||
# Module interfaces
|
||||
A viewmodule exposes a UI to the user. The PythonQt-based modules
|
||||
are considered experimental (and as of march 2019 may be on the
|
||||
way out again as never-used-much and PythonQt is not packaged
|
||||
on Debian anymore).
|
||||
|
||||
There are three (four) interfaces for Calamares modules:
|
||||
* qtplugin,
|
||||
There are three (four) **interfaces** for Calamares modules:
|
||||
* qtplugin (viewmodules, jobmodules),
|
||||
* python (jobmodules only),
|
||||
* pythonqt (optional),
|
||||
* pythonqt (viewmodules, jobmodules, optional),
|
||||
* process (jobmodules only).
|
||||
|
||||
# Module directory
|
||||
## Module directory
|
||||
|
||||
Each Calamares module lives in its own directory. The contents
|
||||
of the directory depend on the interface and type of the module.
|
||||
|
||||
## Module descriptor
|
||||
### Module descriptor
|
||||
|
||||
A Calamares module must have a *module descriptor file*, named
|
||||
`module.desc`. For C++ (qtplugin) modules using CMake as a build-
|
||||
@ -49,25 +50,66 @@ Module descriptors **must** have the following keys:
|
||||
- *interface* (see below for the different interfaces; generally we
|
||||
refer to the kinds of modules by their interface)
|
||||
|
||||
Module descriptors for Python and PythonQt modules **must** have the following key:
|
||||
- *script* (the name of the Python script to load, nearly always `main.py`)
|
||||
|
||||
Module descriptors **may** have the following keys:
|
||||
- *required* **unimplemented** (a list of modules which are required for this module
|
||||
- *requiredModules* (a list of modules which are required for this module
|
||||
to operate properly)
|
||||
- *emergency* (a boolean value, set to true to mark the module
|
||||
as an emergency module)
|
||||
|
||||
## Module-specific configuration
|
||||
### Required Modules
|
||||
|
||||
A module may list zero (if it has no requirements) or more modules
|
||||
by name. As modules are loaded from the global sequence in `settings.conf`,
|
||||
each module is checked that all of the modules it requires are
|
||||
already loaded before it. This ensures that if a module needs
|
||||
another one to fill in globalstorage keys, that happens before
|
||||
it needs those keys.
|
||||
|
||||
### Emergency Modules
|
||||
|
||||
Only C++ modules and job modules may be emergency modules. If, during an
|
||||
*exec* step in the sequence, a module fails, installation as a whole fails
|
||||
and the install is aborted. If there are emergency modules in the **same**
|
||||
exec block, those will be executed before the installation is aborted.
|
||||
Non-emergency modules are not executed.
|
||||
|
||||
If an emergency-module fails while processing emergency-modules for
|
||||
another failed module, that failure is ignored and emergency-module
|
||||
processing continues.
|
||||
|
||||
Use the EMERGENCY keyword in the CMake description of a C++ module
|
||||
to generate a suitable `module.desc`.
|
||||
|
||||
A module that is marked as an emergency module in its module.desc
|
||||
must **also** set the *emergency* key to *true* in its configuration file
|
||||
(see below). If it does not, the module is not considered to be an emergency
|
||||
module after all (this is so that you can have modules that have several
|
||||
instances, only some of which are actually needed for emergencies).
|
||||
|
||||
### Module-specific configuration
|
||||
|
||||
A Calamares module **may** read a module configuration file,
|
||||
named `<modulename>.conf`. If such a file is present in the
|
||||
module's directory, it is shipped as a *default* configuration file.
|
||||
module's directory, it can be shipped as a *default* configuration file.
|
||||
This only happens if the CMake-time option `INSTALL_CONFIG` is on.
|
||||
|
||||
The sample configuration files may work and may be suitable for
|
||||
your distribution, but no guarantee is given about their stability
|
||||
beyond syntactic correctness.
|
||||
|
||||
The module configuration file, if it exists, is a YAML 1.2 document
|
||||
which contains a YAML map of anything.
|
||||
|
||||
All default module configuration files are installed in
|
||||
All sample module configuration files are installed in
|
||||
`$DESTDIR/share/calamares/modules` but can be overridden by
|
||||
files with the same name placed manually (or by the packager)
|
||||
in `/etc/calamares/modules`.
|
||||
|
||||
|
||||
|
||||
## C++ modules
|
||||
|
||||
Currently the recommended way to write a module which exposes one or more
|
||||
@ -79,6 +121,8 @@ To add a Qt plugin module, put it in a subdirectory and make sure it has
|
||||
a `CMakeLists.txt` with a `calamares_add_plugin` call. It will be picked
|
||||
up automatically by our CMake magic. The `module.desc` file is optional.
|
||||
|
||||
|
||||
|
||||
## Python modules
|
||||
|
||||
Modules may use one of the python interfaces, which may be present
|
||||
@ -90,7 +134,7 @@ or the experimental pythonqt job- and viewmodule interfaces.
|
||||
To add a Python or process jobmodule, put it in a subdirectory and make sure
|
||||
it has a `module.desc`. It will be picked up automatically by our CMake magic.
|
||||
For all kinds of Python jobs, the key *script* must be set to the name of
|
||||
the main python file for the job. This is almost universally "main.py".
|
||||
the main python file for the job. This is almost universally `main.py`.
|
||||
|
||||
`CMakeLists.txt` is *not* used for Python and process jobmodules.
|
||||
|
||||
@ -113,6 +157,17 @@ function `run()` as entry point. The function `run()` must return `None` if
|
||||
everything went well, or a tuple `(str,str)` with an error message and
|
||||
description if something went wrong.
|
||||
|
||||
### Python API
|
||||
|
||||
**TODO:** this needs documentation
|
||||
|
||||
|
||||
|
||||
## PythonQt modules
|
||||
|
||||
The PythonQt modules are considered experimental and may be removed again
|
||||
due to low uptake. Their documentation is also almost completely lacking.
|
||||
|
||||
### PythonQt Jobmodule
|
||||
|
||||
A PythonQt jobmodule implements the experimental Job interface by defining
|
||||
@ -123,31 +178,18 @@ a subclass of something.
|
||||
A PythonQt viewmodule implements the experimental View interface by defining
|
||||
a subclass of something.
|
||||
|
||||
### Python API
|
||||
|
||||
**TODO:** this needs documentation
|
||||
|
||||
|
||||
|
||||
## Process jobmodules
|
||||
|
||||
A process jobmodule runs a (single) command. The interface is "process",
|
||||
while the module type must be "job" or "jobmodule".
|
||||
A process jobmodule runs a (single) command. The interface is *process*,
|
||||
while the module type must be *job* or *jobmodule*.
|
||||
|
||||
The key *command* should have a string as value, which is passed to the
|
||||
shell -- remember to quote it properly.
|
||||
|
||||
## Emergency Modules
|
||||
|
||||
Only C++ modules and job modules may be emergency modules. If, during an
|
||||
*exec* step in the sequence, a module fails, installation as a whole fails
|
||||
and the install is aborted. If there are emergency modules in the **same**
|
||||
exec block, those will be executed before the installation is aborted.
|
||||
Non-emergency modules are not executed.
|
||||
|
||||
If an emergency-module fails while processing emergency-modules for
|
||||
another failed module, that failure is ignored and emergency-module
|
||||
processing continues.
|
||||
|
||||
Use the EMERGENCY keyword in the CMake description of a C++ module
|
||||
to generate a suitable `module.desc`.
|
||||
|
||||
A module that is marked as an emergency module in its module.desc
|
||||
must **also** set the *emergency* key to *true* in its configuration file.
|
||||
If it does not, the module is not considered to be an emergency module
|
||||
after all (this is so that you can have modules that have several
|
||||
instances, only some of which are actually needed for emergencies.
|
||||
The module-descriptor key *command* should have a string as value, which is
|
||||
passed to the shell -- remember to quote it properly. It is generally
|
||||
recommended to use a *shellprocess* job module instead (less configuration,
|
||||
easier to have multiple instances).
|
||||
|
@ -1,5 +1,8 @@
|
||||
---
|
||||
type: "job"
|
||||
name: "bootloader"
|
||||
interface: "python"
|
||||
name: "bootloader"
|
||||
script: "main.py"
|
||||
# The partition module sets up the EFI firmware type
|
||||
# global key, which is used to decide how to install.
|
||||
requiredModules: [ "partition" ]
|
||||
|
@ -768,11 +768,11 @@ def run():
|
||||
displaymanagers.remove(dm)
|
||||
|
||||
if not dm_impl:
|
||||
return (
|
||||
_("No display managers selected for the displaymanager module."),
|
||||
_("The list is empty after checking for installed display managers.")
|
||||
libcalamares.utils.warning(
|
||||
"No display managers selected for the displaymanager module. "
|
||||
"The list is empty after checking for installed display managers."
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
# Pick up remaining settings
|
||||
if "defaultDesktopEnvironment" in libcalamares.job.configuration:
|
||||
|
@ -67,18 +67,6 @@ FinishedViewStep::widget()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FinishedViewStep::next()
|
||||
{
|
||||
emit done();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FinishedViewStep::back()
|
||||
{}
|
||||
|
||||
|
||||
bool
|
||||
FinishedViewStep::isNextEnabled() const
|
||||
{
|
||||
|
@ -40,9 +40,6 @@ public:
|
||||
|
||||
QWidget* widget() override;
|
||||
|
||||
void next() override;
|
||||
void back() override;
|
||||
|
||||
bool isNextEnabled() const override;
|
||||
bool isBackEnabled() const override;
|
||||
|
||||
|
@ -80,7 +80,7 @@ ResizeFSJob::RelativeSize::apply( qint64 totalSectors, qint64 sectorSize )
|
||||
case unit_t::None:
|
||||
return -1;
|
||||
case unit_t::Absolute:
|
||||
return CalamaresUtils::MiBtoBytes( value() ) / sectorSize;
|
||||
return CalamaresUtils::MiBtoBytes( static_cast<unsigned long long>( value() ) ) / sectorSize;
|
||||
case unit_t::Percent:
|
||||
if ( value() == 100 )
|
||||
return totalSectors; // Common-case, avoid futzing around
|
||||
|
@ -62,12 +62,6 @@ def modify_grub_default(partitions, root_mount_point, distributor):
|
||||
|
||||
cryptdevice_params = []
|
||||
|
||||
# GRUB needs to decrypt the partition that /boot is on, which may be / or /boot
|
||||
boot_mountpoint = "/"
|
||||
for partition in partitions:
|
||||
if partition["mountPoint"] == "/boot":
|
||||
boot_mountpoint = "/boot"
|
||||
|
||||
if have_dracut:
|
||||
for partition in partitions:
|
||||
has_luks = "luksMapperName" in partition
|
||||
@ -78,7 +72,7 @@ def modify_grub_default(partitions, root_mount_point, distributor):
|
||||
swap_outer_uuid = partition["luksUuid"]
|
||||
swap_outer_mappername = partition["luksMapperName"]
|
||||
|
||||
if (partition["mountPoint"] == boot_mountpoint and has_luks):
|
||||
if (partition["mountPoint"] == "/" and has_luks):
|
||||
cryptdevice_params = [
|
||||
"rd.luks.uuid={!s}".format(partition["luksUuid"])
|
||||
]
|
||||
@ -88,7 +82,7 @@ def modify_grub_default(partitions, root_mount_point, distributor):
|
||||
if partition["fs"] == "linuxswap" and not has_luks:
|
||||
swap_uuid = partition["uuid"]
|
||||
|
||||
if (partition["mountPoint"] == boot_mountpoint and has_luks):
|
||||
if (partition["mountPoint"] == "/" and has_luks):
|
||||
cryptdevice_params = [
|
||||
"cryptdevice=UUID={!s}:{!s}".format(
|
||||
partition["luksUuid"], partition["luksMapperName"]
|
||||
|
@ -53,18 +53,6 @@ InteractiveTerminalViewStep::widget()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InteractiveTerminalViewStep::next()
|
||||
{
|
||||
emit done();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InteractiveTerminalViewStep::back()
|
||||
{}
|
||||
|
||||
|
||||
bool
|
||||
InteractiveTerminalViewStep::isNextEnabled() const
|
||||
{
|
||||
|
@ -41,9 +41,6 @@ public:
|
||||
|
||||
QWidget* widget() override;
|
||||
|
||||
void next() override;
|
||||
void back() override;
|
||||
|
||||
bool isNextEnabled() const override;
|
||||
bool isBackEnabled() const override;
|
||||
|
||||
|
@ -65,19 +65,6 @@ KeyboardViewStep::widget()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
KeyboardViewStep::next()
|
||||
{
|
||||
//TODO: actually save those settings somewhere
|
||||
emit done();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
KeyboardViewStep::back()
|
||||
{}
|
||||
|
||||
|
||||
bool
|
||||
KeyboardViewStep::isNextEnabled() const
|
||||
{
|
||||
|
@ -42,9 +42,6 @@ public:
|
||||
|
||||
QWidget* widget() override;
|
||||
|
||||
void next() override;
|
||||
void back() override;
|
||||
|
||||
bool isNextEnabled() const override;
|
||||
bool isBackEnabled() const override;
|
||||
|
||||
|
@ -59,18 +59,6 @@ LicenseViewStep::widget()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LicenseViewStep::next()
|
||||
{
|
||||
emit done();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LicenseViewStep::back()
|
||||
{}
|
||||
|
||||
|
||||
bool
|
||||
LicenseViewStep::isNextEnabled() const
|
||||
{
|
||||
|
@ -42,9 +42,6 @@ public:
|
||||
|
||||
QWidget* widget() override;
|
||||
|
||||
void next() override;
|
||||
void back() override;
|
||||
|
||||
bool isNextEnabled() const override;
|
||||
bool isBackEnabled() const override;
|
||||
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
explicit LocaleConfiguration();
|
||||
/// @brief Create a locale with everything set to the given @p localeName
|
||||
explicit LocaleConfiguration( const QString& localeName /* "en_US.UTF-8" */ )
|
||||
: LocaleConfiguration( localeName, localeName ) { };
|
||||
: LocaleConfiguration( localeName, localeName ) { }
|
||||
/// @brief Create a locale with language and formats separate
|
||||
explicit LocaleConfiguration( const QString& localeName, const QString& formatsName );
|
||||
|
||||
|
@ -190,18 +190,6 @@ LocaleViewStep::widget()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LocaleViewStep::next()
|
||||
{
|
||||
emit done();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LocaleViewStep::back()
|
||||
{}
|
||||
|
||||
|
||||
bool
|
||||
LocaleViewStep::isNextEnabled() const
|
||||
{
|
||||
|
@ -45,9 +45,6 @@ public:
|
||||
|
||||
QWidget* widget() override;
|
||||
|
||||
void next() override;
|
||||
void back() override;
|
||||
|
||||
bool isNextEnabled() const override;
|
||||
bool isBackEnabled() const override;
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
# Copyright 2014, Kevin Kofler <kevin.kofler@chello.at>
|
||||
# Copyright 2016, Philip Müller <philm@manjaro.org>
|
||||
# Copyright 2017, Alf Gaida <agaida@siduction.org>
|
||||
# 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
|
||||
|
@ -69,18 +69,6 @@ NetInstallViewStep::widget()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NetInstallViewStep::next()
|
||||
{
|
||||
emit done();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NetInstallViewStep::back()
|
||||
{}
|
||||
|
||||
|
||||
bool
|
||||
NetInstallViewStep::isNextEnabled() const
|
||||
{
|
||||
|
@ -42,9 +42,6 @@ public:
|
||||
|
||||
QWidget* widget() override;
|
||||
|
||||
void next() override;
|
||||
void back() override;
|
||||
|
||||
bool isNextEnabled() const override;
|
||||
bool isBackEnabled() const override;
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
*
|
||||
* Copyright 2015-2016, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2018, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com>
|
||||
*
|
||||
* Calamares is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -42,6 +43,25 @@
|
||||
namespace PartUtils
|
||||
{
|
||||
|
||||
static QString
|
||||
convenienceName( const Partition* const candidate )
|
||||
{
|
||||
if ( !candidate->mountPoint().isEmpty() )
|
||||
return candidate->mountPoint();
|
||||
if ( !candidate->partitionPath().isEmpty() )
|
||||
return candidate->partitionPath();
|
||||
if ( !candidate->devicePath().isEmpty() )
|
||||
return candidate->devicePath();
|
||||
if ( !candidate->deviceNode().isEmpty() )
|
||||
return candidate->devicePath();
|
||||
|
||||
QString p;
|
||||
QTextStream s( &p );
|
||||
s << (void *)candidate;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
bool
|
||||
canBeReplaced( Partition* candidate )
|
||||
{
|
||||
@ -63,12 +83,12 @@ canBeReplaced( Partition* candidate )
|
||||
<< QString( "(%1GB)" ).arg( requiredStorageB / 1024 / 1024 / 1024 );
|
||||
cDebug() << "Storage capacity B:" << availableStorageB
|
||||
<< QString( "(%1GB)" ).arg( availableStorageB / 1024 / 1024 / 1024 )
|
||||
<< "for" << candidate->partitionPath() << " length:" << candidate->length();
|
||||
<< "for" << convenienceName( candidate ) << " length:" << candidate->length();
|
||||
|
||||
if ( ok &&
|
||||
availableStorageB > requiredStorageB )
|
||||
{
|
||||
cDebug() << "Partition" << candidate->partitionPath() << "authorized for replace install.";
|
||||
cDebug() << "Partition" << convenienceName( candidate ) << "authorized for replace install.";
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -85,7 +105,7 @@ canBeResized( Partition* candidate )
|
||||
return false;
|
||||
}
|
||||
|
||||
cDebug() << "Checking if" << candidate->partitionPath() << "can be resized.";
|
||||
cDebug() << "Checking if" << convenienceName( candidate ) << "can be resized.";
|
||||
if ( !candidate->fileSystem().supportGrow() ||
|
||||
!candidate->fileSystem().supportShrink() )
|
||||
{
|
||||
@ -117,7 +137,7 @@ canBeResized( Partition* candidate )
|
||||
|
||||
if ( table->numPrimaries() >= table->maxPrimaries() )
|
||||
{
|
||||
cDebug() << " .. partition table already has"
|
||||
cDebug() << " .. partition table already has"
|
||||
<< table->maxPrimaries() << "primary partitions.";
|
||||
return false;
|
||||
}
|
||||
@ -139,13 +159,13 @@ canBeResized( Partition* candidate )
|
||||
<< QString( "(%1GB)" ).arg( advisedStorageGB );
|
||||
cDebug() << "Available storage B:" << availableStorageB
|
||||
<< QString( "(%1GB)" ).arg( availableStorageB / 1024 / 1024 / 1024 )
|
||||
<< "for" << candidate->partitionPath() << " length:" << candidate->length()
|
||||
<< "for" << convenienceName( candidate ) << " length:" << candidate->length()
|
||||
<< " sectorsUsed:" << candidate->sectorsUsed() << " fsType:" << candidate->fileSystem().name();
|
||||
|
||||
if ( ok &&
|
||||
availableStorageB > advisedStorageB )
|
||||
{
|
||||
cDebug() << "Partition" << candidate->partitionPath() << "authorized for resize + autopartition install.";
|
||||
cDebug() << "Partition" << convenienceName( candidate ) << "authorized for resize + autopartition install.";
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -198,7 +218,7 @@ lookForFstabEntries( const QString& partitionPath )
|
||||
mountOptions.append( "noload" );
|
||||
}
|
||||
|
||||
cDebug() << "Checking device" << partitionPath
|
||||
cDebug() << "Checking device" << partitionPath
|
||||
<< "for fstab (fs=" << r.getOutput() << ')';
|
||||
|
||||
FstabEntryList fstabEntries;
|
||||
@ -209,9 +229,9 @@ lookForFstabEntries( const QString& partitionPath )
|
||||
if ( !exit ) // if all is well
|
||||
{
|
||||
QFile fstabFile( mountsDir.path() + "/etc/fstab" );
|
||||
|
||||
|
||||
cDebug() << " .. reading" << fstabFile.fileName();
|
||||
|
||||
|
||||
if ( fstabFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
|
||||
{
|
||||
const QStringList fstabLines = QString::fromLocal8Bit( fstabFile.readAll() )
|
||||
@ -381,7 +401,7 @@ isEfiSystem()
|
||||
bool
|
||||
isEfiBootable( const Partition* candidate )
|
||||
{
|
||||
cDebug() << "Check EFI bootable" << candidate->partitionPath() << candidate->devicePath();
|
||||
cDebug() << "Check EFI bootable" << convenienceName( candidate ) << candidate->devicePath();
|
||||
cDebug() << " .. flags" << candidate->activeFlags();
|
||||
|
||||
auto flags = PartitionInfo::flags( candidate );
|
||||
@ -408,6 +428,149 @@ isEfiBootable( const Partition* candidate )
|
||||
flags.testFlag( PartitionTable::FlagBoot );
|
||||
}
|
||||
|
||||
QString
|
||||
findFS( QString fsName, FileSystem::Type* fsType )
|
||||
{
|
||||
QStringList fsLanguage { QLatin1Literal( "C" ) }; // Required language list to turn off localization
|
||||
if ( fsName.isEmpty() )
|
||||
fsName = QStringLiteral( "ext4" );
|
||||
|
||||
FileSystem::Type tmpType = FileSystem::typeForName( fsName, fsLanguage );
|
||||
if ( tmpType != FileSystem::Unknown )
|
||||
{
|
||||
cDebug() << "Found filesystem" << fsName;
|
||||
if ( fsType )
|
||||
*fsType = tmpType;
|
||||
return fsName;
|
||||
}
|
||||
|
||||
// Second pass: try case-insensitive
|
||||
const auto fstypes = FileSystem::types();
|
||||
for ( FileSystem::Type t : fstypes )
|
||||
{
|
||||
if ( 0 == QString::compare( fsName, FileSystem::nameForType( t, fsLanguage ), Qt::CaseInsensitive ) )
|
||||
{
|
||||
QString fsRealName = FileSystem::nameForType( t, fsLanguage );
|
||||
cDebug() << "Filesystem name" << fsName << "translated to" << fsRealName;
|
||||
if ( fsType )
|
||||
*fsType = t;
|
||||
return fsRealName;
|
||||
}
|
||||
}
|
||||
|
||||
cDebug() << "Filesystem" << fsName << "not found, using ext4";
|
||||
fsName = QStringLiteral( "ext4" );
|
||||
// fsType can be used to check whether fsName was a valid filesystem.
|
||||
if (fsType)
|
||||
*fsType = FileSystem::Unknown;
|
||||
#ifdef DEBUG_FILESYSTEMS
|
||||
// This bit is for distro's debugging their settings, and shows
|
||||
// all the strings that KPMCore is matching against for FS type.
|
||||
{
|
||||
Logger::CDebug d;
|
||||
using TR = Logger::DebugRow< int, QString >;
|
||||
const auto fstypes = FileSystem::types();
|
||||
d << "Available types (" << fstypes.count() << ')';
|
||||
for ( FileSystem::Type t : fstypes )
|
||||
d << TR( static_cast<int>( t ), FileSystem::nameForType( t, fsLanguage ) );
|
||||
}
|
||||
#endif
|
||||
return fsName;
|
||||
}
|
||||
|
||||
static qint64
|
||||
sizeToBytes( double size, SizeUnit unit, qint64 totalSize )
|
||||
{
|
||||
qint64 bytes;
|
||||
|
||||
switch ( unit )
|
||||
{
|
||||
case SizeUnit::Percent:
|
||||
bytes = qint64( static_cast<double>( totalSize ) * size / 100.0L );
|
||||
break;
|
||||
case SizeUnit::KiB:
|
||||
bytes = CalamaresUtils::KiBtoBytes(size);
|
||||
break;
|
||||
case SizeUnit::MiB:
|
||||
bytes = CalamaresUtils::MiBtoBytes(size);
|
||||
break;
|
||||
case SizeUnit::GiB:
|
||||
bytes = CalamaresUtils::GiBtoBytes(size);
|
||||
break;
|
||||
default:
|
||||
bytes = size;
|
||||
break;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
double
|
||||
parseSizeString( const QString& sizeString, SizeUnit* unit )
|
||||
{
|
||||
double value;
|
||||
bool ok;
|
||||
QString valueString;
|
||||
QString unitString;
|
||||
|
||||
QRegExp rx( "[KkMmGg%]" );
|
||||
int pos = rx.indexIn( sizeString );
|
||||
if (pos > 0)
|
||||
{
|
||||
valueString = sizeString.mid( 0, pos );
|
||||
unitString = sizeString.mid( pos );
|
||||
}
|
||||
else
|
||||
valueString = sizeString;
|
||||
|
||||
value = valueString.toDouble( &ok );
|
||||
if ( !ok )
|
||||
{
|
||||
/*
|
||||
* In case the conversion fails, a size of 100% allows a few cases to pass
|
||||
* anyway (e.g. when it is the last partition of the layout)
|
||||
*/
|
||||
*unit = SizeUnit::Percent;
|
||||
return 100.0L;
|
||||
}
|
||||
|
||||
if ( unitString.length() > 0 )
|
||||
{
|
||||
if ( unitString.at(0) == '%' )
|
||||
*unit = SizeUnit::Percent;
|
||||
else if ( unitString.at(0).toUpper() == 'K' )
|
||||
*unit = SizeUnit::KiB;
|
||||
else if ( unitString.at(0).toUpper() == 'M' )
|
||||
*unit = SizeUnit::MiB;
|
||||
else if ( unitString.at(0).toUpper() == 'G' )
|
||||
*unit = SizeUnit::GiB;
|
||||
else
|
||||
*unit = SizeUnit::Byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
*unit = SizeUnit::Byte;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
qint64
|
||||
parseSizeString( const QString& sizeString, qint64 totalSize )
|
||||
{
|
||||
SizeUnit unit;
|
||||
double value = parseSizeString( sizeString, &unit );
|
||||
|
||||
return sizeToBytes( value, unit, totalSize );
|
||||
}
|
||||
|
||||
qint64
|
||||
sizeToSectors( double size, SizeUnit unit, qint64 totalSectors, qint64 logicalSize )
|
||||
{
|
||||
qint64 bytes = sizeToBytes( size, unit, totalSectors * logicalSize );
|
||||
return bytesToSectors( static_cast<unsigned long long>( bytes ), logicalSize );
|
||||
}
|
||||
|
||||
} // nmamespace PartUtils
|
||||
|
||||
/* Implementation of methods for FstabEntry, from OsproberEntry.h */
|
||||
|
@ -2,6 +2,7 @@
|
||||
*
|
||||
* Copyright 2015-2016, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2018, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com>
|
||||
*
|
||||
* Calamares is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -21,7 +22,12 @@
|
||||
#define PARTUTILS_H
|
||||
|
||||
#include "OsproberEntry.h"
|
||||
#include "utils/Units.h"
|
||||
|
||||
// KPMcore
|
||||
#include <kpmcore/fs/filesystem.h>
|
||||
|
||||
// Qt
|
||||
#include <QString>
|
||||
|
||||
class PartitionCoreModule;
|
||||
@ -29,6 +35,16 @@ class Partition;
|
||||
|
||||
namespace PartUtils
|
||||
{
|
||||
using CalamaresUtils::MiBtoBytes;
|
||||
|
||||
enum SizeUnit
|
||||
{
|
||||
Percent = 0,
|
||||
Byte,
|
||||
KiB,
|
||||
MiB,
|
||||
GiB
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief canBeReplaced checks whether the given Partition satisfies the criteria
|
||||
@ -73,6 +89,56 @@ bool isEfiSystem();
|
||||
* the partition table layout, this may mean different flags.
|
||||
*/
|
||||
bool isEfiBootable( const Partition* candidate );
|
||||
|
||||
/** @brief translate @p fsName into a recognized name and type
|
||||
*
|
||||
* Makes several attempts to translate the string into a
|
||||
* name that KPMCore will recognize.
|
||||
* The corresponding filesystem type is stored in @p fsType, and
|
||||
* its value is FileSystem::Unknown if @p fsName is not recognized.
|
||||
*/
|
||||
QString findFS( QString fsName, FileSystem::Type* fsType );
|
||||
|
||||
/**
|
||||
* @brief Parse a partition size string and return its value and unit used.
|
||||
* @param sizeString the string to parse.
|
||||
* @param unit pointer to a SizeUnit variable for storing the parsed unit.
|
||||
* @return the size value, as parsed from the input string.
|
||||
*/
|
||||
double parseSizeString( const QString& sizeString, SizeUnit* unit );
|
||||
|
||||
/**
|
||||
* @brief Parse a partition size string and return its value in bytes.
|
||||
* @param sizeString the string to parse.
|
||||
* @param totalSize the size of the selected drive (used when the size is expressed in %)
|
||||
* @return the size value in bytes.
|
||||
*/
|
||||
qint64 parseSizeString( const QString& sizeString, qint64 totalSize );
|
||||
|
||||
/**
|
||||
* @brief Convert a partition size to a sectors count.
|
||||
* @param size the partition size.
|
||||
* @param unit the partition size unit.
|
||||
* @param totalSectors the total number of sectors of the selected drive.
|
||||
* @param logicalSize the sector size, in bytes.
|
||||
* @return the number of sectors to be used for the given partition size.
|
||||
*/
|
||||
qint64 sizeToSectors( double size, SizeUnit unit, qint64 totalSectors, qint64 logicalSize );
|
||||
|
||||
constexpr qint64 alignBytesToBlockSize( qint64 bytes, qint64 blocksize )
|
||||
{
|
||||
qint64 blocks = bytes / blocksize;
|
||||
|
||||
if ( blocks * blocksize != bytes )
|
||||
++blocks;
|
||||
return blocks * blocksize;
|
||||
}
|
||||
|
||||
constexpr qint64 bytesToSectors( qint64 bytes, qint64 blocksize )
|
||||
{
|
||||
return alignBytesToBlockSize( alignBytesToBlockSize( bytes, blocksize), MiBtoBytes(1ULL) ) / blocksize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // PARTUTILS_H
|
||||
|
@ -2,6 +2,7 @@
|
||||
*
|
||||
* Copyright 2014-2017, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com>
|
||||
*
|
||||
* Calamares is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -28,6 +29,7 @@
|
||||
#include "utils/Units.h"
|
||||
#include "utils/NamedEnum.h"
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
@ -38,8 +40,6 @@
|
||||
|
||||
namespace PartitionActions
|
||||
{
|
||||
using CalamaresUtils::GiBtoBytes;
|
||||
using CalamaresUtils::MiBtoBytes;
|
||||
using CalamaresUtils::operator""_GiB;
|
||||
using CalamaresUtils::operator""_MiB;
|
||||
|
||||
@ -82,25 +82,10 @@ swapSuggestion( const qint64 availableSpaceB, Choices::SwapChoice swap )
|
||||
return suggestedSwapSizeB;
|
||||
}
|
||||
|
||||
constexpr qint64
|
||||
alignBytesToBlockSize( qint64 bytes, qint64 blocksize )
|
||||
{
|
||||
qint64 blocks = bytes / blocksize;
|
||||
|
||||
if ( blocks * blocksize != bytes )
|
||||
++blocks;
|
||||
return blocks * blocksize;
|
||||
}
|
||||
|
||||
qint64
|
||||
bytesToSectors( qint64 bytes, qint64 blocksize )
|
||||
{
|
||||
return alignBytesToBlockSize( alignBytesToBlockSize( bytes, blocksize), MiBtoBytes(1) ) / blocksize;
|
||||
}
|
||||
|
||||
void
|
||||
doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionOptions o )
|
||||
{
|
||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
QString defaultFsType = o.defaultFsType;
|
||||
if ( FileSystem::typeForName( defaultFsType ) == FileSystem::Unknown )
|
||||
defaultFsType = "ext4";
|
||||
@ -109,19 +94,27 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO
|
||||
|
||||
// Partition sizes are expressed in MiB, should be multiples of
|
||||
// the logical sector size (usually 512B). EFI starts with 2MiB
|
||||
// empty and a 300MiB EFI boot partition, while BIOS starts at
|
||||
// empty and a EFI boot partition, while BIOS starts at
|
||||
// the 1MiB boundary (usually sector 2048).
|
||||
int uefisys_part_sizeB = isEfi ? 300_MiB : 0_MiB;
|
||||
int empty_space_sizeB = isEfi ? 2_MiB : 1_MiB;
|
||||
int uefisys_part_sizeB = 0_MiB;
|
||||
|
||||
if ( isEfi )
|
||||
{
|
||||
if ( gs->contains( "efiSystemPartitionSize" ) )
|
||||
uefisys_part_sizeB = PartUtils::parseSizeString( gs->value( "efiSystemPartitionSize" ).toString(), dev->capacity() );
|
||||
else
|
||||
uefisys_part_sizeB = 300_MiB;
|
||||
}
|
||||
|
||||
// Since sectors count from 0, if the space is 2048 sectors in size,
|
||||
// the first free sector has number 2048 (and there are 2048 sectors
|
||||
// before that one, numbered 0..2047).
|
||||
qint64 firstFreeSector = bytesToSectors( empty_space_sizeB, dev->logicalSize() );
|
||||
qint64 firstFreeSector = PartUtils::bytesToSectors( empty_space_sizeB, dev->logicalSize() );
|
||||
|
||||
if ( isEfi )
|
||||
{
|
||||
qint64 efiSectorCount = bytesToSectors( uefisys_part_sizeB, dev->logicalSize() );
|
||||
qint64 efiSectorCount = PartUtils::bytesToSectors( uefisys_part_sizeB, dev->logicalSize() );
|
||||
Q_ASSERT( efiSectorCount > 0 );
|
||||
|
||||
// Since sectors count from 0, and this partition is created starting
|
||||
|
@ -75,8 +75,6 @@ namespace Choices
|
||||
|
||||
} // namespace Choices
|
||||
|
||||
qint64 bytesToSectors( qint64 bytes, qint64 blocksize );
|
||||
|
||||
/**
|
||||
* @brief doAutopartition sets up an autopartitioning operation on the given Device.
|
||||
* @param core a pointer to the PartitionCoreModule instance.
|
||||
|
@ -154,6 +154,9 @@ public:
|
||||
|
||||
void setPartitionFlags( Device* device, Partition* partition, PartitionTable::Flags flags );
|
||||
|
||||
/// @brief Retrieve the path where the bootloader will be installed
|
||||
QString bootLoaderInstallPath() const { return m_bootLoaderInstallPath; }
|
||||
/// @brief Set the path where the bootloader will be installed
|
||||
void setBootLoaderInstallPath( const QString& path );
|
||||
|
||||
void initLayout();
|
||||
|
@ -18,27 +18,50 @@
|
||||
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
|
||||
#include "core/PartitionLayout.h"
|
||||
|
||||
#include "core/KPMHelpers.h"
|
||||
#include "core/PartitionActions.h"
|
||||
#include "core/PartitionInfo.h"
|
||||
#include "core/PartUtils.h"
|
||||
|
||||
#include <kpmcore/core/device.h>
|
||||
#include <kpmcore/core/partition.h>
|
||||
#include <kpmcore/fs/filesystem.h>
|
||||
|
||||
static FileSystem::Type
|
||||
getDefaultFileSystemType()
|
||||
{
|
||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
FileSystem::Type defaultFS = FileSystem::Ext4;
|
||||
|
||||
if ( gs->contains( "defaultFileSystemType" ) )
|
||||
{
|
||||
PartUtils::findFS( gs->value( "defaultFileSystemType" ).toString(), &defaultFS);
|
||||
if ( defaultFS == FileSystem::Unknown )
|
||||
defaultFS = FileSystem::Ext4;
|
||||
}
|
||||
|
||||
return defaultFS;
|
||||
}
|
||||
|
||||
PartitionLayout::PartitionLayout()
|
||||
{
|
||||
m_defaultFsType = getDefaultFileSystemType();
|
||||
}
|
||||
|
||||
PartitionLayout::PartitionLayout( PartitionLayout::PartitionEntry entry )
|
||||
{
|
||||
partLayout.append( entry );
|
||||
m_defaultFsType = getDefaultFileSystemType();
|
||||
m_partLayout.append( entry );
|
||||
}
|
||||
|
||||
PartitionLayout::PartitionLayout( const PartitionLayout& layout )
|
||||
: partLayout( layout.partLayout )
|
||||
: m_partLayout( layout.m_partLayout )
|
||||
, m_defaultFsType( layout.m_defaultFsType )
|
||||
{
|
||||
}
|
||||
|
||||
@ -49,64 +72,14 @@ PartitionLayout::~PartitionLayout()
|
||||
void
|
||||
PartitionLayout::addEntry( PartitionLayout::PartitionEntry entry )
|
||||
{
|
||||
partLayout.append( entry );
|
||||
}
|
||||
|
||||
static double
|
||||
parseSizeString( const QString& sizeString, PartitionLayout::SizeUnit* unit )
|
||||
{
|
||||
double value;
|
||||
bool ok;
|
||||
QString valueString;
|
||||
QString unitString;
|
||||
|
||||
QRegExp rx( "[KkMmGg%]" );
|
||||
int pos = rx.indexIn( sizeString );
|
||||
if (pos > 0)
|
||||
{
|
||||
valueString = sizeString.mid( 0, pos );
|
||||
unitString = sizeString.mid( pos );
|
||||
}
|
||||
else
|
||||
valueString = sizeString;
|
||||
|
||||
value = valueString.toDouble( &ok );
|
||||
if ( !ok )
|
||||
{
|
||||
/*
|
||||
* In case the conversion fails, a size of 100% allows a few cases to pass
|
||||
* anyway (e.g. when it is the last partition of the layout)
|
||||
*/
|
||||
*unit = PartitionLayout::SizeUnit::Percent;
|
||||
return 100;
|
||||
}
|
||||
|
||||
if ( unitString.length() > 0 )
|
||||
{
|
||||
if ( unitString.at(0) == '%' )
|
||||
*unit = PartitionLayout::SizeUnit::Percent;
|
||||
else if ( unitString.at(0).toUpper() == 'K' )
|
||||
*unit = PartitionLayout::SizeUnit::KiB;
|
||||
else if ( unitString.at(0).toUpper() == 'M' )
|
||||
*unit = PartitionLayout::SizeUnit::MiB;
|
||||
else if ( unitString.at(0).toUpper() == 'G' )
|
||||
*unit = PartitionLayout::SizeUnit::GiB;
|
||||
else
|
||||
*unit = PartitionLayout::SizeUnit::Byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
*unit = PartitionLayout::SizeUnit::Byte;
|
||||
}
|
||||
|
||||
return value;
|
||||
m_partLayout.append( entry );
|
||||
}
|
||||
|
||||
PartitionLayout::PartitionEntry::PartitionEntry(const QString& size, const QString& min)
|
||||
{
|
||||
partSize = parseSizeString( size , &partSizeUnit );
|
||||
partSize = PartUtils::parseSizeString( size , &partSizeUnit );
|
||||
if ( !min.isEmpty() )
|
||||
partMinSize = parseSizeString( min , &partMinSizeUnit );
|
||||
partMinSize = PartUtils::parseSizeString( min , &partMinSizeUnit );
|
||||
}
|
||||
|
||||
void
|
||||
@ -115,9 +88,9 @@ PartitionLayout::addEntry( const QString& mountPoint, const QString& size, const
|
||||
PartitionLayout::PartitionEntry entry( size, min );
|
||||
|
||||
entry.partMountPoint = mountPoint;
|
||||
entry.partFileSystem = FileSystem::Ext4;
|
||||
entry.partFileSystem = m_defaultFsType;
|
||||
|
||||
partLayout.append( entry );
|
||||
m_partLayout.append( entry );
|
||||
}
|
||||
|
||||
void
|
||||
@ -127,38 +100,11 @@ PartitionLayout::addEntry( const QString& label, const QString& mountPoint, cons
|
||||
|
||||
entry.partLabel = label;
|
||||
entry.partMountPoint = mountPoint;
|
||||
entry.partFileSystem = FileSystem::typeForName( fs );
|
||||
PartUtils::findFS( fs, &entry.partFileSystem );
|
||||
if ( entry.partFileSystem == FileSystem::Unknown )
|
||||
entry.partFileSystem = m_defaultFsType;
|
||||
|
||||
partLayout.append( entry );
|
||||
}
|
||||
|
||||
static qint64
|
||||
sizeToSectors( double size, PartitionLayout::SizeUnit unit, qint64 totalSize, qint64 logicalSize )
|
||||
{
|
||||
qint64 sectors;
|
||||
double tmp;
|
||||
|
||||
if ( unit == PartitionLayout::SizeUnit::Percent )
|
||||
{
|
||||
tmp = static_cast<double>( totalSize ) * size / 100;
|
||||
sectors = static_cast<qint64>( tmp );
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp = size;
|
||||
if ( unit >= PartitionLayout::SizeUnit::KiB )
|
||||
tmp *= 1024;
|
||||
if ( unit >= PartitionLayout::SizeUnit::MiB )
|
||||
tmp *= 1024;
|
||||
if ( unit >= PartitionLayout::SizeUnit::GiB )
|
||||
tmp *= 1024;
|
||||
|
||||
sectors = PartitionActions::bytesToSectors( static_cast<unsigned long long>( tmp ),
|
||||
logicalSize
|
||||
);
|
||||
}
|
||||
|
||||
return sectors;
|
||||
m_partLayout.append( entry );
|
||||
}
|
||||
|
||||
QList< Partition* >
|
||||
@ -175,13 +121,13 @@ PartitionLayout::execute( Device *dev, qint64 firstSector,
|
||||
// TODO: Refine partition sizes to make sure there is room for every partition
|
||||
// Use a default (200-500M ?) minimum size for partition without minSize
|
||||
|
||||
foreach( const PartitionLayout::PartitionEntry& part, partLayout )
|
||||
foreach( const PartitionLayout::PartitionEntry& part, m_partLayout )
|
||||
{
|
||||
Partition *currentPartition = nullptr;
|
||||
|
||||
// Calculate partition size
|
||||
size = sizeToSectors( part.partSize, part.partSizeUnit, totalSize, dev->logicalSize() );
|
||||
minSize = sizeToSectors( part.partMinSize, part.partMinSizeUnit, totalSize, dev->logicalSize() );
|
||||
size = PartUtils::sizeToSectors( part.partSize, part.partSizeUnit, totalSize, dev->logicalSize() );
|
||||
minSize = PartUtils::sizeToSectors( part.partMinSize, part.partMinSizeUnit, totalSize, dev->logicalSize() );
|
||||
if ( size < minSize )
|
||||
size = minSize;
|
||||
if ( size > availableSize )
|
||||
@ -194,7 +140,7 @@ PartitionLayout::execute( Device *dev, qint64 firstSector,
|
||||
parent,
|
||||
*dev,
|
||||
role,
|
||||
static_cast<FileSystem::Type>(part.partFileSystem),
|
||||
part.partFileSystem,
|
||||
firstSector,
|
||||
end,
|
||||
PartitionTable::FlagNone
|
||||
@ -206,7 +152,7 @@ PartitionLayout::execute( Device *dev, qint64 firstSector,
|
||||
parent,
|
||||
*dev,
|
||||
role,
|
||||
static_cast<FileSystem::Type>(part.partFileSystem),
|
||||
part.partFileSystem,
|
||||
firstSector,
|
||||
end,
|
||||
luksPassphrase,
|
||||
|
@ -20,10 +20,13 @@
|
||||
#ifndef PARTITIONLAYOUT_H
|
||||
#define PARTITIONLAYOUT_H
|
||||
|
||||
#include "core/PartUtils.h"
|
||||
|
||||
#include "Typedefs.h"
|
||||
|
||||
// KPMcore
|
||||
#include <kpmcore/core/partitiontable.h>
|
||||
#include <kpmcore/fs/filesystem.h>
|
||||
|
||||
// Qt
|
||||
#include <QList>
|
||||
@ -35,24 +38,15 @@ class PartitionLayout
|
||||
{
|
||||
public:
|
||||
|
||||
enum SizeUnit
|
||||
{
|
||||
Percent = 0,
|
||||
Byte,
|
||||
KiB,
|
||||
MiB,
|
||||
GiB
|
||||
};
|
||||
|
||||
struct PartitionEntry
|
||||
{
|
||||
QString partLabel;
|
||||
QString partMountPoint;
|
||||
int partFileSystem = 0;
|
||||
FileSystem::Type partFileSystem = FileSystem::Unknown;
|
||||
double partSize = 0.0L;
|
||||
SizeUnit partSizeUnit = Percent;
|
||||
PartUtils::SizeUnit partSizeUnit = PartUtils::SizeUnit::Percent;
|
||||
double partMinSize = 0.0L;
|
||||
SizeUnit partMinSizeUnit = Percent;
|
||||
PartUtils::SizeUnit partMinSizeUnit = PartUtils::SizeUnit::Percent;
|
||||
|
||||
/// @brief All-zeroes PartitionEntry
|
||||
PartitionEntry() {};
|
||||
@ -76,7 +70,8 @@ public:
|
||||
QList< Partition* > execute( Device *dev, qint64 firstSector, qint64 lastSector, QString luksPassphrase, PartitionNode* parent, const PartitionRole& role );
|
||||
|
||||
private:
|
||||
QList< PartitionEntry > partLayout;
|
||||
FileSystem::Type m_defaultFsType;
|
||||
QList< PartitionEntry > m_partLayout;
|
||||
};
|
||||
|
||||
#endif /* PARTITIONLAYOUT_H */
|
||||
|
@ -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 );
|
||||
|
||||
@ -1248,7 +1243,7 @@ ChoicePage::setupActions()
|
||||
}
|
||||
if ( PartUtils::canBeReplaced( *it ) )
|
||||
{
|
||||
cDebug() << ".. contains replacable" << it;
|
||||
cDebug() << ".. contains replaceable" << it;
|
||||
atLeastOneCanBeReplaced = true;
|
||||
}
|
||||
if ( (*it)->isMounted() )
|
||||
|
@ -34,7 +34,7 @@ CreateVolumeGroupDialog::CreateVolumeGroupDialog( QString& vgName,
|
||||
, m_selectedPVs( selectedPVs )
|
||||
, m_peSize( pSize )
|
||||
{
|
||||
setWindowTitle( "Create Volume Group" );
|
||||
setWindowTitle( tr( "Create Volume Group" ) );
|
||||
|
||||
peSize()->setValue( pSize );
|
||||
|
||||
|
@ -44,7 +44,7 @@ void
|
||||
standardMountPoints(QComboBox& combo)
|
||||
{
|
||||
combo.clear();
|
||||
combo.addItem( combo.tr( "(no mount point)" ) );
|
||||
combo.addItem( QObject::tr( "(no mount point)" ) );
|
||||
combo.addItems( standardMountPoints() );
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,6 @@
|
||||
#include <kpmcore/ops/removevolumegroupoperation.h>
|
||||
|
||||
// Qt
|
||||
#include <QDebug>
|
||||
#include <QHeaderView>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QMessageBox>
|
||||
@ -90,22 +89,9 @@ PartitionPage::PartitionPage( PartitionCoreModule* core, QWidget* parent )
|
||||
|
||||
updateFromCurrentDevice();
|
||||
|
||||
connect( m_ui->deviceComboBox, &QComboBox::currentTextChanged,
|
||||
[ this ]( const QString& /* text */ )
|
||||
{
|
||||
updateFromCurrentDevice();
|
||||
} );
|
||||
connect( m_ui->bootLoaderComboBox, static_cast<void(QComboBox::*)(const QString &)>(&QComboBox::activated),
|
||||
[ this ]( const QString& /* text */ )
|
||||
{
|
||||
m_lastSelectedBootLoaderIndex = m_ui->bootLoaderComboBox->currentIndex();
|
||||
} );
|
||||
|
||||
connect( m_ui->bootLoaderComboBox, &QComboBox::currentTextChanged,
|
||||
[ this ]( const QString& /* text */ )
|
||||
{
|
||||
updateBootLoaderInstallPath();
|
||||
} );
|
||||
connect( m_ui->deviceComboBox, &QComboBox::currentTextChanged, this, &PartitionPage::updateFromCurrentDevice );
|
||||
connect( m_ui->bootLoaderComboBox, QOverload<int>::of(&QComboBox::activated), this, &PartitionPage::updateSelectedBootLoaderIndex );
|
||||
connect( m_ui->bootLoaderComboBox, &QComboBox::currentTextChanged, this, &PartitionPage::updateBootLoaderInstallPath );
|
||||
|
||||
connect( m_core, &PartitionCoreModule::isDirtyChanged, m_ui->revertButton, &QWidget::setEnabled );
|
||||
|
||||
@ -376,18 +362,18 @@ PartitionPage::onCreateClicked()
|
||||
if ( !checkCanCreate( model->device() ) )
|
||||
return;
|
||||
|
||||
QPointer< CreatePartitionDialog > dlg = new CreatePartitionDialog( model->device(),
|
||||
partition->parent(),
|
||||
nullptr,
|
||||
getCurrentUsedMountpoints(),
|
||||
this );
|
||||
dlg->initFromFreeSpace( partition );
|
||||
if ( dlg->exec() == QDialog::Accepted )
|
||||
CreatePartitionDialog dlg(
|
||||
model->device(),
|
||||
partition->parent(),
|
||||
nullptr,
|
||||
getCurrentUsedMountpoints(),
|
||||
this );
|
||||
dlg.initFromFreeSpace( partition );
|
||||
if ( dlg.exec() == QDialog::Accepted )
|
||||
{
|
||||
Partition* newPart = dlg->createPartition();
|
||||
m_core->createPartition( model->device(), newPart, dlg->newFlags() );
|
||||
Partition* newPart = dlg.createPartition();
|
||||
m_core->createPartition( model->device(), newPart, dlg.newFlags() );
|
||||
}
|
||||
delete dlg;
|
||||
}
|
||||
|
||||
void
|
||||
@ -508,10 +494,17 @@ PartitionPage::updateBootLoaderInstallPath()
|
||||
QVariant var = m_ui->bootLoaderComboBox->currentData( BootLoaderModel::BootLoaderPathRole );
|
||||
if ( !var.isValid() )
|
||||
return;
|
||||
qDebug() << "PartitionPage::updateBootLoaderInstallPath" << var.toString();
|
||||
cDebug() << "PartitionPage::updateBootLoaderInstallPath" << var.toString();
|
||||
m_core->setBootLoaderInstallPath( var.toString() );
|
||||
}
|
||||
|
||||
void
|
||||
PartitionPage::updateSelectedBootLoaderIndex()
|
||||
{
|
||||
m_lastSelectedBootLoaderIndex = m_ui->bootLoaderComboBox->currentIndex();
|
||||
cDebug() << "Selected bootloader index" << m_lastSelectedBootLoaderIndex;
|
||||
}
|
||||
|
||||
void
|
||||
PartitionPage::updateFromCurrentDevice()
|
||||
{
|
||||
@ -581,7 +574,7 @@ void
|
||||
PartitionPage::onPartitionModelReset()
|
||||
{
|
||||
m_ui->partitionTreeView->expandAll();
|
||||
// updateButtons();
|
||||
updateButtons();
|
||||
updateBootLoaderIndex();
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,14 @@ public:
|
||||
int selectedDeviceIndex();
|
||||
void selectDeviceByIndex( int index );
|
||||
|
||||
private slots:
|
||||
/// @brief Update everything when the base device changes
|
||||
void updateFromCurrentDevice();
|
||||
/// @brief Update when the selected device for boot loader changes
|
||||
void updateBootLoaderInstallPath();
|
||||
/// @brief Explicitly selected boot loader path
|
||||
void updateSelectedBootLoaderIndex();
|
||||
|
||||
private:
|
||||
QScopedPointer< Ui_PartitionPage > m_ui;
|
||||
PartitionCoreModule* m_core;
|
||||
@ -67,8 +75,6 @@ private:
|
||||
|
||||
void updatePartitionToCreate( Device*, Partition* );
|
||||
void editExistingPartition( Device*, Partition* );
|
||||
void updateBootLoaderInstallPath();
|
||||
void updateFromCurrentDevice();
|
||||
void updateBootLoaderIndex();
|
||||
|
||||
/**
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Copyright 2014, Aurélien Gâteau <agateau@kde.org>
|
||||
* Copyright 2014-2017, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2018, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2019, Collabora Ltd
|
||||
* Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com>
|
||||
*
|
||||
* Calamares is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -60,6 +60,8 @@
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
#include <QFutureWatcher>
|
||||
|
||||
#include <unistd.h> // 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 <strong>%1</strong> (%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 "
|
||||
@ -493,55 +478,6 @@ nameToChoice( QString name, bool& ok )
|
||||
return names.find( name, ok );
|
||||
}
|
||||
|
||||
/** @brief translate @p defaultFS into a recognized name
|
||||
*
|
||||
* Makes several attempts to translate the string into a
|
||||
* name that KPMCore will recognize.
|
||||
*/
|
||||
static QString
|
||||
findFS( QString defaultFS )
|
||||
{
|
||||
QStringList fsLanguage { QLatin1Literal( "C" ) }; // Required language list to turn off localization
|
||||
if ( defaultFS.isEmpty() )
|
||||
{
|
||||
cWarning() << "Partition-module setting *defaultFileSystemType* is missing, using ext4";
|
||||
defaultFS = QStringLiteral( "ext4" );
|
||||
}
|
||||
if ( FileSystem::typeForName( defaultFS, fsLanguage ) != FileSystem::Unknown )
|
||||
{
|
||||
cDebug() << "Partition-module setting *defaultFileSystemType*" << defaultFS;
|
||||
return defaultFS;
|
||||
}
|
||||
|
||||
// Second pass: try case-insensitive
|
||||
const auto fstypes = FileSystem::types();
|
||||
for ( FileSystem::Type t : fstypes )
|
||||
{
|
||||
if ( 0 == QString::compare( defaultFS, FileSystem::nameForType( t, fsLanguage ), Qt::CaseInsensitive ) )
|
||||
{
|
||||
defaultFS = FileSystem::nameForType( t, fsLanguage );
|
||||
cWarning() << "Partition-module setting *defaultFileSystemType* changed" << defaultFS;
|
||||
return defaultFS;
|
||||
}
|
||||
}
|
||||
|
||||
cWarning() << "Partition-module setting *defaultFileSystemType* is bad (" << defaultFS << ") using ext4.";
|
||||
defaultFS = QStringLiteral( "ext4" );
|
||||
#ifdef DEBUG_FILESYSTEMS
|
||||
// This bit is for distro's debugging their settings, and shows
|
||||
// all the strings that KPMCore is matching against for FS type.
|
||||
{
|
||||
Logger::CDebug d;
|
||||
using TR = Logger::DebugRow< int, QString >;
|
||||
const auto fstypes = FileSystem::types();
|
||||
d << "Available types (" << fstypes.count() << ')';
|
||||
for ( FileSystem::Type t : fstypes )
|
||||
d << TR( static_cast<int>( t ), FileSystem::nameForType( t, fsLanguage ) );
|
||||
}
|
||||
#endif
|
||||
return defaultFS;
|
||||
}
|
||||
|
||||
void
|
||||
PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
@ -553,6 +489,17 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
efiSP = QStringLiteral( "/boot/efi" );
|
||||
gs->insert( "efiSystemPartition", efiSP );
|
||||
|
||||
// Set up firmwareType global storage entry. This is used, e.g. by the bootloader module.
|
||||
QString firmwareType( PartUtils::isEfiSystem() ? QStringLiteral( "efi" ) : QStringLiteral( "bios" ) );
|
||||
cDebug() << "Setting firmwareType to" << firmwareType;
|
||||
gs->insert( "firmwareType", firmwareType );
|
||||
|
||||
// Read and parse key efiSystemPartitionSize
|
||||
if ( configurationMap.contains( "efiSystemPartitionSize" ) )
|
||||
{
|
||||
gs->insert( "efiSystemPartitionSize", CalamaresUtils::getString( configurationMap, "efiSystemPartitionSize" ) );
|
||||
}
|
||||
|
||||
// SWAP SETTINGS
|
||||
//
|
||||
// This is a bit convoluted because there's legacy settings to handle as well
|
||||
@ -630,23 +577,38 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
gs->insert( "alwaysShowPartitionLabels", CalamaresUtils::getBool( configurationMap, "alwaysShowPartitionLabels", true ) );
|
||||
gs->insert( "enableLuksAutomatedPartitioning", CalamaresUtils::getBool( configurationMap, "enableLuksAutomatedPartitioning", true ) );
|
||||
gs->insert( "allowManualPartitioning", CalamaresUtils::getBool( configurationMap, "allowManualPartitioning", true ) );
|
||||
gs->insert( "defaultFileSystemType", findFS( CalamaresUtils::getString( configurationMap, "defaultFileSystemType" ) ) );
|
||||
|
||||
// The defaultFileSystemType setting needs a bit more processing,
|
||||
// as we want to cover various cases (such as different cases)
|
||||
QString fsName = CalamaresUtils::getString( configurationMap, "defaultFileSystemType" );
|
||||
FileSystem::Type fsType;
|
||||
if ( fsName.isEmpty() )
|
||||
cWarning() << "Partition-module setting *defaultFileSystemType* is missing, will use ext4";
|
||||
QString fsRealName = PartUtils::findFS( fsName, &fsType );
|
||||
if ( fsRealName == fsName )
|
||||
cDebug() << "Partition-module setting *defaultFileSystemType*" << fsRealName;
|
||||
else if ( fsType != FileSystem::Unknown )
|
||||
cWarning() << "Partition-module setting *defaultFileSystemType* changed" << fsRealName;
|
||||
else
|
||||
cWarning() << "Partition-module setting *defaultFileSystemType* is bad (" << fsRealName << ") using ext4.";
|
||||
gs->insert( "defaultFileSystemType", fsRealName );
|
||||
|
||||
|
||||
// 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" ) )
|
||||
{
|
||||
@ -665,5 +627,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<PartitionViewStep>(); )
|
||||
|
@ -36,6 +36,8 @@ class PartitionPage;
|
||||
class PartitionCoreModule;
|
||||
class QStackedWidget;
|
||||
|
||||
template<typename T> 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<void>* m_future;
|
||||
|
||||
QSet< PartitionActions::Choices::SwapChoice > m_swapChoices;
|
||||
};
|
||||
|
@ -35,7 +35,7 @@ ResizeVolumeGroupDialog::ResizeVolumeGroupDialog( LvmDevice *device,
|
||||
: VolumeGroupBaseDialog( device->name(), device->physicalVolumes(), parent )
|
||||
, m_selectedPVs( selectedPVs )
|
||||
{
|
||||
setWindowTitle( "Resize Volume Group" );
|
||||
setWindowTitle( tr( "Resize Volume Group" ) );
|
||||
|
||||
for ( int i = 0; i < pvList()->count(); i++ )
|
||||
pvList()->item(i)->setCheckState( Qt::Checked );
|
||||
|
@ -11,7 +11,7 @@
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>VolumeGroupDialog</string>
|
||||
<string>Create Volume Group</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
class CreateVolumeGroupJob : public Calamares::Job
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CreateVolumeGroupJob( QString& vgName, QVector< const Partition* > pvList, const qint32 peSize );
|
||||
|
||||
|
@ -25,6 +25,7 @@ class LvmDevice;
|
||||
|
||||
class DeactivateVolumeGroupJob : public Calamares::Job
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DeactivateVolumeGroupJob( LvmDevice* device );
|
||||
|
||||
|
@ -25,6 +25,7 @@ class LvmDevice;
|
||||
|
||||
class RemoveVolumeGroupJob : public Calamares::Job
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
RemoveVolumeGroupJob( LvmDevice* device );
|
||||
|
||||
|
@ -28,6 +28,7 @@ class Partition;
|
||||
|
||||
class ResizeVolumeGroupJob : public Calamares::Job
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ResizeVolumeGroupJob( LvmDevice* device, QVector< const Partition* >& partitionList );
|
||||
|
||||
|
@ -3,6 +3,10 @@
|
||||
# etc.) use just /boot.
|
||||
efiSystemPartition: "/boot/efi"
|
||||
|
||||
# This optional setting specifies the size of the EFI system partition.
|
||||
# If nothing is specified, the default size of 300MiB will be used.
|
||||
# efiSystemPartitionSize: 300M
|
||||
|
||||
# In autogenerated partitioning, allow the user to select a swap size?
|
||||
# If there is exactly one choice, no UI is presented, and the user
|
||||
# cannot make a choice -- this setting is used. If there is more than
|
||||
|
@ -350,7 +350,8 @@ PartitionJobTests::testResizePartition()
|
||||
|
||||
// Make the test data file smaller than the full size of the partition to
|
||||
// accomodate for the file system overhead
|
||||
const QByteArray testData = generateTestData( CalamaresUtils::MiBtoBytes( qMin( oldSizeMB, newSizeMB ) ) * 3 / 4 );
|
||||
const unsigned long long minSizeMB = qMin( oldSizeMB, newSizeMB );
|
||||
const QByteArray testData = generateTestData( CalamaresUtils::MiBtoBytes( minSizeMB ) * 3 / 4 );
|
||||
const QString testName = "test.data";
|
||||
|
||||
// Setup: create the test partition
|
||||
|
@ -76,18 +76,6 @@ PlasmaLnfViewStep::widget()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlasmaLnfViewStep::next()
|
||||
{
|
||||
emit done();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlasmaLnfViewStep::back()
|
||||
{}
|
||||
|
||||
|
||||
bool
|
||||
PlasmaLnfViewStep::isNextEnabled() const
|
||||
{
|
||||
|
@ -41,9 +41,6 @@ public:
|
||||
|
||||
QWidget* widget() override;
|
||||
|
||||
void next() override;
|
||||
void back() override;
|
||||
|
||||
bool isNextEnabled() const override;
|
||||
bool isBackEnabled() const override;
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
# Copyright 2016, Artoo <artoo@manjaro.org>
|
||||
# Copyright 2017, Alf Gaida <agaida@siduction.org>
|
||||
# Copyright 2018, Gabriel Craciunescu <crazy@frugalware.org>
|
||||
# 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
|
||||
@ -24,6 +25,16 @@ import libcalamares
|
||||
|
||||
from libcalamares.utils import debug, target_env_call
|
||||
|
||||
import gettext
|
||||
_ = gettext.translation("calamares-python",
|
||||
localedir=libcalamares.utils.gettext_path(),
|
||||
languages=libcalamares.utils.gettext_languages(),
|
||||
fallback=True).gettext
|
||||
|
||||
|
||||
def pretty_name():
|
||||
return _("Configure Plymouth theme")
|
||||
|
||||
|
||||
class PlymouthController:
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#
|
||||
# Copyright 2015, Teo Mrnjavac <teo@kde.org>
|
||||
# Copyright 2017. Alf Gaida <agaida@siduction.org>
|
||||
# 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
|
||||
@ -22,6 +23,16 @@
|
||||
import subprocess
|
||||
import libcalamares
|
||||
|
||||
import gettext
|
||||
_ = gettext.translation("calamares-python",
|
||||
localedir=libcalamares.utils.gettext_path(),
|
||||
languages=libcalamares.utils.gettext_languages(),
|
||||
fallback=True).gettext
|
||||
|
||||
|
||||
def pretty_name():
|
||||
return _("Remove live user from target system")
|
||||
|
||||
|
||||
def run():
|
||||
"""
|
||||
|
@ -6,7 +6,7 @@
|
||||
# Copyright 2016, Artoo <artoo@manjaro.org>
|
||||
# Copyright 2017, Philip Müller <philm@manjaro.org>
|
||||
# Copyright 2018, Artoo <artoo@artixlinux.org>
|
||||
# Copyright 2018, Adriaan de Groot <groot@kde.org>
|
||||
# Copyright 2018-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
|
||||
@ -27,6 +27,17 @@ from libcalamares.utils import target_env_call, warning
|
||||
from os.path import exists, join
|
||||
|
||||
|
||||
import gettext
|
||||
_ = gettext.translation("calamares-python",
|
||||
localedir=libcalamares.utils.gettext_path(),
|
||||
languages=libcalamares.utils.gettext_languages(),
|
||||
fallback=True).gettext
|
||||
|
||||
|
||||
def pretty_name():
|
||||
return _("Configure OpenRC services")
|
||||
|
||||
|
||||
class OpenrcController:
|
||||
"""
|
||||
This is the openrc service controller.
|
||||
@ -45,6 +56,22 @@ class OpenrcController:
|
||||
self.initdDir = libcalamares.job.configuration['initdDir']
|
||||
self.runlevelsDir = libcalamares.job.configuration['runlevelsDir']
|
||||
|
||||
|
||||
def make_failure_description(self, state, name, runlevel):
|
||||
"""
|
||||
Returns a generic "could not <foo>" failure message, specialized
|
||||
for the action @p state and the specific service @p name in @p runlevel.
|
||||
"""
|
||||
if state == "add":
|
||||
description = _("Cannot add service {name!s} to run-level {level!s}.")
|
||||
elif state == "del":
|
||||
description = _("Cannot remove service {name!s} from run-level {level!s}.")
|
||||
else:
|
||||
description = _("Unknown service-action <code>{arg!s}</code> for service {name!s} in run-level {level!s}.")
|
||||
|
||||
return description.format(arg=state, name=name, level=runlevel)
|
||||
|
||||
|
||||
def update(self, state):
|
||||
"""
|
||||
Call rc-update for each service listed
|
||||
@ -69,24 +96,31 @@ class OpenrcController:
|
||||
if exists(runlevel_path):
|
||||
ec = target_env_call(["rc-update", state, name, runlevel])
|
||||
if ec != 0:
|
||||
warning("Cannot {} service {} to {}".format(state, name, runlevel))
|
||||
warning("rc-update returned error code {!s}".format(ec))
|
||||
if mandatory:
|
||||
return ("Cannot {} service {} to {}".format(state, name, runlevel),
|
||||
"rc-update {} call in chroot returned error code {}".format(state, ec)
|
||||
title = _("Cannot modify service")
|
||||
diagnostic = _("<code>rc-update {arg!s}</code> call in chroot returned error code {num!s}.").format(arg=state, num=ec)
|
||||
return (title,
|
||||
self.make_failure_description(state, name, runlevel) + " " + diagnostic
|
||||
)
|
||||
else:
|
||||
warning("Could not {} service {} in {}, error {!s}".format(state, name, runlevel, ec))
|
||||
else:
|
||||
warning("Target runlevel {} does not exist for {}.".format(runlevel, name))
|
||||
if mandatory:
|
||||
return ("Target runlevel {} does not exist for {}.".format(runlevel, name),
|
||||
"No {} found.".format(runlevel_path))
|
||||
else:
|
||||
warning("Target runlevel {} does not exist for {}.".format(runlevel, name))
|
||||
title = _("Target runlevel does not exist")
|
||||
diagnostic = _("The path for runlevel {level!s} is <code>{path!s}</code>, which does not exist.").format(level=runlevel, path=runlevel_path)
|
||||
|
||||
return (title,
|
||||
self.make_failure_description(state, name, runlevel) + " " + diagnostic
|
||||
)
|
||||
else:
|
||||
warning("Target service {} does not exist in {}.".format(name, self.initdDir))
|
||||
if mandatory:
|
||||
return ("Target service {} does not exist.".format(name),
|
||||
"No {} found.".format(service_path))
|
||||
else:
|
||||
warning("Target service {} does not exist in {}.".format(name, self.initdDir))
|
||||
title = _("Target service does not exist")
|
||||
diagnostic = _("The path for service {name!s} is <code>{path!s}</code>, which does not exist.").format(name=name, path=service_path)
|
||||
return (title,
|
||||
self.make_failure_description(state, name, runlevel) + " " + diagnostic
|
||||
)
|
||||
|
||||
|
||||
def run(self):
|
||||
|
@ -6,7 +6,7 @@
|
||||
# Copyright 2014, Philip Müller <philm@manjaro.org>
|
||||
# Copyright 2014, Teo Mrnjavac <teo@kde.org>
|
||||
# Copyright 2017, Alf Gaida <agaida@siduction.org>
|
||||
# Copyright 2018, Adriaan de Groot <groot@kde.org>
|
||||
# Copyright 2018-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
|
||||
@ -24,6 +24,17 @@
|
||||
import libcalamares
|
||||
|
||||
|
||||
import gettext
|
||||
_ = gettext.translation("calamares-python",
|
||||
localedir=libcalamares.utils.gettext_path(),
|
||||
languages=libcalamares.utils.gettext_languages(),
|
||||
fallback=True).gettext
|
||||
|
||||
|
||||
def pretty_name():
|
||||
return _("Configure systemd services")
|
||||
|
||||
|
||||
def systemctl(targets, command, suffix):
|
||||
"""
|
||||
For each entry in @p targets, run "systemctl <command> <thing>",
|
||||
@ -47,17 +58,32 @@ def systemctl(targets, command, suffix):
|
||||
)
|
||||
|
||||
if ec != 0:
|
||||
libcalamares.utils.warning(
|
||||
"Cannot {} systemd {} {}".format(command, suffix, name)
|
||||
)
|
||||
libcalamares.utils.warning(
|
||||
"systemctl {} call in chroot returned error code {}".format(command, ec)
|
||||
)
|
||||
if mandatory:
|
||||
return ("Cannot {} systemd {} {}".format(command, suffix, name),
|
||||
"systemctl {} call in chroot returned error code {}".format(command, ec)
|
||||
title = _("Cannot modify service")
|
||||
diagnostic = _("<code>systemctl {arg!s}</code> call in chroot returned error code {num!s}.").format(arg=command, num=ec)
|
||||
|
||||
if command == "enable" and suffix == ".service":
|
||||
description = _("Cannot enable systemd service <code>{name!s}</code>.")
|
||||
elif command == "enable" and suffix == ".target":
|
||||
description = _("Cannot enable systemd target <code>{name!s}</code>.")
|
||||
elif command == "disable" and suffix == ".service":
|
||||
description = _("Cannot enable systemd service <code>{name!s}</code>.")
|
||||
elif command == "disable" and suffix == ".target":
|
||||
description = _("Cannot disable systemd target <code>{name!s}</code>.")
|
||||
elif command == "mask":
|
||||
description = _("Cannot mask systemd unit <code>{name!s}</code>.")
|
||||
else:
|
||||
description = _("Unknown systemd commands <code>{command!s}</code> and <code>{suffix!s}</code> for unit {name!s}.")
|
||||
|
||||
return (title,
|
||||
description.format(name=name, command=command, suffix=suffix) + " " + diagnostic
|
||||
)
|
||||
else:
|
||||
libcalamares.utils.warning(
|
||||
"Cannot {} systemd {} {}".format(command, suffix, name)
|
||||
)
|
||||
libcalamares.utils.warning(
|
||||
"systemctl {} call in chroot returned error code {}".format(command, ec)
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
@ -92,6 +118,4 @@ def run():
|
||||
if r is not None:
|
||||
return r
|
||||
|
||||
|
||||
# This could have just been return r
|
||||
return None
|
||||
|
@ -51,18 +51,6 @@ SummaryViewStep::widget()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SummaryViewStep::next()
|
||||
{
|
||||
emit done();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SummaryViewStep::back()
|
||||
{}
|
||||
|
||||
|
||||
bool
|
||||
SummaryViewStep::isNextEnabled() const
|
||||
{
|
||||
|
@ -40,9 +40,6 @@ public:
|
||||
|
||||
QWidget* widget() override;
|
||||
|
||||
void next() override;
|
||||
void back() override;
|
||||
|
||||
bool isNextEnabled() const override;
|
||||
bool isBackEnabled() const override;
|
||||
|
||||
|
@ -67,18 +67,6 @@ TrackingViewStep::widget()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackingViewStep::next()
|
||||
{
|
||||
emit done();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackingViewStep::back()
|
||||
{}
|
||||
|
||||
|
||||
bool
|
||||
TrackingViewStep::isNextEnabled() const
|
||||
{
|
||||
|
@ -43,9 +43,6 @@ public:
|
||||
|
||||
QWidget* widget() override;
|
||||
|
||||
void next() override;
|
||||
void back() override;
|
||||
|
||||
bool isNextEnabled() const override;
|
||||
bool isBackEnabled() const override;
|
||||
|
||||
|
@ -154,29 +154,29 @@ CreateUserJob::exec()
|
||||
useradd << "-c" << m_fullName;
|
||||
useradd << m_userName;
|
||||
|
||||
auto pres = CalamaresUtils::System::instance()->targetEnvCommand( useradd );
|
||||
if ( pres.getExitCode() )
|
||||
auto commandResult = CalamaresUtils::System::instance()->targetEnvCommand( useradd );
|
||||
if ( commandResult.getExitCode() )
|
||||
{
|
||||
cError() << "useradd failed" << pres.getExitCode();
|
||||
return pres.explainProcess( useradd, 10 /* bogus timeout */ );
|
||||
cError() << "useradd failed" << commandResult.getExitCode();
|
||||
return commandResult.explainProcess( useradd, 10 /* bogus timeout */ );
|
||||
}
|
||||
|
||||
pres = CalamaresUtils::System::instance()->targetEnvCommand(
|
||||
commandResult = CalamaresUtils::System::instance()->targetEnvCommand(
|
||||
{ "usermod", "-aG", defaultGroups, m_userName } );
|
||||
if ( pres.getExitCode() )
|
||||
if ( commandResult.getExitCode() )
|
||||
{
|
||||
cError() << "usermod failed" << pres.getExitCode();
|
||||
return pres.explainProcess( "usermod", 10 );
|
||||
cError() << "usermod failed" << commandResult.getExitCode();
|
||||
return commandResult.explainProcess( "usermod", 10 );
|
||||
}
|
||||
|
||||
QString userGroup = QString( "%1:%2" ).arg( m_userName ).arg( m_userName );
|
||||
QString homeDir = QString( "/home/%1" ).arg( m_userName );
|
||||
pres = CalamaresUtils::System::instance()->targetEnvCommand(
|
||||
commandResult = CalamaresUtils::System::instance()->targetEnvCommand(
|
||||
{ "chown", "-R", userGroup, homeDir } );
|
||||
if ( pres.getExitCode() )
|
||||
if ( commandResult.getExitCode() )
|
||||
{
|
||||
cError() << "chown failed" << pres.getExitCode();
|
||||
return pres.explainProcess( "chown", 10 );
|
||||
cError() << "chown failed" << commandResult.getExitCode();
|
||||
return commandResult.explainProcess( "chown", 10 );
|
||||
}
|
||||
|
||||
return Calamares::JobResult::ok();
|
||||
|
@ -61,18 +61,6 @@ UsersViewStep::widget()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UsersViewStep::next()
|
||||
{
|
||||
emit done();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UsersViewStep::back()
|
||||
{}
|
||||
|
||||
|
||||
bool
|
||||
UsersViewStep::isNextEnabled() const
|
||||
{
|
||||
|
@ -43,9 +43,6 @@ public:
|
||||
|
||||
QWidget* widget() override;
|
||||
|
||||
void next() override;
|
||||
void back() override;
|
||||
|
||||
bool isNextEnabled() const override;
|
||||
bool isBackEnabled() const override;
|
||||
|
||||
|
@ -72,18 +72,6 @@ WebViewStep::widget()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WebViewStep::next()
|
||||
{
|
||||
emit done();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WebViewStep::back()
|
||||
{}
|
||||
|
||||
|
||||
bool
|
||||
WebViewStep::isNextEnabled() const
|
||||
{
|
||||
|
@ -50,8 +50,6 @@ public:
|
||||
|
||||
QWidget* widget() override;
|
||||
|
||||
void next() override;
|
||||
void back() override;
|
||||
void onActivate() override;
|
||||
|
||||
bool isNextEnabled() const override;
|
||||
|
@ -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}
|
||||
)
|
||||
|
||||
|
@ -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 <QApplication>
|
||||
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 <QVariant>
|
||||
|
||||
@ -30,12 +31,10 @@ CALAMARES_PLUGIN_FACTORY_DEFINITION( WelcomeViewStepFactory, registerPlugin<Welc
|
||||
|
||||
WelcomeViewStep::WelcomeViewStep( QObject* parent )
|
||||
: Calamares::ViewStep( parent )
|
||||
, m_requirementsChecker( new RequirementsChecker( this ) )
|
||||
, m_requirementsChecker( new GeneralRequirements( this ) )
|
||||
{
|
||||
emit nextStatusChanged( true );
|
||||
m_widget = new WelcomePage( m_requirementsChecker );
|
||||
connect( m_requirementsChecker, &RequirementsChecker::verdictChanged,
|
||||
this, &WelcomeViewStep::nextStatusChanged );
|
||||
connect( Calamares::ModuleManager::instance(), &Calamares::ModuleManager::requirementsComplete, this, &WelcomeViewStep::nextStatusChanged );
|
||||
m_widget = new WelcomePage();
|
||||
}
|
||||
|
||||
|
||||
@ -60,22 +59,10 @@ WelcomeViewStep::widget()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WelcomeViewStep::next()
|
||||
{
|
||||
emit done();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WelcomeViewStep::back()
|
||||
{}
|
||||
|
||||
|
||||
bool
|
||||
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
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <modulesystem/Requirement.h>
|
||||
#include <utils/PluginFactory.h>
|
||||
#include <viewpages/ViewStep.h>
|
||||
|
||||
@ -29,7 +30,7 @@
|
||||
#include <QVariantMap>
|
||||
|
||||
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 )
|
||||
|
83
src/modules/welcome/checker/CheckerContainer.cpp
Normal file
83
src/modules/welcome/checker/CheckerContainer.cpp
Normal 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;
|
||||
}
|
64
src/modules/welcome/checker/CheckerContainer.h
Normal file
64
src/modules/welcome/checker/CheckerContainer.h
Normal 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
|
@ -18,11 +18,12 @@
|
||||
* 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 "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 <unistd.h> //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<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;
|
||||
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<const char *, bool>;
|
||||
|
||||
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,15 +378,7 @@ RequirementsChecker::checkHasInternet()
|
||||
|
||||
|
||||
bool
|
||||
RequirementsChecker::checkIsRoot()
|
||||
GeneralRequirements::checkIsRoot()
|
||||
{
|
||||
return !geteuid();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RequirementsChecker::detectFirmwareType()
|
||||
{
|
||||
QString fwType = QFile::exists( "/sys/firmware/efi/efivars" ) ? "efi" : "bios";
|
||||
Calamares::JobQueue::instance()->globalStorage()->insert( "firmwareType", fwType );
|
||||
}
|
@ -17,52 +17,23 @@
|
||||
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef REQUIREMENTSCHECKER_H
|
||||
#define REQUIREMENTSCHECKER_H
|
||||
#ifndef GENERALREQUIREMENTS_H
|
||||
#define GENERALREQUIREMENTS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
|
||||
#include <functional>
|
||||
#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;
|
||||
@ -74,15 +45,10 @@ private:
|
||||
bool checkHasPower();
|
||||
bool checkHasInternet();
|
||||
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
|
@ -1,7 +1,7 @@
|
||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||
*
|
||||
* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#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 );
|
||||
}
|
51
src/modules/welcome/checker/ResultWidget.h
Normal file
51
src/modules/welcome/checker/ResultWidget.h
Normal 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
|
@ -1,7 +1,7 @@
|
||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||
*
|
||||
* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "CheckerWidget.h"
|
||||
#include "ResultsListWidget.h"
|
||||
|
||||
#include "CheckItemWidget.h"
|
||||
#include "ResultWidget.h"
|
||||
|
||||
#include "Branding.h"
|
||||
#include "utils/CalamaresUtilsGui.h"
|
||||
@ -33,7 +33,7 @@
|
||||
#include <QLabel>
|
||||
|
||||
|
||||
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.<br/>"
|
||||
"Installation cannot continue. "
|
||||
"<a href=\"#details\">Details...</a>" )
|
||||
.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.<br/>"
|
||||
"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 );
|
@ -1,6 +1,7 @@
|
||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||
*
|
||||
* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef CHECKERWIDGET_H
|
||||
#define CHECKERWIDGET_H
|
||||
#ifndef CHECKER_RESULTSLISTWIDGET_H
|
||||
#define CHECKER_RESULTSLISTWIDGET_H
|
||||
|
||||
#include "RequirementsChecker.h"
|
||||
#include "modulesystem/Requirement.h"
|
||||
|
||||
#include <QBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
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
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user