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

This commit is contained in:
Philip Müller 2019-12-12 19:53:47 +01:00
commit 14aba17cc3
28 changed files with 6817 additions and 513 deletions

View File

@ -7,6 +7,12 @@ source_file = lang/calamares_en.ts
source_lang = en source_lang = en
type = QT type = QT
[calamares.tz]
file_filter = lang/tz_<lang>.ts
source_file = lang/tz_en.ts
source_lang = en
type = QT
[calamares.dummypythonqt] [calamares.dummypythonqt]
file_filter = src/modules/dummypythonqt/lang/<lang>/LC_MESSAGES/dummypythonqt.po file_filter = src/modules/dummypythonqt/lang/<lang>/LC_MESSAGES/dummypythonqt.po
source_file = src/modules/dummypythonqt/lang/dummypythonqt.pot source_file = src/modules/dummypythonqt/lang/dummypythonqt.pot

11
CHANGES
View File

@ -9,10 +9,17 @@ This release contains contributions from (alphabetically by first name):
- No other contributors this time around. - No other contributors this time around.
## Core ## ## Core ##
- No changes to core functionality. - Timezone support code has migrated into the core of Calamares. This
means that modules now have easier access to timezone information.
Translations for timezones have also been enabled, so it is **possible**
at least to translate the displayed zones in the *welcome* module.
## Modules ## ## Modules ##
- No changes to modules. - The *license* module has seen a significant change to its looks.
Actions are now labeled more clearly, and the URL (or filename)
for each license is displayed.
- The *welcome* module now supports translations for timezone and
location names (e.g. "Berlin" is "Berlijn" in Dutch).
# 3.2.17.1 (2019-12-02) # # 3.2.17.1 (2019-12-02) #

View File

@ -67,8 +67,12 @@ macro(add_calamares_translations language)
# calamares and qt language files # calamares and qt language files
set( calamares_i18n_qrc_content "${calamares_i18n_qrc_content}<qresource prefix=\"/lang\">\n" ) set( calamares_i18n_qrc_content "${calamares_i18n_qrc_content}<qresource prefix=\"/lang\">\n" )
foreach( lang ${CALAMARES_LANGUAGES} ) foreach( lang ${CALAMARES_LANGUAGES} )
set( calamares_i18n_qrc_content "${calamares_i18n_qrc_content}<file>calamares_${lang}.qm</file>\n" ) foreach( tlsource "calamares_${lang}" "tz_${lang}" )
list( APPEND TS_FILES "${CMAKE_SOURCE_DIR}/lang/calamares_${lang}.ts" ) if( EXISTS "${CMAKE_SOURCE_DIR}/lang/${tlsource}.ts" )
set( calamares_i18n_qrc_content "${calamares_i18n_qrc_content}<file>${tlsource}.qm</file>\n" )
list( APPEND TS_FILES "${CMAKE_SOURCE_DIR}/lang/${tlsource}.ts" )
endif()
endforeach()
endforeach() endforeach()
set( calamares_i18n_qrc_content "${calamares_i18n_qrc_content}</qresource>\n" ) set( calamares_i18n_qrc_content "${calamares_i18n_qrc_content}</qresource>\n" )

View File

@ -50,12 +50,17 @@ fi
# sources, then push to Transifex # sources, then push to Transifex
export QT_SELECT=5 export QT_SELECT=5
lupdate -version > /dev/null 2>&1 || export QT_SELECT=qt5
lupdate -version > /dev/null 2>&1 || { echo "! No working lupdate" ; lupdate -version ; exit 1 ; }
# Don't pull branding translations in, # Don't pull branding translations in,
# those are done separately. # those are done separately.
_srcdirs="src/calamares src/libcalamares src/libcalamaresui src/modules src/qml" _srcdirs="src/calamares src/libcalamares src/libcalamaresui src/modules src/qml"
lupdate $_srcdirs -ts -no-obsolete lang/calamares_en.ts lupdate -no-obsolete $_srcdirs -ts lang/calamares_en.ts
lupdate -no-obsolete -extensions cxxtr src/libcalamares/locale -ts lang/tz_en.ts
tx push --source --no-interactive -r calamares.calamares-master tx push --source --no-interactive -r calamares.calamares-master
tx push --source --no-interactive -r calamares.tz
tx push --source --no-interactive -r calamares.fdo tx push --source --no-interactive -r calamares.fdo
### PYTHON MODULES ### PYTHON MODULES

2617
lang/tz_en.ts Normal file

File diff suppressed because it is too large Load Diff

2617
lang/tz_nl.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,7 @@ set( libSources
locale/Label.cpp locale/Label.cpp
locale/LabelModel.cpp locale/LabelModel.cpp
locale/Lookup.cpp locale/Lookup.cpp
locale/TimeZone.cpp
locale/TranslatableConfiguration.cpp locale/TranslatableConfiguration.cpp
# Network service # Network service

View File

@ -15,6 +15,13 @@
* Conditions herein. * Conditions herein.
*/ */
/* MODIFICATIONS
*
* Edited anyway:
* 20191211 India changed to AnyLanguage, since Hindi doesn't make sense. #1284
*
*/
// BEGIN Generated from CLDR data // BEGIN Generated from CLDR data
// *INDENT-OFF* // *INDENT-OFF*
// clang-format off // clang-format off
@ -115,7 +122,7 @@ static const CountryData country_data_table[] = {
{ QLocale::Language::Spanish, QLocale::Country::CanaryIslands, 'I', 'C' }, { QLocale::Language::Spanish, QLocale::Country::CanaryIslands, 'I', 'C' },
{ QLocale::Language::Indonesian, QLocale::Country::Indonesia, 'I', 'D' }, { QLocale::Language::Indonesian, QLocale::Country::Indonesia, 'I', 'D' },
{ QLocale::Language::Hebrew, QLocale::Country::Israel, 'I', 'L' }, { QLocale::Language::Hebrew, QLocale::Country::Israel, 'I', 'L' },
{ QLocale::Language::Hindi, QLocale::Country::India, 'I', 'N' }, { QLocale::Language::AnyLanguage, QLocale::Country::India, 'I', 'N' },
{ QLocale::Language::Arabic, QLocale::Country::Iraq, 'I', 'Q' }, { QLocale::Language::Arabic, QLocale::Country::Iraq, 'I', 'Q' },
{ QLocale::Language::Persian, QLocale::Country::Iran, 'I', 'R' }, { QLocale::Language::Persian, QLocale::Country::Iran, 'I', 'R' },
{ QLocale::Language::Icelandic, QLocale::Country::Iceland, 'I', 'S' }, { QLocale::Language::Icelandic, QLocale::Country::Iceland, 'I', 'S' },

View File

@ -19,6 +19,7 @@
#include "Tests.h" #include "Tests.h"
#include "locale/LabelModel.h" #include "locale/LabelModel.h"
#include "locale/TimeZone.h"
#include "locale/TranslatableConfiguration.h" #include "locale/TranslatableConfiguration.h"
#include "CalamaresVersion.h" #include "CalamaresVersion.h"
@ -199,3 +200,55 @@ LocaleTests::testTranslatableConfig2()
QVERIFY( ts3.isEmpty() ); QVERIFY( ts3.isEmpty() );
QCOMPARE( ts3.count(), 1 ); // The empty string QCOMPARE( ts3.count(), 1 ); // The empty string
} }
void
LocaleTests::testSimpleZones()
{
using namespace CalamaresUtils::Locale;
{
TZRegion r;
QVERIFY( r.tr().isEmpty() );
}
{
TZZone n;
QVERIFY( n.tr().isEmpty() );
}
{
TZRegion r0( "xAmsterdam" );
QCOMPARE( r0.tr(), QStringLiteral( "xAmsterdam" ) );
TZRegion r1( r0 );
QCOMPARE( r0.tr(), QStringLiteral( "xAmsterdam" ) );
QCOMPARE( r1.tr(), QStringLiteral( "xAmsterdam" ) );
TZRegion r2( std::move( r0 ) );
QCOMPARE( r2.tr(), QStringLiteral( "xAmsterdam" ) );
QCOMPARE( r0.tr(), QString() );
}
{
TZZone r0( nullptr );
QVERIFY( r0.tr().isEmpty() );
TZZone r1( r0 );
QVERIFY( r1.tr().isEmpty() );
TZZone r2( std::move( r0 ) );
QVERIFY( r2.tr().isEmpty() );
}
}
void
LocaleTests::testComplexZones()
{
using namespace CalamaresUtils::Locale;
{
TZZone r0( "America/New_York" );
TZZone r1( "America/New York" );
QCOMPARE( r0.tr(), r1.tr() );
QCOMPARE( r0.tr(), QStringLiteral( "America/New York" ) );
}
{
TZZone r( "zxc,;*_vm" );
QVERIFY( !r.tr().isEmpty() );
QCOMPARE( r.tr(), QStringLiteral( "zxc,;* vm" ) ); // Only _ is special
}
}

View File

@ -36,6 +36,10 @@ private Q_SLOTS:
void testTranslatableLanguages(); void testTranslatableLanguages();
void testTranslatableConfig1(); void testTranslatableConfig1();
void testTranslatableConfig2(); void testTranslatableConfig2();
// TimeZone testing
void testSimpleZones();
void testComplexZones();
}; };
#endif #endif

View File

@ -0,0 +1,279 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TimeZone.h"
#include "utils/Logger.h"
#include <QFile>
#include <QStringList>
#include <QTextStream>
#include <cstring>
static const char TZ_DATA_FILE[] = "/usr/share/zoneinfo/zone.tab";
static double
getRightGeoLocation( QString str )
{
double sign = 1, num = 0.00;
// Determine sign
if ( str.startsWith( '-' ) )
{
sign = -1;
str.remove( 0, 1 );
}
else if ( str.startsWith( '+' ) )
{
str.remove( 0, 1 );
}
if ( str.length() == 4 || str.length() == 6 )
{
num = str.mid( 0, 2 ).toDouble() + str.mid( 2, 2 ).toDouble() / 60.0;
}
else if ( str.length() == 5 || str.length() == 7 )
{
num = str.mid( 0, 3 ).toDouble() + str.mid( 3, 2 ).toDouble() / 60.0;
}
return sign * num;
}
namespace CalamaresUtils
{
namespace Locale
{
CStringPair::CStringPair( CStringPair&& t )
: m_human( nullptr )
, m_key()
{
// My pointers are initialized to nullptr
std::swap( m_human, t.m_human );
std::swap( m_key, t.m_key );
}
CStringPair::CStringPair( const CStringPair& t )
: m_human( t.m_human ? strdup( t.m_human ) : nullptr )
, m_key( t.m_key )
{
}
/** @brief Massage an identifier into a human-readable form
*
* Makes a copy of @p s, caller must free() it.
*/
static char*
munge( const char* s )
{
char* t = strdup( s );
if ( !t )
{
return nullptr;
}
// replace("_"," ") in the Python script
char* p = t;
while ( *p )
{
if ( ( *p ) == '_' )
{
*p = ' ';
}
++p;
}
return t;
}
CStringPair::CStringPair( const char* s1 )
: m_human( s1 ? munge( s1 ) : nullptr )
, m_key( s1 ? QString( s1 ) : QString() )
{
}
CStringPair::~CStringPair()
{
free( m_human );
}
QString
TZRegion::tr() const
{
// NOTE: context name must match what's used in zone-extractor.py
return QObject::tr( m_human, "tz_regions" );
}
TZRegion::~TZRegion()
{
qDeleteAll( m_zones );
}
const CStringPairList&
TZRegion::fromZoneTab()
{
static CStringPairList zoneTab = TZRegion::fromFile( TZ_DATA_FILE );
return zoneTab;
}
CStringPairList
TZRegion::fromFile( const char* fileName )
{
CStringPairList model;
QFile file( fileName );
if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
{
return model;
}
TZRegion* thisRegion = nullptr;
QTextStream in( &file );
while ( !in.atEnd() )
{
QString line = in.readLine().trimmed().split( '#', QString::KeepEmptyParts ).first().trimmed();
if ( line.isEmpty() )
{
continue;
}
QStringList list = line.split( QRegExp( "[\t ]" ), QString::SkipEmptyParts );
if ( list.size() < 3 )
{
continue;
}
QStringList timezoneParts = list.at( 2 ).split( '/', QString::SkipEmptyParts );
if ( timezoneParts.size() < 2 )
{
continue;
}
QString region = timezoneParts.first().trimmed();
;
if ( region.isEmpty() )
{
continue;
}
auto keyMatch = [&region]( const CStringPair* r ) { return r->key() == region; };
auto it = std::find_if( model.begin(), model.end(), keyMatch );
if ( it != model.end() )
{
thisRegion = dynamic_cast< TZRegion* >( *it );
}
else
{
thisRegion = new TZRegion( region.toUtf8().data() );
model.append( thisRegion );
}
QString countryCode = list.at( 0 ).trimmed();
if ( countryCode.size() != 2 )
{
continue;
}
timezoneParts.removeFirst();
thisRegion->m_zones.append(
new TZZone( region, timezoneParts.join( '/' ).toUtf8().constData(), countryCode, list.at( 1 ) ) );
}
auto sorter = []( const CStringPair* l, const CStringPair* r ) { return *l < *r; };
std::sort( model.begin(), model.end(), sorter );
for ( auto& it : model )
{
TZRegion* r = dynamic_cast< TZRegion* >( it );
if ( r )
{
std::sort( r->m_zones.begin(), r->m_zones.end(), sorter );
}
}
return model;
}
TZZone::TZZone( const QString& region, const char* zoneName, const QString& country, QString position )
: CStringPair( zoneName )
, m_region( region )
, m_country( country )
{
int cooSplitPos = position.indexOf( QRegExp( "[-+]" ), 1 );
if ( cooSplitPos > 0 )
{
m_latitude = getRightGeoLocation( position.mid( 0, cooSplitPos ) );
m_longitude = getRightGeoLocation( position.mid( cooSplitPos ) );
}
}
QString
TZZone::tr() const
{
// NOTE: context name must match what's used in zone-extractor.py
return QObject::tr( m_human, "tz_names" );
}
CStringListModel::CStringListModel( CStringPairList l )
: m_list( l )
{
}
CStringListModel::~CStringListModel() {}
int
CStringListModel::rowCount( const QModelIndex& parent ) const
{
return m_list.count();
}
QVariant
CStringListModel::data( const QModelIndex& index, int role ) const
{
if ( ( role != Qt::DisplayRole ) && ( role != Qt::UserRole ) )
{
return QVariant();
}
if ( !index.isValid() )
{
return QVariant();
}
const auto* item = m_list.at( index.row() );
return item ? ( role == Qt::DisplayRole ? item->tr() : item->key() ) : QVariant();
}
const CStringPair*
CStringListModel::item( int index ) const
{
if ( ( index < 0 ) || ( index >= m_list.count() ) )
{
return nullptr;
}
return m_list[ index ];
}
} // namespace Locale
} // namespace CalamaresUtils

