From aac5f990a792e985ca1add517d633d3b3ca0e8b8 Mon Sep 17 00:00:00 2001
From: Joachim Langenbach <joachim.langenbach@engsas.de>
Date: Fri, 27 Jan 2012 19:44:01 +0100
Subject: [PATCH] Added a screenw which displays weather for defined locations on a world map- The map is taken from NASA blue marble project

---
 mythplugins/mythweather/mythweather/location.cpp   |  140 +++++++++++++
 mythplugins/mythweather/mythweather/location.h     |   63 ++++++
 .../mythweather/mythweather/mythweather.pro        |   10 +-
 .../mythweather/mythweather/weatherScreen.cpp      |    4 +-
 .../mythweather/mythweather/weatherUtils.cpp       |    8 +
 .../mythweather/mythweather/worldweatherscreen.cpp |  213 ++++++++++++++++++++
 .../mythweather/mythweather/worldweatherscreen.h   |  101 +++++++++
 .../mythweather/theme/default-wide/weather-ui.xml  |    6 +
 .../mythweather/theme/default/weather-ui.xml       |    6 +
 9 files changed, 547 insertions(+), 4 deletions(-)
 create mode 100644 mythplugins/mythweather/mythweather/location.cpp
 create mode 100644 mythplugins/mythweather/mythweather/location.h
 create mode 100644 mythplugins/mythweather/mythweather/worldweatherscreen.cpp
 create mode 100644 mythplugins/mythweather/mythweather/worldweatherscreen.h

