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

This commit is contained in:
Philip Müller 2020-03-27 13:09:00 +01:00
commit af4a7086df
42 changed files with 1660 additions and 411 deletions

View File

@ -7,6 +7,16 @@ charset = utf-8
end_of_line = lf end_of_line = lf
trim_trailing_whitespace = true trim_trailing_whitespace = true
[CMakeLists.txt]
indent_style = space
indent_size = 4
insert_final_newline = true
[*.cmake]
indent_style = space
indent_size = 4
insert_final_newline = true
[*.{py,cpp,h}] [*.{py,cpp,h}]
indent_style = space indent_style = space
indent_size = 4 indent_size = 4

View File

@ -6,6 +6,7 @@ website will have to do for older versions.
# 3.2.21 (unreleased) # # 3.2.21 (unreleased) #
This release contains contributions from (alphabetically by first name): This release contains contributions from (alphabetically by first name):
- Anke Boersma
- Camilo Higuita - Camilo Higuita
- Gabriel Craciunescu - Gabriel Craciunescu
- Gaël PORTAY - Gaël PORTAY
@ -25,6 +26,11 @@ This release contains contributions from (alphabetically by first name):
more configurable: the branding key *sidebar* controls it. The sidebar more configurable: the branding key *sidebar* controls it. The sidebar
can be shown as a widget (default, as it has been), hidden, or use a can be shown as a widget (default, as it has been), hidden, or use a
new QML view which is more easily customised. new QML view which is more easily customised.
- A new `settings.conf` key *quit-at-end* will automatically close
Calamares (by clicking on the *Done* button) when the end of the
sequence is reached. If *finished* is the last module in the sequence,
this will run whatever it is configured for; you can also leave out
the finished page and Calamares will close after the exec parts.
## Modules ## ## Modules ##
- *packages* now reports more details in the installation progress-bar. - *packages* now reports more details in the installation progress-bar.

View File

@ -181,3 +181,11 @@ disable-cancel: false
# #
# YAML: boolean. # YAML: boolean.
disable-cancel-during-exec: false disable-cancel-during-exec: false
# If this is set to true, then once the end of the sequence has
# been reached, the quit (done) button is clicked automatically
# and Calamares will close. Default is false: the user will see
# that the end of installation has been reached, and that things are ok.
#
#
quit-at-end: false

View File

@ -6,26 +6,72 @@ In principle, all parts can be styled through CSS.
Missing parts should be filed as issues. Missing parts should be filed as issues.
The IDs are based on the object names in the C++ code. The IDs are based on the object names in the C++ code.
You can use the Debug Dialog to find out object names:
- Open the debug dialog
- Choose tab *Tools*
- Click *Widget Tree* button
The list of object names is printed in the log.
Documentation for styling Qt Widgets through a stylesheet Documentation for styling Qt Widgets through a stylesheet
can be found at can be found at
https://doc.qt.io/qt-5/stylesheet-examples.html https://doc.qt.io/qt-5/stylesheet-examples.html
https://doc.qt.io/qt-5/stylesheet-reference.html
In Calamares, styling widget classes is supported (e.g. In Calamares, styling widget classes is supported (e.g.
using `QComboBox` as a selector). You can also use specific using `QComboBox` as a selector).
object names (ids), which you can find through debugging tools.
This example stylesheet has all the actual styling commented out.
The examples are not exhaustive.
*/ */
/* Main application window. /*** Generic Widgets.
*
* You can style **all** widgets of a given class by selecting
* the class name. Some widgets have specialized sub-selectors.
*/
/*
QPushButton { background-color: green; }
*/
/*** Main application window.
*
* The main application window has the sidebar, which in turn
* contains a logo and a list of items -- note that the list
* can **not** be styled, since it has its own custom C++
* delegate code.
*/
/*
#mainApp { } #mainApp { }
#logoApp { }
#sidebarApp { } #sidebarApp { }
#sidebarMenuApp { } #logoApp { }
*/ */
/* Partitioning module. /*** Welcome module.
*
* There are plenty of parts, but the buttons are the most interesting
* ones (donate, release notes, ...). The little icon image can be
* styled through *qproperty-icon*, which is a little obscure.
* URLs can reference the QRC paths of the Calamares application
* or loaded via plugins or within the filesystem. There is no
* comprehensive list of available icons, though.
*/
/*
QPushButton#aboutButton { qproperty-icon: url(:/data/images/release.svg); }
#donateButton,
#supportButton,
#releaseNotesButton,
#knownIssuesButton { qproperty-icon: url(:/data/images/help.svg); }
*/
/*** Partitioning module.
*
* Many moving parts, which you will need to experiment with.
*/
/*
#bootInfoIcon { } #bootInfoIcon { }
#bootInfoLable { } #bootInfoLable { }
#deviceInfoIcon { } #deviceInfoIcon { }
@ -34,8 +80,13 @@ object names (ids), which you can find through debugging tools.
#partitionBarView { } #partitionBarView { }
*/ */
/* Licensing module. /*** Licensing module.
*
* The licensing module paints individual widgets for each of
* the licenses. The item can be collapsed or expanded.
*/
/*
#licenseItem { } #licenseItem { }
#licenseItemFullText { } #licenseItemFullText { }
*/ */

View File

@ -83,7 +83,7 @@ CalamaresApplication::init()
initQmlPath(); initQmlPath();
initBranding(); initBranding();
CalamaresUtils::installTranslator( QLocale::system(), QString(), this ); CalamaresUtils::installTranslator( QLocale::system(), QString() );
setQuitOnLastWindowClosed( false ); setQuitOnLastWindowClosed( false );
setWindowIcon( QIcon( Calamares::Branding::instance()->imagePath( Calamares::Branding::ProductIcon ) ) ); setWindowIcon( QIcon( Calamares::Branding::instance()->imagePath( Calamares::Branding::ProductIcon ) ) );

View File

@ -69,6 +69,7 @@ public:
if ( anyFailed && !job->isEmergency() ) if ( anyFailed && !job->isEmergency() )
{ {
cDebug() << "Skipping non-emergency job" << job->prettyName(); cDebug() << "Skipping non-emergency job" << job->prettyName();
++m_jobIndex;
continue; continue;
} }
@ -83,11 +84,9 @@ public:
message = result.message(); message = result.message();
details = result.details(); details = result.details();
} }
if ( !anyFailed ) emitProgress( 1.0 );
{
++m_jobIndex; ++m_jobIndex;
} }
}
if ( anyFailed ) if ( anyFailed )
{ {
emitFailed( message, details ); emitFailed( message, details );
@ -141,7 +140,7 @@ private:
m_queue, "failed", Qt::QueuedConnection, Q_ARG( QString, message ), Q_ARG( QString, details ) ); m_queue, "failed", Qt::QueuedConnection, Q_ARG( QString, message ), Q_ARG( QString, details ) );
} }
void emitFinished() { QMetaObject::invokeMethod( m_queue, "finished", Qt::QueuedConnection ); } void emitFinished() { QMetaObject::invokeMethod( m_queue, "finish", Qt::QueuedConnection ); }
}; };
JobThread::~JobThread() {} JobThread::~JobThread() {}
@ -196,6 +195,7 @@ JobQueue::start()
Q_ASSERT( !m_thread->isRunning() ); Q_ASSERT( !m_thread->isRunning() );
m_thread->setJobs( std::move( m_jobs ) ); m_thread->setJobs( std::move( m_jobs ) );
m_jobs.clear(); m_jobs.clear();
m_finished = false;
m_thread->start(); m_thread->start();
} }
@ -217,4 +217,11 @@ JobQueue::enqueue( const JobList& jobs )
emit queueChanged( m_jobs ); emit queueChanged( m_jobs );
} }
void
JobQueue::finish()
{
m_finished = true;
emit finished();
}
} // namespace Calamares } // namespace Calamares

View File

@ -45,6 +45,11 @@ public:
void enqueue( const JobList& jobs ); void enqueue( const JobList& jobs );
void start(); void start();
bool isRunning() const { return !m_finished; }
public slots:
void finish();
signals: signals:
void queueChanged( const JobList& jobs ); void queueChanged( const JobList& jobs );
void progress( qreal percent, const QString& prettyName ); void progress( qreal percent, const QString& prettyName );
@ -57,6 +62,7 @@ private:
JobList m_jobs; JobList m_jobs;
JobThread* m_thread; JobThread* m_thread;
GlobalStorage* m_storage; GlobalStorage* m_storage;
bool m_finished = true; ///< Initially, not running
}; };
} // namespace Calamares } // namespace Calamares

View File

@ -232,6 +232,7 @@ Settings::Settings( const QString& settingsFilePath, bool debugMode )
m_isSetupMode = requireBool( config, "oem-setup", !m_doChroot ); m_isSetupMode = requireBool( config, "oem-setup", !m_doChroot );
m_disableCancel = requireBool( config, "disable-cancel", false ); m_disableCancel = requireBool( config, "disable-cancel", false );
m_disableCancelDuringExec = requireBool( config, "disable-cancel-during-exec", false ); m_disableCancelDuringExec = requireBool( config, "disable-cancel-during-exec", false );
m_quitAtEnd = requireBool( config, "quit-at-end", false );
} }
catch ( YAML::Exception& e ) catch ( YAML::Exception& e )
{ {

View File

@ -101,6 +101,9 @@ public:
/** @brief Temporary setting of disable-cancel: can't cancel during exec. */ /** @brief Temporary setting of disable-cancel: can't cancel during exec. */
bool disableCancelDuringExec() const { return m_disableCancelDuringExec; } bool disableCancelDuringExec() const { return m_disableCancelDuringExec; }
/** @brief Is quit-at-end set? (Quit automatically when done) */
bool quitAtEnd() const { return m_quitAtEnd; }
private: private:
static Settings* s_instance; static Settings* s_instance;
@ -117,6 +120,7 @@ private:
bool m_promptInstall; bool m_promptInstall;
bool m_disableCancel; bool m_disableCancel;
bool m_disableCancelDuringExec; bool m_disableCancelDuringExec;
bool m_quitAtEnd;
}; };
} // namespace Calamares } // namespace Calamares

View File

