Merge branch 'shuffle-geoip'
This commit is contained in:
commit
c3754126d0
5
CHANGES
5
CHANGES
@ -35,6 +35,11 @@ This release contains contributions from (alphabetically by first name):
|
||||
- *finished* has a new mechanism for configuring the behavior of the
|
||||
*restart now* button. The old-style boolean configuration is still
|
||||
supported but generates a warning. #1138
|
||||
- *locale* module GeoIP configuration has a new preferred format.
|
||||
See `locale.conf` for details. The old configuration is still
|
||||
supported but will be phased out before 3.3.0 -- in particular,
|
||||
support for "legacy" format will be removed, since that was a
|
||||
crutch for the disappearance of one GeoIP provider in 2018.
|
||||
- *oemid* is a new module for configuring OEM phase-0 (image pre-mastering,
|
||||
or pre-deployment) things. It has limited functionality at the moment,
|
||||
writing only a single batch-identifier file. #943
|
||||
|
@ -13,6 +13,9 @@ configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/CalamaresConfig.h.in
|
||||
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/../calamares/CalamaresVersion.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/CalamaresVersion.h )
|
||||
|
||||
set( OPTIONAL_PRIVATE_LIBRARIES "" )
|
||||
set( OPTIONAL_PUBLIC_LIBRARIES "" )
|
||||
|
||||
set( libSources
|
||||
CppJob.cpp
|
||||
GlobalStorage.cpp
|
||||
@ -21,10 +24,17 @@ set( libSources
|
||||
JobQueue.cpp
|
||||
ProcessJob.cpp
|
||||
Settings.cpp
|
||||
|
||||
|
||||
# GeoIP services
|
||||
geoip/Interface.cpp
|
||||
geoip/GeoIPJSON.cpp
|
||||
geoip/Handler.cpp
|
||||
|
||||
# Locale-data service
|
||||
locale/Label.cpp
|
||||
locale/LabelModel.cpp
|
||||
locale/Lookup.cpp
|
||||
|
||||
|
||||
# Partition service
|
||||
partition/PartitionSize.cpp
|
||||
|
||||
@ -32,7 +42,6 @@ set( libSources
|
||||
utils/CalamaresUtilsSystem.cpp
|
||||
utils/CommandList.cpp
|
||||
utils/Dirs.cpp
|
||||
utils/LocaleLabel.cpp
|
||||
utils/Logger.cpp
|
||||
utils/PluginFactory.cpp
|
||||
utils/Retranslator.cpp
|
||||
@ -54,9 +63,11 @@ include_directories(
|
||||
${YAMLCPP_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
### OPTIONAL Python support
|
||||
#
|
||||
#
|
||||
if( WITH_PYTHON )
|
||||
set( libSources
|
||||
${libSources}
|
||||
list( APPEND libSources
|
||||
PythonHelper.cpp
|
||||
PythonJob.cpp
|
||||
PythonJobApi.cpp
|
||||
@ -71,13 +82,24 @@ if( WITH_PYTHON )
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
link_directories(${Boost_LIBRARY_DIRS})
|
||||
|
||||
set( OPTIONAL_PRIVATE_LIBRARIES
|
||||
${OPTIONAL_PRIVATE_LIBRARIES}
|
||||
list( APPEND OPTIONAL_PRIVATE_LIBRARIES
|
||||
${PYTHON_LIBRARIES}
|
||||
${Boost_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
### OPTIONAL GeoIP XML support
|
||||
#
|
||||
#
|
||||
find_package(Qt5 COMPONENTS Xml)
|
||||
if( Qt5Xml_FOUND )
|
||||
list( APPEND libSources geoip/GeoIPXML.cpp )
|
||||
list( APPEND OPTIONAL_PUBLIC_LIBRARIES Qt5::Network Qt5::Xml )
|
||||
endif()
|
||||
|
||||
### LIBRARY
|
||||
#
|
||||
#
|
||||
add_library( calamares SHARED ${libSources} ${kdsagSources} )
|
||||
set_target_properties( calamares
|
||||
PROPERTIES
|
||||
@ -92,6 +114,7 @@ target_link_libraries( calamares
|
||||
LINK_PUBLIC
|
||||
${YAMLCPP_LIBRARY}
|
||||
Qt5::Core
|
||||
${OPTIONAL_PUBLIC_LIBRARIES}
|
||||
)
|
||||
|
||||
install( TARGETS calamares
|
||||
@ -101,19 +124,6 @@ install( TARGETS calamares
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
if ( ECM_FOUND AND BUILD_TESTING )
|
||||
ecm_add_test(
|
||||
Tests.cpp
|
||||
TEST_NAME
|
||||
libcalamarestest
|
||||
LINK_LIBRARIES
|
||||
calamares
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
)
|
||||
calamares_automoc( libcalamarestest )
|
||||
endif()
|
||||
|
||||
# Make symlink lib/calamares/libcalamares.so to lib/libcalamares.so.VERSION so
|
||||
# lib/calamares can be used as module path for the Python interpreter.
|
||||
install( CODE "
|
||||
@ -130,3 +140,37 @@ install( FILES ${CMAKE_CURRENT_BINARY_DIR}/CalamaresConfig.h DESTINATION include
|
||||
install( FILES ${rootHeaders} DESTINATION include/libcalamares )
|
||||
install( FILES ${kdsingleapplicationguardHeaders} DESTINATION include/libcalamares/kdsingleapplicationguard )
|
||||
install( FILES ${utilsHeaders} DESTINATION include/libcalamares/utils )
|
||||
|
||||
### TESTING
|
||||
#
|
||||
#
|
||||
if ( ECM_FOUND AND BUILD_TESTING )
|
||||
ecm_add_test(
|
||||
Tests.cpp
|
||||
TEST_NAME
|
||||
libcalamarestest
|
||||
LINK_LIBRARIES
|
||||
calamares
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
)
|
||||
calamares_automoc( libcalamarestest )
|
||||
|
||||
ecm_add_test(
|
||||
geoip/GeoIPTests.cpp
|
||||
${geoip_src}
|
||||
TEST_NAME
|
||||
geoiptest
|
||||
LINK_LIBRARIES
|
||||
calamares
|
||||
Qt5::Test
|
||||
${YAMLCPP_LIBRARY}
|
||||
)
|
||||
calamares_automoc( geoiptest )
|
||||
endif()
|
||||
|
||||
if( BUILD_TESTING )
|
||||
add_executable( test_geoip geoip/test_geoip.cpp ${geoip_src} )
|
||||
target_link_libraries( test_geoip calamares Qt5::Network ${YAMLCPP_LIBRARY} )
|
||||
calamares_automoc( test_geoip )
|
||||
endif()
|
||||
|
@ -25,11 +25,20 @@
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
namespace CalamaresUtils::GeoIP
|
||||
{
|
||||
|
||||
GeoIPJSON::GeoIPJSON(const QString& attribute)
|
||||
: GeoIP( attribute.isEmpty() ? QStringLiteral( "time_zone" ) : attribute )
|
||||
: Interface( attribute.isEmpty() ? QStringLiteral( "time_zone" ) : attribute )
|
||||
{
|
||||
}
|
||||
|
||||
/** @brief Indexes into a map @m by selectors @p l
|
||||
*
|
||||
* Each element of @p l is an index into map @m or a sub-map thereof,
|
||||
* so that "foo.bar.baz" looks up "baz" in the sub-map "bar" of sub-map
|
||||
* "foo" of @p m, like a regular JSON lookup would.
|
||||
*/
|
||||
static QString
|
||||
selectMap( const QVariantMap& m, const QStringList& l, int index)
|
||||
{
|
||||
@ -48,8 +57,8 @@ selectMap( const QVariantMap& m, const QStringList& l, int index)
|
||||
}
|
||||
}
|
||||
|
||||
GeoIP::RegionZonePair
|
||||
GeoIPJSON::processReply( const QByteArray& data )
|
||||
QString
|
||||
GeoIPJSON::rawReply( const QByteArray& data )
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -60,7 +69,7 @@ GeoIPJSON::processReply( const QByteArray& data )
|
||||
var.isValid() &&
|
||||
var.type() == QVariant::Map )
|
||||
{
|
||||
return splitTZString( selectMap( var.toMap(), m_element.split('.'), 0 ) );
|
||||
return selectMap( var.toMap(), m_element.split('.'), 0 );
|
||||
}
|
||||
else
|
||||
cWarning() << "Invalid YAML data for GeoIPJSON";
|
||||
@ -70,5 +79,15 @@ GeoIPJSON::processReply( const QByteArray& data )
|
||||
CalamaresUtils::explainYamlException( e, data, "GeoIP data");
|
||||
}
|
||||
|
||||
return qMakePair( QString(), QString() );
|
||||
return QString();
|
||||
}
|
||||
|
||||
GeoIP::RegionZonePair
|
||||
GeoIPJSON::processReply( const QByteArray& data )
|
||||
{
|
||||
return splitTZString( rawReply( data ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace
|
@ -1,6 +1,6 @@
|
||||
/* === This file is part of Calamares - <http://github.com/calamares> ===
|
||||
*
|
||||
* Copyright 2018, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2018-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
|
||||
@ -16,19 +16,23 @@
|
||||
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GEOIPJSON_H
|
||||
#define GEOIPJSON_H
|
||||
#ifndef GEOIP_GEOIPJSON_H
|
||||
#define GEOIP_GEOIPJSON_H
|
||||
|
||||
#include "GeoIP.h"
|
||||
#include "Interface.h"
|
||||
|
||||
namespace CalamaresUtils::GeoIP
|
||||
{
|
||||
/** @brief GeoIP lookup for services that return JSON.
|
||||
*
|
||||
* This is the original implementation of GeoIP lookup,
|
||||
* (e.g. using the FreeGeoIP.net service), or similar.
|
||||
*
|
||||
* The data is assumed to be in JSON format with a time_zone attribute.
|
||||
*
|
||||
* @note This class is an implementation detail.
|
||||
*/
|
||||
class GeoIPJSON : public GeoIP
|
||||
class GeoIPJSON : public Interface
|
||||
{
|
||||
public:
|
||||
/** @brief Configure the attribute name which is selected.
|
||||
@ -38,7 +42,9 @@ public:
|
||||
*/
|
||||
explicit GeoIPJSON( const QString& attribute = QString() );
|
||||
|
||||
virtual RegionZonePair processReply( const QByteArray& );
|
||||
virtual RegionZonePair processReply( const QByteArray& ) override;
|
||||
virtual QString rawReply(const QByteArray & ) override;
|
||||
} ;
|
||||
|
||||
} // namespace
|
||||
#endif
|
@ -19,9 +19,10 @@
|
||||
#include "GeoIPTests.h"
|
||||
|
||||
#include "GeoIPJSON.h"
|
||||
#ifdef HAVE_XML
|
||||
#ifdef QT_XML_LIB
|
||||
#include "GeoIPXML.h"
|
||||
#endif
|
||||
#include "Handler.h"
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
@ -31,6 +32,8 @@
|
||||
|
||||
QTEST_GUILESS_MAIN( GeoIPTests )
|
||||
|
||||
using namespace CalamaresUtils::GeoIP;
|
||||
|
||||
GeoIPTests::GeoIPTests()
|
||||
{
|
||||
}
|
||||
@ -118,7 +121,7 @@ static const char xml_data_ubiquity[] =
|
||||
void
|
||||
GeoIPTests::testXML()
|
||||
{
|
||||
#ifdef HAVE_XML
|
||||
#ifdef QT_XML_LIB
|
||||
GeoIPXML handler;
|
||||
auto tz = handler.processReply( xml_data_ubiquity );
|
||||
|
||||
@ -133,7 +136,7 @@ GeoIPTests::testXML2()
|
||||
static const char data[] =
|
||||
"<Response><TimeZone>America/North Dakota/Beulah</TimeZone></Response>"; // With a space!
|
||||
|
||||
#ifdef HAVE_XML
|
||||
#ifdef QT_XML_LIB
|
||||
GeoIPXML handler;
|
||||
auto tz = handler.processReply( data );
|
||||
|
||||
@ -145,7 +148,7 @@ GeoIPTests::testXML2()
|
||||
|
||||
void GeoIPTests::testXMLalt()
|
||||
{
|
||||
#ifdef HAVE_XML
|
||||
#ifdef QT_XML_LIB
|
||||
GeoIPXML handler( "ZT" );
|
||||
|
||||
auto tz = handler.processReply( "<A><B/><C><ZT>Moon/Dark_side</ZT></C></A>" );
|
||||
@ -157,7 +160,7 @@ void GeoIPTests::testXMLalt()
|
||||
void
|
||||
GeoIPTests::testXMLbad()
|
||||
{
|
||||
#ifdef HAVE_XML
|
||||
#ifdef QT_XML_LIB
|
||||
GeoIPXML handler;
|
||||
auto tz = handler.processReply( "{time_zone: \"Europe/Paris\"}" );
|
||||
QCOMPARE( tz.first, QString() );
|
||||
@ -172,24 +175,25 @@ GeoIPTests::testXMLbad()
|
||||
|
||||
void GeoIPTests::testSplitTZ()
|
||||
{
|
||||
auto tz = GeoIP::splitTZString( QStringLiteral("Moon/Dark_side") );
|
||||
using namespace CalamaresUtils::GeoIP;
|
||||
auto tz = splitTZString( QStringLiteral("Moon/Dark_side") );
|
||||
QCOMPARE( tz.first, QStringLiteral("Moon") );
|
||||
QCOMPARE( tz.second, QStringLiteral("Dark_side") );
|
||||
|
||||
// Some providers return weirdly escaped data
|
||||
tz = GeoIP::splitTZString( QStringLiteral("America\\/NewYork") );
|
||||
tz = splitTZString( QStringLiteral("America\\/NewYork") );
|
||||
QCOMPARE( tz.first, QStringLiteral("America") );
|
||||
QCOMPARE( tz.second, QStringLiteral("NewYork") ); // That's not actually the zone name
|
||||
|
||||
// Check that bogus data fails
|
||||
tz = GeoIP::splitTZString( QString() );
|
||||
tz = splitTZString( QString() );
|
||||
QCOMPARE( tz.first, QString() );
|
||||
|
||||
tz = GeoIP::splitTZString( QStringLiteral("America.NewYork") );
|
||||
tz = splitTZString( QStringLiteral("America.NewYork") );
|
||||
QCOMPARE( tz.first, QString() );
|
||||
|
||||
// Check that three-level is split properly and space is replaced
|
||||
tz = GeoIP::splitTZString( QStringLiteral("America/North Dakota/Beulah") );
|
||||
tz = splitTZString( QStringLiteral("America/North Dakota/Beulah") );
|
||||
QCOMPARE( tz.first, QStringLiteral("America") );
|
||||
QCOMPARE( tz.second, QStringLiteral("North_Dakota/Beulah") );
|
||||
}
|
||||
@ -216,14 +220,18 @@ synchronous_get( const char* urlstring )
|
||||
#define CHECK_GET(t, selector, url) \
|
||||
{ \
|
||||
auto tz = GeoIP##t( selector ).processReply( synchronous_get( url ) ); \
|
||||
qDebug() << tz; \
|
||||
QCOMPARE( default_tz, tz ); \
|
||||
auto tz2 = CalamaresUtils::GeoIP::Handler( ""#t, url, selector ).get(); \
|
||||
qDebug() << tz2; \
|
||||
QCOMPARE( default_tz, tz2 ); \
|
||||
}
|
||||
|
||||
void GeoIPTests::testGet()
|
||||
{
|
||||
if ( !QProcessEnvironment::systemEnvironment().contains( QStringLiteral("TEST_HTTP_GET") ) )
|
||||
{
|
||||
qDebug() << "Skipping HTTP GET tests";
|
||||
qDebug() << "Skipping HTTP GET tests, set TEST_HTTP_GET environment variable to enable";
|
||||
return;
|
||||
}
|
||||
|
||||
@ -241,15 +249,12 @@ void GeoIPTests::testGet()
|
||||
// the TZ data is the same as the default_tz; this is fragile if the
|
||||
// services don't agree on the location of where the test is run.
|
||||
CHECK_GET( JSON, QString(), "https://geoip.kde.org/v1/calamares" ) // Check it's consistent
|
||||
CHECK_GET( JSON, QString(), "http://freegeoip.net/json/" ) // Original FreeGeoIP service
|
||||
CHECK_GET( JSON, QStringLiteral("timezone"), "https://ipapi.co/json" ) // Different JSON
|
||||
CHECK_GET( JSON, QStringLiteral("timezone"), "http://ip-api.com/json" )
|
||||
|
||||
CHECK_GET( JSON, QStringLiteral("location.time_zone"), "http://geoip.nekudo.com/api/" ) // 2-level JSON
|
||||
|
||||
CHECK_GET( JSON, QStringLiteral("Location.TimeZone"), "https://geoip.kde.org/debug" ) // 2-level JSON
|
||||
|
||||
#ifdef HAVE_XML
|
||||
#ifdef QT_XML_LIB
|
||||
CHECK_GET( XML, QString(), "http://geoip.ubuntu.com/lookup" ) // Ubiquity's XML format
|
||||
CHECK_GET( XML, QString(), "https://geoip.kde.org/v1/ubiquity" ) // Temporary KDE service
|
||||
#endif
|
@ -23,38 +23,68 @@
|
||||
#include <QNetworkReply>
|
||||
#include <QtXml/QDomDocument>
|
||||
|
||||
namespace CalamaresUtils::GeoIP
|
||||
{
|
||||
|
||||
GeoIPXML::GeoIPXML( const QString& element )
|
||||
: GeoIP( element.isEmpty() ? QStringLiteral( "TimeZone" ) : element )
|
||||
: Interface( element.isEmpty() ? QStringLiteral( "TimeZone" ) : element )
|
||||
{
|
||||
}
|
||||
|
||||
GeoIP::RegionZonePair
|
||||
GeoIPXML::processReply( const QByteArray& data )
|
||||
static QStringList
|
||||
getElementTexts( const QByteArray& data, const QString& tag )
|
||||
{
|
||||
QStringList elements;
|
||||
|
||||
QString domError;
|
||||
int errorLine, errorColumn;
|
||||
|
||||
QDomDocument doc;
|
||||
if ( doc.setContent( data, false, &domError, &errorLine, &errorColumn ) )
|
||||
{
|
||||
const auto tzElements = doc.elementsByTagName( m_element );
|
||||
const auto tzElements = doc.elementsByTagName( tag );
|
||||
cDebug() << "GeoIP found" << tzElements.length() << "elements";
|
||||
for ( int it = 0; it < tzElements.length(); ++it )
|
||||
{
|
||||
auto e = tzElements.at(it).toElement();
|
||||
auto tz = splitTZString( e.text() );
|
||||
if ( !tz.first.isEmpty() )
|
||||
return tz;
|
||||
auto e_text = e.text();
|
||||
if ( !e_text.isEmpty() )
|
||||
elements.append( e_text );
|
||||
}
|
||||
|
||||
// None of them valid
|
||||
cWarning() << "GeopIP XML had no recognizable timezone";
|
||||
return qMakePair( QString(), QString() );
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "GeoIP XML data error:" << domError << "(line" << errorLine << errorColumn << ')';
|
||||
}
|
||||
|
||||
return qMakePair( QString(), QString() );
|
||||
if ( elements.count() < 1 )
|
||||
cWarning() << "GeopIP XML had no non-empty elements" << tag;
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
GeoIPXML::rawReply( const QByteArray& data )
|
||||
{
|
||||
for ( const auto& e : getElementTexts( data, m_element ) )
|
||||
if ( !e.isEmpty() )
|
||||
return e;
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
GeoIP::RegionZonePair
|
||||
GeoIPXML::processReply( const QByteArray& data )
|
||||
{
|
||||
for ( const auto& e : getElementTexts( data, m_element ) )
|
||||
{
|
||||
auto tz = splitTZString( e );
|
||||
if ( !tz.first.isEmpty() )
|
||||
return tz;
|
||||
}
|
||||
|
||||
return RegionZonePair();
|
||||
}
|
||||
|
||||
} // namespace
|
@ -1,6 +1,6 @@
|
||||
/* === This file is part of Calamares - <http://github.com/calamares> ===
|
||||
*
|
||||
* Copyright 2018, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2018-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
|
||||
@ -16,19 +16,23 @@
|
||||
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GEOIPXML_H
|
||||
#define GEOIPXML_H
|
||||
#ifndef GEOIP_GEOIPXML_H
|
||||
#define GEOIP_GEOIPXML_H
|
||||
|
||||
#include "GeoIP.h"
|
||||
#include "Interface.h"
|
||||
|
||||
namespace CalamaresUtils::GeoIP
|
||||
{
|
||||
/** @brief GeoIP lookup with XML data
|
||||
*
|
||||
* The data is assumed to be in XML format with a
|
||||
* <Response><TimeZone></TimeZone></Response>
|
||||
* element, which contains the text (string) for the region/zone. This
|
||||
* format is expected by, e.g. the Ubiquity installer.
|
||||
*
|
||||
* @note This class is an implementation detail.
|
||||
*/
|
||||
class GeoIPXML : public GeoIP
|
||||
class GeoIPXML : public Interface
|
||||
{
|
||||
public:
|
||||
/** @brief Configure the element tag which is selected.
|
||||
@ -38,7 +42,9 @@ public:
|
||||
*/
|
||||
explicit GeoIPXML( const QString& element = QString() );
|
||||
|
||||
virtual RegionZonePair processReply( const QByteArray& );
|
||||
virtual RegionZonePair processReply( const QByteArray& ) override;
|
||||
virtual QString rawReply(const QByteArray & ) override;
|
||||
} ;
|
||||
|
||||
} // namespace
|
||||
#endif
|
183
src/libcalamares/geoip/Handler.cpp
Normal file
183
src/libcalamares/geoip/Handler.cpp
Normal file
@ -0,0 +1,183 @@
|
||||
/* === This file is part of Calamares - <http://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 "Handler.h"
|
||||
|
||||
#include "GeoIPJSON.h"
|
||||
#if defined(QT_XML_LIB)
|
||||
#include "GeoIPXML.h"
|
||||
#endif
|
||||
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/NamedEnum.h"
|
||||
#include "utils/Variant.h"
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include <memory>
|
||||
|
||||
static const NamedEnumTable< CalamaresUtils::GeoIP::Handler::Type >&
|
||||
handlerTypes()
|
||||
{
|
||||
using Type = CalamaresUtils::GeoIP::Handler::Type;
|
||||
|
||||
static const NamedEnumTable<Type> names{
|
||||
{ QStringLiteral( "none" ), Type::None},
|
||||
{ QStringLiteral( "json" ), Type::JSON},
|
||||
{ QStringLiteral( "xml" ), Type::XML}
|
||||
};
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
namespace CalamaresUtils::GeoIP
|
||||
{
|
||||
|
||||
Handler::Handler()
|
||||
: m_type( Type::None )
|
||||
{
|
||||
}
|
||||
|
||||
Handler::Handler( const QString& implementation, const QString& url, const QString& selector )
|
||||
: m_type( Type::None )
|
||||
, m_url( url )
|
||||
, m_selector( selector )
|
||||
{
|
||||
bool ok = false;
|
||||
m_type = handlerTypes().find( implementation, ok );
|
||||
#if !defined(QT_XML_LIB)
|
||||
if ( m_type == Type::XML )
|
||||
{
|
||||
m_type = Type::None;
|
||||
cWarning() << "GeoIP style XML is not supported in this version of Calamares.";
|
||||
}
|
||||
#endif
|
||||
if ( !ok )
|
||||
{
|
||||
cWarning() << "GeoIP Style" << implementation << "is not recognized.";
|
||||
}
|
||||
}
|
||||
|
||||
Handler::~Handler()
|
||||
{
|
||||
}
|
||||
|
||||
static QByteArray
|
||||
synchronous_get( const QString& urlstring )
|
||||
{
|
||||
QUrl url( urlstring );
|
||||
QNetworkAccessManager manager;
|
||||
QEventLoop loop;
|
||||
|
||||
QObject::connect( &manager, &QNetworkAccessManager::finished, &loop, &QEventLoop::quit );
|
||||
|
||||
QNetworkRequest request( url );
|
||||
QNetworkReply* reply = manager.get( request );
|
||||
loop.exec();
|
||||
reply->deleteLater();
|
||||
return reply->readAll();
|
||||
}
|
||||
|
||||
static std::unique_ptr< Interface >
|
||||
create_interface( Handler::Type t, const QString& selector )
|
||||
{
|
||||
switch( t )
|
||||
{
|
||||
case Handler::Type::None:
|
||||
return nullptr;
|
||||
case Handler::Type::JSON:
|
||||
return std::make_unique< GeoIPJSON >( selector );
|
||||
case Handler::Type::XML:
|
||||
#if defined(QT_XML_LIB)
|
||||
return std::make_unique< GeoIPXML >( selector );
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
default: // there are no others
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static RegionZonePair
|
||||
do_query( Handler::Type type, const QString& url, const QString& selector )
|
||||
{
|
||||
const auto interface = create_interface( type, selector );
|
||||
if ( !interface )
|
||||
return RegionZonePair();
|
||||
|
||||
return interface->processReply( synchronous_get( url ) );
|
||||
}
|
||||
|
||||
static QString
|
||||
do_raw_query( Handler::Type type, const QString& url, const QString& selector )
|
||||
{
|
||||
const auto interface = create_interface( type, selector );
|
||||
if ( !interface )
|
||||
return QString();
|
||||
|
||||
return interface->rawReply( synchronous_get( url ) );
|
||||
}
|
||||
|
||||
RegionZonePair
|
||||
Handler::get() const
|
||||
{
|
||||
if ( !isValid() )
|
||||
return RegionZonePair();
|
||||
return do_query( m_type, m_url, m_selector );
|
||||
}
|
||||
|
||||
|
||||
QFuture< RegionZonePair >
|
||||
Handler::query() const
|
||||
{
|
||||
Handler::Type type = m_type;
|
||||
QString url = m_url;
|
||||
QString selector = m_selector;
|
||||
|
||||
return QtConcurrent::run( [=]
|
||||
{
|
||||
return do_query( type, url, selector );
|
||||
} );
|
||||
}
|
||||
|
||||
QString
|
||||
Handler::getRaw() const
|
||||
{
|
||||
if ( !isValid() )
|
||||
return QString();
|
||||
return do_raw_query( m_type, m_url, m_selector );
|
||||
}
|
||||
|
||||
|
||||
QFuture< QString >
|
||||
Handler::queryRaw() const
|
||||
{
|
||||
Handler::Type type = m_type;
|
||||
QString url = m_url;
|
||||
QString selector = m_selector;
|
||||
|
||||
return QtConcurrent::run( [=]
|
||||
{
|
||||
return do_raw_query( type, url, selector );
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
91
src/libcalamares/geoip/Handler.h
Normal file
91
src/libcalamares/geoip/Handler.h
Normal file
@ -0,0 +1,91 @@
|
||||
/* === This file is part of Calamares - <http://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 GEOIP_HANDLER_H
|
||||
#define GEOIP_HANDLER_H
|
||||
|
||||
#include "Interface.h"
|
||||
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
#include <QString>
|
||||
#include <QVariantMap>
|
||||
|
||||
namespace CalamaresUtils {}
|
||||
namespace CalamaresUtils::GeoIP
|
||||
{
|
||||
|
||||
/** @brief Handle one complete GeoIP lookup.
|
||||
*
|
||||
* This class handles one complete GeoIP lookup. Create it with
|
||||
* suitable configuration values, then call get(). This is a
|
||||
* synchronous API and will return an invalid zone pair on
|
||||
* error or if the configuration is not understood. For an
|
||||
* async API, use query().
|
||||
*/
|
||||
class DLLEXPORT Handler
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
None,
|
||||
JSON,
|
||||
XML
|
||||
} ;
|
||||
|
||||
/** @brief An unconfigured handler; this always returns errors. */
|
||||
Handler();
|
||||
/** @brief A handler for a specific GeoIP source.
|
||||
*
|
||||
* The @p implementation name selects an implementation; currently JSON and XML
|
||||
* are supported. The @p url is retrieved by query() and then the @p selector
|
||||
* is used to select something from the data returned by the @url.
|
||||
*/
|
||||
Handler( const QString& implementation, const QString& url, const QString& selector );
|
||||
|
||||
~Handler();
|
||||
|
||||
/** @brief Synchronously get the GeoIP result.
|
||||
*
|
||||
* If the Handler is valid, then do the actual fetching and interpretation
|
||||
* of data and return the result. An invalid Handler will return an
|
||||
* invalid (empty) result.
|
||||
*/
|
||||
RegionZonePair get() const;
|
||||
/// @brief Like get, but don't interpret the contents
|
||||
QString getRaw() const;
|
||||
|
||||
/** @brief Asynchronously get the GeoIP result.
|
||||
*
|
||||
* See get() for the return value.
|
||||
*/
|
||||
QFuture< RegionZonePair > query() const;
|
||||
/// @brief Like query, but don't interpret the contents
|
||||
QFuture< QString > queryRaw() const;
|
||||
|
||||
bool isValid() const { return m_type != Type::None; }
|
||||
Type type() const { return m_type; }
|
||||
|
||||
private:
|
||||
Type m_type;
|
||||
const QString m_url;
|
||||
const QString m_selector;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
@ -16,21 +16,24 @@
|
||||
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "GeoIP.h"
|
||||
#include "Interface.h"
|
||||
|
||||
#include "utils/Logger.h"
|
||||
|
||||
GeoIP::GeoIP(const QString& e)
|
||||
namespace CalamaresUtils::GeoIP
|
||||
{
|
||||
|
||||
Interface::Interface(const QString& e)
|
||||
: m_element( e )
|
||||
{
|
||||
}
|
||||
|
||||
GeoIP::~GeoIP()
|
||||
Interface::~Interface()
|
||||
{
|
||||
}
|
||||
|
||||
GeoIP::RegionZonePair
|
||||
GeoIP::splitTZString( const QString& tz )
|
||||
RegionZonePair
|
||||
splitTZString( const QString& tz )
|
||||
{
|
||||
QString timezoneString( tz );
|
||||
timezoneString.remove( '\\' );
|
||||
@ -42,8 +45,10 @@ GeoIP::splitTZString( const QString& tz )
|
||||
cDebug() << "GeoIP reporting" << timezoneString;
|
||||
QString region = tzParts.takeFirst();
|
||||
QString zone = tzParts.join( '/' );
|
||||
return qMakePair( region, zone );
|
||||
return RegionZonePair( region, zone );
|
||||
}
|
||||
|
||||
return qMakePair( QString(), QString() );
|
||||
return RegionZonePair( QString(), QString() );
|
||||
}
|
||||
|
||||
} // namespace
|
98
src/libcalamares/geoip/Interface.h
Normal file
98
src/libcalamares/geoip/Interface.h
Normal file
@ -0,0 +1,98 @@
|
||||
/* === This file is part of Calamares - <http://github.com/calamares> ===
|
||||
*
|
||||
* Copyright 2018-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 GEOIP_INTERFACE_H
|
||||
#define GEOIP_INTERFACE_H
|
||||
|
||||
#include "DllMacro.h"
|
||||
|
||||
#include <QPair>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
class QByteArray;
|
||||
|
||||
namespace CalamaresUtils {}
|
||||
namespace CalamaresUtils::GeoIP
|
||||
{
|
||||
/** @brief A Region, Zone pair of strings
|
||||
*
|
||||
* A GeoIP lookup returns a timezone, which is represented as a Region,
|
||||
* Zone pair of strings (e.g. "Europe" and "Amsterdam"). Generally,
|
||||
* pasting the strings back together with a "/" is the right thing to
|
||||
* do. The Zone **may** contain a "/" (e.g. "Kentucky/Monticello").
|
||||
*/
|
||||
class DLLEXPORT RegionZonePair : public QPair<QString, QString>
|
||||
{
|
||||
public:
|
||||
/** @brief Construct from an existing pair. */
|
||||
explicit RegionZonePair( const QPair& p ) : QPair(p) { }
|
||||
/** @brief Construct from two strings, like qMakePair(). */
|
||||
RegionZonePair( const QString& region, const QString& zone ) : QPair( region, zone ) { }
|
||||
/** @brief An invalid zone pair (empty strings). */
|
||||
RegionZonePair() : QPair( QString(), QString() ) { }
|
||||
|
||||
bool isValid() const { return !first.isEmpty(); }
|
||||
} ;
|
||||
|
||||
/** @brief Splits a region/zone string into a pair.
|
||||
*
|
||||
* Cleans up the string by removing backslashes (\\)
|
||||
* since some providers return silly-escaped names. Replaces
|
||||
* spaces with _ since some providers return human-readable names.
|
||||
* Splits on the first / in the resulting string, or returns a
|
||||
* pair of empty QStrings if it can't. (e.g. America/North Dakota/Beulah
|
||||
* will return "America", "North_Dakota/Beulah").
|
||||
*/
|
||||
DLLEXPORT RegionZonePair
|
||||
splitTZString( const QString& s );
|
||||
|
||||
/**
|
||||
* @brief Interface for GeoIP retrievers.
|
||||
*
|
||||
* A GeoIP retriever takes a configured URL (from the config file)
|
||||
* and can handle the data returned from its interpretation of that
|
||||
* configured URL, returning a region and zone.
|
||||
*/
|
||||
class DLLEXPORT Interface
|
||||
{
|
||||
public:
|
||||
virtual ~Interface();
|
||||
|
||||
/** @brief Handle a (successful) request by interpreting the data.
|
||||
*
|
||||
* Should return a ( <zone>, <region> ) pair, e.g.
|
||||
* ( "Europe", "Amsterdam" ). This is called **only** if the
|
||||
* request to the fullUrl was successful; the handler
|
||||
* is free to read as much, or as little, data as it
|
||||
* likes. On error, returns a RegionZonePair with empty
|
||||
* strings (e.g. ( "", "" ) ).
|
||||
*/
|
||||
virtual RegionZonePair processReply( const QByteArray& ) = 0;
|
||||
|
||||
/** @brief Get the raw reply data. */
|
||||
virtual QString rawReply( const QByteArray& ) = 0;
|
||||
|
||||
protected:
|
||||
Interface( const QString& e = QString() );
|
||||
|
||||
QString m_element; // string for selecting from data
|
||||
} ;
|
||||
|
||||
} // namespace
|
||||
#endif
|
@ -23,11 +23,12 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "GeoIPJSON.h"
|
||||
#ifdef HAVE_XML
|
||||
#ifdef QT_XML_LIB
|
||||
#include "GeoIPXML.h"
|
||||
#endif
|
||||
|
||||
using std::cerr;
|
||||
using namespace CalamaresUtils::GeoIP;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
@ -37,10 +38,10 @@ int main(int argc, char** argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
GeoIP* handler = nullptr;
|
||||
Interface* handler = nullptr;
|
||||
if ( QStringLiteral( "json" ) == argv[1] )
|
||||
handler = new GeoIPJSON;
|
||||
#ifdef HAVE_XML
|
||||
#ifdef QT_XML_LIB
|
||||
else if ( QStringLiteral( "xml" ) == argv[1] )
|
||||
handler = new GeoIPXML;
|
||||
#endif
|
@ -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>
|
||||
*
|
||||
* Calamares is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -17,12 +17,12 @@
|
||||
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "LocaleLabel.h"
|
||||
#include "Label.h"
|
||||
|
||||
namespace CalamaresUtils
|
||||
namespace CalamaresUtils::Locale
|
||||
{
|
||||
|
||||
LocaleLabel::LocaleLabel()
|
||||
Label::Label()
|
||||
: m_locale( QLocale() )
|
||||
{
|
||||
m_localeId = m_locale.name();
|
||||
@ -30,15 +30,15 @@ LocaleLabel::LocaleLabel()
|
||||
setLabels( QString(), LabelFormat::IfNeededWithCountry );
|
||||
}
|
||||
|
||||
LocaleLabel::LocaleLabel( const QString& locale, LabelFormat format )
|
||||
: m_locale( LocaleLabel::getLocale( locale ) )
|
||||
Label::Label( const QString& locale, LabelFormat format )
|
||||
: m_locale( Label::getLocale( locale ) )
|
||||
, m_localeId( locale )
|
||||
{
|
||||
setLabels( locale, format );
|
||||
}
|
||||
|
||||
void
|
||||
LocaleLabel::setLabels( const QString& locale, LabelFormat format )
|
||||
Label::setLabels( const QString& locale, LabelFormat format )
|
||||
{
|
||||
//: language[name] (country[name])
|
||||
QString longFormat = QObject::tr( "%1 (%2)" );
|
||||
@ -59,7 +59,7 @@ LocaleLabel::setLabels( const QString& locale, LabelFormat format )
|
||||
m_englishLabel = needsCountryName ? longFormat.arg( englishName, QLocale::countryToString( m_locale.country() ) ) : englishName;
|
||||
}
|
||||
|
||||
QLocale LocaleLabel::getLocale( const QString& localeName )
|
||||
QLocale Label::getLocale( const QString& localeName )
|
||||
{
|
||||
if ( localeName.contains( "@latin" ) )
|
||||
{
|
@ -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>
|
||||
*
|
||||
* Calamares is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -17,13 +17,14 @@
|
||||
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef UTILS_LOCALELABEL_H
|
||||
#define UTILS_LOCALELABEL_H
|
||||
#ifndef LOCALE_LABEL_H
|
||||
#define LOCALE_LABEL_H
|
||||
|
||||
#include <QLocale>
|
||||
#include <QString>
|
||||
|
||||
namespace CalamaresUtils
|
||||
namespace CalamaresUtils {}
|
||||
namespace CalamaresUtils::Locale
|
||||
{
|
||||
|
||||
/**
|
||||
@ -33,14 +34,14 @@ namespace CalamaresUtils
|
||||
* translation system) into QLocales, and also into consistent
|
||||
* human-readable text labels.
|
||||
*/
|
||||
class LocaleLabel
|
||||
class Label
|
||||
{
|
||||
public:
|
||||
/** @brief Formatting option for label -- add (country) to label. */
|
||||
enum class LabelFormat { AlwaysWithCountry, IfNeededWithCountry } ;
|
||||
|
||||
/** @brief Empty locale. This uses the system-default locale. */
|
||||
LocaleLabel();
|
||||
Label();
|
||||
|
||||
/** @brief Construct from a locale name.
|
||||
*
|
||||
@ -48,13 +49,13 @@ public:
|
||||
* The @p format determines whether the country name is always present
|
||||
* in the label (human-readable form) or only if needed for disambiguation.
|
||||
*/
|
||||
LocaleLabel( const QString& localeName, LabelFormat format = LabelFormat::IfNeededWithCountry );
|
||||
Label( const QString& localeName, LabelFormat format = LabelFormat::IfNeededWithCountry );
|
||||
|
||||
/** @brief Define a sorting order.
|
||||
*
|
||||
* English (@see isEnglish() -- it means en_US) is sorted at the top.
|
||||
*/
|
||||
bool operator <( const LocaleLabel& other ) const
|
||||
bool operator <( const Label& other ) const
|
||||
{
|
||||
return m_localeId < other.m_localeId;
|
||||
}
|
||||
@ -91,6 +92,18 @@ public:
|
||||
return m_locale.name();
|
||||
}
|
||||
|
||||
/// @brief Convenience accessor to the language part of the locale
|
||||
QLocale::Language language() const
|
||||
{
|
||||
return m_locale.language();
|
||||
}
|
||||
|
||||
/// @brief Convenience accessor to the country part (if any) of the locale
|
||||
QLocale::Country country() const
|
||||
{
|
||||
return m_locale.country();
|
||||
}
|
||||
|
||||
/** @brief Get a Qt locale for the given @p localeName
|
||||
*
|
||||
* This special-cases `sr@latin`, which is used as a translation
|
@ -16,30 +16,37 @@
|
||||
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "LocaleModel.h"
|
||||
#include "LabelModel.h"
|
||||
|
||||
LocaleModel::LocaleModel( const QStringList& locales, QObject* parent )
|
||||
#include "Lookup.h"
|
||||
|
||||
#include "CalamaresVersion.h" // For the list of translations
|
||||
|
||||
namespace CalamaresUtils::Locale
|
||||
{
|
||||
|
||||
LabelModel::LabelModel( const QStringList& locales, QObject* parent )
|
||||
: QAbstractListModel( parent )
|
||||
{
|
||||
Q_ASSERT( locales.count() > 0 );
|
||||
m_locales.reserve( locales.count() );
|
||||
|
||||
for ( const auto& l : locales )
|
||||
m_locales.push_back( CalamaresUtils::LocaleLabel( l ) );
|
||||
m_locales.push_back( Label( l ) );
|
||||
}
|
||||
|
||||
LocaleModel::~LocaleModel()
|
||||
LabelModel::~LabelModel()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
LocaleModel::rowCount( const QModelIndex& ) const
|
||||
LabelModel::rowCount( const QModelIndex& ) const
|
||||
{
|
||||
return m_locales.count();
|
||||
}
|
||||
|
||||
QVariant
|
||||
LocaleModel::data( const QModelIndex& index, int role ) const
|
||||
LabelModel::data( const QModelIndex& index, int role ) const
|
||||
{
|
||||
if ( ( role != LabelRole ) && ( role != EnglishLabelRole ) )
|
||||
return QVariant();
|
||||
@ -59,8 +66,8 @@ LocaleModel::data( const QModelIndex& index, int role ) const
|
||||
}
|
||||
}
|
||||
|
||||
const CalamaresUtils::LocaleLabel&
|
||||
LocaleModel::locale( int row )
|
||||
const Label&
|
||||
LabelModel::locale( int row ) const
|
||||
{
|
||||
if ( ( row < 0 ) || ( row >= m_locales.count() ) )
|
||||
{
|
||||
@ -73,7 +80,7 @@ LocaleModel::locale( int row )
|
||||
}
|
||||
|
||||
int
|
||||
LocaleModel::find( std::function<bool ( const LocaleLabel& )> predicate ) const
|
||||
LabelModel::find( std::function<bool ( const Label& )> predicate ) const
|
||||
{
|
||||
for ( int row = 0; row < m_locales.count() ; ++row )
|
||||
{
|
||||
@ -84,26 +91,40 @@ LocaleModel::find( std::function<bool ( const LocaleLabel& )> predicate ) const
|
||||
}
|
||||
|
||||
int
|
||||
LocaleModel::find( std::function<bool ( const QLocale& )> predicate ) const
|
||||
LabelModel::find( std::function<bool ( const QLocale& )> predicate ) const
|
||||
{
|
||||
return find( [&]( const LocaleLabel& l )
|
||||
return find( [&]( const Label& l )
|
||||
{
|
||||
return predicate( l.locale() );
|
||||
} );
|
||||
}
|
||||
|
||||
int
|
||||
LocaleModel::find( const QLocale& locale ) const
|
||||
LabelModel::find( const QLocale& locale ) const
|
||||
{
|
||||
return find( [&]( const LocaleLabel& l )
|
||||
return find( [&]( const Label& l )
|
||||
{
|
||||
return locale == l.locale();
|
||||
} );
|
||||
}
|
||||
|
||||
void
|
||||
LocaleTwoColumnDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
int
|
||||
LabelModel::find( const QString& countryCode ) const
|
||||
{
|
||||
QStyledItemDelegate::paint( painter, option, index );
|
||||
option.widget->style()->drawItemText( painter, option.rect, Qt::AlignRight | Qt::AlignVCenter, option.palette, false, index.data( LocaleModel::EnglishLabelRole ).toString() );
|
||||
if ( countryCode.length() != 2 )
|
||||
return -1;
|
||||
|
||||
auto c_l = countryData( countryCode );
|
||||
int r = find( [&]( const Label& l ){ return ( l.language() == c_l.second ) && ( l.country() == c_l.first ); } );
|
||||
if ( r >= 0 )
|
||||
return r;
|
||||
return find( [&]( const Label& l ){ return l.language() == c_l.second; } );
|
||||
}
|
||||
|
||||
LabelModel* const availableTranslations()
|
||||
{
|
||||
static LabelModel model( QString( CALAMARES_TRANSLATION_LANGUAGES ).split( ';') );
|
||||
return &model;
|
||||
}
|
||||
|
||||
} // namespace
|
@ -16,28 +16,31 @@
|
||||
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef WELCOME_LOCALEMODEL_H
|
||||
#define WELCOME_LOCALEMODEL_H
|
||||
#ifndef LOCALE_LABELMODEL_H
|
||||
#define LOCALE_LABELMODEL_H
|
||||
|
||||
#include "DllMacro.h"
|
||||
#include "Label.h"
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QVector>
|
||||
|
||||
#include "utils/LocaleLabel.h"
|
||||
|
||||
class LocaleModel : public QAbstractListModel
|
||||
namespace CalamaresUtils {}
|
||||
namespace CalamaresUtils::Locale
|
||||
{
|
||||
|
||||
class DLLEXPORT LabelModel : public QAbstractListModel
|
||||
{
|
||||
public:
|
||||
using LocaleLabel = CalamaresUtils::LocaleLabel;
|
||||
|
||||
enum
|
||||
{
|
||||
LabelRole = Qt::DisplayRole,
|
||||
EnglishLabelRole = Qt::UserRole + 1
|
||||
};
|
||||
|
||||
LocaleModel( const QStringList& locales, QObject* parent = nullptr );
|
||||
virtual ~LocaleModel() override;
|
||||
LabelModel( const QStringList& locales, QObject* parent = nullptr );
|
||||
virtual ~LabelModel() override;
|
||||
|
||||
int rowCount( const QModelIndex& parent ) const override;
|
||||
|
||||
@ -48,26 +51,34 @@ public:
|
||||
* This is the backing data for the model; if @p row is out-of-range,
|
||||
* returns a reference to en_US.
|
||||
*/
|
||||
const LocaleLabel& locale( int row );
|
||||
const Label& locale( int row ) const;
|
||||
|
||||
/** @brief Searches for an item that matches @p predicate
|
||||
*
|
||||
* Returns the row number of the first match, or -1 if there isn't one.
|
||||
*/
|
||||
int find( std::function<bool( const QLocale& )> predicate ) const;
|
||||
int find( std::function<bool( const LocaleLabel& )> predicate ) const;
|
||||
int find( std::function<bool( const Label& )> predicate ) const;
|
||||
/// @brief Looks for an item using the same locale, -1 if there isn't one
|
||||
int find( const QLocale& ) const;
|
||||
/// @brief Looks for an item that best matches the 2-letter country code
|
||||
int find( const QString& countryCode ) const;
|
||||
|
||||
private:
|
||||
QVector< LocaleLabel > m_locales;
|
||||
QVector< Label > m_locales;
|
||||
} ;
|
||||
|
||||
class LocaleTwoColumnDelegate : public QStyledItemDelegate
|
||||
{
|
||||
public:
|
||||
using QStyledItemDelegate::QStyledItemDelegate;
|
||||
|
||||
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const override;
|
||||
} ;
|
||||
/** @brief Returns a model with all available translations.
|
||||
*
|
||||
* The translations are set when Calamares is compiled; the list
|
||||
* is provided by CMake via the CALAMARES_TRANSLATION_LANGUAGES
|
||||
* #define.
|
||||
*
|
||||
* This model is a singleton and can be shared.
|
||||
*
|
||||
* NOTE: While the model is not typed const, it should be. Do not modify.
|
||||
*/
|
||||
DLLEXPORT LabelModel* const availableTranslations();
|
||||
|
||||
} // namespace
|
||||
#endif
|
@ -20,7 +20,7 @@
|
||||
|
||||
#include "CountryData_p.cpp"
|
||||
|
||||
namespace Calamares
|
||||
namespace CalamaresUtils::Locale
|
||||
{
|
||||
|
||||
struct TwoChar
|
||||
@ -35,7 +35,7 @@ struct TwoChar
|
||||
cc2 = code[1].toLatin1();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char cc1;
|
||||
char cc2;
|
||||
};
|
||||
@ -44,7 +44,7 @@ static const CountryData* lookup( TwoChar c )
|
||||
{
|
||||
if ( !c.cc1 )
|
||||
return nullptr;
|
||||
|
||||
|
||||
const CountryData* p = std::find_if(country_data_table, country_data_table + country_data_size,
|
||||
[c=c]( const CountryData& d ){ return (d.cc1 == c.cc1) && (d.cc2 == c.cc2); }
|
||||
);
|
||||
@ -52,7 +52,7 @@ static const CountryData* lookup( TwoChar c )
|
||||
return nullptr;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
QLocale::Country countryForCode(const QString& code)
|
||||
{
|
||||
const CountryData* p = lookup( TwoChar( code ) );
|
||||
|
@ -24,25 +24,26 @@
|
||||
#include <QLocale>
|
||||
#include <QPair>
|
||||
|
||||
namespace Calamares
|
||||
namespace CalamaresUtils {}
|
||||
namespace CalamaresUtils::Locale
|
||||
{
|
||||
/* All the functions in this file do lookups of locale data
|
||||
* based on CLDR tables; these are lookups that you can't (easily)
|
||||
* do with just QLocale (e.g. from 2-letter country code to a likely
|
||||
* locale).
|
||||
*/
|
||||
|
||||
|
||||
/// @brief Map a 2-letter code to a Country, or AnyCountry if not found
|
||||
DLLEXPORT QLocale::Country countryForCode( const QString& code );
|
||||
/** @brief Map a Country to a Language, or AnyLanguage if not found
|
||||
*
|
||||
*
|
||||
* This is a *likely* language for the given country, based on the
|
||||
* CLDR tables. For instance, this maps Belgium to Dutch.
|
||||
*/
|
||||
DLLEXPORT QLocale::Language languageForCountry( QLocale::Country country );
|
||||
/// @brief Map a 2-letter code to a Language, or AnyLanguage if not found
|
||||
DLLEXPORT QLocale::Language languageForCountry( const QString& code );
|
||||
|
||||
|
||||
/// @brief Get both Country and Language for a 2-letter code
|
||||
DLLEXPORT QPair< QLocale::Country, QLocale::Language > countryData( const QString& code );
|
||||
/// @brief Get a likely locale for a 2-letter country code
|
||||
|
@ -8,16 +8,6 @@ endif()
|
||||
|
||||
include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui )
|
||||
|
||||
set( geoip_src GeoIP.cpp GeoIPJSON.cpp )
|
||||
set( geoip_libs )
|
||||
|
||||
find_package(Qt5 COMPONENTS Xml)
|
||||
if( Qt5Xml_FOUND )
|
||||
list( APPEND geoip_src GeoIPXML.cpp )
|
||||
list( APPEND geoip_libs Qt5::Xml )
|
||||
add_definitions( -DHAVE_XML )
|
||||
endif()
|
||||
|
||||
calamares_add_plugin( locale
|
||||
TYPE viewmodule
|
||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||
@ -42,20 +32,6 @@ calamares_add_plugin( locale
|
||||
)
|
||||
|
||||
if( ECM_FOUND AND BUILD_TESTING )
|
||||
ecm_add_test(
|
||||
GeoIPTests.cpp
|
||||
${geoip_src}
|
||||
TEST_NAME
|
||||
geoiptest
|
||||
LINK_LIBRARIES
|
||||
calamaresui
|
||||
Qt5::Network
|
||||
Qt5::Test
|
||||
${geoip_libs}
|
||||
${YAMLCPP_LIBRARY}
|
||||
)
|
||||
calamares_automoc( geoiptest )
|
||||
|
||||
ecm_add_test(
|
||||
Tests.cpp
|
||||
LocaleConfiguration.cpp
|
||||
@ -67,9 +43,3 @@ if( ECM_FOUND AND BUILD_TESTING )
|
||||
)
|
||||
calamares_automoc( localetest )
|
||||
endif()
|
||||
|
||||
if( BUILD_TESTING )
|
||||
add_executable( test_geoip test_geoip.cpp ${geoip_src} )
|
||||
target_link_libraries( test_geoip calamaresui Qt5::Network ${geoip_libs} ${YAMLCPP_LIBRARY} )
|
||||
calamares_automoc( test_geoip )
|
||||
endif()
|
||||
|
@ -1,70 +0,0 @@
|
||||
/* === This file is part of Calamares - <http://github.com/calamares> ===
|
||||
*
|
||||
* Copyright 2018, 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 GEOIP_H
|
||||
#define GEOIP_H
|
||||
|
||||
#include <QPair>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
class QByteArray;
|
||||
|
||||
/**
|
||||
* @brief Interface for GeoIP retrievers.
|
||||
*
|
||||
* A GeoIP retriever takes a configured URL (from the config file)
|
||||
* and can handle the data returned from its interpretation of that
|
||||
* configured URL, returning a region and zone.
|
||||
*/
|
||||
class GeoIP
|
||||
{
|
||||
public:
|
||||
using RegionZonePair = QPair<QString, QString>;
|
||||
|
||||
virtual ~GeoIP();
|
||||
|
||||
/** @brief Handle a (successful) request by interpreting the data.
|
||||
*
|
||||
* Should return a ( <zone>, <region> ) pair, e.g.
|
||||
* ( "Europe", "Amsterdam" ). This is called **only** if the
|
||||
* request to the fullUrl was successful; the handler
|
||||
* is free to read as much, or as little, data as it
|
||||
* likes. On error, returns a RegionZonePair with empty
|
||||
* strings (e.g. ( "", "" ) ).
|
||||
*/
|
||||
virtual RegionZonePair processReply( const QByteArray& ) = 0;
|
||||
|
||||
/** @brief Splits a region/zone string into a pair.
|
||||
*
|
||||
* Cleans up the string by removing backslashes (\\)
|
||||
* since some providers return silly-escaped names. Replaces
|
||||
* spaces with _ since some providers return human-readable names.
|
||||
* Splits on the first / in the resulting string, or returns a
|
||||
* pair of empty QStrings if it can't. (e.g. America/North Dakota/Beulah
|
||||
* will return "America", "North_Dakota/Beulah").
|
||||
*/
|
||||
static RegionZonePair splitTZString( const QString& s );
|
||||
|
||||
protected:
|
||||
GeoIP( const QString& e = QString() );
|
||||
|
||||
QString m_element; // string for selecting from data
|
||||
} ;
|
||||
|
||||
#endif
|
@ -27,8 +27,8 @@
|
||||
#include "LCLocaleDialog.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#include "locale/Label.h"
|
||||
#include "utils/CalamaresUtilsGui.h"
|
||||
#include "utils/LocaleLabel.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Retranslator.h"
|
||||
|
||||
@ -387,10 +387,10 @@ LocalePage::init( const QString& initialRegion,
|
||||
|
||||
std::pair< QString, QString > LocalePage::prettyLocaleStatus( const LocaleConfiguration& lc ) const
|
||||
{
|
||||
using CalamaresUtils::LocaleLabel;
|
||||
using CalamaresUtils::Locale::Label;
|
||||
|
||||
LocaleLabel lang( lc.language(), LocaleLabel::LabelFormat::AlwaysWithCountry );
|
||||
LocaleLabel num( lc.lc_numeric, LocaleLabel::LabelFormat::AlwaysWithCountry );
|
||||
Label lang( lc.language(), Label::LabelFormat::AlwaysWithCountry );
|
||||
Label num( lc.lc_numeric, Label::LabelFormat::AlwaysWithCountry );
|
||||
|
||||
return std::make_pair< QString, QString >(
|
||||
tr( "The system language will be set to %1." ).arg( lang.label() ),
|
||||
|
@ -19,18 +19,15 @@
|
||||
|
||||
#include "LocaleViewStep.h"
|
||||
|
||||
#include "GeoIP.h"
|
||||
#include "GeoIPJSON.h"
|
||||
#ifdef HAVE_XML
|
||||
#include "GeoIPXML.h"
|
||||
#endif
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
#include "LocalePage.h"
|
||||
|
||||
#include "timezonewidget/localeglobal.h"
|
||||
#include "widgets/WaitingWidget.h"
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
|
||||
#include "geoip/Handler.h"
|
||||
|
||||
#include "utils/CalamaresUtilsGui.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Variant.h"
|
||||
@ -116,54 +113,16 @@ LocaleViewStep::setUpPage()
|
||||
void
|
||||
LocaleViewStep::fetchGeoIpTimezone()
|
||||
{
|
||||
QString actualUrl( m_geoipUrl );
|
||||
GeoIP *handler = nullptr;
|
||||
|
||||
if ( m_geoipStyle.isEmpty() || m_geoipStyle == "legacy" )
|
||||
CalamaresUtils::GeoIP::Handler h( m_geoipStyle, m_geoipUrl, m_geoipSelector );
|
||||
if ( h.isValid() )
|
||||
{
|
||||
actualUrl.append( "/json/" );
|
||||
handler = new GeoIPJSON( m_geoipSelector );
|
||||
m_startingTimezone = h.get();
|
||||
if ( !m_startingTimezone.isValid() )
|
||||
cWarning() << "GeoIP lookup at" << m_geoipUrl << "failed.";
|
||||
}
|
||||
else if ( m_geoipStyle == "json" )
|
||||
{
|
||||
handler = new GeoIPJSON( m_geoipSelector );
|
||||
}
|
||||
#if defined(HAVE_XML)
|
||||
else if ( m_geoipStyle == "xml" )
|
||||
{
|
||||
handler = new GeoIPXML( m_geoipSelector );
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
cWarning() << "GeoIP Style" << m_geoipStyle << "is not recognized.";
|
||||
setUpPage();
|
||||
return;
|
||||
}
|
||||
cDebug() << "Fetching GeoIP data from" << actualUrl;
|
||||
|
||||
QNetworkAccessManager *manager = new QNetworkAccessManager( this );
|
||||
connect( manager, &QNetworkAccessManager::finished,
|
||||
[=]( QNetworkReply* reply )
|
||||
{
|
||||
if ( reply->error() == QNetworkReply::NoError )
|
||||
{
|
||||
auto tz = handler->processReply( reply->readAll() );
|
||||
if ( !tz.first.isEmpty() )
|
||||
m_startingTimezone = tz;
|
||||
else
|
||||
cWarning() << "GeoIP lookup at" << reply->url() << "failed.";
|
||||
}
|
||||
delete handler;
|
||||
reply->deleteLater();
|
||||
manager->deleteLater();
|
||||
setUpPage();
|
||||
} );
|
||||
|
||||
QNetworkRequest request;
|
||||
request.setUrl( QUrl::fromUserInput( actualUrl ) );
|
||||
request.setAttribute( QNetworkRequest::FollowRedirectsAttribute, true );
|
||||
manager->get( request );
|
||||
setUpPage();
|
||||
}
|
||||
|
||||
|
||||
@ -251,35 +210,43 @@ LocaleViewStep::onLeave()
|
||||
void
|
||||
LocaleViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
if ( configurationMap.contains( "region" ) &&
|
||||
configurationMap.value( "region" ).type() == QVariant::String &&
|
||||
!configurationMap.value( "region" ).toString().isEmpty() &&
|
||||
configurationMap.contains( "zone" ) &&
|
||||
configurationMap.value( "zone" ).type() == QVariant::String &&
|
||||
!configurationMap.value( "zone" ).toString().isEmpty() )
|
||||
QString region = CalamaresUtils::getString( configurationMap, "region" );
|
||||
QString zone = CalamaresUtils::getString( configurationMap, "zone" );
|
||||
if ( !region.isEmpty() && !zone.isEmpty() )
|
||||
{
|
||||
m_startingTimezone = qMakePair( configurationMap.value( "region" ).toString(),
|
||||
configurationMap.value( "zone" ).toString() );
|
||||
m_startingTimezone = CalamaresUtils::GeoIP::RegionZonePair( region, zone );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_startingTimezone = qMakePair( QStringLiteral( "America" ),
|
||||
QStringLiteral( "New_York" ) );
|
||||
m_startingTimezone = CalamaresUtils::GeoIP::RegionZonePair( QStringLiteral( "America" ), QStringLiteral( "New_York" ) );
|
||||
}
|
||||
|
||||
if ( configurationMap.contains( "localeGenPath" ) &&
|
||||
configurationMap.value( "localeGenPath" ).type() == QVariant::String &&
|
||||
!configurationMap.value( "localeGenPath" ).toString().isEmpty() )
|
||||
{
|
||||
m_localeGenPath = configurationMap.value( "localeGenPath" ).toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_localeGenPath = CalamaresUtils::getString( configurationMap, "localeGenPath" );
|
||||
if ( m_localeGenPath.isEmpty() )
|
||||
m_localeGenPath = QStringLiteral( "/etc/locale.gen" );
|
||||
}
|
||||
|
||||
// Optional
|
||||
m_geoipUrl = CalamaresUtils::getString( configurationMap, "geoipUrl" );
|
||||
m_geoipStyle = CalamaresUtils::getString( configurationMap, "geoipStyle" );
|
||||
m_geoipSelector = CalamaresUtils::getString( configurationMap, "geoipSelector" );
|
||||
bool ok = false;
|
||||
QVariantMap geoip = CalamaresUtils::getSubMap( configurationMap, "geoip", ok );
|
||||
if ( ok )
|
||||
{
|
||||
m_geoipUrl = CalamaresUtils::getString( geoip, "url" );
|
||||
m_geoipStyle = CalamaresUtils::getString( geoip, "style" );
|
||||
m_geoipSelector = CalamaresUtils::getString( geoip, "selector" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Optional
|
||||
m_geoipUrl = CalamaresUtils::getString( configurationMap, "geoipUrl" );
|
||||
m_geoipStyle = CalamaresUtils::getString( configurationMap, "geoipStyle" );
|
||||
m_geoipSelector = CalamaresUtils::getString( configurationMap, "geoipSelector" );
|
||||
|
||||
if ( !m_geoipUrl.isEmpty() && ( m_geoipStyle.isEmpty() || m_geoipStyle == "legacy" ) )
|
||||
{
|
||||
m_geoipStyle = "json";
|
||||
m_geoipUrl.append( "/json/" );
|
||||
}
|
||||
|
||||
if ( !m_geoipUrl.isEmpty() )
|
||||
cWarning() << "Legacy-style GeoIP configuration is deprecated. Use geoip: map.";
|
||||
}
|
||||
}
|
||||
|
@ -20,14 +20,14 @@
|
||||
#ifndef LOCALEVIEWSTEP_H
|
||||
#define LOCALEVIEWSTEP_H
|
||||
|
||||
#include <QObject>
|
||||
#include "geoip/Interface.h"
|
||||
#include "utils/PluginFactory.h"
|
||||
#include "viewpages/ViewStep.h"
|
||||
|
||||
#include <utils/PluginFactory.h>
|
||||
#include <viewpages/ViewStep.h>
|
||||
|
||||
#include <PluginDllMacro.h>
|
||||
#include "PluginDllMacro.h"
|
||||
|
||||
#include <QFutureWatcher>
|
||||
#include <QObject>
|
||||
|
||||
class LocalePage;
|
||||
class WaitingWidget;
|
||||
@ -71,7 +71,7 @@ private:
|
||||
bool m_nextEnabled;
|
||||
QString m_prettyStatus;
|
||||
|
||||
QPair< QString, QString > m_startingTimezone;
|
||||
CalamaresUtils::GeoIP::RegionZonePair m_startingTimezone;
|
||||
QString m_localeGenPath;
|
||||
|
||||
QString m_geoipUrl; // The URL, depening on style might be modified on lookup
|
||||
|
@ -25,21 +25,46 @@ zone: "New_York"
|
||||
# custom path for locale.gen
|
||||
#localeGenPath: "PATH_TO/locale.gen"
|
||||
|
||||
# GeoIP based Language settings:
|
||||
# GeoIP based Language settings: Leave commented out to disable GeoIP.
|
||||
#
|
||||
# GeoIP need an working Internet connection.
|
||||
# GeoIP needs a working Internet connection.
|
||||
# This can be managed from `welcome.conf` by adding
|
||||
# internet to the list of required conditions.
|
||||
#
|
||||
# Leave commented out to disable GeoIP.
|
||||
# The configuration
|
||||
# is in three parts: a *style*, which can be "json" or "xml"
|
||||
# depending on the kind of data returned by the service, and
|
||||
# a *url* where the data is retrieved, and an optional *selector*
|
||||
# to pick the right field out of the returned data (e.g. field
|
||||
# name in JSON or element name in XML).
|
||||
#
|
||||
# An HTTP request is made to *geoipUrl* -- depending on the geoipStyle,
|
||||
# the URL may be modified before use. The request should return
|
||||
# valid data in a suitable format, depending on geoipStyle;
|
||||
# The default selector (when the setting is blank) is picked to
|
||||
# work with existing JSON providers (which use "time_zone") and
|
||||
# Ubiquity's XML providers (which use "TimeZone").
|
||||
#
|
||||
# If the service configured via *url* uses
|
||||
# a different attribute name (e.g. "timezone") in JSON or a
|
||||
# different element tag (e.g. "<Time_Zone>") in XML, set this
|
||||
# string to the name or tag to be used.
|
||||
#
|
||||
# In JSON:
|
||||
# - if the string contains "." characters, this is used as a
|
||||
# multi-level selector, e.g. "a.b" will select the timezone
|
||||
# from data "{a: {b: "Europe/Amsterdam" } }".
|
||||
# - each part of the string split by "." characters is used as
|
||||
# a key into the JSON data.
|
||||
# In XML:
|
||||
# - all elements with the named tag (e.g. all TimeZone) elements
|
||||
# from the document are checked; the first one with non-empty
|
||||
# text value is used.
|
||||
#
|
||||
#
|
||||
# An HTTP(S) request is made to *url*. The request should return
|
||||
# valid data in a suitable format, depending on *style*;
|
||||
# generally this includes a string value with the timezone
|
||||
# in <region>/<zone> format. For services that return data which
|
||||
# does not follow the conventions of "suitable data" described
|
||||
# below, *geoIPSelector* may be used to pick different data.
|
||||
# below, *selector* may be used to pick different data.
|
||||
#
|
||||
# Note that this example URL works, but the service is shutting
|
||||
# down in June 2018.
|
||||
@ -58,40 +83,9 @@ zone: "New_York"
|
||||
# - backslashes are removed
|
||||
# - spaces are replaced with _
|
||||
#
|
||||
#geoipUrl: "freegeoip.net"
|
||||
|
||||
# GeoIP style. Leave commented out for the "legacy" interpretation.
|
||||
# This setting only makes sense if geoipUrl is set, enabliing geoIP.
|
||||
#
|
||||
# Possible values are:
|
||||
# unset same as "legacy"
|
||||
# blank same as "legacy"
|
||||
# "legacy" appends "/json" to geoipUrl, above, and uses JSON format
|
||||
# (which is what freegeoip.net provides there).
|
||||
# "json" URL is not modified, uses JSON format.
|
||||
# "xml" URL is not modified, uses XML format.
|
||||
#
|
||||
# The JSON format is provided by freegeoip.net, but that service is
|
||||
# shutting down in June 2018. There are other providers with the same
|
||||
# format. XML format is provided for Ubiquity.
|
||||
#geoipStyle: "legacy"
|
||||
|
||||
# GeoIP selector. Leave commented out for the default selector
|
||||
# (which depends on the style: JSON uses "time_zone" and XML
|
||||
# uses TimeZone, for the FreeGeoIP-alike and the Ubiquity-alike
|
||||
# respectively). If the service configured via *geoipUrl* uses
|
||||
# a different attribute name (e.g. "timezone") in JSON or a
|
||||
# different element tag (e.g. "<Time_Zone>") in XML, set this
|
||||
# string to the name or tag to be used.
|
||||
#
|
||||
# In JSON:
|
||||
# - if the string contains "." characters, this is used as a
|
||||
# multi-level selector, e.g. "a.b" will select the timezone
|
||||
# from data "{a: {b: "Europe/Amsterdam" } }".
|
||||
# - each part of the string split by "." characters is used as
|
||||
# a key into the JSON data.
|
||||
# In XML:
|
||||
# - all elements with the named tag (e.g. all TimeZone) elements
|
||||
# from the document are checked; the first one with non-empty
|
||||
# text value is used.
|
||||
#geoipSelector: ""
|
||||
# Legacy settings "geoipStyle", "geoipUrl" and "geoipSelector"
|
||||
# in the top-level are still supported, but I'd advise against.
|
||||
geoip:
|
||||
style: "json"
|
||||
url: "https://geoip.kde.org/v1/calamares"
|
||||
selector: "" # leave blank for the default
|
||||
|
@ -27,7 +27,6 @@ calamares_add_plugin( welcome
|
||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||
SOURCES
|
||||
${CHECKER_SOURCES}
|
||||
LocaleModel.cpp
|
||||
WelcomeViewStep.cpp
|
||||
WelcomePage.cpp
|
||||
UI
|
||||
|
@ -21,16 +21,16 @@
|
||||
#include "WelcomePage.h"
|
||||
|
||||
#include "ui_WelcomePage.h"
|
||||
#include "LocaleModel.h"
|
||||
#include "checker/CheckerContainer.h"
|
||||
|
||||
#include "Branding.h"
|
||||
#include "CalamaresVersion.h"
|
||||
#include "Settings.h"
|
||||
#include "ViewManager.h"
|
||||
|
||||
#include "locale/LabelModel.h"
|
||||
#include "modulesystem/ModuleManager.h"
|
||||
#include "utils/CalamaresUtilsGui.h"
|
||||
#include "utils/LocaleLabel.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Retranslator.h"
|
||||
|
||||
@ -131,7 +131,7 @@ WelcomePage::initLanguages()
|
||||
ui->languageWidget->clear();
|
||||
ui->languageWidget->setInsertPolicy( QComboBox::InsertAtBottom );
|
||||
|
||||
m_languages = new LocaleModel( QString( CALAMARES_TRANSLATION_LANGUAGES ).split( ';') );
|
||||
m_languages = CalamaresUtils::Locale::availableTranslations();
|
||||
ui->languageWidget->setModel( m_languages );
|
||||
ui->languageWidget->setItemDelegate( new LocaleTwoColumnDelegate( ui->languageWidget ) );
|
||||
|
||||
@ -257,7 +257,23 @@ WelcomePage::focusInEvent( QFocusEvent* e )
|
||||
e->accept();
|
||||
}
|
||||
|
||||
bool WelcomePage::verdict() const
|
||||
bool
|
||||
WelcomePage::verdict() const
|
||||
{
|
||||
return m_checkingWidget->verdict();
|
||||
}
|
||||
|
||||
void
|
||||
WelcomePage::externallySelectedLanguage( int row )
|
||||
{
|
||||
if ( ( row >= 0 ) && ( row < ui->languageWidget->count() ) )
|
||||
ui->languageWidget->setCurrentIndex( row );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LocaleTwoColumnDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
QStyledItemDelegate::paint( painter, option, index );
|
||||
option.widget->style()->drawItemText( painter, option.rect, Qt::AlignRight | Qt::AlignVCenter, option.palette, false, index.data( CalamaresUtils::Locale::LabelModel::EnglishLabelRole ).toString() );
|
||||
}
|
||||
|
@ -20,6 +20,9 @@
|
||||
#ifndef WELCOMEPAGE_H
|
||||
#define WELCOMEPAGE_H
|
||||
|
||||
#include "locale/LabelModel.h"
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui
|
||||
@ -28,7 +31,6 @@ class WelcomePage;
|
||||
}
|
||||
|
||||
class CheckerContainer;
|
||||
class LocaleModel;
|
||||
|
||||
class WelcomePage : public QWidget
|
||||
{
|
||||
@ -44,6 +46,8 @@ public:
|
||||
/// @brief Results of requirements checking
|
||||
bool verdict() const;
|
||||
|
||||
/// @brief Change the language from an external source.
|
||||
void externallySelectedLanguage( int row );
|
||||
protected:
|
||||
void focusInEvent( QFocusEvent* e ) override; //choose the child widget to focus
|
||||
|
||||
@ -53,7 +57,19 @@ private:
|
||||
|
||||
Ui::WelcomePage* ui;
|
||||
CheckerContainer* m_checkingWidget;
|
||||
LocaleModel *m_languages;
|
||||
CalamaresUtils::Locale::LabelModel *m_languages;
|
||||
};
|
||||
|
||||
/** @brief Delegate to display language information in two columns.
|
||||
*
|
||||
* Displays the native language name and the English language name.
|
||||
*/
|
||||
class LocaleTwoColumnDelegate : public QStyledItemDelegate
|
||||
{
|
||||
public:
|
||||
using QStyledItemDelegate::QStyledItemDelegate;
|
||||
|
||||
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const override;
|
||||
} ;
|
||||
|
||||
#endif // WELCOMEPAGE_H
|
||||
|
@ -22,9 +22,13 @@
|
||||
#include "WelcomePage.h"
|
||||
#include "checker/GeneralRequirements.h"
|
||||
|
||||
#include "geoip/Handler.h"
|
||||
#include "locale/Lookup.h"
|
||||
#include "modulesystem/ModuleManager.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Variant.h"
|
||||
|
||||
#include <QFutureWatcher>
|
||||
#include <QVariant>
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DEFINITION( WelcomeViewStepFactory, registerPlugin<WelcomeViewStep>(); )
|
||||
@ -97,18 +101,9 @@ WelcomeViewStep::jobs() const
|
||||
void
|
||||
WelcomeViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
bool showSupportUrl =
|
||||
configurationMap.contains( "showSupportUrl" ) &&
|
||||
configurationMap.value( "showSupportUrl" ).type() == QVariant::Bool &&
|
||||
configurationMap.value( "showSupportUrl" ).toBool();
|
||||
bool showKnownIssuesUrl =
|
||||
configurationMap.contains( "showKnownIssuesUrl" ) &&
|
||||
configurationMap.value( "showKnownIssuesUrl" ).type() == QVariant::Bool &&
|
||||
configurationMap.value( "showKnownIssuesUrl" ).toBool();
|
||||
bool showReleaseNotesUrl =
|
||||
configurationMap.contains( "showReleaseNotesUrl" ) &&
|
||||
configurationMap.value( "showReleaseNotesUrl" ).type() == QVariant::Bool &&
|
||||
configurationMap.value( "showReleaseNotesUrl" ).toBool();
|
||||
bool showSupportUrl = CalamaresUtils::getBool( configurationMap, "showSupportUrl", false );
|
||||
bool showKnownIssuesUrl = CalamaresUtils::getBool( configurationMap, "showKnownIssuesUrl", false );
|
||||
bool showReleaseNotesUrl = CalamaresUtils::getBool( configurationMap, "showReleaseNotesUrl", false );
|
||||
|
||||
m_widget->setUpLinks( showSupportUrl,
|
||||
showKnownIssuesUrl,
|
||||
@ -120,9 +115,57 @@ WelcomeViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
else
|
||||
cWarning() << "no valid requirements map found in welcome "
|
||||
"module configuration.";
|
||||
|
||||
bool ok = false;
|
||||
QVariantMap geoip = CalamaresUtils::getSubMap( configurationMap, "geoip", ok );
|
||||
if ( ok )
|
||||
{
|
||||
using FWString = QFutureWatcher< QString >;
|
||||
|
||||
auto* handler = new CalamaresUtils::GeoIP::Handler(
|
||||
CalamaresUtils::getString( geoip, "style" ),
|
||||
CalamaresUtils::getString( geoip, "url" ),
|
||||
CalamaresUtils::getString( geoip, "selector" ) );
|
||||
auto* future = new FWString();
|
||||
connect( future, &FWString::finished, [view=this, f=future, h=handler]()
|
||||
{
|
||||
QString countryResult = f->future().result();
|
||||
cDebug() << "GeoIP result for welcome=" << countryResult;
|
||||
view->setCountry( countryResult );
|
||||
f->deleteLater();
|
||||
delete h;
|
||||
} );
|
||||
future->setFuture( handler->queryRaw() );
|
||||
}
|
||||
}
|
||||
|
||||
Calamares::RequirementsList WelcomeViewStep::checkRequirements()
|
||||
Calamares::RequirementsList
|
||||
WelcomeViewStep::checkRequirements()
|
||||
{
|
||||
return m_requirementsChecker->checkRequirements();
|
||||
}
|
||||
|
||||
void
|
||||
WelcomeViewStep::setCountry( const QString& countryCode )
|
||||
{
|
||||
if ( countryCode.length() != 2 )
|
||||
{
|
||||
cDebug() << "Unusable country code" << countryCode;
|
||||
return;
|
||||
}
|
||||
|
||||
auto c_l = CalamaresUtils::Locale::countryData( countryCode );
|
||||
if ( c_l.first == QLocale::Country::AnyCountry )
|
||||
{
|
||||
cDebug() << "Unusable country code" << countryCode;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
int r = CalamaresUtils::Locale::availableTranslations()->find( countryCode );
|
||||
if ( r < 0 )
|
||||
cDebug() << "Unusable country code" << countryCode << "(no suitable translation)";
|
||||
if ( ( r >= 0 ) && m_widget )
|
||||
m_widget->externallySelectedLanguage( r );
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,13 @@ public:
|
||||
|
||||
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
||||
|
||||
/** @brief Sets the country that Calamares is running in.
|
||||
*
|
||||
* This (ideally) sets up language and locale settings that are right for
|
||||
* the given 2-letter country code.
|
||||
*/
|
||||
void setCountry( const QString& );
|
||||
|
||||
Calamares::RequirementsList checkRequirements() override;
|
||||
|
||||
private:
|
||||
|
@ -47,3 +47,16 @@ requirements:
|
||||
# - storage
|
||||
- ram
|
||||
# - root
|
||||
|
||||
# GeoIP checking
|
||||
#
|
||||
# This can be used to pre-select a language based on the country
|
||||
# the user is currently in. It *assumes* that there's internet
|
||||
# connectivity, though. Configuration is like in the locale module,
|
||||
# but remember to use a URL that returns full data **and** to
|
||||
# use a selector that will pick the country, not the timezone.
|
||||
|
||||
geoip:
|
||||
style: "xml"
|
||||
url: "https://geoip.kde.org/v1/ubiquity" # extended XML format
|
||||
selector: "CountryCode" # blank uses default, which is wrong
|
||||
|
Loading…
Reference in New Issue
Block a user