Merge branch 'issue-1391' into calamares
This commit is contained in:
commit
a3e528aae3
@ -1,5 +1,5 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
|
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
|
||||||
* SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot <groot@kde.org>
|
* SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot <groot@kde.org>
|
||||||
*
|
*
|
||||||
@ -36,8 +36,8 @@ using CalamaresUtils::operator""_MiB;
|
|||||||
namespace Calamares
|
namespace Calamares
|
||||||
{
|
{
|
||||||
|
|
||||||
GlobalStorage::GlobalStorage()
|
GlobalStorage::GlobalStorage( QObject* parent )
|
||||||
: QObject( nullptr )
|
: QObject( parent )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
|
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
|
||||||
* SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot <groot@kde.org>
|
* SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot <groot@kde.org>
|
||||||
*
|
*
|
||||||
@ -39,7 +39,7 @@ class GlobalStorage : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit GlobalStorage();
|
explicit GlobalStorage( QObject* parent = nullptr );
|
||||||
|
|
||||||
//NOTE: thread safety is guaranteed by JobQueue, which executes jobs one by one.
|
//NOTE: thread safety is guaranteed by JobQueue, which executes jobs one by one.
|
||||||
// If at any time jobs become concurrent, this class must be made thread-safe.
|
// If at any time jobs become concurrent, this class must be made thread-safe.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
|
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
|
||||||
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
|
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
|
||||||
*
|
*
|
||||||
@ -170,7 +170,7 @@ JobQueue::globalStorage() const
|
|||||||
JobQueue::JobQueue( QObject* parent )
|
JobQueue::JobQueue( QObject* parent )
|
||||||
: QObject( parent )
|
: QObject( parent )
|
||||||
, m_thread( new JobThread( this ) )
|
, m_thread( new JobThread( this ) )
|
||||||
, m_storage( new GlobalStorage() )
|
, m_storage( new GlobalStorage( this ) )
|
||||||
{
|
{
|
||||||
Q_ASSERT( !s_instance );
|
Q_ASSERT( !s_instance );
|
||||||
s_instance = this;
|
s_instance = this;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
*
|
*
|
||||||
* Calamares is free software: you can redistribute it and/or modify
|
* Calamares is free software: you can redistribute it and/or modify
|
||||||
@ -168,7 +168,11 @@ Manager::checkHasInternet()
|
|||||||
{
|
{
|
||||||
hasInternet = synchronousPing( d->m_hasInternetUrl );
|
hasInternet = synchronousPing( d->m_hasInternetUrl );
|
||||||
}
|
}
|
||||||
d->m_hasInternet = hasInternet;
|
if ( hasInternet != d->m_hasInternet )
|
||||||
|
{
|
||||||
|
d->m_hasInternet = hasInternet;
|
||||||
|
emit hasInternetChanged( hasInternet );
|
||||||
|
}
|
||||||
return hasInternet;
|
return hasInternet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
*
|
*
|
||||||
* Calamares is free software: you can redistribute it and/or modify
|
* Calamares is free software: you can redistribute it and/or modify
|
||||||
@ -98,9 +98,10 @@ struct RequestStatus
|
|||||||
|
|
||||||
QDebug& operator<<( QDebug& s, const RequestStatus& e );
|
QDebug& operator<<( QDebug& s, const RequestStatus& e );
|
||||||
|
|
||||||
class DLLEXPORT Manager : QObject
|
class DLLEXPORT Manager : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY( bool hasInternet READ hasInternet NOTIFY hasInternetChanged FINAL )
|
||||||
|
|
||||||
Manager();
|
Manager();
|
||||||
|
|
||||||
@ -133,6 +134,16 @@ public:
|
|||||||
|
|
||||||
/// @brief Set the URL which is used for the general "is there internet" check.
|
/// @brief Set the URL which is used for the general "is there internet" check.
|
||||||
void setCheckHasInternetUrl( const QUrl& url );
|
void setCheckHasInternetUrl( const QUrl& url );
|
||||||
|
|
||||||
|
/** @brief Do a network request asynchronously.
|
||||||
|
*
|
||||||
|
* Returns a pointer to the reply-from-the-request.
|
||||||
|
* This may be a nullptr if an error occurs immediately.
|
||||||
|
* The caller is responsible for cleaning up the reply (eventually).
|
||||||
|
*/
|
||||||
|
QNetworkReply* asynchronousGet( const QUrl& url, const RequestOptions& options = RequestOptions() );
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
/** @brief Do an explicit check for internet connectivity.
|
/** @brief Do an explicit check for internet connectivity.
|
||||||
*
|
*
|
||||||
* This **may** do a ping to the configured check URL, but can also
|
* This **may** do a ping to the configured check URL, but can also
|
||||||
@ -148,13 +159,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool hasInternet();
|
bool hasInternet();
|
||||||
|
|
||||||
/** @brief Do a network request asynchronously.
|
signals:
|
||||||
|
/** @brief Indicates that internet connectivity status has changed
|
||||||
*
|
*
|
||||||
* Returns a pointer to the reply-from-the-request.
|
* The value is that returned from hasInternet() -- @c true when there
|
||||||
* This may be a nullptr if an error occurs immediately.
|
* is connectivity, @c false otherwise.
|
||||||
* The caller is responsible for cleaning up the reply (eventually).
|
|
||||||
*/
|
*/
|
||||||
QNetworkReply* asynchronousGet( const QUrl& url, const RequestOptions& options = RequestOptions() );
|
void hasInternetChanged( bool );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Private;
|
class Private;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
*
|
*
|
||||||
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||||
*
|
*
|
||||||
* Calamares is free software: you can redistribute it and/or modify
|
* Calamares is free software: you can redistribute it and/or modify
|
||||||
@ -24,6 +24,7 @@
|
|||||||
#define UTILS_RAII_H
|
#define UTILS_RAII_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QSignalBlocker>
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
@ -44,4 +45,21 @@ struct cqDeleter
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @brief Sets a bool to @p value and resets to !value on destruction
|
||||||
|
template < bool value >
|
||||||
|
struct cBoolSetter
|
||||||
|
{
|
||||||
|
bool& m_b;
|
||||||
|
|
||||||
|
cBoolSetter( bool& b )
|
||||||
|
: m_b( b )
|
||||||
|
{
|
||||||
|
m_b = value;
|
||||||
|
}
|
||||||
|
~cBoolSetter() { m_b = !value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Blocks signals on a QObject until destruction
|
||||||
|
using cSignalBlocker = QSignalBlocker;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -103,10 +103,36 @@ public:
|
|||||||
RequirementsModel* requirementsModel() { return m_requirementsModel; }
|
RequirementsModel* requirementsModel() { return m_requirementsModel; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
/** @brief Emitted when all the module **configuration** has been read
|
||||||
|
*
|
||||||
|
* This indicates that all of the module.desc files have been
|
||||||
|
* loaded; bad ones are silently skipped, so this just indicates
|
||||||
|
* that the module manager is ready for the next phase (loading).
|
||||||
|
*/
|
||||||
void initDone();
|
void initDone();
|
||||||
void modulesLoaded(); /// All of the modules were loaded successfully
|
/** @brief Emitted when all the modules are loaded successfully
|
||||||
void modulesFailed( QStringList ); /// .. or not
|
*
|
||||||
// Below, see RequirementsChecker documentation
|
* Each module listed in the settings is loaded. Modules are loaded
|
||||||
|
* only once, even when instantiated multiple times. If all of
|
||||||
|
* the listed modules are successfully loaded, this signal is
|
||||||
|
* emitted (otherwise, it isn't, so you need to wait for **both**
|
||||||
|
* of the signals).
|
||||||
|
*
|
||||||
|
* If this is emitted (i.e. all modules have loaded) then the next
|
||||||
|
* phase, requirements checking, can be started.
|
||||||
|
*/
|
||||||
|
void modulesLoaded();
|
||||||
|
/** @brief Emitted if any modules failed to load
|
||||||
|
*
|
||||||
|
* Modules that failed to load (for any reason) are listed by
|
||||||
|
* instance key (e.g. "welcome@welcome", "shellprocess@mycustomthing").
|
||||||
|
*/
|
||||||
|
void modulesFailed( QStringList );
|
||||||
|
/** @brief Emitted after all requirements have been checked
|
||||||
|
*
|
||||||
|
* The bool value indicates if all of the **mandatory** requirements
|
||||||
|
* are satisfied (e.g. whether installation can continue).
|
||||||
|
*/
|
||||||
void requirementsComplete( bool );
|
void requirementsComplete( bool );
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "JobQueue.h"
|
#include "JobQueue.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "ViewManager.h"
|
#include "ViewManager.h"
|
||||||
|
#include "network/Manager.h"
|
||||||
#include "utils/Dirs.h"
|
#include "utils/Dirs.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
@ -242,6 +243,10 @@ registerQmlModels()
|
|||||||
"io.calamares.core", 1, 0, "Global", []( QQmlEngine*, QJSEngine* ) -> QObject* {
|
"io.calamares.core", 1, 0, "Global", []( QQmlEngine*, QJSEngine* ) -> QObject* {
|
||||||
return Calamares::JobQueue::instance()->globalStorage();
|
return Calamares::JobQueue::instance()->globalStorage();
|
||||||
} );
|
} );
|
||||||
|
qmlRegisterSingletonType< CalamaresUtils::Network::Manager >(
|
||||||
|
"io.calamares.core", 1, 0, "Network", []( QQmlEngine*, QJSEngine* ) -> QObject* {
|
||||||
|
return &CalamaresUtils::Network::Manager::instance();
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
*
|
*
|
||||||
* Copyright 2019-2020, Adriaan de Groot <groot@kde.org>
|
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||||
* Copyright 2020, Camilo Higuita <milo.h@aol.com>
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
* License-Filename: LICENSE
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -19,85 +20,43 @@
|
|||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#include "LCLocaleDialog.h"
|
|
||||||
#include "SetTimezoneJob.h"
|
#include "SetTimezoneJob.h"
|
||||||
#include "timezonewidget/timezonewidget.h"
|
|
||||||
|
|
||||||
#include "GlobalStorage.h"
|
#include "GlobalStorage.h"
|
||||||
#include "JobQueue.h"
|
#include "JobQueue.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
|
||||||
#include "locale/Label.h"
|
#include "locale/Label.h"
|
||||||
#include "locale/TimeZone.h"
|
#include "modulesystem/ModuleManager.h"
|
||||||
#include "utils/CalamaresUtilsGui.h"
|
#include "network/Manager.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
#include "utils/Retranslator.h"
|
#include "utils/Variant.h"
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QTimeZone>
|
||||||
|
|
||||||
Config::Config( QObject* parent )
|
/** @brief Load supported locale keys
|
||||||
: QObject( parent )
|
*
|
||||||
, m_regionList( CalamaresUtils::Locale::TZRegion::fromZoneTab() )
|
* If i18n/SUPPORTED exists, read the lines from that and return those
|
||||||
, m_regionModel( new CalamaresUtils::Locale::CStringListModel( m_regionList ) )
|
* as supported locales; otherwise, try the file at @p localeGenPath
|
||||||
, m_zonesModel( new CalamaresUtils::Locale::CStringListModel() )
|
* and get lines from that. Failing both, try the output of `locale -a`.
|
||||||
, m_blockTzWidgetSet( false )
|
*
|
||||||
|
* This gives us a list of locale identifiers (e.g. en_US.UTF-8), which
|
||||||
|
* are not particularly human-readable.
|
||||||
|
*
|
||||||
|
* Only UTF-8 locales are returned (even if the system claims to support
|
||||||
|
* other, non-UTF-8, locales).
|
||||||
|
*/
|
||||||
|
static QStringList
|
||||||
|
loadLocales( const QString& localeGenPath )
|
||||||
{
|
{
|
||||||
connect( m_regionModel, &CalamaresUtils::Locale::CStringListModel::currentIndexChanged, [&]() {
|
QStringList localeGenLines;
|
||||||
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 ) )
|
|
||||||
{
|
|
||||||
m_regionModel->setCurrentIndex( m_regionModel->indexOf( initialRegion ) );
|
|
||||||
m_zonesModel->setList( region->zones() );
|
|
||||||
m_zonesModel->setCurrentIndex( m_zonesModel->indexOf( initialZone ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_regionModel->setCurrentIndex( m_regionModel->indexOf( "America" ) );
|
|
||||||
m_zonesModel->setList(
|
|
||||||
static_cast< const TZRegion* >( m_regionModel->item( m_regionModel->currentIndex() ) )->zones() );
|
|
||||||
m_zonesModel->setCurrentIndex( m_zonesModel->indexOf( "New_York" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some distros come with a meaningfully commented and easy to parse locale.gen,
|
// 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
|
// 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
|
// supported locales. We first try that one, and if it doesn't exist, we fall back
|
||||||
// to parsing the lines from locale.gen
|
// to parsing the lines from locale.gen
|
||||||
m_localeGenLines.clear();
|
localeGenLines.clear();
|
||||||
QFile supported( "/usr/share/i18n/SUPPORTED" );
|
QFile supported( "/usr/share/i18n/SUPPORTED" );
|
||||||
QByteArray ba;
|
QByteArray ba;
|
||||||
|
|
||||||
@ -109,7 +68,7 @@ Config::setLocaleInfo( const QString& initialRegion, const QString& initialZone,
|
|||||||
const auto lines = ba.split( '\n' );
|
const auto lines = ba.split( '\n' );
|
||||||
for ( const QByteArray& line : lines )
|
for ( const QByteArray& line : lines )
|
||||||
{
|
{
|
||||||
m_localeGenLines.append( QString::fromLatin1( line.simplified() ) );
|
localeGenLines.append( QString::fromLatin1( line.simplified() ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -150,11 +109,11 @@ Config::setLocaleInfo( const QString& initialRegion, const QString& initialZone,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_localeGenLines.append( lineString );
|
localeGenLines.append( lineString );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( m_localeGenLines.isEmpty() )
|
if ( localeGenLines.isEmpty() )
|
||||||
{
|
{
|
||||||
cWarning() << "cannot acquire a list of available locales."
|
cWarning() << "cannot acquire a list of available locales."
|
||||||
<< "The locale and localecfg modules will be broken as long as this "
|
<< "The locale and localecfg modules will be broken as long as this "
|
||||||
@ -164,168 +123,388 @@ Config::setLocaleInfo( const QString& initialRegion, const QString& initialZone,
|
|||||||
<< "* a well-formed"
|
<< "* a well-formed"
|
||||||
<< ( localeGenPath.isEmpty() ? QLatin1String( "/etc/locale.gen" ) : localeGenPath ) << "\n\tOR"
|
<< ( localeGenPath.isEmpty() ? QLatin1String( "/etc/locale.gen" ) : localeGenPath ) << "\n\tOR"
|
||||||
<< "* a complete pre-compiled locale-gen database which allows complete locale -a output.";
|
<< "* 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.
|
return localeGenLines; // 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
|
// Assuming we have a list of supported locales, we usually only want UTF-8 ones
|
||||||
// because it's not 1995.
|
// because it's not 1995.
|
||||||
for ( auto it = m_localeGenLines.begin(); it != m_localeGenLines.end(); )
|
auto notUtf8 = []( const QString& s ) {
|
||||||
{
|
return !s.contains( "UTF-8", Qt::CaseInsensitive ) && !s.contains( "utf8", Qt::CaseInsensitive );
|
||||||
if ( !it->contains( "UTF-8", Qt::CaseInsensitive ) && !it->contains( "utf8", Qt::CaseInsensitive ) )
|
};
|
||||||
{
|
auto it = std::remove_if( localeGenLines.begin(), localeGenLines.end(), notUtf8 );
|
||||||
it = m_localeGenLines.erase( it );
|
localeGenLines.erase( it, localeGenLines.end() );
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We strip " UTF-8" from "en_US.UTF-8 UTF-8" because it's redundant redundant.
|
// 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 )
|
// Also simplify whitespace.
|
||||||
{
|
auto unredundant = []( QString& s ) {
|
||||||
if ( it->endsWith( " UTF-8" ) )
|
if ( s.endsWith( " UTF-8" ) )
|
||||||
{
|
{
|
||||||
it->chop( 6 );
|
s.chop( 6 );
|
||||||
}
|
}
|
||||||
*it = it->simplified();
|
s = s.simplified();
|
||||||
}
|
};
|
||||||
updateGlobalStorage();
|
std::for_each( localeGenLines.begin(), localeGenLines.end(), unredundant );
|
||||||
updateLocaleLabels();
|
|
||||||
|
return localeGenLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const CalamaresUtils::Locale::CStringPairList&
|
||||||
|
timezoneData()
|
||||||
|
{
|
||||||
|
return CalamaresUtils::Locale::TZRegion::fromZoneTab();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Config::Config( QObject* parent )
|
||||||
|
: QObject( parent )
|
||||||
|
, m_regionModel( std::make_unique< CalamaresUtils::Locale::CStringListModel >( ::timezoneData() ) )
|
||||||
|
, m_zonesModel( std::make_unique< CalamaresUtils::Locale::CStringListModel >() )
|
||||||
|
{
|
||||||
|
// Slightly unusual: connect to our *own* signals. Wherever the language
|
||||||
|
// or the location is changed, these signals are emitted, so hook up to
|
||||||
|
// them to update global storage accordingly. This simplifies code:
|
||||||
|
// we don't need to call an update-GS method, or introduce an intermediate
|
||||||
|
// update-thing-and-GS method. And everywhere where we **do** change
|
||||||
|
// language or location, we already emit the signal.
|
||||||
|
connect( this, &Config::currentLanguageCodeChanged, [&]() {
|
||||||
|
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
gs->insert( "locale", m_selectedLocaleConfiguration.toBcp47() );
|
||||||
|
} );
|
||||||
|
|
||||||
|
connect( this, &Config::currentLCCodeChanged, [&]() {
|
||||||
|
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
// Update GS localeConf (the LC_ variables)
|
||||||
|
auto map = localeConfiguration().toMap();
|
||||||
|
QVariantMap vm;
|
||||||
|
for ( auto it = map.constBegin(); it != map.constEnd(); ++it )
|
||||||
|
{
|
||||||
|
vm.insert( it.key(), it.value() );
|
||||||
|
}
|
||||||
|
gs->insert( "localeConf", vm );
|
||||||
|
} );
|
||||||
|
|
||||||
|
connect( this, &Config::currentLocationChanged, [&]() {
|
||||||
|
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
|
||||||
|
// Update the GS region and zone (and possibly the live timezone)
|
||||||
|
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() );
|
||||||
|
if ( locationChanged && m_adjustLiveTimezone )
|
||||||
|
{
|
||||||
|
QProcess::execute( "timedatectl", // depends on systemd
|
||||||
|
{ "set-timezone", location->region() + '/' + location->zone() } );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
auto prettyStatusNotify = [&]() { emit prettyStatusChanged( prettyStatus() ); };
|
||||||
|
connect( this, &Config::currentLanguageStatusChanged, prettyStatusNotify );
|
||||||
|
connect( this, &Config::currentLCStatusChanged, prettyStatusNotify );
|
||||||
|
connect( this, &Config::currentLocationStatusChanged, prettyStatusNotify );
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::~Config() {}
|
||||||
|
|
||||||
|
const CalamaresUtils::Locale::CStringPairList&
|
||||||
|
Config::timezoneData() const
|
||||||
|
{
|
||||||
|
return ::timezoneData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Config::updateGlobalLocale()
|
Config::setCurrentLocation()
|
||||||
{
|
{
|
||||||
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
if ( !m_currentLocation && m_startingTimezone.isValid() )
|
||||||
const QString bcp47 = m_selectedLocaleConfiguration.toBcp47();
|
{
|
||||||
gs->insert( "locale", bcp47 );
|
setCurrentLocation( m_startingTimezone.first, m_startingTimezone.second );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Config::setCurrentLocation(const QString& regionzone)
|
||||||
|
{
|
||||||
|
auto r = CalamaresUtils::GeoIP::splitTZString( regionzone );
|
||||||
|
if ( r.isValid() )
|
||||||
|
{
|
||||||
|
setCurrentLocation( r.first, r.second );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Config::updateGlobalStorage()
|
Config::setCurrentLocation( const QString& regionName, const QString& zoneName )
|
||||||
{
|
{
|
||||||
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
using namespace CalamaresUtils::Locale;
|
||||||
|
auto* region = timezoneData().find< TZRegion >( regionName );
|
||||||
const auto* location = currentLocation();
|
auto* zone = region ? region->zones().find< TZZone >( zoneName ) : nullptr;
|
||||||
bool locationChanged = ( location->region() != gs->value( "locationRegion" ) )
|
if ( zone )
|
||||||
|| ( location->zone() != gs->value( "locationZone" ) );
|
|
||||||
#ifdef DEBUG_TIMEZONES
|
|
||||||
if ( locationChanged )
|
|
||||||
{
|
{
|
||||||
cDebug() << "Location changed" << gs->value( "locationRegion" ) << ',' << gs->value( "locationZone" ) << "to"
|
setCurrentLocation( zone );
|
||||||
<< location->region() << ',' << location->zone();
|
|
||||||
}
|
}
|
||||||
#endif
|
else
|
||||||
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
|
// Recursive, but America/New_York always exists.
|
||||||
{ "set-timezone", location->region() + '/' + location->zone() } );
|
setCurrentLocation( QStringLiteral( "America" ), QStringLiteral( "New_York" ) );
|
||||||
}
|
}
|
||||||
#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
|
void
|
||||||
Config::updateLocaleLabels()
|
Config::setCurrentLocation( const CalamaresUtils::Locale::TZZone* location )
|
||||||
{
|
{
|
||||||
LocaleConfiguration lc
|
if ( location != m_currentLocation )
|
||||||
= m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration() : m_selectedLocaleConfiguration;
|
{
|
||||||
auto labels = prettyLocaleStatus( lc );
|
m_currentLocation = location;
|
||||||
emit prettyStatusChanged();
|
// Overwrite those settings that have not been made explicit.
|
||||||
}
|
auto newLocale = automaticLocaleConfiguration();
|
||||||
|
if ( !m_selectedLocaleConfiguration.explicit_lang )
|
||||||
|
{
|
||||||
|
m_selectedLocaleConfiguration.setLanguage( newLocale.language() );
|
||||||
|
emit currentLanguageStatusChanged( currentLanguageStatus() );
|
||||||
|
}
|
||||||
|
if ( !m_selectedLocaleConfiguration.explicit_lc )
|
||||||
|
{
|
||||||
|
m_selectedLocaleConfiguration.lc_numeric = newLocale.lc_numeric;
|
||||||
|
m_selectedLocaleConfiguration.lc_time = newLocale.lc_time;
|
||||||
|
m_selectedLocaleConfiguration.lc_monetary = newLocale.lc_monetary;
|
||||||
|
m_selectedLocaleConfiguration.lc_paper = newLocale.lc_paper;
|
||||||
|
m_selectedLocaleConfiguration.lc_name = newLocale.lc_name;
|
||||||
|
m_selectedLocaleConfiguration.lc_address = newLocale.lc_address;
|
||||||
|
m_selectedLocaleConfiguration.lc_telephone = newLocale.lc_telephone;
|
||||||
|
m_selectedLocaleConfiguration.lc_measurement = newLocale.lc_measurement;
|
||||||
|
m_selectedLocaleConfiguration.lc_identification = newLocale.lc_identification;
|
||||||
|
|
||||||
|
emit currentLCStatusChanged( currentLCStatus() );
|
||||||
std::pair< QString, QString >
|
}
|
||||||
Config::prettyLocaleStatus( const LocaleConfiguration& lc ) const
|
emit currentLocationChanged( m_currentLocation );
|
||||||
{
|
}
|
||||||
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
|
LocaleConfiguration
|
||||||
Config::guessLocaleConfiguration() const
|
Config::automaticLocaleConfiguration() const
|
||||||
{
|
{
|
||||||
|
// Special case: no location has been set at **all**
|
||||||
|
if ( !currentLocation() )
|
||||||
|
{
|
||||||
|
return LocaleConfiguration();
|
||||||
|
}
|
||||||
return LocaleConfiguration::fromLanguageAndLocation(
|
return LocaleConfiguration::fromLanguageAndLocation(
|
||||||
QLocale().name(), m_localeGenLines, currentLocation() ? currentLocation()->country() : "" );
|
QLocale().name(), supportedLocales(), currentLocation()->country() );
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap< QString, QString >
|
LocaleConfiguration
|
||||||
Config::localesMap()
|
Config::localeConfiguration() const
|
||||||
{
|
{
|
||||||
return m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration().toMap()
|
return m_selectedLocaleConfiguration.isEmpty() ? automaticLocaleConfiguration() : m_selectedLocaleConfiguration;
|
||||||
: m_selectedLocaleConfiguration.toMap();
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Config::setLanguageExplicitly( const QString& language )
|
||||||
|
{
|
||||||
|
m_selectedLocaleConfiguration.setLanguage( language );
|
||||||
|
m_selectedLocaleConfiguration.explicit_lang = true;
|
||||||
|
|
||||||
|
emit currentLanguageStatusChanged( currentLanguageStatus() );
|
||||||
|
emit currentLanguageCodeChanged( currentLanguageCode() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Config::setLCLocaleExplicitly( const QString& locale )
|
||||||
|
{
|
||||||
|
// TODO: improve the granularity of this setting.
|
||||||
|
m_selectedLocaleConfiguration.lc_numeric = locale;
|
||||||
|
m_selectedLocaleConfiguration.lc_time = locale;
|
||||||
|
m_selectedLocaleConfiguration.lc_monetary = locale;
|
||||||
|
m_selectedLocaleConfiguration.lc_paper = locale;
|
||||||
|
m_selectedLocaleConfiguration.lc_name = locale;
|
||||||
|
m_selectedLocaleConfiguration.lc_address = locale;
|
||||||
|
m_selectedLocaleConfiguration.lc_telephone = locale;
|
||||||
|
m_selectedLocaleConfiguration.lc_measurement = locale;
|
||||||
|
m_selectedLocaleConfiguration.lc_identification = locale;
|
||||||
|
m_selectedLocaleConfiguration.explicit_lc = true;
|
||||||
|
|
||||||
|
emit currentLCStatusChanged( currentLCStatus() );
|
||||||
|
emit currentLCCodeChanged( currentLCCode() );
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
Config::currentLocationStatus() const
|
||||||
|
{
|
||||||
|
return tr( "Set timezone to %1/%2." ).arg( m_currentLocation->region(), m_currentLocation->zone() );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QString
|
||||||
|
localeLabel( const QString& s )
|
||||||
|
{
|
||||||
|
using CalamaresUtils::Locale::Label;
|
||||||
|
|
||||||
|
Label lang( s, Label::LabelFormat::AlwaysWithCountry );
|
||||||
|
return lang.label();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
Config::currentLanguageStatus() const
|
||||||
|
{
|
||||||
|
return tr( "The system language will be set to %1." )
|
||||||
|
.arg( localeLabel( m_selectedLocaleConfiguration.language() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
Config::currentLCStatus() const
|
||||||
|
{
|
||||||
|
return tr( "The numbers and dates locale will be set to %1." )
|
||||||
|
.arg( localeLabel( m_selectedLocaleConfiguration.lc_numeric ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
Config::prettyStatus() const
|
Config::prettyStatus() const
|
||||||
{
|
{
|
||||||
QString status;
|
QStringList l { currentLocationStatus(), currentLanguageStatus(), currentLCStatus() };
|
||||||
status += tr( "Set timezone to %1/%2.<br/>" )
|
return l.join( QStringLiteral( "<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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
const CalamaresUtils::Locale::TZZone*
|
getLocaleGenLines( const QVariantMap& configurationMap, QStringList& localeGenLines )
|
||||||
Config::currentLocation() const
|
|
||||||
{
|
{
|
||||||
return static_cast< const CalamaresUtils::Locale::TZZone* >( m_zonesModel->item( m_zonesModel->currentIndex() ) );
|
QString localeGenPath = CalamaresUtils::getString( configurationMap, "localeGenPath" );
|
||||||
|
if ( localeGenPath.isEmpty() )
|
||||||
|
{
|
||||||
|
localeGenPath = QStringLiteral( "/etc/locale.gen" );
|
||||||
|
}
|
||||||
|
localeGenLines = loadLocales( localeGenPath );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
getAdjustLiveTimezone( const QVariantMap& configurationMap, bool& adjustLiveTimezone )
|
||||||
|
{
|
||||||
|
adjustLiveTimezone = CalamaresUtils::getBool(
|
||||||
|
configurationMap, "adjustLiveTimezone", Calamares::Settings::instance()->doChroot() );
|
||||||
|
#ifdef DEBUG_TIMEZONES
|
||||||
|
if ( m_adjustLiveTimezone )
|
||||||
|
{
|
||||||
|
cWarning() << "Turning off live-timezone adjustments because debugging is on.";
|
||||||
|
adjustLiveTimezone = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
if ( adjustLiveTimezone )
|
||||||
|
{
|
||||||
|
cWarning() << "Turning off live-timezone adjustments on FreeBSD.";
|
||||||
|
adjustLiveTimezone = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
getStartingTimezone( const QVariantMap& configurationMap, CalamaresUtils::GeoIP::RegionZonePair& startingTimezone )
|
||||||
|
{
|
||||||
|
QString region = CalamaresUtils::getString( configurationMap, "region" );
|
||||||
|
QString zone = CalamaresUtils::getString( configurationMap, "zone" );
|
||||||
|
if ( !region.isEmpty() && !zone.isEmpty() )
|
||||||
|
{
|
||||||
|
startingTimezone = CalamaresUtils::GeoIP::RegionZonePair( region, zone );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startingTimezone
|
||||||
|
= CalamaresUtils::GeoIP::RegionZonePair( QStringLiteral( "America" ), QStringLiteral( "New_York" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( CalamaresUtils::getBool( configurationMap, "useSystemTimezone", false ) )
|
||||||
|
{
|
||||||
|
auto systemtz = CalamaresUtils::GeoIP::splitTZString( QTimeZone::systemTimeZoneId() );
|
||||||
|
if ( systemtz.isValid() )
|
||||||
|
{
|
||||||
|
cDebug() << "Overriding configured timezone" << startingTimezone << "with system timezone" << systemtz;
|
||||||
|
startingTimezone = systemtz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
getGeoIP( const QVariantMap& configurationMap, std::unique_ptr< CalamaresUtils::GeoIP::Handler >& geoip )
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
QVariantMap map = CalamaresUtils::getSubMap( configurationMap, "geoip", ok );
|
||||||
|
if ( ok )
|
||||||
|
{
|
||||||
|
QString url = CalamaresUtils::getString( map, "url" );
|
||||||
|
QString style = CalamaresUtils::getString( map, "style" );
|
||||||
|
QString selector = CalamaresUtils::getString( map, "selector" );
|
||||||
|
|
||||||
|
geoip = std::make_unique< CalamaresUtils::GeoIP::Handler >( style, url, selector );
|
||||||
|
if ( !geoip->isValid() )
|
||||||
|
{
|
||||||
|
cWarning() << "GeoIP Style" << style << "is not recognized.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Config::setConfigurationMap( const QVariantMap& configurationMap )
|
||||||
|
{
|
||||||
|
getLocaleGenLines( configurationMap, m_localeGenLines );
|
||||||
|
getAdjustLiveTimezone( configurationMap, m_adjustLiveTimezone );
|
||||||
|
getStartingTimezone( configurationMap, m_startingTimezone );
|
||||||
|
getGeoIP( configurationMap, m_geoip );
|
||||||
|
|
||||||
|
if ( m_geoip && m_geoip->isValid() )
|
||||||
|
{
|
||||||
|
connect(
|
||||||
|
Calamares::ModuleManager::instance(), &Calamares::ModuleManager::modulesLoaded, this, &Config::startGeoIP );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Calamares::JobList
|
||||||
|
Config::createJobs()
|
||||||
|
{
|
||||||
|
Calamares::JobList list;
|
||||||
|
const CalamaresUtils::Locale::TZZone* location = currentLocation();
|
||||||
|
|
||||||
|
if ( location )
|
||||||
|
{
|
||||||
|
Calamares::Job* j = new SetTimezoneJob( location->region(), location->zone() );
|
||||||
|
list.append( Calamares::job_ptr( j ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Config::startGeoIP()
|
||||||
|
{
|
||||||
|
if ( m_geoip && m_geoip->isValid() )
|
||||||
|
{
|
||||||
|
auto& network = CalamaresUtils::Network::Manager::instance();
|
||||||
|
if ( network.hasInternet() || network.synchronousPing( m_geoip->url() ) )
|
||||||
|
{
|
||||||
|
using Watcher = QFutureWatcher< CalamaresUtils::GeoIP::RegionZonePair >;
|
||||||
|
m_geoipWatcher = std::make_unique< Watcher >();
|
||||||
|
m_geoipWatcher->setFuture( m_geoip->query() );
|
||||||
|
connect( m_geoipWatcher.get(), &Watcher::finished, this, &Config::completeGeoIP );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Config::completeGeoIP()
|
||||||
|
{
|
||||||
|
if ( !currentLocation() )
|
||||||
|
{
|
||||||
|
auto r = m_geoipWatcher->result();
|
||||||
|
if ( r.isValid() )
|
||||||
|
{
|
||||||
|
m_startingTimezone = r;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cWarning() << "GeoIP returned invalid result.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cWarning() << "GeoIP result ignored because a location is already set.";
|
||||||
|
}
|
||||||
|
m_geoipWatcher.reset();
|
||||||
|
m_geoip.reset();
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
*
|
*
|
||||||
* Copyright 2019-2020, Adriaan de Groot <groot@kde.org>
|
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||||
* Copyright 2020, Camilo Higuita <milo.h@aol.com>
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
* License-Filename: LICENSE
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -23,9 +24,11 @@
|
|||||||
#include "LocaleConfiguration.h"
|
#include "LocaleConfiguration.h"
|
||||||
|
|
||||||
#include "Job.h"
|
#include "Job.h"
|
||||||
|
#include "geoip/Handler.h"
|
||||||
|
#include "geoip/Interface.h"
|
||||||
#include "locale/TimeZone.h"
|
#include "locale/TimeZone.h"
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QFutureWatcher>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -33,53 +36,150 @@
|
|||||||
class Config : public QObject
|
class Config : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY( const QStringList& supportedLocales READ supportedLocales CONSTANT FINAL )
|
||||||
Q_PROPERTY( CalamaresUtils::Locale::CStringListModel* zonesModel READ zonesModel CONSTANT FINAL )
|
Q_PROPERTY( CalamaresUtils::Locale::CStringListModel* zonesModel READ zonesModel CONSTANT FINAL )
|
||||||
Q_PROPERTY( CalamaresUtils::Locale::CStringListModel* regionModel READ regionModel CONSTANT FINAL )
|
Q_PROPERTY( CalamaresUtils::Locale::CStringListModel* regionModel READ regionModel CONSTANT FINAL )
|
||||||
|
|
||||||
|
Q_PROPERTY( const CalamaresUtils::Locale::TZZone* currentLocation READ currentLocation WRITE setCurrentLocation
|
||||||
|
NOTIFY currentLocationChanged )
|
||||||
|
|
||||||
|
// Status are complete, human-readable, messages
|
||||||
|
Q_PROPERTY( QString currentLocationStatus READ currentLocationStatus NOTIFY currentLanguageStatusChanged )
|
||||||
|
Q_PROPERTY( QString currentLanguageStatus READ currentLanguageStatus NOTIFY currentLanguageStatusChanged )
|
||||||
|
Q_PROPERTY( QString currentLCStatus READ currentLCStatus NOTIFY currentLCStatusChanged )
|
||||||
|
// Code are internal identifiers, like "en_US.UTF-8"
|
||||||
|
Q_PROPERTY( QString currentLanguageCode READ currentLanguageCode WRITE setLanguageExplicitly NOTIFY currentLanguageCodeChanged )
|
||||||
|
Q_PROPERTY( QString currentLCCode READ currentLCCode WRITE setLCLocaleExplicitly NOTIFY currentLCCodeChanged )
|
||||||
|
|
||||||
|
// This is a long human-readable string with all three statuses
|
||||||
Q_PROPERTY( QString prettyStatus READ prettyStatus NOTIFY prettyStatusChanged FINAL )
|
Q_PROPERTY( QString prettyStatus READ prettyStatus NOTIFY prettyStatusChanged FINAL )
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Config( QObject* parent = nullptr );
|
Config( QObject* parent = nullptr );
|
||||||
~Config();
|
~Config();
|
||||||
CalamaresUtils::Locale::CStringListModel* regionModel() const;
|
|
||||||
CalamaresUtils::Locale::CStringListModel* zonesModel() const;
|
|
||||||
|
|
||||||
void setLocaleInfo( const QString& initialRegion, const QString& initialZone, const QString& localeGenPath );
|
|
||||||
|
|
||||||
|
void setConfigurationMap( const QVariantMap& );
|
||||||
Calamares::JobList createJobs();
|
Calamares::JobList createJobs();
|
||||||
QMap< QString, QString > localesMap();
|
|
||||||
|
// Underlying data for the models
|
||||||
|
const CalamaresUtils::Locale::CStringPairList& timezoneData() const;
|
||||||
|
|
||||||
|
/** @brief The currently selected location (timezone)
|
||||||
|
*
|
||||||
|
* The location is a pointer into the date that timezoneData() returns.
|
||||||
|
*/
|
||||||
|
const CalamaresUtils::Locale::TZZone* currentLocation() const { return m_currentLocation; }
|
||||||
|
|
||||||
|
/// locale configuration (LC_* and LANG) based solely on the current location.
|
||||||
|
LocaleConfiguration automaticLocaleConfiguration() const;
|
||||||
|
/// locale configuration that takes explicit settings into account
|
||||||
|
LocaleConfiguration localeConfiguration() const;
|
||||||
|
|
||||||
|
/// The human-readable description of what timezone is used
|
||||||
|
QString currentLocationStatus() const;
|
||||||
|
/// The human-readable description of what language is used
|
||||||
|
QString currentLanguageStatus() const;
|
||||||
|
/// The human-readable description of what locale (LC_*) is used
|
||||||
|
QString currentLCStatus() const;
|
||||||
|
|
||||||
|
/// The human-readable summary of what the module will do
|
||||||
QString prettyStatus() const;
|
QString prettyStatus() const;
|
||||||
|
|
||||||
private:
|
const QStringList& supportedLocales() const { return m_localeGenLines; }
|
||||||
CalamaresUtils::Locale::CStringPairList m_regionList;
|
CalamaresUtils::Locale::CStringListModel* regionModel() const { return m_regionModel.get(); }
|
||||||
CalamaresUtils::Locale::CStringListModel* m_regionModel;
|
CalamaresUtils::Locale::CStringListModel* zonesModel() const { return m_zonesModel.get(); }
|
||||||
CalamaresUtils::Locale::CStringListModel* m_zonesModel;
|
|
||||||
|
|
||||||
LocaleConfiguration m_selectedLocaleConfiguration;
|
/// Special case, set location from starting timezone if not already set
|
||||||
|
void setCurrentLocation();
|
||||||
|
|
||||||
QStringList m_localeGenLines;
|
public Q_SLOTS:
|
||||||
int m_currentRegion = -1;
|
/// Set a language by user-choice, overriding future location changes
|
||||||
|
void setLanguageExplicitly( const QString& language );
|
||||||
|
/// Set LC (formats) by user-choice, overriding future location changes
|
||||||
|
void setLCLocaleExplicitly( const QString& locale );
|
||||||
|
|
||||||
bool m_blockTzWidgetSet;
|
/** @brief Sets a location by full name
|
||||||
|
|
||||||
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,
|
* @p regionzone should be an identifier from zone.tab, e.g. "Africa/Abidjan",
|
||||||
* and writes it to GS *locale* key (as a string, in BCP47 format).
|
* which is split into regon and zone. Invalid names will **not**
|
||||||
|
* change the actual location.
|
||||||
*/
|
*/
|
||||||
void updateGlobalLocale();
|
void setCurrentLocation( const QString& regionzone );
|
||||||
void updateGlobalStorage();
|
/** @brief Sets a location by split name
|
||||||
void updateLocaleLabels();
|
*
|
||||||
|
* @p region should be "America" or the like, while @p zone
|
||||||
|
* names a zone within that region.
|
||||||
|
*/
|
||||||
|
void setCurrentLocation( const QString& region, const QString& zone );
|
||||||
|
/** @brief Sets a location by pointer
|
||||||
|
*
|
||||||
|
* Pointer should be within the same model as the widget uses.
|
||||||
|
* This can update the locale configuration -- the automatic one
|
||||||
|
* follows the current location, and otherwise only explicitly-set
|
||||||
|
* values will ignore changes to the location.
|
||||||
|
*/
|
||||||
|
void setCurrentLocation( const CalamaresUtils::Locale::TZZone* location );
|
||||||
|
|
||||||
const CalamaresUtils::Locale::TZZone* currentLocation() const;
|
QString currentLanguageCode() const { return localeConfiguration().language(); }
|
||||||
|
QString currentLCCode() const { return localeConfiguration().lc_numeric; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void prettyStatusChanged();
|
void currentLocationChanged( const CalamaresUtils::Locale::TZZone* location ) const;
|
||||||
|
void currentLocationStatusChanged( const QString& ) const;
|
||||||
|
void currentLanguageStatusChanged( const QString& ) const;
|
||||||
|
void currentLCStatusChanged( const QString& ) const;
|
||||||
|
void prettyStatusChanged( const QString& ) const;
|
||||||
|
void currentLanguageCodeChanged( const QString& ) const;
|
||||||
|
void currentLCCodeChanged( const QString& ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// A list of supported locale identifiers (e.g. "en_US.UTF-8")
|
||||||
|
QStringList m_localeGenLines;
|
||||||
|
|
||||||
|
/// The regions (America, Asia, Europe ..)
|
||||||
|
std::unique_ptr< CalamaresUtils::Locale::CStringListModel > m_regionModel;
|
||||||
|
/// The zones for the current region (e.g. America/New_York)
|
||||||
|
std::unique_ptr< CalamaresUtils::Locale::CStringListModel > m_zonesModel;
|
||||||
|
|
||||||
|
/// The location, points into the timezone data
|
||||||
|
const CalamaresUtils::Locale::TZZone* m_currentLocation = nullptr;
|
||||||
|
|
||||||
|
/** @brief Specific locale configurations
|
||||||
|
*
|
||||||
|
* "Automatic" locale configuration based on the location (e.g.
|
||||||
|
* Europe/Amsterdam means Dutch language and Dutch locale) leave
|
||||||
|
* this empty; if the user explicitly sets something, then
|
||||||
|
* this configuration is non-empty and takes precedence over the
|
||||||
|
* automatic location settings (so a user in Amsterdam can still
|
||||||
|
* pick Ukranian settings, for instance).
|
||||||
|
*/
|
||||||
|
LocaleConfiguration m_selectedLocaleConfiguration;
|
||||||
|
|
||||||
|
/** @brief Should we adjust the "live" timezone when the location changes?
|
||||||
|
*
|
||||||
|
* In the Widgets UI, clicking around on the world map adjusts the
|
||||||
|
* timezone, and the live system can be made to follow that.
|
||||||
|
*/
|
||||||
|
bool m_adjustLiveTimezone;
|
||||||
|
|
||||||
|
/** @brief The initial timezone (region, zone) specified in the config.
|
||||||
|
*
|
||||||
|
* This may be overridden by setting *useSystemTimezone* or by
|
||||||
|
* GeoIP settings.
|
||||||
|
*/
|
||||||
|
CalamaresUtils::GeoIP::RegionZonePair m_startingTimezone;
|
||||||
|
|
||||||
|
/** @brief Handler for GeoIP lookup (if configured)
|
||||||
|
*
|
||||||
|
* The GeoIP lookup needs to be started at some suitable time,
|
||||||
|
* by explicitly calling *TODO*
|
||||||
|
*/
|
||||||
|
std::unique_ptr< CalamaresUtils::GeoIP::Handler > m_geoip;
|
||||||
|
|
||||||
|
// Implementation details for doing GeoIP lookup
|
||||||
|
void startGeoIP();
|
||||||
|
void completeGeoIP();
|
||||||
|
std::unique_ptr< QFutureWatcher< CalamaresUtils::GeoIP::RegionZonePair > > m_geoipWatcher;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ LocaleConfiguration::LocaleConfiguration( const QString& localeName, const QStri
|
|||||||
lc_numeric = lc_time = lc_monetary = lc_paper = lc_name = lc_address = lc_telephone = lc_measurement
|
lc_numeric = lc_time = lc_monetary = lc_paper = lc_name = lc_address = lc_telephone = lc_measurement
|
||||||
= lc_identification = formatsName;
|
= lc_identification = formatsName;
|
||||||
|
|
||||||
(void)setLanguage( localeName );
|
setLanguage( localeName );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ LocaleConfiguration::fromLanguageAndLocation( const QString& languageLocale,
|
|||||||
if ( language == "pt" || language == "zh" )
|
if ( language == "pt" || language == "zh" )
|
||||||
{
|
{
|
||||||
QString proposedLocale = QString( "%1_%2" ).arg( language ).arg( countryCode );
|
QString proposedLocale = QString( "%1_%2" ).arg( language ).arg( countryCode );
|
||||||
foreach ( QString line, linesForLanguage )
|
for ( const QString& line : linesForLanguage )
|
||||||
{
|
{
|
||||||
if ( line.contains( proposedLocale ) )
|
if ( line.contains( proposedLocale ) )
|
||||||
{
|
{
|
||||||
|
@ -26,36 +26,53 @@
|
|||||||
|
|
||||||
class LocaleConfiguration
|
class LocaleConfiguration
|
||||||
{
|
{
|
||||||
public:
|
public: // TODO: private (but need to be public for tests)
|
||||||
/// @brief Create an empty locale, with nothing set
|
/** @brief Create a locale with everything set to the given @p localeName
|
||||||
explicit LocaleConfiguration();
|
*
|
||||||
/// @brief Create a locale with everything set to the given @p localeName
|
* Consumers should use fromLanguageAndLocation() instead.
|
||||||
|
*/
|
||||||
explicit LocaleConfiguration( const QString& localeName /* "en_US.UTF-8" */ )
|
explicit LocaleConfiguration( const QString& localeName /* "en_US.UTF-8" */ )
|
||||||
: LocaleConfiguration( localeName, localeName )
|
: LocaleConfiguration( localeName, localeName )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
/// @brief Create a locale with language and formats separate
|
/** @brief Create a locale with language and formats separate
|
||||||
|
*
|
||||||
|
* Consumers should use fromLanguageAndLocation() instead.
|
||||||
|
*/
|
||||||
explicit LocaleConfiguration( const QString& localeName, const QString& formatsName );
|
explicit LocaleConfiguration( const QString& localeName, const QString& formatsName );
|
||||||
|
|
||||||
|
/// @brief Create an empty locale, with nothing set
|
||||||
|
explicit LocaleConfiguration();
|
||||||
|
|
||||||
|
/** @brief Create a "sensible" locale configuration for @p language and @p countryCode
|
||||||
|
*
|
||||||
|
* This method applies some heuristics to pick a good locale (from the list
|
||||||
|
* @p availableLocales), along with a good language (for instance, in
|
||||||
|
* large countries with many languages, picking a generally used one).
|
||||||
|
*/
|
||||||
static LocaleConfiguration
|
static LocaleConfiguration
|
||||||
fromLanguageAndLocation( const QString& language, const QStringList& availableLocales, const QString& countryCode );
|
fromLanguageAndLocation( const QString& language, const QStringList& availableLocales, const QString& countryCode );
|
||||||
|
|
||||||
|
/// Is this an empty (default-constructed and not modified) configuration?
|
||||||
bool isEmpty() const;
|
bool isEmpty() const;
|
||||||
|
|
||||||
/** @brief sets lang and the BCP47 representation
|
/** @brief sets language to @p localeName
|
||||||
*
|
*
|
||||||
* Note that the documentation how this works is in packages.conf
|
* The language may be regionalized, e.g. "nl_BE". Both the language
|
||||||
|
* (with region) and BCP47 representation (without region, lowercase)
|
||||||
|
* are updated. The BCP47 representation is used by the packages module.
|
||||||
|
* See also `packages.conf` for a discussion of how this is used.
|
||||||
*/
|
*/
|
||||||
void setLanguage( const QString& localeName );
|
void setLanguage( const QString& localeName );
|
||||||
|
/// Current language (including region)
|
||||||
QString language() const { return m_lang; }
|
QString language() const { return m_lang; }
|
||||||
|
/// Current language (lowercase, BCP47 format, no region)
|
||||||
// Note that the documentation how this works is in packages.conf
|
|
||||||
QString toBcp47() const { return m_languageLocaleBcp47; }
|
QString toBcp47() const { return m_languageLocaleBcp47; }
|
||||||
|
|
||||||
QMap< QString, QString > toMap() const;
|
QMap< QString, QString > toMap() const;
|
||||||
|
|
||||||
// These become all uppercase in locale.conf, but we keep them lowercase here to
|
// These become all uppercase in locale.conf, but we keep them lowercase here to
|
||||||
// avoid confusion with locale.h.
|
// avoid confusion with <locale.h>, which defines (e.g.) LC_NUMERIC macro.
|
||||||
QString lc_numeric, lc_time, lc_monetary, lc_paper, lc_name, lc_address, lc_telephone, lc_measurement,
|
QString lc_numeric, lc_time, lc_monetary, lc_paper, lc_name, lc_address, lc_telephone, lc_measurement,
|
||||||
lc_identification;
|
lc_identification;
|
||||||
|
|
||||||
|
@ -19,37 +19,30 @@
|
|||||||
|
|
||||||
#include "LocalePage.h"
|
#include "LocalePage.h"
|
||||||
|
|
||||||
#include "SetTimezoneJob.h"
|
#include "Config.h"
|
||||||
|
#include "LCLocaleDialog.h"
|
||||||
#include "timezonewidget/timezonewidget.h"
|
#include "timezonewidget/timezonewidget.h"
|
||||||
|
|
||||||
#include "GlobalStorage.h"
|
|
||||||
#include "JobQueue.h"
|
|
||||||
#include "LCLocaleDialog.h"
|
|
||||||
#include "Settings.h"
|
|
||||||
|
|
||||||
#include "locale/Label.h"
|
|
||||||
#include "locale/TimeZone.h"
|
|
||||||
#include "utils/CalamaresUtilsGui.h"
|
#include "utils/CalamaresUtilsGui.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/RAII.h"
|
||||||
#include "utils/Retranslator.h"
|
#include "utils/Retranslator.h"
|
||||||
|
|
||||||
#include <QBoxLayout>
|
#include <QBoxLayout>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QFile>
|
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QProcess>
|
#include <QPointer>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
|
||||||
LocalePage::LocalePage( QWidget* parent )
|
LocalePage::LocalePage( Config* config, QWidget* parent )
|
||||||
: QWidget( parent )
|
: QWidget( parent )
|
||||||
, m_regionList( CalamaresUtils::Locale::TZRegion::fromZoneTab() )
|
, m_config( config )
|
||||||
, m_regionModel( std::make_unique< CalamaresUtils::Locale::CStringListModel >( m_regionList ) )
|
|
||||||
, m_blockTzWidgetSet( false )
|
, m_blockTzWidgetSet( false )
|
||||||
{
|
{
|
||||||
QBoxLayout* mainLayout = new QVBoxLayout;
|
QBoxLayout* mainLayout = new QVBoxLayout;
|
||||||
|
|
||||||
QBoxLayout* tzwLayout = new QHBoxLayout;
|
QBoxLayout* tzwLayout = new QHBoxLayout;
|
||||||
m_tzWidget = new TimeZoneWidget( this );
|
m_tzWidget = new TimeZoneWidget( config->timezoneData(), this );
|
||||||
tzwLayout->addStretch();
|
tzwLayout->addStretch();
|
||||||
tzwLayout->addWidget( m_tzWidget );
|
tzwLayout->addWidget( m_tzWidget );
|
||||||
tzwLayout->addStretch();
|
tzwLayout->addStretch();
|
||||||
@ -105,9 +98,24 @@ LocalePage::LocalePage( QWidget* parent )
|
|||||||
setMinimumWidth( m_tzWidget->width() );
|
setMinimumWidth( m_tzWidget->width() );
|
||||||
setLayout( mainLayout );
|
setLayout( mainLayout );
|
||||||
|
|
||||||
|
// Set up the location before connecting signals, to avoid a signal
|
||||||
|
// storm as various parts interact.
|
||||||
|
m_regionCombo->setModel( m_config->regionModel() );
|
||||||
|
locationChanged( m_config->currentLocation() ); // doesn't inform TZ widget
|
||||||
|
m_tzWidget->setCurrentLocation( m_config->currentLocation() );
|
||||||
|
|
||||||
|
connect( config, &Config::currentLCStatusChanged, m_formatsLabel, &QLabel::setText );
|
||||||
|
connect( config, &Config::currentLanguageStatusChanged, m_localeLabel, &QLabel::setText );
|
||||||
|
connect( config, &Config::currentLocationChanged, m_tzWidget, &TimeZoneWidget::setCurrentLocation );
|
||||||
|
connect( config, &Config::currentLocationChanged, this, &LocalePage::locationChanged );
|
||||||
|
connect( m_tzWidget,
|
||||||
|
&TimeZoneWidget::locationChanged,
|
||||||
|
config,
|
||||||
|
QOverload< const CalamaresUtils::Locale::TZZone* >::of( &Config::setCurrentLocation ) );
|
||||||
|
|
||||||
connect( m_regionCombo, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, &LocalePage::regionChanged );
|
connect( m_regionCombo, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, &LocalePage::regionChanged );
|
||||||
connect( m_zoneCombo, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, &LocalePage::zoneChanged );
|
connect( m_zoneCombo, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, &LocalePage::zoneChanged );
|
||||||
connect( m_tzWidget, &TimeZoneWidget::locationChanged, this, &LocalePage::locationChanged );
|
|
||||||
connect( m_localeChangeButton, &QPushButton::clicked, this, &LocalePage::changeLocale );
|
connect( m_localeChangeButton, &QPushButton::clicked, this, &LocalePage::changeLocale );
|
||||||
connect( m_formatsChangeButton, &QPushButton::clicked, this, &LocalePage::changeFormats );
|
connect( m_formatsChangeButton, &QPushButton::clicked, this, &LocalePage::changeFormats );
|
||||||
|
|
||||||
@ -115,10 +123,7 @@ LocalePage::LocalePage( QWidget* parent )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LocalePage::~LocalePage()
|
LocalePage::~LocalePage() {}
|
||||||
{
|
|
||||||
qDeleteAll( m_regionList );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -128,175 +133,8 @@ LocalePage::updateLocaleLabels()
|
|||||||
m_zoneLabel->setText( tr( "Zone:" ) );
|
m_zoneLabel->setText( tr( "Zone:" ) );
|
||||||
m_localeChangeButton->setText( tr( "&Change..." ) );
|
m_localeChangeButton->setText( tr( "&Change..." ) );
|
||||||
m_formatsChangeButton->setText( tr( "&Change..." ) );
|
m_formatsChangeButton->setText( tr( "&Change..." ) );
|
||||||
|
m_localeLabel->setText( m_config->currentLanguageStatus() );
|
||||||
LocaleConfiguration lc
|
m_formatsLabel->setText( m_config->currentLCStatus() );
|
||||||
= m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration() : m_selectedLocaleConfiguration;
|
|
||||||
auto labels = prettyLocaleStatus( lc );
|
|
||||||
m_localeLabel->setText( labels.first );
|
|
||||||
m_formatsLabel->setText( labels.second );
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
LocalePage::init( const QString& initialRegion, const QString& initialZone, const QString& localeGenPath )
|
|
||||||
{
|
|
||||||
using namespace CalamaresUtils::Locale;
|
|
||||||
|
|
||||||
m_regionCombo->setModel( m_regionModel.get() );
|
|
||||||
m_regionCombo->currentIndexChanged( m_regionCombo->currentIndex() );
|
|
||||||
|
|
||||||
auto* region = m_regionList.find< TZRegion >( initialRegion );
|
|
||||||
if ( region && region->zones().find< TZZone >( initialZone ) )
|
|
||||||
{
|
|
||||||
m_tzWidget->setCurrentLocation( initialRegion, initialZone );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_tzWidget->setCurrentLocation( "America", "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.
|
|
||||||
auto notUtf8 = []( const QString& s ) {
|
|
||||||
return !s.contains( "UTF-8", Qt::CaseInsensitive ) && !s.contains( "utf8", Qt::CaseInsensitive );
|
|
||||||
};
|
|
||||||
auto it = std::remove_if( m_localeGenLines.begin(), m_localeGenLines.end(), notUtf8 );
|
|
||||||
m_localeGenLines.erase( it, m_localeGenLines.end() );
|
|
||||||
|
|
||||||
// We strip " UTF-8" from "en_US.UTF-8 UTF-8" because it's redundant redundant.
|
|
||||||
// Also simplify whitespace.
|
|
||||||
auto unredundant = []( QString& s ) {
|
|
||||||
if ( s.endsWith( " UTF-8" ) )
|
|
||||||
{
|
|
||||||
s.chop( 6 );
|
|
||||||
}
|
|
||||||
s = s.simplified();
|
|
||||||
};
|
|
||||||
std::for_each( m_localeGenLines.begin(), m_localeGenLines.end(), unredundant );
|
|
||||||
|
|
||||||
updateGlobalStorage();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair< QString, QString >
|
|
||||||
LocalePage::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() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
QString
|
|
||||||
LocalePage::prettyStatus() const
|
|
||||||
{
|
|
||||||
QString status;
|
|
||||||
status += tr( "Set timezone to %1/%2.<br/>" ).arg( m_regionCombo->currentText() ).arg( m_zoneCombo->currentText() );
|
|
||||||
|
|
||||||
LocaleConfiguration lc
|
|
||||||
= m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration() : m_selectedLocaleConfiguration;
|
|
||||||
auto labels = prettyLocaleStatus( lc );
|
|
||||||
status += labels.first + "<br/>";
|
|
||||||
status += labels.second + "<br/>";
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Calamares::JobList
|
|
||||||
LocalePage::createJobs()
|
|
||||||
{
|
|
||||||
QList< Calamares::job_ptr > list;
|
|
||||||
const CalamaresUtils::Locale::TZZone* location = m_tzWidget->currentLocation();
|
|
||||||
|
|
||||||
Calamares::Job* j = new SetTimezoneJob( location->region(), location->zone() );
|
|
||||||
list.append( Calamares::job_ptr( j ) );
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QMap< QString, QString >
|
|
||||||
LocalePage::localesMap()
|
|
||||||
{
|
|
||||||
return m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration().toMap()
|
|
||||||
: m_selectedLocaleConfiguration.toMap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -304,82 +142,10 @@ void
|
|||||||
LocalePage::onActivate()
|
LocalePage::onActivate()
|
||||||
{
|
{
|
||||||
m_regionCombo->setFocus();
|
m_regionCombo->setFocus();
|
||||||
if ( m_selectedLocaleConfiguration.isEmpty() || !m_selectedLocaleConfiguration.explicit_lang )
|
|
||||||
{
|
|
||||||
auto newLocale = guessLocaleConfiguration();
|
|
||||||
m_selectedLocaleConfiguration.setLanguage( newLocale.language() );
|
|
||||||
updateGlobalLocale();
|
|
||||||
updateLocaleLabels();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LocaleConfiguration
|
|
||||||
LocalePage::guessLocaleConfiguration() const
|
|
||||||
{
|
|
||||||
return LocaleConfiguration::fromLanguageAndLocation(
|
|
||||||
QLocale().name(), m_localeGenLines, m_tzWidget->currentLocation()->country() );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
LocalePage::updateGlobalLocale()
|
|
||||||
{
|
|
||||||
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
|
||||||
const QString bcp47 = m_selectedLocaleConfiguration.toBcp47();
|
|
||||||
gs->insert( "locale", bcp47 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
LocalePage::updateGlobalStorage()
|
|
||||||
{
|
|
||||||
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
|
||||||
|
|
||||||
const auto* location = m_tzWidget->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();
|
updateLocaleLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
LocalePage::regionChanged( int currentIndex )
|
LocalePage::regionChanged( int currentIndex )
|
||||||
{
|
{
|
||||||
@ -388,15 +154,17 @@ LocalePage::regionChanged( int currentIndex )
|
|||||||
Q_UNUSED( currentIndex )
|
Q_UNUSED( currentIndex )
|
||||||
QString selectedRegion = m_regionCombo->currentData().toString();
|
QString selectedRegion = m_regionCombo->currentData().toString();
|
||||||
|
|
||||||
TZRegion* region = m_regionList.find< TZRegion >( selectedRegion );
|
TZRegion* region = m_config->timezoneData().find< TZRegion >( selectedRegion );
|
||||||
if ( !region )
|
if ( !region )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_zoneCombo->blockSignals( true );
|
{
|
||||||
m_zoneCombo->setModel( new CStringListModel( region->zones() ) );
|
cSignalBlocker b( m_zoneCombo );
|
||||||
m_zoneCombo->blockSignals( false );
|
m_zoneCombo->setModel( new CStringListModel( region->zones() ) );
|
||||||
|
}
|
||||||
|
|
||||||
m_zoneCombo->currentIndexChanged( m_zoneCombo->currentIndex() );
|
m_zoneCombo->currentIndexChanged( m_zoneCombo->currentIndex() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,16 +173,19 @@ LocalePage::zoneChanged( int currentIndex )
|
|||||||
{
|
{
|
||||||
Q_UNUSED( currentIndex )
|
Q_UNUSED( currentIndex )
|
||||||
if ( !m_blockTzWidgetSet )
|
if ( !m_blockTzWidgetSet )
|
||||||
m_tzWidget->setCurrentLocation( m_regionCombo->currentData().toString(),
|
{
|
||||||
m_zoneCombo->currentData().toString() );
|
m_config->setCurrentLocation( m_regionCombo->currentData().toString(), m_zoneCombo->currentData().toString() );
|
||||||
|
}
|
||||||
updateGlobalStorage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LocalePage::locationChanged( const CalamaresUtils::Locale::TZZone* location )
|
LocalePage::locationChanged( const CalamaresUtils::Locale::TZZone* location )
|
||||||
{
|
{
|
||||||
m_blockTzWidgetSet = true;
|
if ( !location )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cBoolSetter< true > b( m_blockTzWidgetSet );
|
||||||
|
|
||||||
// Set region index
|
// Set region index
|
||||||
int index = m_regionCombo->findData( location->region() );
|
int index = m_regionCombo->findData( location->region() );
|
||||||
@ -433,58 +204,35 @@ LocalePage::locationChanged( const CalamaresUtils::Locale::TZZone* location )
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_zoneCombo->setCurrentIndex( index );
|
m_zoneCombo->setCurrentIndex( index );
|
||||||
|
|
||||||
m_blockTzWidgetSet = false;
|
|
||||||
|
|
||||||
updateGlobalStorage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LocalePage::changeLocale()
|
LocalePage::changeLocale()
|
||||||
{
|
{
|
||||||
LCLocaleDialog* dlg
|
QPointer< LCLocaleDialog > dlg(
|
||||||
= new LCLocaleDialog( m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration().language()
|
new LCLocaleDialog( m_config->localeConfiguration().language(), m_config->supportedLocales(), this ) );
|
||||||
: m_selectedLocaleConfiguration.language(),
|
|
||||||
m_localeGenLines,
|
|
||||||
this );
|
|
||||||
dlg->exec();
|
dlg->exec();
|
||||||
if ( dlg->result() == QDialog::Accepted && !dlg->selectedLCLocale().isEmpty() )
|
if ( dlg && dlg->result() == QDialog::Accepted && !dlg->selectedLCLocale().isEmpty() )
|
||||||
{
|
{
|
||||||
m_selectedLocaleConfiguration.setLanguage( dlg->selectedLCLocale() );
|
m_config->setLanguageExplicitly( dlg->selectedLCLocale() );
|
||||||
m_selectedLocaleConfiguration.explicit_lang = true;
|
updateLocaleLabels();
|
||||||
this->updateGlobalLocale();
|
|
||||||
this->updateLocaleLabels();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dlg->deleteLater();
|
delete dlg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
LocalePage::changeFormats()
|
LocalePage::changeFormats()
|
||||||
{
|
{
|
||||||
LCLocaleDialog* dlg
|
QPointer< LCLocaleDialog > dlg(
|
||||||
= new LCLocaleDialog( m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration().lc_numeric
|
new LCLocaleDialog( m_config->localeConfiguration().lc_numeric, m_config->supportedLocales(), this ) );
|
||||||
: m_selectedLocaleConfiguration.lc_numeric,
|
|
||||||
m_localeGenLines,
|
|
||||||
this );
|
|
||||||
dlg->exec();
|
dlg->exec();
|
||||||
if ( dlg->result() == QDialog::Accepted && !dlg->selectedLCLocale().isEmpty() )
|
if ( dlg && dlg->result() == QDialog::Accepted && !dlg->selectedLCLocale().isEmpty() )
|
||||||
{
|
{
|
||||||
// TODO: improve the granularity of this setting.
|
m_config->setLCLocaleExplicitly( dlg->selectedLCLocale() );
|
||||||
m_selectedLocaleConfiguration.lc_numeric = dlg->selectedLCLocale();
|
updateLocaleLabels();
|
||||||
m_selectedLocaleConfiguration.lc_time = dlg->selectedLCLocale();
|
|
||||||
m_selectedLocaleConfiguration.lc_monetary = dlg->selectedLCLocale();
|
|
||||||
m_selectedLocaleConfiguration.lc_paper = dlg->selectedLCLocale();
|
|
||||||
m_selectedLocaleConfiguration.lc_name = dlg->selectedLCLocale();
|
|
||||||
m_selectedLocaleConfiguration.lc_address = dlg->selectedLCLocale();
|
|
||||||
m_selectedLocaleConfiguration.lc_telephone = dlg->selectedLCLocale();
|
|
||||||
m_selectedLocaleConfiguration.lc_measurement = dlg->selectedLCLocale();
|
|
||||||
m_selectedLocaleConfiguration.lc_identification = dlg->selectedLCLocale();
|
|
||||||
m_selectedLocaleConfiguration.explicit_lc = true;
|
|
||||||
|
|
||||||
this->updateLocaleLabels();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dlg->deleteLater();
|
delete dlg;
|
||||||
}
|
}
|
||||||
|
@ -32,39 +32,23 @@
|
|||||||
class QComboBox;
|
class QComboBox;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
|
|
||||||
|
class Config;
|
||||||
class TimeZoneWidget;
|
class TimeZoneWidget;
|
||||||
|
|
||||||
class LocalePage : public QWidget
|
class LocalePage : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit LocalePage( QWidget* parent = nullptr );
|
explicit LocalePage( class Config* config, QWidget* parent = nullptr );
|
||||||
virtual ~LocalePage();
|
virtual ~LocalePage();
|
||||||
|
|
||||||
void init( const QString& initialRegion, const QString& initialZone, const QString& localeGenPath );
|
|
||||||
|
|
||||||
QString prettyStatus() const;
|
|
||||||
|
|
||||||
Calamares::JobList createJobs();
|
|
||||||
|
|
||||||
QMap< QString, QString > localesMap();
|
|
||||||
|
|
||||||
void onActivate();
|
void onActivate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LocaleConfiguration guessLocaleConfiguration() const;
|
/// @brief Non-owning pointer to the ViewStep's config
|
||||||
|
Config* m_config;
|
||||||
|
|
||||||
// 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();
|
void updateLocaleLabels();
|
||||||
|
|
||||||
void regionChanged( int currentIndex );
|
void regionChanged( int currentIndex );
|
||||||
@ -73,10 +57,6 @@ private:
|
|||||||
void changeLocale();
|
void changeLocale();
|
||||||
void changeFormats();
|
void changeFormats();
|
||||||
|
|
||||||
// Dynamically, QList< TZRegion* >
|
|
||||||
CalamaresUtils::Locale::CStringPairList m_regionList;
|
|
||||||
std::unique_ptr< CalamaresUtils::Locale::CStringListModel > m_regionModel;
|
|
||||||
|
|
||||||
TimeZoneWidget* m_tzWidget;
|
TimeZoneWidget* m_tzWidget;
|
||||||
QComboBox* m_regionCombo;
|
QComboBox* m_regionCombo;
|
||||||
QComboBox* m_zoneCombo;
|
QComboBox* m_zoneCombo;
|
||||||
@ -88,9 +68,6 @@ private:
|
|||||||
QLabel* m_formatsLabel;
|
QLabel* m_formatsLabel;
|
||||||
QPushButton* m_formatsChangeButton;
|
QPushButton* m_formatsChangeButton;
|
||||||
|
|
||||||
LocaleConfiguration m_selectedLocaleConfiguration;
|
|
||||||
|
|
||||||
QStringList m_localeGenLines;
|
|
||||||
|
|
||||||
bool m_blockTzWidgetSet;
|
bool m_blockTzWidgetSet;
|
||||||
};
|
};
|
||||||
|
@ -34,7 +34,6 @@
|
|||||||
|
|
||||||
#include <QBoxLayout>
|
#include <QBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QtConcurrent/QtConcurrentRun>
|
|
||||||
|
|
||||||
|
|
||||||
CALAMARES_PLUGIN_FACTORY_DEFINITION( LocaleViewStepFactory, registerPlugin< LocaleViewStep >(); )
|
CALAMARES_PLUGIN_FACTORY_DEFINITION( LocaleViewStepFactory, registerPlugin< LocaleViewStep >(); )
|
||||||
@ -44,7 +43,7 @@ LocaleViewStep::LocaleViewStep( QObject* parent )
|
|||||||
, m_widget( new QWidget() )
|
, m_widget( new QWidget() )
|
||||||
, m_actualWidget( nullptr )
|
, m_actualWidget( nullptr )
|
||||||
, m_nextEnabled( false )
|
, m_nextEnabled( false )
|
||||||
, m_geoip( nullptr )
|
, m_config( std::make_unique< Config >() )
|
||||||
{
|
{
|
||||||
QBoxLayout* mainLayout = new QHBoxLayout;
|
QBoxLayout* mainLayout = new QHBoxLayout;
|
||||||
m_widget->setLayout( mainLayout );
|
m_widget->setLayout( mainLayout );
|
||||||
@ -66,11 +65,11 @@ LocaleViewStep::~LocaleViewStep()
|
|||||||
void
|
void
|
||||||
LocaleViewStep::setUpPage()
|
LocaleViewStep::setUpPage()
|
||||||
{
|
{
|
||||||
|
m_config->setCurrentLocation();
|
||||||
if ( !m_actualWidget )
|
if ( !m_actualWidget )
|
||||||
{
|
{
|
||||||
m_actualWidget = new LocalePage();
|
m_actualWidget = new LocalePage( m_config.get() );
|
||||||
}
|
}
|
||||||
m_actualWidget->init( m_startingTimezone.first, m_startingTimezone.second, m_localeGenPath );
|
|
||||||
m_widget->layout()->addWidget( m_actualWidget );
|
m_widget->layout()->addWidget( m_actualWidget );
|
||||||
|
|
||||||
ensureSize( m_actualWidget->sizeHint() );
|
ensureSize( m_actualWidget->sizeHint() );
|
||||||
@ -80,20 +79,6 @@ LocaleViewStep::setUpPage()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
LocaleViewStep::fetchGeoIpTimezone()
|
|
||||||
{
|
|
||||||
if ( m_geoip && m_geoip->isValid() )
|
|
||||||
{
|
|
||||||
m_startingTimezone = m_geoip->get();
|
|
||||||
if ( !m_startingTimezone.isValid() )
|
|
||||||
{
|
|
||||||
cWarning() << "GeoIP lookup at" << m_geoip->url() << "failed.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QString
|
QString
|
||||||
LocaleViewStep::prettyName() const
|
LocaleViewStep::prettyName() const
|
||||||
{
|
{
|
||||||
@ -104,7 +89,7 @@ LocaleViewStep::prettyName() const
|
|||||||
QString
|
QString
|
||||||
LocaleViewStep::prettyStatus() const
|
LocaleViewStep::prettyStatus() const
|
||||||
{
|
{
|
||||||
return m_prettyStatus;
|
return m_config->prettyStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -146,7 +131,7 @@ LocaleViewStep::isAtEnd() const
|
|||||||
Calamares::JobList
|
Calamares::JobList
|
||||||
LocaleViewStep::jobs() const
|
LocaleViewStep::jobs() const
|
||||||
{
|
{
|
||||||
return m_jobs;
|
return m_config->createJobs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -164,83 +149,11 @@ LocaleViewStep::onActivate()
|
|||||||
void
|
void
|
||||||
LocaleViewStep::onLeave()
|
LocaleViewStep::onLeave()
|
||||||
{
|
{
|
||||||
if ( m_actualWidget )
|
|
||||||
{
|
|
||||||
m_jobs = m_actualWidget->createJobs();
|
|
||||||
m_prettyStatus = m_actualWidget->prettyStatus();
|
|
||||||
|
|
||||||
auto map = m_actualWidget->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
|
void
|
||||||
LocaleViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
LocaleViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||||
{
|
{
|
||||||
QString region = CalamaresUtils::getString( configurationMap, "region" );
|
m_config->setConfigurationMap( configurationMap );
|
||||||
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.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Calamares::RequirementsList
|
|
||||||
LocaleViewStep::checkRequirements()
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
@ -20,15 +20,11 @@
|
|||||||
#ifndef LOCALEVIEWSTEP_H
|
#ifndef LOCALEVIEWSTEP_H
|
||||||
#define LOCALEVIEWSTEP_H
|
#define LOCALEVIEWSTEP_H
|
||||||
|
|
||||||
#include "geoip/Handler.h"
|
#include "Config.h"
|
||||||
#include "geoip/Interface.h"
|
|
||||||
#include "utils/PluginFactory.h"
|
|
||||||
#include "viewpages/ViewStep.h"
|
|
||||||
|
|
||||||
#include "DllMacro.h"
|
#include "DllMacro.h"
|
||||||
|
#include "utils/PluginFactory.h"
|
||||||
#include <QFutureWatcher>
|
#include "viewpages/ViewStep.h"
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -60,25 +56,16 @@ public:
|
|||||||
|
|
||||||
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
||||||
|
|
||||||
/// @brief Do setup (returns empty list) asynchronously
|
|
||||||
virtual Calamares::RequirementsList checkRequirements() override;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void setUpPage();
|
void setUpPage();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void fetchGeoIpTimezone();
|
|
||||||
QWidget* m_widget;
|
QWidget* m_widget;
|
||||||
|
|
||||||
LocalePage* m_actualWidget;
|
LocalePage* m_actualWidget;
|
||||||
bool m_nextEnabled;
|
bool m_nextEnabled;
|
||||||
QString m_prettyStatus;
|
|
||||||
|
|
||||||
CalamaresUtils::GeoIP::RegionZonePair m_startingTimezone;
|
std::unique_ptr< Config > m_config;
|
||||||
QString m_localeGenPath;
|
|
||||||
|
|
||||||
Calamares::JobList m_jobs;
|
|
||||||
std::unique_ptr< CalamaresUtils::GeoIP::Handler > m_geoip;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( LocaleViewStepFactory )
|
CALAMARES_PLUGIN_FACTORY_DECLARATION( LocaleViewStepFactory )
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
# This settings are used to set your default system time zone.
|
# These settings are used to set your default system time zone.
|
||||||
# Time zones are usually located under /usr/share/zoneinfo and
|
# Time zones are usually located under /usr/share/zoneinfo and
|
||||||
# provided by the 'tzdata' package of your Distribution.
|
# provided by the 'tzdata' package of your Distribution.
|
||||||
#
|
#
|
||||||
@ -11,20 +11,41 @@
|
|||||||
# the locale page can be set through keys *region* and *zone*.
|
# the locale page can be set through keys *region* and *zone*.
|
||||||
# If either is not set, defaults to America/New_York.
|
# If either is not set, defaults to America/New_York.
|
||||||
#
|
#
|
||||||
|
# Note that useSystemTimezone and GeoIP settings can change the
|
||||||
|
# starting time zone.
|
||||||
|
#
|
||||||
region: "America"
|
region: "America"
|
||||||
zone: "New_York"
|
zone: "New_York"
|
||||||
|
|
||||||
|
# Instead of using *region* and *zone* specified above,
|
||||||
|
# you can use the system's notion of the timezone, instead.
|
||||||
|
# This can help if your system is automatically configured with
|
||||||
|
# a sensible TZ rather than chasing a fixed default.
|
||||||
|
#
|
||||||
|
# The default is false.
|
||||||
|
#
|
||||||
|
# useSystemTimezone: true
|
||||||
|
|
||||||
|
# Should changing the system location (e.g. clicking around on the timezone
|
||||||
|
# map) immediately reflect the changed timezone in the live system?
|
||||||
|
# By default, installers (with a target system) do, and setup (e.g. OEM
|
||||||
|
# configuration) does not, but you can switch it on here (or off, if
|
||||||
|
# you think it's annoying in the installer).
|
||||||
|
#
|
||||||
|
# Note that not all systems support live adjustment.
|
||||||
|
#
|
||||||
|
# adjustLiveTimezone: true
|
||||||
|
|
||||||
# System locales are detected in the following order:
|
# System locales are detected in the following order:
|
||||||
#
|
#
|
||||||
# - /usr/share/i18n/SUPPORTED
|
# - /usr/share/i18n/SUPPORTED
|
||||||
# - localeGenPath (defaults to /etc/locale.gen if not set)
|
# - localeGenPath (defaults to /etc/locale.gen if not set)
|
||||||
# - 'locale -a' output
|
# - `locale -a` output
|
||||||
#
|
#
|
||||||
# Enable only when your Distribution is using an
|
# Enable only when your Distribution is using a
|
||||||
# custom path for locale.gen
|
# custom path for locale.gen
|
||||||
#
|
#
|
||||||
#localeGenPath: "PATH_TO/locale.gen"
|
#localeGenPath: "/etc/locale.gen"
|
||||||
|
|
||||||
# GeoIP based Language settings: Leave commented out to disable GeoIP.
|
# GeoIP based Language settings: Leave commented out to disable GeoIP.
|
||||||
#
|
#
|
||||||
|
@ -4,7 +4,35 @@ $id: https://calamares.io/schemas/locale
|
|||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
"region": { type: str }
|
region: { type: string,
|
||||||
"zone": { type: str }
|
enum: [
|
||||||
"localeGenPath": { type: string, required: true }
|
Africa,
|
||||||
"geoipUrl": { type: str }
|
America,
|
||||||
|
Antarctica,
|
||||||
|
Arctic,
|
||||||
|
Asia,
|
||||||
|
Atlantic,
|
||||||
|
Australia,
|
||||||
|
Europe,
|
||||||
|
Indian,
|
||||||
|
Pacific
|
||||||
|
]
|
||||||
|
}
|
||||||
|
zone: { type: string }
|
||||||
|
useSystemTimezone: { type: boolean, default: false }
|
||||||
|
|
||||||
|
adjustLiveTimezone: { type: boolean, default: true }
|
||||||
|
|
||||||
|
localeGenPath: { type: string }
|
||||||
|
|
||||||
|
# TODO: refactor, this is reused in welcome
|
||||||
|
geoip:
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
style: { type: string, enum: [ none, fixed, xml, json ] }
|
||||||
|
url: { type: string }
|
||||||
|
selector: { type: string }
|
||||||
|
required: [ style, url, selector ]
|
||||||
|
|
||||||
|
required: [ region, zone ]
|
||||||
|
@ -25,9 +25,9 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
static const char* zoneNames[]
|
static const char* zoneNames[]
|
||||||
= { "0.0", "1.0", "2.0", "3.0", "3.5", "4.0", "4.5", "5.0", "5.5", "5.75", "6.0", "6.5", "7.0",
|
= { "0.0", "1.0", "2.0", "3.0", "3.5", "4.0", "4.5", "5.0", "5.5", "5.75", "6.0", "6.5", "7.0",
|
||||||
"8.0", "9.0", "9.5", "10.0", "10.5", "11.0", "12.0", "12.75", "13.0", "-1.0", "-2.0", "-3.0",
|
"8.0", "9.0", "9.5", "10.0", "10.5", "11.0", "12.0", "12.75", "13.0", "-1.0", "-2.0", "-3.0", "-3.5",
|
||||||
"-3.5", "-4.0", "-4.5", "-5.0", "-5.5", "-6.0", "-7.0", "-8.0", "-9.0", "-9.5", "-10.0", "-11.0" };
|
"-4.0", "-4.5", "-5.0", "-5.5", "-6.0", "-7.0", "-8.0", "-9.0", "-9.5", "-10.0", "-11.0" };
|
||||||
static_assert( TimeZoneImageList::zoneCount == ( sizeof( zoneNames ) / sizeof( zoneNames[ 0 ] ) ),
|
static_assert( TimeZoneImageList::zoneCount == ( sizeof( zoneNames ) / sizeof( zoneNames[ 0 ] ) ),
|
||||||
"Incorrect number of zones" );
|
"Incorrect number of zones" );
|
||||||
|
|
||||||
|
@ -34,9 +34,17 @@
|
|||||||
#define ZONE_NAME QStringLiteral( "zone" )
|
#define ZONE_NAME QStringLiteral( "zone" )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TimeZoneWidget::TimeZoneWidget( QWidget* parent )
|
static QPoint
|
||||||
|
getLocationPosition( const CalamaresUtils::Locale::TZZone* l )
|
||||||
|
{
|
||||||
|
return TimeZoneImageList::getLocationPosition( l->longitude(), l->latitude() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TimeZoneWidget::TimeZoneWidget( const CalamaresUtils::Locale::CStringPairList& zones, QWidget* parent )
|
||||||
: QWidget( parent )
|
: QWidget( parent )
|
||||||
, timeZoneImages( TimeZoneImageList::fromQRC() )
|
, timeZoneImages( TimeZoneImageList::fromQRC() )
|
||||||
|
, m_zonesData( zones )
|
||||||
{
|
{
|
||||||
setMouseTracking( false );
|
setMouseTracking( false );
|
||||||
setCursor( Qt::PointingHandCursor );
|
setCursor( Qt::PointingHandCursor );
|
||||||
@ -57,27 +65,13 @@ TimeZoneWidget::TimeZoneWidget( QWidget* parent )
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TimeZoneWidget::setCurrentLocation( QString regionName, QString zoneName )
|
TimeZoneWidget::setCurrentLocation( const CalamaresUtils::Locale::TZZone* location )
|
||||||
{
|
{
|
||||||
using namespace CalamaresUtils::Locale;
|
if ( location == m_currentLocation )
|
||||||
const auto& regions = TZRegion::fromZoneTab();
|
|
||||||
auto* region = regions.find< TZRegion >( regionName );
|
|
||||||
if ( !region )
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* zone = region->zones().find< TZZone >( zoneName );
|
|
||||||
if ( zone )
|
|
||||||
{
|
|
||||||
setCurrentLocation( zone );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TimeZoneWidget::setCurrentLocation( const CalamaresUtils::Locale::TZZone* location )
|
|
||||||
{
|
|
||||||
m_currentLocation = location;
|
m_currentLocation = location;
|
||||||
|
|
||||||
// Set zone
|
// Set zone
|
||||||
@ -93,7 +87,6 @@ TimeZoneWidget::setCurrentLocation( const CalamaresUtils::Locale::TZZone* locati
|
|||||||
|
|
||||||
// Repaint widget
|
// Repaint widget
|
||||||
repaint();
|
repaint();
|
||||||
emit locationChanged( m_currentLocation );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -101,11 +94,18 @@ TimeZoneWidget::setCurrentLocation( const CalamaresUtils::Locale::TZZone* locati
|
|||||||
//### Private
|
//### Private
|
||||||
//###
|
//###
|
||||||
|
|
||||||
|
struct PainterEnder
|
||||||
|
{
|
||||||
|
QPainter& p;
|
||||||
|
~PainterEnder() { p.end(); }
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
TimeZoneWidget::paintEvent( QPaintEvent* )
|
TimeZoneWidget::paintEvent( QPaintEvent* )
|
||||||
{
|
{
|
||||||
QFontMetrics fontMetrics( font );
|
QFontMetrics fontMetrics( font );
|
||||||
QPainter painter( this );
|
QPainter painter( this );
|
||||||
|
PainterEnder painter_end { painter };
|
||||||
|
|
||||||
painter.setRenderHint( QPainter::Antialiasing );
|
painter.setRenderHint( QPainter::Antialiasing );
|
||||||
painter.setFont( font );
|
painter.setFont( font );
|
||||||
@ -116,6 +116,11 @@ TimeZoneWidget::paintEvent( QPaintEvent* )
|
|||||||
// Draw zone image
|
// Draw zone image
|
||||||
painter.drawImage( 0, 0, currentZoneImage );
|
painter.drawImage( 0, 0, currentZoneImage );
|
||||||
|
|
||||||
|
if ( !m_currentLocation )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_TIMEZONES
|
#ifdef DEBUG_TIMEZONES
|
||||||
QPoint point = getLocationPosition( m_currentLocation );
|
QPoint point = getLocationPosition( m_currentLocation );
|
||||||
// Draw latitude lines
|
// Draw latitude lines
|
||||||
@ -175,8 +180,6 @@ TimeZoneWidget::paintEvent( QPaintEvent* )
|
|||||||
painter.setPen( Qt::white );
|
painter.setPen( Qt::white );
|
||||||
painter.drawText( rect.x() + 5, rect.bottom() - 4, m_currentLocation ? m_currentLocation->tr() : QString() );
|
painter.drawText( rect.x() + 5, rect.bottom() - 4, m_currentLocation ? m_currentLocation->tr() : QString() );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
painter.end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -194,7 +197,7 @@ TimeZoneWidget::mousePressEvent( QMouseEvent* event )
|
|||||||
|
|
||||||
using namespace CalamaresUtils::Locale;
|
using namespace CalamaresUtils::Locale;
|
||||||
const TZZone* closest = nullptr;
|
const TZZone* closest = nullptr;
|
||||||
for ( const auto* region_p : TZRegion::fromZoneTab() )
|
for ( const auto* region_p : m_zonesData )
|
||||||
{
|
{
|
||||||
const auto* region = dynamic_cast< const TZRegion* >( region_p );
|
const auto* region = dynamic_cast< const TZRegion* >( region_p );
|
||||||
if ( region )
|
if ( region )
|
||||||
@ -222,6 +225,6 @@ TimeZoneWidget::mousePressEvent( QMouseEvent* event )
|
|||||||
// Set zone image and repaint widget
|
// Set zone image and repaint widget
|
||||||
setCurrentLocation( closest );
|
setCurrentLocation( closest );
|
||||||
// Emit signal
|
// Emit signal
|
||||||
emit locationChanged( m_currentLocation );
|
emit locationChanged( closest );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,32 +31,48 @@
|
|||||||
#include <QFont>
|
#include <QFont>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
/** @brief The TimeZoneWidget shows a map and reports where clicks happen
|
||||||
|
*
|
||||||
|
* This widget shows a map (unspecified whether it's a whole world map
|
||||||
|
* or can show regionsvia some kind of internal state). Mouse clicks are
|
||||||
|
* translated into timezone locations (e.g. the zone for America/New_York).
|
||||||
|
*
|
||||||
|
* The current location can be changed programmatically, by name
|
||||||
|
* or through a pointer to a location. If a pointer is used, take care
|
||||||
|
* that the pointer is to a zone in the same model as used by the
|
||||||
|
* widget.
|
||||||
|
*
|
||||||
|
* When a location is chosen -- by mouse click or programmatically --
|
||||||
|
* the locationChanged() signal is emitted with the new location.
|
||||||
|
*
|
||||||
|
* NOTE: the widget currently uses the globally cached TZRegion::fromZoneTab()
|
||||||
|
*/
|
||||||
class TimeZoneWidget : public QWidget
|
class TimeZoneWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
using TZZone = CalamaresUtils::Locale::TZZone;
|
using TZZone = CalamaresUtils::Locale::TZZone;
|
||||||
|
|
||||||
explicit TimeZoneWidget( QWidget* parent = nullptr );
|
explicit TimeZoneWidget( const CalamaresUtils::Locale::CStringPairList& zones, QWidget* parent = nullptr );
|
||||||
|
|
||||||
void setCurrentLocation( QString region, QString zone );
|
public Q_SLOTS:
|
||||||
|
/** @brief Sets a location by pointer
|
||||||
|
*
|
||||||
|
* Pointer should be within the same model as the widget uses.
|
||||||
|
*/
|
||||||
void setCurrentLocation( const TZZone* location );
|
void setCurrentLocation( const TZZone* location );
|
||||||
const TZZone* currentLocation() { return m_currentLocation; }
|
|
||||||
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
/** @brief The location has changed by mouse click */
|
||||||
void locationChanged( const TZZone* location );
|
void locationChanged( const TZZone* location );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QFont font;
|
QFont font;
|
||||||
QImage background, pin, currentZoneImage;
|
QImage background, pin, currentZoneImage;
|
||||||
TimeZoneImageList timeZoneImages;
|
TimeZoneImageList timeZoneImages;
|
||||||
const TZZone* m_currentLocation = nullptr; // Not owned by me
|
|
||||||
|
|
||||||
QPoint getLocationPosition( const TZZone* l )
|
const CalamaresUtils::Locale::CStringPairList& m_zonesData;
|
||||||
{
|
const TZZone* m_currentLocation = nullptr; // Not owned by me
|
||||||
return timeZoneImages.getLocationPosition( l->longitude(), l->latitude() );
|
|
||||||
}
|
|
||||||
|
|
||||||
void paintEvent( QPaintEvent* event );
|
void paintEvent( QPaintEvent* event );
|
||||||
void mousePressEvent( QMouseEvent* event );
|
void mousePressEvent( QMouseEvent* event );
|
||||||
|
@ -19,74 +19,20 @@
|
|||||||
|
|
||||||
#include "LocaleQmlViewStep.h"
|
#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/Logger.h"
|
||||||
#include "utils/Variant.h"
|
|
||||||
#include "utils/Yaml.h"
|
|
||||||
|
|
||||||
#include "Branding.h"
|
|
||||||
#include "modulesystem/ModuleManager.h"
|
|
||||||
#include <QQmlEngine>
|
|
||||||
#include <QFutureWatcher>
|
|
||||||
#include <QPixmap>
|
|
||||||
#include <QVariant>
|
|
||||||
|
|
||||||
CALAMARES_PLUGIN_FACTORY_DEFINITION( LocaleQmlViewStepFactory, registerPlugin< LocaleQmlViewStep >(); )
|
CALAMARES_PLUGIN_FACTORY_DEFINITION( LocaleQmlViewStepFactory, registerPlugin< LocaleQmlViewStep >(); )
|
||||||
|
|
||||||
LocaleQmlViewStep::LocaleQmlViewStep( QObject* parent )
|
LocaleQmlViewStep::LocaleQmlViewStep( QObject* parent )
|
||||||
: Calamares::QmlViewStep( parent )
|
: Calamares::QmlViewStep( parent )
|
||||||
, m_config( new Config( this ) )
|
, m_config( std::make_unique< Config >( this ) )
|
||||||
, m_nextEnabled( false )
|
|
||||||
, m_geoip( nullptr )
|
|
||||||
{
|
{
|
||||||
emit nextStatusChanged( m_nextEnabled );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject*
|
QObject*
|
||||||
LocaleQmlViewStep::getConfig()
|
LocaleQmlViewStep::getConfig()
|
||||||
{
|
{
|
||||||
return m_config;
|
return m_config.get();
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
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
|
QString
|
||||||
@ -95,17 +41,21 @@ LocaleQmlViewStep::prettyName() const
|
|||||||
return tr( "Location" );
|
return tr( "Location" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
LocaleQmlViewStep::prettyStatus() const
|
||||||
|
{
|
||||||
|
return m_config->prettyStatus();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LocaleQmlViewStep::isNextEnabled() const
|
LocaleQmlViewStep::isNextEnabled() const
|
||||||
{
|
{
|
||||||
// TODO: should return true
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LocaleQmlViewStep::isBackEnabled() const
|
LocaleQmlViewStep::isBackEnabled() const
|
||||||
{
|
{
|
||||||
// TODO: should return true (it's weird that you are not allowed to have welcome *after* anything
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +63,6 @@ LocaleQmlViewStep::isBackEnabled() const
|
|||||||
bool
|
bool
|
||||||
LocaleQmlViewStep::isAtBeginning() const
|
LocaleQmlViewStep::isAtBeginning() const
|
||||||
{
|
{
|
||||||
// TODO: adjust to "pages" in the QML
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,79 +70,18 @@ LocaleQmlViewStep::isAtBeginning() const
|
|||||||
bool
|
bool
|
||||||
LocaleQmlViewStep::isAtEnd() const
|
LocaleQmlViewStep::isAtEnd() const
|
||||||
{
|
{
|
||||||
// TODO: adjust to "pages" in the QML
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Calamares::JobList
|
Calamares::JobList
|
||||||
LocaleQmlViewStep::jobs() const
|
LocaleQmlViewStep::jobs() const
|
||||||
{
|
{
|
||||||
return m_jobs;
|
return m_config->createJobs();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocaleQmlViewStep::onActivate()
|
void
|
||||||
|
LocaleQmlViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||||
{
|
{
|
||||||
// TODO no sure if it is needed at all or for the abstract class to start something
|
m_config->setConfigurationMap( configurationMap );
|
||||||
}
|
Calamares::QmlViewStep::setConfigurationMap( configurationMap ); // call parent implementation last
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,10 @@
|
|||||||
#define LOCALE_QMLVIEWSTEP_H
|
#define LOCALE_QMLVIEWSTEP_H
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "geoip/Handler.h"
|
|
||||||
#include "geoip/Interface.h"
|
#include "DllMacro.h"
|
||||||
#include "utils/PluginFactory.h"
|
#include "utils/PluginFactory.h"
|
||||||
#include "viewpages/QmlViewStep.h"
|
#include "viewpages/QmlViewStep.h"
|
||||||
#include <DllMacro.h>
|
|
||||||
|
|
||||||
#include <QFutureWatcher>
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -39,6 +35,7 @@ public:
|
|||||||
explicit LocaleQmlViewStep( QObject* parent = nullptr );
|
explicit LocaleQmlViewStep( QObject* parent = nullptr );
|
||||||
|
|
||||||
QString prettyName() const override;
|
QString prettyName() const override;
|
||||||
|
QString prettyStatus() const override;
|
||||||
|
|
||||||
bool isNextEnabled() const override;
|
bool isNextEnabled() const override;
|
||||||
bool isBackEnabled() const override;
|
bool isBackEnabled() const override;
|
||||||
@ -47,28 +44,12 @@ public:
|
|||||||
bool isAtEnd() const override;
|
bool isAtEnd() const override;
|
||||||
|
|
||||||
Calamares::JobList jobs() const override;
|
Calamares::JobList jobs() const override;
|
||||||
void onActivate() override;
|
|
||||||
void onLeave() override;
|
|
||||||
|
|
||||||
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
||||||
QObject* getConfig() override;
|
QObject* getConfig() override;
|
||||||
|
|
||||||
virtual Calamares::RequirementsList checkRequirements() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO: a generic QML viewstep should return a config object from a method
|
std::unique_ptr< Config > m_config;
|
||||||
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 )
|
CALAMARES_PLUGIN_FACTORY_DECLARATION( LocaleQmlViewStepFactory )
|
||||||
|
@ -74,6 +74,7 @@ Column {
|
|||||||
var tz2 = responseJSON.timezoneId
|
var tz2 = responseJSON.timezoneId
|
||||||
|
|
||||||
tzText.text = "Timezone: " + tz2
|
tzText.text = "Timezone: " + tz2
|
||||||
|
config.setCurrentLocation(tz2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +127,7 @@ Column {
|
|||||||
anchorPoint.x: image.width/4
|
anchorPoint.x: image.width/4
|
||||||
anchorPoint.y: image.height
|
anchorPoint.y: image.height
|
||||||
coordinate: QtPositioning.coordinate(
|
coordinate: QtPositioning.coordinate(
|
||||||
map.center.latitude,
|
map.center.latitude,
|
||||||
map.center.longitude)
|
map.center.longitude)
|
||||||
//coordinate: QtPositioning.coordinate(40.730610, -73.935242) // New York
|
//coordinate: QtPositioning.coordinate(40.730610, -73.935242) // New York
|
||||||
|
|
||||||
@ -156,7 +157,7 @@ Column {
|
|||||||
map.center.longitude = coordinate.longitude
|
map.center.longitude = coordinate.longitude
|
||||||
|
|
||||||
getTz();
|
getTz();
|
||||||
|
|
||||||
console.log(coordinate.latitude, coordinate.longitude)
|
console.log(coordinate.latitude, coordinate.longitude)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -199,7 +200,7 @@ Column {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 100
|
height: 100
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
@ -32,10 +32,6 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
//Needs to come from Locale config
|
|
||||||
property var confLang: "en_US.UTF8"
|
|
||||||
property var confLocale: "nl_NL.UTF8"
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: textArea
|
id: textArea
|
||||||
x: 28
|
x: 28
|
||||||
@ -57,7 +53,7 @@ Item {
|
|||||||
width: 240
|
width: 240
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: qsTr("<h1>Languages</h1> </br>
|
text: qsTr("<h1>Languages</h1> </br>
|
||||||
The system locale setting affects the language and character set for some command line user interface elements. The current setting is <strong>%1</strong>.").arg(confLang)
|
The system locale setting affects the language and character set for some command line user interface elements. The current setting is <strong>%1</strong>.").arg(config.currentLanguageCode)
|
||||||
font.pointSize: 10
|
font.pointSize: 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,8 +72,7 @@ Item {
|
|||||||
id: list1
|
id: list1
|
||||||
focus: true
|
focus: true
|
||||||
|
|
||||||
// bogus entries, need to come from Locale config
|
model: config.supportedLocales
|
||||||
model: ["en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8"]
|
|
||||||
|
|
||||||
currentIndex: 1
|
currentIndex: 1
|
||||||
highlight: Rectangle {
|
highlight: Rectangle {
|
||||||
@ -95,17 +90,17 @@ Item {
|
|||||||
}
|
}
|
||||||
onClicked: {
|
onClicked: {
|
||||||
list1.currentIndex = index
|
list1.currentIndex = index
|
||||||
confLang = list1.currentIndex
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onCurrentItemChanged: { config.currentLanguageCode = model[currentIndex] } /* This works because model is a stringlist */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: i18n
|
id: lc_numeric
|
||||||
x: 430
|
x: 430
|
||||||
y: 40
|
y: 40
|
||||||
|
|
||||||
@ -118,7 +113,7 @@ Item {
|
|||||||
width: 240
|
width: 240
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: qsTr("<h1>Locales</h1> </br>
|
text: qsTr("<h1>Locales</h1> </br>
|
||||||
The system locale setting affects the language and character set for some command line user interface elements. The current setting is <strong>%1</strong>.").arg(confLocale)
|
The system locale setting affects the numbers and dates format. The current setting is <strong>%1</strong>.").arg(config.currentLCCode)
|
||||||
font.pointSize: 10
|
font.pointSize: 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,7 +134,7 @@ Item {
|
|||||||
focus: true
|
focus: true
|
||||||
|
|
||||||
// bogus entries, need to come from Locale config
|
// bogus entries, need to come from Locale config
|
||||||
model: ["en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8"]
|
model: config.supportedLocales
|
||||||
|
|
||||||
currentIndex: 2
|
currentIndex: 2
|
||||||
highlight: Rectangle {
|
highlight: Rectangle {
|
||||||
@ -154,11 +149,10 @@ Item {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
list2.currentIndex = index
|
list2.currentIndex = index
|
||||||
confLocale = list1.currentIndex
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onCurrentItemChanged: console.debug(currentIndex)
|
onCurrentItemChanged: { config.currentLCCode = model[currentIndex]; } /* This works because model is a stringlist */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,41 +31,14 @@ Page {
|
|||||||
|
|
||||||
property var confLang: "American English"
|
property var confLang: "American English"
|
||||||
property var confLocale: "Nederland"
|
property var confLocale: "Nederland"
|
||||||
//Needs to come from .conf/geoip
|
|
||||||
property var hasInternet: true
|
|
||||||
|
|
||||||
function getInt(format) {
|
|
||||||
var requestURL = "https://example.org/";
|
|
||||||
var xhr = new XMLHttpRequest;
|
|
||||||
|
|
||||||
xhr.onreadystatechange = function() {
|
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
|
||||||
|
|
||||||
if (xhr.status !== 200) {
|
|
||||||
console.log("Disconnected!!");
|
|
||||||
var connected = false
|
|
||||||
hasInternet = connected
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
console.log("Connected!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xhr.open("GET", requestURL, true);
|
|
||||||
xhr.send();
|
|
||||||
}
|
|
||||||
Component.onCompleted: {
|
|
||||||
getInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: image
|
id: image
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height / 1.28
|
height: parent.height / 1.28
|
||||||
source: (hasInternet) ? "Map.qml" : "Offline.qml"
|
// Network is in io.calamares.core
|
||||||
|
source: Network.hasInternet ? "Map.qml" : "Offline.qml"
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
@ -95,7 +68,7 @@ Page {
|
|||||||
Label {
|
Label {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: qsTr("System language set to %1").arg(confLang)
|
text: config.currentLanguageStatus
|
||||||
}
|
}
|
||||||
Kirigami.Separator {
|
Kirigami.Separator {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@ -103,7 +76,7 @@ Page {
|
|||||||
Label {
|
Label {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: qsTr("Numbers and dates locale set to %1").arg(confLocale)
|
text: config.currentLCStatus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Button {
|
Button {
|
||||||
|
Loading…
Reference in New Issue
Block a user