@ -33,9 +33,7 @@ Label::Label( const QString& locale, LabelFormat format, QObject* parent )
: QObject( parent ) : QObject( parent )
, m_locale( Label::getLocale( locale ) ) , m_locale( Label::getLocale( locale ) )
, m_localeId( locale.isEmpty() ? m_locale.name() : locale ) , m_localeId( locale.isEmpty() ? m_locale.name() : locale )
{ {
//: language[name] (country[name])
QString longFormat = QObject::tr( "%1 (%2)" ); QString longFormat = QObject::tr( "%1 (%2)" );
QString languageName = m_locale.nativeLanguageName(); QString languageName = m_locale.nativeLanguageName();

View File

@ -40,10 +40,6 @@ class Label : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY( QString label READ label CONSTANT FINAL )
Q_PROPERTY( QString englishLabel READ englishLabel CONSTANT FINAL )
Q_PROPERTY( QString localeId MEMBER m_localeId CONSTANT FINAL )
public: public:
/** @brief Formatting option for label -- add (country) to label. */ /** @brief Formatting option for label -- add (country) to label. */
enum class LabelFormat enum class LabelFormat
@ -65,6 +61,7 @@ public:
LabelFormat format = LabelFormat::IfNeededWithCountry, LabelFormat format = LabelFormat::IfNeededWithCountry,
QObject* parent = nullptr ); QObject* parent = nullptr );
/** @brief Define a sorting order. /** @brief Define a sorting order.
* *
* Locales are sorted by their id, which means the ISO 2-letter code + country. * Locales are sorted by their id, which means the ISO 2-letter code + country.

View File

@ -239,7 +239,13 @@ CStringListModel::CStringListModel( CStringPairList l )
{ {
} }
CStringListModel::~CStringListModel() {} void
CStringListModel::setList( CalamaresUtils::Locale::CStringPairList l )
{
beginResetModel();
m_list = l;
endResetModel();
}
int int
CStringListModel::rowCount( const QModelIndex& ) const CStringListModel::rowCount( const QModelIndex& ) const
@ -264,6 +270,30 @@ CStringListModel::data( const QModelIndex& index, int role ) const
return item ? ( role == Qt::DisplayRole ? item->tr() : item->key() ) : QVariant(); return item ? ( role == Qt::DisplayRole ? item->tr() : item->key() ) : QVariant();
} }
void
CStringListModel::setCurrentIndex( int index )
{
if ( ( index < 0 ) || ( index >= m_list.count() ) )
{
return;
}
m_currentIndex = index;
emit currentIndexChanged();
}
int
CStringListModel::currentIndex() const
{
return m_currentIndex;
}
QHash< int, QByteArray >
CStringListModel::roleNames() const
{
return { { Qt::DisplayRole, "label" }, { Qt::UserRole, "key" } };
}
const CStringPair* const CStringPair*
CStringListModel::item( int index ) const CStringListModel::item( int index ) const
{ {

View File

@ -44,8 +44,9 @@ namespace Locale
* QPair<QString, QString> because there is API that needs * QPair<QString, QString> because there is API that needs
* C-style strings. * C-style strings.
*/ */
class CStringPair class CStringPair : public QObject
{ {
Q_OBJECT
public: public:
/// @brief An empty pair /// @brief An empty pair
CStringPair() {} CStringPair() {}
@ -86,6 +87,7 @@ public:
/// @brief A pair of strings for timezone regions (e.g. "America") /// @brief A pair of strings for timezone regions (e.g. "America")
class TZRegion : public CStringPair class TZRegion : public CStringPair
{ {
Q_OBJECT
public: public:
using CStringPair::CStringPair; using CStringPair::CStringPair;
virtual ~TZRegion() override; virtual ~TZRegion() override;
@ -117,6 +119,7 @@ private:
/// @brief A pair of strings for specific timezone names (e.g. "New_York") /// @brief A pair of strings for specific timezone names (e.g. "New_York")
class TZZone : public CStringPair class TZZone : public CStringPair
{ {
Q_OBJECT
public: public:
using CStringPair::CStringPair; using CStringPair::CStringPair;
QString tr() const override; QString tr() const override;
@ -137,21 +140,52 @@ protected:
class CStringListModel : public QAbstractListModel class CStringListModel : public QAbstractListModel
{ {
Q_OBJECT
Q_PROPERTY( int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged )
public: public:
/// @brief Create empty model /// @brief Create empty model
CStringListModel(); CStringListModel() {}
/// @brief Create model from list (non-owning) /// @brief Create model from list (non-owning)
CStringListModel( CStringPairList ); CStringListModel( CStringPairList );
virtual ~CStringListModel() override;
int rowCount( const QModelIndex& parent ) const override; int rowCount( const QModelIndex& parent ) const override;
QVariant data( const QModelIndex& index, int role ) const override; QVariant data( const QModelIndex& index, int role ) const override;
const CStringPair* item( int index ) const; const CStringPair* item( int index ) const;
QHash< int, QByteArray > roleNames() const override;
void setCurrentIndex( int index );
int currentIndex() const;
void setList( CStringPairList );
inline int indexOf( const QString& key )
{
const auto it = std::find_if(
m_list.constBegin(), m_list.constEnd(), [&]( const CalamaresUtils::Locale::CStringPair* item ) -> bool {
return item->key() == key;
} );
if ( it != m_list.constEnd() )
{
// distance() is usually a long long
return int( std::distance( m_list.constBegin(), it ) );
}
else
{
return -1;
}
}
private: private:
CStringPairList m_list; CStringPairList m_list;
int m_currentIndex = -1;
signals:
void currentIndexChanged();
}; };
} // namespace Locale } // namespace Locale

View File

@ -276,7 +276,7 @@ Manager::synchronousGet( const QUrl& url, const RequestOptions& options )
} }
QNetworkReply* QNetworkReply*
Manager::asynchronouseGet( const QUrl& url, const CalamaresUtils::Network::RequestOptions& options ) Manager::asynchronousGet( const QUrl& url, const CalamaresUtils::Network::RequestOptions& options )
{ {
return asynchronousRun( d->nam(), url, options ); return asynchronousRun( d->nam(), url, options );
} }

View File

@ -146,7 +146,7 @@ public:
* This may be a nullptr if an error occurs immediately. * This may be a nullptr if an error occurs immediately.
* The caller is responsible for cleaning up the reply (eventually). * The caller is responsible for cleaning up the reply (eventually).
*/ */
QNetworkReply* asynchronouseGet( const QUrl& url, const RequestOptions& options = RequestOptions() ); QNetworkReply* asynchronousGet( const QUrl& url, const RequestOptions& options = RequestOptions() );
private: private:
class Private; class Private;

View File

@ -197,7 +197,7 @@ static QTranslator* s_tztranslator = nullptr;
static QString s_translatorLocaleName; static QString s_translatorLocaleName;
void void
installTranslator( const QLocale& locale, const QString& brandingTranslationsPrefix, QObject* ) installTranslator( const QLocale& locale, const QString& brandingTranslationsPrefix )
{ {
loadSingletonTranslator( BrandingLoader( locale, brandingTranslationsPrefix ), s_brandingTranslator ); loadSingletonTranslator( BrandingLoader( locale, brandingTranslationsPrefix ), s_brandingTranslator );
loadSingletonTranslator( TZLoader( locale ), s_tztranslator ); loadSingletonTranslator( TZLoader( locale ), s_tztranslator );

View File

@ -36,9 +36,8 @@ namespace CalamaresUtils
* @brief installTranslator changes the application language. * @brief installTranslator changes the application language.
* @param locale the new locale. * @param locale the new locale.
* @param brandingTranslationsPrefix the branding path prefix, from Calamares::Branding. * @param brandingTranslationsPrefix the branding path prefix, from Calamares::Branding.
* @param parent the parent QObject.
*/ */
DLLEXPORT void installTranslator( const QLocale& locale, const QString& brandingTranslationsPrefix, QObject* parent ); DLLEXPORT void installTranslator( const QLocale& locale, const QString& brandingTranslationsPrefix );
DLLEXPORT QString translatorLocaleName(); DLLEXPORT QString translatorLocaleName();

View File

@ -29,8 +29,8 @@
#include "utils/Paste.h" #include "utils/Paste.h"
#include "utils/Retranslator.h" #include "utils/Retranslator.h"
#include "viewpages/BlankViewStep.h" #include "viewpages/BlankViewStep.h"
#include "viewpages/ViewStep.h"
#include "viewpages/ExecutionViewStep.h" #include "viewpages/ExecutionViewStep.h"
#include "viewpages/ViewStep.h"
#include <QApplication> #include <QApplication>
#include <QBoxLayout> #include <QBoxLayout>
@ -309,6 +309,13 @@ stepIsExecute( const ViewStepList& steps, int index )
&& ( qobject_cast< ExecutionViewStep* >( steps.at( index ) ) != nullptr ); && ( qobject_cast< ExecutionViewStep* >( steps.at( index ) ) != nullptr );
} }
static inline bool
isAtVeryEnd( const ViewStepList& steps, int index )
{
return ( index >= steps.count() ) || ( index == steps.count() - 1 && steps.last()->isAtEnd() );
}
void void
ViewManager::next() ViewManager::next()
{ {
@ -412,13 +419,17 @@ ViewManager::updateButtonLabels()
m_back->setText( tr( "&Back" ) ); m_back->setText( tr( "&Back" ) );
// Cancel button changes label at the end // Cancel button changes label at the end
if ( isAtVeryEnd() ) if ( isAtVeryEnd( m_steps, m_currentStep ) )
{ {
m_quit->setText( tr( "&Done" ) ); m_quit->setText( tr( "&Done" ) );
m_quit->setToolTip( quitOnCompleteTooltip ); m_quit->setToolTip( quitOnCompleteTooltip );
m_quit->setVisible( true ); // At end, always visible and enabled. m_quit->setVisible( true ); // At end, always visible and enabled.
setButtonIcon( m_quit, "dialog-ok-apply" ); setButtonIcon( m_quit, "dialog-ok-apply" );
updateCancelEnabled( true ); updateCancelEnabled( true );
if ( settings->quitAtEnd() )
{
m_quit->click();
}
} }
else else
{ {
@ -473,7 +484,7 @@ ViewManager::confirmCancelInstallation()
const auto* const settings = Calamares::Settings::instance(); const auto* const settings = Calamares::Settings::instance();
// When we're at the very end, then it's always OK to exit. // When we're at the very end, then it's always OK to exit.
if ( isAtVeryEnd() ) if ( isAtVeryEnd( m_steps, m_currentStep ) )
{ {
return true; return true;
} }

View File

@ -132,12 +132,6 @@ private:
void updateButtonLabels(); void updateButtonLabels();
void updateCancelEnabled( bool enabled ); void updateCancelEnabled( bool enabled );
bool isAtVeryEnd() const
{
return ( m_currentStep >= m_steps.count() )
|| ( m_currentStep == m_steps.count() - 1 && m_steps.last()->isAtEnd() );
}
static ViewManager* s_instance; static ViewManager* s_instance;
ViewStepList m_steps; ViewStepList m_steps;

View File

@ -136,7 +136,7 @@ ExecutionViewStep::isAtBeginning() const
bool bool
ExecutionViewStep::isAtEnd() const ExecutionViewStep::isAtEnd() const
{ {
return true; return !JobQueue::instance()->isRunning();
} }
void void

View File

@ -102,7 +102,7 @@ def run():
status = _("Dummy python step {}").format(str(c) + ":" + repr(k)) status = _("Dummy python step {}").format(str(c) + ":" + repr(k))
libcalamares.utils.debug(_("Dummy python step {}").format(str(k))) libcalamares.utils.debug(_("Dummy python step {}").format(str(k)))
sleep(1) sleep(1)
libcalamares.job.setprogress(c * 1.0 / len(configlist)) libcalamares.job.setprogress(c * 1.0 / (len(configlist)+1))
c += 1 c += 1
sleep(3) sleep(3)

View File

@ -18,12 +18,12 @@
#include "KeyboardViewStep.h" #include "KeyboardViewStep.h"
#include "JobQueue.h"
#include "GlobalStorage.h"
#include "KeyboardPage.h" #include "KeyboardPage.h"
CALAMARES_PLUGIN_FACTORY_DEFINITION( KeyboardViewStepFactory, registerPlugin<KeyboardViewStep>(); ) #include "GlobalStorage.h"
#include "JobQueue.h"
CALAMARES_PLUGIN_FACTORY_DEFINITION( KeyboardViewStepFactory, registerPlugin< KeyboardViewStep >(); )
KeyboardViewStep::KeyboardViewStep( QObject* parent ) KeyboardViewStep::KeyboardViewStep( QObject* parent )
: Calamares::ViewStep( parent ) : Calamares::ViewStep( parent )
@ -40,7 +40,9 @@ KeyboardViewStep::KeyboardViewStep( QObject* parent )
KeyboardViewStep::~KeyboardViewStep() KeyboardViewStep::~KeyboardViewStep()
{ {
if ( m_widget && m_widget->parent() == nullptr ) if ( m_widget && m_widget->parent() == nullptr )
{
m_widget->deleteLater(); m_widget->deleteLater();
}
} }
@ -111,9 +113,7 @@ void
KeyboardViewStep::onLeave() KeyboardViewStep::onLeave()
{ {
m_widget->finalize(); m_widget->finalize();
m_jobs = m_widget->createJobs( m_xOrgConfFileName, m_jobs = m_widget->createJobs( m_xOrgConfFileName, m_convertedKeymapPath, m_writeEtcDefaultKeyboard );
m_convertedKeymapPath,
m_writeEtcDefaultKeyboard );
m_prettyStatus = m_widget->prettyStatus(); m_prettyStatus = m_widget->prettyStatus();
} }
@ -121,29 +121,35 @@ KeyboardViewStep::onLeave()
void void
KeyboardViewStep::setConfigurationMap( const QVariantMap& configurationMap ) KeyboardViewStep::setConfigurationMap( const QVariantMap& configurationMap )
{ {
if ( configurationMap.contains( "xOrgConfFileName" ) && if ( configurationMap.contains( "xOrgConfFileName" )
configurationMap.value( "xOrgConfFileName" ).type() == QVariant::String && && configurationMap.value( "xOrgConfFileName" ).type() == QVariant::String
!configurationMap.value( "xOrgConfFileName" ).toString().isEmpty() ) && !configurationMap.value( "xOrgConfFileName" ).toString().isEmpty() )
{ {
m_xOrgConfFileName = configurationMap.value( "xOrgConfFileName" ) m_xOrgConfFileName = configurationMap.value( "xOrgConfFileName" ).toString();
.toString();
} }
else else
{
m_xOrgConfFileName = "00-keyboard.conf"; m_xOrgConfFileName = "00-keyboard.conf";
}
if ( configurationMap.contains( "convertedKeymapPath" ) && if ( configurationMap.contains( "convertedKeymapPath" )
configurationMap.value( "convertedKeymapPath" ).type() == QVariant::String && && configurationMap.value( "convertedKeymapPath" ).type() == QVariant::String
!configurationMap.value( "convertedKeymapPath" ).toString().isEmpty() ) && !configurationMap.value( "convertedKeymapPath" ).toString().isEmpty() )
{ {
m_convertedKeymapPath = configurationMap.value( "convertedKeymapPath" ) m_convertedKeymapPath = configurationMap.value( "convertedKeymapPath" ).toString();
.toString();
} }
else else
{
m_convertedKeymapPath = QString(); m_convertedKeymapPath = QString();
}
if ( configurationMap.contains( "writeEtcDefaultKeyboard" ) && if ( configurationMap.contains( "writeEtcDefaultKeyboard" )
configurationMap.value( "writeEtcDefaultKeyboard" ).type() == QVariant::Bool ) && configurationMap.value( "writeEtcDefaultKeyboard" ).type() == QVariant::Bool )
{
m_writeEtcDefaultKeyboard = configurationMap.value( "writeEtcDefaultKeyboard" ).toBool(); m_writeEtcDefaultKeyboard = configurationMap.value( "writeEtcDefaultKeyboard" ).toBool();
}
else else
{
m_writeEtcDefaultKeyboard = true; m_writeEtcDefaultKeyboard = true;
}
} }

View File

@ -20,12 +20,11 @@
#ifndef KEYBOARDVIEWSTEP_H #ifndef KEYBOARDVIEWSTEP_H
#define KEYBOARDVIEWSTEP_H #define KEYBOARDVIEWSTEP_H
#include <QObject> #include "DllMacro.h"
#include "utils/PluginFactory.h" #include "utils/PluginFactory.h"
#include "viewpages/ViewStep.h" #include "viewpages/ViewStep.h"
#include "DllMacro.h" #include <QObject>
class KeyboardPage; class KeyboardPage;
@ -48,7 +47,7 @@ public:
bool isAtBeginning() const override; bool isAtBeginning() const override;
bool isAtEnd() const override; bool isAtEnd() const override;
QList< Calamares::job_ptr > jobs() const override; Calamares::JobList jobs() const override;
void onActivate() override; void onActivate() override;
void onLeave() override; void onLeave() override;
@ -64,7 +63,7 @@ private:
QString m_convertedKeymapPath; QString m_convertedKeymapPath;
bool m_writeEtcDefaultKeyboard; bool m_writeEtcDefaultKeyboard;
QList< Calamares::job_ptr > m_jobs; Calamares::JobList m_jobs;
}; };
CALAMARES_PLUGIN_FACTORY_DECLARATION( KeyboardViewStepFactory ) CALAMARES_PLUGIN_FACTORY_DECLARATION( KeyboardViewStepFactory )

View File

@ -13,6 +13,7 @@ calamares_add_plugin( locale
EXPORT_MACRO PLUGINDLLEXPORT_PRO EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES SOURCES
${geoip_src} ${geoip_src}
Config.cpp
LCLocaleDialog.cpp LCLocaleDialog.cpp
LocaleConfiguration.cpp LocaleConfiguration.cpp
LocalePage.cpp LocalePage.cpp

View File

@ -0,0 +1,324 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019-2020, Adriaan de Groot <groot@kde.org>
* Copyright 2020, Camilo Higuita <milo.h@aol.com>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Config.h"
#include "LCLocaleDialog.h"
#include "SetTimezoneJob.h"
#include "timezonewidget/timezonewidget.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include "Settings.h"
#include "locale/Label.h"
#include "locale/TimeZone.h"
#include "utils/CalamaresUtilsGui.h"
#include "utils/Logger.h"
#include "utils/Retranslator.h"
#include <QDebug>
#include <QProcess>
Config::Config( QObject* parent )
: QObject( parent )
, m_regionList( CalamaresUtils::Locale::TZRegion::fromZoneTab() )
, m_regionModel( new CalamaresUtils::Locale::CStringListModel( m_regionList ) )
, m_zonesModel( new CalamaresUtils::Locale::CStringListModel() )
, m_blockTzWidgetSet( false )
{
connect( m_regionModel, &CalamaresUtils::Locale::CStringListModel::currentIndexChanged, [&]() {
m_zonesModel->setList( static_cast< const CalamaresUtils::Locale::TZRegion* >(
m_regionModel->item( m_regionModel->currentIndex() ) )
->zones() );
updateLocaleLabels();
} );
connect(
m_zonesModel, &CalamaresUtils::Locale::CStringListModel::currentIndexChanged, [&]() { updateLocaleLabels(); } );
}
Config::~Config()
{
qDeleteAll( m_regionList );
}
CalamaresUtils::Locale::CStringListModel*
Config::zonesModel() const
{
return m_zonesModel;
}
CalamaresUtils::Locale::CStringListModel*
Config::regionModel() const
{
return m_regionModel;
}
void
Config::setLocaleInfo( const QString& initialRegion, const QString& initialZone, const QString& localeGenPath )
{
using namespace CalamaresUtils::Locale;
cDebug() << "REGION MODEL SIZE" << initialRegion << initialZone;
auto* region = m_regionList.find< TZRegion >( initialRegion );
if ( region && region->zones().find< TZZone >( initialZone ) )
{
this->m_regionModel->setCurrentIndex( m_regionModel->indexOf( initialRegion ) );
m_zonesModel->setList( region->zones() );
this->m_zonesModel->setCurrentIndex( m_zonesModel->indexOf( initialZone ) );
}
else
{
this->m_regionModel->setCurrentIndex( m_regionModel->indexOf( "America" ) );
m_zonesModel->setList(
static_cast< const TZRegion* >( m_regionModel->item( m_regionModel->currentIndex() ) )->zones() );
this->m_zonesModel->setCurrentIndex( m_zonesModel->indexOf( "New_York" ) );
}
// Some distros come with a meaningfully commented and easy to parse locale.gen,
// and others ship a separate file /usr/share/i18n/SUPPORTED with a clean list of
// supported locales. We first try that one, and if it doesn't exist, we fall back
// to parsing the lines from locale.gen
m_localeGenLines.clear();
QFile supported( "/usr/share/i18n/SUPPORTED" );
QByteArray ba;
if ( supported.exists() && supported.open( QIODevice::ReadOnly | QIODevice::Text ) )
{
ba = supported.readAll();
supported.close();
const auto lines = ba.split( '\n' );
for ( const QByteArray& line : lines )
{
m_localeGenLines.append( QString::fromLatin1( line.simplified() ) );
}
}
else
{
QFile localeGen( localeGenPath );
if ( localeGen.open( QIODevice::ReadOnly | QIODevice::Text ) )
{
ba = localeGen.readAll();
localeGen.close();
}
else
{
cWarning() << "Cannot open file" << localeGenPath
<< ". Assuming the supported languages are already built into "
"the locale archive.";
QProcess localeA;
localeA.start( "locale", QStringList() << "-a" );
localeA.waitForFinished();
ba = localeA.readAllStandardOutput();
}
const auto lines = ba.split( '\n' );
for ( const QByteArray& line : lines )
{
if ( line.startsWith( "## " ) || line.startsWith( "# " ) || line.simplified() == "#" )
{
continue;
}
QString lineString = QString::fromLatin1( line.simplified() );
if ( lineString.startsWith( "#" ) )
{
lineString.remove( '#' );
}
lineString = lineString.simplified();
if ( lineString.isEmpty() )
{
continue;
}
m_localeGenLines.append( lineString );
}
}
if ( m_localeGenLines.isEmpty() )
{
cWarning() << "cannot acquire a list of available locales."
<< "The locale and localecfg modules will be broken as long as this "
"system does not provide"
<< "\n\t "
<< "* a well-formed" << supported.fileName() << "\n\tOR"
<< "* a well-formed"
<< ( localeGenPath.isEmpty() ? QLatin1String( "/etc/locale.gen" ) : localeGenPath ) << "\n\tOR"
<< "* a complete pre-compiled locale-gen database which allows complete locale -a output.";
return; // something went wrong and there's nothing we can do about it.
}
// Assuming we have a list of supported locales, we usually only want UTF-8 ones
// because it's not 1995.
for ( auto it = m_localeGenLines.begin(); it != m_localeGenLines.end(); )
{
if ( !it->contains( "UTF-8", Qt::CaseInsensitive ) && !it->contains( "utf8", Qt::CaseInsensitive ) )
{
it = m_localeGenLines.erase( it );
}
else
{
++it;
}
}
// We strip " UTF-8" from "en_US.UTF-8 UTF-8" because it's redundant redundant.
for ( auto it = m_localeGenLines.begin(); it != m_localeGenLines.end(); ++it )
{
if ( it->endsWith( " UTF-8" ) )
{
it->chop( 6 );
}
*it = it->simplified();
}
updateGlobalStorage();
updateLocaleLabels();
}
void
Config::updateGlobalLocale()
{
auto* gs = Calamares::JobQueue::instance()->globalStorage();
const QString bcp47 = m_selectedLocaleConfiguration.toBcp47();
gs->insert( "locale", bcp47 );
}
void
Config::updateGlobalStorage()
{
auto* gs = Calamares::JobQueue::instance()->globalStorage();
const auto* location = currentLocation();
bool locationChanged = ( location->region() != gs->value( "locationRegion" ) )
|| ( location->zone() != gs->value( "locationZone" ) );
gs->insert( "locationRegion", location->region() );
gs->insert( "locationZone", location->zone() );
updateGlobalLocale();
// If we're in chroot mode (normal install mode), then we immediately set the
// timezone on the live system. When debugging timezones, don't bother.
#ifndef DEBUG_TIMEZONES
if ( locationChanged && Calamares::Settings::instance()->doChroot() )
{
QProcess::execute( "timedatectl", // depends on systemd
{ "set-timezone", location->region() + '/' + location->zone() } );
}
#endif
// Preserve those settings that have been made explicit.
auto newLocale = guessLocaleConfiguration();
if ( !m_selectedLocaleConfiguration.isEmpty() && m_selectedLocaleConfiguration.explicit_lang )
{
newLocale.setLanguage( m_selectedLocaleConfiguration.language() );
}
if ( !m_selectedLocaleConfiguration.isEmpty() && m_selectedLocaleConfiguration.explicit_lc )
{
newLocale.lc_numeric = m_selectedLocaleConfiguration.lc_numeric;
newLocale.lc_time = m_selectedLocaleConfiguration.lc_time;
newLocale.lc_monetary = m_selectedLocaleConfiguration.lc_monetary;
newLocale.lc_paper = m_selectedLocaleConfiguration.lc_paper;
newLocale.lc_name = m_selectedLocaleConfiguration.lc_name;
newLocale.lc_address = m_selectedLocaleConfiguration.lc_address;
newLocale.lc_telephone = m_selectedLocaleConfiguration.lc_telephone;
newLocale.lc_measurement = m_selectedLocaleConfiguration.lc_measurement;
newLocale.lc_identification = m_selectedLocaleConfiguration.lc_identification;
}
newLocale.explicit_lang = m_selectedLocaleConfiguration.explicit_lang;
newLocale.explicit_lc = m_selectedLocaleConfiguration.explicit_lc;
m_selectedLocaleConfiguration = newLocale;
updateLocaleLabels();
}
void
Config::updateLocaleLabels()
{
LocaleConfiguration lc
= m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration() : m_selectedLocaleConfiguration;
auto labels = prettyLocaleStatus( lc );
emit prettyStatusChanged();
}
std::pair< QString, QString >
Config::prettyLocaleStatus( const LocaleConfiguration& lc ) const
{
using CalamaresUtils::Locale::Label;
Label lang( lc.language(), Label::LabelFormat::AlwaysWithCountry );
Label num( lc.lc_numeric, Label::LabelFormat::AlwaysWithCountry );
return std::make_pair< QString, QString >(
tr( "The system language will be set to %1." ).arg( lang.label() ),
tr( "The numbers and dates locale will be set to %1." ).arg( num.label() ) );
}
Calamares::JobList
Config::createJobs()
{
QList< Calamares::job_ptr > list;
const CalamaresUtils::Locale::TZZone* location = currentLocation();
Calamares::Job* j = new SetTimezoneJob( location->region(), location->zone() );
list.append( Calamares::job_ptr( j ) );
return list;
}
LocaleConfiguration
Config::guessLocaleConfiguration() const
{
return LocaleConfiguration::fromLanguageAndLocation(
QLocale().name(), m_localeGenLines, currentLocation() ? currentLocation()->country() : "" );
}
QMap< QString, QString >
Config::localesMap()
{
return m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration().toMap()
: m_selectedLocaleConfiguration.toMap();
}
QString
Config::prettyStatus() const
{
QString status;
status += tr( "Set timezone to %1/%2.<br/>" )
.arg( m_regionModel->item( m_regionModel->currentIndex() )->tr() )
.arg( m_zonesModel->item( m_zonesModel->currentIndex() )->tr() );
LocaleConfiguration lc
= m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration() : m_selectedLocaleConfiguration;
auto labels = prettyLocaleStatus( lc );
status += labels.first + "<br/>";
status += labels.second + "<br/>";
return status;
}
const CalamaresUtils::Locale::TZZone*
Config::currentLocation() const
{
return static_cast< const CalamaresUtils::Locale::TZZone* >( m_zonesModel->item( m_zonesModel->currentIndex() ) );
}

View File

@ -0,0 +1,87 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019-2020, Adriaan de Groot <groot@kde.org>
* Copyright 2020, Camilo Higuita <milo.h@aol.com>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LOCALE_CONFIG_H
#define LOCALE_CONFIG_H
#include "LocaleConfiguration.h"
#include "timezonewidget/localeglobal.h"
#include "Job.h"
#include "locale/TimeZone.h"
#include <QAbstractListModel>
#include <QObject>
#include <memory>
class Config : public QObject
{
Q_OBJECT
Q_PROPERTY( CalamaresUtils::Locale::CStringListModel* zonesModel READ zonesModel CONSTANT FINAL )
Q_PROPERTY( CalamaresUtils::Locale::CStringListModel* regionModel READ regionModel CONSTANT FINAL )
Q_PROPERTY( QString prettyStatus READ prettyStatus NOTIFY prettyStatusChanged FINAL )
public:
Config( QObject* parent = nullptr );
~Config();
CalamaresUtils::Locale::CStringListModel* regionModel() const;
CalamaresUtils::Locale::CStringListModel* zonesModel() const;
void setLocaleInfo( const QString& initialRegion, const QString& initialZone, const QString& localeGenPath );
Calamares::JobList createJobs();
QMap< QString, QString > localesMap();
QString prettyStatus() const;
private:
CalamaresUtils::Locale::CStringPairList m_regionList;
CalamaresUtils::Locale::CStringListModel* m_regionModel;
CalamaresUtils::Locale::CStringListModel* m_zonesModel;
LocaleConfiguration m_selectedLocaleConfiguration;
QStringList m_localeGenLines;
int m_currentRegion = -1;
bool m_blockTzWidgetSet;
LocaleConfiguration guessLocaleConfiguration() const;
// For the given locale config, return two strings describing
// the settings for language and numbers.
std::pair< QString, QString > prettyLocaleStatus( const LocaleConfiguration& ) const;
/** @brief Update the GS *locale* key with the selected system language.
*
* This uses whatever is set in m_selectedLocaleConfiguration as the language,
* and writes it to GS *locale* key (as a string, in BCP47 format).
*/
void updateGlobalLocale();
void updateGlobalStorage();
void updateLocaleLabels();
const CalamaresUtils::Locale::TZZone* currentLocation() const;
signals:
void prettyStatusChanged();
};
#endif

View File

@ -0,0 +1,29 @@
# When debugging the timezone widget, add this debugging definition
# to have a debugging-friendly timezone widget, debug logging,
# and no intrusive timezone-setting while clicking around.
option( DEBUG_TIMEZONES "Debug-friendly timezone widget." OFF )
if( DEBUG_TIMEZONES )
add_definitions( -DDEBUG_TIMEZONES )
endif()
# Because we're sharing sources with the regular locale module
set( _locale ${CMAKE_CURRENT_SOURCE_DIR}/../locale )
include_directories( ${_locale} )
calamares_add_plugin( localeq
TYPE viewmodule
EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES
LocaleQmlViewStep.cpp
${_locale}/LocaleConfiguration.cpp
${_locale}/Config.cpp
${_locale}/SetTimezoneJob.cpp
${_locale}/timezonewidget/localeglobal.cpp
RESOURCES
${_locale}/locale.qrc
LINK_PRIVATE_LIBRARIES
calamaresui
Qt5::Network
SHARED_LIB
)

View File

@ -0,0 +1,203 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2018,2020 Adriaan de Groot <groot@kde.org>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include "LocaleQmlViewStep.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include "geoip/Handler.h"
#include "network/Manager.h"
#include "utils/CalamaresUtilsGui.h"
#include "utils/Logger.h"
#include "utils/Variant.h"
#include "utils/Yaml.h"
#include "timezonewidget/localeglobal.h"
#include "Branding.h"
#include "modulesystem/ModuleManager.h"
#include <QQmlEngine>
#include <QFutureWatcher>
#include <QPixmap>
#include <QVariant>
CALAMARES_PLUGIN_FACTORY_DEFINITION( LocaleQmlViewStepFactory, registerPlugin< LocaleQmlViewStep >(); )
LocaleQmlViewStep::LocaleQmlViewStep( QObject* parent )
: Calamares::QmlViewStep( parent )
, m_config( new Config( this ) )
, m_nextEnabled( false )
, m_geoip( nullptr )
{
emit nextStatusChanged( m_nextEnabled );
}
QObject*
LocaleQmlViewStep::getConfig()
{
return m_config;
}
void
LocaleQmlViewStep::fetchGeoIpTimezone()
{
if ( m_geoip && m_geoip->isValid() )
{
m_startingTimezone = m_geoip->get();
if ( !m_startingTimezone.isValid() )
{
cWarning() << "GeoIP lookup at" << m_geoip->url() << "failed.";
}
}
m_config->setLocaleInfo(m_startingTimezone.first, m_startingTimezone.second, m_localeGenPath);
}
Calamares::RequirementsList LocaleQmlViewStep::checkRequirements()
{
LocaleGlobal::init();
if ( m_geoip && m_geoip->isValid() )
{
auto& network = CalamaresUtils::Network::Manager::instance();
if ( network.hasInternet() )
{
fetchGeoIpTimezone();
}
else
{
if ( network.synchronousPing( m_geoip->url() ) )
{
fetchGeoIpTimezone();
}
}
}
return Calamares::RequirementsList();
}
QString
LocaleQmlViewStep::prettyName() const
{
return tr( "Location" );
}
bool
LocaleQmlViewStep::isNextEnabled() const
{
// TODO: should return true
return true;
}
bool
LocaleQmlViewStep::isBackEnabled() const
{
// TODO: should return true (it's weird that you are not allowed to have welcome *after* anything
return true;
}
bool
LocaleQmlViewStep::isAtBeginning() const
{
// TODO: adjust to "pages" in the QML
return true;
}
bool
LocaleQmlViewStep::isAtEnd() const
{
// TODO: adjust to "pages" in the QML
return true;
}
Calamares::JobList
LocaleQmlViewStep::jobs() const
{
return m_jobs;
}
void LocaleQmlViewStep::onActivate()
{
// TODO no sure if it is needed at all or for the abstract class to start something
}
void LocaleQmlViewStep::onLeave()
{
if ( true )
{
m_jobs = m_config->createJobs();
// m_prettyStatus = m_actualWidget->prettyStatus();
auto map = m_config->localesMap();
QVariantMap vm;
for ( auto it = map.constBegin(); it != map.constEnd(); ++it )
{
vm.insert( it.key(), it.value() );
}
Calamares::JobQueue::instance()->globalStorage()->insert( "localeConf", vm );
}
else
{
m_jobs.clear();
Calamares::JobQueue::instance()->globalStorage()->remove( "localeConf" );
}
}
void LocaleQmlViewStep::setConfigurationMap(const QVariantMap& configurationMap)
{
QString region = CalamaresUtils::getString( configurationMap, "region" );
QString zone = CalamaresUtils::getString( configurationMap, "zone" );
if ( !region.isEmpty() && !zone.isEmpty() )
{
m_startingTimezone = CalamaresUtils::GeoIP::RegionZonePair( region, zone );
}
else
{
m_startingTimezone
= CalamaresUtils::GeoIP::RegionZonePair( QStringLiteral( "America" ), QStringLiteral( "New_York" ) );
}
m_localeGenPath = CalamaresUtils::getString( configurationMap, "localeGenPath" );
if ( m_localeGenPath.isEmpty() )
{
m_localeGenPath = QStringLiteral( "/etc/locale.gen" );
}
bool ok = false;
QVariantMap geoip = CalamaresUtils::getSubMap( configurationMap, "geoip", ok );
if ( ok )
{
QString url = CalamaresUtils::getString( geoip, "url" );
QString style = CalamaresUtils::getString( geoip, "style" );
QString selector = CalamaresUtils::getString( geoip, "selector" );
m_geoip = std::make_unique< CalamaresUtils::GeoIP::Handler >( style, url, selector );
if ( !m_geoip->isValid() )
{
cWarning() << "GeoIP Style" << style << "is not recognized.";
}
}
checkRequirements();
Calamares::QmlViewStep::setConfigurationMap( configurationMap ); // call parent implementation last
setContextProperty( "Localeq", m_config );
}

View File

@ -0,0 +1,76 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019-2020 Adriaan de Groot <groot@kde.org>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LOCALE_QMLVIEWSTEP_H
#define LOCALE_QMLVIEWSTEP_H
#include "Config.h"
#include "geoip/Handler.h"
#include "geoip/Interface.h"
#include "utils/PluginFactory.h"
#include "viewpages/QmlViewStep.h"
#include <DllMacro.h>
#include <QFutureWatcher>
#include <QObject>
#include <memory>
class PLUGINDLLEXPORT LocaleQmlViewStep : public Calamares::QmlViewStep
{
Q_OBJECT
public:
explicit LocaleQmlViewStep( QObject* parent = nullptr );
QString prettyName() const override;
bool isNextEnabled() const override;
bool isBackEnabled() const override;
bool isAtBeginning() const override;
bool isAtEnd() const override;
Calamares::JobList jobs() const override;
void onActivate() override;
void onLeave() override;
void setConfigurationMap( const QVariantMap& configurationMap ) override;
QObject* getConfig() override;
virtual Calamares::RequirementsList checkRequirements() override;
private:
// TODO: a generic QML viewstep should return a config object from a method
Config *m_config;
bool m_nextEnabled;
QString m_prettyStatus;
CalamaresUtils::GeoIP::RegionZonePair m_startingTimezone;
QString m_localeGenPath;
Calamares::JobList m_jobs;
std::unique_ptr< CalamaresUtils::GeoIP::Handler > m_geoip;
void fetchGeoIpTimezone();
};
CALAMARES_PLUGIN_FACTORY_DECLARATION( LocaleQmlViewStepFactory )
#endif

View File

@ -0,0 +1,97 @@
---
# This settings are used to set your default system time zone.
# Time zones are usually located under /usr/share/zoneinfo and
# provided by the 'tzdata' package of your Distribution.
#
# Distributions using systemd can list available
# time zones by using the timedatectl command.
# timedatectl list-timezones
#
# The starting timezone (e.g. the pin-on-the-map) when entering
# the locale page can be set through keys *region* and *zone*.
# If either is not set, defaults to America/New_York.
#
region: "America"
zone: "New_York"
# System locales are detected in the following order:
#
# - /usr/share/i18n/SUPPORTED
# - localeGenPath (defaults to /etc/locale.gen if not set)
# - 'locale -a' output
#
# Enable only when your Distribution is using an
# custom path for locale.gen
#
#localeGenPath: "PATH_TO/locale.gen"
# GeoIP based Language settings: Leave commented out to disable GeoIP.
#
# GeoIP needs a working Internet connection.
# This can be managed from `welcome.conf` by adding
# internet to the list of required conditions.
#
# The configuration
# is in three parts: a *style*, which can be "json" or "xml"
# depending on the kind of data returned by the service, and
# a *url* where the data is retrieved, and an optional *selector*
# to pick the right field out of the returned data (e.g. field
# name in JSON or element name in XML).
#
# The default selector (when the setting is blank) is picked to
# work with existing JSON providers (which use "time_zone") and
# Ubiquity's XML providers (which use "TimeZone").
#
# If the service configured via *url* uses
# a different attribute name (e.g. "timezone") in JSON or a
# different element tag (e.g. "<Time_Zone>") in XML, set this
# string to the name or tag to be used.
#
# In JSON:
# - if the string contains "." characters, this is used as a
# multi-level selector, e.g. "a.b" will select the timezone
# from data "{a: {b: "Europe/Amsterdam" } }".
# - each part of the string split by "." characters is used as
# a key into the JSON data.
# In XML:
# - all elements with the named tag (e.g. all TimeZone) elements
# from the document are checked; the first one with non-empty
# text value is used.
#
#
# An HTTP(S) request is made to *url*. The request should return
# valid data in a suitable format, depending on *style*;
# generally this includes a string value with the timezone
# in <region>/<zone> format. For services that return data which
# does not follow the conventions of "suitable data" described
# below, *selector* may be used to pick different data.
#
# Note that this example URL works, but the service is shutting
# down in June 2018.
#
# Suitable JSON data looks like
# ```
# {"time_zone":"America/New_York"}
# ```
# Suitable XML data looks like
# ```
# <Response><TimeZone>Europe/Brussels</TimeZone></Response>
# ```
#
# To accommodate providers of GeoIP timezone data with peculiar timezone
# naming conventions, the following cleanups are performed automatically:
# - backslashes are removed
# - spaces are replaced with _
#
# Legacy settings "geoipStyle", "geoipUrl" and "geoipSelector"
# in the top-level are still supported, but I'd advise against.
#
# To disable GeoIP checking, either comment-out the entire geoip section,
# or set the *style* key to an unsupported format (e.g. `none`).
# Also, note the analogous feature in src/modules/welcome/welcome.conf.
#
geoip:
style: "json"
url: "https://geoip.kde.org/v1/calamares"
selector: "" # leave blank for the default

View File

@ -0,0 +1,113 @@
import io.calamares.modules 1.0 as Modules
import io.calamares.ui 1.0
import QtQuick 2.10
import QtQuick.Controls 2.10
import QtQuick.Layouts 1.3
import org.kde.kirigami 2.7 as Kirigami
import QtGraphicalEffects 1.0
ResponsiveBase
{
id: control
Modules.Locale //locale handler
{
id: _locale
}
title: stackView.currentItem.title
subtitle: stackView.currentItem.subtitle
message: stackView.currentItem.message
stackView.initialItem: Item
{
id: _regionsListComponent
property string title: qsTr("Region")
property string subtitle: qsTr("Pick your preferred region or use the default one based on your current location")
property string message: qsTr("Select your preferred zone within your location to continue with the installation")
ListViewTemplate
{
id: _regionListView
anchors.centerIn: parent
implicitWidth: Math.min(parent.width, 500)
implicitHeight: Math.min(contentHeight, 500)
currentIndex: model.currentIndex
model: _locale.Config.regionModel
delegate: ListItemDelegate
{
id: _delegate
label1.text: model.label
onClicked:
{
_regionListView.model.currentIndex = index
_stackView.push(_zonesListComponent)
}
}
footer: RowLayout
{
width: parent.width
z: 99999
Button
{
Layout.fillWidth: true
text: qsTr("Timezones")
icon.name: "go-previous"
onClicked: control.stackView.push(_zonesListComponent)
}
}
}
}
Component
{
id: _zonesListComponent
Item
{
property string title: qsTr("Timezone")
property string subtitle: _locale.Config.prettyStatus
property string message: ""
ListViewTemplate
{
id: _zonesListView
anchors.centerIn: parent
implicitWidth: Math.min(parent.width, 500)
implicitHeight: Math.min(contentHeight, 500)
currentIndex: model.currentIndex
model: _locale.Config.zonesModel
delegate: ListItemDelegate
{
id: _delegate
label1.text: model.label
onClicked:
{
_zonesListView.model.currentIndex = index
positionViewAtIndex(index, ListView.Center)
}
}
footer: RowLayout
{
width: parent.width
z: 99999
Button
{
Layout.fillWidth: true
icon.name: "go-previous"
text: qsTr("Regions")
onClicked: control.stackView.pop()
}
}
}
}
}
}

View File

@ -187,7 +187,7 @@ NetInstallPage::loadGroupList( const QString& confUrl )
using namespace CalamaresUtils::Network; using namespace CalamaresUtils::Network;
cDebug() << "NetInstall loading groups from" << confUrl; cDebug() << "NetInstall loading groups from" << confUrl;
QNetworkReply* reply = Manager::instance().asynchronouseGet( QNetworkReply* reply = Manager::instance().asynchronousGet(
QUrl( confUrl ), QUrl( confUrl ),
RequestOptions( RequestOptions::FakeUserAgent | RequestOptions::FollowRedirect, std::chrono::seconds( 30 ) ) ); RequestOptions( RequestOptions::FakeUserAgent | RequestOptions::FollowRedirect, std::chrono::seconds( 30 ) ) );

View File

@ -2,8 +2,9 @@
* *
* Copyright 2014, Aurélien Gâteau <agateau@kde.org> * Copyright 2014, Aurélien Gâteau <agateau@kde.org>
* Copyright 2014-2017, Teo Mrnjavac <teo@kde.org> * Copyright 2014-2017, Teo Mrnjavac <teo@kde.org>
* Copyright 2018-2019, Adriaan de Groot <groot@kde.org> * Copyright 2018-2019, 2020, Adriaan de Groot <groot@kde.org>
* Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com> * Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com>
* Copyright 2020, Anke Boersma <demm@kaosx.us
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -22,23 +23,22 @@
#include "gui/PartitionViewStep.h" #include "gui/PartitionViewStep.h"
#include "core/DeviceModel.h" #include "core/DeviceModel.h"
#include "core/PartitionActions.h"
#include "core/PartitionCoreModule.h"
#include "core/PartitionModel.h"
#include "core/KPMHelpers.h" #include "core/KPMHelpers.h"
#include "core/OsproberEntry.h" #include "core/OsproberEntry.h"
#include "core/PartUtils.h" #include "core/PartUtils.h"
#include "core/PartitionActions.h"
#include "core/PartitionCoreModule.h"
#include "core/PartitionModel.h"
#include "gui/ChoicePage.h" #include "gui/ChoicePage.h"
#include "gui/PartitionPage.h"
#include "gui/PartitionBarsView.h" #include "gui/PartitionBarsView.h"
#include "gui/PartitionLabelsView.h" #include "gui/PartitionLabelsView.h"
#include "gui/PartitionPage.h"
#include "Branding.h" #include "Branding.h"
#include "CalamaresVersion.h" #include "CalamaresVersion.h"
#include "GlobalStorage.h" #include "GlobalStorage.h"
#include "Job.h" #include "Job.h"
#include "JobQueue.h" #include "JobQueue.h"
#include "utils/CalamaresUtilsGui.h" #include "utils/CalamaresUtilsGui.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/NamedEnum.h" #include "utils/NamedEnum.h"
@ -51,17 +51,16 @@
#include <kpmcore/core/partition.h> #include <kpmcore/core/partition.h>
#include <kpmcore/fs/filesystem.h> #include <kpmcore/fs/filesystem.h>
// Qt
#include <QApplication> #include <QApplication>
#include <QDir> #include <QDir>
#include <QFormLayout> #include <QFormLayout>
#include <QFutureWatcher>
#include <QLabel> #include <QLabel>
#include <QMessageBox> #include <QMessageBox>
#include <QProcess> #include <QProcess>
#include <QStackedWidget> #include <QStackedWidget>
#include <QTimer> #include <QTimer>
#include <QtConcurrent/QtConcurrent> #include <QtConcurrent/QtConcurrent>
#include <QFutureWatcher>
PartitionViewStep::PartitionViewStep( QObject* parent ) PartitionViewStep::PartitionViewStep( QObject* parent )
: Calamares::ViewStep( parent ) : Calamares::ViewStep( parent )
@ -108,19 +107,21 @@ PartitionViewStep::continueLoading()
m_waitingWidget->deleteLater(); m_waitingWidget->deleteLater();
m_waitingWidget = nullptr; m_waitingWidget = nullptr;
connect( m_core, &PartitionCoreModule::hasRootMountPointChanged, connect( m_core, &PartitionCoreModule::hasRootMountPointChanged, this, &PartitionViewStep::nextStatusChanged );
this, &PartitionViewStep::nextStatusChanged ); connect( m_choicePage, &ChoicePage::nextStatusChanged, this, &PartitionViewStep::nextStatusChanged );
connect( m_choicePage, &ChoicePage::nextStatusChanged,
this, &PartitionViewStep::nextStatusChanged );
} }
PartitionViewStep::~PartitionViewStep() PartitionViewStep::~PartitionViewStep()
{ {
if ( m_choicePage && m_choicePage->parent() == nullptr ) if ( m_choicePage && m_choicePage->parent() == nullptr )
{
m_choicePage->deleteLater(); m_choicePage->deleteLater();
}
if ( m_manualPartitionPage && m_manualPartitionPage->parent() == nullptr ) if ( m_manualPartitionPage && m_manualPartitionPage->parent() == nullptr )
{
m_manualPartitionPage->deleteLater(); m_manualPartitionPage->deleteLater();
}
} }
@ -168,12 +169,12 @@ PartitionViewStep::createSummaryWidget() const
.arg( *Calamares::Branding::ShortVersionedName ); .arg( *Calamares::Branding::ShortVersionedName );
break; break;
case ChoicePage::Erase: case ChoicePage::Erase:
modeText = tr( "<strong>Erase</strong> disk and install %1." ) modeText
.arg( *Calamares::Branding::ShortVersionedName ); = tr( "<strong>Erase</strong> disk and install %1." ).arg( *Calamares::Branding::ShortVersionedName );
break; break;
case ChoicePage::Replace: case ChoicePage::Replace:
modeText = tr( "<strong>Replace</strong> a partition with %1." ) modeText
.arg( *Calamares::Branding::ShortVersionedName ); = tr( "<strong>Replace</strong> a partition with %1." ).arg( *Calamares::Branding::ShortVersionedName );
break; break;
case ChoicePage::NoChoice: case ChoicePage::NoChoice:
case ChoicePage::Manual: case ChoicePage::Manual:
@ -190,7 +191,8 @@ PartitionViewStep::createSummaryWidget() const
switch ( choice ) switch ( choice )
{ {
case ChoicePage::Alongside: case ChoicePage::Alongside:
modeText = tr( "Install %1 <strong>alongside</strong> another operating system on disk <strong>%2</strong> (%3)." ) modeText = tr( "Install %1 <strong>alongside</strong> another operating system on disk "
"<strong>%2</strong> (%3)." )
.arg( *Calamares::Branding::ShortVersionedName ) .arg( *Calamares::Branding::ShortVersionedName )
.arg( info.deviceNode ) .arg( info.deviceNode )
.arg( info.deviceName ); .arg( info.deviceName );
@ -217,9 +219,8 @@ PartitionViewStep::createSummaryWidget() const
} }
else // multiple disk previews! else // multiple disk previews!
{ {
diskInfoLabel->setText( tr( "Disk <strong>%1</strong> (%2)" ) diskInfoLabel->setText(
.arg( info.deviceNode ) tr( "Disk <strong>%1</strong> (%2)" ).arg( info.deviceNode ).arg( info.deviceName ) );
.arg( info.deviceName ) );
} }
formLayout->addRow( diskInfoLabel ); formLayout->addRow( diskInfoLabel );
@ -227,10 +228,10 @@ PartitionViewStep::createSummaryWidget() const
PartitionLabelsView* previewLabels; PartitionLabelsView* previewLabels;
QVBoxLayout* field; QVBoxLayout* field;
PartitionBarsView::NestedPartitionsMode mode = Calamares::JobQueue::instance()->globalStorage()-> PartitionBarsView::NestedPartitionsMode mode
value( "drawNestedPartitions" ).toBool() ? = Calamares::JobQueue::instance()->globalStorage()->value( "drawNestedPartitions" ).toBool()
PartitionBarsView::DrawNestedPartitions : ? PartitionBarsView::DrawNestedPartitions
PartitionBarsView::NoNestedPartitions; : PartitionBarsView::NoNestedPartitions;
preview = new PartitionBarsView; preview = new PartitionBarsView;
preview->setNestedPartitionsMode( mode ); preview->setNestedPartitionsMode( mode );
previewLabels = new PartitionLabelsView; previewLabels = new PartitionLabelsView;
@ -268,8 +269,10 @@ PartitionViewStep::createSummaryWidget() const
foreach ( const Calamares::job_ptr& job, jobs() ) foreach ( const Calamares::job_ptr& job, jobs() )
{ {
if ( !job->prettyDescription().isEmpty() ) if ( !job->prettyDescription().isEmpty() )
{
jobsLines.append( job->prettyDescription() ); jobsLines.append( job->prettyDescription() );
} }
}
if ( !jobsLines.isEmpty() ) if ( !jobsLines.isEmpty() )
{ {
QLabel* jobsLabel = new QLabel( widget ); QLabel* jobsLabel = new QLabel( widget );
@ -301,8 +304,10 @@ PartitionViewStep::next()
m_widget->setCurrentWidget( m_manualPartitionPage ); m_widget->setCurrentWidget( m_manualPartitionPage );
m_manualPartitionPage->selectDeviceByIndex( m_choicePage->lastSelectedDeviceIndex() ); m_manualPartitionPage->selectDeviceByIndex( m_choicePage->lastSelectedDeviceIndex() );
if ( m_core->isDirty() ) if ( m_core->isDirty() )
{
m_manualPartitionPage->onRevertClicked(); m_manualPartitionPage->onRevertClicked();
} }
}
cDebug() << "Choice applied: " << m_choicePage->currentChoice(); cDebug() << "Choice applied: " << m_choicePage->currentChoice();
} }
} }
@ -329,10 +334,14 @@ bool
PartitionViewStep::isNextEnabled() const PartitionViewStep::isNextEnabled() const
{ {
if ( m_choicePage && m_widget->currentWidget() == m_choicePage ) if ( m_choicePage && m_widget->currentWidget() == m_choicePage )
{
return m_choicePage->isNextEnabled(); return m_choicePage->isNextEnabled();
}
if ( m_manualPartitionPage && m_widget->currentWidget() == m_manualPartitionPage ) if ( m_manualPartitionPage && m_widget->currentWidget() == m_manualPartitionPage )
{
return m_core->hasRootMountPoint(); return m_core->hasRootMountPoint();
}
return false; return false;
} }
@ -349,7 +358,9 @@ bool
PartitionViewStep::isAtBeginning() const PartitionViewStep::isAtBeginning() const
{ {
if ( m_widget->currentWidget() != m_choicePage ) if ( m_widget->currentWidget() != m_choicePage )
{
return false; return false;
}
return true; return true;
} }
@ -359,10 +370,11 @@ PartitionViewStep::isAtEnd() const
{ {
if ( m_widget->currentWidget() == m_choicePage ) if ( m_widget->currentWidget() == m_choicePage )
{ {
if ( m_choicePage->currentChoice() == ChoicePage::Erase || if ( m_choicePage->currentChoice() == ChoicePage::Erase || m_choicePage->currentChoice() == ChoicePage::Replace
m_choicePage->currentChoice() == ChoicePage::Replace || || m_choicePage->currentChoice() == ChoicePage::Alongside )
m_choicePage->currentChoice() == ChoicePage::Alongside ) {
return true; return true;
}
return false; return false;
} }
return true; return true;
@ -381,11 +393,10 @@ PartitionViewStep::onActivate()
} }
// if we're coming back to PVS from the next VS // if we're coming back to PVS from the next VS
if ( m_widget->currentWidget() == m_choicePage && if ( m_widget->currentWidget() == m_choicePage && m_choicePage->currentChoice() == ChoicePage::Alongside )
m_choicePage->currentChoice() == ChoicePage::Alongside )
{ {
m_choicePage->applyActionChoice( ChoicePage::Alongside ); m_choicePage->applyActionChoice( ChoicePage::Alongside );
// m_choicePage->reset(); // m_choicePage->reset();
//FIXME: ReplaceWidget should be reset maybe? //FIXME: ReplaceWidget should be reset maybe?
} }
} }
@ -404,8 +415,8 @@ PartitionViewStep::onLeave()
{ {
if ( PartUtils::isEfiSystem() ) if ( PartUtils::isEfiSystem() )
{ {
QString espMountPoint = Calamares::JobQueue::instance()->globalStorage()-> QString espMountPoint
value( "efiSystemPartition" ).toString(); = Calamares::JobQueue::instance()->globalStorage()->value( "efiSystemPartition" ).toString();
Partition* esp = m_core->findPartitionByMountPoint( espMountPoint ); Partition* esp = m_core->findPartitionByMountPoint( espMountPoint );
QString message; QString message;
@ -443,11 +454,32 @@ PartitionViewStep::onLeave()
if ( !message.isEmpty() ) if ( !message.isEmpty() )
{ {
cWarning() << message; cWarning() << message;
QMessageBox::warning( m_manualPartitionPage, QMessageBox::warning( m_manualPartitionPage, message, description );
message,
description );
} }
} }
else
{
cDebug() << "device: BIOS";
// TODO: this *always* warns, which might be annoying, so it'd be
// best to find a way to detect that bios_grub partition.
QString message = tr( "Option to use GPT on BIOS" );
QString description = tr( "A GPT partition table is the best option for all "
"systems. This installer supports such a setup for "
"BIOS systems too."
"<br/><br/>"
"To configure a GPT partition table on BIOS, "
"(if not done so already) go back "
"and set the partion table to GPT, next create a 8 MB "
"unformatted partition with the "
"<strong>bios_grub</strong> flag enabled.<br/><br/>"
"An unformatted 8 MB partition is necessary "
"to start %1 on a BIOS system with GPT." )
.arg( *Calamares::Branding::ShortProductName );
QMessageBox::information( m_manualPartitionPage, message, description );
}
Partition* root_p = m_core->findPartitionByMountPoint( "/" ); Partition* root_p = m_core->findPartitionByMountPoint( "/" );
Partition* boot_p = m_core->findPartitionByMountPoint( "/boot" ); Partition* boot_p = m_core->findPartitionByMountPoint( "/boot" );
@ -459,8 +491,7 @@ PartitionViewStep::onLeave()
// If the root partition is encrypted, and there's a separate boot // If the root partition is encrypted, and there's a separate boot
// partition which is not encrypted // partition which is not encrypted
if ( root_p->fileSystem().type() == FileSystem::Luks && if ( root_p->fileSystem().type() == FileSystem::Luks && boot_p->fileSystem().type() != FileSystem::Luks )
boot_p->fileSystem().type() != FileSystem::Luks )
{ {
message = tr( "Boot partition not encrypted" ); message = tr( "Boot partition not encrypted" );
description = tr( "A separate boot partition was set up together with " description = tr( "A separate boot partition was set up together with "
@ -476,9 +507,7 @@ PartitionViewStep::onLeave()
"recreate it, selecting <strong>Encrypt</strong> " "recreate it, selecting <strong>Encrypt</strong> "
"in the partition creation window." ); "in the partition creation window." );
QMessageBox::warning( m_manualPartitionPage, QMessageBox::warning( m_manualPartitionPage, message, description );
message,
description );
} }
} }
} }
@ -493,7 +522,9 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
QString efiSP = CalamaresUtils::getString( configurationMap, "efiSystemPartition" ); QString efiSP = CalamaresUtils::getString( configurationMap, "efiSystemPartition" );
if ( efiSP.isEmpty() ) if ( efiSP.isEmpty() )
{
efiSP = QStringLiteral( "/boot/efi" ); efiSP = QStringLiteral( "/boot/efi" );
}
gs->insert( "efiSystemPartition", efiSP ); gs->insert( "efiSystemPartition", efiSP );
// Set up firmwareType global storage entry. This is used, e.g. by the bootloader module. // Set up firmwareType global storage entry. This is used, e.g. by the bootloader module.
@ -511,16 +542,22 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
// //
// This is a bit convoluted because there's legacy settings to handle as well // This is a bit convoluted because there's legacy settings to handle as well
// as the new-style list of choices, with mapping back-and-forth. // as the new-style list of choices, with mapping back-and-forth.
if ( configurationMap.contains( "userSwapChoices" ) && if ( configurationMap.contains( "userSwapChoices" )
( configurationMap.contains( "ensureSuspendToDisk" ) || configurationMap.contains( "neverCreateSwap" ) ) ) && ( configurationMap.contains( "ensureSuspendToDisk" ) || configurationMap.contains( "neverCreateSwap" ) ) )
{
cError() << "Partition-module configuration mixes old- and new-style swap settings."; cError() << "Partition-module configuration mixes old- and new-style swap settings.";
}
if ( configurationMap.contains( "ensureSuspendToDisk" ) ) if ( configurationMap.contains( "ensureSuspendToDisk" ) )
{
cWarning() << "Partition-module setting *ensureSuspendToDisk* is deprecated."; cWarning() << "Partition-module setting *ensureSuspendToDisk* is deprecated.";
}
bool ensureSuspendToDisk = CalamaresUtils::getBool( configurationMap, "ensureSuspendToDisk", true ); bool ensureSuspendToDisk = CalamaresUtils::getBool( configurationMap, "ensureSuspendToDisk", true );
if ( configurationMap.contains( "neverCreateSwap" ) ) if ( configurationMap.contains( "neverCreateSwap" ) )
{
cWarning() << "Partition-module setting *neverCreateSwap* is deprecated."; cWarning() << "Partition-module setting *neverCreateSwap* is deprecated.";
}
bool neverCreateSwap = CalamaresUtils::getBool( configurationMap, "neverCreateSwap", false ); bool neverCreateSwap = CalamaresUtils::getBool( configurationMap, "neverCreateSwap", false );
QSet< PartitionActions::Choices::SwapChoice > choices; // Available swap choices QSet< PartitionActions::Choices::SwapChoice > choices; // Available swap choices
@ -535,8 +572,10 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
bool ok = false; bool ok = false;
auto v = PartitionActions::Choices::nameToChoice( item, ok ); auto v = PartitionActions::Choices::nameToChoice( item, ok );
if ( ok ) if ( ok )
{
choices.insert( v ); choices.insert( v );
} }
}
if ( choices.isEmpty() ) if ( choices.isEmpty() )
{ {
@ -553,19 +592,28 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
{ {
// Convert the legacy settings into a single setting for now. // Convert the legacy settings into a single setting for now.
if ( neverCreateSwap ) if ( neverCreateSwap )
{
choices.insert( PartitionActions::Choices::SwapChoice::NoSwap ); choices.insert( PartitionActions::Choices::SwapChoice::NoSwap );
}
else if ( ensureSuspendToDisk ) else if ( ensureSuspendToDisk )
{
choices.insert( PartitionActions::Choices::SwapChoice::FullSwap ); choices.insert( PartitionActions::Choices::SwapChoice::FullSwap );
}
else else
{
choices.insert( PartitionActions::Choices::SwapChoice::SmallSwap ); choices.insert( PartitionActions::Choices::SwapChoice::SmallSwap );
} }
}
// Not all are supported right now // FIXME // Not all are supported right now // FIXME
static const char unsupportedSetting[] = "Partition-module does not support *userSwapChoices* setting"; static const char unsupportedSetting[] = "Partition-module does not support *userSwapChoices* setting";
#define COMPLAIN_UNSUPPORTED(x) \ #define COMPLAIN_UNSUPPORTED( x ) \
if ( choices.contains( x ) ) \ if ( choices.contains( x ) ) \
{ cWarning() << unsupportedSetting << PartitionActions::Choices::choiceToName( x ); choices.remove( x ); } { \
cWarning() << unsupportedSetting << PartitionActions::Choices::choiceToName( x ); \
choices.remove( x ); \
}
COMPLAIN_UNSUPPORTED( PartitionActions::Choices::SwapChoice::SwapFile ) COMPLAIN_UNSUPPORTED( PartitionActions::Choices::SwapChoice::SwapFile )
COMPLAIN_UNSUPPORTED( PartitionActions::Choices::SwapChoice::ReuseSwap ) COMPLAIN_UNSUPPORTED( PartitionActions::Choices::SwapChoice::ReuseSwap )
@ -584,23 +632,35 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
// OTHER SETTINGS // OTHER SETTINGS
// //
gs->insert( "drawNestedPartitions", CalamaresUtils::getBool( configurationMap, "drawNestedPartitions", false ) ); gs->insert( "drawNestedPartitions", CalamaresUtils::getBool( configurationMap, "drawNestedPartitions", false ) );
gs->insert( "alwaysShowPartitionLabels", CalamaresUtils::getBool( configurationMap, "alwaysShowPartitionLabels", true ) ); gs->insert( "alwaysShowPartitionLabels",
gs->insert( "enableLuksAutomatedPartitioning", CalamaresUtils::getBool( configurationMap, "enableLuksAutomatedPartitioning", true ) ); CalamaresUtils::getBool( configurationMap, "alwaysShowPartitionLabels", true ) );
gs->insert( "allowManualPartitioning", CalamaresUtils::getBool( configurationMap, "allowManualPartitioning", true ) ); gs->insert( "enableLuksAutomatedPartitioning",
CalamaresUtils::getBool( configurationMap, "enableLuksAutomatedPartitioning", true ) );
gs->insert( "allowManualPartitioning",
CalamaresUtils::getBool( configurationMap, "allowManualPartitioning", true ) );
// The defaultFileSystemType setting needs a bit more processing, // The defaultFileSystemType setting needs a bit more processing,
// as we want to cover various cases (such as different cases) // as we want to cover various cases (such as different cases)
QString fsName = CalamaresUtils::getString( configurationMap, "defaultFileSystemType" ); QString fsName = CalamaresUtils::getString( configurationMap, "defaultFileSystemType" );
FileSystem::Type fsType; FileSystem::Type fsType;
if ( fsName.isEmpty() ) if ( fsName.isEmpty() )
{
cWarning() << "Partition-module setting *defaultFileSystemType* is missing, will use ext4"; cWarning() << "Partition-module setting *defaultFileSystemType* is missing, will use ext4";
}
QString fsRealName = PartUtils::findFS( fsName, &fsType ); QString fsRealName = PartUtils::findFS( fsName, &fsType );
if ( fsRealName == fsName ) if ( fsRealName == fsName )
{
cDebug() << "Partition-module setting *defaultFileSystemType*" << fsRealName; cDebug() << "Partition-module setting *defaultFileSystemType*" << fsRealName;
}
else if ( fsType != FileSystem::Unknown ) else if ( fsType != FileSystem::Unknown )
{
cWarning() << "Partition-module setting *defaultFileSystemType* changed" << fsRealName; cWarning() << "Partition-module setting *defaultFileSystemType* changed" << fsRealName;
}
else else
cWarning() << "Partition-module setting *defaultFileSystemType* is bad (" << fsName << ") using" << fsRealName << "instead."; {
cWarning() << "Partition-module setting *defaultFileSystemType* is bad (" << fsName << ") using" << fsRealName
<< "instead.";
}
gs->insert( "defaultFileSystemType", fsRealName ); gs->insert( "defaultFileSystemType", fsRealName );
@ -608,21 +668,18 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
// because it could take a while. Then when it's done, we can set up the widgets // because it could take a while. Then when it's done, we can set up the widgets
// and remove the spinner. // and remove the spinner.
m_future = new QFutureWatcher< void >(); m_future = new QFutureWatcher< void >();
connect( m_future, &QFutureWatcher< void >::finished, connect( m_future, &QFutureWatcher< void >::finished, this, [this] {
this, [ this ]
{
continueLoading(); continueLoading();
this->m_future->deleteLater(); this->m_future->deleteLater();
this->m_future = nullptr; this->m_future = nullptr;
} ); } );
QFuture< void > future = QFuture< void > future = QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule );
QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule );
m_future->setFuture( future ); m_future->setFuture( future );
if ( configurationMap.contains( "partitionLayout" ) ) if ( configurationMap.contains( "partitionLayout" ) )
{ {
m_core->initLayout( configurationMap.values( "partitionLayout" ).at(0).toList() ); m_core->initLayout( configurationMap.values( "partitionLayout" ).at( 0 ).toList() );
} }
else else
{ {
@ -641,14 +698,15 @@ Calamares::RequirementsList
PartitionViewStep::checkRequirements() PartitionViewStep::checkRequirements()
{ {
if ( m_future ) if ( m_future )
{
m_future->waitForFinished(); m_future->waitForFinished();
}
Calamares::RequirementsList l; Calamares::RequirementsList l;
l.append( l.append( {
{
QLatin1String( "partitions" ), QLatin1String( "partitions" ),
[]{ return tr( "has at least one disk device available." ); }, [] { return tr( "has at least one disk device available." ); },
[]{ return tr( "There are no partitions to install on." ); }, [] { return tr( "There are no partitions to install on." ); },
m_core->deviceModel()->rowCount() > 0, // satisfied m_core->deviceModel()->rowCount() > 0, // satisfied
#ifdef DEBUG_PARTITION_UNSAFE #ifdef DEBUG_PARTITION_UNSAFE
false // optional false // optional
@ -661,4 +719,4 @@ PartitionViewStep::checkRequirements()
} }
CALAMARES_PLUGIN_FACTORY_DEFINITION( PartitionViewStepFactory, registerPlugin<PartitionViewStep>(); ) CALAMARES_PLUGIN_FACTORY_DEFINITION( PartitionViewStepFactory, registerPlugin< PartitionViewStep >(); )

View File

@ -12,8 +12,6 @@ else()
add_definitions( -DWITHOUT_LIBPARTED ) add_definitions( -DWITHOUT_LIBPARTED )
endif() endif()
include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui )
set( CHECKER_SOURCES set( CHECKER_SOURCES
checker/CheckerContainer.cpp checker/CheckerContainer.cpp
checker/GeneralRequirements.cpp checker/GeneralRequirements.cpp

View File

@ -17,27 +17,27 @@
*/ */
#include "Config.h" #include "Config.h"
#include "utils/Logger.h"
#include "utils/Retranslator.h"
#include "Branding.h" #include "Branding.h"
#include "Settings.h" #include "Settings.h"
#include "utils/Logger.h"
#include <QApplication> #include "utils/Retranslator.h"
void void
RequirementsModel::setRequirementsList( const Calamares::RequirementsList& requirements ) RequirementsModel::setRequirementsList( const Calamares::RequirementsList& requirements )
{ {
CALAMARES_RETRANSLATE_SLOT( &RequirementsModel::retranslate )
emit beginResetModel(); emit beginResetModel();
m_requierements = requirements; m_requirements = requirements;
m_satisfiedRequirements = true;
auto isUnSatisfied = []( const Calamares::RequirementEntry& e ) { return !e.satisfied; }; auto isUnSatisfied = []( const Calamares::RequirementEntry& e ) { return !e.satisfied; };
auto isMandatoryAndUnSatisfied = []( const Calamares::RequirementEntry& e ) { return e.mandatory && !e.satisfied; }; auto isMandatoryAndUnSatisfied = []( const Calamares::RequirementEntry& e ) { return e.mandatory && !e.satisfied; };
m_satisfiedRequirements = std::none_of( m_requierements.begin(), m_requierements.end(), isUnSatisfied ); m_satisfiedRequirements = std::none_of( m_requirements.begin(), m_requirements.end(), isUnSatisfied );
m_satisfiedMandatory = std::none_of( m_requierements.begin(), m_requierements.end(), isMandatoryAndUnSatisfied ); m_satisfiedMandatory = std::none_of( m_requirements.begin(), m_requirements.end(), isMandatoryAndUnSatisfied );
emit satisfiedRequirementsChanged(m_satisfiedRequirements); emit satisfiedRequirementsChanged( m_satisfiedRequirements );
emit satisfiedMandatoryChanged(); emit satisfiedMandatoryChanged();
emit endResetModel(); emit endResetModel();
} }
@ -45,13 +45,13 @@ RequirementsModel::setRequirementsList( const Calamares::RequirementsList& requi
int int
RequirementsModel::rowCount( const QModelIndex& ) const RequirementsModel::rowCount( const QModelIndex& ) const
{ {
return m_requierements.count(); return m_requirements.count();
} }
QVariant QVariant
RequirementsModel::data( const QModelIndex& index, int role ) const RequirementsModel::data( const QModelIndex& index, int role ) const
{ {
const auto requirement = m_requierements.at( index.row() ); const auto requirement = m_requirements.at( index.row() );
switch ( role ) switch ( role )
{ {
@ -70,52 +70,37 @@ RequirementsModel::data( const QModelIndex& index, int role ) const
} }
} }
QHash<int, QByteArray> QHash< int, QByteArray >
RequirementsModel::roleNames() const RequirementsModel::roleNames() const
{ {
static QHash<int, QByteArray> roles; static QHash< int, QByteArray > roles;
roles[Roles::Name] = "name"; roles[ Roles::Name ] = "name";
roles[Roles::Details] = "details"; roles[ Roles::Details ] = "details";
roles[Roles::NegatedText] = "negatedText"; roles[ Roles::NegatedText ] = "negatedText";
roles[Roles::Satisfied] = "satisfied"; roles[ Roles::Satisfied ] = "satisfied";
roles[Roles::Mandatory] = "mandatory"; roles[ Roles::Mandatory ] = "mandatory";
return roles; return roles;
} }
Config::Config( QObject* parent ) : QObject( parent ) Config::Config( QObject* parent )
, m_requirementsModel( new RequirementsModel( this )) : QObject( parent )
, m_requirementsModel( new RequirementsModel( this ) )
, m_languages( CalamaresUtils::Locale::availableTranslations() ) , m_languages( CalamaresUtils::Locale::availableTranslations() )
{ {
connect(m_requirementsModel, &RequirementsModel::satisfiedRequirementsChanged, this, &Config::setIsNextEnabled); connect( m_requirementsModel, &RequirementsModel::satisfiedRequirementsChanged, this, &Config::setIsNextEnabled );
initLanguages(); initLanguages();
CALAMARES_RETRANSLATE_SLOT( &Config::retranslate ) CALAMARES_RETRANSLATE_SLOT( &Config::retranslate )
} }
void void
Config::retranslate() Config::retranslate()
{ {
QString message; m_genericWelcomeMessage = genericWelcomeMessage().arg( *Calamares::Branding::VersionedName );
if ( Calamares::Settings::instance()->isSetupMode() )
{
message = Calamares::Branding::instance()->welcomeStyleCalamares()
? tr( "<h1>Welcome to the Calamares setup program for %1.</h1>" )
: tr( "<h1>Welcome to %1 setup.</h1>" );
}
else
{
message = Calamares::Branding::instance()->welcomeStyleCalamares()
? tr( "<h1>Welcome to the Calamares installer for %1.</h1>" )
: tr( "<h1>Welcome to the %1 installer.</h1>" );
}
m_genericWelcomeMessage = message.arg( *Calamares::Branding::VersionedName );
emit genericWelcomeMessageChanged(); emit genericWelcomeMessageChanged();
// ui->supportButton->setText( tr( "%1 support" ).arg( *Calamares::Branding::ShortProductName ) ); m_requirementsModel->retranslate();
} }
CalamaresUtils::Locale::LabelModel* CalamaresUtils::Locale::LabelModel*
@ -168,7 +153,7 @@ Config::initLanguages()
QString name = m_languages->locale( matchedLocaleIndex ).name(); QString name = m_languages->locale( matchedLocaleIndex ).name();
cDebug() << Logger::SubEntry << "Matched with index" << matchedLocaleIndex << name; cDebug() << Logger::SubEntry << "Matched with index" << matchedLocaleIndex << name;
CalamaresUtils::installTranslator( name, Calamares::Branding::instance()->translationsDirectory(), qApp ); CalamaresUtils::installTranslator( name, Calamares::Branding::instance()->translationsDirectory() );
setLocaleIndex( matchedLocaleIndex ); setLocaleIndex( matchedLocaleIndex );
} }
else else
@ -181,22 +166,25 @@ void
Config::setCountryCode( const QString& countryCode ) Config::setCountryCode( const QString& countryCode )
{ {
m_countryCode = countryCode; m_countryCode = countryCode;
setLocaleIndex(CalamaresUtils::Locale::availableTranslations()->find( m_countryCode )); setLocaleIndex( CalamaresUtils::Locale::availableTranslations()->find( m_countryCode ) );
emit countryCodeChanged( m_countryCode ); emit countryCodeChanged( m_countryCode );
} }
void void
Config::setLanguageIcon(const QString &languageIcon ) Config::setLanguageIcon( const QString& languageIcon )
{ {
m_languageIcon = languageIcon; m_languageIcon = languageIcon;
} }
void void
Config::setLocaleIndex(const int& index) Config::setLocaleIndex( const int& index )
{ {
if(index == m_localeIndex || index > CalamaresUtils::Locale::availableTranslations()->rowCount(QModelIndex()) || index < 0) if ( index == m_localeIndex || index > CalamaresUtils::Locale::availableTranslations()->rowCount( QModelIndex() )
|| index < 0 )
{
return; return;
}
m_localeIndex = index; m_localeIndex = index;
@ -204,8 +192,7 @@ Config::setLocaleIndex(const int& index)
cDebug() << "Selected locale" << selectedLocale; cDebug() << "Selected locale" << selectedLocale;
QLocale::setDefault( selectedLocale ); QLocale::setDefault( selectedLocale );
CalamaresUtils::installTranslator( CalamaresUtils::installTranslator( selectedLocale, Calamares::Branding::instance()->translationsDirectory() );
selectedLocale, Calamares::Branding::instance()->translationsDirectory(), qApp );
emit localeIndexChanged( m_localeIndex ); emit localeIndexChanged( m_localeIndex );
} }
@ -223,51 +210,118 @@ Config::setIsNextEnabled( const bool& isNextEnabled )
emit isNextEnabledChanged( m_isNextEnabled ); emit isNextEnabledChanged( m_isNextEnabled );
} }
QString Config::donateUrl() const QString
Config::donateUrl() const
{ {
return m_donateUrl; return m_donateUrl;
} }
void Config::setDonateUrl(const QString& url) void
Config::setDonateUrl( const QString& url )
{ {
m_donateUrl = url; m_donateUrl = url;
emit donateUrlChanged();
} }
QString Config::knownIssuesUrl() const QString
Config::knownIssuesUrl() const
{ {
return m_knownIssuesUrl; return m_knownIssuesUrl;
} }
void Config::setKnownIssuesUrl(const QString& url) void
Config::setKnownIssuesUrl( const QString& url )
{ {
m_knownIssuesUrl = url; m_knownIssuesUrl = url;
emit knownIssuesUrlChanged();
} }
void Config::setReleaseNotesUrl(const QString& url) void
Config::setReleaseNotesUrl( const QString& url )
{ {
m_releaseNotesUrl = url; m_releaseNotesUrl = url;
emit releaseNotesUrlChanged();
} }
QString Config::releaseNotesUrl() const QString
Config::releaseNotesUrl() const
{ {
return m_releaseNotesUrl; return m_releaseNotesUrl;
} }
QString Config::supportUrl() const QString
Config::supportUrl() const
{ {
return m_supportUrl; return m_supportUrl;
} }
void Config::setSupportUrl(const QString& url) void
Config::setSupportUrl( const QString& url )
{ {
m_supportUrl = url; m_supportUrl = url;
emit supportUrlChanged();
} }
void
RequirementsModel::retranslate()
{
if ( !m_satisfiedRequirements )
{
QString message;
const bool setup = Calamares::Settings::instance()->isSetupMode();
if ( !m_satisfiedMandatory )
{
message = setup ? tr( "This computer does not satisfy the minimum "
"requirements for setting up %1.<br/>"
"Setup cannot continue. "
"<a href=\"#details\">Details...</a>" )
: tr( "This computer does not satisfy the minimum "
"requirements for installing %1.<br/>"
"Installation cannot continue. "
"<a href=\"#details\">Details...</a>" );
}
else
{
message = setup ? tr( "This computer does not satisfy some of the "
"recommended requirements for setting up %1.<br/>"
"Setup can continue, but some features "
"might be disabled." )
: tr( "This computer does not satisfy some of the "
"recommended requirements for installing %1.<br/>"
"Installation can continue, but some features "
"might be disabled." );
}
m_warningMessage = message.arg( *Calamares::Branding::ShortVersionedName );
}
else
{
m_warningMessage = tr( "This program will ask you some questions and "
"set up %2 on your computer." )
.arg( *Calamares::Branding::ProductName );
}
emit warningMessageChanged();
}
QString
Config::genericWelcomeMessage()
{
QString message;
if ( Calamares::Settings::instance()->isSetupMode() )
{
message = Calamares::Branding::instance()->welcomeStyleCalamares()
? tr( "<h1>Welcome to the Calamares setup program for %1.</h1>" )
: tr( "<h1>Welcome to %1 setup.</h1>" );
}
else
{
message = Calamares::Branding::instance()->welcomeStyleCalamares()
? tr( "<h1>Welcome to the Calamares installer for %1.</h1>" )
: tr( "<h1>Welcome to the %1 installer.</h1>" );
}
return message;
}

View File

@ -19,21 +19,23 @@
#ifndef WELCOME_CONFIG_H #ifndef WELCOME_CONFIG_H
#define WELCOME_CONFIG_H #define WELCOME_CONFIG_H
#include <QObject>
#include <QUrl>
#include "modulesystem/Requirement.h" #include "modulesystem/Requirement.h"
#include "locale/LabelModel.h" #include "locale/LabelModel.h"
#include <QObject>
#include <QUrl>
// TODO: move this (and modulesystem/Requirement) to libcalamares
class RequirementsModel : public QAbstractListModel class RequirementsModel : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
using QAbstractListModel::QAbstractListModel; Q_PROPERTY( bool satisfiedRequirements READ satisfiedRequirements NOTIFY satisfiedRequirementsChanged FINAL )
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 )
Q_PROPERTY(bool satisfiedMandatory READ satisfiedMandatory NOTIFY satisfiedMandatoryChanged FINAL)
public: public:
using QAbstractListModel::QAbstractListModel;
enum Roles : short enum Roles : short
{ {
Name, Name,
@ -44,90 +46,92 @@ public:
HasDetails HasDetails
}; };
bool satisfiedRequirements() const bool satisfiedRequirements() const { return m_satisfiedRequirements; }
bool satisfiedMandatory() const { return m_satisfiedMandatory; }
const Calamares::RequirementEntry& getEntry( const int& index ) const
{ {
return m_satisfiedRequirements; if ( index > count() || index < 0 )
{
return *( new Calamares::RequirementEntry() );
} }
bool satisfiedMandatory() const return m_requirements.at( index );
{
return m_satisfiedMandatory;
}
const Calamares::RequirementEntry& getEntry(const int& index) const
{
if(index > count() || index < 0)
return *(new Calamares::RequirementEntry());
return m_requierements.at(index);
} }
void setRequirementsList( const Calamares::RequirementsList& requirements ); void setRequirementsList( const Calamares::RequirementsList& requirements );
int rowCount(const QModelIndex&) const override; int rowCount( const QModelIndex& ) const override;
int count() const int count() const { return m_requirements.count(); }
{
return m_requierements.count();
}
QVariant data(const QModelIndex& index, int role) const override; QString warningMessage() const { return m_warningMessage; }
void retranslate();
QVariant data( const QModelIndex& index, int role ) const override;
protected: protected:
QHash<int, QByteArray> roleNames() const override; QHash< int, QByteArray > roleNames() const override;
private: private:
Calamares::RequirementsList m_requierements; Calamares::RequirementsList m_requirements;
bool m_satisfiedRequirements = false; bool m_satisfiedRequirements = false;
bool m_satisfiedMandatory = false; bool m_satisfiedMandatory = false;
QString m_warningMessage;
signals: signals:
void satisfiedRequirementsChanged(bool value); void satisfiedRequirementsChanged( bool value );
void satisfiedMandatoryChanged(); void satisfiedMandatoryChanged();
void warningMessageChanged();
}; };
class Config : public QObject class Config : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY( CalamaresUtils::Locale::LabelModel* languagesModel READ languagesModel CONSTANT FINAL) Q_PROPERTY( CalamaresUtils::Locale::LabelModel* languagesModel READ languagesModel CONSTANT FINAL )
Q_PROPERTY( RequirementsModel* requirementsModel MEMBER m_requirementsModel CONSTANT FINAL ) Q_PROPERTY( RequirementsModel* requirementsModel MEMBER m_requirementsModel CONSTANT FINAL )
Q_PROPERTY( QString languageIcon READ languageIcon CONSTANT FINAL ) Q_PROPERTY( QString languageIcon READ languageIcon CONSTANT FINAL )
Q_PROPERTY( QString countryCode MEMBER m_countryCode NOTIFY countryCodeChanged FINAL ) Q_PROPERTY( QString countryCode MEMBER m_countryCode NOTIFY countryCodeChanged FINAL )
Q_PROPERTY (int localeIndex READ localeIndex WRITE setLocaleIndex NOTIFY localeIndexChanged) Q_PROPERTY( int localeIndex READ localeIndex WRITE setLocaleIndex NOTIFY localeIndexChanged )
Q_PROPERTY( QString genericWelcomeMessage MEMBER m_genericWelcomeMessage NOTIFY genericWelcomeMessageChanged FINAL ) Q_PROPERTY( QString genericWelcomeMessage MEMBER m_genericWelcomeMessage NOTIFY genericWelcomeMessageChanged FINAL )
Q_PROPERTY( QString warningMessage MEMBER m_warningMessage CONSTANT FINAL )
Q_PROPERTY(QString supportUrl MEMBER m_supportUrl CONSTANT FINAL) Q_PROPERTY( QString supportUrl MEMBER m_supportUrl NOTIFY supportUrlChanged FINAL )
Q_PROPERTY(QString knownIssuesUrl MEMBER m_knownIssuesUrl CONSTANT FINAL) Q_PROPERTY( QString knownIssuesUrl MEMBER m_knownIssuesUrl NOTIFY knownIssuesUrlChanged FINAL )
Q_PROPERTY(QString releaseNotesUrl MEMBER m_releaseNotesUrl CONSTANT FINAL) Q_PROPERTY( QString releaseNotesUrl MEMBER m_releaseNotesUrl NOTIFY releaseNotesUrlChanged FINAL )
Q_PROPERTY(QString donateUrl MEMBER m_donateUrl CONSTANT FINAL) Q_PROPERTY( QString donateUrl MEMBER m_donateUrl NOTIFY donateUrlChanged FINAL )
Q_PROPERTY( bool isNextEnabled MEMBER m_isNextEnabled NOTIFY isNextEnabledChanged FINAL )
public: public:
Config( QObject* parent = nullptr ); Config( QObject* parent = nullptr );
void setCountryCode( const QString &countryCode ); void setCountryCode( const QString& countryCode );
void setLanguageIcon( const QString &languageIcon ); void setLanguageIcon( const QString& languageIcon );
RequirementsModel& requirementsModel () const; RequirementsModel& requirementsModel() const;
void setIsNextEnabled( const bool& isNextEnabled ); void setIsNextEnabled( const bool& isNextEnabled );
void setLocaleIndex(const int &index); void setLocaleIndex( const int& index );
int localeIndex() const { return m_localeIndex; } int localeIndex() const { return m_localeIndex; }
QString supportUrl() const; QString supportUrl() const;
void setSupportUrl(const QString &url); void setSupportUrl( const QString& url );
QString knownIssuesUrl() const; QString knownIssuesUrl() const;
void setKnownIssuesUrl(const QString &url); void setKnownIssuesUrl( const QString& url );
QString releaseNotesUrl() const; QString releaseNotesUrl() const;
void setReleaseNotesUrl(const QString &url); void setReleaseNotesUrl( const QString& url );
QString donateUrl() const; QString donateUrl() const;
void setDonateUrl(const QString &url); void setDonateUrl( const QString& url );
QString genericWelcomeMessage();
public slots: public slots:
CalamaresUtils::Locale::LabelModel* languagesModel() const; CalamaresUtils::Locale::LabelModel* languagesModel() const;
@ -144,9 +148,7 @@ private:
bool m_isNextEnabled = false; bool m_isNextEnabled = false;
CalamaresUtils::Locale::LabelModel* m_languages; CalamaresUtils::Locale::LabelModel* m_languages;
QString m_genericWelcomeMessage = tr("This program will ask you some questions and set up your installation"); QString m_genericWelcomeMessage;
QString m_warningMessage = tr("This program does not satisfy the minimum requirements for installing.\nInstallation can not continue");
QString m_supportUrl; QString m_supportUrl;
QString m_knownIssuesUrl; QString m_knownIssuesUrl;
@ -158,6 +160,10 @@ signals:
void localeIndexChanged( int localeIndex ); void localeIndexChanged( int localeIndex );
void isNextEnabledChanged( bool isNextEnabled ); void isNextEnabledChanged( bool isNextEnabled );
void genericWelcomeMessageChanged(); void genericWelcomeMessageChanged();
void supportUrlChanged();
void knownIssuesUrlChanged();
void releaseNotesUrlChanged();
void donateUrlChanged();
}; };
#endif #endif

