Merge branch 'locale-polish'

This commit is contained in:
Adriaan de Groot 2019-09-14 07:56:52 -04:00
commit 0c14bbc50b
13 changed files with 477 additions and 416 deletions

View File

@ -12,6 +12,9 @@ This release contains contributions from (alphabetically by first name):
## Modules ##
- *locale* module no longer recognized the legacy GeoIP configuration.
This has been deprecated since Calamares 3.2.8.
# 3.2.13 (2019-08-30) #

View File

@ -18,10 +18,15 @@
#include "Manager.h"
#include "utils/Logger.h"
#include <QEventLoop>
#include <QMutex>
#include <QMutexLocker>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QThread>
#include <QTimer>
namespace CalamaresUtils
@ -45,21 +50,91 @@ RequestOptions::applyToRequest( QNetworkRequest* request ) const
}
}
struct Manager::Private
class Manager::Private : public QObject
{
Q_OBJECT
private:
std::unique_ptr< QNetworkAccessManager > m_nam;
using ThreadNam = QPair< QThread*, QNetworkAccessManager* >;
QVector< ThreadNam > m_perThreadNams;
public slots:
void cleanupNam();
public:
QUrl m_hasInternetUrl;
bool m_hasInternet;
Private();
QNetworkAccessManager* nam();
};
Manager::Private::Private()
: m_nam( std::make_unique< QNetworkAccessManager >() )
, m_hasInternet( false )
{
m_perThreadNams.reserve( 20 );
m_perThreadNams.append( qMakePair( QThread::currentThread(), m_nam.get() ) );
}
static QMutex*
namMutex()
{
static QMutex namMutex;
return &namMutex;
}
QNetworkAccessManager*
Manager::Private::nam()
{
QMutexLocker lock( namMutex() );
auto* thread = QThread::currentThread();
int index = 0;
for ( const auto& n : m_perThreadNams )
{
if ( n.first == thread )
{
return n.second;
}
++index;
}
// Need a new NAM for this thread
QNetworkAccessManager* nam = new QNetworkAccessManager();
m_perThreadNams.append( qMakePair( thread, nam ) );
QObject::connect( thread, &QThread::finished, this, &Manager::Private::cleanupNam );
return nam;
}
void
Manager::Private::cleanupNam()
{
QMutexLocker lock( namMutex() );
auto* thread = QThread::currentThread();
bool cleanupFound = false;
int cleanupIndex = 0;
for ( const auto& n : m_perThreadNams )
{
if ( n.first == thread )
{
cleanupFound = true;
delete n.second;
break;
}
++cleanupIndex;
}
if ( cleanupFound )
{
m_perThreadNams.remove( cleanupIndex );
}
}
Manager::Manager()
: d( std::make_unique< Private >() )
{
@ -83,9 +158,9 @@ Manager::hasInternet()
bool
Manager::checkHasInternet()
{
bool hasInternet = d->m_nam->networkAccessible() == QNetworkAccessManager::Accessible;
bool hasInternet = d->nam()->networkAccessible() == QNetworkAccessManager::Accessible;
if ( !hasInternet && ( d->m_nam->networkAccessible() == QNetworkAccessManager::UnknownAccessibility ) )
if ( !hasInternet && ( d->nam()->networkAccessible() == QNetworkAccessManager::UnknownAccessibility ) )
{
hasInternet = synchronousPing( d->m_hasInternetUrl );
}
@ -108,9 +183,11 @@ Manager::setCheckHasInternetUrl( const QUrl& url )
* On failure, returns nullptr (e.g. bad URL, timeout).
*/
static QNetworkReply*
asynchronousRun( const std::unique_ptr< QNetworkAccessManager >& nam, const QUrl& url, const RequestOptions& options )
asynchronousRun( QNetworkAccessManager* nam, const QUrl& url, const RequestOptions& options )
{
QNetworkRequest request = QNetworkRequest( url );
options.applyToRequest( &request );
QNetworkReply* reply = nam->get( request );
QTimer* timer = nullptr;
@ -121,7 +198,6 @@ asynchronousRun( const std::unique_ptr< QNetworkAccessManager >& nam, const QUrl
return nullptr;
}
options.applyToRequest( &request );
if ( options.hasTimeout() )
{
timer = new QTimer( reply );
@ -142,7 +218,7 @@ asynchronousRun( const std::unique_ptr< QNetworkAccessManager >& nam, const QUrl
* is marked for later automatic deletion, so don't store the pointer.
*/
static QPair< RequestStatus, QNetworkReply* >
synchronousRun( const std::unique_ptr< QNetworkAccessManager >& nam, const QUrl& url, const RequestOptions& options )
synchronousRun( QNetworkAccessManager* nam, const QUrl& url, const RequestOptions& options )
{
auto* reply = asynchronousRun( nam, url, options );
if ( !reply )
@ -176,7 +252,7 @@ Manager::synchronousPing( const QUrl& url, const RequestOptions& options )
return RequestStatus::Failed;
}
auto reply = synchronousRun( d->m_nam, url, options );
auto reply = synchronousRun( d->nam(), url, options );
if ( reply.first )
{
return reply.second->bytesAvailable() ? RequestStatus::Ok : RequestStatus::Empty;
@ -195,16 +271,18 @@ Manager::synchronousGet( const QUrl& url, const RequestOptions& options )
return QByteArray();
}
auto reply = synchronousRun( d->m_nam, url, options );
auto reply = synchronousRun( d->nam(), url, options );
return reply.first ? reply.second->readAll() : QByteArray();
}
QNetworkReply*
Manager::asynchronouseGet( const QUrl& url, const CalamaresUtils::Network::RequestOptions& options )
{
return asynchronousRun( d->m_nam, url, options );
return asynchronousRun( d->nam(), url, options );
}
} // namespace Network
} // namespace CalamaresUtils
#include "Manager.moc"

View File

@ -25,9 +25,7 @@
#include <QListWidget>
#include <QPushButton>
LCLocaleDialog::LCLocaleDialog( const QString& guessedLCLocale,
const QStringList& localeGenLines,
QWidget* parent )
LCLocaleDialog::LCLocaleDialog( const QString& guessedLCLocale, const QStringList& localeGenLines, QWidget* parent )
: QDialog( parent )
{
setModal( true );
@ -60,34 +58,33 @@ LCLocaleDialog::LCLocaleDialog( const QString& guessedLCLocale,
}
}
QDialogButtonBox* dbb = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
Qt::Horizontal,
this );
QDialogButtonBox* dbb
= new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this );
dbb->button( QDialogButtonBox::Cancel )->setText( tr( "&Cancel" ) );
dbb->button( QDialogButtonBox::Ok )->setText( tr( "&OK" ) );
mainLayout->addWidget( dbb );
connect( dbb->button( QDialogButtonBox::Ok ), &QPushButton::clicked,
this, &QDialog::accept );
connect( dbb->button( QDialogButtonBox::Cancel ), &QPushButton::clicked,
this, &QDialog::reject );
connect( dbb->button( QDialogButtonBox::Ok ), &QPushButton::clicked, this, &QDialog::accept );
connect( dbb->button( QDialogButtonBox::Cancel ), &QPushButton::clicked, this, &QDialog::reject );
connect( m_localesWidget, &QListWidget::itemDoubleClicked,
this, &QDialog::accept );
connect( m_localesWidget, &QListWidget::itemSelectionChanged,
[this, dbb]()
{
connect( m_localesWidget, &QListWidget::itemDoubleClicked, this, &QDialog::accept );
connect( m_localesWidget, &QListWidget::itemSelectionChanged, [this, dbb]() {
if ( m_localesWidget->selectedItems().isEmpty() )
{
dbb->button( QDialogButtonBox::Ok )->setEnabled( false );
}
else
{
dbb->button( QDialogButtonBox::Ok )->setEnabled( true );
}
} );
if ( selected > -1 )
{
m_localesWidget->setCurrentRow( selected );
}
}
QString

View File

@ -30,8 +30,7 @@ LocaleConfiguration::LocaleConfiguration()
LocaleConfiguration::LocaleConfiguration( const QString& localeName, const QString& formatsName )
: LocaleConfiguration()
{
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;
(void)setLanguage( localeName );
@ -58,28 +57,37 @@ LocaleConfiguration::fromLanguageAndLocation( const QString& languageLocale,
for ( const QString& line : availableLocales )
{
if ( line.startsWith( language ) )
{
linesForLanguage.append( line );
}
}
QString lang;
if ( linesForLanguage.length() == 0 || languageLocale.isEmpty() )
{
lang = "en_US.UTF-8";
}
else if ( linesForLanguage.length() == 1 )
{
lang = linesForLanguage.first();
}
else
{
QStringList linesForLanguageUtf;
// FIXME: this might be useless if we already filter out non-UTF8 locales
foreach ( QString line, linesForLanguage )
{
if ( line.contains( "UTF-8", Qt::CaseInsensitive ) ||
line.contains( "utf8", Qt::CaseInsensitive ) )
if ( line.contains( "UTF-8", Qt::CaseInsensitive ) || line.contains( "utf8", Qt::CaseInsensitive ) )
{
linesForLanguageUtf.append( line );
}
}
if ( linesForLanguageUtf.length() == 1 )
{
lang = linesForLanguageUtf.first();
}
}
// lang could still be empty if we found multiple locales that satisfy myLanguage
@ -92,8 +100,7 @@ LocaleConfiguration::fromLanguageAndLocation( const QString& languageLocale,
# locale categories reflect the selected location. */
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 )
{
if ( line.contains( proposedLocale ) )
@ -116,13 +123,14 @@ LocaleConfiguration::fromLanguageAndLocation( const QString& languageLocale,
break;
}
}
}
// Else we have an unrecognized or unsupported locale, all we can do is go with
// en_US.UTF-8 UTF-8. This completes all default language setting guesswork.
if ( lang.isEmpty() )
{
lang = "en_US.UTF-8";
}
// The following block was inspired by Ubiquity, scripts/localechooser-apply.
@ -171,8 +179,7 @@ LocaleConfiguration::fromLanguageAndLocation( const QString& languageLocale,
// We make a proposed locale based on the UI language and the timezone's country. There is no
// guarantee that this will be a valid, supported locale (often it won't).
QString lc_formats;
QString combined = QString( "%1_%2" ).arg( language )
.arg( countryCode );
QString combined = QString( "%1_%2" ).arg( language ).arg( countryCode );
// We look up if it's a supported locale.
for ( const QString& line : availableLocales )
{
@ -248,9 +255,8 @@ LocaleConfiguration::fromLanguageAndLocation( const QString& languageLocale,
};
if ( countryToDefaultLanguage.contains( countryCode ) )
{
QString combinedLocale =
QString( "%1_%2" ).arg( countryToDefaultLanguage.value( countryCode ) )
.arg( countryCode );
QString combinedLocale
= QString( "%1_%2" ).arg( countryToDefaultLanguage.value( countryCode ) ).arg( countryCode );
for ( const QString& line : availableLocales )
{
@ -267,7 +273,9 @@ LocaleConfiguration::fromLanguageAndLocation( const QString& languageLocale,
// If we cannot make a good choice for a given country we go with the LANG
// setting, which defaults to en_US.UTF-8 UTF-8 if all else fails.
if ( lc_formats.isEmpty() )
{
lc_formats = lang;
}
return LocaleConfiguration( lang, lc_formats );
}
@ -276,54 +284,36 @@ LocaleConfiguration::fromLanguageAndLocation( const QString& languageLocale,
bool
LocaleConfiguration::isEmpty() const
{
return m_lang.isEmpty() &&
lc_numeric.isEmpty() &&
lc_time.isEmpty() &&
lc_monetary.isEmpty() &&
lc_paper.isEmpty() &&
lc_name.isEmpty() &&
lc_address.isEmpty() &&
lc_telephone.isEmpty() &&
lc_measurement.isEmpty() &&
lc_identification.isEmpty();
return m_lang.isEmpty() && lc_numeric.isEmpty() && lc_time.isEmpty() && lc_monetary.isEmpty() && lc_paper.isEmpty()
&& lc_name.isEmpty() && lc_address.isEmpty() && lc_telephone.isEmpty() && lc_measurement.isEmpty()
&& lc_identification.isEmpty();
}
/// @brief Sets @p value on @p key in the @p map if @p value is non-empty
static inline void
add_lc( QMap< QString, QString >& map, const char* key, const QString& value )
{
if ( !value.isEmpty() )
{
map.insert( key, value );
}
}
QMap< QString, QString >
LocaleConfiguration::toMap() const
{
QMap< QString, QString > map;
if ( !m_lang.isEmpty() )
map.insert( "LANG", m_lang );
if ( !lc_numeric.isEmpty() )
map.insert( "LC_NUMERIC", lc_numeric );
if ( !lc_time.isEmpty() )
map.insert( "LC_TIME", lc_time );
if ( !lc_monetary.isEmpty() )
map.insert( "LC_MONETARY", lc_monetary );
if ( !lc_paper.isEmpty() )
map.insert( "LC_PAPER", lc_paper );
if ( !lc_name.isEmpty() )
map.insert( "LC_NAME", lc_name );
if ( !lc_address.isEmpty() )
map.insert( "LC_ADDRESS", lc_address );
if ( !lc_telephone.isEmpty() )
map.insert( "LC_TELEPHONE", lc_telephone );
if ( !lc_measurement.isEmpty() )
map.insert( "LC_MEASUREMENT", lc_measurement );
if ( !lc_identification.isEmpty() )
map.insert( "LC_IDENTIFICATION", lc_identification );
add_lc( map, "LANG", m_lang );
add_lc( map, "LC_NUMERIC", lc_numeric );
add_lc( map, "LC_TIME", lc_time );
add_lc( map, "LC_MONETARY", lc_monetary );
add_lc( map, "LC_PAPER", lc_paper );
add_lc( map, "LC_NAME", lc_name );
add_lc( map, "LC_ADDRESS", lc_address );
add_lc( map, "LC_TELEPHONE", lc_telephone );
add_lc( map, "LC_MEASUREMENT", lc_measurement );
add_lc( map, "LC_IDENTIFICATION", lc_identification );
return map;
}

View File

@ -21,8 +21,8 @@
#define LOCALECONFIGURATION_H
#include <QDebug>
#include <QString>
#include <QMap>
#include <QString>
class LocaleConfiguration
{
@ -31,13 +31,14 @@ public:
explicit LocaleConfiguration();
/// @brief Create a locale with everything set to the given @p localeName
explicit LocaleConfiguration( const QString& localeName /* "en_US.UTF-8" */ )
: LocaleConfiguration( localeName, localeName ) { }
: LocaleConfiguration( localeName, localeName )
{
}
/// @brief Create a locale with language and formats separate
explicit LocaleConfiguration( const QString& localeName, const QString& formatsName );
static LocaleConfiguration fromLanguageAndLocation( const QString& language,
const QStringList& availableLocales,
const QString& countryCode );
static LocaleConfiguration
fromLanguageAndLocation( const QString& language, const QStringList& availableLocales, const QString& countryCode );
bool isEmpty() const;
@ -55,8 +56,8 @@ public:
// These become all uppercase in locale.conf, but we keep them lowercase here to
// avoid confusion with locale.h.
QString lc_numeric, lc_time, lc_monetary, lc_paper, lc_name, lc_address,
lc_telephone, lc_measurement, lc_identification;
QString lc_numeric, lc_time, lc_monetary, lc_paper, lc_name, lc_address, lc_telephone, lc_measurement,
lc_identification;
// If the user has explicitly selected language (from the dialog)
// or numbers format, set these to avoid implicit changes to them.
@ -67,7 +68,8 @@ private:
QString m_languageLocaleBcp47;
};
inline QDebug& operator <<( QDebug& s, const LocaleConfiguration& l )
inline QDebug&
operator<<( QDebug& s, const LocaleConfiguration& l )
{
return s << l.language() << '(' << l.toBcp47() << ") +" << l.lc_numeric;
}

View File

@ -35,8 +35,8 @@
#include <QBoxLayout>
#include <QComboBox>
#include <QLabel>
#include <QPushButton>
#include <QProcess>
#include <QPushButton>
LocalePage::LocalePage( QWidget* parent )
: QWidget( parent )
@ -99,154 +99,49 @@ LocalePage::LocalePage( QWidget* parent )
setLayout( mainLayout );
connect( m_regionCombo,
static_cast< void ( QComboBox::* )( int ) >( &QComboBox::currentIndexChanged ),
[this]( int currentIndex )
{
Q_UNUSED( currentIndex )
QHash< QString, QList< LocaleGlobal::Location > > regions = LocaleGlobal::getLocations();
if ( !regions.contains( m_regionCombo->currentData().toString() ) )
return;
connect( m_regionCombo, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, &LocalePage::regionChanged );
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_formatsChangeButton, &QPushButton::clicked, this, &LocalePage::changeFormats );
m_zoneCombo->blockSignals( true );
m_zoneCombo->clear();
const QList< LocaleGlobal::Location > zones = regions.value( m_regionCombo->currentData().toString() );
for ( const LocaleGlobal::Location& zone : zones )
{
m_zoneCombo->addItem( LocaleGlobal::Location::pretty( zone.zone ), zone.zone );
}
m_zoneCombo->model()->sort( 0 );
m_zoneCombo->blockSignals( false );
m_zoneCombo->currentIndexChanged( m_zoneCombo->currentIndex() );
} );
connect( m_zoneCombo,
static_cast< void ( QComboBox::* )( int ) >( &QComboBox::currentIndexChanged ),
[this]( int currentIndex )
{
Q_UNUSED( currentIndex )
if ( !m_blockTzWidgetSet )
m_tzWidget->setCurrentLocation( m_regionCombo->currentData().toString(),
m_zoneCombo->currentData().toString() );
updateGlobalStorage();
} );
connect( m_tzWidget, &TimeZoneWidget::locationChanged,
[this]( LocaleGlobal::Location location )
{
m_blockTzWidgetSet = true;
// Set region index
int index = m_regionCombo->findData( location.region );
if ( index < 0 )
return;
m_regionCombo->setCurrentIndex( index );
// Set zone index
index = m_zoneCombo->findData( location.zone );
if ( index < 0 )
return;
m_zoneCombo->setCurrentIndex( index );
m_blockTzWidgetSet = false;
updateGlobalStorage();
} );
connect( m_localeChangeButton, &QPushButton::clicked,
[this]
{
LCLocaleDialog* dlg =
new LCLocaleDialog( m_selectedLocaleConfiguration.isEmpty() ?
guessLocaleConfiguration().language() :
m_selectedLocaleConfiguration.language(),
m_localeGenLines,
this );
dlg->exec();
if ( dlg->result() == QDialog::Accepted &&
!dlg->selectedLCLocale().isEmpty() )
{
m_selectedLocaleConfiguration.setLanguage( dlg->selectedLCLocale() );
m_selectedLocaleConfiguration.explicit_lang = true;
this->updateGlobalLocale();
this->updateLocaleLabels();
}
dlg->deleteLater();
} );
connect( m_formatsChangeButton, &QPushButton::clicked,
[this]
{
LCLocaleDialog* dlg =
new LCLocaleDialog( m_selectedLocaleConfiguration.isEmpty() ?
guessLocaleConfiguration().lc_numeric :
m_selectedLocaleConfiguration.lc_numeric,
m_localeGenLines,
this );
dlg->exec();
if ( dlg->result() == QDialog::Accepted &&
!dlg->selectedLCLocale().isEmpty() )
{
// TODO: improve the granularity of this setting.
m_selectedLocaleConfiguration.lc_numeric = dlg->selectedLCLocale();
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();
} );
CALAMARES_RETRANSLATE(
m_regionLabel->setText( tr( "Region:" ) );
m_zoneLabel->setText( tr( "Zone:" ) );
updateLocaleLabels();
m_localeChangeButton->setText( tr( "&Change..." ) );
m_formatsChangeButton->setText( tr( "&Change..." ) );
)
CALAMARES_RETRANSLATE_SLOT( &LocalePage::updateLocaleLabels )
}
LocalePage::~LocalePage()
{}
LocalePage::~LocalePage() {}
void
LocalePage::updateLocaleLabels()
{
LocaleConfiguration lc = m_selectedLocaleConfiguration.isEmpty() ?
guessLocaleConfiguration() :
m_selectedLocaleConfiguration;
m_regionLabel->setText( tr( "Region:" ) );
m_zoneLabel->setText( tr( "Zone:" ) );
m_localeChangeButton->setText( tr( "&Change..." ) );
m_formatsChangeButton->setText( tr( "&Change..." ) );
LocaleConfiguration lc
= m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration() : m_selectedLocaleConfiguration;
auto labels = prettyLocaleStatus( lc );
m_localeLabel->setText( labels.first );
m_formatsLabel->setText( labels.second );
}
static inline bool
containsLocation( const QList< LocaleGlobal::Location >& locations, const QString& zone )
{
for ( const LocaleGlobal::Location& location : locations )
{
if ( location.zone == zone )
{
return true;
}
}
return false;
}
void
LocalePage::init( const QString& initialRegion,
const QString& initialZone,
const QString& localeGenPath )
LocalePage::init( const QString& initialRegion, const QString& initialZone, const QString& localeGenPath )
{
m_regionCombo->blockSignals( true );
m_zoneCombo->blockSignals( true );
@ -267,20 +162,7 @@ LocalePage::init( const QString& initialRegion,
m_regionCombo->currentIndexChanged( m_regionCombo->currentIndex() );
// Default location
auto containsLocation = []( const QList< LocaleGlobal::Location >& locations,
const QString& zone ) -> bool
{
for ( const LocaleGlobal::Location& location : locations )
{
if ( location.zone == zone )
return true;
}
return false;
};
if ( keys.contains( initialRegion ) &&
containsLocation( regions.value( initialRegion ), initialZone ) )
if ( keys.contains( initialRegion ) && containsLocation( regions.value( initialRegion ), initialZone ) )
{
m_tzWidget->setCurrentLocation( initialRegion, initialZone );
}
@ -298,8 +180,7 @@ LocalePage::init( const QString& initialRegion,
QFile supported( "/usr/share/i18n/SUPPORTED" );
QByteArray ba;
if ( supported.exists() &&
supported.open( QIODevice::ReadOnly | QIODevice::Text ) )
if ( supported.exists() && supported.open( QIODevice::ReadOnly | QIODevice::Text ) )
{
ba = supported.readAll();
supported.close();
@ -331,18 +212,22 @@ LocalePage::init( const QString& initialRegion,
const auto lines = ba.split( '\n' );
for ( const QByteArray& line : lines )
{
if ( line.startsWith( "## " ) ||
line.startsWith( "# " ) ||
line.simplified() == "#" )
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 );
}
@ -354,12 +239,9 @@ LocalePage::init( const QString& initialRegion,
<< "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"
<< supported.fileName()
<< "\n\tOR"
<< "* a well-formed"
<< (localeGenPath.isEmpty() ? QLatin1Literal("/etc/locale.gen") : localeGenPath)
<< "\n\tOR"
<< ( localeGenPath.isEmpty() ? QLatin1Literal( "/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.
}
@ -368,24 +250,30 @@ LocalePage::init( const QString& initialRegion,
// because it's not 1995.
for ( auto it = m_localeGenLines.begin(); it != m_localeGenLines.end(); )
{
if ( !it->contains( "UTF-8", Qt::CaseInsensitive ) &&
!it->contains( "utf8", Qt::CaseInsensitive ) )
if ( !it->contains( "UTF-8", Qt::CaseInsensitive ) && !it->contains( "utf8", Qt::CaseInsensitive ) )
{
it = m_localeGenLines.erase( it );
}
else
{
++it;
}
}
// We strip " UTF-8" from "en_US.UTF-8 UTF-8" because it's redundant redundant.
for ( auto it = m_localeGenLines.begin(); it != m_localeGenLines.end(); ++it )
{
if ( it->endsWith( " UTF-8" ) )
{
it->chop( 6 );
}
*it = it->simplified();
}
updateGlobalStorage();
}
std::pair< QString, QString > LocalePage::prettyLocaleStatus( const LocaleConfiguration& lc ) const
std::pair< QString, QString >
LocalePage::prettyLocaleStatus( const LocaleConfiguration& lc ) const
{
using CalamaresUtils::Locale::Label;
@ -401,13 +289,10 @@ QString
LocalePage::prettyStatus() const
{
QString status;
status += tr( "Set timezone to %1/%2.<br/>" )
.arg( m_regionCombo->currentText() )
.arg( m_zoneCombo->currentText() );
status += tr( "Set timezone to %1/%2.<br/>" ).arg( m_regionCombo->currentText() ).arg( m_zoneCombo->currentText() );
LocaleConfiguration lc = m_selectedLocaleConfiguration.isEmpty() ?
guessLocaleConfiguration() :
m_selectedLocaleConfiguration;
LocaleConfiguration lc
= m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration() : m_selectedLocaleConfiguration;
auto labels = prettyLocaleStatus( lc );
status += labels.first + "<br/>";
status += labels.second + "<br/>";
@ -432,9 +317,8 @@ LocalePage::createJobs()
QMap< QString, QString >
LocalePage::localesMap()
{
return m_selectedLocaleConfiguration.isEmpty() ?
guessLocaleConfiguration().toMap() :
m_selectedLocaleConfiguration.toMap();
return m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration().toMap()
: m_selectedLocaleConfiguration.toMap();
}
@ -442,8 +326,7 @@ void
LocalePage::onActivate()
{
m_regionCombo->setFocus();
if ( m_selectedLocaleConfiguration.isEmpty() ||
!m_selectedLocaleConfiguration.explicit_lang )
if ( m_selectedLocaleConfiguration.isEmpty() || !m_selectedLocaleConfiguration.explicit_lang )
{
auto newLocale = guessLocaleConfiguration();
m_selectedLocaleConfiguration.setLanguage( newLocale.language() );
@ -456,9 +339,8 @@ LocalePage::onActivate()
LocaleConfiguration
LocalePage::guessLocaleConfiguration() const
{
return LocaleConfiguration::fromLanguageAndLocation( QLocale().name(),
m_localeGenLines,
m_tzWidget->getCurrentLocation().country );
return LocaleConfiguration::fromLanguageAndLocation(
QLocale().name(), m_localeGenLines, m_tzWidget->getCurrentLocation().country );
}
@ -477,8 +359,8 @@ LocalePage::updateGlobalStorage()
auto* gs = Calamares::JobQueue::instance()->globalStorage();
LocaleGlobal::Location location = m_tzWidget->getCurrentLocation();
bool locationChanged = ( location.region != gs->value( "locationRegion" ) ) ||
( location.zone != gs->value( "locationZone" ) );
bool locationChanged
= ( location.region != gs->value( "locationRegion" ) ) || ( location.zone != gs->value( "locationZone" ) );
gs->insert( "locationRegion", location.region );
gs->insert( "locationZone", location.zone );
@ -491,18 +373,17 @@ LocalePage::updateGlobalStorage()
if ( locationChanged && Calamares::Settings::instance()->doChroot() )
{
QProcess::execute( "timedatectl", // depends on systemd
{ "set-timezone",
location.region + '/' + location.zone } );
{ "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 )
if ( !m_selectedLocaleConfiguration.isEmpty() && m_selectedLocaleConfiguration.explicit_lang )
{
newLocale.setLanguage( m_selectedLocaleConfiguration.language() );
if ( !m_selectedLocaleConfiguration.isEmpty() &&
m_selectedLocaleConfiguration.explicit_lc )
}
if ( !m_selectedLocaleConfiguration.isEmpty() && m_selectedLocaleConfiguration.explicit_lc )
{
newLocale.lc_numeric = m_selectedLocaleConfiguration.lc_numeric;
newLocale.lc_time = m_selectedLocaleConfiguration.lc_time;
@ -520,3 +401,120 @@ LocalePage::updateGlobalStorage()
m_selectedLocaleConfiguration = newLocale;
updateLocaleLabels();
}
void
LocalePage::regionChanged( int currentIndex )
{
Q_UNUSED( currentIndex )
QHash< QString, QList< LocaleGlobal::Location > > regions = LocaleGlobal::getLocations();
if ( !regions.contains( m_regionCombo->currentData().toString() ) )
{
return;
}
m_zoneCombo->blockSignals( true );
m_zoneCombo->clear();
const QList< LocaleGlobal::Location > zones = regions.value( m_regionCombo->currentData().toString() );
for ( const LocaleGlobal::Location& zone : zones )
{
m_zoneCombo->addItem( LocaleGlobal::Location::pretty( zone.zone ), zone.zone );
}
m_zoneCombo->model()->sort( 0 );
m_zoneCombo->blockSignals( false );
m_zoneCombo->currentIndexChanged( m_zoneCombo->currentIndex() );
}
void
LocalePage::zoneChanged( int currentIndex )
{
Q_UNUSED( currentIndex )
if ( !m_blockTzWidgetSet )
m_tzWidget->setCurrentLocation( m_regionCombo->currentData().toString(),
m_zoneCombo->currentData().toString() );
updateGlobalStorage();
}
void
LocalePage::locationChanged( LocaleGlobal::Location location )
{
m_blockTzWidgetSet = true;
// Set region index
int index = m_regionCombo->findData( location.region );
if ( index < 0 )
{
return;
}
m_regionCombo->setCurrentIndex( index );
// Set zone index
index = m_zoneCombo->findData( location.zone );
if ( index < 0 )
{
return;
}
m_zoneCombo->setCurrentIndex( index );
m_blockTzWidgetSet = false;
updateGlobalStorage();
}
void
LocalePage::changeLocale()
{
LCLocaleDialog* dlg
= new LCLocaleDialog( m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration().language()
: m_selectedLocaleConfiguration.language(),
m_localeGenLines,
this );
dlg->exec();
if ( dlg->result() == QDialog::Accepted && !dlg->selectedLCLocale().isEmpty() )
{
m_selectedLocaleConfiguration.setLanguage( dlg->selectedLCLocale() );
m_selectedLocaleConfiguration.explicit_lang = true;
this->updateGlobalLocale();
this->updateLocaleLabels();
}
dlg->deleteLater();
}
void
LocalePage::changeFormats()
{
LCLocaleDialog* dlg
= new LCLocaleDialog( m_selectedLocaleConfiguration.isEmpty() ? guessLocaleConfiguration().lc_numeric
: m_selectedLocaleConfiguration.lc_numeric,
m_localeGenLines,
this );
dlg->exec();
if ( dlg->result() == QDialog::Accepted && !dlg->selectedLCLocale().isEmpty() )
{
// TODO: improve the granularity of this setting.
m_selectedLocaleConfiguration.lc_numeric = dlg->selectedLCLocale();
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();
}

View File

@ -21,6 +21,8 @@
#define LOCALEPAGE_H
#include "LocaleConfiguration.h"
#include "timezonewidget/localeglobal.h"
#include "Job.h"
#include <QWidget>
@ -37,9 +39,7 @@ public:
explicit LocalePage( QWidget* parent = nullptr );
virtual ~LocalePage();
void init( const QString& initialRegion,
const QString& initialZone,
const QString& localeGenPath );
void init( const QString& initialRegion, const QString& initialZone, const QString& localeGenPath );
QString prettyStatus() const;
@ -65,6 +65,12 @@ private:
void updateGlobalStorage();
void updateLocaleLabels();
void regionChanged( int currentIndex );
void zoneChanged( int currentIndex );
void locationChanged( LocaleGlobal::Location location );
void changeLocale();
void changeFormats();
TimeZoneWidget* m_tzWidget;
QComboBox* m_regionCombo;
QComboBox* m_zoneCombo;

View File

@ -27,7 +27,7 @@
#include "JobQueue.h"
#include "geoip/Handler.h"
#include "network/Manager.h"
#include "utils/CalamaresUtilsGui.h"
#include "utils/Logger.h"
#include "utils/Variant.h"
@ -43,46 +43,14 @@ CALAMARES_PLUGIN_FACTORY_DEFINITION( LocaleViewStepFactory, registerPlugin<Local
LocaleViewStep::LocaleViewStep( QObject* parent )
: Calamares::ViewStep( parent )
, m_widget( new QWidget() )
, m_actualWidget( new LocalePage() )
, m_actualWidget( nullptr )
, m_nextEnabled( false )
, m_geoip( nullptr )
{
QBoxLayout* mainLayout = new QHBoxLayout;
m_widget->setLayout( mainLayout );
CalamaresUtils::unmarginLayout( mainLayout );
m_waitingWidget = new WaitingWidget( tr( "Loading location data..." ) );
mainLayout->addWidget( m_waitingWidget );
connect( &m_initWatcher, &QFutureWatcher< void >::finished,
this, [=]
{
bool hasInternet = Calamares::JobQueue::instance()->globalStorage()
->value( "hasInternet" ).toBool();
if ( m_geoipUrl.isEmpty() || !hasInternet )
setUpPage();
else
fetchGeoIpTimezone();
});
QFuture< void > initFuture = QtConcurrent::run( [=]
{
LocaleGlobal::init();
if ( m_geoipUrl.isEmpty() )
return;
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
// Max 10sec wait for RequirementsChecker to finish, assuming the welcome
// module is used.
// If welcome is not used, either "hasInternet" should be set by other means,
// or the GeoIP feature should be disabled.
for ( int i = 0; i < 10; ++i )
if ( !gs->contains( "hasInternet" ) )
QThread::sleep( 1 );
} );
m_initWatcher.setFuture( initFuture );
emit nextStatusChanged( m_nextEnabled );
}
@ -90,19 +58,22 @@ LocaleViewStep::LocaleViewStep( QObject* parent )
LocaleViewStep::~LocaleViewStep()
{
if ( m_widget && m_widget->parent() == nullptr )
{
m_widget->deleteLater();
}
}
void
LocaleViewStep::setUpPage()
{
m_actualWidget->init( m_startingTimezone.first,
m_startingTimezone.second,
m_localeGenPath );
m_widget->layout()->removeWidget( m_waitingWidget );
m_waitingWidget->deleteLater();
if ( !m_actualWidget )
{
m_actualWidget = new LocalePage();
}
m_actualWidget->init( m_startingTimezone.first, m_startingTimezone.second, m_localeGenPath );
m_widget->layout()->addWidget( m_actualWidget );
m_nextEnabled = true;
emit nextStatusChanged( m_nextEnabled );
}
@ -111,16 +82,14 @@ LocaleViewStep::setUpPage()
void
LocaleViewStep::fetchGeoIpTimezone()
{
CalamaresUtils::GeoIP::Handler h( m_geoipStyle, m_geoipUrl, m_geoipSelector );
if ( h.isValid() )
if ( m_geoip && m_geoip->isValid() )
{
m_startingTimezone = h.get();
m_startingTimezone = m_geoip->get();
if ( !m_startingTimezone.isValid() )
cWarning() << "GeoIP lookup at" << m_geoipUrl << "failed.";
{
cWarning() << "GeoIP lookup at" << m_geoip->url() << "failed.";
}
}
else
cWarning() << "GeoIP Style" << m_geoipStyle << "is not recognized.";
setUpPage();
}
@ -183,6 +152,10 @@ LocaleViewStep::jobs() const
void
LocaleViewStep::onActivate()
{
if ( !m_actualWidget )
{
setUpPage();
}
m_actualWidget->onActivate();
}
@ -191,6 +164,9 @@ void
LocaleViewStep::onLeave()
{
m_jobs.clear();
if ( m_actualWidget )
{
m_jobs.append( m_actualWidget->createJobs() );
m_prettyStatus = m_actualWidget->prettyStatus();
@ -198,10 +174,16 @@ LocaleViewStep::onLeave()
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 );
Calamares::JobQueue::instance()->globalStorage()->insert( "localeConf", vm );
}
else
{
Calamares::JobQueue::instance()->globalStorage()->remove( "localeConf" );
}
}
@ -216,35 +198,51 @@ LocaleViewStep::setConfigurationMap( const QVariantMap& configurationMap )
}
else
{
m_startingTimezone = CalamaresUtils::GeoIP::RegionZonePair( QStringLiteral( "America" ), QStringLiteral( "New_York" ) );
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 )
{
m_geoipUrl = CalamaresUtils::getString( geoip, "url" );
m_geoipStyle = CalamaresUtils::getString( geoip, "style" );
m_geoipSelector = CalamaresUtils::getString( geoip, "selector" );
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()
{
LocaleGlobal::init();
if ( m_geoip && m_geoip->isValid() )
{
auto& network = CalamaresUtils::Network::Manager::instance();
if ( network.hasInternet() )
{
fetchGeoIpTimezone();
}
else
{
// Accommodate deprecated geoip configuration
m_geoipUrl = CalamaresUtils::getString( configurationMap, "geoipUrl" );
m_geoipStyle = CalamaresUtils::getString( configurationMap, "geoipStyle" );
m_geoipSelector = CalamaresUtils::getString( configurationMap, "geoipSelector" );
if ( !m_geoipUrl.isEmpty() && ( m_geoipStyle.isEmpty() || m_geoipStyle == "legacy" ) )
if ( network.synchronousPing( m_geoip->url() ) )
{
m_geoipStyle = "json";
m_geoipUrl.append( "/json/" );
fetchGeoIpTimezone();
}
}
}
if ( !m_geoipUrl.isEmpty() )
cWarning() << "Legacy-style GeoIP configuration is deprecated. Use geoip: map.";
}
return Calamares::RequirementsList();
}

View File

@ -20,6 +20,7 @@
#ifndef LOCALEVIEWSTEP_H
#define LOCALEVIEWSTEP_H
#include "geoip/Handler.h"
#include "geoip/Interface.h"
#include "utils/PluginFactory.h"
#include "viewpages/ViewStep.h"
@ -29,6 +30,8 @@
#include <QFutureWatcher>
#include <QObject>
#include <memory>
class LocalePage;
class WaitingWidget;
@ -58,14 +61,15 @@ public:
void setConfigurationMap( const QVariantMap& configurationMap ) override;
/// @brief Do setup (returns empty list) asynchronously
virtual Calamares::RequirementsList checkRequirements();
private slots:
void setUpPage();
private:
void fetchGeoIpTimezone();
QWidget* m_widget;
QFutureWatcher< void > m_initWatcher;
WaitingWidget* m_waitingWidget;
LocalePage* m_actualWidget;
bool m_nextEnabled;
@ -74,11 +78,8 @@ private:
CalamaresUtils::GeoIP::RegionZonePair m_startingTimezone;
QString m_localeGenPath;
QString m_geoipUrl; // The URL, depening on style might be modified on lookup
QString m_geoipStyle; // String selecting which kind of geoip data to expect
QString m_geoipSelector; // String selecting data from the geoip lookup
QList< Calamares::job_ptr > m_jobs;
std::unique_ptr< CalamaresUtils::GeoIP::Handler > m_geoip;
};
CALAMARES_PLUGIN_FACTORY_DECLARATION( LocaleViewStepFactory )

View File

@ -19,11 +19,11 @@
#include <SetTimezoneJob.h>
#include "JobQueue.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include "Settings.h"
#include "utils/Logger.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h"
#include <QDir>
#include <QFileInfo>
@ -51,14 +51,14 @@ SetTimezoneJob::exec()
// to a running timedated over D-Bus), and we have code that works
if ( !Calamares::Settings::instance()->doChroot() )
{
int ec = CalamaresUtils::System::instance()->
targetEnvCall( { "timedatectl",
"set-timezone",
m_region + '/' + m_zone } );
int ec = CalamaresUtils::System::instance()->targetEnvCall(
{ "timedatectl", "set-timezone", m_region + '/' + m_zone } );
if ( !ec )
{
return Calamares::JobResult::ok();
}
}
QString localtimeSlink( "/etc/localtime" );
QString zoneinfoPath( "/usr/share/zoneinfo" );
@ -72,27 +72,17 @@ SetTimezoneJob::exec()
tr( "Bad path: %1" ).arg( zoneFile.absolutePath() ) );
// Make sure /etc/localtime doesn't exist, otherwise symlinking will fail
CalamaresUtils::System::instance()->
targetEnvCall( { "rm",
"-f",
localtimeSlink } );
CalamaresUtils::System::instance()->targetEnvCall( { "rm", "-f", localtimeSlink } );
int ec = CalamaresUtils::System::instance()->
targetEnvCall( { "ln",
"-s",
zoneinfoPath,
localtimeSlink } );
int ec = CalamaresUtils::System::instance()->targetEnvCall( { "ln", "-s", zoneinfoPath, localtimeSlink } );
if ( ec )
return Calamares::JobResult::error( tr( "Cannot set timezone." ),
tr( "Link creation failed, target: %1; link name: %2" )
.arg( zoneinfoPath )
.arg( "/etc/localtime" ) );
return Calamares::JobResult::error(
tr( "Cannot set timezone." ),
tr( "Link creation failed, target: %1; link name: %2" ).arg( zoneinfoPath ).arg( "/etc/localtime" ) );
QFile timezoneFile( gs->value( "rootMountPoint" ).toString() + "/etc/timezone" );
if ( !timezoneFile.open( QIODevice::WriteOnly |
QIODevice::Text |
QIODevice::Truncate ) )
if ( !timezoneFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
return Calamares::JobResult::error( tr( "Cannot set timezone," ),
tr( "Cannot open /etc/timezone for writing" ) );

View File

@ -26,8 +26,7 @@ class SetTimezoneJob : public Calamares::Job
{
Q_OBJECT
public:
SetTimezoneJob( const QString& region,
const QString& zone );
SetTimezoneJob( const QString& region, const QString& zone );
QString prettyName() const override;
Calamares::JobResult exec() override;

View File

@ -25,19 +25,17 @@
QTEST_GUILESS_MAIN( LocaleTests )
LocaleTests::LocaleTests()
LocaleTests::LocaleTests() {}
LocaleTests::~LocaleTests() {}
void
LocaleTests::initTestCase()
{
}
LocaleTests::~LocaleTests()
{
}
void LocaleTests::initTestCase()
{
}
void LocaleTests::testEmptyLocaleConfiguration()
void
LocaleTests::testEmptyLocaleConfiguration()
{
LocaleConfiguration lc;
@ -45,7 +43,8 @@ void LocaleTests::testEmptyLocaleConfiguration()
QCOMPARE( lc.toBcp47(), QString() );
}
void LocaleTests::testDefaultLocaleConfiguration()
void
LocaleTests::testDefaultLocaleConfiguration()
{
LocaleConfiguration lc( "en_US.UTF-8" );
QVERIFY( !lc.isEmpty() );
@ -58,7 +57,8 @@ void LocaleTests::testDefaultLocaleConfiguration()
QCOMPARE( lc2.toBcp47(), "de" );
}
void LocaleTests::testSplitLocaleConfiguration()
void
LocaleTests::testSplitLocaleConfiguration()
{
LocaleConfiguration lc( "en_US.UTF-8", "de_DE.UTF-8" );
QVERIFY( !lc.isEmpty() );
@ -76,5 +76,4 @@ void LocaleTests::testSplitLocaleConfiguration()
QVERIFY( !lc3.isEmpty() );
QCOMPARE( lc3.toBcp47(), "da" );
QCOMPARE( lc3.lc_numeric, "de_DE.UTF-8" );
}