From 1e0492422449c4b6f843a71037f82832ea37e2bf Mon Sep 17 00:00:00 2001
From: Adriaan de Groot <groot@kde.org>
Date: Tue, 10 Dec 2019 17:29:35 +0100
Subject: [PATCH] [locale] Drop the TZ-widget's timezone database

 - use the global TZ service instead
 - contains hacks to keep some of the API unchanged, which will be
   removed shortly
---
 .../locale/timezonewidget/localeglobal.cpp    | 88 +++----------------
 .../locale/timezonewidget/localeglobal.h      | 14 ++-
 .../locale/timezonewidget/timezonewidget.cpp  | 73 ++++++++-------
 .../locale/timezonewidget/timezonewidget.h    |  7 +-
 4 files changed, 66 insertions(+), 116 deletions(-)

diff --git a/src/modules/locale/timezonewidget/localeglobal.cpp b/src/modules/locale/timezonewidget/localeglobal.cpp
index 683b2bebc..a9c7d3077 100644
--- a/src/modules/locale/timezonewidget/localeglobal.cpp
+++ b/src/modules/locale/timezonewidget/localeglobal.cpp
@@ -22,6 +22,8 @@
 
 #include "localeglobal.h"
 
+#include "locale/TimeZone.h"
+
 #include <QTimeZone>
 
 //###
@@ -29,7 +31,6 @@
 //###
 
 QHash<QString, QHash<QString, QList<LocaleGlobal::Locale> > > LocaleGlobal::locales;
-QHash<QString, QList<LocaleGlobal::Location> > LocaleGlobal::locations;
 
 
 //###
@@ -53,12 +54,21 @@ LocaleGlobal::Location::comment() const
     return qtz.comment();
 }
 
+LocaleGlobal::Location & LocaleGlobal::Location::operator=(const CalamaresUtils::Locale::TZZone& location)
+{
+    region = location.region();
+    zone = location.key();
+    country = location.country();
+    latitude = location.latitude();
+    longitude = location.longitude();
+    return *this;
+}
+
 
 void
 LocaleGlobal::init() {
     // TODO: Error handling
     initLocales();
-    initLocations();
 }
 
 
@@ -70,12 +80,6 @@ LocaleGlobal::getLocales() {
 
 
 
-QHash< QString, QList< LocaleGlobal::Location > >
-LocaleGlobal::getLocations() {
-    return locations;
-}
-
-
 //###
 //### Private methods
 //###
@@ -126,71 +130,3 @@ LocaleGlobal::initLocales() {
         locales[lang][territory].append(locale);
     }
 }
-
-
-
-void
-LocaleGlobal::initLocations() {
-    static const char TZ_DATA_FILE[] = "/usr/share/zoneinfo/zone.tab";
-
-    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;
-}
-
diff --git a/src/modules/locale/timezonewidget/localeglobal.h b/src/modules/locale/timezonewidget/localeglobal.h
index 1a8f796d4..2b0bf0de7 100644
--- a/src/modules/locale/timezonewidget/localeglobal.h
+++ b/src/modules/locale/timezonewidget/localeglobal.h
@@ -36,6 +36,14 @@
 #include <QDebug>
 #include "localeconst.h"
 
+namespace CalamaresUtils
+{
+    namespace Locale
+    {
+        class TZZone;
+    }
+}
+
 class LocaleGlobal
 {
 public:
@@ -50,19 +58,17 @@ public:
         double latitude, longitude;
         static QString pretty( const QString& s );
         QString comment() const;
+
+        Location& operator=(const CalamaresUtils::Locale::TZZone&);
     };
 
     static void init();
     static QHash<QString, QHash<QString, QList<LocaleGlobal::Locale> > > getLocales();
-    static QHash<QString, QList<LocaleGlobal::Location> > getLocations();
 
 private:
     static QHash<QString, QHash<QString, QList<LocaleGlobal::Locale> > > locales;
-    static QHash<QString, QList<LocaleGlobal::Location> > locations;
 
     static void initLocales();
-    static void initLocations();
-    static double getRightGeoLocation( QString str );
 };
 
 inline QDebug& operator <<( QDebug& s, const LocaleGlobal::Location& l )