diff --git a/mythplugins/mythweather/mythweather/location.cpp b/mythplugins/mythweather/mythweather/location.cpp
new file mode 100644
index 0000000..25a374f
--- /dev/null
+++ b/mythplugins/mythweather/mythweather/location.cpp
@@ -0,0 +1,140 @@
+/*
+    Copyright (C) 2012 EngSaS - Engineering Solutions and Services Langenbach. All rights reserved.
+
+    This program 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.
+
+    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "location.h"
+
+#include <mythimage.h>
+#include <mythmainwindow.h>
+
+#include <QStringList>
+#include <QPainter>
+#include <QPixmap>
+#include <QFont>
+#include <QFontMetrics>
+
+// Location::Location(qreal latitude, qreal longitude, QString station, QString name)
+// {
+// 	init();
+// // 	myCoordinates = QtMobility::QGeoCoordinate(latitude, longitude);
+// 	myStation = station;
+// 	myName = name;
+// }
+
+void Location::setName(QString name)
+{
+	myName = name;
+}
+
+QString Location::name() const
+{
+	return myName;
+}
+
+// void Location::setCoordinate(QtMobility::QGeoCoordinate coordinates)
+// {
+// 	myCoordinates = coordinates;
+// }
+
+// QString Location::latitude() const
+// {
+// 	// Format: 27° 28' 3.2" S, 153° 1' 40.4" E, 28.1m
+// 	QString myValues = myCoordinates.toString(QtMobility::QGeoCoordinate::DegreesMinutesSecondsWithHemisphere);
+// 	return myValues.split(", ")[0];
+// }
+// 
+// QString Location::longitude() const
+// {
+// // Format: 27° 28' 3.2" S, 153° 1' 40.4" E, 28.1m
+// 	QString myValues = myCoordinates.toString(QtMobility::QGeoCoordinate::DegreesMinutesSecondsWithHemisphere);
+// 	return myValues.split(", ")[1];
+// }
+
+void Location::setCurrentTemperatur(QString temperature)
+{
+	myCurrentTemperature = temperature;
+}
+
+QString Location::currentTemperature() const
+{
+	return myCurrentTemperature;
+}
+
+void Location::setCurrentWeatherIcon(QString icon)
+{
+	if(!icon.startsWith(":/weathermap/") && !icon.startsWith(":"))
+		icon = ":/weathermap/"+ icon;
+	myCurrentWeatherIcon = icon;
+}
+
+QString Location::currentWeatherIcon() const
+{
+	return myCurrentWeatherIcon;
+}
+
+// QtMobility::QGeoCoordinate Location::toCoordinate() const
+// {
+// 	return myCoordinates;
+// }
+
+bool Location::addToMap(MythImage* map, QPoint position)
+{
+	if(!map)
+		return false;
+	
+	// load weather icon
+	MythImage *weatherIcon = GetMythMainWindow()->GetCurrentPainter()->GetFormatImage();
+	weatherIcon->Load(currentWeatherIcon());
+	if(weatherIcon->isNull())
+		weatherIcon->Load("unknown.png");
+	
+	// add the temperature value
+	QFont iconFont;
+	iconFont.setPixelSize(40);
+	QFontMetrics metrics(iconFont);
+	QString text = QObject::tr("%1: %2 C").arg(name()).arg(currentTemperature());
+	int iconWidth = weatherIcon->size().width();
+	if(iconWidth < metrics.width(text))
+		iconWidth = metrics.width(text);
+	
+	QPixmap icon(iconWidth, weatherIcon->size().height() + 1.2 * float(metrics.height()));
+	icon.fill(Qt::transparent);
+	QPainter painter;
+	painter.begin(&icon);
+	painter.setFont(iconFont);
+	painter.setPen(Qt::white);
+	// remember: iconWidth = weatherIcon.width()
+	painter.drawImage((icon.width() - iconWidth)/2, 0, *weatherIcon);
+	painter.drawText(float(icon.width() - metrics.width(text)) / 2.0, weatherIcon->height() + painter.fontMetrics().height(), text);
+	painter.end();
+	
+	icon = icon.scaled(iconWidth, 80, Qt::KeepAspectRatio);
+	// set offset
+	position.setX(position.x() - icon.width()/2);
+	position.setY(position.y() - 40);
+	painter.begin(map);
+	painter.drawPixmap(position.x(), position.y(), icon);
+	painter.end();
+	
+	return true;
+}
+
+void Location::init()
+{
+	myCurrentWeatherIcon = "unknown.png";
+}
diff --git a/mythplugins/mythweather/mythweather/location.h b/mythplugins/mythweather/mythweather/location.h
new file mode 100644
index 0000000..52b1fd8
--- /dev/null
+++ b/mythplugins/mythweather/mythweather/location.h
@@ -0,0 +1,63 @@
+/*
+    Copyright (C) 2012 EngSaS - Engineering Solutions and Services Langenbach. All rights reserved.
+
+    This program 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.
+
+    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#ifndef LOCATION_H
+#define LOCATION_H
+
+// #include <QGeoCoordinate>
+
+class MythImage;
+
+#include <QMetaType>
+
+/**
+	* @brief Represents a location with its coordinates and weather.
+	*/
+class Location
+{
+	public:
+		inline Location(){ init(); }
+// 		Location(qreal latitude, qreal longitude, QString station, QString name);
+		
+		void setName(QString name);
+		QString name() const;
+// 		void setCoordinate(QtMobility::QGeoCoordinate coordinates);
+// 		QString latitude() const;
+// 		QString longitude() const;
+		void setCurrentTemperatur(QString temperature);
+		QString currentTemperature() const;
+		void setCurrentWeatherIcon(QString icon);
+		QString currentWeatherIcon() const;
+// 		QtMobility::QGeoCoordinate toCoordinate() const;
+		bool addToMap(MythImage *map, QPoint position);
+		
+
+	private:
+		void init();
+		
+// 		QtMobility::QGeoCoordinate myCoordinates;
+		QString myName, myStation, myCurrentWeatherIcon;
+		QString myCurrentTemperature;
+};
+
+typedef QList<Location*> Locations;
+
+Q_DECLARE_METATYPE(Location)
+
+#endif // LOCATION_H
diff --git a/mythplugins/mythweather/mythweather/mythweather.pro b/mythplugins/mythweather/mythweather/mythweather.pro
index a96087b..5255354 100644
--- a/mythplugins/mythweather/mythweather/mythweather.pro
+++ b/mythplugins/mythweather/mythweather/mythweather.pro
@@ -3,6 +3,8 @@ include ( ../../settings.pro )
 include ( ../../programs-libs.pro )
 
 QT += sql xml
+CONFIG += mobility
+MOBILITY += location
 
 TEMPLATE = lib
 CONFIG += plugin thread debug
