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

This commit is contained in:
Philip Müller 2020-04-02 23:53:08 +02:00
commit 76f29dcddd
56 changed files with 1175 additions and 577 deletions

19
CHANGES
View File

@ -3,6 +3,25 @@ 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.22 (unreleased) #
This release contains contributions from (alphabetically by first name):
- Anke Boersma
## Core ##
- Both the sidebar (on the left) and the navigation buttons (along the
bottom of the window) can now be configured to use the traditional
*widgets*, to use *qml*, or *hidden* from view (hiding the navigation
is not recommended unless you have a pure-QML UI to run inside
Calamares). The example QML that is compiled into Calamares has
been improved. To use your own QML, put files `calamares-sidebar.qml`
or `calamares-navigation.qml` into the branding directory.
## Modules ##
- The *welcomeq* module has been improved with better layout and
nicer buttons in the example QML form. (Thanks to Anke Boersma)
# 3.2.21 (2020-03-27) #
This release contains contributions from (alphabetically by first name):

View File

@ -40,10 +40,10 @@
cmake_minimum_required( VERSION 3.3 FATAL_ERROR )
project( CALAMARES
VERSION 3.2.21
VERSION 3.2.22
LANGUAGES C CXX )
set( CALAMARES_VERSION_RC 0 ) # Set to 0 during release cycle, 1 during development
set( CALAMARES_VERSION_RC 1 ) # Set to 0 during release cycle, 1 during development
### OPTIONS
#

View File

@ -44,9 +44,15 @@ windowPlacement: center
# Kind of sidebar (panel on the left, showing progress).
# - "widget" or unset, use traditional sidebar (logo, items)
# - "none", hide it entirely
# - "qml", use sidebar.qml from branding folder
# - "qml", use calamares-sidebar.qml from branding folder
sidebar: widget
# Kind of navigation (button panel on the bottom).
# - "widget" or unset, use traditional navigation
# - "none", hide it entirely
# - "qml", use calamares-navigation.qml from branding folder
navigation: widget
# These are strings shown to the user in the user interface.
# There is no provision for translating them -- since they
# are names, the string is included as-is.

View File

@ -138,11 +138,119 @@ CalamaresWindow::getQmlSidebar( int desiredWidth )
QQuickWidget* w = new QQuickWidget( this );
w->setFixedWidth( desiredWidth );
w->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
w->setResizeMode( QQuickWidget::SizeRootObjectToView );
w->setSource( QUrl(
CalamaresUtils::searchQmlFile( CalamaresUtils::QmlSearch::Both, QStringLiteral( "calamares-sidebar" ) ) ) );
return w;
}
/** @brief Get a button-sized icon. */
static inline QPixmap
getButtonIcon( const QString& name )
{
return Calamares::Branding::instance()->image( name, QSize( 22, 22 ) );
}
static inline void
setButtonIcon( QPushButton* button, const QString& name )
{
auto icon = getButtonIcon( name );
if ( button && !icon.isNull() )
{
button->setIcon( icon );
}
}
QWidget*
CalamaresWindow::getWidgetNavigation()
{
QWidget* navigation = new QWidget( this );
QBoxLayout* bottomLayout = new QHBoxLayout;
bottomLayout->addStretch();
// Create buttons and sets an initial icon; the icons may change
{
auto* back = new QPushButton( getButtonIcon( QStringLiteral( "go-previous" ) ), tr( "&Back" ), navigation );
back->setObjectName( "view-button-back" );
back->setEnabled( m_viewManager->backEnabled() );
connect( back, &QPushButton::clicked, m_viewManager, &Calamares::ViewManager::back );
connect( m_viewManager, &Calamares::ViewManager::backEnabledChanged, back, &QPushButton::setEnabled );
connect( m_viewManager, &Calamares::ViewManager::backLabelChanged, back, &QPushButton::setText );
connect( m_viewManager, &Calamares::ViewManager::backIconChanged, this, [=]( QString n ) {
setButtonIcon( back, n );
} );
bottomLayout->addWidget( back );
}
{
auto* next = new QPushButton( getButtonIcon( QStringLiteral( "go-next" ) ), tr( "&Next" ), navigation );
next->setObjectName( "view-button-next" );
next->setEnabled( m_viewManager->nextEnabled() );
connect( next, &QPushButton::clicked, m_viewManager, &Calamares::ViewManager::next );
connect( m_viewManager, &Calamares::ViewManager::nextEnabledChanged, next, &QPushButton::setEnabled );
connect( m_viewManager, &Calamares::ViewManager::nextLabelChanged, next, &QPushButton::setText );
connect( m_viewManager, &Calamares::ViewManager::nextIconChanged, this, [=]( QString n ) {
setButtonIcon( next, n );
} );
bottomLayout->addWidget( next );
}
bottomLayout->addSpacing( 12 );
{
auto* quit = new QPushButton( getButtonIcon( QStringLiteral( "dialog-cancel" ) ), tr( "&Cancel" ), navigation );
quit->setObjectName( "view-button-cancel" );
connect( quit, &QPushButton::clicked, m_viewManager, &Calamares::ViewManager::quit );
connect( m_viewManager, &Calamares::ViewManager::quitEnabledChanged, quit, &QPushButton::setEnabled );
connect( m_viewManager, &Calamares::ViewManager::quitLabelChanged, quit, &QPushButton::setText );
connect( m_viewManager, &Calamares::ViewManager::quitIconChanged, this, [=]( QString n ) {
setButtonIcon( quit, n );
} );
connect( m_viewManager, &Calamares::ViewManager::quitTooltipChanged, quit, &QPushButton::setToolTip );
connect( m_viewManager, &Calamares::ViewManager::quitVisibleChanged, quit, &QPushButton::setVisible );
bottomLayout->addWidget( quit );
}
navigation->setLayout( bottomLayout );
return navigation;
}
QWidget*
CalamaresWindow::getQmlNavigation()
{
CalamaresUtils::registerCalamaresModels();
QQuickWidget* w = new QQuickWidget( this );
w->setFixedHeight( 64 );
w->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
w->setResizeMode( QQuickWidget::SizeRootObjectToView );
w->setSource( QUrl(
CalamaresUtils::searchQmlFile( CalamaresUtils::QmlSearch::Both, QStringLiteral( "calamares-navigation" ) ) ) );
return w;
}
/**@brief Picks one of two methods to call
*
* Calls method (member function) @p widget or @p qml with arguments @p a
* on the given window, based on the flavor.
*/
template < typename widgetMaker, typename... args >
QWidget*
flavoredWidget( Calamares::Branding::PanelFlavor flavor,
CalamaresWindow* w,
widgetMaker widget,
widgetMaker qml,
args... a )
{
// Member-function calling syntax is (object.*member)(args)
switch ( flavor )
{
case Calamares::Branding::PanelFlavor::Widget:
return ( w->*widget )( a... );
case Calamares::Branding::PanelFlavor::Qml:
return ( w->*qml )( a... );
case Calamares::Branding::PanelFlavor::None:
return nullptr;
}
NOTREACHED return nullptr; // All enum values handled above
}
CalamaresWindow::CalamaresWindow( QWidget* parent )
: QWidget( parent )
, m_debugWindow( nullptr )
@ -188,20 +296,12 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
QBoxLayout* mainLayout = new QHBoxLayout;
setLayout( mainLayout );
QWidget* sideBox = nullptr;
switch ( branding->sidebarFlavor() )
{
case Calamares::Branding::SidebarFlavor::Widget:
sideBox = getWidgetSidebar(
qBound( 100, CalamaresUtils::defaultFontHeight() * 12, w < windowPreferredWidth ? 100 : 190 ) );
break;
case Calamares::Branding::SidebarFlavor::Qml:
sideBox = getQmlSidebar(
qBound( 100, CalamaresUtils::defaultFontHeight() * 12, w < windowPreferredWidth ? 100 : 190 ) );
break;
case Calamares::Branding::SidebarFlavor::None:
sideBox = nullptr;
}
QWidget* sideBox = flavoredWidget(
branding->sidebarFlavor(),
this,
&CalamaresWindow::getWidgetSidebar,
&CalamaresWindow::getQmlSidebar,
qBound( 100, CalamaresUtils::defaultFontHeight() * 12, w < windowPreferredWidth ? 100 : 190 ) );
if ( sideBox )
{
mainLayout->addWidget( sideBox );
@ -219,9 +319,19 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
// and requires an extra show() (at least with KWin/X11) which
// is too annoying. Instead, leave it up to ignoring-the-quit-
// event, which is also the ViewManager's responsibility.
QBoxLayout* contentsLayout = new QVBoxLayout;
contentsLayout->addWidget( m_viewManager->centralWidget() );
QWidget* navigation = flavoredWidget(
branding->navigationFlavor(), this, &CalamaresWindow::getWidgetNavigation, &CalamaresWindow::getQmlNavigation );
if ( navigation )
{
contentsLayout->addWidget( navigation );
}
mainLayout->addLayout( contentsLayout );
mainLayout->addWidget( m_viewManager->centralWidget() );
CalamaresUtils::unmarginLayout( mainLayout );
CalamaresUtils::unmarginLayout( contentsLayout );
setStyleSheet( Calamares::Branding::instance()->stylesheet() );
}

View File

@ -51,9 +51,14 @@ protected:
virtual void closeEvent( QCloseEvent* e ) override;
private:
// Two variations on sidebar (the progress view)
QWidget* getWidgetSidebar( int desiredWidth );
QWidget* getQmlSidebar( int desiredWidth );
// Two variations on navigation (buttons at bottom)
QWidget* getWidgetNavigation();
QWidget* getQmlNavigation();
QPointer< Calamares::DebugWindow > m_debugWindow; // Managed by self
Calamares::ViewManager* m_viewManager;
};

View File

