diff --git a/src/modules/locale/Config.cpp b/src/modules/locale/Config.cpp index 7a49525f2..96d279477 100644 --- a/src/modules/locale/Config.cpp +++ b/src/modules/locale/Config.cpp @@ -148,17 +148,11 @@ loadLocales( const QString& localeGenPath ) return localeGenLines; } -static inline const CalamaresUtils::Locale::CStringPairList& -timezoneData() -{ - return CalamaresUtils::Locale::TZRegion::fromZoneTab(); -} - - Config::Config( QObject* parent ) : QObject( parent ) - , m_regionModel( std::make_unique< CalamaresUtils::Locale::CStringListModel >( ::timezoneData() ) ) - , m_zonesModel( std::make_unique< CalamaresUtils::Locale::CStringListModel >() ) + , m_regionModel( std::make_unique< CalamaresUtils::Locale::RegionsModel >() ) + , m_zonesModel( std::make_unique< CalamaresUtils::Locale::ZonesModel >() ) + , m_regionalZonesModel( std::make_unique< CalamaresUtils::Locale::RegionalZonesModel >( m_zonesModel.get() ) ) { // Slightly unusual: connect to our *own* signals. Wherever the language // or the location is changed, these signals are emitted, so hook up to @@ -208,12 +202,6 @@ Config::Config( QObject* parent ) Config::~Config() {} -const CalamaresUtils::Locale::CStringPairList& -Config::timezoneData() const -{ - return ::timezoneData(); -} - void Config::setCurrentLocation() { @@ -223,7 +211,8 @@ Config::setCurrentLocation() } } -void Config::setCurrentLocation(const QString& regionzone) +void +Config::setCurrentLocation( const QString& regionzone ) { auto r = CalamaresUtils::GeoIP::splitTZString( regionzone ); if ( r.isValid() ) @@ -236,8 +225,7 @@ void Config::setCurrentLocation( const QString& regionName, const QString& zoneName ) { using namespace CalamaresUtils::Locale; - auto* region = timezoneData().find< TZRegion >( regionName ); - auto* zone = region ? region->zones().find< TZZone >( zoneName ) : nullptr; + auto* zone = m_zonesModel->find( regionName, zoneName ); if ( zone ) { setCurrentLocation( zone ); @@ -250,7 +238,7 @@ Config::setCurrentLocation( const QString& regionName, const QString& zoneName ) } void -Config::setCurrentLocation( const CalamaresUtils::Locale::TZZone* location ) +Config::setCurrentLocation( const CalamaresUtils::Locale::TimeZoneData* location ) { if ( location != m_currentLocation ) { @@ -459,7 +447,7 @@ Calamares::JobList Config::createJobs() { Calamares::JobList list; - const CalamaresUtils::Locale::TZZone* location = currentLocation(); + const auto* location = currentLocation(); if ( location ) { diff --git a/src/modules/locale/Config.h b/src/modules/locale/Config.h index e9a8e6373..fccd3822e 100644 --- a/src/modules/locale/Config.h +++ b/src/modules/locale/Config.h @@ -37,18 +37,20 @@ class Config : public QObject { Q_OBJECT Q_PROPERTY( const QStringList& supportedLocales READ supportedLocales CONSTANT FINAL ) - Q_PROPERTY( CalamaresUtils::Locale::CStringListModel* zonesModel READ zonesModel CONSTANT FINAL ) - Q_PROPERTY( CalamaresUtils::Locale::CStringListModel* regionModel READ regionModel CONSTANT FINAL ) + Q_PROPERTY( CalamaresUtils::Locale::RegionsModel* regionModel READ regionModel CONSTANT FINAL ) + Q_PROPERTY( CalamaresUtils::Locale::ZonesModel* zonesModel READ zonesModel CONSTANT FINAL ) + Q_PROPERTY( QAbstractItemModel* regionalZonesModel READ regionalZonesModel CONSTANT FINAL ) - Q_PROPERTY( const CalamaresUtils::Locale::TZZone* currentLocation READ currentLocation WRITE setCurrentLocation - NOTIFY currentLocationChanged ) + Q_PROPERTY( + const CalamaresUtils::Locale::TimeZoneData* currentLocation READ currentLocation NOTIFY currentLocationChanged ) // Status are complete, human-readable, messages Q_PROPERTY( QString currentLocationStatus READ currentLocationStatus NOTIFY currentLanguageStatusChanged ) Q_PROPERTY( QString currentLanguageStatus READ currentLanguageStatus NOTIFY currentLanguageStatusChanged ) Q_PROPERTY( QString currentLCStatus READ currentLCStatus NOTIFY currentLCStatusChanged ) // Code are internal identifiers, like "en_US.UTF-8" - Q_PROPERTY( QString currentLanguageCode READ currentLanguageCode WRITE setLanguageExplicitly NOTIFY currentLanguageCodeChanged ) + Q_PROPERTY( QString currentLanguageCode READ currentLanguageCode WRITE setLanguageExplicitly NOTIFY + currentLanguageCodeChanged ) Q_PROPERTY( QString currentLCCode READ currentLCCode WRITE setLCLocaleExplicitly NOTIFY currentLCCodeChanged ) // This is a long human-readable string with all three statuses @@ -61,15 +63,6 @@ public: void setConfigurationMap( const QVariantMap& ); Calamares::JobList createJobs(); - // Underlying data for the models - const CalamaresUtils::Locale::CStringPairList& timezoneData() const; - - /** @brief The currently selected location (timezone) - * - * The location is a pointer into the date that timezoneData() returns. - */ - const CalamaresUtils::Locale::TZZone* currentLocation() const { return m_currentLocation; } - /// locale configuration (LC_* and LANG) based solely on the current location. LocaleConfiguration automaticLocaleConfiguration() const; /// locale configuration that takes explicit settings into account @@ -85,9 +78,16 @@ public: /// The human-readable summary of what the module will do QString prettyStatus() const; + // A long list of locale codes (e.g. en_US.UTF-8) const QStringList& supportedLocales() const { return m_localeGenLines; } - CalamaresUtils::Locale::CStringListModel* regionModel() const { return m_regionModel.get(); } - CalamaresUtils::Locale::CStringListModel* zonesModel() const { return m_zonesModel.get(); } + // All the regions (Africa, America, ...) + CalamaresUtils::Locale::RegionsModel* regionModel() const { return m_regionModel.get(); } + // All of the timezones in the world, according to zone.tab + CalamaresUtils::Locale::ZonesModel* zonesModel() const { return m_zonesModel.get(); } + // This model can be filtered by region + CalamaresUtils::Locale::RegionalZonesModel* regionalZonesModel() const { return m_regionalZonesModel.get(); } + + const CalamaresUtils::Locale::TimeZoneData* currentLocation() const { return m_currentLocation; } /// Special case, set location from starting timezone if not already set void setCurrentLocation(); @@ -111,20 +111,17 @@ public Q_SLOTS: * names a zone within that region. */ void setCurrentLocation( const QString& region, const QString& zone ); - /** @brief Sets a location by pointer + + /** @brief Sets a location by pointer to zone data. * - * Pointer should be within the same model as the widget uses. - * This can update the locale configuration -- the automatic one - * follows the current location, and otherwise only explicitly-set - * values will ignore changes to the location. */ - void setCurrentLocation( const CalamaresUtils::Locale::TZZone* location ); + void setCurrentLocation( const CalamaresUtils::Locale::TimeZoneData* tz ); QString currentLanguageCode() const { return localeConfiguration().language(); } QString currentLCCode() const { return localeConfiguration().lc_numeric; } signals: - void currentLocationChanged( const CalamaresUtils::Locale::TZZone* location ) const; + void currentLocationChanged( const CalamaresUtils::Locale::TimeZoneData* location ) const; void currentLocationStatusChanged( const QString& ) const; void currentLanguageStatusChanged( const QString& ) const; void currentLCStatusChanged( const QString& ) const; @@ -137,12 +134,11 @@ private: QStringList m_localeGenLines; /// The regions (America, Asia, Europe ..) - std::unique_ptr< CalamaresUtils::Locale::CStringListModel > m_regionModel; - /// The zones for the current region (e.g. America/New_York) - std::unique_ptr< CalamaresUtils::Locale::CStringListModel > m_zonesModel; + std::unique_ptr< CalamaresUtils::Locale::RegionsModel > m_regionModel; + std::unique_ptr< CalamaresUtils::Locale::ZonesModel > m_zonesModel; + std::unique_ptr< CalamaresUtils::Locale::RegionalZonesModel > m_regionalZonesModel; - /// The location, points into the timezone data - const CalamaresUtils::Locale::TZZone* m_currentLocation = nullptr; + const CalamaresUtils::Locale::TimeZoneData* m_currentLocation = nullptr; /** @brief Specific locale configurations * diff --git a/src/modules/locale/LocalePage.cpp b/src/modules/locale/LocalePage.cpp index c10b2dee9..d4ad6854e 100644 --- a/src/modules/locale/LocalePage.cpp +++ b/src/modules/locale/LocalePage.cpp @@ -43,7 +43,7 @@ LocalePage::LocalePage( Config* config, QWidget* parent ) QBoxLayout* mainLayout = new QVBoxLayout; QBoxLayout* tzwLayout = new QHBoxLayout; - m_tzWidget = new TimeZoneWidget( config->timezoneData(), this ); + m_tzWidget = new TimeZoneWidget( m_config->zonesModel(), this ); tzwLayout->addStretch(); tzwLayout->addWidget( m_tzWidget ); tzwLayout->addStretch(); @@ -102,6 +102,7 @@ LocalePage::LocalePage( Config* config, QWidget* parent ) // Set up the location before connecting signals, to avoid a signal // storm as various parts interact. m_regionCombo->setModel( m_config->regionModel() ); + m_zoneCombo->setModel( m_config->regionalZonesModel() ); locationChanged( m_config->currentLocation() ); // doesn't inform TZ widget m_tzWidget->setCurrentLocation( m_config->currentLocation() ); @@ -112,7 +113,7 @@ LocalePage::LocalePage( Config* config, QWidget* parent ) connect( m_tzWidget, &TimeZoneWidget::locationChanged, config, - QOverload< const CalamaresUtils::Locale::TZZone* >::of( &Config::setCurrentLocation ) ); + QOverload< const CalamaresUtils::Locale::TimeZoneData* >::of( &Config::setCurrentLocation ) ); connect( m_regionCombo, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, &LocalePage::regionChanged ); connect( m_zoneCombo, QOverload< int >::of( &QComboBox::currentIndexChanged ), this, &LocalePage::zoneChanged ); @@ -152,35 +153,26 @@ LocalePage::regionChanged( int currentIndex ) { using namespace CalamaresUtils::Locale; - Q_UNUSED( currentIndex ) - QString selectedRegion = m_regionCombo->currentData().toString(); - - TZRegion* region = m_config->timezoneData().find< TZRegion >( selectedRegion ); - if ( !region ) + QString selectedRegion = m_regionCombo->itemData( currentIndex ).toString(); { - return; + cSignalBlocker z( m_zoneCombo ); + m_config->regionalZonesModel()->setRegion( selectedRegion ); } - - { - cSignalBlocker b( m_zoneCombo ); - m_zoneCombo->setModel( new CStringListModel( region->zones() ) ); - } - - m_zoneCombo->currentIndexChanged( m_zoneCombo->currentIndex() ); + m_zoneCombo->currentIndexChanged( 0 ); } void LocalePage::zoneChanged( int currentIndex ) { - Q_UNUSED( currentIndex ) if ( !m_blockTzWidgetSet ) { - m_config->setCurrentLocation( m_regionCombo->currentData().toString(), m_zoneCombo->currentData().toString() ); + m_config->setCurrentLocation( m_regionCombo->currentData().toString(), + m_zoneCombo->itemData( currentIndex ).toString() ); } } void -LocalePage::locationChanged( const CalamaresUtils::Locale::TZZone* location ) +LocalePage::locationChanged( const CalamaresUtils::Locale::TimeZoneData* location ) { if ( !location ) { diff --git a/src/modules/locale/LocalePage.h b/src/modules/locale/LocalePage.h index bf41f8f69..4f2d321b5 100644 --- a/src/modules/locale/LocalePage.h +++ b/src/modules/locale/LocalePage.h @@ -53,7 +53,7 @@ private: void regionChanged( int currentIndex ); void zoneChanged( int currentIndex ); - void locationChanged( const CalamaresUtils::Locale::TZZone* location ); + void locationChanged( const CalamaresUtils::Locale::TimeZoneData* location ); void changeLocale(); void changeFormats(); diff --git a/src/modules/locale/Tests.cpp b/src/modules/locale/Tests.cpp index af37a664b..e7fbb10f2 100644 --- a/src/modules/locale/Tests.cpp +++ b/src/modules/locale/Tests.cpp @@ -22,6 +22,7 @@ #include "timezonewidget/TimeZoneImage.h" #include "locale/TimeZone.h" +#include "utils/Logger.h" #include @@ -115,37 +116,35 @@ LocaleTests::testTZImages() // // using namespace CalamaresUtils::Locale; - const CStringPairList& regions = TZRegion::fromZoneTab(); + const ZonesModel m; int overlapcount = 0; - for ( const auto* pr : regions ) + for ( auto it = m.begin(); it; ++it ) { - const TZRegion* region = dynamic_cast< const TZRegion* >( pr ); - QVERIFY( region ); + QString region = m.data( m.index( it.index() ), ZonesModel::RegionRole ).toString(); + QString zoneName = m.data( m.index( it.index() ), ZonesModel::KeyRole ).toString(); + QVERIFY( !region.isEmpty() ); + QVERIFY( !zoneName.isEmpty() ); + const auto* zone = m.find( region, zoneName ); + const auto* iterzone = *it; - Logger::setupLogLevel( Logger::LOGDEBUG ); - cDebug() << "Region" << region->region() << "zones #" << region->zones().count(); - Logger::setupLogLevel( Logger::LOGERROR ); + QVERIFY( iterzone ); + QVERIFY( zone ); + QCOMPARE( zone, iterzone ); + QCOMPARE( zone->zone(), zoneName ); + QCOMPARE( zone->region(), region ); - const auto zones = region->zones(); - QVERIFY( zones.count() > 0 ); - for ( const auto* pz : zones ) + int overlap = 0; + auto pos = images.getLocationPosition( zone->longitude(), zone->latitude() ); + QVERIFY( images.index( pos, overlap ) >= 0 ); + QVERIFY( overlap > 0 ); // At least one image contains the spot + if ( overlap > 1 ) { - const TZZone* zone = dynamic_cast< const TZZone* >( pz ); - QVERIFY( zone ); - - int overlap = 0; - auto pos = images.getLocationPosition( zone->longitude(), zone->latitude() ); - QVERIFY( images.index( pos, overlap ) >= 0 ); - QVERIFY( overlap > 0 ); // At least one image contains the spot - if ( overlap > 1 ) - { - Logger::setupLogLevel( Logger::LOGDEBUG ); - cDebug() << Logger::SubEntry << "Zone" << zone->zone() << pos; - (void)images.index( pos, overlap ); - Logger::setupLogLevel( Logger::LOGERROR ); - overlapcount++; - } + Logger::setupLogLevel( Logger::LOGDEBUG ); + cDebug() << Logger::SubEntry << "Zone" << zone->zone() << pos; + (void)images.index( pos, overlap ); + Logger::setupLogLevel( Logger::LOGERROR ); + overlapcount++; } } @@ -168,12 +167,17 @@ operator<( const QPoint& l, const QPoint& r ) } void -listAll( const QPoint& p, const CalamaresUtils::Locale::CStringPairList& zones ) +listAll( const QPoint& p, const CalamaresUtils::Locale::ZonesModel& zones ) { using namespace CalamaresUtils::Locale; - for ( const auto* pz : zones ) + for ( auto it = zones.begin(); it; ++it ) { - const TZZone* zone = dynamic_cast< const TZZone* >( pz ); + const auto* zone = *it; + if ( !zone ) + { + cError() << Logger::SubEntry << "NULL zone"; + return; + } if ( p == TimeZoneImageList::getLocationPosition( zone->longitude(), zone->latitude() ) ) { cError() << Logger::SubEntry << zone->zone(); @@ -185,78 +189,36 @@ void LocaleTests::testTZLocations() { using namespace CalamaresUtils::Locale; - const CStringPairList& regions = TZRegion::fromZoneTab(); + ZonesModel zones; int overlapcount = 0; - for ( const auto* pr : regions ) + for ( auto it = zones.begin(); it; ++it ) { - const TZRegion* region = dynamic_cast< const TZRegion* >( pr ); - QVERIFY( region ); - - Logger::setupLogLevel( Logger::LOGDEBUG ); - cDebug() << "Region" << region->region() << "zones #" << region->zones().count(); - Logger::setupLogLevel( Logger::LOGERROR ); - std::set< QPoint > occupied; - const auto zones = region->zones(); - QVERIFY( zones.count() > 0 ); - for ( const auto* pz : zones ) - { - const TZZone* zone = dynamic_cast< const TZZone* >( pz ); - QVERIFY( zone ); + const auto* zone = *it; + QVERIFY( zone ); - auto pos = TimeZoneImageList::getLocationPosition( zone->longitude(), zone->latitude() ); - if ( occupied.find( pos ) != occupied.end() ) - { - cError() << "Zone" << zone->zone() << "occupies same spot as .."; - listAll( pos, zones ); - overlapcount++; - } - occupied.insert( pos ); + auto pos = TimeZoneImageList::getLocationPosition( zone->longitude(), zone->latitude() ); + if ( occupied.find( pos ) != occupied.end() ) + { + cError() << "Zone" << zone->zone() << "occupies same spot as .."; + listAll( pos, zones ); + overlapcount++; } + occupied.insert( pos ); } QEXPECT_FAIL( "", "TZ Images contain pixel-overlaps", Continue ); QCOMPARE( overlapcount, 0 ); } -const CalamaresUtils::Locale::TZZone* -findZone( const QString& name ) -{ - using namespace CalamaresUtils::Locale; - const CStringPairList& regions = TZRegion::fromZoneTab(); - - for ( const auto* pr : regions ) - { - const TZRegion* region = dynamic_cast< const TZRegion* >( pr ); - if ( !region ) - { - continue; - } - const auto zones = region->zones(); - for ( const auto* pz : zones ) - { - const TZZone* zone = dynamic_cast< const TZZone* >( pz ); - if ( !zone ) - { - continue; - } - - if ( zone->zone() == name ) - { - return zone; - } - } - } - return nullptr; -} - void LocaleTests::testSpecificLocations() { - const auto* gibraltar = findZone( "Gibraltar" ); - const auto* ceuta = findZone( "Ceuta" ); + CalamaresUtils::Locale::ZonesModel zones; + const auto* gibraltar = zones.find( "Europe", "Gibraltar" ); + const auto* ceuta = zones.find( "Africa", "Ceuta" ); QVERIFY( gibraltar ); QVERIFY( ceuta ); diff --git a/src/modules/locale/timezonewidget/timezonewidget.cpp b/src/modules/locale/timezonewidget/timezonewidget.cpp index 0972e3296..b1d3cfeaa 100644 --- a/src/modules/locale/timezonewidget/timezonewidget.cpp +++ b/src/modules/locale/timezonewidget/timezonewidget.cpp @@ -35,13 +35,13 @@ #endif static QPoint -getLocationPosition( const CalamaresUtils::Locale::TZZone* l ) +getLocationPosition( const CalamaresUtils::Locale::TimeZoneData* l ) { return TimeZoneImageList::getLocationPosition( l->longitude(), l->latitude() ); } -TimeZoneWidget::TimeZoneWidget( const CalamaresUtils::Locale::CStringPairList& zones, QWidget* parent ) +TimeZoneWidget::TimeZoneWidget( const CalamaresUtils::Locale::ZonesModel* zones, QWidget* parent ) : QWidget( parent ) , timeZoneImages( TimeZoneImageList::fromQRC() ) , m_zonesData( zones ) @@ -65,7 +65,7 @@ TimeZoneWidget::TimeZoneWidget( const CalamaresUtils::Locale::CStringPairList& z void -TimeZoneWidget::setCurrentLocation( const CalamaresUtils::Locale::TZZone* location ) +TimeZoneWidget::setCurrentLocation( const TimeZoneData* location ) { if ( location == m_currentLocation ) { @@ -190,32 +190,24 @@ TimeZoneWidget::mousePressEvent( QMouseEvent* event ) { return; } - // Set nearest location int nX = 999999, mX = event->pos().x(); int nY = 999999, mY = event->pos().y(); using namespace CalamaresUtils::Locale; - const TZZone* closest = nullptr; - for ( const auto* region_p : m_zonesData ) + const TimeZoneData* closest = nullptr; + for ( auto it = m_zonesData->begin(); it; ++it ) { - const auto* region = dynamic_cast< const TZRegion* >( region_p ); - if ( region ) + const auto* zone = *it; + if ( zone ) { - for ( const auto* zone_p : region->zones() ) - { - const auto* zone = dynamic_cast< const TZZone* >( zone_p ); - if ( zone ) - { - QPoint locPos = TimeZoneImageList::getLocationPosition( zone->longitude(), zone->latitude() ); + QPoint locPos = TimeZoneImageList::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(); - } - } + if ( ( abs( mX - locPos.x() ) + abs( mY - locPos.y() ) < abs( mX - nX ) + abs( mY - nY ) ) ) + { + closest = zone; + nX = locPos.x(); + nY = locPos.y(); } } } diff --git a/src/modules/locale/timezonewidget/timezonewidget.h b/src/modules/locale/timezonewidget/timezonewidget.h index 6bb94c0dd..c15570b52 100644 --- a/src/modules/locale/timezonewidget/timezonewidget.h +++ b/src/modules/locale/timezonewidget/timezonewidget.h @@ -51,28 +51,28 @@ class TimeZoneWidget : public QWidget { Q_OBJECT public: - using TZZone = CalamaresUtils::Locale::TZZone; + using TimeZoneData = CalamaresUtils::Locale::TimeZoneData; - explicit TimeZoneWidget( const CalamaresUtils::Locale::CStringPairList& zones, QWidget* parent = nullptr ); + explicit TimeZoneWidget( const CalamaresUtils::Locale::ZonesModel* zones, QWidget* parent = nullptr ); public Q_SLOTS: /** @brief Sets a location by pointer * * Pointer should be within the same model as the widget uses. */ - void setCurrentLocation( const TZZone* location ); + void setCurrentLocation( const TimeZoneData* location ); signals: /** @brief The location has changed by mouse click */ - void locationChanged( const TZZone* location ); + void locationChanged( const TimeZoneData* location ); private: QFont font; QImage background, pin, currentZoneImage; TimeZoneImageList timeZoneImages; - const CalamaresUtils::Locale::CStringPairList& m_zonesData; - const TZZone* m_currentLocation = nullptr; // Not owned by me + const CalamaresUtils::Locale::ZonesModel* m_zonesData; + const TimeZoneData* m_currentLocation = nullptr; // Not owned by me void paintEvent( QPaintEvent* event ); void mousePressEvent( QMouseEvent* event );