View File

@ -25,9 +25,9 @@
#include "Branding.h" #include "Branding.h"
#include "CalamaresVersion.h" #include "CalamaresVersion.h"
#include "Config.h"
#include "Settings.h" #include "Settings.h"
#include "ViewManager.h" #include "ViewManager.h"
#include "Config.h"
#include "locale/LabelModel.h" #include "locale/LabelModel.h"
#include "modulesystem/ModuleManager.h" #include "modulesystem/ModuleManager.h"
@ -44,7 +44,7 @@
#include <QLabel> #include <QLabel>
#include <QMessageBox> #include <QMessageBox>
WelcomePage::WelcomePage( Config *conf, QWidget* parent ) WelcomePage::WelcomePage( Config* conf, QWidget* parent )
: QWidget( parent ) : QWidget( parent )
, ui( new Ui::WelcomePage ) , ui( new Ui::WelcomePage )
, m_checkingWidget( new CheckerContainer( conf->requirementsModel(), this ) ) , m_checkingWidget( new CheckerContainer( conf->requirementsModel(), this ) )
@ -84,13 +84,14 @@ WelcomePage::WelcomePage( Config *conf, QWidget* parent )
ui->verticalLayout->insertWidget( welcome_text_idx + 1, m_checkingWidget ); ui->verticalLayout->insertWidget( welcome_text_idx + 1, m_checkingWidget );
} }
void WelcomePage::init() void
WelcomePage::init()
{ {
//setup the url buttons //setup the url buttons
setupButton( WelcomePage::Button::Support, m_conf->supportUrl()); setupButton( WelcomePage::Button::Support, m_conf->supportUrl() );
setupButton( WelcomePage::Button::KnownIssues, m_conf->knownIssuesUrl() ); setupButton( WelcomePage::Button::KnownIssues, m_conf->knownIssuesUrl() );
setupButton( WelcomePage::Button::ReleaseNotes, m_conf->releaseNotesUrl() ); setupButton( WelcomePage::Button::ReleaseNotes, m_conf->releaseNotesUrl() );
setupButton( WelcomePage::Button::Donate, m_conf->donateUrl()); setupButton( WelcomePage::Button::Donate, m_conf->donateUrl() );
//language icon //language icon
auto icon = Calamares::Branding::instance()->image( m_conf->languageIcon(), QSize( 48, 48 ) ); auto icon = Calamares::Branding::instance()->image( m_conf->languageIcon(), QSize( 48, 48 ) );
@ -113,7 +114,9 @@ WelcomePage::initLanguages()
ui->languageWidget->setCurrentIndex( m_conf->localeIndex() ); ui->languageWidget->setCurrentIndex( m_conf->localeIndex() );
connect( ui->languageWidget, connect( ui->languageWidget,
static_cast< void ( QComboBox::* )( int ) >( &QComboBox::currentIndexChanged ), m_conf, &Config::setLocaleIndex ); static_cast< void ( QComboBox::* )( int ) >( &QComboBox::currentIndexChanged ),
m_conf,
&Config::setLocaleIndex );
} }
void void
@ -232,7 +235,7 @@ WelcomePage::showAboutBox()
"<strong>%2<br/>" "<strong>%2<br/>"
"for %3</strong><br/><br/>" "for %3</strong><br/><br/>"
"Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>" "Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>"
"Copyright 2017-2019 Adriaan de Groot &lt;groot@kde.org&gt;<br/>" "Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>"
"Thanks to <a href=\"https://calamares.io/team/\">the Calamares team</a> " "Thanks to <a href=\"https://calamares.io/team/\">the Calamares team</a> "
"and the <a href=\"https://www.transifex.com/calamares/calamares/\">Calamares " "and the <a href=\"https://www.transifex.com/calamares/calamares/\">Calamares "
"translators team</a>.<br/><br/>" "translators team</a>.<br/><br/>"