@ -0,0 +1,57 @@
import io.calamares.ui 1.0
import io.calamares.core 1.0
import QtQuick 2.3
import QtQuick.Controls 2.10
import QtQuick.Layouts 1.3
Rectangle {
id: navigationBar;
color: Branding.styleString( Branding.SidebarBackground );
RowLayout {
id: buttonBar
height: 64;
anchors.fill: parent;
Item
{
Layout.fillWidth: true;
}
Button
{
text: ViewManager.backLabel;
icon.name: ViewManager.backIcon;
enabled: ViewManager.backEnabled;
visible: true;
onClicked: { ViewManager.back(); }
}
Button
{
text: ViewManager.nextLabel;
icon.name: ViewManager.nextIcon;
enabled: ViewManager.nextEnabled;
visible: true;
onClicked: { ViewManager.next(); }
}
Button
{
Layout.leftMargin: 3 * buttonBar.spacing; // little gap from back/next
Layout.rightMargin: 2 * buttonBar.spacing
text: ViewManager.quitLabel;
icon.name: ViewManager.quitIcon;
ToolTip.visible: hovered
ToolTip.timeout: 5000
ToolTip.delay: 1000
ToolTip.text: ViewManager.quitTooltip;
enabled: ViewManager.quitEnabled;
visible: ViewManager.quitVisible;
onClicked: { ViewManager.quit(); }
}
}
}

View File

@ -1,35 +1,49 @@
import QtQuick 2.3
import io.calamares.ui 1.0
import io.calamares.core 1.0
Column {
import QtQuick 2.3
import QtQuick.Layouts 1.3
Rectangle {
id: hello
width: 200
height: 100
color: "red"
id: sideBar;
color: Branding.styleString( Branding.SidebarBackground );
Text {
anchors.centerIn: parent
text: Branding.string(Branding.VersionedName)
}
}
ColumnLayout {
anchors.fill: parent;
spacing: 0;
/* perhaps we could show a branding image here */
Image {
Layout.topMargin: 12;
Layout.bottomMargin: 12;
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
id: logo;
width: 80;
height: width; // square
source: "file:/" + Branding.imagePath(Branding.ProductLogo);
sourceSize.width: width;
sourceSize.height: height;
}
Repeater {
model: ViewManager
Rectangle {
width: 200
height: 75
color: "black"
Repeater {
model: ViewManager
Rectangle {
Layout.leftMargin: 12;
width: parent.width - 24;
height: 35;
radius: 6;
color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarTextHighlight : Branding.SidebarBackground );
Text {
color: completed ? "green" : "yellow"
text: display
Text {
anchors.verticalCenter: parent.verticalCenter;
x: parent.x + 12;
color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarTextSelect : Branding.SidebarText );
text: display;
}
}
}
Item {
Layout.fillHeight: true;
}
}
}
}

View File

@ -1,5 +1,6 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="calamares-sidebar.qml">calamares-sidebar.qml</file>
<file alias="calamares-navigation.qml">calamares-navigation.qml</file>
</qresource>
</RCC>

View File

