2019-11-26 11:18:35 +01:00
|
|
|
/* === 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"
|
|
|
|
|
2019-12-10 14:36:53 +01:00
|
|
|
#include "utils/Logger.h"
|
|
|
|
|
2019-12-09 21:46:10 +01:00
|
|
|
#include <QFile>
|
|
|
|
#include <QStringList>
|
|
|
|
#include <QTextStream>
|
|
|
|
|
2019-11-26 11:18:35 +01:00
|
|
|
#include <cstring>
|
|
|
|
|
2019-12-09 21:46:10 +01:00
|
|
|
static const char TZ_DATA_FILE[] = "/usr/share/zoneinfo/zone.tab";
|
|
|
|
|
2019-12-10 14:36:53 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-11-26 11:18:35 +01:00
|
|
|
namespace CalamaresUtils
|
|
|
|
{
|
|
|
|
namespace Locale
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
CStringPair::CStringPair( CStringPair&& t )
|
2019-12-09 21:46:10 +01:00
|
|
|
: m_human( nullptr )
|
2019-12-10 10:11:08 +01:00
|
|
|
, m_key()
|
2019-11-26 11:18:35 +01:00
|
|
|
{
|
|
|
|
// 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 )
|
2019-12-10 10:11:08 +01:00
|
|
|
, m_key( t.m_key )
|
2019-11-26 11:18:35 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @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 )
|
2019-12-10 10:11:08 +01:00
|
|
|
, m_key( s1 ? QString( s1 ) : QString() )
|
2019-11-26 11:18:35 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CStringPair::~CStringPair()
|
|
|
|
{
|
|
|
|
free( m_human );
|
|
|
|
}
|
|
|
|
|
2019-11-26 12:30:59 +01:00
|
|
|
|
|
|
|
QString
|
|
|
|
TZRegion::tr() const
|
|
|
|
{
|
|
|
|
// NOTE: context name must match what's used in zone-extractor.py
|
|
|
|
return QObject::tr( m_human, "tz_regions" );
|
|
|
|
}
|
|
|
|
|
2019-12-10 12:45:56 +01:00
|
|
|
TZRegion::~TZRegion()
|
2019-11-26 12:30:59 +01:00
|
|
|
{
|
2019-12-10 12:45:56 +01:00
|
|
|
qDeleteAll( m_zones );
|
2019-11-26 12:30:59 +01:00
|
|
|
}
|
|
|
|
|
2019-12-10 15:32:15 +01:00
|
|
|
CStringPairList
|
2019-12-10 12:45:56 +01:00
|
|
|
TZRegion::fromZoneTab()
|
2019-12-09 21:46:10 +01:00
|
|
|
{
|
2019-12-10 12:45:56 +01:00
|
|
|
return TZRegion::fromFile( TZ_DATA_FILE );
|
2019-12-10 11:36:05 +01:00
|
|
|
}
|
2019-12-09 21:46:10 +01:00
|
|
|
|
2019-12-10 15:32:15 +01:00
|
|
|
CStringPairList
|
2019-12-10 12:45:56 +01:00
|
|
|
TZRegion::fromFile( const char* fileName )
|
2019-12-10 11:36:05 +01:00
|
|
|
{
|
2019-12-10 15:32:15 +01:00
|
|
|
CStringPairList model;
|
2019-12-10 11:36:05 +01:00
|
|
|
|
|
|
|
QFile file( fileName );
|
2019-12-09 21:46:10 +01:00
|
|
|
if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
|
|
|
|
{
|
2019-12-10 11:36:05 +01:00
|
|
|
return model;
|
2019-12-09 21:46:10 +01:00
|
|
|
}
|
|
|
|
|
2019-12-10 15:06:22 +01:00
|
|
|
TZRegion* thisRegion = nullptr;
|
2019-12-09 21:46:10 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-12-10 15:32:15 +01:00
|
|
|
auto keyMatch = [®ion]( const CStringPair* r ) { return r->key() == region; };
|
|
|
|
auto it = std::find_if( model.begin(), model.end(), keyMatch );
|
2019-12-10 15:06:22 +01:00
|
|
|
if ( it != model.end() )
|
|
|
|
{
|
2019-12-10 15:32:15 +01:00
|
|
|
thisRegion = dynamic_cast< TZRegion* >( *it );
|
2019-12-10 15:06:22 +01:00
|
|
|
}
|
|
|
|
else
|
2019-12-09 21:46:10 +01:00
|
|
|
{
|
2019-12-10 15:06:22 +01:00
|
|
|
thisRegion = new TZRegion( region.toUtf8().data() );
|
|
|
|
model.append( thisRegion );
|
2019-12-09 21:46:10 +01:00
|
|
|
}
|
2019-12-10 14:36:53 +01:00
|
|
|
|
|
|
|
QString countryCode = list.at( 0 ).trimmed();
|
|
|
|
if ( countryCode.size() != 2 )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
timezoneParts.removeFirst();
|
2019-12-10 15:32:15 +01:00
|
|
|
thisRegion->m_zones.append(
|
|
|
|
new TZZone( timezoneParts.join( '/' ).toUtf8().constData(), countryCode, list.at( 1 ) ) );
|
2019-12-09 21:46:10 +01:00
|
|
|
}
|
2019-12-10 11:36:05 +01:00
|
|
|
|
2019-12-10 15:32:15 +01:00
|
|
|
auto sorter = []( const CStringPair* l, const CStringPair* r ) { return *l < *r; };
|
|
|
|
std::sort( model.begin(), model.end(), sorter );
|
|
|
|
for ( auto& it : model )
|
2019-12-10 15:06:22 +01:00
|
|
|
{
|
2019-12-10 15:32:15 +01:00
|
|
|
TZRegion* r = dynamic_cast< TZRegion* >( it );
|
|
|
|
if ( r )
|
|
|
|
{
|
|
|
|
std::sort( r->m_zones.begin(), r->m_zones.end(), sorter );
|
|
|
|
}
|
2019-12-10 15:06:22 +01:00
|
|
|
}
|
|
|
|
|
2019-12-10 11:36:05 +01:00
|
|
|
return model;
|
2019-12-09 21:46:10 +01:00
|
|
|
}
|
|
|
|
|
2019-12-10 14:36:53 +01:00
|
|
|
TZZone::TZZone( const char* zoneName, const QString& country, QString position )
|
|
|
|
: CStringPair( zoneName )
|
|
|
|
, 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 + 1 ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-10 12:45:56 +01:00
|
|
|
QString
|
|
|
|
TZZone::tr() const
|
|
|
|
{
|
|
|
|
// NOTE: context name must match what's used in zone-extractor.py
|
|
|
|
return QObject::tr( m_human, "tz_names" );
|
|
|
|
}
|
|
|
|
|
2019-12-10 14:36:53 +01:00
|
|
|
void
|
|
|
|
TZZone::print( QDebug& log ) const
|
|
|
|
{
|
|
|
|
log << key() << '(' << m_country << ' ' << m_latitude << ',' << m_longitude << ')';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-12-10 15:32:15 +01:00
|
|
|
CStringListModel::CStringListModel( CStringPairList l )
|
|
|
|
: m_list( l )
|
2019-12-10 11:54:33 +01:00
|
|
|
{
|
|
|
|
}
|
2019-12-09 21:46:10 +01:00
|
|
|
|
2019-12-10 15:32:15 +01:00
|
|
|
CStringListModel::~CStringListModel() {}
|
2019-12-10 12:45:56 +01:00
|
|
|
|
2019-12-09 21:46:10 +01:00
|
|
|
int
|
2019-12-10 15:32:15 +01:00
|
|
|
CStringListModel::rowCount( const QModelIndex& parent ) const
|
2019-12-09 21:46:10 +01:00
|
|
|
{
|
2019-12-10 15:32:15 +01:00
|
|
|
return m_list.count();
|
2019-12-09 21:46:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QVariant
|
2019-12-10 15:32:15 +01:00
|
|
|
CStringListModel::data( const QModelIndex& index, int role ) const
|
2019-12-09 21:46:10 +01:00
|
|
|
{
|
2019-12-10 12:12:32 +01:00
|
|
|
if ( ( role != Qt::DisplayRole ) && ( role != Qt::UserRole ) )
|
2019-12-09 21:46:10 +01:00
|
|
|
{
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !index.isValid() )
|
|
|
|
{
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
2019-12-10 15:32:15 +01:00
|
|
|
const auto* item = m_list.at( index.row() );
|
|
|
|
return item ? ( role == Qt::DisplayRole ? item->tr() : item->key() ) : QVariant();
|
2019-12-09 21:46:10 +01:00
|
|
|
}
|
|
|
|
|
2019-12-10 15:32:15 +01:00
|
|
|
const CStringPair*
|
|
|
|
CStringListModel::item( int index ) const
|
2019-12-09 22:20:46 +01:00
|
|
|
{
|
2019-12-10 15:32:15 +01:00
|
|
|
if ( ( index < 0 ) || ( index >= m_list.count() ) )
|
2019-12-09 22:20:46 +01:00
|
|
|
{
|
2019-12-10 12:45:56 +01:00
|
|
|
return nullptr;
|
2019-12-09 22:20:46 +01:00
|
|
|
}
|
2019-12-10 15:32:15 +01:00
|
|
|
return m_list[ index ];
|
2019-12-09 22:20:46 +01:00
|
|
|
}
|
2019-12-09 21:46:10 +01:00
|
|
|
|
2019-11-26 11:18:35 +01:00
|
|
|
} // namespace Locale
|
|
|
|
} // namespace CalamaresUtils
|