View File

@ -36,7 +36,7 @@ class WelcomePage : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit WelcomePage( Config *conf, QWidget* parent = nullptr ); explicit WelcomePage( Config* conf, QWidget* parent = nullptr );
enum class Button enum class Button
{ {
@ -75,7 +75,7 @@ private:
CheckerContainer* m_checkingWidget; CheckerContainer* m_checkingWidget;
CalamaresUtils::Locale::LabelModel* m_languages; CalamaresUtils::Locale::LabelModel* m_languages;
Config *m_conf; Config* m_conf;
}; };
/** @brief Delegate to display language information in two columns. /** @brief Delegate to display language information in two columns.

View File

@ -18,19 +18,18 @@
*/ */
#include "WelcomeViewStep.h" #include "WelcomeViewStep.h"
#include "Config.h"
#include "Config.h"
#include "WelcomePage.h" #include "WelcomePage.h"
#include "checker/GeneralRequirements.h" #include "checker/GeneralRequirements.h"
#include "Branding.h"
#include "geoip/Handler.h" #include "geoip/Handler.h"
#include "locale/Lookup.h" #include "locale/Lookup.h"
#include "modulesystem/ModuleManager.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/Variant.h" #include "utils/Variant.h"
#include "Branding.h"
#include "modulesystem/ModuleManager.h"
#include <QFutureWatcher> #include <QFutureWatcher>
#include <QVariant> #include <QVariant>
@ -39,7 +38,7 @@ CALAMARES_PLUGIN_FACTORY_DEFINITION( WelcomeViewStepFactory, registerPlugin< Wel
WelcomeViewStep::WelcomeViewStep( QObject* parent ) WelcomeViewStep::WelcomeViewStep( QObject* parent )
: Calamares::ViewStep( parent ) : Calamares::ViewStep( parent )
, m_requirementsChecker( new GeneralRequirements( this ) ) , m_requirementsChecker( new GeneralRequirements( this ) )
, m_conf( new Config(this) ) , m_conf( new Config( this ) )
{ {
connect( Calamares::ModuleManager::instance(), connect( Calamares::ModuleManager::instance(),
&Calamares::ModuleManager::requirementsComplete, &Calamares::ModuleManager::requirementsComplete,
@ -47,7 +46,7 @@ WelcomeViewStep::WelcomeViewStep( QObject* parent )
&WelcomeViewStep::nextStatusChanged ); &WelcomeViewStep::nextStatusChanged );
// the instance of the qqc2 or qwidgets page // the instance of the qqc2 or qwidgets page
m_widget = new WelcomePage(m_conf); m_widget = new WelcomePage( m_conf );
} }
WelcomeViewStep::~WelcomeViewStep() WelcomeViewStep::~WelcomeViewStep()
@ -145,8 +144,10 @@ WelcomeViewStep::setConfigurationMap( const QVariantMap& configurationMap )
using Calamares::Branding; using Calamares::Branding;
m_conf->setSupportUrl( jobOrBrandingSetting( Branding::SupportUrl, configurationMap, "showSupportUrl" ) ); m_conf->setSupportUrl( jobOrBrandingSetting( Branding::SupportUrl, configurationMap, "showSupportUrl" ) );
m_conf->setKnownIssuesUrl( jobOrBrandingSetting( Branding::KnownIssuesUrl, configurationMap, "showKnownIssuesUrl" ) ); m_conf->setKnownIssuesUrl(
m_conf->setReleaseNotesUrl( jobOrBrandingSetting( Branding::ReleaseNotesUrl, configurationMap, "showReleaseNotesUrl" ) ); jobOrBrandingSetting( Branding::KnownIssuesUrl, configurationMap, "showKnownIssuesUrl" ) );
m_conf->setReleaseNotesUrl(
jobOrBrandingSetting( Branding::ReleaseNotesUrl, configurationMap, "showReleaseNotesUrl" ) );
m_conf->setDonateUrl( CalamaresUtils::getString( configurationMap, "showDonateUrl" ) ); m_conf->setDonateUrl( CalamaresUtils::getString( configurationMap, "showDonateUrl" ) );
if ( configurationMap.contains( "requirements" ) if ( configurationMap.contains( "requirements" )

View File

@ -16,22 +16,22 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef WELCOMEPAGEPLUGIN_H #ifndef WELCOMEVIEWSTEP_H
#define WELCOMEPAGEPLUGIN_H #define WELCOMEVIEWSTEP_H
#include "DllMacro.h"
#include "modulesystem/Requirement.h"
#include "utils/PluginFactory.h"
#include "viewpages/ViewStep.h"
#include <QObject> #include <QObject>
#include <modulesystem/Requirement.h>
#include <utils/PluginFactory.h>
#include <viewpages/ViewStep.h>
#include <DllMacro.h>
#include <QVariantMap> #include <QVariantMap>
class WelcomePage; class WelcomePage;
class GeneralRequirements; class GeneralRequirements;
class Config; class Config;
namespace CalamaresUtils namespace CalamaresUtils
{ {
namespace GeoIP namespace GeoIP
@ -75,9 +75,9 @@ public:
private: private:
WelcomePage* m_widget; WelcomePage* m_widget;
GeneralRequirements* m_requirementsChecker; GeneralRequirements* m_requirementsChecker;
Config *m_conf; Config* m_conf;
}; };
CALAMARES_PLUGIN_FACTORY_DECLARATION( WelcomeViewStepFactory ) CALAMARES_PLUGIN_FACTORY_DECLARATION( WelcomeViewStepFactory )
#endif // WELCOMEPAGEPLUGIN_H #endif // WELCOMEVIEWSTEP_H

View File

@ -288,4 +288,6 @@ ResultsListWidget::retranslate()
} }
} }
#include "utils/moc-warnings.h"
#include "ResultsListWidget.moc" #include "ResultsListWidget.moc"