@ -1,7 +1,7 @@
/* === 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>
* Copyright 2017, 2019-2020, 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,10 +19,10 @@
#include "ProgressTreeDelegate.h"
#include "Branding.h"
#include "CalamaresApplication.h"
#include "CalamaresWindow.h"
#include "ViewManager.h"
#include "Branding.h"
#include "utils/CalamaresUtilsGui.h"
#include <QPainter>
@ -85,10 +85,7 @@ ProgressTreeDelegate::paintViewStep( QPainter* painter,
font.setBold( false );
painter->setFont( font );
bool isCurrent = false;
isCurrent = index.data( Calamares::ViewManager::ProgressTreeItemCurrentRole ).toBool();
if ( isCurrent )
if ( index.row() == index.data( Calamares::ViewManager::ProgressTreeItemCurrentIndex ).toInt() )
{
painter->setPen( Calamares::Branding::instance()->styleString( Calamares::Branding::SidebarTextSelect ) );
QString textHighlight

View File

@ -183,7 +183,7 @@ load_module( const ModuleConfig& moduleConfig )
cDebug() << "Module" << moduleName << "job-configuration:" << configFile;
Calamares::Module* module = Calamares::Module::fromDescriptor( descriptor, name, configFile, moduleDirectory );
Calamares::Module* module = Calamares::moduleFromDescriptor( descriptor, name, configFile, moduleDirectory );
return module;
}

View File

@ -39,6 +39,10 @@ set( libSources
# Modules
modulesystem/InstanceKey.cpp
modulesystem/Module.cpp
modulesystem/Requirement.cpp
modulesystem/RequirementsChecker.cpp
modulesystem/RequirementsModel.cpp
# Network service
network/Manager.cpp

View File

@ -65,9 +65,9 @@ mount( const std::string& device_path,
const std::string& options )
{
return CalamaresUtils::Partition::mount( QString::fromStdString( device_path ),
QString::fromStdString( mount_point ),
QString::fromStdString( filesystem_name ),
QString::fromStdString( options ) );
QString::fromStdString( mount_point ),
QString::fromStdString( filesystem_name ),
QString::fromStdString( options ) );
}

View File

@ -94,8 +94,7 @@ private:
}
};
QDebug&
operator <<( QDebug& s, const Calamares::ModuleSystem::InstanceKey& i );
QDebug& operator<<( QDebug& s, const Calamares::ModuleSystem::InstanceKey& i );
} // namespace ModuleSystem
} // namespace Calamares

View File

@ -20,30 +20,18 @@
#include "Module.h"
#include "CalamaresConfig.h"
#include "CppJobModule.h"
#include "ProcessJobModule.h"
#include "Settings.h"
#include "ViewModule.h"
#include "utils/Dirs.h"
#include "utils/Logger.h"
#include "utils/NamedEnum.h"
#include "utils/Yaml.h"
#ifdef WITH_PYTHON
#include "PythonJobModule.h"
#endif
#ifdef WITH_PYTHONQT
#include "PythonQtViewModule.h"
#endif
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QString>
static const char EMERGENCY[] = "emergency";
namespace Calamares
@ -66,111 +54,6 @@ Module::initFrom( const Calamares::ModuleSystem::Descriptor& moduleDescriptor, c
}
}
Module*
Module::fromDescriptor( const Calamares::ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory )
{
std::unique_ptr< Module > m;
QString typeString = moduleDescriptor.value( "type" ).toString();
QString intfString = moduleDescriptor.value( "interface" ).toString();
if ( typeString.isEmpty() || intfString.isEmpty() )
{
cError() << "Bad module descriptor format" << instanceId;
return nullptr;
}
if ( ( typeString == "view" ) || ( typeString == "viewmodule" ) )
{
if ( intfString == "qtplugin" )
{
m.reset( new ViewModule() );
}
else if ( intfString == "pythonqt" )
{
#ifdef WITH_PYTHONQT
m.reset( new PythonQtViewModule() );
#else
cError() << "PythonQt view modules are not supported in this version of Calamares.";
#endif
}
else
{
cError() << "Bad interface" << intfString << "for module type" << typeString;
}
}
else if ( typeString == "job" )
{
if ( intfString == "qtplugin" )
{
m.reset( new CppJobModule() );
}
else if ( intfString == "process" )
{
m.reset( new ProcessJobModule() );
}
else if ( intfString == "python" )
{
#ifdef WITH_PYTHON
m.reset( new PythonJobModule() );
#else
cError() << "Python modules are not supported in this version of Calamares.";
#endif
}
else
{
cError() << "Bad interface" << intfString << "for module type" << typeString;
}
}
else
{
cError() << "Bad module type" << typeString;
}
if ( !m )
{
cError() << "Bad module type (" << typeString << ") or interface string (" << intfString << ") for module "
<< instanceId;
return nullptr;
}
QDir moduleDir( moduleDirectory );
if ( moduleDir.exists() && moduleDir.isReadable() )
{
m->m_directory = moduleDir.absolutePath();
}
else
{
cError() << "Bad module directory" << moduleDirectory << "for" << instanceId;
return nullptr;
}
m->initFrom( moduleDescriptor, instanceId );
if ( !m->m_key.isValid() )
{
cError() << "Module" << instanceId << "invalid ID";
return nullptr;
}
m->initFrom( moduleDescriptor );
if ( !configFileName.isEmpty() )
{
try
{
m->loadConfigurationFile( configFileName );
}
catch ( YAML::Exception& e )
{
cError() << "YAML parser error " << e.what();
return nullptr;
}
}
return m.release();
}
static QStringList
moduleConfigurationCandidates( bool assumeBuildDir, const QString& moduleName, const QString& configFileName )
{
@ -211,7 +94,8 @@ moduleConfigurationCandidates( bool assumeBuildDir, const QString& moduleName, c
return paths;
}
void Module::loadConfigurationFile( const QString& configFileName ) //throws YAML::Exception
void
Module::loadConfigurationFile( const QString& configFileName ) //throws YAML::Exception
{
QStringList configCandidates
= moduleConfigurationCandidates( Settings::instance()->debugMode(), name(), configFileName );

View File

@ -20,12 +20,12 @@
#ifndef CALAMARES_MODULE_H
#define CALAMARES_MODULE_H
#include "Job.h"
#include "Requirement.h"
#include "DllMacro.h"
#include "Job.h"
#include "modulesystem/Descriptor.h"
#include "modulesystem/InstanceKey.h"
#include "modulesystem/Requirement.h"
#include <QStringList>
#include <QVariant>
@ -33,6 +33,12 @@
namespace Calamares
{
class Module;
Module* moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
/**
* @brief The Module class is a common supertype for Calamares modules.
@ -40,7 +46,7 @@ namespace Calamares
* takes care of creating an object of the correct type starting from a module
* descriptor structure.
*/
class UIDLLEXPORT Module
class DLLEXPORT Module
{
public:
/**
@ -68,18 +74,6 @@ public:
PythonQt // Views only, available as enum even if PythonQt isn't used
};
/**
* @brief fromDescriptor creates a new Module object of the correct type.
* @param moduleDescriptor a module descriptor, already parsed into a variant map.
* @param instanceId the instance id of the new module instance.
* @param configFileName the name of the configuration file to read.
* @param moduleDirectory the path to the directory with this module's files.
* @return a pointer to an object of a subtype of Module.
*/
static Module* fromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
virtual ~Module();
/**
@ -193,6 +187,11 @@ private:
QString m_directory;
ModuleSystem::InstanceKey m_key;
friend Module* Calamares::moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
};
} // namespace Calamares

View File

@ -18,6 +18,8 @@
#ifndef CALAMARES_REQUIREMENT_H
#define CALAMARES_REQUIREMENT_H
#include "DllMacro.h"
#include <QList>
#include <QMetaType>
#include <QString>

View File

@ -18,18 +18,16 @@
#include "RequirementsChecker.h"
#include "Module.h"
#include "Requirement.h"
#include "modulesystem/Module.h"
#include "modulesystem/Requirement.h"
#include "utils/Logger.h"
#include <algorithm>
#include <QFuture>
#include <QFutureWatcher>
#include <QTimer>
#include <QtConcurrent/QtConcurrent>
#include <algorithm>
namespace Calamares
{

View File

@ -18,14 +18,13 @@
#ifndef CALAMARES_REQUIREMENTSCHECKER_H
#define CALAMARES_REQUIREMENTSCHECKER_H
#include "Requirement.h"
#include "modulesystem/Requirement.h"
#include <QFutureWatcher>
#include <QObject>
#include <QTimer>
#include <QVector>
namespace Calamares
{
@ -44,7 +43,7 @@ public:
RequirementsChecker( QVector< Module* > modules, QObject* parent = nullptr );
virtual ~RequirementsChecker() override;
public slots:
public Q_SLOTS:
/// @brief Start checking all the requirements
void run();

View File

@ -0,0 +1,81 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019-2020, 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 "RequirementsModel.h"
namespace Calamares
{
void
RequirementsModel::setRequirementsList( const Calamares::RequirementsList& requirements )
{
emit beginResetModel();
m_requirements = requirements;
auto isUnSatisfied = []( const Calamares::RequirementEntry& e ) { return !e.satisfied; };
auto isMandatoryAndUnSatisfied = []( const Calamares::RequirementEntry& e ) { return e.mandatory && !e.satisfied; };
m_satisfiedRequirements = std::none_of( m_requirements.begin(), m_requirements.end(), isUnSatisfied );
m_satisfiedMandatory = std::none_of( m_requirements.begin(), m_requirements.end(), isMandatoryAndUnSatisfied );
emit satisfiedRequirementsChanged( m_satisfiedRequirements );
emit satisfiedMandatoryChanged( m_satisfiedMandatory );
emit endResetModel();
}
int
RequirementsModel::rowCount( const QModelIndex& ) const
{
return m_requirements.count();
}
QVariant
RequirementsModel::data( const QModelIndex& index, int role ) const
{
const auto requirement = m_requirements.at( index.row() );
switch ( role )
{
case Roles::Name:
return requirement.name;
case Roles::Details:
return requirement.enumerationText();
case Roles::NegatedText:
return requirement.negatedText();
case Roles::Satisfied:
return requirement.satisfied;
case Roles::Mandatory:
return requirement.mandatory;
default:
return QVariant();
}
}
QHash< int, QByteArray >
RequirementsModel::roleNames() const
{
static QHash< int, QByteArray > roles;
roles[ Roles::Name ] = "name";
roles[ Roles::Details ] = "details";
roles[ Roles::NegatedText ] = "negatedText";
roles[ Roles::Satisfied ] = "satisfied";
roles[ Roles::Mandatory ] = "mandatory";
return roles;
}
} // namespace Calamares

View File

@ -0,0 +1,81 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019-2020, 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_REQUIREMENTSMODEL_H
#define CALAMARES_REQUIREMENTSMODEL_H
#include "Requirement.h"
#include "DllMacro.h"
#include <QAbstractListModel>
namespace Calamares
{
class DLLEXPORT RequirementsModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY( bool satisfiedRequirements READ satisfiedRequirements NOTIFY satisfiedRequirementsChanged FINAL )
Q_PROPERTY( bool satisfiedMandatory READ satisfiedMandatory NOTIFY satisfiedMandatoryChanged FINAL )
public:
using QAbstractListModel::QAbstractListModel;
enum Roles : short
{
Name,
Satisfied,
Mandatory,
Details,
NegatedText,
HasDetails
};
// No Q_ENUM because these are exposed through roleNames()
bool satisfiedRequirements() const { return m_satisfiedRequirements; }
bool satisfiedMandatory() const { return m_satisfiedMandatory; }
const Calamares::RequirementEntry& getEntry( int index ) const
{
return m_requirements.at( index );
}
void setRequirementsList( const Calamares::RequirementsList& requirements );
QVariant data( const QModelIndex& index, int role ) const override;
int rowCount( const QModelIndex& ) const override;
int count() const { return m_requirements.count(); }
signals:
void satisfiedRequirementsChanged( bool value );
void satisfiedMandatoryChanged( bool value );
protected:
QHash< int, QByteArray > roleNames() const override;
private:
Calamares::RequirementsList m_requirements;
bool m_satisfiedRequirements = false;
bool m_satisfiedMandatory = false;
};
} // namespace Calamares
#endif

View File

@ -138,4 +138,5 @@ ModuleSystemTests::testBadFromStringCases()
QTEST_GUILESS_MAIN( ModuleSystemTests )
#include "utils/moc-warnings.h"
#include "Tests.moc"

View File

@ -286,4 +286,5 @@ Manager::asynchronousGet( const QUrl& url, const CalamaresUtils::Network::Reques
} // namespace CalamaresUtils
#include "utils/moc-warnings.h"
#include "Manager.moc"

View File

@ -47,6 +47,7 @@ NetworkTests::testPing()
using namespace CalamaresUtils::Network;
Logger::setupLogLevel( Logger::LOGVERBOSE );
auto& nam = Manager::instance();
auto canPing_www_kde_org = nam.synchronousPing( QUrl( "https://www.kde.org" ), RequestOptions( RequestOptions::FollowRedirect ) );
auto canPing_www_kde_org
= nam.synchronousPing( QUrl( "https://www.kde.org" ), RequestOptions( RequestOptions::FollowRedirect ) );
QVERIFY( canPing_www_kde_org );
}

View File

@ -0,0 +1,43 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2020, 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 UTILS_RAII_H
#define UTILS_RAII_H
#include <QObject>
#include <type_traits>
/// @brief Convenience to zero out and deleteLater of any QObject-derived-class
template < typename T >
struct cqDeleter
{
T*& p;
~cqDeleter()
{
static_assert( std::is_base_of< QObject, T >::value, "Not a QObject-class" );
if ( p )
{
p->deleteLater();
}
p = nullptr;
}
};
#endif

View File

@ -419,10 +419,11 @@ Branding::initSimpleSettings( const YAML::Node& doc )
{ QStringLiteral( "free" ), WindowPlacement::Free },
{ QStringLiteral( "center" ), WindowPlacement::Center }
};
static const NamedEnumTable< SidebarFlavor > sidebarFlavorNames {
{ QStringLiteral( "widget" ), SidebarFlavor::Widget },
{ QStringLiteral( "none" ), SidebarFlavor::None },
{ QStringLiteral( "qml" ), SidebarFlavor::Qml }
static const NamedEnumTable< PanelFlavor > sidebarFlavorNames {
{ QStringLiteral( "widget" ), PanelFlavor::Widget },
{ QStringLiteral( "none" ), PanelFlavor::None },
{ QStringLiteral( "hidden" ), PanelFlavor::None },
{ QStringLiteral( "qml" ), PanelFlavor::Qml }
};
// clang-format on
// *INDENT-ON*
@ -448,6 +449,12 @@ Branding::initSimpleSettings( const YAML::Node& doc )
cWarning() << "Branding module-setting *sidebar* interpreted as"
<< sidebarFlavorNames.find( m_sidebarFlavor, ok );
}
m_navigationFlavor = sidebarFlavorNames.find( getString( doc, "navigation" ), ok);
if ( !ok )
{
cWarning() << "Branding module-setting *navigation* interpreted as"
<< sidebarFlavorNames.find( m_navigationFlavor, ok );
}
QString windowSize = getString( doc, "windowSize" );
if ( !windowSize.isEmpty() )

View File

@ -124,13 +124,13 @@ public:
};
Q_ENUM( WindowPlacement )
///@brief What kind of sidebar to use in the main window
enum class SidebarFlavor
enum class PanelFlavor
{
None,
Widget,
Qml
};
Q_ENUM( SidebarFlavor )
Q_ENUM( PanelFlavor )
static Branding* instance();
@ -185,7 +185,9 @@ public:
bool windowPlacementCentered() const { return m_windowPlacement == WindowPlacement::Center; }
///@brief Which sidebar flavor is configured
SidebarFlavor sidebarFlavor() const { return m_sidebarFlavor; }
PanelFlavor sidebarFlavor() const { return m_sidebarFlavor; }
///@brief Which navigation flavor is configured
PanelFlavor navigationFlavor() const { return m_navigationFlavor; }
/**
* Creates a map called "branding" in the global storage, and inserts an
@ -227,7 +229,8 @@ private:
WindowDimension m_windowHeight, m_windowWidth;
WindowPlacement m_windowPlacement;
SidebarFlavor m_sidebarFlavor = SidebarFlavor::Widget;
PanelFlavor m_sidebarFlavor = PanelFlavor::Widget;
PanelFlavor m_navigationFlavor = PanelFlavor::Widget;
};
template < typename U >

View File

@ -6,11 +6,9 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/libcalamares ${CMAKE_BINARY_DIR}/sr
set( calamaresui_SOURCES
modulesystem/CppJobModule.cpp
modulesystem/Module.cpp
modulesystem/ModuleFactory.cpp
modulesystem/ModuleManager.cpp
modulesystem/ProcessJobModule.cpp
modulesystem/Requirement.cpp
modulesystem/RequirementsChecker.cpp
modulesystem/ViewModule.cpp
utils/CalamaresUtilsGui.cpp

View File

@ -3,7 +3,7 @@
* Copyright 2019, Dominic Hayes <ferenosdev@outlook.com>
* Copyright 2019, Gabriel Craciunescu <crazy@frugalware.org>
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org>
* Copyright 2017-2018, 2020, 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
@ -38,6 +38,12 @@
#include <QMessageBox>
#include <QMetaObject>
#define UPDATE_BUTTON_PROPERTY( name, value ) \
{ \
m_##name = value; \
emit name##Changed( m_##name ); \
}
namespace Calamares
{
@ -88,43 +94,12 @@ ViewManager::ViewManager( QObject* parent )
m_stack->setContentsMargins( 0, 0, 0, 0 );
mainLayout->addWidget( m_stack );
// Create buttons and sets an initial icon; the icons may change
m_back = new QPushButton( getButtonIcon( QStringLiteral( "go-previous" ) ), tr( "&Back" ), m_widget );
m_back->setObjectName( "view-button-back" );
m_next = new QPushButton( getButtonIcon( QStringLiteral( "go-next" ) ), tr( "&Next" ), m_widget );
m_next->setObjectName( "view-button-next" );
m_quit = new QPushButton( getButtonIcon( QStringLiteral( "dialog-cancel" ) ), tr( "&Cancel" ), m_widget );
m_quit->setObjectName( "view-button-cancel" );
updateButtonLabels();
CALAMARES_RETRANSLATE_SLOT( &ViewManager::updateButtonLabels )
QBoxLayout* bottomLayout = new QHBoxLayout;
mainLayout->addLayout( bottomLayout );
bottomLayout->addStretch();
bottomLayout->addWidget( m_back );
bottomLayout->addWidget( m_next );
bottomLayout->addSpacing( 12 );
bottomLayout->addWidget( m_quit );
connect( m_next, &QPushButton::clicked, this, &ViewManager::next );
connect( m_back, &QPushButton::clicked, this, &ViewManager::back );
m_back->setEnabled( false );
connect( m_quit, &QPushButton::clicked, this, [this]() {
if ( this->confirmCancelInstallation() )
{
qApp->quit();
}
} );
connect( JobQueue::instance(), &JobQueue::failed, this, &ViewManager::onInstallationFailed );
connect( JobQueue::instance(), &JobQueue::finished, this, &ViewManager::next );
if ( Calamares::Settings::instance()->disableCancel() )
{
m_quit->setVisible( false );
}
// onInstallationFailed( "Title of Failure", "Body of Failure"); // for testing paste functionality
CALAMARES_RETRANSLATE_SLOT( &ViewManager::updateButtonLabels )
}
@ -149,7 +124,8 @@ ViewManager::addViewStep( ViewStep* step )
// If this is the first inserted view step, update status of "Next" button
if ( m_steps.count() == 1 )
{
m_next->setEnabled( step->isNextEnabled() );
m_nextEnabled = step->isNextEnabled();
emit nextEnabledChanged( m_nextEnabled );
}
}
@ -160,13 +136,15 @@ ViewManager::insertViewStep( int before, ViewStep* step )
emit beginInsertRows( QModelIndex(), before, before );
m_steps.insert( before, step );
connect( step, &ViewStep::enlarge, this, &ViewManager::enlarge );
// TODO: this can be a regular slot
connect( step, &ViewStep::nextStatusChanged, this, [this]( bool status ) {
ViewStep* vs = qobject_cast< ViewStep* >( sender() );
if ( vs )
{
if ( vs == m_steps.at( m_currentStep ) )
{
m_next->setEnabled( status );
m_nextEnabled = status;
emit nextEnabledChanged( m_nextEnabled );
}
}
} );
@ -371,8 +349,8 @@ ViewManager::next()
{
// Reached the end in a weird state (e.g. no finished step after an exec)
executing = false;
m_next->setEnabled( false );
m_back->setEnabled( false );
UPDATE_BUTTON_PROPERTY( nextEnabled, false )
UPDATE_BUTTON_PROPERTY( backEnabled, false )
}
updateCancelEnabled( !settings->disableCancel() && !( executing && settings->disableCancelDuringExec() ) );
}
@ -383,8 +361,8 @@ ViewManager::next()
if ( m_currentStep < m_steps.count() )
{
m_next->setEnabled( !executing && m_steps.at( m_currentStep )->isNextEnabled() );
m_back->setEnabled( !executing && m_steps.at( m_currentStep )->isBackEnabled() );
UPDATE_BUTTON_PROPERTY( nextEnabled, !executing && m_steps.at( m_currentStep )->isNextEnabled() )
UPDATE_BUTTON_PROPERTY( backEnabled, !executing && m_steps.at( m_currentStep )->isBackEnabled() )
}
updateButtonLabels();
@ -406,43 +384,44 @@ ViewManager::updateButtonLabels()
// If we're going into the execution step / install phase, other message
if ( stepIsExecute( m_steps, m_currentStep + 1 ) )
{
m_next->setText( nextIsInstallationStep );
setButtonIcon( m_next, "run-install" );
UPDATE_BUTTON_PROPERTY( nextLabel, nextIsInstallationStep )
UPDATE_BUTTON_PROPERTY( nextIcon, "run-install" )
}
else
{
m_next->setText( tr( "&Next" ) );
setButtonIcon( m_next, "go-next" );
UPDATE_BUTTON_PROPERTY( nextLabel, tr( "&Next" ) )
UPDATE_BUTTON_PROPERTY( nextIcon, "go-next" )
}
// Going back is always simple
m_back->setText( tr( "&Back" ) );
UPDATE_BUTTON_PROPERTY( backLabel, tr( "&Back" ) )
UPDATE_BUTTON_PROPERTY( backIcon, "go-back" )
// Cancel button changes label at the end
if ( isAtVeryEnd( m_steps, m_currentStep ) )
{
m_quit->setText( tr( "&Done" ) );
m_quit->setToolTip( quitOnCompleteTooltip );
m_quit->setVisible( true ); // At end, always visible and enabled.
setButtonIcon( m_quit, "dialog-ok-apply" );
UPDATE_BUTTON_PROPERTY( quitLabel, tr( "&Done" ) )
UPDATE_BUTTON_PROPERTY( quitTooltip, quitOnCompleteTooltip )
UPDATE_BUTTON_PROPERTY( quitVisible, true )
UPDATE_BUTTON_PROPERTY( quitIcon, "dialog-ok-apply" )
updateCancelEnabled( true );
if ( settings->quitAtEnd() )
{
m_quit->click();
quit();
}
}
else
{
if ( settings->disableCancel() )
{
m_quit->setVisible( false ); // In case we went back from final
UPDATE_BUTTON_PROPERTY( quitVisible, false )
}
updateCancelEnabled( !settings->disableCancel()
&& !( stepIsExecute( m_steps, m_currentStep ) && settings->disableCancelDuringExec() ) );
m_quit->setText( tr( "&Cancel" ) );
m_quit->setToolTip( cancelBeforeInstallationTooltip );
setButtonIcon( m_quit, "dialog-cancel" );
UPDATE_BUTTON_PROPERTY( quitLabel, tr( "&Cancel" ) )
UPDATE_BUTTON_PROPERTY( quitTooltip, cancelBeforeInstallationTooltip )
UPDATE_BUTTON_PROPERTY( quitIcon, "dialog-cancel" )
}
}
@ -467,17 +446,25 @@ ViewManager::back()
return;
}
m_next->setEnabled( m_steps.at( m_currentStep )->isNextEnabled() );
m_back->setEnabled( m_steps.at( m_currentStep )->isBackEnabled() );
if ( m_currentStep == 0 && m_steps.first()->isAtBeginning() )
{
m_back->setEnabled( false );
}
UPDATE_BUTTON_PROPERTY( nextEnabled, m_steps.at( m_currentStep )->isNextEnabled() )
UPDATE_BUTTON_PROPERTY( backEnabled,
( m_currentStep == 0 && m_steps.first()->isAtBeginning() )
? false
: m_steps.at( m_currentStep )->isBackEnabled() )
updateButtonLabels();
}
void
ViewManager::quit()
{
if ( confirmCancelInstallation() )
{
qApp->quit();
}
}
bool
ViewManager::confirmCancelInstallation()
{
@ -516,7 +503,7 @@ ViewManager::confirmCancelInstallation()
void
ViewManager::updateCancelEnabled( bool enabled )
{
m_quit->setEnabled( enabled );
UPDATE_BUTTON_PROPERTY( quitEnabled, enabled )
emit cancelEnabled( enabled );
}
@ -559,23 +546,8 @@ ViewManager::data( const QModelIndex& index, int role ) const
{
return QVariant();
}
case ProgressTreeItemCurrentRole:
return currentStep() == step;
case ProgressTreeItemCompletedRole:
// Every step *before* the current step is considered "complete"
for ( const auto* otherstep : m_steps )
{
if ( otherstep == currentStep() )
{
break;
}
if ( otherstep == step )
{
return true;
}
}
// .. and the others (including current) are not.
return false;
case ProgressTreeItemCurrentIndex:
return m_currentStep;
default:
return QVariant();
}
@ -592,13 +564,4 @@ ViewManager::rowCount( const QModelIndex& parent ) const
return m_steps.length();
}
QHash< int, QByteArray >
ViewManager::roleNames() const
{
auto h = QAbstractListModel::roleNames();
h.insert( ProgressTreeItemCurrentRole, "current" );
h.insert( ProgressTreeItemCompletedRole, "completed" );
return h;
}
} // namespace Calamares

View File

@ -37,6 +37,23 @@ namespace Calamares
class UIDLLEXPORT ViewManager : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY( int currentStepIndex READ currentStepIndex NOTIFY currentStepChanged FINAL )
Q_PROPERTY( bool nextEnabled READ nextEnabled NOTIFY nextEnabledChanged FINAL )
Q_PROPERTY( QString nextLabel READ nextLabel NOTIFY nextLabelChanged FINAL )
Q_PROPERTY( QString nextIcon READ nextIcon NOTIFY nextIconChanged FINAL )
Q_PROPERTY( bool backEnabled READ backEnabled NOTIFY backEnabledChanged FINAL )
Q_PROPERTY( QString backLabel READ backLabel NOTIFY backLabelChanged FINAL )
Q_PROPERTY( QString backIcon READ backIcon NOTIFY backIconChanged FINAL )
Q_PROPERTY( bool quitEnabled READ quitEnabled NOTIFY quitEnabledChanged FINAL )
Q_PROPERTY( QString quitLabel READ quitLabel NOTIFY quitLabelChanged FINAL )
Q_PROPERTY( QString quitIcon READ quitIcon NOTIFY quitIconChanged FINAL )
Q_PROPERTY( QString quitTooltip READ quitTooltip NOTIFY quitTooltipChanged FINAL )
Q_PROPERTY( bool quitVisible READ quitVisible NOTIFY quitVisibleChanged FINAL )
public:
/**
* @brief instance access to the ViewManager singleton.
@ -90,13 +107,25 @@ public:
*/
bool confirmCancelInstallation();
public slots:
public Q_SLOTS:
/**
* @brief next moves forward to the next page of the current ViewStep (if any),
* or to the first page of the next ViewStep if the current ViewStep doesn't
* have any more pages.
*/
void next();
bool nextEnabled() const
{
return m_nextEnabled; ///< Is the next-button to be enabled
}
QString nextLabel() const
{
return m_nextLabel; ///< What should be displayed on the next-button
}
QString nextIcon() const
{
return m_nextIcon; ///< Name of the icon to show
}
/**
* @brief back moves backward to the previous page of the current ViewStep (if any),
@ -104,6 +133,42 @@ public slots:
* have any pages before the current one.
*/
void back();
bool backEnabled() const
{
return m_backEnabled; ///< Is the back-button to be enabled
}
QString backLabel() const
{
return m_backLabel; ///< What should be displayed on the back-button
}
QString backIcon() const
{
return m_backIcon; ///< Name of the icon to show
}
/**
* @brief Probably quit
*
* Asks for confirmation if necessary. Terminates the application.
*/
void quit();
bool quitEnabled() const
{
return m_quitEnabled; ///< Is the quit-button to be enabled
}
QString quitLabel() const
{
return m_quitLabel; ///< What should be displayed on the quit-button
}
QString quitIcon() const
{
return m_quitIcon; ///< Name of the icon to show
}
bool quitVisible() const
{
return m_quitVisible; ///< Should the quit-button be visible
}
QString quitTooltip() const { return m_quitTooltip; }
/**
* @brief onInstallationFailed displays an error message when a fatal failure
@ -124,6 +189,20 @@ signals:
void enlarge( QSize enlarge ) const; // See ViewStep::enlarge()
void cancelEnabled( bool enabled ) const;
void nextEnabledChanged( bool ) const;
void nextLabelChanged( QString ) const;
void nextIconChanged( QString ) const;
void backEnabledChanged( bool ) const;
void backLabelChanged( QString ) const;
void backIconChanged( QString ) const;
void quitEnabledChanged( bool ) const;
void quitLabelChanged( QString ) const;
void quitIconChanged( QString ) const;
void quitVisibleChanged( bool ) const;
void quitTooltipChanged( QString ) const;
private:
explicit ViewManager( QObject* parent = nullptr );
virtual ~ViewManager() override;
@ -139,9 +218,20 @@ private:
QWidget* m_widget;
QStackedWidget* m_stack;
QPushButton* m_back;
QPushButton* m_next;
QPushButton* m_quit;
bool m_nextEnabled = false;
QString m_nextLabel;
QString m_nextIcon; ///< Name of icon to show on button
bool m_backEnabled = false;
QString m_backLabel;
QString m_backIcon;
bool m_quitEnabled = false;
QString m_quitLabel;
QString m_quitIcon;
QString m_quitTooltip;
bool m_quitVisible = true;
public:
/** @section Model
@ -151,14 +241,11 @@ public:
*/
enum Role
{
ProgressTreeItemCurrentRole = Qt::UserRole + 11, ///< Is this the *current* step?
ProgressTreeItemCompletedRole = Qt::UserRole + 12 ///< Are we past this one?
ProgressTreeItemCurrentIndex = Qt::UserRole + 13 ///< Index (row) of the current step
};
QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const override;
int rowCount( const QModelIndex& parent = QModelIndex() ) const override;
QHash< int, QByteArray > roleNames() const override;
};
} // namespace Calamares