@@ -20,13 +22,15 @@ datafiles.path = $${PREFIX}/share/mythtv/mythweather/
 datafiles.files = weather-screens.xml
 installscripts.path = $${PREFIX}/share/mythtv/mythweather/scripts
 installscripts.files = scripts/*
-INSTALLS += datafiles installscripts
+installmaps.path = $${PREFIX}/share/mythtv/mythweather/bluemarble
+installmaps.files = bluemarble/*.png
+INSTALLS += datafiles installscripts installmaps
 
 # Input
 
 HEADERS += weather.h weatherSource.h sourceManager.h weatherScreen.h dbcheck.h
-HEADERS += weatherSetup.h weatherUtils.h
+HEADERS += weatherSetup.h weatherUtils.h worldweatherscreen.h location.h
 SOURCES += main.cpp weather.cpp weatherSource.cpp sourceManager.cpp weatherScreen.cpp
-SOURCES += dbcheck.cpp weatherSetup.cpp weatherUtils.cpp
+SOURCES += dbcheck.cpp weatherSetup.cpp weatherUtils.cpp worldweatherscreen.cpp location.cpp
 
 include ( ../../libs-targetfix.pro )
diff --git a/mythplugins/mythweather/mythweather/weatherScreen.cpp b/mythplugins/mythweather/mythweather/weatherScreen.cpp
index 9dcbded..0f25c20 100644
--- a/mythplugins/mythweather/mythweather/weatherScreen.cpp
+++ b/mythplugins/mythweather/mythweather/weatherScreen.cpp
@@ -8,10 +8,13 @@ using namespace std;
 // MythWeather headers
 #include "weather.h"
 #include "weatherScreen.h"
+#include "worldweatherscreen.h"
 
 WeatherScreen *WeatherScreen::loadScreen(MythScreenStack *parent,
                                          ScreenListInfo *screenDefn, int id)
 {
+    if(screenDefn->name == "World Weather")
+        return new WorldWeatherScreen(parent, screenDefn, id);
     return new WeatherScreen(parent, screenDefn, id);
 }
 
@@ -24,7 +27,6 @@ WeatherScreen::WeatherScreen(MythScreenStack *parent,
     m_prepared(false),
     m_id(id)
 {
-
     QStringList types = m_screenDefn->dataTypes;
 
     for (int i = 0; i < types.size(); ++i)
diff --git a/mythplugins/mythweather/mythweather/weatherUtils.cpp b/mythplugins/mythweather/mythweather/weatherUtils.cpp
index 3a5ed90..f3e4b64 100644
--- a/mythplugins/mythweather/mythweather/weatherUtils.cpp
+++ b/mythplugins/mythweather/mythweather/weatherUtils.cpp
@@ -8,6 +8,7 @@
 
 // MythWeather headers
 #include "weatherUtils.h"
+#include "worldweatherscreen.h"
 
 static QString getScreenTitle(const QString &screenName)
 {
@@ -33,6 +34,13 @@ ScreenListMap loadScreens()
 {
     ScreenListMap screens;
     QList<QString> searchpath = GetMythUI()->GetThemeSearchPath();
+		
+		ScreenListInfo info = WorldWeatherScreen::info();
+		screens[info.name].multiLoc = false;
+		screens[info.name].name = info.name;
+		screens[info.name].title = info.title;
+		screens[info.name].hasUnits = true;
+		screens[info.name].dataTypes = info.dataTypes;
     
     // Check the theme first if it has its own weather-screens.xml
     
diff --git a/mythplugins/mythweather/mythweather/worldweatherscreen.cpp b/mythplugins/mythweather/mythweather/worldweatherscreen.cpp
new file mode 100644
index 0000000..10e1fc5
--- /dev/null
+++ b/mythplugins/mythweather/mythweather/worldweatherscreen.cpp
@@ -0,0 +1,213 @@
+/*
+    Copyright (C) 2012 EngSaS - Engineering Solutions and Services Langenbach. All rights reserved.
+
+    This program 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.
+
+    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "worldweatherscreen.h"
+
+#include "location.h"
+
+#include <QGeoSearchManager>
+#include <QGeoServiceProvider>
+#include <QGeoCoordinate>
+#include <QGeoAddress>
+
+#include <mythimage.h>
+#include <mythuiimage.h>
+#include <mythmainwindow.h>
+#include <mythdirs.h>
+
+#include <cmath>
+
+using namespace QtMobility;
+
+#include <QDebug>
+
+WorldWeatherScreen::WorldWeatherScreen(MythScreenStack* parent, ScreenListInfo* screenDefn, int id)
+	: WeatherScreen(parent, screenDefn, id)
+{
+	map = NULL;
+	geoProvider = NULL;
+	geoSearch = NULL;
+// 	manager = NULL;
+}
+
+WorldWeatherScreen::~WorldWeatherScreen()
+{
+	if(geoProvider)
+		delete geoProvider;
+}
+
+ScreenListInfo WorldWeatherScreen::info()
+{
+    ScreenListInfo info;
+    info.name = "World Weather";
+    info.title = tr("World Weather");
+    info.hasUnits = false;
+    // seems to be ignored right now
+    info.multiLoc = true;
+		info.dataTypes << "cclocation" << "c1location" << "temp" << "weather" << "weather_icon" << "copyright";
+    return info;
+}
+
+bool WorldWeatherScreen::Create(void )
+{
+    bool foundtheme = false;
+
+    // Load the theme for this screen
+    foundtheme = LoadWindowFromXML("weather-ui.xml", "World Weather", this);
+
+    if (!foundtheme)
+        return false;
+		
+		bool err = false;
+
+    UIUtilE::Assign(this, m_mapImage, "map_image", &err);
+
+		if (err)
+    {
+        VERBOSE(VB_IMPORTANT, "Window World Weather is missing required elements.");
+        return false;
+    }
+
+    if (!prepareScreen(true))
+        return false;
+
+    return true;
+}
+
+void WorldWeatherScreen::newData(QString loc, units_t units, DataMap data)
+{
+	Location *location = new Location();
+	QGeoAddress address;
+	foreach(QString key, data.uniqueKeys()){
+		qDebug() << "WorldWeather::newData: "+ key +": "+ data.value(key);
+		if(key.endsWith("location")){
+			QStringList names = data.value(key).split(", ");
+			if(names.size() < 2)
+				return;
+			location->setName(names[0]);
+			address.setCity(names[0]);
+			address.setCountry(names[1]);
+		}
+		if(key == "temp")
+			location->setCurrentTemperatur(data.value(key));
+		if(key == "weather_icon")
+			location->setCurrentWeatherIcon(data.value(key));
+	}
+	if(address.isEmpty())
+		return;
+	locations << location;
+	QGeoSearchReply *reply = geoSearch->geocode(address);
+	connect(reply, SIGNAL(finished()), this, SLOT(geocodingFinished()));
+}
+
+bool WorldWeatherScreen::prepareScreen(bool checkOnly)
+{
+	// setup provider and scene
+	if(!geoProvider)
+		geoProvider = new QGeoServiceProvider("nokia");
+	if(!geoProvider)
+		return false;
+	if(!geoSearch)
+		geoSearch = geoProvider->searchManager();
+	if(!geoSearch)
+		return false;
+	
+	if(!map || map->isNull())
+		if(!loadMap(SatelliteMapDay))
+			return false;
+
+	// draw empty map
+  m_mapImage->SetImage(map);
+	
+	return true;
+}
+
+void WorldWeatherScreen::geocodingFinished()
+{
+	qDebug() << "geocoding finished";
+	QGeoSearchReply *reply = qobject_cast<QGeoSearchReply*>(sender());
+	if(!reply)
+		return;
+	if(!reply->error() != QGeoSearchReply::NoError){
+		qDebug() << "Network error";
+// 		return;
+	}
+	if(locations.size() < 1)
+		return;
+	
+	Location *location = locations.first();
+	foreach(QGeoPlace place, reply->places()){
+		qDebug() << "trying "+ place.address().city() +" --> "+ location->name();
+		if(place.address().city() == location->name()){
+			qDebug() << "add "+ place.address().city() +" to the map";
+			if(!location->addToMap(map, coordinateToWorldReferencePosition(place.coordinate())))
+				qDebug() << "drawing weathericon has failed";
+			locations.removeFirst();
+			delete location;
+			if(locations.size() < 1)
+				break;
+			location = locations.first();
+		}
+	}
+	
+	emit screenReady(this);
+}
+
+bool WorldWeatherScreen::loadMap(MapType type)
+{
+	if(!map)
+		map = GetMythMainWindow()->GetCurrentPainter()->GetFormatImage();
+	
+	if(type == SatelliteMapNight)
+		map->Load(QString("%1/mythweather/bluemarble/land_ocean_ice_lights_8192.png").arg(GetShareDir()));
+	else
+		map->Load(QString("%1/mythweather/bluemarble/land_shallow_topo_8192.png").arg(GetShareDir()));
+	return !map->isNull();
+}
+
+QPoint WorldWeatherScreen::coordinateToWorldReferencePosition(const QGeoCoordinate& coordinate) const
+{
+	double longitude = coordinate.longitude();
+	double latitude = coordinate.latitude();
+	
+	int x = floor(longitude * mLongitude() + nLongitude());
+	int y = floor(latitude * mLatitude() + nLatitude());
+	
+	return QPoint(x, y);
+}
+
+qreal WorldWeatherScreen::mLongitude() const
+{
+	return qreal(map->size().width())/360.0;
+}
+
+qreal WorldWeatherScreen::mLatitude() const
+{
+	return qreal(map->size().height())/-180.0;
+}
+
+qreal WorldWeatherScreen::nLongitude() const
+{
+	return qreal(map->size().width())/2.0;
+}
+
+qreal WorldWeatherScreen::nLatitude() const
+{
+	return qreal(map->size().height()) + mLatitude() * 90.0;
+}
diff --git a/mythplugins/mythweather/mythweather/worldweatherscreen.h b/mythplugins/mythweather/mythweather/worldweatherscreen.h
new file mode 100644
index 0000000..99e4929
--- /dev/null
+++ b/mythplugins/mythweather/mythweather/worldweatherscreen.h
@@ -0,0 +1,101 @@
+/*
+    Copyright (C) 2012 EngSaS - Engineering Solutions and Services Langenbach. All rights reserved.
+
+    This program 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.
+
+    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#ifndef WORLDWEATHERSCREEN_H
+#define WORLDWEATHERSCREEN_H
+
+#include "weatherScreen.h"
+#include "weatherUtils.h"
+
+class Location;
+
+#include <QGeoCoordinate>
+
+namespace QtMobility{
+	class QGeoServiceProvider;
+	class QGeoSearchManager;
+};
+
+class MythImage;
+
+class WorldWeatherScreen : public WeatherScreen
+{
+    Q_OBJECT
+    public:
+				/**
+					* @brief List of supported maps.
+					*/
+				enum MapType{
+					SatelliteMapDay,		/**< Day map */
+					SatelliteMapNight  	/**< Night map */ 
+				};
+			
+        WorldWeatherScreen(MythScreenStack *parent, ScreenListInfo *screenDefn, int id);
+        ~WorldWeatherScreen();
+		
+        static ScreenListInfo info();
+		
+        bool Create(void);
+				
+    public slots:
+        void newData(QString loc, units_t units, DataMap data);
+				
+    protected:
+        bool prepareScreen(bool checkOnly = false);
+				
+		private slots:
+			void geocodingFinished();
+				
+    private:
+				/**
+					* @brief Loads the map of @p type type.
+					*/
+				bool loadMap(MapType type);
+				/**
+					* @brief Converts the coordinate \a coordinate to a pixel position on the entire map at the maximum zoom level.
+					* 
+					* @note Do not check for longitude between -180 and 180 and latitude between
+					*       -90 and 90, because the map starts over after 180 and -180 and so on.
+					*/
+				QPoint coordinateToWorldReferencePosition(const QtMobility::QGeoCoordinate &coordinate) const;
+				/**
+					* @brief pixel/Deg for longitude.
+					*/
+				qreal mLongitude() const;
+				/**
+					* @brief pixel/deg for latitude.
+					*/
+				qreal mLatitude() const;
+				/**
+					* @brief pixel of greenwich meridian.
+					*/
+				qreal nLongitude() const;
+				/**
+					* @brief pixel of equator.
+					*/
+				qreal nLatitude() const;
+			
+				MythImage *map;
+        MythUIImage *m_mapImage;
+				QtMobility::QGeoServiceProvider *geoProvider;
+				QtMobility::QGeoSearchManager *geoSearch;
+				QList<Location*> locations;
+};
+
+#endif // WORLDWEATHERSCREEN_H
diff --git a/mythplugins/mythweather/theme/default-wide/weather-ui.xml b/mythplugins/mythweather/theme/default-wide/weather-ui.xml
index 5823fc4..174970d 100644
--- a/mythplugins/mythweather/theme/default-wide/weather-ui.xml
+++ b/mythplugins/mythweather/theme/default-wide/weather-ui.xml
@@ -45,6 +45,12 @@
         </textarea>
     </window>
 
+    <window name="World Weather">
+        <imagetype name="map_image">
+            <area>0,65,1280,640</area>
+        </imagetype>
+    </window>
+
     <window name="Current Conditions">
 
         <shape name="background1">
diff --git a/mythplugins/mythweather/theme/default/weather-ui.xml b/mythplugins/mythweather/theme/default/weather-ui.xml
index 4b4a80d..bbc774f 100644
--- a/mythplugins/mythweather/theme/default/weather-ui.xml
+++ b/mythplugins/mythweather/theme/default/weather-ui.xml
@@ -45,6 +45,12 @@
         </textarea>
     </window>
 
+    <window name="World Weather">
+        <imagetype name="map_image">
+            <area>30,80,760,380</area>
+        </imagetype>
+    </window>
+    
     <window name="Current Conditions">
 
         <shape name="background1">
-- 
1.7.3.4

