2016-09-27 13:37:18 +00:00
/*
This file is part of Telegram Desktop ,
the official desktop version of Telegram messaging app , see https : //telegram.org
Telegram Desktop 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 .
It 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 .
In addition , as a special exception , the copyright holders give permission
to link the code of portions of this program with the OpenSSL library .
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
2017-01-11 18:31:31 +00:00
Copyright ( c ) 2014 - 2017 John Preston , https : //desktop.telegram.org
2016-09-27 13:37:18 +00:00
*/
# include "history/history_location_manager.h"
# include "mainwidget.h"
2017-04-13 08:27:10 +00:00
# include "lang/lang_keys.h"
2017-03-04 10:23:56 +00:00
# include "platform/platform_specific.h"
2016-09-27 13:37:18 +00:00
2017-02-03 10:17:40 +00:00
namespace {
constexpr auto kCoordPrecision = 8 ;
2017-03-06 08:08:59 +00:00
constexpr auto kMaxHttpRedirects = 5 ;
2017-02-03 10:17:40 +00:00
} // namespace
2016-09-27 13:37:18 +00:00
QString LocationClickHandler : : copyToClipboardContextItemText ( ) const {
return lang ( lng_context_copy_link ) ;
}
void LocationClickHandler : : onClick ( Qt : : MouseButton button ) const {
if ( ! psLaunchMaps ( _coords ) ) {
QDesktopServices : : openUrl ( _text ) ;
}
}
void LocationClickHandler : : setup ( ) {
2017-02-03 10:17:40 +00:00
auto latlon = _coords . latAsString ( ) + ' , ' + _coords . lonAsString ( ) ;
2016-09-27 13:37:18 +00:00
_text = qsl ( " https://maps.google.com/maps?q= " ) + latlon + qsl ( " &ll= " ) + latlon + qsl ( " &z=16 " ) ;
}
namespace {
LocationManager * locationManager = nullptr ;
} // namespace
void initLocationManager ( ) {
if ( ! locationManager ) {
locationManager = new LocationManager ( ) ;
locationManager - > init ( ) ;
}
}
void reinitLocationManager ( ) {
if ( locationManager ) {
locationManager - > reinit ( ) ;
}
}
void deinitLocationManager ( ) {
if ( locationManager ) {
locationManager - > deinit ( ) ;
delete locationManager ;
locationManager = nullptr ;
}
}
void LocationManager : : init ( ) {
if ( manager ) delete manager ;
manager = new QNetworkAccessManager ( ) ;
App : : setProxySettings ( * manager ) ;
connect ( manager , SIGNAL ( authenticationRequired ( QNetworkReply * , QAuthenticator * ) ) , this , SLOT ( onFailed ( QNetworkReply * ) ) ) ;
# ifndef OS_MAC_OLD
connect ( manager , SIGNAL ( sslErrors ( QNetworkReply * , const QList < QSslError > & ) ) , this , SLOT ( onFailed ( QNetworkReply * ) ) ) ;
# endif // OS_MAC_OLD
connect ( manager , SIGNAL ( finished ( QNetworkReply * ) ) , this , SLOT ( onFinished ( QNetworkReply * ) ) ) ;
2016-10-18 11:48:03 +00:00
if ( notLoadedPlaceholder ) {
delete notLoadedPlaceholder - > v ( ) ;
delete notLoadedPlaceholder ;
2016-09-27 13:37:18 +00:00
}
2016-10-18 11:48:03 +00:00
auto data = QImage ( cIntRetinaFactor ( ) , cIntRetinaFactor ( ) , QImage : : Format_ARGB32_Premultiplied ) ;
2016-10-31 12:29:26 +00:00
data . fill ( st : : imageBgTransparent - > c ) ;
2016-10-18 11:48:03 +00:00
data . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
2017-02-21 13:45:56 +00:00
notLoadedPlaceholder = new ImagePtr ( App : : pixmapFromImageInPlace ( std : : move ( data ) ) , " GIF " ) ;
2016-09-27 13:37:18 +00:00
}
void LocationManager : : reinit ( ) {
if ( manager ) App : : setProxySettings ( * manager ) ;
}
void LocationManager : : deinit ( ) {
if ( manager ) {
delete manager ;
manager = nullptr ;
}
2016-10-18 11:48:03 +00:00
if ( notLoadedPlaceholder ) {
delete notLoadedPlaceholder - > v ( ) ;
delete notLoadedPlaceholder ;
notLoadedPlaceholder = nullptr ;
2016-09-27 13:37:18 +00:00
}
dataLoadings . clear ( ) ;
imageLoadings . clear ( ) ;
}
void LocationManager : : getData ( LocationData * data ) {
if ( ! manager ) {
DEBUG_LOG ( ( " App Error: getting image link data without manager init! " ) ) ;
return failed ( data ) ;
}
int32 w = st : : locationSize . width ( ) , h = st : : locationSize . height ( ) ;
int32 zoom = 13 , scale = 1 ;
if ( cScale ( ) = = dbisTwo | | cRetina ( ) ) {
scale = 2 ;
} else {
w = convertScale ( w ) ;
h = convertScale ( h ) ;
}
2017-02-03 10:17:40 +00:00
auto coords = data - > coords . latAsString ( ) + ' , ' + data - > coords . lonAsString ( ) ;
2016-09-27 13:37:18 +00:00
QString url = qsl ( " https://maps.googleapis.com/maps/api/staticmap?center= " ) + coords + qsl ( " &zoom=%1&size=%2x%3&maptype=roadmap&scale=%4&markers=color:red|size:big| " ) . arg ( zoom ) . arg ( w ) . arg ( h ) . arg ( scale ) + coords + qsl ( " &sensor=false " ) ;
QNetworkReply * reply = manager - > get ( QNetworkRequest ( QUrl ( url ) ) ) ;
imageLoadings [ reply ] = data ;
}
void LocationManager : : onFinished ( QNetworkReply * reply ) {
if ( ! manager ) return ;
if ( reply - > error ( ) ! = QNetworkReply : : NoError ) return onFailed ( reply ) ;
QVariant statusCode = reply - > attribute ( QNetworkRequest : : HttpStatusCodeAttribute ) ;
if ( statusCode . isValid ( ) ) {
int status = statusCode . toInt ( ) ;
if ( status = = 301 | | status = = 302 ) {
QString loc = reply - > header ( QNetworkRequest : : LocationHeader ) . toString ( ) ;
if ( ! loc . isEmpty ( ) ) {
QMap < QNetworkReply * , LocationData * > : : iterator i = dataLoadings . find ( reply ) ;
if ( i ! = dataLoadings . cend ( ) ) {
LocationData * d = i . value ( ) ;
if ( serverRedirects . constFind ( d ) = = serverRedirects . cend ( ) ) {
serverRedirects . insert ( d , 1 ) ;
2017-03-06 08:08:59 +00:00
} else if ( + + serverRedirects [ d ] > kMaxHttpRedirects ) {
2016-09-27 13:37:18 +00:00
DEBUG_LOG ( ( " Network Error: Too many HTTP redirects in onFinished() for image link: %1 " ) . arg ( loc ) ) ;
return onFailed ( reply ) ;
}
dataLoadings . erase ( i ) ;
dataLoadings . insert ( manager - > get ( QNetworkRequest ( loc ) ) , d ) ;
return ;
} else if ( ( i = imageLoadings . find ( reply ) ) ! = imageLoadings . cend ( ) ) {
LocationData * d = i . value ( ) ;
if ( serverRedirects . constFind ( d ) = = serverRedirects . cend ( ) ) {
serverRedirects . insert ( d , 1 ) ;
2017-03-06 08:08:59 +00:00
} else if ( + + serverRedirects [ d ] > kMaxHttpRedirects ) {
2016-09-27 13:37:18 +00:00
DEBUG_LOG ( ( " Network Error: Too many HTTP redirects in onFinished() for image link: %1 " ) . arg ( loc ) ) ;
return onFailed ( reply ) ;
}
imageLoadings . erase ( i ) ;
imageLoadings . insert ( manager - > get ( QNetworkRequest ( loc ) ) , d ) ;
return ;
}
}
}
if ( status ! = 200 ) {
DEBUG_LOG ( ( " Network Error: Bad HTTP status received in onFinished() for image link: %1 " ) . arg ( status ) ) ;
return onFailed ( reply ) ;
}
}
LocationData * d = 0 ;
QMap < QNetworkReply * , LocationData * > : : iterator i = dataLoadings . find ( reply ) ;
if ( i ! = dataLoadings . cend ( ) ) {
d = i . value ( ) ;
dataLoadings . erase ( i ) ;
QJsonParseError e ;
QJsonDocument doc = QJsonDocument : : fromJson ( reply - > readAll ( ) , & e ) ;
if ( e . error ! = QJsonParseError : : NoError ) {
DEBUG_LOG ( ( " JSON Error: Bad json received in onFinished() for image link " ) ) ;
return onFailed ( reply ) ;
}
failed ( d ) ;
if ( App : : main ( ) ) App : : main ( ) - > update ( ) ;
} else {
i = imageLoadings . find ( reply ) ;
if ( i ! = imageLoadings . cend ( ) ) {
d = i . value ( ) ;
imageLoadings . erase ( i ) ;
QPixmap thumb ;
QByteArray format ;
QByteArray data ( reply - > readAll ( ) ) ;
{
QBuffer buffer ( & data ) ;
QImageReader reader ( & buffer ) ;
# ifndef OS_MAC_OLD
reader . setAutoTransform ( true ) ;
# endif // OS_MAC_OLD
thumb = QPixmap : : fromImageReader ( & reader , Qt : : ColorOnly ) ;
format = reader . format ( ) ;
thumb . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
if ( format . isEmpty ( ) ) format = QByteArray ( " JPG " ) ;
}
d - > loading = false ;
2016-10-18 11:48:03 +00:00
d - > thumb = thumb . isNull ( ) ? ( * notLoadedPlaceholder ) : ImagePtr ( thumb , format ) ;
2016-09-27 13:37:18 +00:00
serverRedirects . remove ( d ) ;
if ( App : : main ( ) ) App : : main ( ) - > update ( ) ;
}
}
}
void LocationManager : : onFailed ( QNetworkReply * reply ) {
if ( ! manager ) return ;
LocationData * d = 0 ;
QMap < QNetworkReply * , LocationData * > : : iterator i = dataLoadings . find ( reply ) ;
if ( i ! = dataLoadings . cend ( ) ) {
d = i . value ( ) ;
dataLoadings . erase ( i ) ;
} else {
i = imageLoadings . find ( reply ) ;
if ( i ! = imageLoadings . cend ( ) ) {
d = i . value ( ) ;
imageLoadings . erase ( i ) ;
}
}
2017-02-03 10:17:40 +00:00
DEBUG_LOG ( ( " Network Error: failed to get data for image link %1,%2 error %3 " ) . arg ( d ? d - > coords . latAsString ( ) : QString ( ) ) . arg ( d ? d - > coords . lonAsString ( ) : QString ( ) ) . arg ( reply - > errorString ( ) ) ) ;
2016-09-27 13:37:18 +00:00
if ( d ) {
failed ( d ) ;
}
}
void LocationManager : : failed ( LocationData * data ) {
data - > loading = false ;
2016-10-18 11:48:03 +00:00
data - > thumb = * notLoadedPlaceholder ;
2016-09-27 13:37:18 +00:00
serverRedirects . remove ( data ) ;
}
void LocationData : : load ( ) {
if ( ! thumb - > isNull ( ) ) return thumb - > load ( false , false ) ;
if ( loading ) return ;
loading = true ;
if ( locationManager ) {
locationManager - > getData ( this ) ;
}
}