View File

@ -41,7 +41,7 @@ CALAMARES_PLUGIN_FACTORY_DEFINITION( WelcomeQmlViewStepFactory, registerPlugin<
WelcomeQmlViewStep::WelcomeQmlViewStep( QObject* parent ) WelcomeQmlViewStep::WelcomeQmlViewStep( QObject* parent )
: Calamares::QmlViewStep(parent ) : Calamares::QmlViewStep(parent )
, m_config( new Config( ) ) // the qml singleton takes ownership and deletes it , m_config( new Config( this ) ) // the qml singleton takes ownership and deletes it
// , m_nextEnabled( false ) // , m_nextEnabled( false )
, m_requirementsChecker( new GeneralRequirements( this ) ) , m_requirementsChecker( new GeneralRequirements( this ) )
@ -98,10 +98,46 @@ WelcomeQmlViewStep::jobs() const
return Calamares::JobList(); return Calamares::JobList();
} }
/** @brief Look up a URL for a button
*
* Looks up @p key in @p map; if it is a *boolean* value, then
* assume an old-style configuration, and fetch the string from
* the branding settings @p e. If it is a string, not a boolean,
* use it as-is. If not found, or a weird type, returns empty.
*
* This allows switching the showKnownIssuesUrl and similar settings
* in welcome.conf from a boolean (deferring to branding) to an
* actual string for immediate use. Empty strings, as well as
* "false" as a setting, will hide the buttons as before.
*/
static QString
jobOrBrandingSetting( Calamares::Branding::StringEntry e, const QVariantMap& map, const QString& key )
{
if ( !map.contains( key ) )
{
return QString();
}
auto v = map.value( key );
if ( v.type() == QVariant::Bool )
{
return v.toBool() ? ( *e ) : QString();
}
if ( v.type() == QVariant::String )
{
return v.toString();
}
return QString();
}
void void
WelcomeQmlViewStep::setConfigurationMap( const QVariantMap& configurationMap ) WelcomeQmlViewStep::setConfigurationMap( const QVariantMap& configurationMap )
{ {
using Calamares::Branding; using Calamares::Branding;
m_config->setSupportUrl( jobOrBrandingSetting( Branding::SupportUrl, configurationMap, "showSupportUrl" ) );
m_config->setKnownIssuesUrl( jobOrBrandingSetting( Branding::KnownIssuesUrl, configurationMap, "showKnownIssuesUrl" ) );
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 accesed withouth having to declare a property, get and setter for each