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

This commit is contained in:
Philip Müller 2020-07-05 10:02:39 +02:00
commit a8230a6411
16 changed files with 314 additions and 147 deletions

View File

@ -7,6 +7,12 @@
--- ---
componentName: default componentName: default
### WELCOME / OVERALL WORDING
#
# These settings affect some overall phrasing and looks,
# which are most visible in the welcome page.
# This selects between different welcome texts. When false, uses # This selects between different welcome texts. When false, uses
# the traditional "Welcome to the %1 installer.", and when true, # the traditional "Welcome to the %1 installer.", and when true,
# uses "Welcome to the Calamares installer for %1." This allows # uses "Welcome to the Calamares installer for %1." This allows
@ -20,6 +26,12 @@ welcomeStyleCalamares: false
# may have surprising effects on HiDPI monitors). # may have surprising effects on HiDPI monitors).
welcomeExpandingLogo: true welcomeExpandingLogo: true
### WINDOW CONFIGURATION
#
# The settings here affect the placement of the Calamares
# window through hints to the window manager and initial
# sizing of the Calamares window.
# Size and expansion policy for Calamares. # Size and expansion policy for Calamares.
# - "normal" or unset, expand as needed, use *windowSize* # - "normal" or unset, expand as needed, use *windowSize*
# - "fullscreen", start as large as possible, ignore *windowSize* # - "fullscreen", start as large as possible, ignore *windowSize*
@ -41,6 +53,14 @@ windowSize: 800px,520px
# *windowExpanding* set to "fullscreen"). # *windowExpanding* set to "fullscreen").
windowPlacement: center windowPlacement: center
### PANELS CONFIGURATION
#
# Calamares has a main content area, and two panels (navigation
# and progress / sidebar). The panels can be controlled individually,
# or switched off. If both panels are switched off, the layout of
# the main content area loses its margins, on the assumption that
# you're doing something special.
# Kind of sidebar (panel on the left, showing progress). # Kind of sidebar (panel on the left, showing progress).
# - "widget" or unset, use traditional sidebar (logo, items) # - "widget" or unset, use traditional sidebar (logo, items)
# - "none", hide it entirely # - "none", hide it entirely
@ -66,6 +86,12 @@ sidebar: widget
# except the default is *bottom*. # except the default is *bottom*.
navigation: widget navigation: widget
### STRINGS, IMAGES AND COLORS
#
# This section contains the "branding proper" of names
# and images, rather than global-look settings.
# These are strings shown to the user in the user interface. # These are strings shown to the user in the user interface.
# There is no provision for translating them -- since they # There is no provision for translating them -- since they
# are names, the string is included as-is. # are names, the string is included as-is.
@ -139,9 +165,28 @@ images:
# productWallpaper: "wallpaper.png" # productWallpaper: "wallpaper.png"
productWelcome: "languages.png" productWelcome: "languages.png"
# Colors for text and background components.
#
# - sidebarBackground is the background of the sidebar
# - sidebarText is the (foreground) text color
# - sidebarTextHighlight sets the background of the selected (current) step.
# Optional, and defaults to the application palette.
# - sidebarSelect is the text color of the selected step.
#
# These colors can **also** be set through the stylesheet, if the
# branding component also ships a stylesheet.qss. Then they are
# the corresponding CSS attributes of #sidebarApp.
style:
sidebarBackground: "#292F34"
sidebarText: "#FFFFFF"
sidebarTextSelect: "#292F34"
sidebarTextHighlight: "#D35400"
### SLIDESHOW
#
# The slideshow is displayed during execution steps (e.g. when the # The slideshow is displayed during execution steps (e.g. when the
# installer is actually writing to disk and doing other slow things). # installer is actually writing to disk and doing other slow things).
#
# The slideshow can be a QML file (recommended) which can display # The slideshow can be a QML file (recommended) which can display
# arbitrary things -- text, images, animations, or even play a game -- # arbitrary things -- text, images, animations, or even play a game --
# during the execution step. The QML **is** abruptly stopped when the # during the execution step. The QML **is** abruptly stopped when the
@ -171,19 +216,3 @@ slideshow: "show.qml"
slideshowAPI: 2 slideshowAPI: 2
# Colors for text and background components.
#
# - sidebarBackground is the background of the sidebar
# - sidebarText is the (foreground) text color
# - sidebarTextHighlight sets the background of the selected (current) step.
# Optional, and defaults to the application palette.
# - sidebarSelect is the text color of the selected step.
#
# These colors can **also** be set through the stylesheet, if the
# branding component also ships a stylesheet.qss. Then they are
# the corresponding CSS attributes of #sidebarApp.
style:
sidebarBackground: "#292F34"
sidebarText: "#FFFFFF"
sidebarTextSelect: "#292F34"
sidebarTextHighlight: "#D35400"

View File