View File

@ -0,0 +1,159 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LOCALE_TIMEZONE_H
#define LOCALE_TIMEZONE_H
#include "DllMacro.h"
#include "utils/Logger.h"
#include <QAbstractListModel>
#include <QObject>
#include <QString>
#include <memory>
namespace CalamaresUtils
{
namespace Locale
{
/** @brief A pair of strings, one human-readable, one a key
*
* Given an identifier-like string (e.g. "New_York"), makes
* a human-readable version of that and keeps a copy of the
* identifier itself.
*
* This explicitly uses const char* instead of just being
* QPair<QString, QString> because there is API that needs
* C-style strings.
*/
class CStringPair
{
public:
/// @brief An empty pair
CStringPair() {};
/// @brief Given an identifier, create the pair
explicit CStringPair( const char* s1 );
CStringPair( CStringPair&& t );
CStringPair( const CStringPair& );
virtual ~CStringPair();
/// @brief Give the localized human-readable form
virtual QString tr() const = 0;
QString key() const { return m_key; }
bool operator<( const CStringPair& other ) const { return m_key < other.m_key; }
protected:
char* m_human = nullptr;
QString m_key;
};
class CStringPairList : public QList< CStringPair* >
{
public:
template < typename T >
T* find( const QString& key ) const
{
for ( auto* p : *this )
{
if ( p->key() == key )
{
return dynamic_cast< T* >( p );
}
}
return nullptr;
}
};
/// @brief A pair of strings for timezone regions (e.g. "America")
class TZRegion : public CStringPair
{
public:
using CStringPair::CStringPair;
virtual ~TZRegion();
QString tr() const override;
QString region() const { return key(); }
/** @brief Create list from a zone.tab-like file
*
* Returns a list of all the regions; each region has a list
* of zones within that region. Dyamically, the items in the
* returned list are TZRegions; their zones dynamically are
* TZZones even though all those lists have type CStringPairList.
*
* The list owns the regions, and the regions own their own list of zones.
* When getting rid of the list, remember to qDeleteAll() on it.
*/
static CStringPairList fromFile( const char* fileName );
/// @brief Calls fromFile with the standard zone.tab name
static const CStringPairList& fromZoneTab();
const CStringPairList& zones() const { return m_zones; }
private:
CStringPairList m_zones;
};
/// @brief A pair of strings for specific timezone names (e.g. "New_York")
class TZZone : public CStringPair
{
public:
using CStringPair::CStringPair;
QString tr() const override;
TZZone( const QString& region, const char* zoneName, const QString& country, QString position );
QString region() const { return m_region; }
QString zone() const { return key(); }
QString country() const { return m_country; }
double latitude() const { return m_latitude; }
double longitude() const { return m_longitude; }
protected:
QString m_region;
QString m_country;
double m_latitude = 0.0, m_longitude = 0.0;
};
class CStringListModel : public QAbstractListModel
{
public:
/// @brief Create empty model
CStringListModel();
/// @brief Create model from list (non-owning)
CStringListModel( CStringPairList );
virtual ~CStringListModel() override;
int rowCount( const QModelIndex& parent ) const override;
QVariant data( const QModelIndex& index, int role ) const override;
const CStringPair* item( int index ) const;
private:
CStringPairList m_list;
};
} // namespace Locale
} // namespace CalamaresUtils
#endif // LOCALE_TIMEZONE_H

View File