View File

@ -21,8 +21,8 @@
#ifndef CALAMARES_CPPJOBMODULE_H
#define CALAMARES_CPPJOBMODULE_H
#include "Module.h"
#include "DllMacro.h"
#include "modulesystem/Module.h"
class QPluginLoader;
@ -42,12 +42,16 @@ protected:
void initFrom( const QVariantMap& moduleDescriptor ) override;
private:
friend class Module; //so only the superclass can instantiate
explicit CppJobModule();
virtual ~CppJobModule() override;
QPluginLoader* m_loader;
job_ptr m_job;
friend Module* Calamares::moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
};
} // namespace Calamares

View File

@ -0,0 +1,154 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2018, 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 "ModuleFactory.h"
#include "CalamaresConfig.h"
#include "CppJobModule.h"
#include "ProcessJobModule.h"
#include "ViewModule.h"
#include "utils/Dirs.h"
#include "utils/Logger.h"
#include "utils/NamedEnum.h"
#include "utils/Yaml.h"
#ifdef WITH_PYTHON
#include "PythonJobModule.h"
#endif
#ifdef WITH_PYTHONQT
#include "PythonQtViewModule.h"
#endif
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QString>
namespace Calamares
{
Module*
moduleFromDescriptor( const Calamares::ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory )
{
std::unique_ptr< Module > m;
QString typeString = moduleDescriptor.value( "type" ).toString();
QString intfString = moduleDescriptor.value( "interface" ).toString();
if ( typeString.isEmpty() || intfString.isEmpty() )
{
cError() << "Bad module descriptor format" << instanceId;
return nullptr;
}
if ( ( typeString == "view" ) || ( typeString == "viewmodule" ) )
{
if ( intfString == "qtplugin" )
{
m.reset( new ViewModule() );
}
else if ( intfString == "pythonqt" )
{
#ifdef WITH_PYTHONQT
m.reset( new PythonQtViewModule() );
#else
cError() << "PythonQt view modules are not supported in this version of Calamares.";
#endif
}
else
{
cError() << "Bad interface" << intfString << "for module type" << typeString;
}
}
else if ( typeString == "job" )
{
if ( intfString == "qtplugin" )
{
m.reset( new CppJobModule() );
}
else if ( intfString == "process" )
{
m.reset( new ProcessJobModule() );
}
else if ( intfString == "python" )
{
#ifdef WITH_PYTHON
m.reset( new PythonJobModule() );
#else
cError() << "Python modules are not supported in this version of Calamares.";
#endif
}
else
{
cError() << "Bad interface" << intfString << "for module type" << typeString;
}
}
else
{
cError() << "Bad module type" << typeString;
}
if ( !m )
{
cError() << "Bad module type (" << typeString << ") or interface string (" << intfString << ") for module "
<< instanceId;
return nullptr;
}
QDir moduleDir( moduleDirectory );
if ( moduleDir.exists() && moduleDir.isReadable() )
{
m->m_directory = moduleDir.absolutePath();
}
else
{
cError() << "Bad module directory" << moduleDirectory << "for" << instanceId;
return nullptr;
}
m->initFrom( moduleDescriptor, instanceId );
if ( !m->m_key.isValid() )
{
cError() << "Module" << instanceId << "invalid ID";
return nullptr;
}
m->initFrom( moduleDescriptor );
if ( !configFileName.isEmpty() )
{
try
{
m->loadConfigurationFile( configFileName );
}
catch ( YAML::Exception& e )
{
cError() << "YAML parser error " << e.what();
return nullptr;
}
}
return m.release();
}
} // namespace Calamares

