diff --git a/CHANGES b/CHANGES
index e5958750f..3a6ebd0f3 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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):
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 837010be4..d70863929 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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
#
diff --git a/src/branding/default/branding.desc b/src/branding/default/branding.desc
index e7b9d9898..365af30e9 100644
--- a/src/branding/default/branding.desc
+++ b/src/branding/default/branding.desc
@@ -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.
diff --git a/src/calamares/CalamaresWindow.cpp b/src/calamares/CalamaresWindow.cpp
index f2ff42aa8..5d4565406 100644
--- a/src/calamares/CalamaresWindow.cpp
+++ b/src/calamares/CalamaresWindow.cpp
@@ -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() );
}
diff --git a/src/calamares/CalamaresWindow.h b/src/calamares/CalamaresWindow.h
index 5cbbdfca6..d6592c99a 100644
--- a/src/calamares/CalamaresWindow.h
+++ b/src/calamares/CalamaresWindow.h
@@ -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;
};
diff --git a/src/calamares/calamares-navigation.qml b/src/calamares/calamares-navigation.qml
new file mode 100644
index 000000000..c7cd91835
--- /dev/null
+++ b/src/calamares/calamares-navigation.qml
@@ -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(); }
+ }
+ }
+}
diff --git a/src/calamares/calamares-sidebar.qml b/src/calamares/calamares-sidebar.qml
index a486bdb17..183a9acb2 100644
--- a/src/calamares/calamares-sidebar.qml
+++ b/src/calamares/calamares-sidebar.qml
@@ -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;
}
}
}
-
-}
diff --git a/src/calamares/calamares.qrc b/src/calamares/calamares.qrc
index fdcd5e05d..17db2e08a 100644
--- a/src/calamares/calamares.qrc
+++ b/src/calamares/calamares.qrc
@@ -1,5 +1,6 @@
calamares-sidebar.qml
+ calamares-navigation.qml
diff --git a/src/calamares/progresstree/ProgressTreeDelegate.cpp b/src/calamares/progresstree/ProgressTreeDelegate.cpp
index e7041d1b9..7b7101f5d 100644
--- a/src/calamares/progresstree/ProgressTreeDelegate.cpp
+++ b/src/calamares/progresstree/ProgressTreeDelegate.cpp
@@ -1,7 +1,7 @@
/* === This file is part of Calamares - ===
*
* Copyright 2014-2015, Teo Mrnjavac
- * Copyright 2017, 2019, Adriaan de Groot
+ * Copyright 2017, 2019-2020, Adriaan de Groot
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,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
@@ -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
diff --git a/src/calamares/testmain.cpp b/src/calamares/testmain.cpp
index 0845218eb..8dcf41faa 100644
--- a/src/calamares/testmain.cpp
+++ b/src/calamares/testmain.cpp
@@ -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;
}
diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt
index 608768a97..91dce96cd 100644
--- a/src/libcalamares/CMakeLists.txt
+++ b/src/libcalamares/CMakeLists.txt
@@ -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
diff --git a/src/libcalamares/PythonJobApi.cpp b/src/libcalamares/PythonJobApi.cpp
index cf7984c87..ecca466fe 100644
--- a/src/libcalamares/PythonJobApi.cpp
+++ b/src/libcalamares/PythonJobApi.cpp
@@ -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 ) );
}
diff --git a/src/libcalamares/modulesystem/InstanceKey.h b/src/libcalamares/modulesystem/InstanceKey.h
index 495401903..724827330 100644
--- a/src/libcalamares/modulesystem/InstanceKey.h
+++ b/src/libcalamares/modulesystem/InstanceKey.h
@@ -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
diff --git a/src/libcalamaresui/modulesystem/Module.cpp b/src/libcalamares/modulesystem/Module.cpp
similarity index 64%
rename from src/libcalamaresui/modulesystem/Module.cpp
rename to src/libcalamares/modulesystem/Module.cpp
index 35b1508f1..9620299ec 100644
--- a/src/libcalamaresui/modulesystem/Module.cpp
+++ b/src/libcalamares/modulesystem/Module.cpp
@@ -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
#include
#include
#include
-
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 );
diff --git a/src/libcalamaresui/modulesystem/Module.h b/src/libcalamares/modulesystem/Module.h
similarity index 87%
rename from src/libcalamaresui/modulesystem/Module.h
rename to src/libcalamares/modulesystem/Module.h
index 0891f8a25..ba4533fae 100644
--- a/src/libcalamaresui/modulesystem/Module.h
+++ b/src/libcalamares/modulesystem/Module.h
@@ -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
#include
@@ -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
diff --git a/src/libcalamaresui/modulesystem/Requirement.cpp b/src/libcalamares/modulesystem/Requirement.cpp
similarity index 100%
rename from src/libcalamaresui/modulesystem/Requirement.cpp
rename to src/libcalamares/modulesystem/Requirement.cpp
diff --git a/src/libcalamaresui/modulesystem/Requirement.h b/src/libcalamares/modulesystem/Requirement.h
similarity index 98%
rename from src/libcalamaresui/modulesystem/Requirement.h
rename to src/libcalamares/modulesystem/Requirement.h
index 3f8d1a54b..da3cf29dd 100644
--- a/src/libcalamaresui/modulesystem/Requirement.h
+++ b/src/libcalamares/modulesystem/Requirement.h
@@ -18,6 +18,8 @@
#ifndef CALAMARES_REQUIREMENT_H
#define CALAMARES_REQUIREMENT_H
+#include "DllMacro.h"
+
#include
#include
#include
diff --git a/src/libcalamaresui/modulesystem/RequirementsChecker.cpp b/src/libcalamares/modulesystem/RequirementsChecker.cpp
similarity index 98%
rename from src/libcalamaresui/modulesystem/RequirementsChecker.cpp
rename to src/libcalamares/modulesystem/RequirementsChecker.cpp
index 41281c9b9..97a4c912f 100644
--- a/src/libcalamaresui/modulesystem/RequirementsChecker.cpp
+++ b/src/libcalamares/modulesystem/RequirementsChecker.cpp
@@ -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
-
#include
#include
#include
#include
+#include
namespace Calamares
{
diff --git a/src/libcalamaresui/modulesystem/RequirementsChecker.h b/src/libcalamares/modulesystem/RequirementsChecker.h
similarity index 97%
rename from src/libcalamaresui/modulesystem/RequirementsChecker.h
rename to src/libcalamares/modulesystem/RequirementsChecker.h
index 2e1708016..450495dc1 100644
--- a/src/libcalamaresui/modulesystem/RequirementsChecker.h
+++ b/src/libcalamares/modulesystem/RequirementsChecker.h
@@ -18,14 +18,13 @@
#ifndef CALAMARES_REQUIREMENTSCHECKER_H
#define CALAMARES_REQUIREMENTSCHECKER_H
-#include "Requirement.h"
+#include "modulesystem/Requirement.h"
#include
#include
#include
#include
-
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();
diff --git a/src/libcalamares/modulesystem/RequirementsModel.cpp b/src/libcalamares/modulesystem/RequirementsModel.cpp
new file mode 100644
index 000000000..4001d2d81
--- /dev/null
+++ b/src/libcalamares/modulesystem/RequirementsModel.cpp
@@ -0,0 +1,81 @@
+/* === This file is part of Calamares - ===
+ *
+ * Copyright 2019-2020, Adriaan de Groot
+ *
+ * Calamares is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Calamares is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Calamares. If not, see .
+ */
+
+#include "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
diff --git a/src/libcalamares/modulesystem/RequirementsModel.h b/src/libcalamares/modulesystem/RequirementsModel.h
new file mode 100644
index 000000000..2acf785e7
--- /dev/null
+++ b/src/libcalamares/modulesystem/RequirementsModel.h
@@ -0,0 +1,81 @@
+/* === This file is part of Calamares - ===
+ *
+ * Copyright 2019-2020, Adriaan de Groot
+ *
+ * Calamares is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Calamares is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Calamares. If not, see .
+ */
+
+#ifndef CALAMARES_REQUIREMENTSMODEL_H
+#define CALAMARES_REQUIREMENTSMODEL_H
+
+#include "Requirement.h"
+
+#include "DllMacro.h"
+
+#include
+
+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
diff --git a/src/libcalamares/modulesystem/Tests.cpp b/src/libcalamares/modulesystem/Tests.cpp
index e7301a0be..b1fab7ffc 100644
--- a/src/libcalamares/modulesystem/Tests.cpp
+++ b/src/libcalamares/modulesystem/Tests.cpp
@@ -138,4 +138,5 @@ ModuleSystemTests::testBadFromStringCases()
QTEST_GUILESS_MAIN( ModuleSystemTests )
#include "utils/moc-warnings.h"
+
#include "Tests.moc"
diff --git a/src/libcalamares/network/Manager.cpp b/src/libcalamares/network/Manager.cpp
index 1d58efba9..6e8a1e93d 100644
--- a/src/libcalamares/network/Manager.cpp
+++ b/src/libcalamares/network/Manager.cpp
@@ -286,4 +286,5 @@ Manager::asynchronousGet( const QUrl& url, const CalamaresUtils::Network::Reques
} // namespace CalamaresUtils
#include "utils/moc-warnings.h"
+
#include "Manager.moc"
diff --git a/src/libcalamares/network/Tests.cpp b/src/libcalamares/network/Tests.cpp
index 830545b96..dc893a9c9 100644
--- a/src/libcalamares/network/Tests.cpp
+++ b/src/libcalamares/network/Tests.cpp
@@ -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 );
}
diff --git a/src/libcalamares/utils/RAII.h b/src/libcalamares/utils/RAII.h
new file mode 100644
index 000000000..4d8210a25
--- /dev/null
+++ b/src/libcalamares/utils/RAII.h
@@ -0,0 +1,43 @@
+/* === This file is part of Calamares - ===
+ *
+ * Copyright 2020, Adriaan de Groot
+ *
+ * Calamares is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Calamares is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Calamares. If not, see .
+ */
+
+#ifndef UTILS_RAII_H
+#define UTILS_RAII_H
+
+#include
+
+#include
+
+/// @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
diff --git a/src/libcalamaresui/Branding.cpp b/src/libcalamaresui/Branding.cpp
index 5c41f5ea2..25fab307e 100644
--- a/src/libcalamaresui/Branding.cpp
+++ b/src/libcalamaresui/Branding.cpp
@@ -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() )
diff --git a/src/libcalamaresui/Branding.h b/src/libcalamaresui/Branding.h
index 88f658473..b7ba637d6 100644
--- a/src/libcalamaresui/Branding.h
+++ b/src/libcalamaresui/Branding.h
@@ -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 >
diff --git a/src/libcalamaresui/CMakeLists.txt b/src/libcalamaresui/CMakeLists.txt
index c603ca22d..e813b0009 100644
--- a/src/libcalamaresui/CMakeLists.txt
+++ b/src/libcalamaresui/CMakeLists.txt
@@ -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
diff --git a/src/libcalamaresui/ViewManager.cpp b/src/libcalamaresui/ViewManager.cpp
index 9972c3af9..9bfb31e43 100644
--- a/src/libcalamaresui/ViewManager.cpp
+++ b/src/libcalamaresui/ViewManager.cpp
@@ -3,7 +3,7 @@
* Copyright 2019, Dominic Hayes
* Copyright 2019, Gabriel Craciunescu
* Copyright 2014-2015, Teo Mrnjavac
- * Copyright 2017-2018, Adriaan de Groot
+ * Copyright 2017-2018, 2020, Adriaan de Groot
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,6 +38,12 @@
#include
#include
+#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
diff --git a/src/libcalamaresui/ViewManager.h b/src/libcalamaresui/ViewManager.h
index a4bedd7bc..ad9376f1a 100644
--- a/src/libcalamaresui/ViewManager.h
+++ b/src/libcalamaresui/ViewManager.h
@@ -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
diff --git a/src/libcalamaresui/modulesystem/CppJobModule.h b/src/libcalamaresui/modulesystem/CppJobModule.h
index d97443a8a..2fd82433c 100644
--- a/src/libcalamaresui/modulesystem/CppJobModule.h
+++ b/src/libcalamaresui/modulesystem/CppJobModule.h
@@ -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
diff --git a/src/libcalamaresui/modulesystem/ModuleFactory.cpp b/src/libcalamaresui/modulesystem/ModuleFactory.cpp
new file mode 100644
index 000000000..f3b46eab7
--- /dev/null
+++ b/src/libcalamaresui/modulesystem/ModuleFactory.cpp
@@ -0,0 +1,154 @@
+/* === This file is part of Calamares - ===
+ *
+ * Copyright 2014-2015, Teo Mrnjavac
+ * Copyright 2017-2018, Adriaan de Groot
+ *
+ * Calamares is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Calamares is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Calamares. If not, see .
+ */
+
+#include "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
+#include
+#include
+#include
+
+
+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
diff --git a/src/libcalamaresui/modulesystem/ModuleFactory.h b/src/libcalamaresui/modulesystem/ModuleFactory.h
new file mode 100644
index 000000000..8184967d2
--- /dev/null
+++ b/src/libcalamaresui/modulesystem/ModuleFactory.h
@@ -0,0 +1,47 @@
+/* === This file is part of Calamares - ===
+ *
+ * Copyright 2014-2015, Teo Mrnjavac
+ * Copyright 2017, Adriaan de Groot
+ *
+ * Calamares is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Calamares is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Calamares. If not, see .
+ */
+
+#ifndef CALAMARES_MODULEFACTORY_H
+#define CALAMARES_MODULEFACTORY_H
+
+#include "DllMacro.h"
+
+#include "modulesystem/Descriptor.h"
+#include "modulesystem/Module.h"
+
+#include
+
+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
diff --git a/src/libcalamaresui/modulesystem/ModuleManager.cpp b/src/libcalamaresui/modulesystem/ModuleManager.cpp
index f88d5999d..8d4b2342f 100644
--- a/src/libcalamaresui/modulesystem/ModuleManager.cpp
+++ b/src/libcalamaresui/modulesystem/ModuleManager.cpp
@@ -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"
diff --git a/src/libcalamaresui/modulesystem/ModuleManager.h b/src/libcalamaresui/modulesystem/ModuleManager.h
index be485c01d..fdb63cd87 100644
--- a/src/libcalamaresui/modulesystem/ModuleManager.h
+++ b/src/libcalamaresui/modulesystem/ModuleManager.h
@@ -22,8 +22,7 @@
#include "modulesystem/Descriptor.h"
#include "modulesystem/InstanceKey.h"
-
-#include "Requirement.h"
+#include "modulesystem/Requirement.h"
#include
#include
diff --git a/src/libcalamaresui/modulesystem/ProcessJobModule.h b/src/libcalamaresui/modulesystem/ProcessJobModule.h
index da2badbd0..87c6e2da8 100644
--- a/src/libcalamaresui/modulesystem/ProcessJobModule.h
+++ b/src/libcalamaresui/modulesystem/ProcessJobModule.h
@@ -20,9 +20,8 @@
#ifndef CALAMARES_PROCESSJOBMODULE_H
#define CALAMARES_PROCESSJOBMODULE_H
-#include "Module.h"
-
#include "DllMacro.h"
+#include "modulesystem/Module.h"
#include
@@ -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
diff --git a/src/libcalamaresui/modulesystem/PythonJobModule.h b/src/libcalamaresui/modulesystem/PythonJobModule.h
index 295ab5942..85f25ab74 100644
--- a/src/libcalamaresui/modulesystem/PythonJobModule.h
+++ b/src/libcalamaresui/modulesystem/PythonJobModule.h
@@ -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
diff --git a/src/libcalamaresui/modulesystem/PythonQtViewModule.h b/src/libcalamaresui/modulesystem/PythonQtViewModule.h
index 33b8d041b..64cc0f8a9 100644
--- a/src/libcalamaresui/modulesystem/PythonQtViewModule.h
+++ b/src/libcalamaresui/modulesystem/PythonQtViewModule.h
@@ -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
diff --git a/src/libcalamaresui/modulesystem/ViewModule.h b/src/libcalamaresui/modulesystem/ViewModule.h
index c1ee8ff69..1d24ca811 100644
--- a/src/libcalamaresui/modulesystem/ViewModule.h
+++ b/src/libcalamaresui/modulesystem/ViewModule.h
@@ -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
diff --git a/src/modules/netinstall/Config.cpp b/src/modules/netinstall/Config.cpp
index 78718add1..556cb1cf9 100644
--- a/src/modules/netinstall/Config.cpp
+++ b/src/modules/netinstall/Config.cpp
@@ -23,6 +23,7 @@
#include "network/Manager.h"
#include "utils/Logger.h"
+#include "utils/RAII.h"
#include "utils/Yaml.h"
#include
@@ -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.
diff --git a/src/modules/netinstall/README.md b/src/modules/netinstall/README.md
index cda4b6c88..cb6159d95 100644
--- a/src/modules/netinstall/README.md
+++ b/src/modules/netinstall/README.md
@@ -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
diff --git a/src/modules/netinstall/netinstall.conf b/src/modules/netinstall/netinstall.conf
index 82e12d558..5eeef905c 100644
--- a/src/modules/netinstall/netinstall.conf
+++ b/src/modules/netinstall/netinstall.conf
@@ -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:
diff --git a/src/modules/partition/gui/PartitionViewStep.cpp b/src/modules/partition/gui/PartitionViewStep.cpp
index 6a1cde3a6..ed35fafa4 100644
--- a/src/modules/partition/gui/PartitionViewStep.cpp
+++ b/src/modules/partition/gui/PartitionViewStep.cpp
@@ -471,7 +471,7 @@ PartitionViewStep::onLeave()
"
"
"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 "
"bios_grub flag enabled.
"
"An unformatted 8 MB partition is necessary "
diff --git a/src/modules/welcome/Config.cpp b/src/modules/welcome/Config.cpp
index 43987f4b2..1c2b17c38 100644
--- a/src/modules/welcome/Config.cpp
+++ b/src/modules/welcome/Config.cpp
@@ -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. "
+ "Setup cannot continue. "
+ "Details..." )
+ : tr( "This computer does not satisfy the minimum "
+ "requirements for installing %1. "
+ "Installation cannot continue. "
+ "Details..." );
+ }
+ else
+ {
+ message = setup ? tr( "This computer does not satisfy some of the "
+ "recommended requirements for setting up %1. "
+ "Setup can continue, but some features "
+ "might be disabled." )
+ : tr( "This computer does not satisfy some of the "
+ "recommended requirements for installing %1. "
+ "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. "
- "Setup cannot continue. "
- "Details..." )
- : tr( "This computer does not satisfy the minimum "
- "requirements for installing %1. "
- "Installation cannot continue. "
- "Details..." );
- }
- else
- {
- message = setup ? tr( "This computer does not satisfy some of the "
- "recommended requirements for setting up %1. "
- "Setup can continue, but some features "
- "might be disabled." )
- : tr( "This computer does not satisfy some of the "
- "recommended requirements for installing %1. "
- "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;
+}
diff --git a/src/modules/welcome/Config.h b/src/modules/welcome/Config.h
index 389a45eec..80e4eeea9 100644
--- a/src/modules/welcome/Config.h
+++ b/src/modules/welcome/Config.h
@@ -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
#include
-// 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
diff --git a/src/modules/welcome/WelcomeViewStep.cpp b/src/modules/welcome/WelcomeViewStep.cpp
index 848d319db..3a0bef18f 100644
--- a/src/modules/welcome/WelcomeViewStep.cpp
+++ b/src/modules/welcome/WelcomeViewStep.cpp
@@ -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()
diff --git a/src/modules/welcome/checker/CheckerContainer.cpp b/src/modules/welcome/checker/CheckerContainer.cpp
index 0e790fbb4..10da425ab 100644
--- a/src/modules/welcome/checker/CheckerContainer.cpp
+++ b/src/modules/welcome/checker/CheckerContainer.cpp
@@ -31,7 +31,7 @@
#include
-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 )
diff --git a/src/modules/welcome/checker/CheckerContainer.h b/src/modules/welcome/checker/CheckerContainer.h
index f38f198ea..5ebefa36e 100644
--- a/src/modules/welcome/checker/CheckerContainer.h
+++ b/src/modules/welcome/checker/CheckerContainer.h
@@ -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
diff --git a/src/modules/welcome/checker/ResultsListWidget.cpp b/src/modules/welcome/checker/ResultsListWidget.cpp
index 275010b2f..c16cda4c4 100644
--- a/src/modules/welcome/checker/ResultsListWidget.cpp
+++ b/src/modules/welcome/checker/ResultsListWidget.cpp
@@ -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 )
{
diff --git a/src/modules/welcome/checker/ResultsListWidget.h b/src/modules/welcome/checker/ResultsListWidget.h
index eb1bdb611..05a8adfa4 100644
--- a/src/modules/welcome/checker/ResultsListWidget.h
+++ b/src/modules/welcome/checker/ResultsListWidget.h
@@ -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
};
diff --git a/src/modules/welcomeq/WelcomeQmlViewStep.cpp b/src/modules/welcomeq/WelcomeQmlViewStep.cpp
index 0961ce67f..c1046b506 100644
--- a/src/modules/welcomeq/WelcomeQmlViewStep.cpp
+++ b/src/modules/welcomeq/WelcomeQmlViewStep.cpp
@@ -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 )
{
diff --git a/src/modules/welcomeq/about.qml b/src/modules/welcomeq/about.qml
new file mode 100644
index 000000000..f301c6659
--- /dev/null
+++ b/src/modules/welcomeq/about.qml
@@ -0,0 +1,121 @@
+/* === This file is part of Calamares - ===
+ *
+ * Copyright 2020, Anke Boersma
+ *
+ * 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 .
+ */
+
+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("