@ -0,0 +1,478 @@
/* GENERATED FILE DO NOT EDIT
*
* === This file is part of Calamares - <https://github.com/calamares> ===
*
* This file is derived from zone.tab, which has its own copyright statement:
*
* This file is in the public domain, so clarified as of
* 2009-05-17 by Arthur David Olson.
*
* From Paul Eggert (2018-06-27):
* This file is intended as a backward-compatibility aid for older programs.
* New programs should use zone1970.tab. This file is like zone1970.tab (see
* zone1970.tab's comments), but with the following additional restrictions:
*
* 1. This file contains only ASCII characters.
* 2. The first data column contains exactly one country code.
*
*/
/** THIS FILE EXISTS ONLY FOR TRANSLATIONS PURPOSES **/
// *INDENT-OFF*
// clang-format off
/* This returns a reference to local, which is a terrible idea.
* Good thing it's not meant to be compiled.
*/
static const QStringList& tz_regions_table()
{
return QStringList {
QObject::tr("Africa", "tz_regions"),
QObject::tr("America", "tz_regions"),
QObject::tr("Antarctica", "tz_regions"),
QObject::tr("Arctic", "tz_regions"),
QObject::tr("Asia", "tz_regions"),
QObject::tr("Atlantic", "tz_regions"),
QObject::tr("Australia", "tz_regions"),
QObject::tr("Europe", "tz_regions"),
QObject::tr("Indian", "tz_regions"),
QObject::tr("Pacific", "tz_regions"),
QString()
};
}
/* This returns a reference to local, which is a terrible idea.
* Good thing it's not meant to be compiled.
*/
static const QStringList& tz_names_table()
{
return QStringList {
QObject::tr("Abidjan", "tz_names"),
QObject::tr("Accra", "tz_names"),
QObject::tr("Adak", "tz_names"),
QObject::tr("Addis Ababa", "tz_names"),
QObject::tr("Adelaide", "tz_names"),
QObject::tr("Aden", "tz_names"),
QObject::tr("Algiers", "tz_names"),
QObject::tr("Almaty", "tz_names"),
QObject::tr("Amman", "tz_names"),
QObject::tr("Amsterdam", "tz_names"),
QObject::tr("Anadyr", "tz_names"),
QObject::tr("Anchorage", "tz_names"),
QObject::tr("Andorra", "tz_names"),
QObject::tr("Anguilla", "tz_names"),
QObject::tr("Antananarivo", "tz_names"),
QObject::tr("Antigua", "tz_names"),
QObject::tr("Apia", "tz_names"),
QObject::tr("Aqtau", "tz_names"),
QObject::tr("Aqtobe", "tz_names"),
QObject::tr("Araguaina", "tz_names"),
QObject::tr("Argentina/Buenos Aires", "tz_names"),
QObject::tr("Argentina/Catamarca", "tz_names"),
QObject::tr("Argentina/Cordoba", "tz_names"),
QObject::tr("Argentina/Jujuy", "tz_names"),
QObject::tr("Argentina/La Rioja", "tz_names"),
QObject::tr("Argentina/Mendoza", "tz_names"),
QObject::tr("Argentina/Rio Gallegos", "tz_names"),
QObject::tr("Argentina/Salta", "tz_names"),
QObject::tr("Argentina/San Juan", "tz_names"),
QObject::tr("Argentina/San Luis", "tz_names"),
QObject::tr("Argentina/Tucuman", "tz_names"),
QObject::tr("Argentina/Ushuaia", "tz_names"),
QObject::tr("Aruba", "tz_names"),
QObject::tr("Ashgabat", "tz_names"),
QObject::tr("Asmara", "tz_names"),
QObject::tr("Astrakhan", "tz_names"),
QObject::tr("Asuncion", "tz_names"),
QObject::tr("Athens", "tz_names"),
QObject::tr("Atikokan", "tz_names"),
QObject::tr("Atyrau", "tz_names"),
QObject::tr("Auckland", "tz_names"),
QObject::tr("Azores", "tz_names"),
QObject::tr("Baghdad", "tz_names"),
QObject::tr("Bahia", "tz_names"),
QObject::tr("Bahia Banderas", "tz_names"),
QObject::tr("Bahrain", "tz_names"),
QObject::tr("Baku", "tz_names"),
QObject::tr("Bamako", "tz_names"),
QObject::tr("Bangkok", "tz_names"),
QObject::tr("Bangui", "tz_names"),
QObject::tr("Banjul", "tz_names"),
QObject::tr("Barbados", "tz_names"),
QObject::tr("Barnaul", "tz_names"),
QObject::tr("Beirut", "tz_names"),
QObject::tr("Belem", "tz_names"),
QObject::tr("Belgrade", "tz_names"),
QObject::tr("Belize", "tz_names"),
QObject::tr("Berlin", "tz_names"),
QObject::tr("Bermuda", "tz_names"),
QObject::tr("Bishkek", "tz_names"),
QObject::tr("Bissau", "tz_names"),
QObject::tr("Blanc-Sablon", "tz_names"),
QObject::tr("Blantyre", "tz_names"),
QObject::tr("Boa Vista", "tz_names"),
QObject::tr("Bogota", "tz_names"),
QObject::tr("Boise", "tz_names"),
QObject::tr("Bougainville", "tz_names"),
QObject::tr("Bratislava", "tz_names"),
QObject::tr("Brazzaville", "tz_names"),
QObject::tr("Brisbane", "tz_names"),
QObject::tr("Broken Hill", "tz_names"),
QObject::tr("Brunei", "tz_names"),
QObject::tr("Brussels", "tz_names"),
QObject::tr("Bucharest", "tz_names"),
QObject::tr("Budapest", "tz_names"),
QObject::tr("Bujumbura", "tz_names"),
QObject::tr("Busingen", "tz_names"),
QObject::tr("Cairo", "tz_names"),
QObject::tr("Cambridge Bay", "tz_names"),
QObject::tr("Campo Grande", "tz_names"),
QObject::tr("Canary", "tz_names"),
QObject::tr("Cancun", "tz_names"),
QObject::tr("Cape Verde", "tz_names"),
QObject::tr("Caracas", "tz_names"),
QObject::tr("Casablanca", "tz_names"),
QObject::tr("Casey", "tz_names"),
QObject::tr("Cayenne", "tz_names"),
QObject::tr("Cayman", "tz_names"),
QObject::tr("Ceuta", "tz_names"),
QObject::tr("Chagos", "tz_names"),
QObject::tr("Chatham", "tz_names"),
QObject::tr("Chicago", "tz_names"),
QObject::tr("Chihuahua", "tz_names"),
QObject::tr("Chisinau", "tz_names"),
QObject::tr("Chita", "tz_names"),
QObject::tr("Choibalsan", "tz_names"),
QObject::tr("Christmas", "tz_names"),
QObject::tr("Chuuk", "tz_names"),
QObject::tr("Cocos", "tz_names"),
QObject::tr("Colombo", "tz_names"),
QObject::tr("Comoro", "tz_names"),
QObject::tr("Conakry", "tz_names"),
QObject::tr("Copenhagen", "tz_names"),
QObject::tr("Costa Rica", "tz_names"),
QObject::tr("Creston", "tz_names"),
QObject::tr("Cuiaba", "tz_names"),
QObject::tr("Curacao", "tz_names"),
QObject::tr("Currie", "tz_names"),
QObject::tr("Dakar", "tz_names"),
QObject::tr("Damascus", "tz_names"),
QObject::tr("Danmarkshavn", "tz_names"),
QObject::tr("Dar es Salaam", "tz_names"),
QObject::tr("Darwin", "tz_names"),
QObject::tr("Davis", "tz_names"),
QObject::tr("Dawson", "tz_names"),
QObject::tr("Dawson Creek", "tz_names"),
QObject::tr("Denver", "tz_names"),
QObject::tr("Detroit", "tz_names"),
QObject::tr("Dhaka", "tz_names"),
QObject::tr("Dili", "tz_names"),
QObject::tr("Djibouti", "tz_names"),
QObject::tr("Dominica", "tz_names"),
QObject::tr("Douala", "tz_names"),
QObject::tr("Dubai", "tz_names"),
QObject::tr("Dublin", "tz_names"),
QObject::tr("DumontDUrville", "tz_names"),
QObject::tr("Dushanbe", "tz_names"),
QObject::tr("Easter", "tz_names"),
QObject::tr("Edmonton", "tz_names"),
QObject::tr("Efate", "tz_names"),
QObject::tr("Eirunepe", "tz_names"),
QObject::tr("El Aaiun", "tz_names"),
QObject::tr("El Salvador", "tz_names"),
QObject::tr("Enderbury", "tz_names"),
QObject::tr("Eucla", "tz_names"),
QObject::tr("Fakaofo", "tz_names"),
QObject::tr("Famagusta", "tz_names"),
QObject::tr("Faroe", "tz_names"),
QObject::tr("Fiji", "tz_names"),
QObject::tr("Fort Nelson", "tz_names"),
QObject::tr("Fortaleza", "tz_names"),
QObject::tr("Freetown", "tz_names"),
QObject::tr("Funafuti", "tz_names"),
QObject::tr("Gaborone", "tz_names"),
QObject::tr("Galapagos", "tz_names"),
QObject::tr("Gambier", "tz_names"),
QObject::tr("Gaza", "tz_names"),
QObject::tr("Gibraltar", "tz_names"),
QObject::tr("Glace Bay", "tz_names"),
QObject::tr("Godthab", "tz_names"),
QObject::tr("Goose Bay", "tz_names"),
QObject::tr("Grand Turk", "tz_names"),
QObject::tr("Grenada", "tz_names"),
QObject::tr("Guadalcanal", "tz_names"),
QObject::tr("Guadeloupe", "tz_names"),
QObject::tr("Guam", "tz_names"),
QObject::tr("Guatemala", "tz_names"),
QObject::tr("Guayaquil", "tz_names"),
QObject::tr("Guernsey", "tz_names"),
QObject::tr("Guyana", "tz_names"),
QObject::tr("Halifax", "tz_names"),
QObject::tr("Harare", "tz_names"),
QObject::tr("Havana", "tz_names"),
QObject::tr("Hebron", "tz_names"),
QObject::tr("Helsinki", "tz_names"),
QObject::tr("Hermosillo", "tz_names"),
QObject::tr("Ho Chi Minh", "tz_names"),
QObject::tr("Hobart", "tz_names"),
QObject::tr("Hong Kong", "tz_names"),
QObject::tr("Honolulu", "tz_names"),
QObject::tr("Hovd", "tz_names"),
QObject::tr("Indiana/Indianapolis", "tz_names"),
QObject::tr("Indiana/Knox", "tz_names"),
QObject::tr("Indiana/Marengo", "tz_names"),
QObject::tr("Indiana/Petersburg", "tz_names"),
QObject::tr("Indiana/Tell City", "tz_names"),
QObject::tr("Indiana/Vevay", "tz_names"),
QObject::tr("Indiana/Vincennes", "tz_names"),
QObject::tr("Indiana/Winamac", "tz_names"),
QObject::tr("Inuvik", "tz_names"),
QObject::tr("Iqaluit", "tz_names"),
QObject::tr("Irkutsk", "tz_names"),
QObject::tr("Isle of Man", "tz_names"),
QObject::tr("Istanbul", "tz_names"),
QObject::tr("Jakarta", "tz_names"),
QObject::tr("Jamaica", "tz_names"),
QObject::tr("Jayapura", "tz_names"),
QObject::tr("Jersey", "tz_names"),
QObject::tr("Jerusalem", "tz_names"),
QObject::tr("Johannesburg", "tz_names"),
QObject::tr("Juba", "tz_names"),
QObject::tr("Juneau", "tz_names"),
QObject::tr("Kabul", "tz_names"),
QObject::tr("Kaliningrad", "tz_names"),
QObject::tr("Kamchatka", "tz_names"),
QObject::tr("Kampala", "tz_names"),
QObject::tr("Karachi", "tz_names"),
QObject::tr("Kathmandu", "tz_names"),
QObject::tr("Kentucky/Louisville", "tz_names"),
QObject::tr("Kentucky/Monticello", "tz_names"),
QObject::tr("Kerguelen", "tz_names"),
QObject::tr("Khandyga", "tz_names"),
QObject::tr("Khartoum", "tz_names"),
QObject::tr("Kiev", "tz_names"),
QObject::tr("Kigali", "tz_names"),
QObject::tr("Kinshasa", "tz_names"),
QObject::tr("Kiritimati", "tz_names"),
QObject::tr("Kirov", "tz_names"),
QObject::tr("Kolkata", "tz_names"),
QObject::tr("Kosrae", "tz_names"),
QObject::tr("Kralendijk", "tz_names"),
QObject::tr("Krasnoyarsk", "tz_names"),
QObject::tr("Kuala Lumpur", "tz_names"),
QObject::tr("Kuching", "tz_names"),
QObject::tr("Kuwait", "tz_names"),
QObject::tr("Kwajalein", "tz_names"),
QObject::tr("La Paz", "tz_names"),
QObject::tr("Lagos", "tz_names"),
QObject::tr("Libreville", "tz_names"),
QObject::tr("Lima", "tz_names"),
QObject::tr("Lindeman", "tz_names"),
QObject::tr("Lisbon", "tz_names"),
QObject::tr("Ljubljana", "tz_names"),
QObject::tr("Lome", "tz_names"),
QObject::tr("London", "tz_names"),
QObject::tr("Longyearbyen", "tz_names"),
QObject::tr("Lord Howe", "tz_names"),
QObject::tr("Los Angeles", "tz_names"),
QObject::tr("Lower Princes", "tz_names"),
QObject::tr("Luanda", "tz_names"),
QObject::tr("Lubumbashi", "tz_names"),
QObject::tr("Lusaka", "tz_names"),
QObject::tr("Luxembourg", "tz_names"),
QObject::tr("Macau", "tz_names"),
QObject::tr("Maceio", "tz_names"),
QObject::tr("Macquarie", "tz_names"),
QObject::tr("Madeira", "tz_names"),
QObject::tr("Madrid", "tz_names"),
QObject::tr("Magadan", "tz_names"),
QObject::tr("Mahe", "tz_names"),
QObject::tr("Majuro", "tz_names"),
QObject::tr("Makassar", "tz_names"),
QObject::tr("Malabo", "tz_names"),
QObject::tr("Maldives", "tz_names"),
QObject::tr("Malta", "tz_names"),
QObject::tr("Managua", "tz_names"),
QObject::tr("Manaus", "tz_names"),
QObject::tr("Manila", "tz_names"),
QObject::tr("Maputo", "tz_names"),
QObject::tr("Mariehamn", "tz_names"),
QObject::tr("Marigot", "tz_names"),
QObject::tr("Marquesas", "tz_names"),
QObject::tr("Martinique", "tz_names"),
QObject::tr("Maseru", "tz_names"),
QObject::tr("Matamoros", "tz_names"),
QObject::tr("Mauritius", "tz_names"),
QObject::tr("Mawson", "tz_names"),
QObject::tr("Mayotte", "tz_names"),
QObject::tr("Mazatlan", "tz_names"),
QObject::tr("Mbabane", "tz_names"),
QObject::tr("McMurdo", "tz_names"),
QObject::tr("Melbourne", "tz_names"),
QObject::tr("Menominee", "tz_names"),
QObject::tr("Merida", "tz_names"),
QObject::tr("Metlakatla", "tz_names"),
QObject::tr("Mexico City", "tz_names"),
QObject::tr("Midway", "tz_names"),
QObject::tr("Minsk", "tz_names"),
QObject::tr("Miquelon", "tz_names"),
QObject::tr("Mogadishu", "tz_names"),
QObject::tr("Monaco", "tz_names"),
QObject::tr("Moncton", "tz_names"),
QObject::tr("Monrovia", "tz_names"),
QObject::tr("Monterrey", "tz_names"),
QObject::tr("Montevideo", "tz_names"),
QObject::tr("Montserrat", "tz_names"),
QObject::tr("Moscow", "tz_names"),
QObject::tr("Muscat", "tz_names"),
QObject::tr("Nairobi", "tz_names"),
QObject::tr("Nassau", "tz_names"),
QObject::tr("Nauru", "tz_names"),
QObject::tr("Ndjamena", "tz_names"),
QObject::tr("New York", "tz_names"),
QObject::tr("Niamey", "tz_names"),
QObject::tr("Nicosia", "tz_names"),
QObject::tr("Nipigon", "tz_names"),
QObject::tr("Niue", "tz_names"),
QObject::tr("Nome", "tz_names"),
QObject::tr("Norfolk", "tz_names"),
QObject::tr("Noronha", "tz_names"),
QObject::tr("North Dakota/Beulah", "tz_names"),
QObject::tr("North Dakota/Center", "tz_names"),
QObject::tr("North Dakota/New Salem", "tz_names"),
QObject::tr("Nouakchott", "tz_names"),
QObject::tr("Noumea", "tz_names"),
QObject::tr("Novokuznetsk", "tz_names"),
QObject::tr("Novosibirsk", "tz_names"),
QObject::tr("Ojinaga", "tz_names"),
QObject::tr("Omsk", "tz_names"),
QObject::tr("Oral", "tz_names"),
QObject::tr("Oslo", "tz_names"),
QObject::tr("Ouagadougou", "tz_names"),
QObject::tr("Pago Pago", "tz_names"),
QObject::tr("Palau", "tz_names"),
QObject::tr("Palmer", "tz_names"),
QObject::tr("Panama", "tz_names"),
QObject::tr("Pangnirtung", "tz_names"),
QObject::tr("Paramaribo", "tz_names"),
QObject::tr("Paris", "tz_names"),
QObject::tr("Perth", "tz_names"),
QObject::tr("Phnom Penh", "tz_names"),
QObject::tr("Phoenix", "tz_names"),
QObject::tr("Pitcairn", "tz_names"),
QObject::tr("Podgorica", "tz_names"),
QObject::tr("Pohnpei", "tz_names"),
QObject::tr("Pontianak", "tz_names"),
QObject::tr("Port Moresby", "tz_names"),
QObject::tr("Port of Spain", "tz_names"),
QObject::tr("Port-au-Prince", "tz_names"),
QObject::tr("Porto Velho", "tz_names"),
QObject::tr("Porto-Novo", "tz_names"),
QObject::tr("Prague", "tz_names"),
QObject::tr("Puerto Rico", "tz_names"),
QObject::tr("Punta Arenas", "tz_names"),
QObject::tr("Pyongyang", "tz_names"),
QObject::tr("Qatar", "tz_names"),
QObject::tr("Qostanay", "tz_names"),
QObject::tr("Qyzylorda", "tz_names"),
QObject::tr("Rainy River", "tz_names"),
QObject::tr("Rankin Inlet", "tz_names"),
QObject::tr("Rarotonga", "tz_names"),
QObject::tr("Recife", "tz_names"),
QObject::tr("Regina", "tz_names"),
QObject::tr("Resolute", "tz_names"),
QObject::tr("Reunion", "tz_names"),
QObject::tr("Reykjavik", "tz_names"),
QObject::tr("Riga", "tz_names"),
QObject::tr("Rio Branco", "tz_names"),
QObject::tr("Riyadh", "tz_names"),
QObject::tr("Rome", "tz_names"),
QObject::tr("Rothera", "tz_names"),
QObject::tr("Saipan", "tz_names"),
QObject::tr("Sakhalin", "tz_names"),
QObject::tr("Samara", "tz_names"),
QObject::tr("Samarkand", "tz_names"),
QObject::tr("San Marino", "tz_names"),
QObject::tr("Santarem", "tz_names"),
QObject::tr("Santiago", "tz_names"),
QObject::tr("Santo Domingo", "tz_names"),
QObject::tr("Sao Paulo", "tz_names"),
QObject::tr("Sao Tome", "tz_names"),
QObject::tr("Sarajevo", "tz_names"),
QObject::tr("Saratov", "tz_names"),
QObject::tr("Scoresbysund", "tz_names"),
QObject::tr("Seoul", "tz_names"),
QObject::tr("Shanghai", "tz_names"),
QObject::tr("Simferopol", "tz_names"),
QObject::tr("Singapore", "tz_names"),
QObject::tr("Sitka", "tz_names"),
QObject::tr("Skopje", "tz_names"),
QObject::tr("Sofia", "tz_names"),
QObject::tr("South Georgia", "tz_names"),
QObject::tr("Srednekolymsk", "tz_names"),
QObject::tr("St Barthelemy", "tz_names"),
QObject::tr("St Helena", "tz_names"),
QObject::tr("St Johns", "tz_names"),
QObject::tr("St Kitts", "tz_names"),
QObject::tr("St Lucia", "tz_names"),
QObject::tr("St Thomas", "tz_names"),
QObject::tr("St Vincent", "tz_names"),
QObject::tr("Stanley", "tz_names"),
QObject::tr("Stockholm", "tz_names"),
QObject::tr("Swift Current", "tz_names"),
QObject::tr("Sydney", "tz_names"),
QObject::tr("Syowa", "tz_names"),
QObject::tr("Tahiti", "tz_names"),
QObject::tr("Taipei", "tz_names"),
QObject::tr("Tallinn", "tz_names"),
QObject::tr("Tarawa", "tz_names"),
QObject::tr("Tashkent", "tz_names"),
QObject::tr("Tbilisi", "tz_names"),
QObject::tr("Tegucigalpa", "tz_names"),
QObject::tr("Tehran", "tz_names"),
QObject::tr("Thimphu", "tz_names"),
QObject::tr("Thule", "tz_names"),
QObject::tr("Thunder Bay", "tz_names"),
QObject::tr("Tijuana", "tz_names"),
QObject::tr("Tirane", "tz_names"),
QObject::tr("Tokyo", "tz_names"),
QObject::tr("Tomsk", "tz_names"),
QObject::tr("Tongatapu", "tz_names"),
QObject::tr("Toronto", "tz_names"),
QObject::tr("Tortola", "tz_names"),
QObject::tr("Tripoli", "tz_names"),
QObject::tr("Troll", "tz_names"),
QObject::tr("Tunis", "tz_names"),
QObject::tr("Ulaanbaatar", "tz_names"),
QObject::tr("Ulyanovsk", "tz_names"),
QObject::tr("Urumqi", "tz_names"),
QObject::tr("Ust-Nera", "tz_names"),
QObject::tr("Uzhgorod", "tz_names"),
QObject::tr("Vaduz", "tz_names"),
QObject::tr("Vancouver", "tz_names"),
QObject::tr("Vatican", "tz_names"),
QObject::tr("Vienna", "tz_names"),
QObject::tr("Vientiane", "tz_names"),
QObject::tr("Vilnius", "tz_names"),
QObject::tr("Vladivostok", "tz_names"),
QObject::tr("Volgograd", "tz_names"),
QObject::tr("Vostok", "tz_names"),
QObject::tr("Wake", "tz_names"),
QObject::tr("Wallis", "tz_names"),
QObject::tr("Warsaw", "tz_names"),
QObject::tr("Whitehorse", "tz_names"),
QObject::tr("Windhoek", "tz_names"),
QObject::tr("Winnipeg", "tz_names"),
QObject::tr("Yakutat", "tz_names"),
QObject::tr("Yakutsk", "tz_names"),
QObject::tr("Yangon", "tz_names"),
QObject::tr("Yekaterinburg", "tz_names"),
QObject::tr("Yellowknife", "tz_names"),
QObject::tr("Yerevan", "tz_names"),
QObject::tr("Zagreb", "tz_names"),
QObject::tr("Zaporozhye", "tz_names"),
QObject::tr("Zurich", "tz_names"),
QString()
};
}