View File

@ -0,0 +1,47 @@
/* === 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
* 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_MODULEFACTORY_H
#define CALAMARES_MODULEFACTORY_H
#include "DllMacro.h"
#include "modulesystem/Descriptor.h"
#include "modulesystem/Module.h"
#include <QString>
namespace Calamares
{
/**
* @brief fromDescriptor creates a new Module object of the correct type.
* @param moduleDescriptor a module descriptor, already parsed into a variant map.
* @param instanceId the instance id of the new module instance.
* @param configFileName the name of the configuration file to read.
* @param moduleDirectory the path to the directory with this module's files.
* @return a pointer to an object of a subtype of Module.
*/
UIDLLEXPORT Module* moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
} // namespace Calamares
#endif // CALAMARES_MODULEFACTORY_H

View File

@ -19,11 +19,11 @@
#include "ModuleManager.h"
#include "Module.h"
#include "RequirementsChecker.h"
#include "Settings.h"
#include "ViewManager.h"
#include "Settings.h"
#include "modulesystem/Module.h"
#include "modulesystem/RequirementsChecker.h"
#include "utils/Logger.h"
#include "utils/Yaml.h"
#include "viewpages/ExecutionViewStep.h"
@ -285,10 +285,11 @@ ModuleManager::loadModules()
}
else
{
thisModule = Module::fromDescriptor( descriptor,
instanceKey.id(),
configFileName,
m_moduleDirectoriesByModuleName.value( instanceKey.module() ) );
thisModule
= Calamares::moduleFromDescriptor( descriptor,
instanceKey.id(),
configFileName,
m_moduleDirectoriesByModuleName.value( instanceKey.module() ) );
if ( !thisModule )
{
cError() << "Module" << instanceKey.toString() << "cannot be created from descriptor"

View File

@ -22,8 +22,7 @@
#include "modulesystem/Descriptor.h"
#include "modulesystem/InstanceKey.h"
#include "Requirement.h"
#include "modulesystem/Requirement.h"
#include <QObject>
#include <QStringList>

View File

@ -20,9 +20,8 @@
#ifndef CALAMARES_PROCESSJOBMODULE_H
#define CALAMARES_PROCESSJOBMODULE_H
#include "Module.h"
#include "DllMacro.h"
#include "modulesystem/Module.h"
#include <chrono>
@ -42,7 +41,6 @@ protected:
void initFrom( const QVariantMap& moduleDescriptor ) override;
private:
friend class Module;
explicit ProcessJobModule();
virtual ~ProcessJobModule() override;
@ -51,6 +49,11 @@ private:
std::chrono::seconds m_secondsTimeout;
bool m_runInChroot;
job_ptr m_job;
friend Module* Calamares::moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
};
} // namespace Calamares