@ -111,12 +111,12 @@ CalamaresWindow::getWidgetSidebar( QWidget* parent, int desiredWidth )
sideLayout->addWidget( debugWindowBtn ); sideLayout->addWidget( debugWindowBtn );
debugWindowBtn->setFlat( true ); debugWindowBtn->setFlat( true );
debugWindowBtn->setCheckable( true ); debugWindowBtn->setCheckable( true );
connect( debugWindowBtn, &QPushButton::clicked, this, [ = ]( bool checked ) { connect( debugWindowBtn, &QPushButton::clicked, this, [=]( bool checked ) {
if ( checked ) if ( checked )
{ {
m_debugWindow = new Calamares::DebugWindow(); m_debugWindow = new Calamares::DebugWindow();
m_debugWindow->show(); m_debugWindow->show();
connect( m_debugWindow.data(), &Calamares::DebugWindow::closed, this, [ = ]() { connect( m_debugWindow.data(), &Calamares::DebugWindow::closed, this, [=]() {
m_debugWindow->deleteLater(); m_debugWindow->deleteLater();
debugWindowBtn->setChecked( false ); debugWindowBtn->setChecked( false );
} ); } );
@ -167,7 +167,7 @@ CalamaresWindow::getWidgetNavigation( QWidget* parent )
connect( back, &QPushButton::clicked, m_viewManager, &Calamares::ViewManager::back ); connect( back, &QPushButton::clicked, m_viewManager, &Calamares::ViewManager::back );
connect( m_viewManager, &Calamares::ViewManager::backEnabledChanged, back, &QPushButton::setEnabled ); connect( m_viewManager, &Calamares::ViewManager::backEnabledChanged, back, &QPushButton::setEnabled );
connect( m_viewManager, &Calamares::ViewManager::backLabelChanged, back, &QPushButton::setText ); connect( m_viewManager, &Calamares::ViewManager::backLabelChanged, back, &QPushButton::setText );
connect( m_viewManager, &Calamares::ViewManager::backIconChanged, this, [ = ]( QString n ) { connect( m_viewManager, &Calamares::ViewManager::backIconChanged, this, [=]( QString n ) {
setButtonIcon( back, n ); setButtonIcon( back, n );
} ); } );
bottomLayout->addWidget( back ); bottomLayout->addWidget( back );
@ -179,7 +179,7 @@ CalamaresWindow::getWidgetNavigation( QWidget* parent )
connect( next, &QPushButton::clicked, m_viewManager, &Calamares::ViewManager::next ); connect( next, &QPushButton::clicked, m_viewManager, &Calamares::ViewManager::next );
connect( m_viewManager, &Calamares::ViewManager::nextEnabledChanged, next, &QPushButton::setEnabled ); connect( m_viewManager, &Calamares::ViewManager::nextEnabledChanged, next, &QPushButton::setEnabled );
connect( m_viewManager, &Calamares::ViewManager::nextLabelChanged, next, &QPushButton::setText ); connect( m_viewManager, &Calamares::ViewManager::nextLabelChanged, next, &QPushButton::setText );
connect( m_viewManager, &Calamares::ViewManager::nextIconChanged, this, [ = ]( QString n ) { connect( m_viewManager, &Calamares::ViewManager::nextIconChanged, this, [=]( QString n ) {
setButtonIcon( next, n ); setButtonIcon( next, n );
} ); } );
bottomLayout->addWidget( next ); bottomLayout->addWidget( next );
@ -191,7 +191,7 @@ CalamaresWindow::getWidgetNavigation( QWidget* parent )
connect( quit, &QPushButton::clicked, m_viewManager, &Calamares::ViewManager::quit ); connect( quit, &QPushButton::clicked, m_viewManager, &Calamares::ViewManager::quit );
connect( m_viewManager, &Calamares::ViewManager::quitEnabledChanged, quit, &QPushButton::setEnabled ); connect( m_viewManager, &Calamares::ViewManager::quitEnabledChanged, quit, &QPushButton::setEnabled );
connect( m_viewManager, &Calamares::ViewManager::quitLabelChanged, quit, &QPushButton::setText ); connect( m_viewManager, &Calamares::ViewManager::quitLabelChanged, quit, &QPushButton::setText );
connect( m_viewManager, &Calamares::ViewManager::quitIconChanged, this, [ = ]( QString n ) { connect( m_viewManager, &Calamares::ViewManager::quitIconChanged, this, [=]( QString n ) {
setButtonIcon( quit, n ); setButtonIcon( quit, n );
} ); } );
connect( m_viewManager, &Calamares::ViewManager::quitTooltipChanged, quit, &QPushButton::setToolTip ); connect( m_viewManager, &Calamares::ViewManager::quitTooltipChanged, quit, &QPushButton::setToolTip );
@ -237,11 +237,13 @@ CalamaresWindow::getQmlNavigation( QWidget* parent )
} }
#else #else
// Bogus to keep the linker happy // Bogus to keep the linker happy
QWidget * CalamaresWindow::getQmlSidebar(QWidget* , int ) QWidget*
CalamaresWindow::getQmlSidebar( QWidget*, int )
{ {
return nullptr; return nullptr;
} }
QWidget * CalamaresWindow::getQmlNavigation(QWidget* ) QWidget*
CalamaresWindow::getQmlNavigation( QWidget* )
{ {
return nullptr; return nullptr;
} }
@ -401,6 +403,14 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
insertIf( mainLayout, PanelSide::Right, navigation, branding->navigationSide() ); insertIf( mainLayout, PanelSide::Right, navigation, branding->navigationSide() );
insertIf( mainLayout, PanelSide::Right, sideBox, branding->sidebarSide() ); insertIf( mainLayout, PanelSide::Right, sideBox, branding->sidebarSide() );
// layout->count() returns number of things in it; above we have put
// at **least** the central widget, which comes from the view manager,
// both vertically and horizontally -- so if there's a panel along
// either axis, the count in that axis will be > 1.
m_viewManager->setPanelSides(
( contentsLayout->count() > 1 ? Qt::Orientations( Qt::Horizontal ) : Qt::Orientations() )
| ( mainLayout->count() > 1 ? Qt::Orientations( Qt::Vertical ) : Qt::Orientations() ) );
CalamaresUtils::unmarginLayout( mainLayout ); CalamaresUtils::unmarginLayout( mainLayout );
CalamaresUtils::unmarginLayout( contentsLayout ); CalamaresUtils::unmarginLayout( contentsLayout );
baseWidget->setLayout( mainLayout ); baseWidget->setLayout( mainLayout );

View File

@ -38,21 +38,19 @@ namespace CalamaresUtils
bool bool
getBool( const QVariantMap& map, const QString& key, bool d ) getBool( const QVariantMap& map, const QString& key, bool d )
{ {
bool result = d;
if ( map.contains( key ) ) if ( map.contains( key ) )
{ {
auto v = map.value( key ); auto v = map.value( key );
if ( v.type() == QVariant::Bool ) if ( v.type() == QVariant::Bool )
{ {
result = v.toBool(); return v.toBool();
} }
} }
return d;
return result;
} }
QString QString
getString( const QVariantMap& map, const QString& key ) getString( const QVariantMap& map, const QString& key, const QString& d )
{ {
if ( map.contains( key ) ) if ( map.contains( key ) )
{ {
@ -62,11 +60,11 @@ getString( const QVariantMap& map, const QString& key )
return v.toString(); return v.toString();
} }
} }
return QString(); return d;
} }
QStringList QStringList
getStringList( const QVariantMap& map, const QString& key ) getStringList( const QVariantMap& map, const QString& key, const QStringList& d )
{ {
if ( map.contains( key ) ) if ( map.contains( key ) )
{ {
@ -76,60 +74,53 @@ getStringList( const QVariantMap& map, const QString& key )
return v.toStringList(); return v.toStringList();
} }
} }
return QStringList(); return d;
} }
qint64 qint64
getInteger( const QVariantMap& map, const QString& key, qint64 d ) getInteger( const QVariantMap& map, const QString& key, qint64 d )
{ {
qint64 result = d;
if ( map.contains( key ) ) if ( map.contains( key ) )
{ {
auto v = map.value( key ); auto v = map.value( key );
result = v.toString().toLongLong(nullptr, 0); return v.toString().toLongLong(nullptr, 0);
} }
return d;
return result;
} }
quint64 quint64
getUnsignedInteger( const QVariantMap& map, const QString& key, quint64 u ) getUnsignedInteger( const QVariantMap& map, const QString& key, quint64 d )
{ {
quint64 result = u;
if ( map.contains( key ) ) if ( map.contains( key ) )
{ {
auto v = map.value( key ); auto v = map.value( key );
result = v.toString().toULongLong(nullptr, 0); return v.toString().toULongLong(nullptr, 0);
} }
return d;
return result;
} }
double double
getDouble( const QVariantMap& map, const QString& key, double d ) getDouble( const QVariantMap& map, const QString& key, double d )
{ {
double result = d;
if ( map.contains( key ) ) if ( map.contains( key ) )
{ {
auto v = map.value( key ); auto v = map.value( key );
if ( v.type() == QVariant::Int ) if ( v.type() == QVariant::Int )
{ {
result = v.toInt(); return v.toInt();
} }
else if ( v.type() == QVariant::Double ) else if ( v.type() == QVariant::Double )
{ {
result = v.toDouble(); return v.toDouble();
} }
} }
return d;
return result;
} }
QVariantMap QVariantMap
getSubMap( const QVariantMap& map, const QString& key, bool& success ) getSubMap( const QVariantMap& map, const QString& key, bool& success, const QVariantMap& d )
{ {
success = false; success = false;
if ( map.contains( key ) ) if ( map.contains( key ) )
{ {
auto v = map.value( key ); auto v = map.value( key );
@ -139,7 +130,7 @@ getSubMap( const QVariantMap& map, const QString& key, bool& success )
return v.toMap(); return v.toMap();
} }
} }
return QVariantMap(); return d;
} }
} // namespace CalamaresUtils } // namespace CalamaresUtils