View File

@ -0,0 +1,108 @@
#! /usr/bin/env python3
#
# === This file is part of Calamares - <https://github.com/calamares> ===
#
# Python3 script to scrape some data out of zoneinfo/zone.tab.
#
### BEGIN LICENSES
#
# Copyright 2019 Adriaan de Groot <groot@kde.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
### END LICENSES
### BEGIN USAGE
#
"""
Python3 script to scrape some data out of zoneinfo/zone.tab.
To use this script, you must have a zone.tab in a standard location,
/usr/share/zoneinfo/zone.tab (this is usual on FreeBSD and Linux).
Prints out a few tables of zone names for use in translations.
"""
def scrape_file(file, regionset, zoneset):
for line in file.readlines():
if line.startswith("#"):
continue
parts = line.split("\t")
if len(parts) < 3:
continue
zoneid = parts[2]
if not "/" in zoneid:
continue
region, zone = zoneid.split("/", 1)
zone = zone.strip().replace("_", " ")
regionset.add(region)
assert(zone not in zoneset)
zoneset.add(zone)
def write_set(file, label, set):
file.write("/* This returns a reference to local, which is a terrible idea.\n * Good thing it's not meant to be compiled.\n */\n")
# Note {{ is an escaped { for Python string formatting
file.write("static const QStringList& {!s}_table()\n{{\n\treturn QStringList {{\n".format(label))
for x in sorted(set):
file.write("""\t\tQObject::tr("{!s}", "{!s}"),\n""".format(x, label))
file.write("\t\tQString()\n\t};\n}\n\n")
cpp_header_comment = """/* GENERATED FILE DO NOT EDIT
*
* === This file is part of Calamares - <https://github.com/calamares> ===
*
* This file is derived from zone.tab, which has its own copyright statement:
*
* This file is in the public domain, so clarified as of
* 2009-05-17 by Arthur David Olson.
*
* From Paul Eggert (2018-06-27):
* This file is intended as a backward-compatibility aid for older programs.
* New programs should use zone1970.tab. This file is like zone1970.tab (see
* zone1970.tab's comments), but with the following additional restrictions:
*
* 1. This file contains only ASCII characters.
* 2. The first data column contains exactly one country code.
*
*/
/** THIS FILE EXISTS ONLY FOR TRANSLATIONS PURPOSES **/
// *INDENT-OFF*
// clang-format off
"""
if __name__ == "__main__":
regions=set()
zones=set()
with open("/usr/share/zoneinfo/zone.tab", "r") as f:
scrape_file(f, regions, zones)
with open("ZoneData_p.cpp", "w") as f:
f.write(cpp_header_comment)
write_set(f, "tz_regions", regions)
write_set(f, "tz_names", zones)

View File

@ -25,90 +25,156 @@
#include <QEvent> #include <QEvent>
#include <QTranslator> #include <QTranslator>
/** @brief Helper class for loading translations
*
* This is used by the loadSingletonTranslator() function to hand off
* work to translation-type specific code.
*/
struct TranslationLoader
{
static QString mungeLocaleName( const QLocale& locale )
{
QString localeName = locale.name();
localeName.replace( "-", "_" );
if ( localeName == "C" )
{
localeName = "en";
}
// Special case of sr@latin
//
// See top-level CMakeLists.txt about special cases for translation loading.
if ( locale.language() == QLocale::Language::Serbian && locale.script() == QLocale::Script::LatinScript )
{
localeName = QStringLiteral( "sr@latin" );
}
return localeName;
}
TranslationLoader( const QLocale& locale )
: m_locale( locale )
, m_localeName( mungeLocaleName( locale ) )
{
}
virtual ~TranslationLoader() {};
/// @brief Loads @p translator with the specific translations of this type
virtual bool tryLoad( QTranslator* translator ) = 0;
const QLocale& m_locale;
QString m_localeName;
};
struct BrandingLoader : public TranslationLoader
{
BrandingLoader( const QLocale& locale, const QString& prefix )
: TranslationLoader( locale )
, m_prefix( prefix )
{
}
bool tryLoad( QTranslator* translator ) override
{
if ( m_prefix.isEmpty() )
{
return false;
}
QString brandingTranslationsDirPath( m_prefix );
brandingTranslationsDirPath.truncate( m_prefix.lastIndexOf( QDir::separator() ) );
QDir brandingTranslationsDir( brandingTranslationsDirPath );
if ( brandingTranslationsDir.exists() )
{
QString filenameBase( m_prefix );
filenameBase.remove( 0, m_prefix.lastIndexOf( QDir::separator() ) + 1 );
if ( translator->load( m_locale, filenameBase, "_", brandingTranslationsDir.absolutePath() ) )
{
cDebug() << Logger::SubEntry << "Branding using locale:" << m_localeName;
return true;
}
else
{
cDebug() << Logger::SubEntry << "Branding using default, system locale not found:" << m_localeName;
// TODO: this loads something completely different
return translator->load( m_prefix + "en" );
}
}
return false;
}
QString m_prefix;
};
struct CalamaresLoader : public TranslationLoader
{
using TranslationLoader::TranslationLoader;
bool tryLoad( QTranslator* translator ) override
{
if ( translator->load( QString( ":/lang/calamares_" ) + m_localeName ) )
{
cDebug() << Logger::SubEntry << "Calamares using locale:" << m_localeName;
return true;
}
else
{
cDebug() << Logger::SubEntry << "Calamares using default, system locale not found:" << m_localeName;
return translator->load( QString( ":/lang/calamares_en" ) );
}
}
};
struct TZLoader : public TranslationLoader
{
using TranslationLoader::TranslationLoader;
bool tryLoad( QTranslator* translator ) override
{
if ( translator->load( QString( ":/lang/tz_" ) + m_localeName ) )
{
cDebug() << Logger::SubEntry << "Calamares Timezones using locale:" << m_localeName;
return true;
}
else
{
cDebug() << Logger::SubEntry
<< "Calamares Timezones using default, system locale not found:" << m_localeName;
return translator->load( QString( ":/lang/tz_en" ) );
}
}
};
static void
loadSingletonTranslator( TranslationLoader&& loader, QTranslator*& translator_p )
{
QTranslator* translator = new QTranslator();
loader.tryLoad( translator );
if ( translator_p )
{
QCoreApplication::removeTranslator( translator_p );
delete translator_p;
}
QCoreApplication::installTranslator( translator );
translator_p = translator;
}
namespace CalamaresUtils namespace CalamaresUtils
{ {
static QTranslator* s_brandingTranslator = nullptr; static QTranslator* s_brandingTranslator = nullptr;
static QTranslator* s_translator = nullptr; static QTranslator* s_translator = nullptr;
static QTranslator* s_tztranslator = nullptr;
static QString s_translatorLocaleName; static QString s_translatorLocaleName;
void void
installTranslator( const QLocale& locale, const QString& brandingTranslationsPrefix, QObject* parent ) installTranslator( const QLocale& locale, const QString& brandingTranslationsPrefix, QObject* parent )
{ {
QString localeName = locale.name(); loadSingletonTranslator( BrandingLoader( locale, brandingTranslationsPrefix ), s_brandingTranslator );
localeName.replace( "-", "_" ); loadSingletonTranslator( TZLoader( locale ), s_tztranslator );
if ( localeName == "C" ) CalamaresLoader l( locale ); // because we want the extracted localeName
{ loadSingletonTranslator( std::move( l ), s_translator );
localeName = "en"; s_translatorLocaleName = l.m_localeName;
}
// Special case of sr@latin
//
// See top-level CMakeLists.txt about special cases for translation loading.
if ( locale.language() == QLocale::Language::Serbian && locale.script() == QLocale::Script::LatinScript )
{
localeName = QStringLiteral( "sr@latin" );
}
cDebug() << "Looking for translations for" << localeName;
QTranslator* translator = nullptr;
// Branding translations
if ( !brandingTranslationsPrefix.isEmpty() )
{
QString brandingTranslationsDirPath( brandingTranslationsPrefix );
brandingTranslationsDirPath.truncate( brandingTranslationsPrefix.lastIndexOf( QDir::separator() ) );
QDir brandingTranslationsDir( brandingTranslationsDirPath );
if ( brandingTranslationsDir.exists() )
{
QString filenameBase( brandingTranslationsPrefix );
filenameBase.remove( 0, brandingTranslationsPrefix.lastIndexOf( QDir::separator() ) + 1 );
translator = new QTranslator( parent );
if ( translator->load( locale, filenameBase, "_", brandingTranslationsDir.absolutePath() ) )
{
cDebug() << Logger::SubEntry << "Branding using locale:" << localeName;
}
else
{
cDebug() << Logger::SubEntry << "Branding using default, system locale not found:" << localeName;
translator->load( brandingTranslationsPrefix + "en" );
}
if ( s_brandingTranslator )
{
QCoreApplication::removeTranslator( s_brandingTranslator );
delete s_brandingTranslator;
}
QCoreApplication::installTranslator( translator );
s_brandingTranslator = translator;
}
}
// Calamares translations
translator = new QTranslator( parent );
if ( translator->load( QString( ":/lang/calamares_" ) + localeName ) )
{
cDebug() << Logger::SubEntry << "Calamares using locale:" << localeName;
}
else
{
cDebug() << Logger::SubEntry << "Calamares using default, system locale not found:" << localeName;
translator->load( QString( ":/lang/calamares_en" ) );
}
if ( s_translator )
{
QCoreApplication::removeTranslator( s_translator );
delete s_translator;
}
QCoreApplication::installTranslator( translator );
s_translator = translator;
s_translatorLocaleName = localeName;
} }

View File

@ -44,6 +44,12 @@
#include <algorithm> #include <algorithm>
static const char mustAccept[] = "#acceptFrame { border: 1px solid red;"
"background-color: #fff6f6;"
"border-radius: 4px;"
"padding: 2px; }";
static const char okAccept[] = "#acceptFrame { padding: 3px }";
const NamedEnumTable< LicenseEntry::Type >& const NamedEnumTable< LicenseEntry::Type >&
LicenseEntry::typeNames() LicenseEntry::typeNames()
{ {
@ -104,13 +110,8 @@ LicensePage::LicensePage( QWidget* parent )
ui->mainText->setWordWrap( true ); ui->mainText->setWordWrap( true );
ui->mainText->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ); ui->mainText->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
ui->additionalText->setWordWrap( true );
ui->acceptFrame->setFrameStyle( QFrame::NoFrame | QFrame::Plain ); ui->acceptFrame->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
ui->acceptFrame->setStyleSheet( "#acceptFrame { border: 1px solid red;" ui->acceptFrame->setStyleSheet( mustAccept );
"background-color: #fff6f6;"
"border-radius: 4px;"
"padding: 2px; }" );
ui->acceptFrame->layout()->setMargin( CalamaresUtils::defaultFontHeight() / 2 ); ui->acceptFrame->layout()->setMargin( CalamaresUtils::defaultFontHeight() / 2 );
updateGlobalStorage( false ); // Have not agreed yet updateGlobalStorage( false ); // Have not agreed yet
@ -136,6 +137,7 @@ LicensePage::setEntries( const QList< LicenseEntry >& entriesList )
m_entries.append( w ); m_entries.append( w );
m_allLicensesOptional &= !entry.isRequired(); m_allLicensesOptional &= !entry.isRequired();
} }
ui->licenseEntriesLayout->addSpacerItem( new QSpacerItem( 10, 10, QSizePolicy::Minimum, QSizePolicy::Expanding ) );
ui->acceptCheckBox->setChecked( false ); ui->acceptCheckBox->setChecked( false );
checkAcceptance( false ); checkAcceptance( false );
@ -154,7 +156,8 @@ LicensePage::retranslate()
ui->mainText->setText( tr( "This setup procedure will install proprietary " ui->mainText->setText( tr( "This setup procedure will install proprietary "
"software that is subject to licensing terms." ) "software that is subject to licensing terms." )
+ br + review ); + br + review );
ui->additionalText->setText( tr( "If you do not agree with the terms, the setup procedure cannot continue." ) ); QString mustAcceptText( tr( "If you do not agree with the terms, the setup procedure cannot continue." ) );
ui->acceptCheckBox->setToolTip( mustAcceptText );
} }
else else
{ {
@ -163,8 +166,9 @@ LicensePage::retranslate()
"in order to provide additional features and enhance the user " "in order to provide additional features and enhance the user "
"experience." ) "experience." )
+ br + review ); + br + review );
ui->additionalText->setText( tr( "If you do not agree with the terms, proprietary software will not " QString okAcceptText( tr( "If you do not agree with the terms, proprietary software will not "
"be installed, and open source alternatives will be used instead." ) ); "be installed, and open source alternatives will be used instead." ) );
ui->acceptCheckBox->setToolTip( okAcceptText );
} }
ui->retranslateUi( this ); ui->retranslateUi( this );
@ -195,14 +199,11 @@ LicensePage::checkAcceptance( bool checked )
m_isNextEnabled = checked || m_allLicensesOptional; m_isNextEnabled = checked || m_allLicensesOptional;
if ( !m_isNextEnabled ) if ( !m_isNextEnabled )
{ {
ui->acceptFrame->setStyleSheet( "#acceptFrame { border: 1px solid red;" ui->acceptFrame->setStyleSheet( mustAccept );
"background-color: #fff8f8;"
"border-radius: 4px;"
"padding: 2px; }" );
} }
else else
{ {
ui->acceptFrame->setStyleSheet( "#acceptFrame { padding: 3px }" ); ui->acceptFrame->setStyleSheet( okAccept );
} }
emit nextStatusChanged( m_isNextEnabled ); emit nextStatusChanged( m_isNextEnabled );
} }