View File

@ -19,9 +19,8 @@
#ifndef CALAMARES_PYTHONJOBMODULE_H
#define CALAMARES_PYTHONJOBMODULE_H
#include "Module.h"
#include "DllMacro.h"
#include "modulesystem/Module.h"
namespace Calamares
{
@ -39,13 +38,17 @@ protected:
void initFrom( const QVariantMap& moduleDescriptor ) override;
private:
friend class Module;
explicit PythonJobModule();
virtual ~PythonJobModule() override;
QString m_scriptFileName;
QString m_workingPath;
job_ptr m_job;
friend Module* Calamares::moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
};
} // namespace Calamares

View File

@ -19,8 +19,8 @@
#ifndef CALAMARES_PYTHONQTVIEWMODULE_H
#define CALAMARES_PYTHONQTVIEWMODULE_H
#include "Module.h"
#include "DllMacro.h"
#include "Module.h"
namespace Calamares
{
@ -40,7 +40,6 @@ protected:
void initFrom( const QVariantMap& moduleDescriptor ) override;
private:
friend class Module; //so only the superclass can instantiate
explicit PythonQtViewModule();
virtual ~PythonQtViewModule();
@ -48,6 +47,11 @@ private:
QString m_scriptFileName;
QString m_workingPath;
friend Module* Calamares::moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
};
} // namespace Calamares

View File

@ -20,8 +20,8 @@
#ifndef CALAMARES_VIEWMODULE_H
#define CALAMARES_VIEWMODULE_H
#include "Module.h"
#include "DllMacro.h"
#include "modulesystem/Module.h"
class QPluginLoader;
@ -45,12 +45,16 @@ protected:
void initFrom( const QVariantMap& moduleDescriptor ) override;
private:
friend class Module; //so only the superclass can instantiate
explicit ViewModule();
virtual ~ViewModule() override;
QPluginLoader* m_loader;
ViewStep* m_viewStep = nullptr;
friend Module* Calamares::moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
};
} // namespace Calamares

View File

@ -23,6 +23,7 @@
#include "network/Manager.h"
#include "utils/Logger.h"
#include "utils/RAII.h"
#include "utils/Yaml.h"
#include <QNetworkReply>
@ -96,21 +97,6 @@ Config::loadGroupList( const QUrl& url )
}
}
/// @brief Convenience to zero out and deleteLater on the reply, used in dataIsHere
struct ReplyDeleter
{
QNetworkReply*& p;
~ReplyDeleter()
{
if ( p )
{
p->deleteLater();
}
p = nullptr;
}
};
void
Config::receivedGroupData()
{
@ -123,7 +109,7 @@ Config::receivedGroupData()
cDebug() << "NetInstall group data received" << m_reply->size() << "bytes from" << m_reply->url();
ReplyDeleter d { m_reply };
cqDeleter< QNetworkReply > d{ m_reply };
// If m_required is *false* then we still say we're ready
// even if the reply is corrupt or missing.

View File

@ -19,7 +19,9 @@ least should contain a *groupsUrl* key:
The URL must point to a YAML file, the *groups* file. See below for
the format of that groups file. The URL may be a local file (e.g.
scheme `file:///`) or a regular HTTP(s) URL.
scheme `file:///`) or a regular HTTP(s) URL. The URL has one special
case: the literal string `local` is used to indicate that the groups
data is contained in the `netinstall.conf` file itself.
## Groups Configuration
@ -47,13 +49,16 @@ More keys (per group) are supported:
- *selected*: if true, display the group as selected. Defaults to false.
- *critical*: if true, make the installation process fail if installing
any of the packages in the group fails. Otherwise, just log a warning.
Defaults to false.
Defaults to false. If not set in a subgroup (see below), inherits from
the parent group.
- *immutable*: if true, the state of the group (and all its subgroups)
cannot be changed; it really only makes sense in combination
with *selected* set to true. This only affects the user-interface.
- *expanded*: if true, the group is shown in an expanded form (that is,
not-collapsed) in the treeview on start. This only affects the user-
interface.
interface. Only top-level groups are show expanded-initially.
- *immutable*: if true, the group cannot be changed (packages selected
or deselected) and no checkboxes are shown for the group.
- *subgroups*: if present this follows the same structure as the top level
of the YAML file, allowing there to be sub-groups of packages to an
arbitary depth

View File

@ -54,6 +54,8 @@ label:
# If, and only if, *groupsUrl* is set to the literal string `local`,
# groups data is read from this file. The value of *groups* must be
# a list, with the same format as the regular `netinstall.yaml` file.
# See the `README.md` file in the *netinstall* module for documentation
# on the format of groups data.
#
# This is recommended only for small static package lists.
groups:

View File

@ -471,7 +471,7 @@ PartitionViewStep::onLeave()
"<br/><br/>"
"To configure a GPT partition table on BIOS, "
"(if not done so already) go back "
"and set the partion table to GPT, next create a 8 MB "
"and set the partition table to GPT, next create a 8 MB "
"unformatted partition with the "
"<strong>bios_grub</strong> flag enabled.<br/><br/>"
"An unformatted 8 MB partition is necessary "

View File