diff --git a/src/modules/locale/timezonewidget/timezonewidget.cpp b/src/modules/locale/timezonewidget/timezonewidget.cpp
index 33a8f25ac..bcf95cc25 100644
--- a/src/modules/locale/timezonewidget/timezonewidget.cpp
+++ b/src/modules/locale/timezonewidget/timezonewidget.cpp
@@ -1,7 +1,7 @@
 /* === This file is part of Calamares - <https://github.com/calamares> ===
  *
  *   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
  *   by Roland Singer <roland@manjaro.org>
@@ -24,6 +24,7 @@
 #include <cmath>
 
 #include "utils/Logger.h"
+#include "locale/TimeZone.h"
 
 #include "timezonewidget.h"
 
@@ -67,28 +68,27 @@ TimeZoneWidget::TimeZoneWidget( QWidget* parent ) :
 }
 
 
-void TimeZoneWidget::setCurrentLocation( QString region, QString zone )
+void TimeZoneWidget::setCurrentLocation( QString regionName, QString zoneName )
 {
-    QHash<QString, QList<LocaleGlobal::Location> > hash = LocaleGlobal::getLocations();
-
-    if ( !hash.contains( region ) )
+    using namespace CalamaresUtils::Locale;
+    const auto& regions = TZRegion::fromZoneTab();
+    auto *region = regions.find<TZRegion>( regionName );
+    if ( !region )
+    {
         return;
+    }
 
-    QList<LocaleGlobal::Location> locations = hash.value( region );
-    for ( int i = 0; i < locations.size(); ++i )
+    auto *zone = region->zones().find< TZZone >(zoneName);
+    if ( zone )
     {
-        if ( locations.at( i ).zone == zone )
-        {
-            setCurrentLocation( locations.at( i ) );
-            break;
-        }
+        setCurrentLocation( zone );
     }
 }
 
 
-void TimeZoneWidget::setCurrentLocation( LocaleGlobal::Location location )
+void TimeZoneWidget::setCurrentLocation( const CalamaresUtils::Locale::TZZone *location )
 {
-    currentLocation = location;
+    currentLocation = *location;
 
     // Set zone
     QPoint pos = getLocationPosition( currentLocation.longitude, currentLocation.latitude );
@@ -259,32 +259,37 @@ void TimeZoneWidget::mousePressEvent( QMouseEvent* event )
     // Set nearest location
     int nX = 999999, mX = event->pos().x();
     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();
-
-        for ( int i = 0; i < locations.size(); ++i )
+        const auto* region = dynamic_cast<const TZRegion*>(region_p);
+        if ( region )
         {
-            LocaleGlobal::Location loc = locations[i];
-            QPoint locPos = getLocationPosition( loc.longitude, loc.latitude );
-
-            if ( ( abs( mX - locPos.x() ) + abs( mY - locPos.y() )  <  abs( mX - nX ) + abs( mY - nY ) ) )
+            for ( const auto* zone_p : region->zones() )
             {
-                currentLocation = loc;
-                nX = locPos.x();
-                nY = locPos.y();
+                const auto* zone = dynamic_cast<const TZZone*>(zone_p);
+                if ( zone )
+                {
+                    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
-    setCurrentLocation( currentLocation );
-
-    // Emit signal
-    emit locationChanged( currentLocation );
+    if ( closest )
+    {
+        // Set zone image and repaint widget
+        setCurrentLocation( closest );
+        // Emit signal
+        emit locationChanged( currentLocation );
+    }
 }
diff --git a/src/modules/locale/timezonewidget/timezonewidget.h b/src/modules/locale/timezonewidget/timezonewidget.h
index dd49b3311..5b09709ba 100644
--- a/src/modules/locale/timezonewidget/timezonewidget.h
+++ b/src/modules/locale/timezonewidget/timezonewidget.h
@@ -24,6 +24,10 @@
 #ifndef TIMEZONEWIDGET_H
 #define TIMEZONEWIDGET_H
 
+#include "localeglobal.h"
+
+#include "locale/TimeZone.h"
+
 #include <QWidget>
 #include <QPainter>
 #include <QImage>
@@ -34,7 +38,6 @@
 #include <QMouseEvent>
 #include <QFontMetrics>
 #include <QFont>
-#include "localeglobal.h"
 
 
 #define RGB_TRANSPARENT 0
@@ -54,7 +57,7 @@ public:
         return currentLocation;
     }
     void setCurrentLocation( QString region, QString zone );
-    void setCurrentLocation( LocaleGlobal::Location location );
+    void setCurrentLocation( const CalamaresUtils::Locale::TZZone *location );
 
 signals:
     void locationChanged( LocaleGlobal::Location location );