View File

@ -15,7 +15,7 @@
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0,0,0,0"> <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0,0,0">
<item> <item>
<widget class="QLabel" name="titleLabel"> <widget class="QLabel" name="titleLabel">
<property name="text"> <property name="text">
@ -87,7 +87,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>765</width> <width>765</width>
<height>81</height> <height>89</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="licenseEntriesLayout"/> <layout class="QVBoxLayout" name="licenseEntriesLayout"/>
@ -107,22 +107,6 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<widget class="QLabel" name="additionalText">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string notr="true"/>
</property>
<property name="text">
<string notr="true">&lt;additionalText&gt;</string>
</property>
</widget>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_3"> <layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing"> <property name="spacing">

View File

@ -27,13 +27,9 @@
#include <QFile> #include <QFile>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
#include <QToolButton> #include <QPushButton>
#include <QVBoxLayout> #include <QVBoxLayout>
static constexpr const auto ArrowOpenExternalLink = Qt::RightArrow;
static constexpr const auto ArrowLocalLicenseIsCollapsed = Qt::UpArrow;
static constexpr const auto ArrowLocalLicenseIsExpanded = Qt::DownArrow;
static QString static QString
loadLocalFile( const QUrl& u ) loadLocalFile( const QUrl& u )
{ {
@ -56,9 +52,9 @@ LicenseWidget::LicenseWidget( LicenseEntry entry, QWidget* parent )
: QWidget( parent ) : QWidget( parent )
, m_entry( std::move( entry ) ) , m_entry( std::move( entry ) )
, m_label( new QLabel( this ) ) , m_label( new QLabel( this ) )
, m_viewLicenseLabel( new QLabel( this ) ) , m_viewLicenseButton( new QPushButton( this ) )
, m_expandLicenseButton( nullptr ) , m_licenceTextLabel( new QLabel( this ) )
, m_fullText( nullptr ) , m_isExpanded( m_entry.expandByDefault() )
{ {
QPalette pal( palette() ); QPalette pal( palette() );
pal.setColor( QPalette::Background, palette().window().color().lighter( 108 ) ); pal.setColor( QPalette::Background, palette().window().color().lighter( 108 ) );
@ -70,53 +66,40 @@ LicenseWidget::LicenseWidget( LicenseEntry entry, QWidget* parent )
setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ); setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
setContentsMargins( 4, 4, 4, 4 ); setContentsMargins( 4, 4, 4, 4 );
QVBoxLayout* vLayout = new QVBoxLayout;
QWidget* topPart = new QWidget( this );
topPart->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
vLayout->addWidget( topPart );
QHBoxLayout* wiLayout = new QHBoxLayout; QHBoxLayout* wiLayout = new QHBoxLayout;
topPart->setLayout( wiLayout );
m_label->setWordWrap( true ); m_label->setWordWrap( true );
m_label->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum ); m_label->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
wiLayout->addWidget( m_label ); wiLayout->addWidget( m_label );
m_viewLicenseLabel->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); wiLayout->addSpacing( 10 );
m_viewLicenseLabel->setAlignment( Qt::AlignVCenter | Qt::AlignRight ); m_viewLicenseButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
wiLayout->addWidget( m_viewLicenseLabel ); wiLayout->addWidget( m_viewLicenseButton );
m_licenceTextLabel->setStyleSheet( "border-top: 1px solid black; margin-top: 0px; padding-top: 1em;" );
m_licenceTextLabel->setObjectName( "licenseItemFullText" );
m_expandLicenseButton = new QToolButton( this );
wiLayout->addWidget( m_expandLicenseButton );
if ( m_entry.isLocal() ) if ( m_entry.isLocal() )
{ {
QVBoxLayout* vLayout = new QVBoxLayout; m_fullTextContents = loadLocalFile( m_entry.m_url );
showLocalLicenseText();
m_expandLicenseButton->setArrowType( ArrowLocalLicenseIsCollapsed ); connect( m_viewLicenseButton, &QAbstractButton::clicked, this, &LicenseWidget::expandClicked );
connect( m_expandLicenseButton, &QAbstractButton::clicked, this, &LicenseWidget::expandClicked );
vLayout->addLayout( wiLayout );
m_fullText = new QLabel( this );
m_fullText->setText( loadLocalFile( m_entry.m_url ) );
m_fullText->hide();
m_fullText->setStyleSheet( "border-top: 1px solid black; margin-top: 1em; padding-top: 1em;" );
m_fullText->setObjectName( "licenseItemFullText" );
vLayout->addWidget( m_fullText );
setLayout( vLayout );
if ( m_entry.expandByDefault() )
{
// Since we started in a collapsed state, toggle it to expand.
// This can only be done once the full text has been added.
expandClicked();
}
} }
else else
{ {
m_expandLicenseButton->setArrowType( ArrowOpenExternalLink ); m_licenceTextLabel->setText( tr( "URL: %1" ).arg( m_entry.m_url.toDisplayString() ) );
connect( m_expandLicenseButton, &QAbstractButton::clicked, this, &LicenseWidget::viewClicked ); connect( m_viewLicenseButton, &QAbstractButton::clicked, this, &LicenseWidget::viewClicked );
// Normally setOpenExternalLinks( true ) would do, but we need the
// open code anyway for the toolbutton, let's share it.
connect( m_viewLicenseLabel, &QLabel::linkActivated, this, &LicenseWidget::viewClicked );
setLayout( wiLayout ); // Only the horizontal layout needed
} }
m_licenceTextLabel->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
vLayout->addWidget( m_licenceTextLabel );
setLayout( vLayout );
retranslateUi(); retranslateUi();
} }
@ -172,21 +155,31 @@ LicenseWidget::retranslateUi()
} }
void void
LicenseWidget::expandClicked() LicenseWidget::showLocalLicenseText()
{ {
if ( m_expandLicenseButton->arrowType() == ArrowLocalLicenseIsExpanded ) if ( m_isExpanded )
{ {
m_expandLicenseButton->setArrowType( ArrowLocalLicenseIsCollapsed ); m_licenceTextLabel->setText( m_fullTextContents );
} }
else else
{ {
m_expandLicenseButton->setArrowType( ArrowLocalLicenseIsExpanded ); QString fileName = m_entry.m_url.toDisplayString();
if ( fileName.startsWith( "file:" ) )
{
fileName = fileName.remove( 0, 5 );
}
m_licenceTextLabel->setText( tr( "File: %1" ).arg( fileName ) );
} }
}
void
LicenseWidget::expandClicked()
{
m_isExpanded = !m_isExpanded;
// Show/hide based on the new arrow direction. // Show/hide based on the new arrow direction.
if ( m_fullText ) if ( !m_fullTextContents.isEmpty() )
{ {
m_fullText->setHidden( m_expandLicenseButton->arrowType() == ArrowLocalLicenseIsCollapsed ); showLocalLicenseText();
} }
updateExpandToolTip(); updateExpandToolTip();
@ -198,17 +191,11 @@ LicenseWidget::updateExpandToolTip()
{ {
if ( m_entry.isLocal() ) if ( m_entry.isLocal() )
{ {
const bool isNowCollapsed = m_expandLicenseButton->arrowType() == ArrowLocalLicenseIsCollapsed; m_viewLicenseButton->setText( m_isExpanded ? tr( "Hide license text" ) : tr( "Show the license text" ) );
m_expandLicenseButton->setToolTip( isNowCollapsed ? tr( "Shows the complete license text" )
: tr( "Hide license text" ) );
m_viewLicenseLabel->setText( isNowCollapsed ? tr( "Show license agreement" ) : tr( "Hide license agreement" ) );
} }
else else
{ {
m_expandLicenseButton->setToolTip( tr( "Opens the license agreement in a browser window." ) ); m_viewLicenseButton->setText( tr( "Open license agreement in browser." ) );
m_viewLicenseLabel->setText(
tr( "<a href=\"%1\">View license agreement</a>" ).arg( m_entry.m_url.toString() ) );
} }
} }

View File

@ -27,7 +27,7 @@
#include <QLabel> #include <QLabel>
#include <QWidget> #include <QWidget>
class QToolButton; class QPushButton;
class LicenseWidget : public QWidget class LicenseWidget : public QWidget
{ {
@ -38,14 +38,16 @@ public:
void retranslateUi(); void retranslateUi();
private: private:
void showLocalLicenseText(); // Display (or hide) the local license text
void expandClicked(); // "slot" to toggle show/hide of local license text void expandClicked(); // "slot" to toggle show/hide of local license text
void viewClicked(); // "slot" to open link void viewClicked(); // "slot" to open link
void updateExpandToolTip(); void updateExpandToolTip();
LicenseEntry m_entry; LicenseEntry m_entry;
QLabel* m_label; QLabel* m_label;
QLabel* m_viewLicenseLabel; QPushButton* m_viewLicenseButton;
QToolButton* m_expandLicenseButton; QLabel* m_licenceTextLabel;
QLabel* m_fullText; QString m_fullTextContents;
bool m_isExpanded;
}; };
#endif #endif

View File

@ -28,6 +28,7 @@
#include "Settings.h" #include "Settings.h"
#include "locale/Label.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/Retranslator.h" #include "utils/Retranslator.h"
@ -41,6 +42,8 @@
LocalePage::LocalePage( QWidget* parent ) LocalePage::LocalePage( QWidget* parent )
: QWidget( parent ) : QWidget( parent )
, m_blockTzWidgetSet( false ) , m_blockTzWidgetSet( false )
, m_regionList( CalamaresUtils::Locale::TZRegion::fromZoneTab() )
, m_regionModel( std::make_unique< CalamaresUtils::Locale::CStringListModel >( m_regionList ) )
{ {
QBoxLayout* mainLayout = new QVBoxLayout; QBoxLayout* mainLayout = new QVBoxLayout;
@ -109,7 +112,10 @@ LocalePage::LocalePage( QWidget* parent )
} }
LocalePage::~LocalePage() {} LocalePage::~LocalePage()
{
qDeleteAll( m_regionList );
}
void void
@ -127,42 +133,16 @@ LocalePage::updateLocaleLabels()
m_formatsLabel->setText( labels.second ); 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 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 ); using namespace CalamaresUtils::Locale;
m_zoneCombo->blockSignals( true );
// Setup locations
QHash< QString, QList< LocaleGlobal::Location > > regions = LocaleGlobal::getLocations();
QStringList keys = regions.keys();
keys.sort();
foreach ( const QString& key, keys )
{
m_regionCombo->addItem( LocaleGlobal::Location::pretty( key ), key );
}
m_regionCombo->blockSignals( false );
m_zoneCombo->blockSignals( false );
m_regionCombo->setModel( m_regionModel.get() );
m_regionCombo->currentIndexChanged( m_regionCombo->currentIndex() ); m_regionCombo->currentIndexChanged( m_regionCombo->currentIndex() );
if ( keys.contains( initialRegion ) && containsLocation( regions.value( initialRegion ), initialZone ) ) auto* region = m_regionList.find< TZRegion >( initialRegion );
if ( region && region->zones().find< TZZone >( initialZone ) )
{ {
m_tzWidget->setCurrentLocation( initialRegion, initialZone ); m_tzWidget->setCurrentLocation( initialRegion, initialZone );
} }
@ -170,7 +150,6 @@ LocalePage::init( const QString& initialRegion, const QString& initialZone, cons
{ {
m_tzWidget->setCurrentLocation( "America", "New_York" ); m_tzWidget->setCurrentLocation( "America", "New_York" );
} }
emit m_tzWidget->locationChanged( m_tzWidget->getCurrentLocation() );
// 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
@ -301,13 +280,13 @@ LocalePage::prettyStatus() const
} }
QList< Calamares::job_ptr > Calamares::JobList
LocalePage::createJobs() LocalePage::createJobs()
{ {
QList< Calamares::job_ptr > list; QList< Calamares::job_ptr > list;
LocaleGlobal::Location location = m_tzWidget->getCurrentLocation(); const CalamaresUtils::Locale::TZZone* location = m_tzWidget->currentLocation();
Calamares::Job* j = new SetTimezoneJob( location.region, location.zone ); Calamares::Job* j = new SetTimezoneJob( location->region(), location->zone() );
list.append( Calamares::job_ptr( j ) ); list.append( Calamares::job_ptr( j ) );
return list; return list;
@ -340,7 +319,7 @@ LocaleConfiguration
LocalePage::guessLocaleConfiguration() const LocalePage::guessLocaleConfiguration() const
{ {
return LocaleConfiguration::fromLanguageAndLocation( return LocaleConfiguration::fromLanguageAndLocation(
QLocale().name(), m_localeGenLines, m_tzWidget->getCurrentLocation().country ); QLocale().name(), m_localeGenLines, m_tzWidget->currentLocation()->country() );
} }
@ -358,12 +337,12 @@ LocalePage::updateGlobalStorage()
{ {
auto* gs = Calamares::JobQueue::instance()->globalStorage(); auto* gs = Calamares::JobQueue::instance()->globalStorage();
LocaleGlobal::Location location = m_tzWidget->getCurrentLocation(); const auto* location = m_tzWidget->currentLocation();
bool locationChanged bool locationChanged = ( location->region() != gs->value( "locationRegion" ) )
= ( location.region != gs->value( "locationRegion" ) ) || ( location.zone != gs->value( "locationZone" ) ); || ( location->zone() != gs->value( "locationZone" ) );
gs->insert( "locationRegion", location.region ); gs->insert( "locationRegion", location->region() );
gs->insert( "locationZone", location.zone ); gs->insert( "locationZone", location->zone() );
updateGlobalLocale(); updateGlobalLocale();
@ -373,7 +352,7 @@ LocalePage::updateGlobalStorage()
if ( locationChanged && Calamares::Settings::instance()->doChroot() ) if ( locationChanged && Calamares::Settings::instance()->doChroot() )
{ {
QProcess::execute( "timedatectl", // depends on systemd QProcess::execute( "timedatectl", // depends on systemd
{ "set-timezone", location.region + '/' + location.zone } ); { "set-timezone", location->region() + '/' + location->zone() } );
} }
#endif #endif
@ -402,31 +381,23 @@ LocalePage::updateGlobalStorage()
updateLocaleLabels(); updateLocaleLabels();
} }
void void
LocalePage::regionChanged( int currentIndex ) LocalePage::regionChanged( int currentIndex )
{ {
using namespace CalamaresUtils::Locale;
Q_UNUSED( currentIndex ) Q_UNUSED( currentIndex )
QHash< QString, QList< LocaleGlobal::Location > > regions = LocaleGlobal::getLocations(); QString selectedRegion = m_regionCombo->currentData().toString();
if ( !regions.contains( m_regionCombo->currentData().toString() ) )
TZRegion* region = m_regionList.find< TZRegion >( selectedRegion );
if ( !region )
{ {
return; return;
} }
m_zoneCombo->blockSignals( true ); m_zoneCombo->blockSignals( true );
m_zoneCombo->setModel( new CStringListModel( region->zones() ) );
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->blockSignals( false );
m_zoneCombo->currentIndexChanged( m_zoneCombo->currentIndex() ); m_zoneCombo->currentIndexChanged( m_zoneCombo->currentIndex() );
} }
@ -442,12 +413,12 @@ LocalePage::zoneChanged( int currentIndex )
} }
void void
LocalePage::locationChanged( LocaleGlobal::Location location ) LocalePage::locationChanged( const CalamaresUtils::Locale::TZZone* location )
{ {
m_blockTzWidgetSet = true; m_blockTzWidgetSet = true;
// Set region index // Set region index
int index = m_regionCombo->findData( location.region ); int index = m_regionCombo->findData( location->region() );
if ( index < 0 ) if ( index < 0 )
{ {
return; return;
@ -456,7 +427,7 @@ LocalePage::locationChanged( LocaleGlobal::Location location )
m_regionCombo->setCurrentIndex( index ); m_regionCombo->setCurrentIndex( index );
// Set zone index // Set zone index
index = m_zoneCombo->findData( location.zone ); index = m_zoneCombo->findData( location->zone() );
if ( index < 0 ) if ( index < 0 )
{ {
return; return;

View File

@ -24,9 +24,12 @@
#include "timezonewidget/localeglobal.h" #include "timezonewidget/localeglobal.h"
#include "Job.h" #include "Job.h"
#include "locale/TimeZone.h"
#include <QWidget> #include <QWidget>
#include <memory>
class QComboBox; class QComboBox;
class QLabel; class QLabel;
class QPushButton; class QPushButton;
@ -67,10 +70,14 @@ private:
void regionChanged( int currentIndex ); void regionChanged( int currentIndex );
void zoneChanged( int currentIndex ); void zoneChanged( int currentIndex );
void locationChanged( LocaleGlobal::Location location ); void locationChanged( const CalamaresUtils::Locale::TZZone* location );
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;

View File

@ -142,7 +142,7 @@ LocaleViewStep::isAtEnd() const
} }
QList< Calamares::job_ptr > Calamares::JobList
LocaleViewStep::jobs() const LocaleViewStep::jobs() const
{ {
return m_jobs; return m_jobs;
@ -163,12 +163,9 @@ LocaleViewStep::onActivate()
void void
LocaleViewStep::onLeave() LocaleViewStep::onLeave()
{ {
m_jobs.clear();
if ( m_actualWidget ) if ( m_actualWidget )
{ {
m_jobs.append( m_actualWidget->createJobs() ); m_jobs = m_actualWidget->createJobs();
m_prettyStatus = m_actualWidget->prettyStatus(); m_prettyStatus = m_actualWidget->prettyStatus();
auto map = m_actualWidget->localesMap(); auto map = m_actualWidget->localesMap();
@ -182,6 +179,7 @@ LocaleViewStep::onLeave()
} }
else else
{ {
m_jobs.clear();
Calamares::JobQueue::instance()->globalStorage()->remove( "localeConf" ); Calamares::JobQueue::instance()->globalStorage()->remove( "localeConf" );
} }
} }

View File

@ -33,7 +33,6 @@
#include <memory> #include <memory>
class LocalePage; class LocalePage;
class WaitingWidget;
class PLUGINDLLEXPORT LocaleViewStep : public Calamares::ViewStep class PLUGINDLLEXPORT LocaleViewStep : public Calamares::ViewStep
{ {
@ -54,7 +53,7 @@ public:
bool isAtBeginning() const override; bool isAtBeginning() const override;
bool isAtEnd() const override; bool isAtEnd() const override;
QList< Calamares::job_ptr > jobs() const override; Calamares::JobList jobs() const override;
void onActivate() override; void onActivate() override;
void onLeave() override; void onLeave() override;
@ -78,7 +77,7 @@ private:
CalamaresUtils::GeoIP::RegionZonePair m_startingTimezone; CalamaresUtils::GeoIP::RegionZonePair m_startingTimezone;
QString m_localeGenPath; QString m_localeGenPath;
QList< Calamares::job_ptr > m_jobs; Calamares::JobList m_jobs;
std::unique_ptr< CalamaresUtils::GeoIP::Handler > m_geoip; std::unique_ptr< CalamaresUtils::GeoIP::Handler > m_geoip;
}; };

View File

@ -1,32 +0,0 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2014, Teo Mrnjavac <teo@kde.org>
*
* Originally from the Manjaro Installation Framework
* by Roland Singer <roland@manjaro.org>
* Copyright (C) 2007 Free Software Foundation, Inc.
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LOCALECONST_H
#define LOCALECONST_H
#define LOCALESDIR "/usr/share/i18n/locales"
#define TZ_DATA_FILE "/usr/share/zoneinfo/zone.tab"
#define USER_IMAGES_PATH "/usr/share/pixmaps/faces"
#endif // LOCALECONST_H

View File

@ -22,14 +22,15 @@
#include "localeglobal.h" #include "localeglobal.h"
#include "locale/TimeZone.h"
#include <QTimeZone> #include <QTimeZone>
//### //###
//### Private variables //### Private variables
//### //###
QHash<QString, QHash<QString, QList<LocaleGlobal::Locale> > > LocaleGlobal::locales; QHash< QString, QHash< QString, QList< LocaleGlobal::Locale > > > LocaleGlobal::locales;
QHash<QString, QList<LocaleGlobal::Location> > LocaleGlobal::locations;
//### //###
@ -37,158 +38,89 @@ QHash<QString, QList<LocaleGlobal::Location> > LocaleGlobal::locations;
//### //###
QString
LocaleGlobal::Location::pretty( const QString& s )
{
return QString( s ).replace( '_', ' ' ).simplified();
}
QString
LocaleGlobal::Location::comment() const
{
QTimeZone qtz = QTimeZone( QString( "%1/%2" )
.arg( region )
.arg( zone ).toLatin1() );
return qtz.comment();
}
void void
LocaleGlobal::init() { LocaleGlobal::init()
{
// TODO: Error handling // TODO: Error handling
initLocales(); initLocales();
initLocations();
} }
QHash< QString, QHash< QString, QList< LocaleGlobal::Locale > > > QHash< QString, QHash< QString, QList< LocaleGlobal::Locale > > >
LocaleGlobal::getLocales() { LocaleGlobal::getLocales()
{
return locales; return locales;
} }
QHash< QString, QList< LocaleGlobal::Location > >
LocaleGlobal::getLocations() {
return locations;
}
//### //###
//### Private methods //### Private methods
//### //###
void void
LocaleGlobal::initLocales() { LocaleGlobal::initLocales()
{
static const char LOCALESDIR[] = "/usr/share/i18n/locales";
locales.clear(); locales.clear();
QStringList files = QDir(LOCALESDIR).entryList(QDir::Files, QDir::Name); QStringList files = QDir( LOCALESDIR ).entryList( QDir::Files, QDir::Name );
for (int i = 0; i < files.size(); ++i) { for ( int i = 0; i < files.size(); ++i )
QString filename = files.at(i); {
QFile file(QString(LOCALESDIR) + "/" + filename); QString filename = files.at( i );
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) QFile file( QString( LOCALESDIR ) + "/" + filename );
if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
{
continue; continue;
}
QTextStream in(&file); QTextStream in( &file );
QString commentChar = "%"; QString commentChar = "%";
Locale locale; Locale locale;
QString lang, territory; QString lang, territory;
locale.locale = filename; locale.locale = filename;
while (!in.atEnd()) { while ( !in.atEnd() )
{
QString line = in.readLine().trimmed(); QString line = in.readLine().trimmed();
QStringList split = line.split(commentChar, QString::KeepEmptyParts).first().split(QRegExp(" (?=[^\"]*(\"[^\"]*\"[^\"]*)*$)"), QString::SkipEmptyParts); QStringList split = line.split( commentChar, QString::KeepEmptyParts )
.first()
.split( QRegExp( " (?=[^\"]*(\"[^\"]*\"[^\"]*)*$)" ), QString::SkipEmptyParts );
if (split.size() < 2) if ( split.size() < 2 )
{
continue; continue;
}
QString sub1 = QString(split.at(0)).remove("\""); QString sub1 = QString( split.at( 0 ) ).remove( "\"" );
QString sub2 = QString(split.at(1)).remove("\""); QString sub2 = QString( split.at( 1 ) ).remove( "\"" );
if (sub1 == "comment_char") if ( sub1 == "comment_char" )
{
commentChar = sub2; commentChar = sub2;
else if (sub1 == "title") }
else if ( sub1 == "title" )
{
locale.description = sub2; locale.description = sub2;
else if (sub1 == "territory") }
territory= sub2; else if ( sub1 == "territory" )
else if (sub1 == "language") {
territory = sub2;
}
else if ( sub1 == "language" )
{
lang = sub2; lang = sub2;
}
} }
if (lang.isEmpty() || territory.isEmpty()) if ( lang.isEmpty() || territory.isEmpty() )
{
continue; continue;
}
locales[lang][territory].append(locale); locales[ lang ][ territory ].append( locale );
} }
} }
void
LocaleGlobal::initLocations() {
locations.clear();
QFile file(TZ_DATA_FILE);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTextStream in(&file);
while (!in.atEnd()) {
QString line = in.readLine().trimmed().split('#', QString::KeepEmptyParts).first().trimmed();
if (line.isEmpty())
continue;
QStringList list = line.split(QRegExp("[\t ]"), QString::SkipEmptyParts);
if (list.size() < 3)
continue;
Location location;
QStringList timezoneParts = list.at(2).split('/', QString::SkipEmptyParts);
int cooSplitPos = QString(list.at(1)).remove(0, 1).indexOf(QRegExp("[-+]")) + 1;
if (timezoneParts.size() < 2)
continue;
QString countryCode = list.at(0).trimmed();
if (countryCode.size() != 2)
continue;
location.region = timezoneParts.takeFirst();
location.zone = timezoneParts.join( '/' );
location.latitude = getRightGeoLocation(list.at(1).mid(0, cooSplitPos));
location.longitude = getRightGeoLocation(list.at(1).mid(cooSplitPos));
location.country = countryCode;
locations[location.region].append(location);
}
}
double
LocaleGlobal::getRightGeoLocation(QString str) {
double sign = 1, num = 0.00;
// Determind sign
if (str.startsWith('-')) {
sign = -1;
str.remove(0, 1);
}
else if (str.startsWith('+')) {
str.remove(0, 1);
}
if (str.length() == 4 || str.length() == 6)
num = str.mid(0, 2).toDouble() + str.mid(2, 2).toDouble() / 60;
else if (str.length() == 5 || str.length() == 7)
num = str.mid(0, 3).toDouble() + str.mid(3, 2).toDouble() / 60;
return sign * num;
}

View File

@ -24,17 +24,24 @@
#ifndef LOCALEGLOBAL_H #ifndef LOCALEGLOBAL_H
#define LOCALEGLOBAL_H #define LOCALEGLOBAL_H
#include <QString> #include <QDebug>
#include <QFile>
#include <QTextStream>
#include <QDir> #include <QDir>
#include <QStringList> #include <QFile>
#include <QList>
#include <QHash> #include <QHash>
#include <QList>
#include <QMap> #include <QMap>
#include <QRegExp> #include <QRegExp>
#include <QDebug> #include <QString>
#include "localeconst.h" #include <QStringList>
#include <QTextStream>
namespace CalamaresUtils
{
namespace Locale
{
class TZZone;
}
} // namespace CalamaresUtils
class LocaleGlobal class LocaleGlobal
{ {
@ -44,30 +51,13 @@ public:
QString description, locale; QString description, locale;
}; };
struct Location
{
QString region, zone, country;
double latitude, longitude;
static QString pretty( const QString& s );
QString comment() const;
};
static void init(); static void init();
static QHash<QString, QHash<QString, QList<LocaleGlobal::Locale> > > getLocales(); static QHash< QString, QHash< QString, QList< LocaleGlobal::Locale > > > getLocales();
static QHash<QString, QList<LocaleGlobal::Location> > getLocations();
private: private:
static QHash<QString, QHash<QString, QList<LocaleGlobal::Locale> > > locales; static QHash< QString, QHash< QString, QList< LocaleGlobal::Locale > > > locales;
static QHash<QString, QList<LocaleGlobal::Location> > locations;
static void initLocales(); static void initLocales();
static void initLocations();
static double getRightGeoLocation( QString str );
}; };
inline QDebug& operator <<( QDebug& s, const LocaleGlobal::Location& l ) #endif // LOCALEGLOBAL_H
{
return s << l.region << '/' << l.zone << '(' << l.country << ") @N" << l.latitude << 'E' << l.longitude;
}
#endif // LOCALEGLOBAL_H

View File

@ -1,7 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org> * Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org> * Copyright 2017-2019, Adriaan de Groot <groot@kde.org>
* *
* Originally from the Manjaro Installation Framework * Originally from the Manjaro Installation Framework
* by Roland Singer <roland@manjaro.org> * by Roland Singer <roland@manjaro.org>
@ -23,10 +23,13 @@
#include <cmath> #include <cmath>
#include "locale/TimeZone.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "timezonewidget.h" #include "timezonewidget.h"
// Pixel value indicating that a spot is outside of a zone
#define RGB_TRANSPARENT 0
static constexpr double MAP_Y_OFFSET = 0.125; static constexpr double MAP_Y_OFFSET = 0.125;
static constexpr double MAP_X_OFFSET = -0.0370; static constexpr double MAP_X_OFFSET = -0.0370;
@ -37,8 +40,8 @@ constexpr static double MATH_PI = 3.14159265;
constexpr static QLatin1String ZONE_NAME( "zone" ); constexpr static QLatin1String ZONE_NAME( "zone" );
#endif #endif
TimeZoneWidget::TimeZoneWidget( QWidget* parent ) : TimeZoneWidget::TimeZoneWidget( QWidget* parent )
QWidget( parent ) : QWidget( parent )
{ {
setMouseTracking( false ); setMouseTracking( false );
setCursor( Qt::PointingHandCursor ); setCursor( Qt::PointingHandCursor );
@ -48,54 +51,67 @@ TimeZoneWidget::TimeZoneWidget( QWidget* parent ) :
font.setBold( false ); font.setBold( false );
// Images // Images
background = QImage( ":/images/bg.png" ).scaled( X_SIZE, Y_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); background = QImage( ":/images/bg.png" );
pin = QImage( ":/images/pin.png" ); pin = QImage( ":/images/pin.png" );
#ifdef DEBUG_TIMEZONES
if ( background.size() != QSize( 780, 340 ) )
{
cWarning() << "Timezone background size mitsmatch" << background.size();
}
#endif
// Set size // Set size
setMinimumSize( background.size() ); setMinimumSize( background.size() );
setMaximumSize( background.size() ); setMaximumSize( background.size() );
// Zone images // Zone images
QStringList zones = QString( ZONES ).split( " ", QString::SkipEmptyParts ); for ( const auto* zoneName :
for ( int i = 0; i < zones.size(); ++i ) { "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", "11.5", "12.0", "12.75", "13.0", "-1.0", "-2.0", "-3.0",
"-3.5", "-4.0", "-4.5", "-5.0", "-5.5", "-6.0", "-7.0", "-8.0", "-9.0", "-9.5", "-10.0", "-11.0" } )
{ {
timeZoneImages.append( QImage( ":/images/timezone_" + zones.at( i ) + ".png" ).scaled( X_SIZE, Y_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) ); timeZoneImages.append( QImage( QStringLiteral( ":/images/timezone_" ) + zoneName + ".png" ) );
#ifdef DEBUG_TIMEZONES #ifdef DEBUG_TIMEZONES
timeZoneImages.last().setText( ZONE_NAME, zones.at( i ) ); if ( timeZoneImages.last().size() != background.size() )
{
cWarning() << "Timezone image size mismatch" << zoneName << timeZoneImages.last().size();
}
timeZoneImages.last().setText( ZONE_NAME, zoneName );
#endif #endif
} }
} }
void TimeZoneWidget::setCurrentLocation( QString region, QString zone ) void
TimeZoneWidget::setCurrentLocation( QString regionName, QString zoneName )
{ {
QHash<QString, QList<LocaleGlobal::Location> > hash = LocaleGlobal::getLocations(); using namespace CalamaresUtils::Locale;
const auto& regions = TZRegion::fromZoneTab();
if ( !hash.contains( region ) ) auto* region = regions.find< TZRegion >( regionName );
return; if ( !region )
QList<LocaleGlobal::Location> locations = hash.value( region );
for ( int i = 0; i < locations.size(); ++i )
{ {
if ( locations.at( i ).zone == zone ) return;
{ }
setCurrentLocation( locations.at( i ) );
break; auto* zone = region->zones().find< TZZone >( zoneName );
} if ( zone )
{
setCurrentLocation( zone );
} }
} }
void TimeZoneWidget::setCurrentLocation( LocaleGlobal::Location location ) void
TimeZoneWidget::setCurrentLocation( const CalamaresUtils::Locale::TZZone* location )
{ {
currentLocation = location; m_currentLocation = location;
// Set zone // Set zone
QPoint pos = getLocationPosition( currentLocation.longitude, currentLocation.latitude ); QPoint pos = getLocationPosition( location );
#ifdef DEBUG_TIMEZONES #ifdef DEBUG_TIMEZONES
cDebug() << "Setting location" << location.region << location.zone << location.country; cDebug() << "Setting location" << location->region() << location->zone() << '(' << location->country() << '@' << location->latitude() << 'N' << location->longitude() << 'E' << ')';
cDebug() << Logger::SubEntry << "longitude" << location.longitude << "latitude" << location.latitude;
cDebug() << Logger::SubEntry << "pixel x" << pos.x() << "pixel y" << pos.y(); cDebug() << Logger::SubEntry << "pixel x" << pos.x() << "pixel y" << pos.y();
bool found = false; bool found = false;
@ -104,7 +120,7 @@ void TimeZoneWidget::setCurrentLocation( LocaleGlobal::Location location )
for ( int i = 0; i < timeZoneImages.size(); ++i ) for ( int i = 0; i < timeZoneImages.size(); ++i )
{ {
QImage zone = timeZoneImages[i]; QImage zone = timeZoneImages[ i ];
// If not transparent set as current // If not transparent set as current
if ( zone.pixel( pos ) != RGB_TRANSPARENT ) if ( zone.pixel( pos ) != RGB_TRANSPARENT )
@ -119,7 +135,9 @@ void TimeZoneWidget::setCurrentLocation( LocaleGlobal::Location location )
cDebug() << Logger::SubEntry << "First zone found" << i << zone.text( ZONE_NAME ); cDebug() << Logger::SubEntry << "First zone found" << i << zone.text( ZONE_NAME );
} }
else else
{
cDebug() << Logger::SubEntry << "Also in zone" << i << zone.text( ZONE_NAME ); cDebug() << Logger::SubEntry << "Also in zone" << i << zone.text( ZONE_NAME );
}
#else #else
currentZoneImage = zone; currentZoneImage = zone;
break; break;
@ -129,16 +147,17 @@ void TimeZoneWidget::setCurrentLocation( LocaleGlobal::Location location )
// Repaint widget // Repaint widget
repaint(); repaint();
emit locationChanged( m_currentLocation );
} }
//### //###
//### Private //### Private
//### //###
QPoint TimeZoneWidget::getLocationPosition( double longitude, double latitude ) QPoint
TimeZoneWidget::getLocationPosition( double longitude, double latitude )
{ {
const int width = this->width(); const int width = this->width();
const int height = this->height(); const int height = this->height();
@ -152,39 +171,64 @@ QPoint TimeZoneWidget::getLocationPosition( double longitude, double latitude )
// of the different cities / regions looks ok -- at least Thule ends up in the right // of the different cities / regions looks ok -- at least Thule ends up in the right
// country, and Inuvik isn't in the ocean. // country, and Inuvik isn't in the ocean.
if ( latitude > 70.0 ) if ( latitude > 70.0 )
{
y -= sin( MATH_PI * ( latitude - 70.0 ) / 56.0 ) * MAP_Y_OFFSET * height * 0.8; y -= sin( MATH_PI * ( latitude - 70.0 ) / 56.0 ) * MAP_Y_OFFSET * height * 0.8;
}
if ( latitude > 74.0 ) if ( latitude > 74.0 )
{
y += 4; y += 4;
}
if ( latitude > 69.0 ) if ( latitude > 69.0 )
{
y -= 2; y -= 2;
}
if ( latitude > 59.0 ) if ( latitude > 59.0 )
{
y -= 4 * int( ( latitude - 54.0 ) / 5.0 ); y -= 4 * int( ( latitude - 54.0 ) / 5.0 );
}
if ( latitude > 54.0 ) if ( latitude > 54.0 )
{
y -= 2; y -= 2;
}
if ( latitude > 49.0 ) if ( latitude > 49.0 )
y -= int ( (latitude - 44.0) / 5.0 ); {
y -= int( ( latitude - 44.0 ) / 5.0 );
}
// Far south, some stretching occurs as well, but it is less pronounced. // Far south, some stretching occurs as well, but it is less pronounced.
// Move down by 1 pixel per 5 degrees past 10 south // Move down by 1 pixel per 5 degrees past 10 south
if ( latitude < 0 ) if ( latitude < 0 )
y += int( (-latitude) / 5.0 ); {
y += int( ( -latitude ) / 5.0 );
}
// Antarctica isn't shown on the map, but you could try clicking there // Antarctica isn't shown on the map, but you could try clicking there
if ( latitude < -60 ) if ( latitude < -60 )
{
y = height - 1; y = height - 1;
}
if ( x < 0 ) if ( x < 0 )
x = width+x; {
x = width + x;
}
if ( x >= width ) if ( x >= width )
{
x -= width; x -= width;
}
if ( y < 0 ) if ( y < 0 )
y = height+y; {
y = height + y;
}
if ( y >= height ) if ( y >= height )
{
y -= height; y -= height;
}
return QPoint( int(x), int(y) ); return QPoint( int( x ), int( y ) );
} }
void TimeZoneWidget::paintEvent( QPaintEvent* ) void
TimeZoneWidget::paintEvent( QPaintEvent* )
{ {
const int width = this->width(); const int width = this->width();
const int height = this->height(); const int height = this->height();
@ -201,90 +245,107 @@ void TimeZoneWidget::paintEvent( QPaintEvent* )
painter.drawImage( 0, 0, currentZoneImage ); painter.drawImage( 0, 0, currentZoneImage );
#ifdef DEBUG_TIMEZONES #ifdef DEBUG_TIMEZONES
QPoint point = getLocationPosition( currentLocation.longitude, currentLocation.latitude ); QPoint point = getLocationPosition( m_currentLocation );
// Draw latitude lines // Draw latitude lines
for ( int y_lat = -50; y_lat < 80 ; y_lat+=5 ) for ( int y_lat = -50; y_lat < 80; y_lat += 5 )
{ {
QPen p( y_lat ? Qt::black : Qt::red ); QPen p( y_lat ? Qt::black : Qt::red );
p.setWidth( 0 ); p.setWidth( 0 );
painter.setPen( p ); painter.setPen( p );
QPoint latLine0( getLocationPosition( 0, y_lat ) ); QPoint latLine0( getLocationPosition( 0, y_lat ) );
int llx = latLine0.x() + ((y_lat & 1) ? -10 : 0); int llx = latLine0.x() + ( ( y_lat & 1 ) ? -10 : 0 );
int lly = latLine0.y(); int lly = latLine0.y();
for ( int c = 0 ; c < width ; ++c ) for ( int c = 0; c < width; ++c )
{
painter.drawPoint( c, lly ); painter.drawPoint( c, lly );
}
} }
// Just a dot in the selected location, no label // Just a dot in the selected location, no label
painter.setPen( Qt::red ); painter.setPen( Qt::red );
painter.drawPoint( point ); painter.drawPoint( point );
#else #else
// Draw pin at current location // Draw pin at current location
QPoint point = getLocationPosition( currentLocation.longitude, currentLocation.latitude ); QPoint point = getLocationPosition( m_currentLocation );
painter.drawImage( point.x() - pin.width()/2, point.y() - pin.height()/2, pin ); painter.drawImage( point.x() - pin.width() / 2, point.y() - pin.height() / 2, pin );
// Draw text and box // Draw text and box
const int textWidth = fontMetrics.horizontalAdvance( LocaleGlobal::Location::pretty( currentLocation.zone ) ); const int textWidth = fontMetrics.horizontalAdvance( m_currentLocation ? m_currentLocation->tr() : QString() );
const int textHeight = fontMetrics.height(); const int textHeight = fontMetrics.height();
QRect rect = QRect( point.x() - textWidth/2 - 5, point.y() - textHeight - 8, textWidth + 10, textHeight - 2 ); QRect rect = QRect( point.x() - textWidth / 2 - 5, point.y() - textHeight - 8, textWidth + 10, textHeight - 2 );
if ( rect.x() <= 5 ) if ( rect.x() <= 5 )
{
rect.moveLeft( 5 ); rect.moveLeft( 5 );
if ( rect.right() >= width-5 ) }
if ( rect.right() >= width - 5 )
{
rect.moveRight( width - 5 ); rect.moveRight( width - 5 );
}
if ( rect.y() <= 5 ) if ( rect.y() <= 5 )
{
rect.moveTop( 5 ); rect.moveTop( 5 );
if ( rect.y() >= height-5 ) }
rect.moveBottom( height-5 ); if ( rect.y() >= height - 5 )
{
rect.moveBottom( height - 5 );
}
painter.setPen( QPen() ); // no pen painter.setPen( QPen() ); // no pen
painter.setBrush( QColor( 40, 40, 40 ) ); painter.setBrush( QColor( 40, 40, 40 ) );
painter.drawRoundedRect( rect, 3, 3 ); painter.drawRoundedRect( rect, 3, 3 );
painter.setPen( Qt::white ); painter.setPen( Qt::white );
painter.drawText( rect.x() + 5, rect.bottom() - 4, LocaleGlobal::Location::pretty( currentLocation.zone ) ); painter.drawText( rect.x() + 5, rect.bottom() - 4, m_currentLocation ? m_currentLocation->tr() : QString() );
#endif #endif
painter.end(); painter.end();
} }
void
void TimeZoneWidget::mousePressEvent( QMouseEvent* event ) TimeZoneWidget::mousePressEvent( QMouseEvent* event )
{ {
if ( event->button() != Qt::LeftButton ) if ( event->button() != Qt::LeftButton )
{
return; return;
}
// Set nearest location // Set nearest location
int nX = 999999, mX = event->pos().x(); int nX = 999999, mX = event->pos().x();
int nY = 999999, mY = event->pos().y(); int nY = 999999, mY = event->pos().y();
QHash<QString, QList<LocaleGlobal::Location> > hash = LocaleGlobal::getLocations();
QHash<QString, QList<LocaleGlobal::Location> >::iterator iter = hash.begin();
while ( iter != hash.end() ) using namespace CalamaresUtils::Locale;
const TZZone* closest = nullptr;
for ( const auto* region_p : TZRegion::fromZoneTab() )
{ {
QList<LocaleGlobal::Location> locations = iter.value(); const auto* region = dynamic_cast< const TZRegion* >( region_p );
if ( region )
for ( int i = 0; i < locations.size(); ++i )
{ {
LocaleGlobal::Location loc = locations[i]; for ( const auto* zone_p : region->zones() )
QPoint locPos = getLocationPosition( loc.longitude, loc.latitude );
if ( ( abs( mX - locPos.x() ) + abs( mY - locPos.y() ) < abs( mX - nX ) + abs( mY - nY ) ) )
{ {
currentLocation = loc; const auto* zone = dynamic_cast< const TZZone* >( zone_p );
nX = locPos.x(); if ( zone )
nY = locPos.y(); {
QPoint locPos = getLocationPosition( zone->longitude(), zone->latitude() );
if ( ( abs( mX - locPos.x() ) + abs( mY - locPos.y() ) < abs( mX - nX ) + abs( mY - nY ) ) )
{
closest = zone;
nX = locPos.x();
nY = locPos.y();
}
}
} }
} }
++iter;
} }
// Set zone image and repaint widget if ( closest )
setCurrentLocation( currentLocation ); {
// Set zone image and repaint widget
// Emit signal setCurrentLocation( closest );
emit locationChanged( currentLocation ); // Emit signal
emit locationChanged( m_currentLocation );
}
} }

View File

@ -24,55 +24,48 @@
#ifndef TIMEZONEWIDGET_H #ifndef TIMEZONEWIDGET_H
#define TIMEZONEWIDGET_H #define TIMEZONEWIDGET_H
#include <QWidget>
#include <QPainter>
#include <QImage>
#include <QFile>
#include <QTextStream>
#include <QList>
#include <QStringList>
#include <QMouseEvent>
#include <QFontMetrics>
#include <QFont>
#include "localeglobal.h" #include "localeglobal.h"
#include "locale/TimeZone.h"
#define RGB_TRANSPARENT 0 #include <QFile>
#define ZONES "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 11.5 12.0 12.75 13.0 -1.0 -2.0 -3.0 -3.5 -4.0 -4.5 -5.0 -5.5 -6.0 -7.0 -8.0 -9.0 -9.5 -10.0 -11.0" #include <QFont>
#define X_SIZE 780 #include <QFontMetrics>
#define Y_SIZE 340 #include <QImage>
#include <QList>
#include <QMouseEvent>
#include <QPainter>
#include <QStringList>
#include <QTextStream>
#include <QWidget>
class TimeZoneWidget : public QWidget class TimeZoneWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
using TZZone = CalamaresUtils::Locale::TZZone;
explicit TimeZoneWidget( QWidget* parent = nullptr ); explicit TimeZoneWidget( QWidget* parent = nullptr );
LocaleGlobal::Location getCurrentLocation()
{
return currentLocation;
}
void setCurrentLocation( QString region, QString zone ); void setCurrentLocation( QString region, QString zone );
void setCurrentLocation( LocaleGlobal::Location location ); void setCurrentLocation( const TZZone* location );
const TZZone* currentLocation() { return m_currentLocation; }
signals: signals:
void locationChanged( LocaleGlobal::Location location ); void locationChanged( const TZZone* location );
private: private:
QFont font; QFont font;
QImage background, pin, currentZoneImage; QImage background, pin, currentZoneImage;
QList<QImage> timeZoneImages; QList< QImage > timeZoneImages;
LocaleGlobal::Location currentLocation; const TZZone* m_currentLocation = nullptr; // Not owned by me
QPoint getLocationPosition( const LocaleGlobal::Location& l ) QPoint getLocationPosition( const TZZone* l ) { return getLocationPosition( l->longitude(), l->latitude() ); }
{
return getLocationPosition( l.longitude, l.latitude );
}
QPoint getLocationPosition( double longitude, double latitude ); QPoint getLocationPosition( double longitude, double latitude );
void paintEvent( QPaintEvent* event ); void paintEvent( QPaintEvent* event );
void mousePressEvent( QMouseEvent* event ); void mousePressEvent( QMouseEvent* event );
}; };
#endif // TIMEZONEWIDGET_H #endif // TIMEZONEWIDGET_H