View File

@ -33,45 +33,44 @@
namespace CalamaresUtils namespace CalamaresUtils
{ {
/** /**
* Get a bool value from a mapping with a given key; returns the default * Get a bool value from a mapping with a given key; returns @p d if no value.
* if no value is stored in the map.
*/ */
DLLEXPORT bool getBool( const QVariantMap& map, const QString& key, bool d ); DLLEXPORT bool getBool( const QVariantMap& map, const QString& key, bool d = false );
/** /**
* Get a string value from a mapping; returns empty QString if no value. * Get a string value from a mapping with a given key; returns @p d if no value.
*/ */
DLLEXPORT QString getString( const QVariantMap& map, const QString& key ); DLLEXPORT QString getString( const QVariantMap& map, const QString& key, const QString& d = QString() );
/** /**
* Get a string list from a mapping; returns empty list if no value. * Get a string list from a mapping with a given key; returns @p d if no value.
*/ */
DLLEXPORT QStringList getStringList( const QVariantMap& map, const QString& key ); DLLEXPORT QStringList getStringList( const QVariantMap& map, const QString& key, const QStringList& d = QStringList() );
/** /**
* Get an integer value from a mapping; returns @p d if no value. * Get an integer value from a mapping with a given key; returns @p d if no value.
*/ */
DLLEXPORT qint64 getInteger( const QVariantMap& map, const QString& key, qint64 d ); DLLEXPORT qint64 getInteger( const QVariantMap& map, const QString& key, qint64 d = 0);
/** /**
* Get an unsigned integer value from a mapping; returns @p u if no value. * Get an unsigned integer value from a mapping with a given key; returns @p d if no value.
*/ */
DLLEXPORT quint64 getUnsignedInteger( const QVariantMap& map, const QString& key, quint64 u ); DLLEXPORT quint64 getUnsignedInteger( const QVariantMap& map, const QString& key, quint64 d = 0 );
/** /**
* Get a double value from a mapping (integers are converted); returns @p d if no value. * Get a double value from a mapping with a given key (integers are converted); returns @p d if no value.
*/ */
DLLEXPORT double getDouble( const QVariantMap& map, const QString& key, double d ); DLLEXPORT double getDouble( const QVariantMap& map, const QString& key, double d = 0.0 );
/** /**
* Returns a sub-map (i.e. a nested map) from the given mapping with the * Returns a sub-map (i.e. a nested map) from a given mapping with a
* given key. @p success is set to true if the @p key exists * given key. @p success is set to true if the @p key exists
* in @p map and converts to a map, false otherwise. * in @p map and converts to a map, false otherwise.
* *
* Returns an empty map if there is no such key or it is not a map-value. * Returns @p d if there is no such key or it is not a map-value.
* (e.g. if @p success is false). * (e.g. if @p success is false).
*/ */
DLLEXPORT QVariantMap getSubMap( const QVariantMap& map, const QString& key, bool& success ); DLLEXPORT QVariantMap getSubMap( const QVariantMap& map, const QString& key, bool& success, const QVariantMap& d = QVariantMap() );
} // namespace CalamaresUtils } // namespace CalamaresUtils
#endif #endif

View File

@ -67,10 +67,12 @@ ViewManager::ViewManager( QObject* parent )
: QAbstractListModel( parent ) : QAbstractListModel( parent )
, m_currentStep( -1 ) , m_currentStep( -1 )
, m_widget( new QWidget() ) , m_widget( new QWidget() )
, m_panelSides( Qt::Horizontal | Qt::Vertical )
{ {
Q_ASSERT( !s_instance ); Q_ASSERT( !s_instance );
QBoxLayout* mainLayout = new QVBoxLayout; QBoxLayout* mainLayout = new QVBoxLayout;
mainLayout->setContentsMargins( 0, 0, 0, 0 );
m_widget->setObjectName( "viewManager" ); m_widget->setObjectName( "viewManager" );
m_widget->setLayout( mainLayout ); m_widget->setLayout( mainLayout );
@ -127,15 +129,19 @@ ViewManager::insertViewStep( int before, ViewStep* step )
{ {
cError() << "ViewStep" << step->moduleInstanceKey() << "has no widget."; cError() << "ViewStep" << step->moduleInstanceKey() << "has no widget.";
} }
else
QLayout* layout = step->widget()->layout();
if ( layout )
{ {
layout->setContentsMargins( 0, 0, 0, 0 ); QLayout* layout = step->widget()->layout();
if ( layout )
{
const auto margins = step->widgetMargins( m_panelSides );
layout->setContentsMargins( margins.width(), margins.height(), margins.width(), margins.height() );
}
m_stack->insertWidget( before, step->widget() );
m_stack->setCurrentIndex( 0 );
step->widget()->setFocus();
} }
m_stack->insertWidget( before, step->widget() );
m_stack->setCurrentIndex( 0 );
step->widget()->setFocus();
emit endInsertRows(); emit endInsertRows();
} }

View File

@ -54,6 +54,9 @@ class UIDLLEXPORT ViewManager : public QAbstractListModel
Q_PROPERTY( bool quitVisible READ quitVisible NOTIFY quitVisibleChanged FINAL ) Q_PROPERTY( bool quitVisible READ quitVisible NOTIFY quitVisibleChanged FINAL )
///@brief Sides on which the ViewManager has side-panels
Q_PROPERTY( Qt::Orientations panelSides READ panelSides WRITE setPanelSides MEMBER m_panelSides )
public: public:
/** /**
* @brief instance access to the ViewManager singleton. * @brief instance access to the ViewManager singleton.
@ -100,13 +103,17 @@ public:
int currentStepIndex() const; int currentStepIndex() const;
/** /**
* @ brief Called when "Cancel" is clicked; asks for confirmation. * @brief Called when "Cancel" is clicked; asks for confirmation.
* Other means of closing Calamares also call this method, e.g. alt-F4. * Other means of closing Calamares also call this method, e.g. alt-F4.
* At the end of installation, no confirmation is asked. Returns true * At the end of installation, no confirmation is asked.
* if the user confirms closing the window. *
* @return @c true if the user confirms closing the window.
*/ */
bool confirmCancelInstallation(); bool confirmCancelInstallation();
Qt::Orientations panelSides() const { return m_panelSides; }
void setPanelSides( Qt::Orientations panelSides ) { m_panelSides = panelSides; }
public Q_SLOTS: public Q_SLOTS:
/** /**
* @brief next moves forward to the next page of the current ViewStep (if any), * @brief next moves forward to the next page of the current ViewStep (if any),
@ -244,6 +251,8 @@ private:
QString m_quitTooltip; QString m_quitTooltip;
bool m_quitVisible = true; bool m_quitVisible = true;
Qt::Orientations m_panelSides;
public: public:
/** @section Model /** @section Model
* *

View File

@ -87,6 +87,7 @@ UIDLLEXPORT QPixmap defaultPixmap( ImageType type,
ImageMode mode = CalamaresUtils::Original, ImageMode mode = CalamaresUtils::Original,
const QSize& size = QSize( 0, 0 ) ); const QSize& size = QSize( 0, 0 ) );
// TODO:3.3:This has only one consumer, move to ImageRegistry, make static
/** /**
* @brief createRoundedImage returns a rounded version of a pixmap. * @brief createRoundedImage returns a rounded version of a pixmap.
* @param avatar the input pixmap. * @param avatar the input pixmap.
@ -103,6 +104,7 @@ UIDLLEXPORT QPixmap createRoundedImage( const QPixmap& avatar, const QSize& size
*/ */
UIDLLEXPORT void unmarginLayout( QLayout* layout ); UIDLLEXPORT void unmarginLayout( QLayout* layout );
// TODO:3.3:This has only one consumer, move to LicensePage, make static
/** /**
* @brief clearLayout recursively walks the QLayout tree and deletes all the child * @brief clearLayout recursively walks the QLayout tree and deletes all the child
* widgets and layouts. * widgets and layouts.
@ -113,7 +115,7 @@ UIDLLEXPORT void clearLayout( QLayout* layout );
UIDLLEXPORT void setDefaultFontSize( int points ); UIDLLEXPORT void setDefaultFontSize( int points );
UIDLLEXPORT int defaultFontSize(); // in points UIDLLEXPORT int defaultFontSize(); // in points
UIDLLEXPORT int defaultFontHeight(); // in pixels, DPI-specific UIDLLEXPORT int defaultFontHeight(); // in pixels, DPI-specific
UIDLLEXPORT QFont defaultFont(); UIDLLEXPORT QFont defaultFont(); // TODO:3.3:This has one consumer, move to BlankViewStep
UIDLLEXPORT QFont largeFont(); UIDLLEXPORT QFont largeFont();
UIDLLEXPORT QSize defaultIconSize(); UIDLLEXPORT QSize defaultIconSize();

View File

@ -151,6 +151,22 @@ QmlViewStep::widget()
return m_widget; return m_widget;
} }
QSize
QmlViewStep::widgetMargins( Qt::Orientations panelSides )
{
// If any panels around it, use the standard, but if all the
// panels are hidden, like on full-screen with subsumed navigation,
// then no margins.
if ( panelSides )
{
return ViewStep::widgetMargins( panelSides );
}
else
{
return QSize( 0, 0 );
}
}
void void
QmlViewStep::loadComplete() QmlViewStep::loadComplete()
{ {

View File

@ -35,6 +35,15 @@ namespace Calamares
* This is generally a **base** class for other view steps, but * This is generally a **base** class for other view steps, but
* it can be used stand-alone for viewsteps that don't really have * it can be used stand-alone for viewsteps that don't really have
* any functionality. * any functionality.
*
* Most subclasses will override the following methods:
* - prettyName() to provide a meaningful human-readable name
* - jobs() if there is real work to be done during installation
* - getConfig() to return a meaningful configuration object
*
* For details on the interaction between the config object and
* the QML in the module, see the module documentation:
* src/modules/README.md
*/ */
class QmlViewStep : public Calamares::ViewStep class QmlViewStep : public Calamares::ViewStep
{ {
@ -55,6 +64,7 @@ public:
virtual QString prettyName() const override; virtual QString prettyName() const override;
virtual QWidget* widget() override; virtual QWidget* widget() override;
virtual QSize widgetMargins( Qt::Orientations panelSides ) override;
virtual bool isNextEnabled() const override; virtual bool isNextEnabled() const override;
virtual bool isBackEnabled() const override; virtual bool isBackEnabled() const override;

View File

@ -19,6 +19,9 @@
#include "ViewStep.h" #include "ViewStep.h"
#include <QApplication>
#include <QStyle>
namespace Calamares namespace Calamares
{ {
@ -85,4 +88,14 @@ ViewStep::checkRequirements()
return RequirementsList(); return RequirementsList();
} }
QSize
ViewStep::widgetMargins( Qt::Orientations panelSides )
{
Q_UNUSED( panelSides )
// Application's default style
const auto* s = QApplication::style();
return QSize( s->pixelMetric( QStyle::PM_LayoutLeftMargin ), s->pixelMetric( QStyle::PM_LayoutTopMargin ) );
}
} // namespace Calamares } // namespace Calamares

View File

@ -52,27 +52,61 @@ public:
explicit ViewStep( QObject* parent = nullptr ); explicit ViewStep( QObject* parent = nullptr );
virtual ~ViewStep() override; virtual ~ViewStep() override;
/** @brief Human-readable name of the step
*
* This (translated) string is shown in the sidebar (progress)
* and during installation. There is no default.
*/
virtual QString prettyName() const = 0; virtual QString prettyName() const = 0;
/** /** @brief Describe what this step will do during install
*
* Optional. May return a non-empty string describing what this * Optional. May return a non-empty string describing what this
* step is going to do (should be translated). This is also used * step is going to do (should be translated). This is also used
* in the summary page to describe what is going to be done. * in the summary page to describe what is going to be done.
* Return an empty string to provide no description. * Return an empty string to provide no description.
*
* The default implementation returns an empty string, so nothing
* will be displayed for this step when a summary is shown.
*/ */
virtual QString prettyStatus() const; virtual QString prettyStatus() const;
/** /** @brief Return a long description what this step will do during install
*
* Optional. May return a widget which will be inserted in the summary * Optional. May return a widget which will be inserted in the summary
* page. The caller takes ownership of the widget. Return nullptr to * page. The caller takes ownership of the widget. Return nullptr to
* provide no widget. In general, this is only used for complicated * provide no widget. In general, this is only used for complicated
* steps where prettyStatus() is not sufficient. * steps where prettyStatus() is not sufficient.
*
* The default implementation returns nullptr, so nothing
* will be displayed for this step when a summary is shown.
*/ */
virtual QWidget* createSummaryWidget() const; virtual QWidget* createSummaryWidget() const;
//TODO: we might want to make this a QSharedPointer /** @brief Get (or create) the widget for this view step
*
* While a view step **may** create the widget when it is loaded,
* it is recommended to wait with widget creation until the
* widget is actually asked for: a view step **may** be used
* without a UI.
*/
virtual QWidget* widget() = 0; virtual QWidget* widget() = 0;
/** @brief Get margins for this widget
*
* This is called by the layout manager to find the desired
* margins (width is used for left and right margin, height is
* used for top and bottom margins) for the widget. The
* @p panelSides indicates where there are panels in the overall
* layout: horizontally and / or vertically adjacent (or none!)
* to the view step's widget.
*
* Should return a size based also on QStyle metrics for layout.
* The default implementation just returns the default layout metrics
* (often 11 pixels on a side).
*/
virtual QSize widgetMargins( Qt::Orientations panelSides );
/** /**
* @brief Multi-page support, go next * @brief Multi-page support, go next
* *

View File

@ -9,20 +9,16 @@ Each Calamares module lives in its own directory.
All modules are installed in `$DESTDIR/lib/calamares/modules`. All modules are installed in `$DESTDIR/lib/calamares/modules`.
There are two **types** of Calamares module: There are two **types** of Calamares module:
* viewmodule, for user-visible modules. These may be in C++, or PythonQt. * viewmodule, for user-visible modules. These use C++ and QWidgets or QML
* jobmodule, for not-user-visible modules. These may be done in C++, * jobmodule, for not-user-visible modules. These may be done in C++,
Python, or as external processes. Python, or as external processes.
A viewmodule exposes a UI to the user. The PythonQt-based modules A viewmodule exposes a UI to the user.
are considered experimental (and as of march 2019 may be on the
way out again as never-used-much and PythonQt is not packaged
on Debian anymore).
There are three (four) **interfaces** for Calamares modules: There are three **interfaces** for Calamares modules:
* qtplugin (viewmodules, jobmodules), * qtplugin (viewmodules, jobmodules),
* python (jobmodules only), * python (jobmodules only),
* pythonqt (viewmodules, jobmodules, optional), * process (jobmodules only, not recommended).
* process (jobmodules only).
## Module directory ## Module directory
@ -50,7 +46,7 @@ Module descriptors **must** have the following keys:
- *interface* (see below for the different interfaces; generally we - *interface* (see below for the different interfaces; generally we
refer to the kinds of modules by their interface) refer to the kinds of modules by their interface)
Module descriptors for Python and PythonQt modules **must** have the following key: Module descriptors for Python modules **must** have the following key:
- *script* (the name of the Python script to load, nearly always `main.py`) - *script* (the name of the Python script to load, nearly always `main.py`)
Module descriptors **may** have the following keys: Module descriptors **may** have the following keys:
@ -133,15 +129,67 @@ a `CMakeLists.txt` with a `calamares_add_plugin` call. It will be picked
up automatically by our CMake magic. The `module.desc` file is not recommended: up automatically by our CMake magic. The `module.desc` file is not recommended:
nearly all cases can be described in CMake. nearly all cases can be described in CMake.
### C++ Jobmodule
**TODO:** this needs documentation
### C++ Widgets Viewmodule
**TODO:** this needs documentation
### C++ QML Viewmodule
A QML Viewmodule (or view step) puts much of the UI work in one or more
QML files; the files may be loaded from the branding directory or compiled
into the module. Which QML is used depends on the deployment and the
configuration files for Calamares.
#### Explicit properties
The QML can access data from the C++ framework though properties
exposed to QML. There are two libraries that need to be imported
explicitly:
```
import io.calamares.core 1.0
import io.calamares.ui 1.0
```
The *ui* library contains the *Branding* object, which corresponds to
the branding information set through `branding.desc`. The Branding
class (in `src/libcalamaresui/Branding.h` offers a QObject-property
based API, where the most important functions are `string()` and the
convenience functions `versionedName()` and similar.
The *core* library contains both *ViewManager*, which handles overall
progress through the application, and *Global*, which holds global
storage information. Both objects have an extensive API. The *ViewManager*
can behave as a model for list views and the like.
These explicit properties from libraries are shared across all the
QML modules (for global storage that goes without saying: it is
the mechanism to share information with other modules).
#### Implicit properties
Each module also has an implicit context property available to it.
No import is needed. The context property *config* (note lower case)
holds the Config object for the module.
The Config object is the bridge between C++ and QML.
A Config object must inherit QObject and should expose, as `Q_PROPERTY`,
all of the relevant configuration information for the module instance.
The general description how to do that is available
in the [Qt documentation](https://doc.qt.io/qt-5/qtqml-cppintegration-topic.html).
## Python modules ## Python modules
Modules may use one of the python interfaces, which may be present Modules may use one of the python interfaces, which may be present
in a Calamares installation (but also may not be). These modules must have in a Calamares installation (but also may not be). These modules must have
a `module.desc` file. The Python script must implement one or more of the a `module.desc` file. The Python script must implement the
Python interfaces for Calamares -- either the python jobmodule interface, Python jobmodule interface.
or the experimental pythonqt job- and viewmodule interfaces.
To add a Python or process jobmodule, put it in a subdirectory and make sure To add a Python or process jobmodule, put it in a subdirectory and make sure
it has a `module.desc`. It will be picked up automatically by our CMake magic. it has a `module.desc`. It will be picked up automatically by our CMake magic.
@ -178,31 +226,19 @@ description if something went wrong.
## PythonQt modules ## PythonQt modules (deprecated)
> Type: viewmodule, jobmodule > Type: viewmodule, jobmodule
> Interface: pythonqt > Interface: pythonqt
The PythonQt modules are considered experimental and may be removed again The PythonQt modules are deprecated and will be removed in Calamares 3.3.
due to low uptake. Their documentation is also almost completely lacking. Their documentation is also almost completely lacking.
### PythonQt Jobmodule
A PythonQt jobmodule implements the experimental Job interface by defining
a subclass of something.
### PythonQt Viewmodule
A PythonQt viewmodule implements the experimental View interface by defining
a subclass of something.
### Python API
**TODO:** this needs documentation
## Process jobmodules ## Process modules
Use of this kind of module is **not** recommended.
> Type: jobmodule > Type: jobmodule
> Interface: process > Interface: process

View File

@ -107,10 +107,6 @@ LicensePage::LicensePage( QWidget* parent )
// ui->verticalLayout->insertSpacing( 1, CalamaresUtils::defaultFontHeight() ); // ui->verticalLayout->insertSpacing( 1, CalamaresUtils::defaultFontHeight() );
CalamaresUtils::unmarginLayout( ui->verticalLayout ); CalamaresUtils::unmarginLayout( ui->verticalLayout );
ui->mainText->setWordWrap( true );
ui->mainText->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
ui->acceptFrame->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
ui->acceptFrame->setStyleSheet( mustAccept ); ui->acceptFrame->setStyleSheet( mustAccept );
ui->acceptFrame->layout()->setMargin( CalamaresUtils::defaultFontHeight() / 2 ); ui->acceptFrame->layout()->setMargin( CalamaresUtils::defaultFontHeight() / 2 );

View File

@ -1,16 +1,18 @@
--- ---
# #
# Which package manager to use, options are: # Which package manager to use, options are:
# - packagekit - PackageKit CLI tool # - apk - Alpine Linux package manager
# - zypp - Zypp RPM frontend
# - yum - Yum RPM frontend
# - dnf - DNF, the new RPM frontend
# - urpmi - Mandriva package manager
# - apt - APT frontend for DEB and RPM # - apt - APT frontend for DEB and RPM
# - dnf - DNF, the new RPM frontend
# - entropy - Sabayon package manager
# - packagekit - PackageKit CLI tool
# - pacman - Pacman # - pacman - Pacman
# - portage - Gentoo package manager # - portage - Gentoo package manager
# - entropy - Sabayon package manager # - urpmi - Mandriva package manager
# - apk = Alpine Linux package manager # - yum - Yum RPM frontend
# - zypp - Zypp RPM frontend
#
# Not actually a package manager, but suitable for testing:
# - dummy - Dummy manager, only logs # - dummy - Dummy manager, only logs
# #
backend: dummy backend: dummy

View File

@ -4,30 +4,39 @@ $id: https://calamares.io/schemas/packages
additionalProperties: false additionalProperties: false
type: object type: object
properties: properties:
"backend": { type: string, required: true, enum: [packagekit, zypp, yum, dnf, urpmi, apt, pacman, portage, entropy] } backend:
"update_db": { type: boolean, default: true } type: string
"operations": enum:
type: seq - apk
sequence: - apt
- type: map - dnf
mapping: - entropy
"install": - packagekit
type: seq - pacman
sequence: - portage
- { type: text } - urpmi
"remove": - yum
type: seq - zypp
sequence: - dummy
- { type: text }
"localInstall": update_db: { type: boolean, default: true }
type: seq update_system: { type: boolean, default: false }
sequence: skip_if_no_internet: { type: boolean, default: false }
- { type: text }
"try_install": operations:
type: seq type: array
sequence: items:
- { type: text } additionalProperties: false
"try_remove": type: object
type: seq properties:
sequence: # TODO: these are either-string-or-struct items,
- { type: text } # need their own little schema.
install: { type: array }
remove: { type: array }
try_install: { type: array }
try_remove: { type: array }
localInstall: { type: array }
source: { type: string }
required: [ backend ]

View File

@ -93,6 +93,10 @@ mapForPartition( Partition* partition, const QString& uuid )
map[ "device" ] = partition->partitionPath(); map[ "device" ] = partition->partitionPath();
map[ "partlabel" ] = partition->label(); map[ "partlabel" ] = partition->label();
map[ "partuuid" ] = partition->uuid(); map[ "partuuid" ] = partition->uuid();
#ifdef WITH_KPMCORE42API
map[ "parttype" ] = partition->type();
map[ "partattrs" ] = partition->attributes();
#endif
map[ "mountPoint" ] = PartitionInfo::mountPoint( partition ); map[ "mountPoint" ] = PartitionInfo::mountPoint( partition );
map[ "fsName" ] = userVisibleFS( partition->fileSystem() ); map[ "fsName" ] = userVisibleFS( partition->fileSystem() );
map[ "fs" ] = untranslatedFS( partition->fileSystem() ); map[ "fs" ] = untranslatedFS( partition->fileSystem() );
@ -110,6 +114,7 @@ mapForPartition( Partition* partition, const QString& uuid )
using TR = Logger::DebugRow< const char* const, const QString& >; using TR = Logger::DebugRow< const char* const, const QString& >;
deb << Logger::SubEntry << "mapping for" << partition->partitionPath() << partition->deviceNode() deb << Logger::SubEntry << "mapping for" << partition->partitionPath() << partition->deviceNode()
<< TR( "partlabel", map[ "partlabel" ].toString() ) << TR( "partuuid", map[ "partuuid" ].toString() ) << TR( "partlabel", map[ "partlabel" ].toString() ) << TR( "partuuid", map[ "partuuid" ].toString() )
<< TR( "parttype", map[ "partype" ].toString() ) << TR( "partattrs", map[ "partattrs" ].toString() )
<< TR( "mountPoint:", PartitionInfo::mountPoint( partition ) ) << TR( "fs:", map[ "fs" ].toString() ) << TR( "mountPoint:", PartitionInfo::mountPoint( partition ) ) << TR( "fs:", map[ "fs" ].toString() )
<< TR( "fsName", map[ "fsName" ].toString() ) << TR( "uuid", uuid ) << TR( "fsName", map[ "fsName" ].toString() ) << TR( "uuid", uuid )
<< TR( "claimed", map[ "claimed" ].toString() ); << TR( "claimed", map[ "claimed" ].toString() );