@ -23,71 +23,15 @@
#include "utils/Logger.h"
#include "utils/Retranslator.h"
void
RequirementsModel::setRequirementsList( const Calamares::RequirementsList& requirements )
{
CALAMARES_RETRANSLATE_SLOT( &RequirementsModel::retranslate )
emit beginResetModel();
m_requirements = requirements;
auto isUnSatisfied = []( const Calamares::RequirementEntry& e ) { return !e.satisfied; };
auto isMandatoryAndUnSatisfied = []( const Calamares::RequirementEntry& e ) { return e.mandatory && !e.satisfied; };
m_satisfiedRequirements = std::none_of( m_requirements.begin(), m_requirements.end(), isUnSatisfied );
m_satisfiedMandatory = std::none_of( m_requirements.begin(), m_requirements.end(), isMandatoryAndUnSatisfied );
emit satisfiedRequirementsChanged( m_satisfiedRequirements );
emit satisfiedMandatoryChanged();
emit endResetModel();
}
int
RequirementsModel::rowCount( const QModelIndex& ) const
{
return m_requirements.count();
}
QVariant
RequirementsModel::data( const QModelIndex& index, int role ) const
{
const auto requirement = m_requirements.at( index.row() );
switch ( role )
{
case Roles::Name:
return requirement.name;
case Roles::Details:
return requirement.enumerationText();
case Roles::NegatedText:
return requirement.negatedText();
case Roles::Satisfied:
return requirement.satisfied;
case Roles::Mandatory:
return requirement.mandatory;
default:
return QVariant();
}
}
QHash< int, QByteArray >
RequirementsModel::roleNames() const
{
static QHash< int, QByteArray > roles;
roles[ Roles::Name ] = "name";
roles[ Roles::Details ] = "details";
roles[ Roles::NegatedText ] = "negatedText";
roles[ Roles::Satisfied ] = "satisfied";
roles[ Roles::Mandatory ] = "mandatory";
return roles;
}
Config::Config( QObject* parent )
: QObject( parent )
, m_requirementsModel( new RequirementsModel( this ) )
, m_requirementsModel( new Calamares::RequirementsModel( this ) )
, m_languages( CalamaresUtils::Locale::availableTranslations() )
{
connect( m_requirementsModel, &RequirementsModel::satisfiedRequirementsChanged, this, &Config::setIsNextEnabled );
connect( m_requirementsModel,
&Calamares::RequirementsModel::satisfiedRequirementsChanged,
this,
&Config::setIsNextEnabled );
initLanguages();
@ -98,9 +42,46 @@ void
Config::retranslate()
{
m_genericWelcomeMessage = genericWelcomeMessage().arg( *Calamares::Branding::VersionedName );
emit genericWelcomeMessageChanged();
emit genericWelcomeMessageChanged( m_genericWelcomeMessage );
m_requirementsModel->retranslate();
if ( !m_requirementsModel->satisfiedRequirements() )
{
QString message;
const bool setup = Calamares::Settings::instance()->isSetupMode();
if ( !m_requirementsModel->satisfiedMandatory() )
{
message = setup ? tr( "This computer does not satisfy the minimum "
"requirements for setting up %1.<br/>"
"Setup cannot continue. "
"<a href=\"#details\">Details...</a>" )
: tr( "This computer does not satisfy the minimum "
"requirements for installing %1.<br/>"
"Installation cannot continue. "
"<a href=\"#details\">Details...</a>" );
}
else
{
message = setup ? tr( "This computer does not satisfy some of the "
"recommended requirements for setting up %1.<br/>"
"Setup can continue, but some features "
"might be disabled." )
: tr( "This computer does not satisfy some of the "
"recommended requirements for installing %1.<br/>"
"Installation can continue, but some features "
"might be disabled." );
}
m_warningMessage = message.arg( *Calamares::Branding::ShortVersionedName );
}
else
{
m_warningMessage = tr( "This program will ask you some questions and "
"set up %2 on your computer." )
.arg( *Calamares::Branding::ProductName );
}
emit warningMessageChanged( m_warningMessage );
}
CalamaresUtils::Locale::LabelModel*
@ -178,7 +159,7 @@ Config::setLanguageIcon( const QString& languageIcon )
}
void
Config::setLocaleIndex( const int& index )
Config::setLocaleIndex( int index )
{
if ( index == m_localeIndex || index > CalamaresUtils::Locale::availableTranslations()->rowCount( QModelIndex() )
|| index < 0 )
@ -189,7 +170,7 @@ Config::setLocaleIndex( const int& index )
m_localeIndex = index;
const auto& selectedLocale = m_languages->locale( m_localeIndex ).locale();
cDebug() << "Selected locale" << selectedLocale;
cDebug() << "Index" << index << "Selected locale" << selectedLocale;
QLocale::setDefault( selectedLocale );
CalamaresUtils::installTranslator( selectedLocale, Calamares::Branding::instance()->translationsDirectory() );
@ -197,14 +178,14 @@ Config::setLocaleIndex( const int& index )
emit localeIndexChanged( m_localeIndex );
}
RequirementsModel&
Calamares::RequirementsModel&
Config::requirementsModel() const
{
return *m_requirementsModel;
}
void
Config::setIsNextEnabled( const bool& isNextEnabled )
Config::setIsNextEnabled( bool isNextEnabled )
{
m_isNextEnabled = isNextEnabled;
emit isNextEnabledChanged( m_isNextEnabled );
@ -262,51 +243,8 @@ Config::setSupportUrl( const QString& url )
emit supportUrlChanged();
}
void
RequirementsModel::retranslate()
{
if ( !m_satisfiedRequirements )
{
QString message;
const bool setup = Calamares::Settings::instance()->isSetupMode();
if ( !m_satisfiedMandatory )
{
message = setup ? tr( "This computer does not satisfy the minimum "
"requirements for setting up %1.<br/>"
"Setup cannot continue. "
"<a href=\"#details\">Details...</a>" )
: tr( "This computer does not satisfy the minimum "
"requirements for installing %1.<br/>"
"Installation cannot continue. "
"<a href=\"#details\">Details...</a>" );
}
else
{
message = setup ? tr( "This computer does not satisfy some of the "
"recommended requirements for setting up %1.<br/>"
"Setup can continue, but some features "
"might be disabled." )
: tr( "This computer does not satisfy some of the "
"recommended requirements for installing %1.<br/>"
"Installation can continue, but some features "
"might be disabled." );
}
m_warningMessage = message.arg( *Calamares::Branding::ShortVersionedName );
}
else
{
m_warningMessage = tr( "This program will ask you some questions and "
"set up %2 on your computer." )
.arg( *Calamares::Branding::ProductName );
}
emit warningMessageChanged();
}
QString
Config::genericWelcomeMessage()
Config::genericWelcomeMessage() const
{
QString message;
@ -325,3 +263,9 @@ Config::genericWelcomeMessage()
return message;
}
QString
Config::warningMessage() const
{
return m_warningMessage;
}

View File

@ -19,79 +19,18 @@
#ifndef WELCOME_CONFIG_H
#define WELCOME_CONFIG_H
#include "modulesystem/Requirement.h"
#include "locale/LabelModel.h"
#include "modulesystem/Requirement.h"
#include "modulesystem/RequirementsModel.h"
#include <QObject>
#include <QUrl>
// TODO: move this (and modulesystem/Requirement) to libcalamares
class RequirementsModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY( bool satisfiedRequirements READ satisfiedRequirements NOTIFY satisfiedRequirementsChanged FINAL )
Q_PROPERTY( bool satisfiedMandatory READ satisfiedMandatory NOTIFY satisfiedMandatoryChanged FINAL )
Q_PROPERTY( QString warningMessage READ warningMessage NOTIFY warningMessageChanged FINAL )
public:
using QAbstractListModel::QAbstractListModel;
enum Roles : short
{
Name,
Satisfied,
Mandatory,
Details,
NegatedText,
HasDetails
};
bool satisfiedRequirements() const { return m_satisfiedRequirements; }
bool satisfiedMandatory() const { return m_satisfiedMandatory; }
const Calamares::RequirementEntry& getEntry( const int& index ) const
{
if ( index > count() || index < 0 )
{
return *( new Calamares::RequirementEntry() );
}
return m_requirements.at( index );
}
void setRequirementsList( const Calamares::RequirementsList& requirements );
int rowCount( const QModelIndex& ) const override;
int count() const { return m_requirements.count(); }
QString warningMessage() const { return m_warningMessage; }
void retranslate();
QVariant data( const QModelIndex& index, int role ) const override;
protected:
QHash< int, QByteArray > roleNames() const override;
private:
Calamares::RequirementsList m_requirements;
bool m_satisfiedRequirements = false;
bool m_satisfiedMandatory = false;
QString m_warningMessage;
signals:
void satisfiedRequirementsChanged( bool value );
void satisfiedMandatoryChanged();
void warningMessageChanged();
};
class Config : public QObject
{
Q_OBJECT
Q_PROPERTY( CalamaresUtils::Locale::LabelModel* languagesModel READ languagesModel CONSTANT FINAL )
Q_PROPERTY( RequirementsModel* requirementsModel MEMBER m_requirementsModel CONSTANT FINAL )
Q_PROPERTY( Calamares::RequirementsModel* requirementsModel MEMBER m_requirementsModel CONSTANT FINAL )
Q_PROPERTY( QString languageIcon READ languageIcon CONSTANT FINAL )
@ -99,6 +38,7 @@ class Config : public QObject
Q_PROPERTY( int localeIndex READ localeIndex WRITE setLocaleIndex NOTIFY localeIndexChanged )
Q_PROPERTY( QString genericWelcomeMessage MEMBER m_genericWelcomeMessage NOTIFY genericWelcomeMessageChanged FINAL )
Q_PROPERTY( QString warningMessage READ warningMessage NOTIFY warningMessageChanged FINAL )
Q_PROPERTY( QString supportUrl MEMBER m_supportUrl NOTIFY supportUrlChanged FINAL )
Q_PROPERTY( QString knownIssuesUrl MEMBER m_knownIssuesUrl NOTIFY knownIssuesUrlChanged FINAL )
@ -109,13 +49,17 @@ class Config : public QObject
public:
Config( QObject* parent = nullptr );
Calamares::RequirementsModel& requirementsModel() const;
void setCountryCode( const QString& countryCode );
QString languageIcon() const;
void setLanguageIcon( const QString& languageIcon );
RequirementsModel& requirementsModel() const;
void setIsNextEnabled( const bool& isNextEnabled );
void setIsNextEnabled( bool isNextEnabled );
void setLocaleIndex( const int& index );
void setLocaleIndex( int index );
int localeIndex() const { return m_localeIndex; }
QString supportUrl() const;
@ -130,40 +74,44 @@ public:
QString donateUrl() const;
void setDonateUrl( const QString& url );
QString genericWelcomeMessage();
QString genericWelcomeMessage() const;
QString warningMessage() const;
public slots:
CalamaresUtils::Locale::LabelModel* languagesModel() const;
void retranslate();
QString languageIcon() const;
private:
void initLanguages();
QVariantMap m_configurationMap;
RequirementsModel* m_requirementsModel;
QString m_languageIcon;
QString m_countryCode;
int m_localeIndex = 0;
bool m_isNextEnabled = false;
CalamaresUtils::Locale::LabelModel* m_languages;
QString m_genericWelcomeMessage;
QString m_supportUrl;
QString m_knownIssuesUrl;
QString m_releaseNotesUrl;
QString m_donateUrl;
signals:
void countryCodeChanged( QString countryCode );
void localeIndexChanged( int localeIndex );
void isNextEnabledChanged( bool isNextEnabled );
void genericWelcomeMessageChanged();
void genericWelcomeMessageChanged( QString message );
void warningMessageChanged( QString message );
void supportUrlChanged();
void knownIssuesUrlChanged();
void releaseNotesUrlChanged();
void donateUrlChanged();
private:
void initLanguages();
Calamares::RequirementsModel* m_requirementsModel;
CalamaresUtils::Locale::LabelModel* m_languages;
QString m_languageIcon;
QString m_countryCode;
int m_localeIndex = 0;
bool m_isNextEnabled = false;
QString m_genericWelcomeMessage;
QString m_warningMessage;
QString m_supportUrl;
QString m_knownIssuesUrl;
QString m_releaseNotesUrl;
QString m_donateUrl;
};
#endif

View File

@ -47,6 +47,7 @@ WelcomeViewStep::WelcomeViewStep( QObject* parent )
// the instance of the qqc2 or qwidgets page
m_widget = new WelcomePage( m_conf );
connect( m_conf, &Config::localeIndexChanged, m_widget, &WelcomePage::externallySelectedLanguage );
}
WelcomeViewStep::~WelcomeViewStep()

View File

@ -31,7 +31,7 @@
#include <QHBoxLayout>
CheckerContainer::CheckerContainer( const RequirementsModel &model, QWidget* parent )
CheckerContainer::CheckerContainer( const Calamares::RequirementsModel &model, QWidget* parent )
: QWidget( parent )
, m_waitingWidget( new WaitingWidget( QString(), this ) )
, m_checkerWidget( nullptr )

View File

@ -40,7 +40,7 @@ class CheckerContainer : public QWidget
{
Q_OBJECT
public:
explicit CheckerContainer(const RequirementsModel &model, QWidget* parent = nullptr );
explicit CheckerContainer(const Calamares::RequirementsModel &model, QWidget* parent = nullptr );
virtual ~CheckerContainer();
bool verdict() const;
@ -58,7 +58,7 @@ protected:
bool m_verdict;
private:
const RequirementsModel &m_model;
const Calamares::RequirementsModel &m_model;
} ;
#endif

View File

@ -47,7 +47,7 @@
static void
createResultWidgets( QLayout* layout,
QList< ResultWidget* >& resultWidgets,
const RequirementsModel &model,
const Calamares::RequirementsModel &model,
std::function< bool( const Calamares::RequirementEntry& ) > predicate
)
{
@ -94,18 +94,18 @@ public:
* The list must continue to exist for the lifetime of the dialog,
* or UB happens.
*/
ResultsListDialog( const RequirementsModel& model, QWidget* parent );
ResultsListDialog( const Calamares::RequirementsModel& model, QWidget* parent );
virtual ~ResultsListDialog();
private:
QLabel* m_title;
QList< ResultWidget* > m_resultWidgets; ///< One widget for each entry with details available
const RequirementsModel& m_model;
const Calamares::RequirementsModel& m_model;
void retranslate();
};
ResultsListDialog::ResultsListDialog( const RequirementsModel& model, QWidget* parent)
ResultsListDialog::ResultsListDialog( const Calamares::RequirementsModel& model, QWidget* parent)
: QDialog( parent )
, m_model( model )
{
@ -151,7 +151,7 @@ ResultsListDialog::retranslate()
}
ResultsListWidget::ResultsListWidget( const RequirementsModel &model, QWidget* parent )
ResultsListWidget::ResultsListWidget( const Calamares::RequirementsModel &model, QWidget* parent )
: QWidget( parent )
, m_model( model )
{

View File

@ -30,7 +30,7 @@ class ResultsListWidget : public QWidget
{
Q_OBJECT
public:
explicit ResultsListWidget(const RequirementsModel &model, QWidget* parent);
explicit ResultsListWidget(const Calamares::RequirementsModel &model, QWidget* parent);
private:
/// @brief A link in the explanatory text has been clicked
@ -38,7 +38,7 @@ private:
void retranslate();
QLabel* m_explanation = nullptr; ///< Explanatory text above the list, with link
const RequirementsModel &m_model;
const Calamares::RequirementsModel &m_model;
QList< ResultWidget* > m_resultWidgets; ///< One widget for each unsatisfied entry
};

View File

@ -139,10 +139,10 @@ WelcomeQmlViewStep::setConfigurationMap( const QVariantMap& configurationMap )
m_config->setReleaseNotesUrl( jobOrBrandingSetting( Branding::ReleaseNotesUrl, configurationMap, "showReleaseNotesUrl" ) );
m_config->setDonateUrl( CalamaresUtils::getString( configurationMap, "showDonateUrl" ) );
// TODO: expand Config class and set the remaining fields // with the configurationMap all those properties can be accesed withouth having to declare a property, get and setter for each
// TODO: expand Config class and set the remaining fields // with the configurationMap all those properties can be accessed without having to declare a property, get and setter for each
// TODO: figure out how the requirements (held by ModuleManager) should be accessible
// to QML as a odel. //will be model as a qvariantmap containing a alert level and the message string
// to QML as a model. //will be model as a qvariantmap containing a alert level and the message string
if ( configurationMap.contains( "requirements" )
&& configurationMap.value( "requirements" ).type() == QVariant::Map )
{

View File

@ -0,0 +1,121 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2020, Anke Boersma <demm@kaosx.us>
*
* 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/>.
*/
import io.calamares.ui 1.0
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
Item {
width: parent.width
height: parent.height
focus: true
property var appName: "Calamares"
property var appVersion: "3.2.22"
Rectangle {
id: textArea
x: 28
y: 14
anchors.fill: parent
color: "#f2f2f2"
Column {
id: column
x: 130
y: 40
Rectangle {
width: 560
height: 250
radius: 10
border.width: 0
Text {
width: 400
height: 250
anchors.centerIn: parent
text: qsTr("<h1>%1</h1><br/>
<strong>%2<br/>
for %3</strong><br/><br/>
Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>
Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>
Thanks to <a href='https://calamares.io/team/'>the Calamares team</a>
and the <a href='https://www.transifex.com/calamares/calamares/'>Calamares
translators team</a>.<br/><br/>
<a href='https://calamares.io/'>Calamares</a>
development is sponsored by <br/>
<a href='http://www.blue-systems.com/'>Blue Systems</a> -
Liberating Software." )
.arg(appName)
.arg(appVersion)
.arg(Branding.string(Branding.VersionedName))
onLinkActivated: Qt.openUrlExternally(link)
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
font.pointSize: 10
anchors.verticalCenterOffset: 10
anchors.horizontalCenterOffset: 40
wrapMode: Text.WordWrap
}
Image {
id: image
x: 8
y: 12
height: 100
fillMode: Image.PreserveAspectFit
source: "img/squid.png"
}
}
}
ToolButton {
id: toolButton
x: 19
y: 29
width: 105
height: 48
text: qsTr("Back")
hoverEnabled: true
onClicked: load.source = ""
Image {
id: image1
x: 0
y: 13
width: 22
height: 22
source: "img/chevron-left-solid.svg"
fillMode: Image.PreserveAspectFit
}
}
}
}

View File

@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="chevron-left" class="svg-inline--fa fa-chevron-left fa-w-10" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z"></path></svg>

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@ -1,6 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2020, Adriaan de Groot <groot@kde.org>
* Copyright 2020, Anke Boersma <demm@kaosx.us>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -31,7 +32,7 @@ Page
header: Item
{
width: parent.width
height: 150
height: parent.height
Text
{
@ -39,7 +40,7 @@ Page
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
// In QML, QString::arg() only takes one argument
text: qsTr("<h3>%1 <quote>%2</quote></h3>").arg(Branding.string(Branding.ProductName)).arg(Branding.string(Branding.Version))
text: qsTr("<h3>Welcome to the %1 <quote>%2</quote> installer</h3>").arg(Branding.string(Branding.ProductName)).arg(Branding.string(Branding.Version))
}
Image
{
@ -49,10 +50,9 @@ Page
// .. otherwise the path is interpreted relative to the "call site", which
// .. might be the QRC file.
source: "file:/" + Branding.imagePath(Branding.ProductWelcome)
height: Math.min(100, parent.height)
width: height
sourceSize.width: width
sourceSize.height: height
fillMode: Image.PreserveAspectFit
}
RowLayout
@ -73,57 +73,65 @@ Page
{
Layout.fillWidth: true
text: qsTr("About")
icon.name: "documentinfo"
icon.name: "dialog-information"
Kirigami.Theme.backgroundColor: Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.4)
Kirigami.Theme.textColor: "#fff"
Kirigami.Theme.textColor: Kirigami.Theme.textColor
visible: false
onClicked: { } // TODO: show an about-Calamares window
onClicked: {
//onClicked: load.source = "file:/usr/share/calamares/branding/kaos_branding/show.qml"
onClicked: load.source = "about.qml"
}
}
Button
{
Layout.fillWidth: true
text: qsTr("Support")
icon.name: "documentinfo"
icon.name: "system-help"
Kirigami.Theme.backgroundColor: Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.4)
Kirigami.Theme.textColor: "#fff"
Kirigami.Theme.textColor: Kirigami.Theme.textColor
visible: config.helpUrl.isValid
onClicked: Qt.openUrlExternally(config.helpUrl)
visible: config.supportUrl !== ""
onClicked: Qt.openUrlExternally(config.supportUrl)
}
Button
{
Layout.fillWidth: true
text: qsTr("Known issues")
icon.name: "documentinfo"
icon.name: "tools-report-bug"
Kirigami.Theme.backgroundColor: Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.4)
Kirigami.Theme.textColor: "#fff"
Kirigami.Theme.textColor: Kirigami.Theme.textColor
visible: config.issuesUrl.isValid
onClicked: Qt.openUrlExternally(config.issuesUrl)
visible: config.knownIssuesUrl !== ""
onClicked: Qt.openUrlExternally(config.knownIssuesUrl)
}
Button
{
Layout.fillWidth: true
text: qsTr("Release notes")
icon.name: "documentinfo"
icon.name: "folder-text"
Kirigami.Theme.backgroundColor: Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.4)
Kirigami.Theme.textColor: "#fff"
Kirigami.Theme.textColor: Kirigami.Theme.textColor
visible: config.notesUrl.isValid
onClicked: Qt.openUrlExternally(config.notesUrl)
visible: config.releaseNotesUrl !== ""
onClicked: Qt.openUrlExternally(config.releaseNotesUrl)
}
Button
{
Layout.fillWidth: true
text: qsTr("Donate")
icon.name: "documentinfo"
icon.name: "taxes-finances"
Kirigami.Theme.backgroundColor: Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.4)
Kirigami.Theme.textColor: "#fff"
Kirigami.Theme.textColor: Kirigami.Theme.textColor
visible: config.donateUrl.isValid
visible: config.donateUrl !== ""
onClicked: Qt.openUrlExternally(config.donateUrl)
}
}
Loader
{
id:load
anchors.fill: parent
}
}
}

View File

@ -1,5 +1,8 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="welcomeq.qml">welcomeq.qml</file>
<file alias="about.qml">about.qml</file>
<file>img/squid.png</file>
<file>img/chevron-left-solid.svg</file>
</qresource>
</RCC>