summaryrefslogtreecommitdiffstats
path: root/kipi-plugins/gpssync
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-19 18:22:05 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-19 18:22:05 +0000
commit57e10fedbcb8c3e8c6590ff0935dbf017ce5587f (patch)
tree3000a7649ca4e40e43f9e7feed963236a0b0f56b /kipi-plugins/gpssync
downloadkipi-plugins-57e10fedbcb8c3e8c6590ff0935dbf017ce5587f.tar.gz
kipi-plugins-57e10fedbcb8c3e8c6590ff0935dbf017ce5587f.zip
Import abandoned KDE3 version of kipi plugins
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/libraries/kipi-plugins@1077221 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kipi-plugins/gpssync')
-rw-r--r--kipi-plugins/gpssync/Makefile.am35
-rw-r--r--kipi-plugins/gpssync/getlonlat.php186
-rw-r--r--kipi-plugins/gpssync/getlonlatalt.php206
-rw-r--r--kipi-plugins/gpssync/gpsbabelbinary.cpp125
-rw-r--r--kipi-plugins/gpssync/gpsbabelbinary.h66
-rw-r--r--kipi-plugins/gpssync/gpsdatacontainer.h78
-rw-r--r--kipi-plugins/gpssync/gpsdataparser.cpp275
-rw-r--r--kipi-plugins/gpssync/gpsdataparser.h74
-rw-r--r--kipi-plugins/gpssync/gpseditdialog.cpp339
-rw-r--r--kipi-plugins/gpssync/gpseditdialog.h79
-rw-r--r--kipi-plugins/gpssync/gpslistviewitem.cpp246
-rw-r--r--kipi-plugins/gpssync/gpslistviewitem.h83
-rw-r--r--kipi-plugins/gpssync/gpsmapwidget.cpp188
-rw-r--r--kipi-plugins/gpssync/gpsmapwidget.h82
-rw-r--r--kipi-plugins/gpssync/gpssyncdialog.cpp548
-rw-r--r--kipi-plugins/gpssync/gpssyncdialog.h87
-rw-r--r--kipi-plugins/gpssync/hi16-action-gpsimagetag.pngbin0 -> 908 bytes
-rw-r--r--kipi-plugins/gpssync/hi32-action-gpsimagetag.pngbin0 -> 2436 bytes
-rw-r--r--kipi-plugins/gpssync/kipiplugin_gpssync.desktop40
-rw-r--r--kipi-plugins/gpssync/kmlexport.cpp523
-rw-r--r--kipi-plugins/gpssync/kmlexport.h195
-rw-r--r--kipi-plugins/gpssync/kmlexportconfig.cpp479
-rw-r--r--kipi-plugins/gpssync/kmlexportconfig.h138
-rw-r--r--kipi-plugins/gpssync/kmlgpsdataparser.cpp141
-rw-r--r--kipi-plugins/gpssync/kmlgpsdataparser.h107
-rw-r--r--kipi-plugins/gpssync/plugin_gpssync.cpp342
-rw-r--r--kipi-plugins/gpssync/plugin_gpssync.h66
27 files changed, 4728 insertions, 0 deletions
diff --git a/kipi-plugins/gpssync/Makefile.am b/kipi-plugins/gpssync/Makefile.am
new file mode 100644
index 0000000..c5fcc64
--- /dev/null
+++ b/kipi-plugins/gpssync/Makefile.am
@@ -0,0 +1,35 @@
+INCLUDES = $(KIPI_PLUGINS_COMMON_INCLUDE) $(LIBKEXIV2_CFLAGS) $(LIBKIPI_CFLAGS) $(all_includes)
+
+METASOURCES = AUTO
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = kipiplugin_gpssync.la
+
+kipiplugin_gpssync_la_DEPENDENCIES = $(LIBKIPI_LIBS_DEP) $(LIBKEXIV2_LIBS_DEP)
+
+# Srcs for the plugin
+kipiplugin_gpssync_la_SOURCES = plugin_gpssync.cpp gpssyncdialog.cpp gpslistviewitem.cpp \
+ gpsbabelbinary.cpp gpsdataparser.cpp gpseditdialog.cpp \
+ gpsmapwidget.cpp kmlexport.cpp kmlexportconfig.cpp \
+ kmlgpsdataparser.cpp
+
+# Libs needed by the plugin
+kipiplugin_gpssync_la_LIBADD = $(LIBKEXIV2_LIBS) -lkipiplugins $(LIBKIPI_LIBS) $(LIB_KHTML) \
+ $(LIB_KPARTS) $(LIB_KIO) $(LIB_KDEUI) $(LIB_KDECORE) $(LIB_QT) \
+ $(LIB_KFILE)
+
+# LD flags for the plugin
+kipiplugin_gpssync_la_LDFLAGS = $(KIPI_PLUGINS_COMMON_LDFLAGS) -module $(KDE_PLUGIN) $(all_libraries)
+
+# Install the desktop file needed to detect the plugin
+kde_services_DATA = kipiplugin_gpssync.desktop
+
+# Icons set for the plugin.
+kipiplugin_gpssyncicondir = $(kde_datadir)/kipiplugin_gpssync/icons
+kipiplugin_gpssyncicon_ICON = AUTO
+
+
+# i18n translation messages
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kipiplugin_gpssync.pot
+
diff --git a/kipi-plugins/gpssync/getlonlat.php b/kipi-plugins/gpssync/getlonlat.php
new file mode 100644
index 0000000..da76386
--- /dev/null
+++ b/kipi-plugins/gpssync/getlonlat.php
@@ -0,0 +1,186 @@
+<?php
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-09-22
+ * Description : a php script to show GPS locator world map
+ * this script is used by GPSSync kipi-plugin.
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * Notes : This script use Google Map API version 2:
+ * http://www.google.com/apis/maps/documentation
+ * This script must be copied to host kipi-plugins
+ * web project page.
+ * This script accept these values from url:
+ * - 'altitude' : picture altitude.
+ * - 'longitude' : picture longitude.
+ * - 'width' : width of map.
+ * - 'height' : height of map.
+ * - 'zoom' : map zoom level.
+ * - 'maptype' : type of map (G_NORMAL_MAP, G_SATELLITE_MAP, G_HYBRID_MAP)
+ * - 'filename' : photo file name as string.
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+?>
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>GPSSync Kipi-plugin Geographical Location Editor</title>
+<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAAy_Vv5rc03ctmYvwfsuTH6RSK29CRGKrdb78LNYpP1_riKtR3zRRxy4unyuWAi2vp7m1isLwuHObXDg"
+type="text/javascript">
+</script>
+<style type="text/css">
+ @import url("http://www.google.com/uds/css/gsearch.css");
+ @import url("http://www.google.com/uds/solutions/localsearch/gmlocalsearch.css");
+</style>
+<script src="http://www.google.com/uds/api?file=uds.js&amp;v=1.0" type="text/javascript"></script>
+<script src="http://www.google.com/uds/solutions/localsearch/gmlocalsearch.js" type="text/javascript"></script>
+
+<style type="text/css">
+ /*<![CDATA[*/
+ body {
+ padding: 0px;
+ margin: 0px;
+ }
+ /*]]>*/
+</style>
+
+<script type="text/javascript">
+
+//<![CDATA[
+function loadMap()
+{
+ var map = new GMap2(document.getElementById("map"));
+ var searchoptions = {
+ suppressInitialResultSelection : true
+ };
+
+ var markeroptions = {
+ autoPan : true,
+ draggable : true,
+<?php
+ $filename = $_GET['filename'];
+ if ($filename != "") echo "title : \"$filename\"";
+?>
+ };
+
+ map.addControl(new GLargeMapControl());
+ map.addControl(new GMapTypeControl());
+ map.addControl(new GScaleControl());
+ map.addControl(new google.maps.LocalSearch(searchoptions), new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(10,20)));
+
+<?php
+ $maptype = $_GET['maptype'];
+ if ($maptype == "") $maptype = "G_NORMAL_MAP";
+
+ echo "map.setCenter(new GLatLng(";
+ echo $_GET['latitude'];
+ echo ", ";
+ echo $_GET['longitude'];
+ echo "), ";
+ echo $_GET['zoom'];
+ echo ", ";
+ echo $maptype;
+ echo ");\n";
+
+ echo "var marker = new GMarker(new GLatLng(";
+ echo $_GET['latitude'];
+ echo ", ";
+ echo $_GET['longitude'];
+ echo "), markeroptions";
+ echo ");\n";
+
+ echo "map.addOverlay(marker)";
+?>
+
+ GEvent.addListener(map, "click",
+ function(overlay, point)
+ {
+ if (point)
+ {
+ marker.setPoint(point);
+ msg = "(lat:" + point.lat() + ", lon:" + point.lng() + ")";
+ window.status=msg;
+ }
+ }
+ );
+
+ GEvent.addListener(marker, "drag",
+ function()
+ {
+ var point = marker.getPoint();
+ msg = "(lat:" + point.lat() + ", lon:" + point.lng() + ")";
+ window.status=msg;
+ }
+ );
+
+ GEvent.addListener(marker, "dragend",
+ function()
+ {
+ var point = marker.getPoint();
+ msg = "(lat:" + point.lat() + ", lon:" + point.lng() + ")";
+ window.status=msg;
+ }
+ );
+
+ GEvent.addListener(map, "zoomend",
+ function(oldLevel, newLevel)
+ {
+ msg = "newZoomLevel:" + newLevel;
+ window.status=msg;
+ }
+ );
+
+ GEvent.addListener(map, "maptypechanged",
+ function()
+ {
+ var myMapType = map.getCurrentMapType();
+ if (myMapType == G_SATELLITE_TYPE) {msg = "newMapType:G_SATELLITE_TYPE";}
+ if (myMapType == G_MAP_TYPE) {msg = "newMapType:G_MAP_TYPE";}
+ if (myMapType == G_HYBRID_TYPE) {msg = "newMapType:G_HYBRID_TYPE";}
+ window.status=msg;
+ }
+ );
+}
+{
+ window.addEventListener("load",
+ function()
+ {
+ loadMap(); // Firefox and standard browsers
+ }
+ , false);
+}
+//]]>
+
+</script>
+</head>
+
+<body onLoad="loadMap()">
+
+<?php
+ echo "<div id=\"map\" ";
+ echo "style=\"width: ";
+ echo $_GET['width'];
+ echo "px; height: ";
+ echo $_GET['height'];
+ echo "px;\">";
+?>
+
+</div>
+</body>
+</html>
diff --git a/kipi-plugins/gpssync/getlonlatalt.php b/kipi-plugins/gpssync/getlonlatalt.php
new file mode 100644
index 0000000..91f2bac
--- /dev/null
+++ b/kipi-plugins/gpssync/getlonlatalt.php
@@ -0,0 +1,206 @@
+<?php
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-09-22
+ * Description : a php script to show GPS locator world map
+ * this script is used by GPSSync kipi-plugin.
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ * Copyright 2008 by Gerhard Kulzer <gerhard at kulzer dot net>
+ *
+ * Notes : This script use Google Map API version 2:
+ * http://www.google.com/apis/maps/documentation
+ * This script must be copied to host kipi-plugins
+ * web project page.
+ * This script accept these values from url:
+ * - 'altitude' : picture altitude.
+ * - 'longitude' : picture longitude.
+ * - 'width' : width of map.
+ * - 'height' : height of map.
+ * - 'zoom' : map zoom level.
+ * - 'maptype' : type of map (G_NORMAL_MAP, G_SATELLITE_MAP, G_HYBRID_MAP)
+ * - 'filename' : photo file name as string.
+
+ * Notes on the service topocoding :
+ * here is how topoGetAltitude behaves:
+ * 1. You call *topoGetAltitude*( lat, lon, action, context, timeout )
+ * 2. As soon as the server sends back the altitude, the asynchronous call
+ * to action(altitude,context) is performed.
+ * Here you can operate with the altitude information. And the context
+ * variable contains any useful data that you also want to pass in,
+ * it can be for example the reference to an element where you want the altitude to be assigned.
+ * So for example you can pass the marker as a context.
+ * Note that you can ommit the context if you don't need it.
+ * 3. If the server response does not arrive (timeout), the asynchronous
+ * call to action(null,context) is performed.
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+?>
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>GPSSync Kipi-plugin Geographical Location Editor</title>
+<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAAy_Vv5rc03ctmYvwfsuTH6RSK29CRGKrdb78LNYpP1_riKtR3zRRxy4unyuWAi2vp7m1isLwuHObXDg"
+type="text/javascript">
+</script>
+<script src="http://www.google.com/uds/api?file=uds.js&amp;v=1.0" type="text/javascript"></script>
+<script src="http://www.google.com/uds/solutions/localsearch/gmlocalsearch.js" type="text/javascript"></script>
+<script type="text/javascript" src="http://topocoding.com/api/getapi_v1.php?key=ILOGFVOBCUOSRHC"></script>
+<style type="text/css">
+ @import url("http://www.google.com/uds/css/gsearch.css");
+ @import url("http://www.google.com/uds/solutions/localsearch/gmlocalsearch.css");
+
+ /*<![CDATA[*/
+ body {
+ padding: 0px;
+ margin: 0px;
+ }
+ /*]]>*/
+</style>
+
+<script type="text/javascript">
+
+//<![CDATA[
+
+function loadMap()
+{
+ var map = new GMap2(document.getElementById("map"));
+ var searchoptions = {
+ suppressInitialResultSelection : true
+ };
+
+ var markeroptions = {
+ autoPan : true,
+ draggable : true,
+<?php
+$topoKey = 'COMBBKMQQYCKMMK';
+include( 'topocoding.inc' );
+
+ // Gets data from URL parameters
+ $filename = $_GET['filename'];
+ if ($filename != "") echo "title : \"$filename\"";
+
+?>
+ };
+
+ map.addControl(new GLargeMapControl());
+ map.addControl(new GMapTypeControl());
+ map.addControl(new GScaleControl());
+ map.addControl(new google.maps.LocalSearch(searchoptions), new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(10,20)));
+
+<?php
+ $maptype = $_GET['maptype'];
+ if ($maptype == "") $maptype = "G_NORMAL_MAP";
+
+ echo "map.setCenter(new GLatLng(";
+ echo $_GET['latitude'];
+ echo ", ";
+ echo $_GET['longitude'];
+ echo "), ";
+ echo $_GET['zoom'];
+ echo ", ";
+ echo $maptype;
+ echo ");\n";
+
+ echo "var marker = new GMarker(new GLatLng(";
+ echo $_GET['latitude'];
+ echo ", ";
+ echo $_GET['longitude'];
+ echo "), markeroptions";
+ echo ");\n";
+ echo "map.addOverlay(marker)";
+?>
+
+ GEvent.addListener(map, "click",
+ function(overlay, point)
+ {
+ if (point)
+ {
+ marker.setPoint(point);
+ topoGetAltitude( point.lat(), point.lng(), function( altitude ) { window.status = "(lat:" + point.lat() + ", lon:" + point.lng() + ", alt:" + altitude + ")" ; } );
+ }
+ }
+ );
+
+ GEvent.addListener(marker, "drag",
+ function()
+ {
+ var point = marker.getPoint();
+ topoGetAltitude( point.lat(), point.lng(), function( altitude ) { window.status = "(lat:" + point.lat() + ", lon:" + point.lng() + ", alt:" + altitude + ")" ; } );
+ }
+ );
+
+ GEvent.addListener(marker, "dragend",
+ function()
+ {
+ var point = marker.getPoint();
+ topoGetAltitude( point.lat(), point.lng(), function( altitude ) { window.status = "(lat:" + point.lat() + ", lon:" + point.lng() + ", alt:" + altitude + ")" ; } );
+ }
+ );
+
+ GEvent.addListener(map, "zoomend",
+ function(oldLevel, newLevel)
+ {
+ msg = "newZoomLevel:" + newLevel;
+ window.status=msg;
+ }
+ );
+
+ GEvent.addListener(map, "maptypechanged",
+ function()
+ {
+ var myMapType = map.getCurrentMapType();
+ if (myMapType == G_SATELLITE_TYPE) {msg = "newMapType:G_SATELLITE_TYPE";}
+ if (myMapType == G_MAP_TYPE) {msg = "newMapType:G_MAP_TYPE";}
+ if (myMapType == G_HYBRID_TYPE) {msg = "newMapType:G_HYBRID_TYPE";}
+ window.status=msg;
+ }
+ );
+}
+{
+ window.addEventListener("load",
+ function()
+ {
+ loadMap(); // Firefox and standard browsers
+ }
+ , false);
+}
+//]]>
+
+</script>
+</head>
+
+<body onLoad="loadMap()">
+<div>
+<?php
+// print_r ( topoGetAltitudes( array( array( 'latitude', 'longitude' ) ) ) );
+?>
+</div>
+<?php
+ echo "<div id=\"map\" ";
+ echo "style=\"width: ";
+ echo $_GET['width'];
+ echo "px; height: ";
+ echo $_GET['height'];
+ echo "px;\">";
+?>
+
+</div>
+</body>
+</html>
diff --git a/kipi-plugins/gpssync/gpsbabelbinary.cpp b/kipi-plugins/gpssync/gpsbabelbinary.cpp
new file mode 100644
index 0000000..5dd6ab2
--- /dev/null
+++ b/kipi-plugins/gpssync/gpsbabelbinary.cpp
@@ -0,0 +1,125 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-09-19
+ * Description : Autodetect gpsbabel binary program and version
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+// KDE includes
+
+#include <kapplication.h>
+#include <kprocess.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kdebug.h>
+
+// Local includes
+
+#include "gpsbabelbinary.h"
+#include "gpsbabelbinary.moc"
+
+namespace KIPIGPSSyncPlugin
+{
+
+class GPSBabelBinaryPriv
+{
+public:
+
+ GPSBabelBinaryPriv()
+ {
+ available = false;
+ version = QString::null;
+ }
+
+ bool available;
+
+ QString version;
+};
+
+GPSBabelBinary::GPSBabelBinary()
+ : QObject()
+{
+ d = new GPSBabelBinaryPriv;
+ checkSystem();
+}
+
+GPSBabelBinary::~GPSBabelBinary()
+{
+ delete d;
+}
+
+void GPSBabelBinary::checkSystem()
+{
+ KProcess process;
+ process.clearArguments();
+ process << path() << "-V";
+
+ connect(&process, SIGNAL(receivedStdout(KProcess *, char*, int)),
+ this, SLOT(slotReadStdoutFromGPSBabel(KProcess*, char*, int)));
+
+ d->available = process.start(KProcess::Block, KProcess::Stdout);
+}
+
+void GPSBabelBinary::slotReadStdoutFromGPSBabel(KProcess*, char* buffer, int buflen)
+{
+ // The gpsbabel output look like this : GPSBabel Version 1.2.5
+ QString headerStarts("GPSBabel Version ");
+
+ QString stdOut = QString::fromLocal8Bit(buffer, buflen);
+ QString firstLine = stdOut.section('\n', 1, 1);
+
+ if (firstLine.startsWith(headerStarts))
+ {
+ d->version = firstLine.remove(0, headerStarts.length());
+ kdDebug( 51001 ) << "Found gpsbabel version: " << version() << endl;
+ }
+}
+
+const char *GPSBabelBinary::path()
+{
+ return "gpsbabel";
+}
+
+bool GPSBabelBinary::isAvailable() const
+{
+ return d->available;
+}
+
+QString GPSBabelBinary::version() const
+{
+ return d->version;
+}
+
+bool GPSBabelBinary::versionIsRight() const
+{
+ if (d->version.isNull() || !isAvailable())
+ return false;
+
+ if (d->version.toFloat() >= minimalVersion().toFloat())
+ return true;
+
+ return false;
+}
+
+QString GPSBabelBinary::minimalVersion() const
+{
+ return QString("1.2.5");
+}
+
+} // namespace KIPIGPSSyncPlugin
diff --git a/kipi-plugins/gpssync/gpsbabelbinary.h b/kipi-plugins/gpssync/gpsbabelbinary.h
new file mode 100644
index 0000000..3dc95ab
--- /dev/null
+++ b/kipi-plugins/gpssync/gpsbabelbinary.h
@@ -0,0 +1,66 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-09-19
+ * Description : Autodetect gpsbabel binary program and version
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+#ifndef GPSBABELBINARY_H
+#define GPSBABELBINARY_H
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qobject.h>
+
+class KProcess;
+
+namespace KIPIGPSSyncPlugin
+{
+
+class GPSBabelBinaryPriv;
+
+class GPSBabelBinary : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ GPSBabelBinary();
+ ~GPSBabelBinary();
+
+ static const char *path();
+ bool isAvailable() const;
+ QString version() const;
+ bool versionIsRight() const;
+ QString minimalVersion() const;
+
+ void checkSystem();
+
+private slots:
+
+ void slotReadStdoutFromGPSBabel(KProcess*, char*, int);
+
+private:
+
+ GPSBabelBinaryPriv *d;
+};
+
+} // namespace KIPIGPSSyncPlugin
+
+#endif // GPSBABELBINARY_H
diff --git a/kipi-plugins/gpssync/gpsdatacontainer.h b/kipi-plugins/gpssync/gpsdatacontainer.h
new file mode 100644
index 0000000..2413950
--- /dev/null
+++ b/kipi-plugins/gpssync/gpsdatacontainer.h
@@ -0,0 +1,78 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-09-19
+ * Description : GPS data container.
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+#ifndef GPSDATACONTAINER_H
+#define GPSDATACONTAINER_H
+
+// Qt includes.
+
+namespace KIPIGPSSyncPlugin
+{
+
+class GPSDataContainer
+{
+public:
+
+ GPSDataContainer(): m_interpolated(false), m_altitude(0.0),
+ m_latitude(0.0), m_longitude(0.0)
+ {};
+
+ GPSDataContainer(double altitude, double latitude,
+ double longitude, bool interpolated)
+ : m_interpolated(interpolated), m_altitude(altitude),
+ m_latitude(latitude), m_longitude(longitude)
+ {};
+
+ ~GPSDataContainer()
+ {};
+
+ GPSDataContainer& operator=(const GPSDataContainer& data)
+ {
+ m_interpolated = data.isInterpolated();
+ m_altitude = data.altitude();
+ m_latitude = data.latitude();
+ m_longitude = data.longitude();
+ return *this;
+ };
+
+ void setInterpolated(bool ite) { m_interpolated = ite; };
+ void setAltitude(double alt) { m_altitude = alt; };
+ void setLatitude(double lat) { m_latitude = lat; };
+ void setLongitude(double lng) { m_longitude = lng; };
+
+ bool isInterpolated() const { return m_interpolated; };
+ double altitude() const { return m_altitude; };
+ double latitude() const { return m_latitude; };
+ double longitude() const { return m_longitude; };
+
+private:
+
+ bool m_interpolated;
+
+ double m_altitude;
+ double m_latitude;
+ double m_longitude;
+};
+
+} // NameSpace KIPIGPSSyncPlugin
+
+#endif // GPSDATACONTAINER_H
diff --git a/kipi-plugins/gpssync/gpsdataparser.cpp b/kipi-plugins/gpssync/gpsdataparser.cpp
new file mode 100644
index 0000000..2124f1d
--- /dev/null
+++ b/kipi-plugins/gpssync/gpsdataparser.cpp
@@ -0,0 +1,275 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-09-19
+ * Description : GPS data file parser.
+ * (GPX format http://www.topografix.com/gpx.asp).
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+// C++ includes.
+
+#include <cmath>
+#include <cstdlib>
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qfile.h>
+#include <qdom.h>
+#include <qtextstream.h>
+
+// KDE includes.
+
+#include <kdebug.h>
+
+// Local includes.
+
+#include "gpsdataparser.h"
+
+namespace KIPIGPSSyncPlugin
+{
+
+GPSDataParser::GPSDataParser()
+{
+ clear();
+}
+
+void GPSDataParser::clear()
+{
+ m_GPSDataMap.clear();
+}
+
+int GPSDataParser::numPoints()
+{
+ return m_GPSDataMap.count();
+}
+
+bool GPSDataParser::matchDate(const QDateTime& photoDateTime, int maxGapTime, int timeZone,
+ bool interpolate, int interpolationDstTime,
+ GPSDataContainer& gpsData)
+{
+ // GPS device are sync in time by satelite using GMT time.
+ // If the camera time is different than GMT time, we need to convert it to GMT time
+ // Using the time zone.
+ QDateTime cameraGMTDateTime = photoDateTime.addSecs(timeZone*(-1));
+
+ kdDebug() << "cameraGMTDateTime: " << cameraGMTDateTime << endl;
+
+ // We trying to find the right date in the GPS points list.
+ bool findItem = false;
+ int nbSecItem = maxGapTime;
+ int nbSecs;
+
+ for (GPSDataMap::Iterator it = m_GPSDataMap.begin();
+ it != m_GPSDataMap.end(); ++it )
+ {
+ // Here we check a possible accuracy in seconds between the
+ // Camera GMT time and the GPS device GMT time.
+
+ nbSecs = abs(cameraGMTDateTime.secsTo( it.key() ));
+
+ // We tring to find the minimal accuracy.
+ if( nbSecs < maxGapTime && nbSecs < nbSecItem)
+ {
+ gpsData = m_GPSDataMap[it.key()];
+ findItem = true;
+ nbSecItem = nbSecs;
+ }
+ }
+
+ if (findItem) return true;
+
+ // If we can't find it, we will trying to interpolate the GPS point.
+
+ if (interpolate)
+ {
+ // The interpolate GPS point will be separate by at the maximum of 'interpolationDstTime'
+ // seconds before and after the next and previous real GPS point found.
+
+ QDateTime prevDateTime = findPrevDate(cameraGMTDateTime, interpolationDstTime);
+ QDateTime nextDateTime = findNextDate(cameraGMTDateTime, interpolationDstTime);
+
+ if (!nextDateTime.isNull() && !prevDateTime.isNull())
+ {
+ GPSDataContainer prevGPSPoint = m_GPSDataMap[prevDateTime];
+ GPSDataContainer nextGPSPoint = m_GPSDataMap[nextDateTime];
+
+ double alt1 = prevGPSPoint.altitude();
+ double lon1 = prevGPSPoint.longitude();
+ double lat1 = prevGPSPoint.latitude();
+ uint t1 = prevDateTime.toTime_t();
+ double alt2 = nextGPSPoint.altitude();
+ double lon2 = nextGPSPoint.longitude();
+ double lat2 = nextGPSPoint.latitude();
+ uint t2 = nextDateTime.toTime_t();
+ uint tCor = cameraGMTDateTime.toTime_t();
+
+ if (tCor-t1 != 0)
+ {
+ gpsData.setAltitude(alt1 + (alt2-alt1) * (tCor-t1)/(t2-t1));
+ gpsData.setLatitude(lat1 + (lat2-lat1) * (tCor-t1)/(t2-t1));
+ gpsData.setLongitude(lon1 + (lon2-lon1) * (tCor-t1)/(t2-t1));
+ gpsData.setInterpolated(true);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+QDateTime GPSDataParser::findNextDate(const QDateTime& dateTime, int secs)
+{
+ // We will find the item in GPS data list where the time is
+ // at the maximum bigger than 'secs' mn of the value to match.
+ QDateTime itemFound = dateTime.addSecs(secs);
+ bool found = false;
+
+ for (GPSDataMap::Iterator it = m_GPSDataMap.begin();
+ it != m_GPSDataMap.end(); ++it )
+ {
+ if (it.key() > dateTime)
+ {
+ if (it.key() < itemFound)
+ {
+ itemFound = it.key();
+ found = true;
+ }
+ }
+ }
+
+ if (found)
+ return itemFound;
+
+ return QDateTime();
+}
+
+QDateTime GPSDataParser::findPrevDate(const QDateTime& dateTime, int secs)
+{
+ // We will find the item in GPS data list where the time is
+ // at the maximum smaller than 'secs' mn of the value to match.
+ QDateTime itemFound = dateTime.addSecs((-1)*secs);
+ bool found = false;
+
+ for (GPSDataMap::Iterator it = m_GPSDataMap.begin();
+ it != m_GPSDataMap.end(); ++it )
+ {
+ if (it.key() < dateTime)
+ {
+ if (it.key() > itemFound)
+ {
+ itemFound = it.key();
+ found = true;
+ }
+ }
+ }
+
+ if (found)
+ return itemFound;
+
+ return QDateTime();
+}
+
+bool GPSDataParser::loadGPXFile(const KURL& url)
+{
+ QFile gpxfile(url.path());
+
+ if (!gpxfile.open(IO_ReadOnly))
+ return false;
+
+ QDomDocument gpxDoc("gpx");
+ if (!gpxDoc.setContent(&gpxfile))
+ return false;
+
+ QDomElement gpxDocElem = gpxDoc.documentElement();
+ if (gpxDocElem.tagName()!="gpx")
+ return false;
+
+ for (QDomNode nTrk = gpxDocElem.firstChild();
+ !nTrk.isNull(); nTrk = nTrk.nextSibling())
+ {
+ QDomElement trkElem = nTrk.toElement();
+ if (trkElem.isNull()) continue;
+ if (trkElem.tagName() != "trk") continue;
+
+ for (QDomNode nTrkseg = trkElem.firstChild();
+ !nTrkseg.isNull(); nTrkseg = nTrkseg.nextSibling())
+ {
+ QDomElement trksegElem = nTrkseg.toElement();
+ if (trksegElem.isNull()) continue;
+ if (trksegElem.tagName() != "trkseg") continue;
+
+ for (QDomNode nTrkpt = trksegElem.firstChild();
+ !nTrkpt.isNull(); nTrkpt = nTrkpt.nextSibling())
+ {
+ QDomElement trkptElem = nTrkpt.toElement();
+ if (trkptElem.isNull()) continue;
+ if (trkptElem.tagName() != "trkpt") continue;
+
+ QDateTime ptDateTime;
+ double ptAltitude = 0.0;
+ double ptLatitude = 0.0;
+ double ptLongitude = 0.0;
+
+ // Get GPS position. If not available continue to next point.
+ QString lat = trkptElem.attribute("lat");
+ QString lon = trkptElem.attribute("lon");
+ if (lat.isEmpty() || lon.isEmpty()) continue;
+
+ ptLatitude = lat.toDouble();
+ ptLongitude = lon.toDouble();
+
+ // Get metadata of track point (altitude and time stamp)
+ for (QDomNode nTrkptMeta = trkptElem.firstChild();
+ !nTrkptMeta.isNull(); nTrkptMeta = nTrkptMeta.nextSibling())
+ {
+ QDomElement trkptMetaElem = nTrkptMeta.toElement();
+ if (trkptMetaElem.isNull()) continue;
+ if (trkptMetaElem.tagName() == QString("time"))
+ {
+ // Get GPS point time stamp. If not available continue to next point.
+ QString time = trkptMetaElem.text();
+ if (time.isEmpty()) continue;
+ ptDateTime = QDateTime::fromString(time, Qt::ISODate);
+ }
+ if (trkptMetaElem.tagName() == QString("ele"))
+ {
+ // Get GPS point altitude. If not available continue to next point.
+ QString ele = trkptMetaElem.text();
+ if (!ele.isEmpty())
+ ptAltitude = ele.toDouble();
+ }
+ }
+
+ if (ptDateTime.isNull())
+ continue;
+
+ GPSDataContainer gpsData(ptAltitude, ptLatitude, ptLongitude, false);
+ m_GPSDataMap.insert( ptDateTime, gpsData );
+ }
+ }
+ }
+
+ kdDebug( 51001 ) << "GPX File " << url.fileName()
+ << " parsed with " << numPoints()
+ << " points extracted" << endl;
+ return true;
+}
+
+} // NameSpace KIPIGPSSyncPlugin
diff --git a/kipi-plugins/gpssync/gpsdataparser.h b/kipi-plugins/gpssync/gpsdataparser.h
new file mode 100644
index 0000000..121a97e
--- /dev/null
+++ b/kipi-plugins/gpssync/gpsdataparser.h
@@ -0,0 +1,74 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-09-19
+ * Description : GPS data file parser.
+ * (GPX format http://www.topografix.com/gpx.asp).
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+#ifndef GPSDATAPARSER_H
+#define GPSDATAPARSER_H
+
+// Qt includes.
+
+#include <qdatetime.h>
+#include <qmap.h>
+
+// KDE includes.
+
+#include <kurl.h>
+
+// Local includes.
+
+#include "gpsdatacontainer.h"
+
+namespace KIPIGPSSyncPlugin
+{
+
+class GPSDataParser
+{
+
+public:
+
+ GPSDataParser();
+ ~GPSDataParser(){};
+
+ bool loadGPXFile(const KURL& url);
+
+ void clear();
+ int numPoints();
+ bool matchDate(const QDateTime& photoDateTime, int maxGapTime, int timeZone,
+ bool interpolate, int interpolationDstTime,
+ GPSDataContainer& gpsData);
+
+private:
+
+ // Methods used to perform interpolation.
+ QDateTime findNextDate(const QDateTime& dateTime, int secs);
+ QDateTime findPrevDate(const QDateTime& dateTime, int secs);
+
+protected:
+
+ typedef QMap<QDateTime, GPSDataContainer> GPSDataMap;
+
+ GPSDataMap m_GPSDataMap;
+};
+
+} // NameSpace KIPIGPSSyncPlugin
+
+#endif // GPSDATAPARSER_H
diff --git a/kipi-plugins/gpssync/gpseditdialog.cpp b/kipi-plugins/gpssync/gpseditdialog.cpp
new file mode 100644
index 0000000..032aecd
--- /dev/null
+++ b/kipi-plugins/gpssync/gpseditdialog.cpp
@@ -0,0 +1,339 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-09-22
+ * Description : a dialog to edit GPS positions
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qtimer.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qvalidator.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <khelpmenu.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+#include <klineedit.h>
+#include <kmessagebox.h>
+#include <khtmlview.h>
+#include <kpopupmenu.h>
+
+// Local includes.
+
+#include "kpaboutdata.h"
+#include "pluginsversion.h"
+#include "gpsmapwidget.h"
+#include "gpseditdialog.h"
+#include "gpseditdialog.moc"
+
+namespace KIPIGPSSyncPlugin
+{
+
+class GPSEditDialogDialogPrivate
+{
+
+public:
+
+ GPSEditDialogDialogPrivate()
+ {
+ altitudeInput = 0;
+ latitudeInput = 0;
+ longitudeInput = 0;
+ worldMap = 0;
+ about = 0;
+ goButton = 0;
+ hasGPSInfo = false;
+ }
+
+ bool hasGPSInfo;
+
+ QPushButton *goButton;
+
+ KLineEdit *altitudeInput;
+ KLineEdit *latitudeInput;
+ KLineEdit *longitudeInput;
+
+ KIPIPlugins::KPAboutData *about;
+
+ GPSDataContainer gpsData;
+
+ GPSMapWidget *worldMap;
+};
+
+GPSEditDialog::GPSEditDialog(QWidget* parent, const GPSDataContainer& gpsData,
+ const QString& fileName, bool hasGPSInfo)
+ : KDialogBase(Plain, i18n("%1 - Edit Geographical Coordinates").arg(fileName),
+ Help|Ok|Cancel, Ok,
+ parent, 0, true, false)
+{
+ d = new GPSEditDialogDialogPrivate;
+ d->hasGPSInfo = hasGPSInfo;
+ d->gpsData = gpsData;
+
+ QGridLayout* grid = new QGridLayout(plainPage(), 8, 3, 0, spacingHint());
+
+ QLabel *message = new QLabel(i18n("<p>Use the map on the right to select the location where "
+ "the picture have been taken. Click with left mouse button or move the marker "
+ "on the map to get the GPS coordinates.<p>"), plainPage());
+
+ QLabel *altitudeLabel = new QLabel(i18n("Altitude:"), plainPage());
+ QLabel *latitudeLabel = new QLabel(i18n("Latitude:"), plainPage());
+ QLabel *longitudeLabel = new QLabel(i18n("Longitude:"), plainPage());
+
+ d->altitudeInput = new KLineEdit(plainPage());
+ d->latitudeInput = new KLineEdit(plainPage());
+ d->longitudeInput = new KLineEdit(plainPage());
+
+ QPushButton *altResetButton = new QPushButton(SmallIcon("clear_left"), QString::null, plainPage());
+ QPushButton *latResetButton = new QPushButton(SmallIcon("clear_left"), QString::null, plainPage());
+ QPushButton *lonResetButton = new QPushButton(SmallIcon("clear_left"), QString::null, plainPage());
+
+ d->altitudeInput->setValidator(new QDoubleValidator(-20000.0, 20000.0, 1, this));
+ d->latitudeInput->setValidator(new QDoubleValidator(-90.0, 90.0, 12, this));
+ d->longitudeInput->setValidator(new QDoubleValidator(-180.0, 180.0, 12, this));
+
+ d->goButton = new QPushButton(i18n("Goto Location"), plainPage());
+ d->goButton->setEnabled(false);
+
+ d->worldMap = new GPSMapWidget(plainPage());
+ d->worldMap->setFileName(fileName);
+ d->worldMap->show();
+
+ grid->addMultiCellWidget(message, 0, 0, 0, 2);
+ grid->addMultiCellWidget(altitudeLabel, 1, 1, 0, 2);
+ grid->addMultiCellWidget(d->altitudeInput, 2, 2, 0, 1);
+ grid->addMultiCellWidget(altResetButton, 2, 2, 2, 2);
+ grid->addMultiCellWidget(latitudeLabel, 3, 3, 0, 2);
+ grid->addMultiCellWidget(d->latitudeInput, 4, 4, 0, 1);
+ grid->addMultiCellWidget(latResetButton, 4, 4, 2, 2);
+ grid->addMultiCellWidget(longitudeLabel, 5, 5, 0, 2);
+ grid->addMultiCellWidget(d->longitudeInput, 6, 6, 0, 1);
+ grid->addMultiCellWidget(lonResetButton, 6, 6, 2, 2);
+ grid->addMultiCellWidget(d->goButton, 7, 7, 0, 1);
+ grid->addMultiCellWidget(d->worldMap->view(), 0, 8, 3, 3);
+ grid->setColStretch(0, 3);
+ grid->setColStretch(3, 10);
+ grid->setRowStretch(8, 10);
+
+ // ---------------------------------------------------------------
+ // About data and help button.
+
+ d->about = new KIPIPlugins::KPAboutData(I18N_NOOP("GPS Sync"),
+ 0,
+ KAboutData::License_GPL,
+ I18N_NOOP("A Plugin to synchronize pictures metadata with a GPS device"),
+ "(c) 2006-2008, Gilles Caulier");
+
+ d->about->addAuthor("Gilles Caulier", I18N_NOOP("Author and Maintainer"),
+ "caulier dot gilles at gmail dot com");
+
+ KHelpMenu* helpMenu = new KHelpMenu(this, d->about, false);
+ helpMenu->menu()->removeItemAt(0);
+ helpMenu->menu()->insertItem(i18n("Plugin Handbook"),
+ this, SLOT(slotHelp()), 0, -1, 0);
+ actionButton(Help)->setPopup( helpMenu->menu() );
+
+ // ---------------------------------------------------------------
+
+ connect(altResetButton, SIGNAL(released()),
+ d->altitudeInput, SLOT(clear()));
+
+ connect(latResetButton, SIGNAL(released()),
+ d->latitudeInput, SLOT(clear()));
+
+ connect(lonResetButton, SIGNAL(released()),
+ d->longitudeInput, SLOT(clear()));
+
+ connect(d->altitudeInput, SIGNAL(textChanged(const QString&)),
+ this, SLOT(slotGPSPositionChanged()));
+
+ connect(d->latitudeInput, SIGNAL(textChanged(const QString&)),
+ this, SLOT(slotGPSPositionChanged()));
+
+ connect(d->longitudeInput, SIGNAL(textChanged(const QString&)),
+ this, SLOT(slotGPSPositionChanged()));
+
+ connect(d->worldMap, SIGNAL(signalNewGPSLocationFromMap(const QString&, const QString&, const QString&)),
+ this, SLOT(slotNewGPSLocationFromMap(const QString&, const QString&, const QString&)));
+
+ connect(d->goButton, SIGNAL(released()),
+ this, SLOT(slotGotoLocation()));
+
+ // ---------------------------------------------------------------
+
+ readSettings();
+ QTimer::singleShot(0, this, SLOT(slotUpdateWorldMap()));
+}
+
+GPSEditDialog::~GPSEditDialog()
+{
+ delete d->about;
+ delete d;
+}
+
+void GPSEditDialog::slotHelp()
+{
+ KApplication::kApplication()->invokeHelp("gpssync", "kipi-plugins");
+}
+
+void GPSEditDialog::closeEvent(QCloseEvent *e)
+{
+ if (!e) return;
+ saveSettings();
+ e->accept();
+}
+
+void GPSEditDialog::slotGPSPositionChanged()
+{
+ d->goButton->setEnabled(true);
+}
+
+void GPSEditDialog::slotGotoLocation()
+{
+ if (!checkGPSLocation()) return;
+ d->worldMap->setGPSPosition(d->latitudeInput->text(), d->longitudeInput->text());
+ slotUpdateWorldMap();
+}
+
+void GPSEditDialog::slotUpdateWorldMap()
+{
+ d->worldMap->resized();
+}
+
+void GPSEditDialog::resizeEvent(QResizeEvent *e)
+{
+ if (!e) return;
+ slotUpdateWorldMap();
+}
+
+void GPSEditDialog::slotCancel()
+{
+ saveSettings();
+ KDialogBase::slotCancel();
+}
+
+void GPSEditDialog::readSettings()
+{
+ KConfig config("kipirc");
+ config.setGroup("GPS Sync Settings");
+ resize(configDialogSize(config, QString("GPS Edit Dialog")));
+
+ d->worldMap->setZoomLevel(config.readNumEntry("Zoom Level", 8));
+ d->worldMap->setMapType(config.readEntry("Map Type", QString("G_MAP_TYPE")));
+
+ d->altitudeInput->blockSignals(true);
+ d->latitudeInput->blockSignals(true);
+ d->longitudeInput->blockSignals(true);
+
+ if (d->hasGPSInfo)
+ {
+ d->altitudeInput->setText(QString::number(d->gpsData.altitude(), 'g', 12));
+ d->latitudeInput->setText(QString::number(d->gpsData.latitude(), 'g', 12));
+ d->longitudeInput->setText(QString::number(d->gpsData.longitude(), 'g', 12));
+ }
+ else
+ {
+ d->altitudeInput->setText(QString::number(config.readDoubleNumEntry("GPS Last Altitude", 0.0), 'g', 12));
+ d->latitudeInput->setText(QString::number(config.readDoubleNumEntry("GPS Last Latitude", 0.0), 'g', 12));
+ d->longitudeInput->setText(QString::number(config.readDoubleNumEntry("GPS Last Longitude", 0.0), 'g', 12));
+ }
+
+ d->altitudeInput->blockSignals(false);
+ d->latitudeInput->blockSignals(false);
+ d->longitudeInput->blockSignals(false);
+
+ d->worldMap->setGPSPosition(d->latitudeInput->text(), d->longitudeInput->text());
+ d->worldMap->resized();
+}
+
+void GPSEditDialog::saveSettings()
+{
+ KConfig config("kipirc");
+ config.setGroup("GPS Sync Settings");
+ saveDialogSize(config, QString("GPS Edit Dialog"));
+ config.writeEntry("GPS Last Latitude", d->latitudeInput->text().toDouble());
+ config.writeEntry("GPS Last Longitude", d->longitudeInput->text().toDouble());
+ config.writeEntry("GPS Last Altitude", d->altitudeInput->text().toDouble());
+ config.writeEntry("Zoom Level", d->worldMap->zoomLevel());
+ config.writeEntry("Map Type", d->worldMap->mapType());
+ config.sync();
+}
+
+GPSDataContainer GPSEditDialog::getGPSInfo()
+{
+ return GPSDataContainer(d->altitudeInput->text().toDouble(),
+ d->latitudeInput->text().toDouble(),
+ d->longitudeInput->text().toDouble(),
+ false);
+}
+
+bool GPSEditDialog::checkGPSLocation()
+{
+ bool ok;
+
+ d->altitudeInput->text().toDouble(&ok);
+ if (!ok)
+ {
+ KMessageBox::error(this, i18n("Altitude value is not correct!"),
+ i18n("Edit Geographical Coordinates"));
+ return false;
+ }
+
+ d->latitudeInput->text().toDouble(&ok);
+ if (!ok)
+ {
+ KMessageBox::error(this, i18n("Latitude value is not correct!"),
+ i18n("Edit Geographical Coordinates"));
+ return false;
+ }
+
+ d->longitudeInput->text().toDouble(&ok);
+ if (!ok)
+ {
+ KMessageBox::error(this, i18n("Longitude value is not correct!"),
+ i18n("Edit Geographical Coordinates"));
+ return false;
+ }
+
+ return true;
+}
+
+void GPSEditDialog::slotOk()
+{
+ if (!checkGPSLocation()) return;
+ saveSettings();
+ accept();
+}
+
+void GPSEditDialog::slotNewGPSLocationFromMap(const QString& lat, const QString& lon, const QString& alt)
+{
+ d->latitudeInput->setText(lat);
+ d->longitudeInput->setText(lon);
+ d->altitudeInput->setText(alt);
+ d->goButton->setEnabled(false);
+}
+
+} // namespace KIPIGPSSyncPlugin
diff --git a/kipi-plugins/gpssync/gpseditdialog.h b/kipi-plugins/gpssync/gpseditdialog.h
new file mode 100644
index 0000000..5ce243d
--- /dev/null
+++ b/kipi-plugins/gpssync/gpseditdialog.h
@@ -0,0 +1,79 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-09-22
+ * Description : a dialog to edit GPS positions
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+#ifndef GPSEDITDIALOG_H
+#define GPSEDITDIALOG_H
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+// Local includes.
+
+#include "gpsdatacontainer.h"
+
+namespace KIPIGPSSyncPlugin
+{
+
+class GPSEditDialogDialogPrivate;
+
+class GPSEditDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ GPSEditDialog(QWidget* parent, const GPSDataContainer& gpsData,
+ const QString& fileName, bool hasGPSInfo);
+ ~GPSEditDialog();
+
+ GPSDataContainer getGPSInfo();
+
+protected slots:
+
+ void slotOk();
+ void slotCancel();
+ void slotNewGPSLocationFromMap(const QString& lat, const QString& lon, const QString& alt);
+ void slotUpdateWorldMap();
+ void slotGotoLocation();
+ void slotGPSPositionChanged();
+ void slotHelp();
+
+protected:
+
+ void resizeEvent(QResizeEvent *);
+ void closeEvent(QCloseEvent *);
+
+private:
+
+ void readSettings();
+ void saveSettings();
+ bool checkGPSLocation();
+
+private:
+
+ GPSEditDialogDialogPrivate *d;
+};
+
+} // namespace KIPIGPSSyncPlugin
+
+#endif /* GPSEDITDIALOG_H */
diff --git a/kipi-plugins/gpssync/gpslistviewitem.cpp b/kipi-plugins/gpssync/gpslistviewitem.cpp
new file mode 100644
index 0000000..8951c87
--- /dev/null
+++ b/kipi-plugins/gpssync/gpslistviewitem.cpp
@@ -0,0 +1,246 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-09-19
+ * Description : GPS file list view item.
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qpainter.h>
+#include <qfileinfo.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kiconloader.h>
+
+// LibKExiv2 includes.
+
+#include <libkexiv2/kexiv2.h>
+
+// Local includes.
+
+#include "gpslistviewitem.h"
+
+namespace KIPIGPSSyncPlugin
+{
+
+class GPSListViewItemPriv
+{
+public:
+
+ GPSListViewItemPriv()
+ {
+ enabled = false;
+ dirty = false;
+ erase = false;
+ hasGPSInfo = false;
+ }
+
+ bool enabled;
+ bool dirty;
+ bool erase;
+ bool hasGPSInfo;
+
+ QDateTime date;
+
+ KURL url;
+
+ GPSDataContainer gpsData;
+};
+
+GPSListViewItem::GPSListViewItem(KListView *view, QListViewItem *after, const KURL& url)
+ : KListViewItem(view, after)
+{
+ d = new GPSListViewItemPriv;
+ d->url = url;
+
+ setEnabled(false);
+ setPixmap(0, SmallIcon( "file_broken", KIcon::SizeLarge, KIcon::DisabledState ));
+ setText(1, d->url.fileName());
+
+ KExiv2Iface::KExiv2 exiv2Iface;
+ exiv2Iface.load(d->url.path());
+ setDateTime(exiv2Iface.getImageDateTime());
+ double alt, lat, lng;
+ d->hasGPSInfo = exiv2Iface.getGPSInfo(alt, lat, lng);
+ if (hasGPSInfo())
+ setGPSInfo(GPSDataContainer(alt, lat, lng, false), false);
+}
+
+GPSListViewItem::~GPSListViewItem()
+{
+ delete d;
+}
+
+void GPSListViewItem::setGPSInfo(const GPSDataContainer& gpsData, bool dirty, bool addedManually)
+{
+ setEnabled(true);
+ d->dirty = dirty;
+ d->gpsData = gpsData;
+ d->erase = false;
+ d->hasGPSInfo = true;
+ setText(3, QString::number(d->gpsData.latitude(), 'g', 12));
+ setText(4, QString::number(d->gpsData.longitude(), 'g', 12));
+ setText(5, QString::number(d->gpsData.altitude(), 'g', 12));
+
+ if (isDirty())
+ {
+ QString status;
+
+ if (d->gpsData.isInterpolated())
+ status = i18n("Interpolated");
+ else
+ {
+ if (addedManually)
+ status = i18n("Added");
+ else
+ status = i18n("Found");
+ }
+
+ setText(6, status);
+ }
+
+ repaint();
+}
+
+GPSDataContainer GPSListViewItem::GPSInfo() const
+{
+ return d->gpsData;
+}
+
+void GPSListViewItem::eraseGPSInfo()
+{
+ d->erase = true;
+ d->dirty = true;
+ setText(6, i18n("Deleted!"));
+ repaint();
+}
+
+void GPSListViewItem::setDateTime(const QDateTime& date)
+{
+ if (date.isValid())
+ {
+ d->date = date;
+ setText(2, date.toString(Qt::LocalDate));
+ }
+ else
+ {
+ setText(2, i18n("Not available"));
+ }
+}
+
+QDateTime GPSListViewItem::dateTime() const
+{
+ return d->date;
+}
+
+KURL GPSListViewItem::url()
+{
+ return d->url;
+}
+
+bool GPSListViewItem::hasGPSInfo()
+{
+ return d->hasGPSInfo;
+}
+
+bool GPSListViewItem::isInterpolated()
+{
+ return d->gpsData.isInterpolated();
+}
+
+void GPSListViewItem::writeGPSInfoToFile()
+{
+ if (isEnabled() && isDirty())
+ {
+ setPixmap(1, SmallIcon("run"));
+ KExiv2Iface::KExiv2 exiv2Iface;
+ bool ret = exiv2Iface.load(d->url.path());
+
+ if (d->erase)
+ ret &= exiv2Iface.removeGPSInfo();
+ else
+ {
+ ret &= exiv2Iface.setGPSInfo(d->gpsData.altitude(),
+ d->gpsData.latitude(),
+ d->gpsData.longitude());
+ }
+
+ ret &= exiv2Iface.save(d->url.path());
+
+ if (ret)
+ setPixmap(1, SmallIcon("ok"));
+ else
+ setPixmap(1, SmallIcon("cancel"));
+
+ d->dirty = false;
+ }
+}
+
+void GPSListViewItem::setEnabled(bool e)
+{
+ d->enabled = e;
+ repaint();
+}
+
+bool GPSListViewItem::isEnabled()
+{
+ return d->enabled;
+}
+
+bool GPSListViewItem::isDirty()
+{
+ return d->dirty;
+}
+
+void GPSListViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment)
+{
+ if (isEnabled())
+ {
+ if ( isDirty() && !d->erase && column >= 3 && column <= 5 )
+ {
+ QColorGroup _cg( cg );
+ QColor c = _cg.text();
+ _cg.setColor( QColorGroup::Text, Qt::red );
+ KListViewItem::paintCell( p, _cg, column, width, alignment );
+ _cg.setColor( QColorGroup::Text, c );
+ }
+ else if ( isDirty() && d->erase && column == 6)
+ {
+ QColorGroup _cg( cg );
+ QColor c = _cg.text();
+ _cg.setColor( QColorGroup::Text, Qt::red );
+ KListViewItem::paintCell( p, _cg, column, width, alignment );
+ _cg.setColor( QColorGroup::Text, c );
+ }
+ else
+ KListViewItem::paintCell(p, cg, column, width, alignment);
+ }
+ else
+ {
+ QColorGroup _cg( cg );
+ QColor c = _cg.text();
+ _cg.setColor( QColorGroup::Text, Qt::gray );
+ KListViewItem::paintCell( p, _cg, column, width, alignment );
+ _cg.setColor( QColorGroup::Text, c );
+ }
+}
+
+} // NameSpace KIPIGPSSyncPlugin
diff --git a/kipi-plugins/gpssync/gpslistviewitem.h b/kipi-plugins/gpssync/gpslistviewitem.h
new file mode 100644
index 0000000..b4483c5
--- /dev/null
+++ b/kipi-plugins/gpssync/gpslistviewitem.h
@@ -0,0 +1,83 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-09-19
+ * Description : GPS file list view item.
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+#ifndef GPSLISTVIEWITEM_H
+#define GPSLISTVIEWITEM_H
+
+// Qt includes.
+
+#include <qdatetime.h>
+#include <qstring.h>
+
+// KDE includes.
+
+#include <kurl.h>
+#include <klistview.h>
+
+// Local includes.
+
+#include "gpsdatacontainer.h"
+
+class QPainter;
+class QColorGroup;
+class QPixmap;
+
+namespace KIPIGPSSyncPlugin
+{
+class GPSListViewItemPriv;
+
+class GPSListViewItem : public KListViewItem
+{
+
+public:
+
+ GPSListViewItem(KListView *view, QListViewItem *after, const KURL& url);
+ ~GPSListViewItem();
+
+ void setGPSInfo(const GPSDataContainer& gpsData, bool dirty=true, bool addedManually=false);
+ GPSDataContainer GPSInfo() const;
+ void eraseGPSInfo();
+
+ void setDateTime(const QDateTime &date);
+ QDateTime dateTime() const;
+
+ void setEnabled(bool e);
+ bool isEnabled();
+ bool isDirty();
+ bool isInterpolated();
+ bool hasGPSInfo();
+
+ KURL url();
+ void writeGPSInfoToFile();
+
+protected:
+
+ void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment);
+
+private:
+
+ GPSListViewItemPriv *d;
+};
+
+} // NameSpace KIPIGPSSyncPlugin
+
+#endif /* GPSLISTVIEWITEM_H */
diff --git a/kipi-plugins/gpssync/gpsmapwidget.cpp b/kipi-plugins/gpssync/gpsmapwidget.cpp
new file mode 100644
index 0000000..92484cd
--- /dev/null
+++ b/kipi-plugins/gpssync/gpsmapwidget.cpp
@@ -0,0 +1,188 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-09-28
+ * Description : a widget to display a GPS web map locator.
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ * Copyright 2008 by Gerhard Kulzer <gerhard at kulzer dot net>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+// KDE includes.
+
+#include <kdebug.h>
+#include <khtmlview.h>
+#include <kurl.h>
+
+// Local includes.
+
+#include "gpsmapwidget.h"
+#include "gpsmapwidget.moc"
+
+namespace KIPIGPSSyncPlugin
+{
+
+class GPSMapWidgetPrivate
+{
+
+public:
+
+ GPSMapWidgetPrivate()
+ {
+ gpsLocalorUrl = QString("http://digikam3rdparty.free.fr/gpslocator/getlonlatalt.php");
+ }
+
+ QString gpsLocalorUrl;
+ QString latitude;
+ QString longitude;
+ QString altitude;
+ QString zoomLevel;
+ QString mapType;
+ QString fileName;
+};
+
+GPSMapWidget::GPSMapWidget(QWidget* parent)
+ : KHTMLPart(parent)
+{
+ d = new GPSMapWidgetPrivate;
+
+ setJScriptEnabled(true);
+ setDNDEnabled(false);
+ setEditable(false);
+
+ view()->setVScrollBarMode(QScrollView::AlwaysOff);
+ view()->setHScrollBarMode(QScrollView::AlwaysOff);
+ view()->setMinimumSize(480, 360);
+}
+
+GPSMapWidget::~GPSMapWidget()
+{
+ delete d;
+}
+
+void GPSMapWidget::setFileName(const QString& fileName)
+{
+ d->fileName = fileName;
+}
+
+QString GPSMapWidget::fileName()
+{
+ return d->fileName;
+}
+
+void GPSMapWidget::setGPSPosition(const QString& lat, const QString& lon)
+{
+ d->latitude = lat;
+ d->longitude = lon;
+}
+
+void GPSMapWidget::setMapType(const QString& mapType)
+{
+ d->mapType = mapType;
+}
+
+QString GPSMapWidget::mapType()
+{
+ return d->mapType;
+}
+
+void GPSMapWidget::setZoomLevel(int zoomLevel)
+{
+ d->zoomLevel = QString::number(zoomLevel);
+}
+
+int GPSMapWidget::GPSMapWidget::zoomLevel()
+{
+ return d->zoomLevel.toInt();
+}
+
+void GPSMapWidget::extractGPSPositionfromStatusbar(const QString& txt)
+{
+ QString status = txt;
+ status.remove(0, 5);
+ status.truncate(status.length()-1);
+ d->latitude = status.section(",", 0, 0);
+ d->longitude = status.section(",", 1, 1);
+ d->altitude = status.section(",", 2, 2);
+ d->longitude.remove(0, 5);
+ d->altitude.remove(0, 5);
+ emit signalNewGPSLocationFromMap(d->latitude, d->longitude, d->altitude);
+}
+
+void GPSMapWidget::khtmlMouseMoveEvent(khtml::MouseMoveEvent *e)
+{
+ QString status = jsStatusBarText();
+
+ // If a new point to the map have been moved, the Status
+ // string is like : "(lat:25.5894748, lon:47.6897455478, alt:211)"
+ if (status.startsWith(QString("(lat:")))
+ extractGPSPositionfromStatusbar(status);
+
+ KHTMLPart::khtmlMouseMoveEvent(e);
+}
+
+void GPSMapWidget::khtmlMouseReleaseEvent(khtml::MouseReleaseEvent *e)
+{
+ QString status = jsStatusBarText();
+
+ // If a new point to the map have been moved, the Status
+ // string is like : "(lat:25.5894748, lon:47.6897455478, alt:211)"
+ if (status.startsWith(QString("(lat:")))
+ extractGPSPositionfromStatusbar(status);
+
+ // If a new map zoom level have been selected, the Status
+ // string is like : "newZoomLevel:5"
+ if (status.startsWith(QString("newZoomLevel:")))
+ {
+ status.remove(0, 13);
+ d->zoomLevel = status;
+ }
+
+ // If a new map type have been selected, the Status
+ // string is like : "newMapType:G_SATELLITE_TYPE"
+ if (status.startsWith(QString("newMapType:")))
+ {
+ status.remove(0, 11);
+ d->mapType = status;
+ }
+
+ KHTMLPart::khtmlMouseReleaseEvent(e);
+}
+
+void GPSMapWidget::resized()
+{
+ QString url = d->gpsLocalorUrl;
+ url.append("?latitude=");
+ url.append(d->latitude);
+ url.append("&longitude=");
+ url.append(d->longitude);
+ url.append("&altitude=");
+ url.append(d->altitude);
+ url.append("&width=");
+ url.append(QString::number(view()->width()));
+ url.append("&height=");
+ url.append(QString::number(view()->height()));
+ url.append("&zoom=");
+ url.append(d->zoomLevel);
+ url.append("&maptype=");
+ url.append(d->mapType);
+ url.append("&filename=");
+ url.append(d->fileName);
+ openURL(KURL(url));
+ kdDebug( 51001 ) << url << endl;
+}
+
+} // namespace KIPIGPSSyncPlugin
diff --git a/kipi-plugins/gpssync/gpsmapwidget.h b/kipi-plugins/gpssync/gpsmapwidget.h
new file mode 100644
index 0000000..3ca2e52
--- /dev/null
+++ b/kipi-plugins/gpssync/gpsmapwidget.h
@@ -0,0 +1,82 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-09-28
+ * Description : a widget to display a GPS web map locator.
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ * Copyright 2008 by Gerhard Kulzer <gerhard at kulzer dot net>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+#ifndef GPSMAPWIDGET_H
+#define GPSMAPWIDGET_H
+
+// Qt includes.
+
+#include <qstring.h>
+
+// KDE includes.
+
+#include <khtml_part.h>
+
+namespace KIPIGPSSyncPlugin
+{
+
+class GPSMapWidgetPrivate;
+
+class GPSMapWidget : public KHTMLPart
+{
+ Q_OBJECT
+
+public:
+
+ GPSMapWidget(QWidget* parent);
+ ~GPSMapWidget();
+
+ void setGPSPosition(const QString& lat, const QString& lon);
+
+ void setZoomLevel(int zoomLevel);
+ int zoomLevel();
+
+ void setMapType(const QString& mapType);
+ QString mapType();
+
+ void setFileName(const QString& fileName);
+ QString fileName();
+
+ void resized();
+
+signals:
+
+ void signalNewGPSLocationFromMap(const QString&, const QString&, const QString&);
+
+protected:
+
+ void khtmlMouseMoveEvent(khtml::MouseMoveEvent*);
+ void khtmlMouseReleaseEvent(khtml::MouseReleaseEvent *);
+
+private:
+
+ void extractGPSPositionfromStatusbar(const QString& txt);
+
+private:
+
+ GPSMapWidgetPrivate *d;
+};
+
+} // namespace KIPIGPSSyncPlugin
+
+#endif /* GPSMAPWIDGET_H */
diff --git a/kipi-plugins/gpssync/gpssyncdialog.cpp b/kipi-plugins/gpssync/gpssyncdialog.cpp
new file mode 100644
index 0000000..eed7154
--- /dev/null
+++ b/kipi-plugins/gpssync/gpssyncdialog.cpp
@@ -0,0 +1,548 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-05-16
+ * Description : a plugin to synchronize pictures with
+ * a GPS device.
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qcombobox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qvgroupbox.h>
+#include <qgrid.h>
+#include <qpushbutton.h>
+#include <qwhatsthis.h>
+#include <qcheckbox.h>
+
+// KDE includes.
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <khelpmenu.h>
+#include <ksqueezedtextlabel.h>
+#include <kiconloader.h>
+#include <kpopupmenu.h>
+#include <kstandarddirs.h>
+#include <klistview.h>
+#include <kfiledialog.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kglobalsettings.h>
+#include <knuminput.h>
+#include <kseparator.h>
+#include <kio/previewjob.h>
+
+// Local includes.
+
+#include "kpaboutdata.h"
+#include "pluginsversion.h"
+#include "gpslistviewitem.h"
+#include "gpsdataparser.h"
+#include "gpseditdialog.h"
+#include "gpssyncdialog.h"
+#include "gpssyncdialog.moc"
+
+namespace KIPIGPSSyncPlugin
+{
+
+class GPSSyncDialogPriv
+{
+public:
+
+ GPSSyncDialogPriv()
+ {
+ listView = 0;
+ interface = 0;
+ maxGapInput = 0;
+ gpxFileName = 0;
+ gpxPointsLabel = 0;
+ timeZoneCB = 0;
+ interpolateBox = 0;
+ maxTimeInput = 0;
+ maxTimeLabel = 0;
+ about = 0;
+ }
+
+ QLabel *gpxPointsLabel;
+ QLabel *maxTimeLabel;
+
+ QComboBox *timeZoneCB;
+
+ QCheckBox *interpolateBox;
+
+ KListView *listView;
+
+ KIntSpinBox *maxGapInput;
+ KIntSpinBox *maxTimeInput;
+
+ KSqueezedTextLabel *gpxFileName;
+
+ KIPI::Interface *interface;
+
+ KIPIPlugins::KPAboutData *about;
+
+ GPSDataParser gpxParser;
+};
+
+GPSSyncDialog::GPSSyncDialog( KIPI::Interface* interface, QWidget* parent)
+ : KDialogBase(Plain, i18n("Geolocation"),
+ Help|User1|User2|User3|Apply|Close, Close,
+ parent, 0, true, false)
+{
+ d = new GPSSyncDialogPriv;
+ d->interface = interface;
+
+ setButtonText(User1, i18n("Correlate"));
+ setButtonText(User2, i18n("Edit..."));
+ setButtonText(User3, i18n("Remove"));
+
+ setButtonTip(User1, i18n("Correlate in time and interpolate distance of data from GPX file with all images on the list."));
+ setButtonTip(User2, i18n("Manually edit GPS coordinates of selected images from the list."));
+ setButtonTip(User3, i18n("Remove GPS coordinates of selected images from the list."));
+
+ enableButton(User1, false);
+ enableButton(User2, true);
+ enableButton(User3, true);
+
+ QGridLayout *mainLayout = new QGridLayout(plainPage(), 3, 1, 0, marginHint());
+
+ // --------------------------------------------------------------
+
+ d->listView = new KListView(plainPage());
+ d->listView->addColumn( i18n("Thumbnail") );
+ d->listView->addColumn( i18n("File Name") );
+ d->listView->addColumn( i18n("Camera time stamp") );
+ d->listView->addColumn( i18n("Latitude") );
+ d->listView->addColumn( i18n("Longitude") );
+ d->listView->addColumn( i18n("Altitude") );
+ d->listView->addColumn( i18n("Status") );
+ d->listView->setResizeMode(QListView::AllColumns);
+ d->listView->setAllColumnsShowFocus(true);
+ d->listView->setSorting(-1);
+ d->listView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ d->listView->setSelectionMode(QListView::Extended);
+ d->listView->setMinimumWidth(450);
+
+ // ---------------------------------------------------------------
+
+ QGroupBox *settingsBox = new QGroupBox(0, Qt::Vertical, i18n("Settings"), plainPage());
+ QGridLayout *settingsBoxLayout = new QGridLayout(settingsBox->layout(), 8, 1,
+ KDialog::spacingHint());
+
+ QPushButton *loadGPXButton = new QPushButton(i18n("Load GPX File..."), settingsBox);
+
+ QLabel *gpxFileLabel = new QLabel(i18n("Current GPX file:"), settingsBox);
+ d->gpxFileName = new KSqueezedTextLabel(i18n("No GPX file"), settingsBox);
+ d->gpxPointsLabel = new QLabel(settingsBox);
+ KSeparator *line = new KSeparator(Horizontal, settingsBox);
+
+ QLabel *maxGapLabel = new QLabel(i18n("Max. time gap (sec.):"), settingsBox);
+ d->maxGapInput = new KIntSpinBox(0, 1000000, 1, 30, 10, settingsBox);
+ QWhatsThis::add(d->maxGapInput, i18n("<p>Sets the maximum difference in "
+ "seconds from a GPS track point to the image time to be matched. "
+ "If the time difference exceeds this setting, no match will be attempted."));
+
+ QLabel *timeZoneLabel = new QLabel(i18n("Time zone:"), settingsBox);
+ d->timeZoneCB = new QComboBox( false, settingsBox );
+
+ // See list of time zomes over the world :
+ // http://en.wikipedia.org/wiki/List_of_time_zones
+ // NOTE: Combo box strings are not i18n.
+ d->timeZoneCB->insertItem("GMT-12:00");
+ d->timeZoneCB->insertItem("GMT-11:00");
+ d->timeZoneCB->insertItem("GMT-10:00");
+ d->timeZoneCB->insertItem("GMT-09:30");
+ d->timeZoneCB->insertItem("GMT-09:00");
+ d->timeZoneCB->insertItem("GMT-08:00");
+ d->timeZoneCB->insertItem("GMT-07:00");
+ d->timeZoneCB->insertItem("GMT-06:00");
+ d->timeZoneCB->insertItem("GMT-05:30");
+ d->timeZoneCB->insertItem("GMT-05:00");
+ d->timeZoneCB->insertItem("GMT-04:30");
+ d->timeZoneCB->insertItem("GMT-04:00");
+ d->timeZoneCB->insertItem("GMT-03:30");
+ d->timeZoneCB->insertItem("GMT-03:00");
+ d->timeZoneCB->insertItem("GMT-02:00");
+ d->timeZoneCB->insertItem("GMT-01:00");
+ d->timeZoneCB->insertItem("GMT+00:00");
+ d->timeZoneCB->insertItem("GMT+01:00");
+ d->timeZoneCB->insertItem("GMT+02:00");
+ d->timeZoneCB->insertItem("GMT+03:00");
+ d->timeZoneCB->insertItem("GMT+03:30");
+ d->timeZoneCB->insertItem("GMT+04:00");
+ d->timeZoneCB->insertItem("GMT+05:00");
+ d->timeZoneCB->insertItem("GMT+05:30"); // See B.K.O # 149491
+ d->timeZoneCB->insertItem("GMT+05:45");
+ d->timeZoneCB->insertItem("GMT+06:00");
+ d->timeZoneCB->insertItem("GMT+06:30");
+ d->timeZoneCB->insertItem("GMT+07:00");
+ d->timeZoneCB->insertItem("GMT+08:00");
+ d->timeZoneCB->insertItem("GMT+08:45");
+ d->timeZoneCB->insertItem("GMT+09:00");
+ d->timeZoneCB->insertItem("GMT+09:30");
+ d->timeZoneCB->insertItem("GMT+10:00");
+ d->timeZoneCB->insertItem("GMT+10:30");
+ d->timeZoneCB->insertItem("GMT+11:00");
+ d->timeZoneCB->insertItem("GMT+11:30");
+ d->timeZoneCB->insertItem("GMT+12:00");
+ d->timeZoneCB->insertItem("GMT+12:45");
+ d->timeZoneCB->insertItem("GMT+13:00");
+ d->timeZoneCB->insertItem("GMT+14:00");
+ QWhatsThis::add(d->timeZoneCB, i18n("<p>Sets the time zone the camera was set to "
+ "during photo shooting, so that the time stamps of the images "
+ "can be converted to GMT to match the GPS time reference.\n"
+ "Note: positive offsets count eastwards from zero longitude (GMT), "
+ "they are 'ahead of time'."));
+
+ d->interpolateBox = new QCheckBox(i18n("Interpolate"), settingsBox);
+ QWhatsThis::add(d->interpolateBox, i18n("<p>Set this option to interpolate GPS track points "
+ "which are not closely matched to the GPX data file."));
+
+ d->maxTimeLabel = new QLabel(i18n("Difference in min.:"), settingsBox);
+ d->maxTimeInput = new KIntSpinBox(0, 240, 1, 15, 10, settingsBox);
+ QWhatsThis::add(d->maxTimeInput, i18n("<p>Sets the maximum time difference in minutes (240 max.)"
+ " to interpolate GPX file points to image time data."));
+
+ settingsBoxLayout->addMultiCellWidget(loadGPXButton, 0, 0, 0, 1);
+ settingsBoxLayout->addMultiCellWidget(gpxFileLabel, 1, 1, 0, 1);
+ settingsBoxLayout->addMultiCellWidget(d->gpxFileName, 2, 2, 0, 1);
+ settingsBoxLayout->addMultiCellWidget(d->gpxPointsLabel, 3, 3, 0, 1);
+ settingsBoxLayout->addMultiCellWidget(line, 4, 4, 0, 1);
+ settingsBoxLayout->addMultiCellWidget(maxGapLabel, 5, 5, 0, 0);
+ settingsBoxLayout->addMultiCellWidget(d->maxGapInput, 5, 5, 1, 1);
+ settingsBoxLayout->addMultiCellWidget(timeZoneLabel, 6, 6, 0, 0);
+ settingsBoxLayout->addMultiCellWidget(d->timeZoneCB, 6, 6, 1, 1);
+ settingsBoxLayout->addMultiCellWidget(d->interpolateBox, 7, 7, 0, 1);
+ settingsBoxLayout->addMultiCellWidget(d->maxTimeLabel, 8, 8, 0, 0);
+ settingsBoxLayout->addMultiCellWidget(d->maxTimeInput, 8, 8, 1, 1);
+
+ // ---------------------------------------------------------------
+
+ mainLayout->addMultiCellWidget(d->listView, 0, 2, 0, 1);
+ mainLayout->addMultiCellWidget(settingsBox, 0, 1, 2, 2);
+ mainLayout->setColStretch(1, 10);
+ mainLayout->setRowStretch(2, 10);
+
+ // ---------------------------------------------------------------
+ // About data and help button.
+
+ d->about = new KIPIPlugins::KPAboutData(I18N_NOOP("GPS Sync"),
+ 0,
+ KAboutData::License_GPL,
+ I18N_NOOP("A plugin to synchronize images' metadata with a GPS device"),
+ "(c) 2006-2008, Gilles Caulier");
+
+ d->about->addAuthor("Gilles Caulier", I18N_NOOP("Author and Maintainer"),
+ "caulier dot gilles at gmail dot com");
+
+ KHelpMenu* helpMenu = new KHelpMenu(this, d->about, false);
+ helpMenu->menu()->removeItemAt(0);
+ helpMenu->menu()->insertItem(i18n("Plugin Handbook"),
+ this, SLOT(slotHelp()), 0, -1, 0);
+ actionButton(Help)->setPopup( helpMenu->menu() );
+
+ // ---------------------------------------------------------------
+
+ connect(loadGPXButton, SIGNAL(released()),
+ this, SLOT(slotLoadGPXFile()));
+
+ connect(d->interpolateBox, SIGNAL(toggled(bool)),
+ d->maxTimeLabel, SLOT(setEnabled(bool)));
+
+ connect(d->interpolateBox, SIGNAL(toggled(bool)),
+ d->maxTimeInput, SLOT(setEnabled(bool)));
+
+ readSettings();
+}
+
+GPSSyncDialog::~GPSSyncDialog()
+{
+ delete d->about;
+ delete d;
+}
+
+void GPSSyncDialog::slotHelp()
+{
+ KApplication::kApplication()->invokeHelp("gpssync", "kipi-plugins");
+}
+
+void GPSSyncDialog::setImages( const KURL::List& images )
+{
+ for( KURL::List::ConstIterator it = images.begin(); it != images.end(); ++it )
+ new GPSListViewItem(d->listView, d->listView->lastItem(), *it);
+
+ KIO::PreviewJob *thumbnailJob = KIO::filePreview(images, 64);
+
+ connect(thumbnailJob, SIGNAL(gotPreview(const KFileItem*, const QPixmap&)),
+ this, SLOT(slotGotThumbnail(const KFileItem*, const QPixmap&)));
+}
+
+void GPSSyncDialog::slotLoadGPXFile()
+{
+ KURL loadGPXFile = KFileDialog::getOpenURL(KGlobalSettings::documentPath(),
+ i18n("%1|GPS Exchange Format").arg("*.gpx"), this,
+ i18n("Select GPX File to Load") );
+ if( loadGPXFile.isEmpty() )
+ return;
+
+ d->gpxParser.clear();
+ bool ret = d->gpxParser.loadGPXFile(loadGPXFile);
+
+ if (!ret)
+ {
+ KMessageBox::error(this, i18n("Cannot parse %1 GPX file!")
+ .arg(loadGPXFile.fileName()), i18n("GPS Sync"));
+ enableButton(User1, false);
+ return;
+ }
+
+ if (d->gpxParser.numPoints() <= 0)
+ {
+ KMessageBox::sorry(this, i18n("The %1 GPX file do not have a date-time track to use!")
+ .arg(loadGPXFile.fileName()), i18n("GPS Sync"));
+ enableButton(User1, false);
+ return;
+ }
+
+ d->gpxFileName->setText(loadGPXFile.fileName());
+ d->gpxPointsLabel->setText(i18n("Points parsed: %1").arg(d->gpxParser.numPoints()));
+ enableButton(User1, true);
+ slotUser1();
+}
+
+void GPSSyncDialog::closeEvent(QCloseEvent *e)
+{
+ if (!e) return;
+ if (!promptUserClose())
+ {
+ e->ignore();
+ return;
+ }
+
+ saveSettings();
+ e->accept();
+}
+
+void GPSSyncDialog::slotClose()
+{
+ if (!promptUserClose()) return;
+ saveSettings();
+ KDialogBase::slotClose();
+}
+
+bool GPSSyncDialog::promptUserClose()
+{
+ // Check if one item is dirty in the list.
+
+ QListViewItemIterator it( d->listView );
+ int dirty = 0;
+
+ while ( it.current() )
+ {
+ GPSListViewItem *item = (GPSListViewItem*) it.current();
+ if (item->isDirty())
+ dirty++;
+
+ ++it;
+ }
+
+ if (dirty > 0)
+ {
+ QString msg = i18n("1 image from the list is not updated.",
+ "%n images from the list are not updated.", dirty);
+
+ if (KMessageBox::No == KMessageBox::warningYesNo(this,
+ i18n("<p>%1\n"
+ "Do you really want to close this window without applying changes?</p>")
+ .arg(msg)))
+ return false;
+ }
+
+ return true;
+}
+
+void GPSSyncDialog::readSettings()
+{
+ KConfig config("kipirc");
+ config.setGroup("GPS Sync Settings");
+ d->maxGapInput->setValue(config.readNumEntry("Max Gap Time", 30));
+ d->timeZoneCB->setCurrentItem(config.readNumEntry("Time Zone", 16)); // GMT+00:00
+ d->interpolateBox->setChecked(config.readBoolEntry("Interpolate", false));
+ d->maxTimeInput->setValue(config.readNumEntry("Max Inter Dist Time", 15));
+
+ d->maxTimeLabel->setEnabled(d->interpolateBox->isChecked());
+ d->maxTimeInput->setEnabled(d->interpolateBox->isChecked());
+ resize(configDialogSize(config, QString("GPS Sync Dialog")));
+}
+
+void GPSSyncDialog::saveSettings()
+{
+ KConfig config("kipirc");
+ config.setGroup("GPS Sync Settings");
+ config.writeEntry("Max Gap Time", d->maxGapInput->value() );
+ config.writeEntry("Time Zone", d->timeZoneCB->currentItem() );
+ config.writeEntry("Interpolate", d->interpolateBox->isChecked() );
+ config.writeEntry("Max Inter Dist Time", d->maxTimeInput->value() );
+ saveDialogSize(config, QString("GPS Sync Dialog"));
+ config.sync();
+}
+
+// Correlate the GPS positions from Pictures using a GPX file data.
+void GPSSyncDialog::slotUser1()
+{
+ int itemsUpdated = 0;
+
+ QListViewItemIterator it( d->listView );
+ while ( it.current() )
+ {
+ GPSListViewItem *item = dynamic_cast<GPSListViewItem*>(it.current());
+ GPSDataContainer gpsData;
+ QString tz = d->timeZoneCB->currentText();
+ int hh = QString(QString(tz[4])+QString(tz[5])).toInt();
+ int mm = QString(QString(tz[7])+QString(tz[8])).toInt();
+ int offset = hh*3600 + mm*60;
+
+ if (tz[3] == QChar('-'))
+ offset = (-1)*offset;
+
+ if (d->gpxParser.matchDate(item->dateTime(),
+ d->maxGapInput->value(),
+ offset,
+ d->interpolateBox->isChecked(),
+ d->maxTimeInput->value()*60,
+ gpsData))
+ {
+ item->setGPSInfo(gpsData);
+ itemsUpdated++;
+ }
+ ++it;
+ }
+
+ if (itemsUpdated == 0)
+ {
+ KMessageBox::sorry(this, i18n("Cannot find pictures to correlate with GPX file data."),
+ i18n("GPS Sync"));
+ return;
+ }
+
+ QString msg = i18n("GPS data of 1 image have been updated on the list using the GPX data file.",
+ "GPS data of %n images have been updated on the list using the GPX data file.",
+ itemsUpdated);
+ msg += '\n';
+ msg += i18n("Press Apply button to update images metadata.");
+
+ KMessageBox::information(this, msg, i18n("GPS Sync"));
+}
+
+// Start the GPS coordinates editor dialog.
+void GPSSyncDialog::slotUser2()
+{
+ if (!d->listView->currentItem())
+ {
+ KMessageBox::information(this, i18n("Please, select at least one image from "
+ "the list to edit GPS coordinates manually."), i18n("GPS Sync"));
+ return;
+ }
+
+ GPSListViewItem *item = dynamic_cast<GPSListViewItem*>(d->listView->currentItem());
+
+ GPSEditDialog dlg(this, item->GPSInfo(),
+ item->url().fileName(),
+ item->hasGPSInfo());
+
+ if (dlg.exec() == KDialogBase::Accepted)
+ {
+ QListViewItemIterator it(d->listView);
+
+ while (it.current())
+ {
+ if (it.current()->isSelected())
+ {
+ GPSListViewItem *selItem = dynamic_cast<GPSListViewItem*>(it.current());
+ selItem->setGPSInfo(dlg.getGPSInfo(), true, true);
+ }
+ ++it;
+ }
+ }
+}
+
+// Remove GPS coordinates from pictures.
+void GPSSyncDialog::slotUser3()
+{
+ if (!d->listView->currentItem())
+ {
+ KMessageBox::information(this, i18n("Please, select at least one image from "
+ "the list to remove GPS coordinates."), i18n("GPS Sync"));
+ return;
+ }
+
+ QListViewItemIterator it(d->listView);
+
+ while (it.current())
+ {
+ if (it.current()->isSelected())
+ {
+ GPSListViewItem *selItem = dynamic_cast<GPSListViewItem*>(it.current());
+ selItem->eraseGPSInfo();
+ }
+ ++it;
+ }
+}
+
+void GPSSyncDialog::slotApply()
+{
+ KURL::List images;
+
+ QListViewItemIterator it( d->listView );
+ while ( it.current() )
+ {
+ GPSListViewItem *selItem = dynamic_cast<GPSListViewItem*>(it.current());
+ d->listView->setSelected(selItem, true);
+ d->listView->ensureItemVisible(selItem);
+ selItem->writeGPSInfoToFile();
+ images.append(selItem->url());
+ ++it;
+ kapp->processEvents();
+ }
+
+ // We use kipi interface refreshImages() method to tell to host than
+ // metadata from pictures have changed and need to be re-readed.
+
+ d->interface->refreshImages(images);
+}
+
+void GPSSyncDialog::slotGotThumbnail(const KFileItem *item, const QPixmap& pix)
+{
+ QListViewItemIterator it(d->listView);
+
+ while (it.current())
+ {
+ GPSListViewItem *selItem = dynamic_cast<GPSListViewItem*>(it.current());
+ if (selItem->url() == item->url())
+ {
+ selItem->setPixmap(0, pix);
+ }
+ ++it;
+ }
+}
+
+} // NameSpace KIPIGPSSyncPlugin
diff --git a/kipi-plugins/gpssync/gpssyncdialog.h b/kipi-plugins/gpssync/gpssyncdialog.h
new file mode 100644
index 0000000..053e97a
--- /dev/null
+++ b/kipi-plugins/gpssync/gpssyncdialog.h
@@ -0,0 +1,87 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-05-16
+ * Description : a plugin to synchronize pictures with
+ * a GPS device.
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+#ifndef GPSSYNCDIALOG_H
+#define GPSSYNCDIALOG_H
+
+// KDE includes.
+
+#include <kdialogbase.h>
+#include <kurl.h>
+
+// LibKipi includes.
+
+#include <libkipi/interface.h>
+
+class QListViewItem;
+
+class KFileItem;
+
+namespace KIPIGPSSyncPlugin
+{
+
+class GPSSyncDialogPriv;
+
+class GPSSyncDialog :public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ GPSSyncDialog(KIPI::Interface* interface, QWidget* parent);
+ ~GPSSyncDialog();
+
+ void setImages(const KURL::List& images);
+
+protected:
+
+ void closeEvent(QCloseEvent *);
+
+protected slots:
+
+ void slotApply();
+ void slotHelp();
+ void slotClose();
+ void slotUser1();
+ void slotUser2();
+ void slotUser3();
+
+private slots:
+
+ void slotGotThumbnail(const KFileItem*, const QPixmap&);
+ void slotLoadGPXFile();
+
+private:
+
+ bool promptUserClose();
+ void readSettings();
+ void saveSettings();
+
+private:
+
+ GPSSyncDialogPriv *d;
+};
+
+} // NameSpace KIPIGPSSyncPlugin
+
+#endif /* GPSSYNCDIALOG_H */
diff --git a/kipi-plugins/gpssync/hi16-action-gpsimagetag.png b/kipi-plugins/gpssync/hi16-action-gpsimagetag.png
new file mode 100644
index 0000000..2d11450
--- /dev/null
+++ b/kipi-plugins/gpssync/hi16-action-gpsimagetag.png
Binary files differ
diff --git a/kipi-plugins/gpssync/hi32-action-gpsimagetag.png b/kipi-plugins/gpssync/hi32-action-gpsimagetag.png
new file mode 100644
index 0000000..64da47f
--- /dev/null
+++ b/kipi-plugins/gpssync/hi32-action-gpsimagetag.png
Binary files differ
diff --git a/kipi-plugins/gpssync/kipiplugin_gpssync.desktop b/kipi-plugins/gpssync/kipiplugin_gpssync.desktop
new file mode 100644
index 0000000..77cab68
--- /dev/null
+++ b/kipi-plugins/gpssync/kipiplugin_gpssync.desktop
@@ -0,0 +1,40 @@
+[Desktop Entry]
+Comment=KIPI plugin to Geolocalize pictures
+Comment[ca]=Connector del KIPI per a geolocalitzar fotografies
+Comment[da]=KIPI-plugin til at lokalisere billeder geografisk
+Comment[de]=Ein KIPI-Modul zur geographischen Zuordnung von Bildern
+Comment[el]=Πρόσθετο του KIPI για γεωτοποθέτηση εικόνων
+Comment[es]=Complemento de KIPI para geolocalizar imágenes
+Comment[et]=KIPI piltide geolokatsiooni plugin
+Comment[fr]=Module externe KIPI pour géolocaliser les images
+Comment[is]=KIPI íforrit til að GPS-staðsetja myndir
+Comment[it]=Plugin di KIPI per geolocalizzare le immagini
+Comment[ja]=Kipi ジオロケーションプラグイン
+Comment[nds]=KIPI-Moduul för Standöörd vun Biller
+Comment[nl]=KIPI-plugin voor het geolokaliseren van afbeeldingen
+Comment[pa]=ਭੂ-ਚਿੱਤਰਾਂ ਲਈ KIPI ਪਲੱਗਇਨ
+Comment[pl]=Wtyczka KIPI - Geolokalizacja zdjęć
+Comment[pt]='Plugin' do KIPI para localizar geograficamente as imagens
+Comment[pt_BR]=Plugin para Geolocalização de Figuras do KIPI
+Comment[sr]=KIPI прикључак за гео-локализацију слика
+Comment[sr@Latn]=KIPI priključak za geo-lokalizaciju slika
+Comment[sv]=KIPI-insticksprogram för att lokalisera bilder geografiskt
+Comment[xx]=xxKIPI plugin to Geolocalize picturesxx
+Comment[zh_CN]=KIPI 地理化图片插件
+Encoding=UTF-8
+Icon=
+Name=GPSSync
+Name[ca]=Sincronització GPS
+Name[da]=GPS-synkronisering
+Name[de]=GPS-Abgleich
+Name[el]=Συγχρονισμός GPS
+Name[fi]=GPS-synkronointi
+Name[pt]=Sincronização GPS
+Name[sv]=GPS-synkronisering
+Name[xx]=xxGPSSyncxx
+Name[zh_CN]=GPS 同步
+ServiceTypes=KIPI/Plugin
+Type=Service
+X-KDE-Library=kipiplugin_gpssync
+X-KIPI-ReqFeatures=ImagesHasTime
+author=Gilles Caulier, caulier dot gilles at gmail dot com
diff --git a/kipi-plugins/gpssync/kmlexport.cpp b/kipi-plugins/gpssync/kmlexport.cpp
new file mode 100644
index 0000000..5262140
--- /dev/null
+++ b/kipi-plugins/gpssync/kmlexport.cpp
@@ -0,0 +1,523 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-05-16
+ * Description : a tool to export GPS data to KML file.
+ *
+ * Copyright (C) 2006-2007 by Stephane Pontier <shadow dot walker at free dot fr>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+extern "C"
+{
+#include <unistd.h>
+}
+
+// Qt includes.
+
+#include <qpainter.h>
+#include <qregexp.h>
+
+// KDE includes.
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kio/job.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+
+// Libkexiv2 includes.
+
+#include <libkexiv2/kexiv2.h>
+
+// LibKipi includes
+
+#include <libkipi/plugin.h>
+#include <libkipi/batchprogressdialog.h>
+#include <libkipi/imageinfo.h>
+
+// Local includes.
+
+#include "kmlexport.h"
+
+namespace KIPIGPSSyncPlugin
+{
+
+kmlExport::kmlExport(KIPI::Interface* interface)
+{
+ m_interface = interface;
+ QWidget* parent = KApplication::kApplication()->mainWidget();
+ m_progressDialog = new KIPI::BatchProgressDialog(parent, i18n("Generating KML file..."));
+}
+
+kmlExport::~kmlExport()
+{
+ delete m_progressDialog;
+}
+
+/*!
+ \fn kmlExport::createDir(QDir dir)
+ */
+bool kmlExport::createDir(QDir dir)
+{
+ if (dir.exists()) return true;
+
+ QDir parent = dir;
+ parent.cdUp();
+ bool ok = createDir(parent);
+ if (!ok)
+ {
+ logError(i18n("Could not create '%1").arg(parent.path()));
+ return false;
+ }
+ return parent.mkdir(dir.dirName());
+}
+
+/*!
+\fn kmlExport::webifyFileName(const QString &fileName)
+ */
+QString kmlExport::webifyFileName(const QString &fileName)
+{
+ QString webFileName=fileName.lower();
+
+ // Remove potentially troublesome chars
+ webFileName=webFileName.replace(QRegExp("[^-0-9a-z]+"), "_");
+
+ return webFileName;
+}
+
+/*!
+ \fn kmlExport::generateSquareThumbnail(const QImage& fullImage, int size)
+ */
+QImage kmlExport::generateSquareThumbnail(const QImage& fullImage, int size)
+{
+ QImage image = fullImage.smoothScale(size, size, QImage::ScaleMax);
+
+ if (image.width() == size && image.height() == size)
+ {
+ return image;
+ }
+ QPixmap croppedPix(size, size);
+ QPainter painter(&croppedPix);
+
+ int sx=0, sy=0;
+ if (image.width()>size)
+ {
+ sx=(image.width() - size)/2;
+ }
+ else
+ {
+ sy=(image.height() - size)/2;
+ }
+ painter.drawImage(0, 0, image, sx, sy, size, size);
+ painter.end();
+
+ return croppedPix.convertToImage();
+}
+
+/*!
+ \fn kmlExport::generateBorderedThumbnail(const QImage& fullImage, int size)
+ */
+QImage kmlExport::generateBorderedThumbnail(const QImage& fullImage, int size)
+{
+ int image_border = 3;
+
+ // getting an image minus the border
+ QImage image = fullImage.smoothScale(size -(2*image_border), size - (2*image_border), QImage::ScaleMax);
+
+ QPixmap croppedPix(image.width() + (2*image_border), image.height() + (2*image_border));
+ QPainter painter(&croppedPix);
+
+ QColor BrushColor(255,255,255);
+ painter.fillRect(0,0,image.width() + (2*image_border),image.height() + (2*image_border),BrushColor);
+ /*! @todo add a corner to the thumbnail and a hotspot to the kml element */
+
+ painter.drawImage(image_border, image_border, image );
+ painter.end();
+
+ return croppedPix.convertToImage();
+}
+
+/*!
+\fn kmlExport::generateImagesthumb(KIPI::Interface* interface, const KURL& imageURL, QDomElement &kmlAlbum )
+ */
+void kmlExport::generateImagesthumb(KIPI::Interface* interface, const KURL& imageURL, QDomElement &kmlAlbum )
+{
+ KIPI::Interface* mInterface = interface;
+ KIPI::ImageInfo info = mInterface->info(imageURL);
+
+ // Load image
+ QString path = imageURL.path();
+ QFile imageFile(path);
+ if (!imageFile.open(IO_ReadOnly))
+ {
+ logWarning(i18n("Could not read image '%1'").arg(path));
+ return;
+ }
+
+ QString imageFormat = QImageIO::imageFormat(&imageFile);
+ if (imageFormat.isEmpty())
+ {
+ logWarning(i18n("Format of image '%1' is unknown").arg(path));
+ return;
+ }
+ imageFile.close();
+ imageFile.open(IO_ReadOnly);
+
+ QByteArray imageData = imageFile.readAll();
+ QImage image;
+ if (!image.loadFromData(imageData) )
+ {
+ logWarning(i18n("Error loading image '%1'").arg(path));
+ return;
+ }
+
+ // Process images
+ /** FIXME depending the soft used, angle could return a good value (digikam) or a value of 0 (gwenview)
+ * and, in some case the picture is not rotated as it should be.
+ */
+ if ( info.angle() != 0 )
+ {
+ QWMatrix matrix;
+ matrix.rotate( info.angle() );
+ image = image.xForm( matrix );
+ }
+ image = image.smoothScale(m_size, m_size, QImage::ScaleMax);
+
+ QImage icon;
+ if (m_optimize_googlemap)
+ {
+ icon = generateSquareThumbnail(image,m_googlemapSize);
+ }
+ else
+ {
+ // icon = image.smoothScale(m_iconSize, m_iconSize, QImage::ScaleMax);
+ icon = generateBorderedThumbnail(image, m_iconSize);
+ }
+
+ // Save images
+ /** @todo remove the extension of the file
+ * it's appear with digikam but not with gwenview
+ * which already seems to strip the extension
+ */
+ QString baseFileName = webifyFileName(info.title());
+ // baseFileName = mUniqueNameHelper.makeNameUnique(baseFileName);
+ QString fullFileName;
+ fullFileName = baseFileName + '.' + imageFormat.lower();
+ QString destPath = m_tempDestDir + m_imageDir + fullFileName;
+ if (!image.save(destPath, imageFormat.ascii(), 85))
+ {
+ // if not able to save the image, it's pointless to create a placemark
+ logWarning(i18n("Could not save image '%1' to '%2'").arg(path).arg(destPath));
+ }
+ else
+ {
+ //logInfo(i18n("Creation of picture '%1'").arg(fullFileName));
+ KExiv2Iface::KExiv2 exiv2Iface;
+ exiv2Iface.load(imageURL.path());
+ double alt, lat, lng;
+ exiv2Iface.getGPSInfo(alt, lat, lng);
+ QDomElement kmlPlacemark = addKmlElement(kmlAlbum, "Placemark");
+ addKmlTextElement(kmlPlacemark,"name",fullFileName);
+ // location and altitude
+ QDomElement kmlGeometry = addKmlElement(kmlPlacemark, "Point");
+
+ if (alt)
+ {
+ addKmlTextElement(kmlGeometry, "coordinates", QString("%1,%2,%3").arg(lng).arg(lat).arg(alt));
+ }
+ else
+ {
+ addKmlTextElement(kmlGeometry, "coordinates", QString("%1,%2").arg(lng).arg(lat));
+ }
+
+ if (m_altitudeMode == 2 )
+ {
+ addKmlTextElement(kmlGeometry, "altitudeMode", "absolute");
+ }
+ else if (m_altitudeMode == 1 )
+ {
+ addKmlTextElement(kmlGeometry, "altitudeMode", "relativeToGround");
+ }
+ else
+ {
+ addKmlTextElement(kmlGeometry, "altitudeMode", "clampToGround");
+ }
+ addKmlTextElement(kmlGeometry, "extrude", "1");
+
+ // we try to load exif value if any otherwise, try the application db
+ /** we need to take the DateTimeOriginal
+ * if we refer to http://www.exif.org/Exif2-2.PDF
+ * (standard)DateTime: is The date and time of image creation. In this standard it is the date and time the file was changed
+ * DateTimeOriginal: The date and time when the original image data was generated.
+ * For a DSC the date and time the picture was taken are recorded.
+ * DateTimeDigitized: The date and time when the image was stored as digital data.
+ * So for:
+ * - a DSC: the right time is the DateTimeDigitized which is also DateTimeOriginal
+ * if the picture has been modified the (standard)DateTime should change.
+ * - a scanned picture, the right time is the DateTimeOriginal which should also be the the DateTime
+ * the (standard)DateTime should be the same except if the picture is modified
+ * - a panorama created from several pictures, the right time is the DateTimeOriginal (average of DateTimeOriginal actually)
+ * The (standard)DateTime is the creation date of the panorama.
+ * it's seems the time to take into acccount is the DateTimeOriginal.
+ * but the exiv2Iface.getImageDateTime() return the (standard)DateTime first
+ * libkexiv2 seems to take Original dateTime first so it shoul be alright now.
+ */
+ QDateTime datetime = exiv2Iface.getImageDateTime();
+ if (datetime.isValid())
+ {
+ QDomElement kmlTimeStamp = addKmlElement(kmlPlacemark, "TimeStamp");
+ addKmlTextElement(kmlTimeStamp, "when", datetime.toString("yyyy-MM-ddThh:mm:ssZ"));
+ }
+ else if ( mInterface->hasFeature(KIPI::ImagesHasTime))
+ {
+ QDomElement kmlTimeStamp = addKmlElement(kmlGeometry, "TimeStamp");
+ addKmlTextElement(kmlTimeStamp, "when", (info.time()).toString("yyyy-MM-ddThh:mm:ssZ"));
+ }
+ QString my_description;
+ if (m_optimize_googlemap)
+ {
+ my_description = "<img src=\"" + m_UrlDestDir + m_imageDir + fullFileName + "\">";
+ }
+ else
+ {
+ my_description = "<img src=\"" + m_imageDir + fullFileName + "\">";
+ }
+ if ( m_interface->hasFeature( KIPI::ImagesHasComments ) )
+ {
+ my_description += "<br/>" + info.description() ;
+ }
+ addKmlTextElement(kmlPlacemark, "description", my_description);
+ logInfo(i18n("Creation of placemark '%1'").arg(fullFileName));
+
+ // Save icon
+ QString iconFileName = "thumb_" + baseFileName + '.' + imageFormat.lower();
+ QString destPath = m_tempDestDir + m_imageDir + iconFileName;
+ if (!icon.save(destPath, imageFormat.ascii(), 85))
+ {
+ logWarning(i18n("Could not save icon for image '%1' to '%2'").arg(path).arg(destPath));
+ }
+ else
+ {
+ //logInfo(i18n("Creation of icon '%1'").arg(iconFileName));
+ // style et icon
+ QDomElement kmlStyle = addKmlElement(kmlPlacemark, "Style");
+ QDomElement kmlIconStyle = addKmlElement(kmlStyle, "IconStyle");
+ QDomElement kmlIcon = addKmlElement(kmlIconStyle, "Icon");
+ if (m_optimize_googlemap)
+ {
+ addKmlTextElement(kmlIcon, "href", m_UrlDestDir + m_imageDir + iconFileName);
+ }
+ else
+ {
+ addKmlTextElement(kmlIcon, "href", m_imageDir + iconFileName);
+ }
+ QDomElement kmlBallonStyle = addKmlElement(kmlStyle, "BalloonStyle");
+ addKmlTextElement(kmlBallonStyle, "text", "$[description]");
+ }
+ }
+}
+
+/*!
+\fn kmlExport::addTrack(QDomElement &kmlAlbum)
+ */
+void kmlExport::addTrack(QDomElement &kmlAlbum)
+{
+ if( m_GPXFile.isEmpty() )
+ {
+ logWarning(i18n("No GPX file Chosen!"));
+ return;
+ }
+
+ m_gpxParser.clear();
+ bool ret = m_gpxParser.loadGPXFile(m_GPXFile);
+
+ if (!ret)
+ {
+ logError(i18n("Cannot parse %1 GPX file!").arg(m_GPXFile));
+ return;
+ }
+
+ if (m_gpxParser.numPoints() <= 0)
+ {
+ logError(i18n("The %1 GPX file do not have a date-time track to use!")
+ .arg(m_GPXFile));
+ return;
+ }
+
+ // create a folder that will contain tracks and points
+ QDomElement kmlFolder = addKmlElement(kmlAlbum, "Folder");
+ addKmlTextElement(kmlFolder, "name", i18n("Tracks"));
+
+ if (!m_optimize_googlemap)
+ {
+ // style of points and track
+ QDomElement kmlTrackStyle = addKmlElement(kmlAlbum, "Style");
+ kmlTrackStyle.setAttribute("id","track");
+ QDomElement kmlIconStyle = addKmlElement(kmlTrackStyle, "IconStyle");
+ QDomElement kmlIcon = addKmlElement(kmlIconStyle, "Icon");
+ //! FIXME is there a way to be sure of the location of the icon?
+ addKmlTextElement(kmlIcon, "href", "http://maps.google.com/mapfiles/kml/pal4/icon60.png");
+
+ m_gpxParser.CreateTrackPoints(kmlFolder, *kmlDocument, m_TimeZone - 12, m_GPXAltitudeMode);
+ }
+
+ // linetrack style
+ QDomElement kmlLineTrackStyle = addKmlElement(kmlAlbum, "Style");
+ kmlLineTrackStyle.setAttribute("id","linetrack");
+ QDomElement kmlLineStyle = addKmlElement(kmlLineTrackStyle, "LineStyle");
+ // the KML color is not #RRGGBB but AABBGGRR
+ QString KMLColorValue = QString("%1%2%3%4")
+ .arg((int)m_GPXOpacity*256/100, 2, 16)
+ .arg((&m_GPXColor)->blue(), 2, 16)
+ .arg((&m_GPXColor)->green(), 2, 16)
+ .arg((&m_GPXColor)->red(), 2, 16);
+ addKmlTextElement(kmlLineStyle, "color", KMLColorValue);
+ addKmlTextElement(kmlLineStyle, "width", QString("%1").arg(m_LineWidth) );
+
+ m_gpxParser.CreateTrackLine(kmlAlbum, *kmlDocument, m_GPXAltitudeMode);
+}
+
+/*!
+ \fn kmlExport::generate()
+ */
+void kmlExport::generate()
+{
+ //! @todo perform a test here before to continue.
+ createDir(m_tempDestDir + m_imageDir);
+
+ m_progressDialog->show();
+ KIPI::ImageCollection selection = m_interface->currentSelection();
+ KIPI::ImageCollection album = m_interface->currentAlbum();
+ // create the document, and it's root
+ kmlDocument = new QDomDocument("");
+ QDomImplementation impl;
+ QDomProcessingInstruction instr = kmlDocument->createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\"");
+ kmlDocument->appendChild(instr);
+ QDomElement kmlRoot = kmlDocument->createElementNS( "http://earth.google.com/kml/2.1","kml");
+ kmlDocument->appendChild( kmlRoot );
+
+ QDomElement kmlAlbum = addKmlElement( kmlRoot, "Document");
+ QDomElement kmlName= addKmlTextElement( kmlAlbum, "name", album.name());
+ QDomElement kmlDescription = addKmlHtmlElement( kmlAlbum, "description", "Created with kmlexport <a href=\"http://www.kipi-plugins.org/\">kipi-plugin</a>");
+
+ if (m_GPXtracks)
+ {
+ addTrack(kmlAlbum);
+ }
+
+ KURL::List images = selection.images();
+ int defectImage = 0;
+ int pos = 1;
+ int count = images.count();
+ KURL::List::ConstIterator imagesEnd (images.constEnd());
+ for( KURL::List::ConstIterator selIt = images.constBegin(); selIt != imagesEnd; ++selIt, ++pos)
+ {
+ KExiv2Iface::KExiv2 exiv2Iface;
+ KIPI::ImageInfo info = m_interface->info( *selIt );
+ // exiv2 load from url not image
+ KURL url = *selIt;
+ exiv2Iface.load(url.path());
+ double alt, lat, lng;
+ bool hasGPSInfo = exiv2Iface.getGPSInfo(alt, lat, lng);
+ if ( hasGPSInfo )
+ {
+ // generation de l'image et de l'icone
+ generateImagesthumb(m_interface,url,kmlAlbum);
+ }
+ else
+ {
+ logWarning(i18n("No position data for '%1'").arg(info.title()));
+ defectImage++;
+ }
+ m_progressDialog->setProgress(pos, count);
+ qApp->processEvents();
+ }
+
+ if (defectImage)
+ {
+ /** @todo if defectImage==count there are no pictures exported, does it worst to continue? */
+ QWidget* parent = KApplication::kApplication()->mainWidget();
+ KMessageBox::information(parent, i18n("No position data for 1 picture",
+ "No position data for %n pictures", defectImage));
+ }
+
+ /** @todo change to kml or kmz if compressed */
+ QFile file( m_tempDestDir + m_KMLFileName + ".kml");
+ /** @todo handle file opening problems */
+ file.open( IO_WriteOnly );
+ QTextStream stream( &file ); // we will serialize the data into the file
+ stream << kmlDocument->toString();
+ file.close();
+
+ delete kmlDocument;
+
+ KIO::moveAs(m_tempDestDir,m_baseDestDir,false);
+ logInfo(i18n("Move to final directory"));
+ m_progressDialog->close();
+}
+
+/*!
+ \fn kmlExport::getConfig()
+ */
+int kmlExport::getConfig()
+{
+ KConfig config("kipirc");
+ config.setGroup("KMLExport Settings");
+
+ m_localTarget = config.readBoolEntry("localTarget");
+ m_optimize_googlemap = config.readBoolEntry("optimize_googlemap");
+ m_iconSize = config.readNumEntry("iconSize");
+ // googlemapSize = config.readNumEntry("googlemapSize");
+ m_size = config.readNumEntry("size");
+
+ // UrlDestDir have to have the trailing
+ m_baseDestDir = config.readEntry("baseDestDir");
+ m_UrlDestDir = config.readEntry("UrlDestDir");
+ m_altitudeMode = config.readNumEntry("Altitude Mode", 0);
+ m_KMLFileName = config.readEntry("KMLFileName");
+ m_GPXtracks = config.readBoolEntry("UseGPXTracks");
+ m_GPXFile = config.readEntry("GPXFile");
+ m_TimeZone = config.readNumEntry("Time Zone", 12);
+ m_LineWidth = config.readNumEntry("Line Width", 4);
+ m_GPXColor = config.readEntry("Track Color", "#17eeee" );
+ m_GPXOpacity = config.readNumEntry("Track Opacity", 64 );
+ m_GPXAltitudeMode = config.readNumEntry("GPX Altitude Mode", 0);
+
+ KStandardDirs dir;
+ m_tempDestDir = dir.saveLocation("tmp", "kipi-kmlrexportplugin-" + QString::number(getpid()) + '/');
+ m_imageDir = "images/";
+ m_googlemapSize = 32;
+ return 1;
+}
+
+void kmlExport::logInfo(const QString& msg)
+{
+ m_progressDialog->addedAction(msg, KIPI::ProgressMessage);
+}
+
+void kmlExport::logError(const QString& msg)
+{
+ m_progressDialog->addedAction(msg, KIPI::ErrorMessage);
+}
+
+void kmlExport::logWarning(const QString& msg)
+{
+ m_progressDialog->addedAction(msg, KIPI::WarningMessage);
+ // mWarnings=true;
+}
+
+} //namespace KIPIGPSSyncPlugin
diff --git a/kipi-plugins/gpssync/kmlexport.h b/kipi-plugins/gpssync/kmlexport.h
new file mode 100644
index 0000000..0dc32f2
--- /dev/null
+++ b/kipi-plugins/gpssync/kmlexport.h
@@ -0,0 +1,195 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-05-16
+ * Description : a tool to export GPS data to KML file.
+ *
+ * Copyright (C) 2006-2007 by Stephane Pontier <shadow dot walker at free dot fr>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+#ifndef KIPIKMLEXPORTKMLEXPORT_H
+#define KIPIKMLEXPORTKMLEXPORT_H
+
+// Qt includes.
+
+#include <qcolor.h>
+#include <qdir.h>
+#include <qdom.h>
+
+// Local includes.
+
+#include "kmlgpsdataparser.h"
+
+class QImage;
+
+namespace KIPI
+{
+ class BatchProgressDialog;
+ class Interface;
+}
+
+namespace KIPIGPSSyncPlugin
+{
+
+/**
+Exporter to KML
+
+ @author KIPI dev. team
+*/
+class kmlExport
+{
+
+public:
+
+ kmlExport(KIPI::Interface* interface);
+ ~kmlExport();
+
+ bool createDir(QDir dir);
+
+ /*! generate the kml element for pictures with tumbnails
+ * @param interface the kipi interface
+ * @param KURL the URL of the picture
+ * @param kmlAlbum the album used
+ */
+ void generateImagesthumb(KIPI::Interface* interface, const KURL&, QDomElement &kmlAlbum);
+
+ /*! Produce a web-friendly file name
+ * otherwise, while google earth works fine, maps.google.com may not find pictures and thumbnail
+ * thank htmlexport
+ * @param the filename
+ * @return the webifyed filename
+ */
+ QString webifyFileName(const QString &fileName);
+
+ /*! Generate a square thumbnail from @fullImage of @size x @size pixels
+ * @param fullImage the original image
+ * @param size the size of the thumbnail
+ * @return the thumbnail
+ */
+ QImage generateSquareThumbnail(const QImage& fullImage, int size);
+
+ /*! Generate a square thumbnail from @fullImage of @size x @size pixels
+ * with a white border
+ * @param fullImage the original image
+ * @param size the size of the thumbnail
+ * @return the thumbnail
+ */
+ QImage generateBorderedThumbnail(const QImage& fullImage, int size);
+ void addTrack(QDomElement &kmlAlbum);
+ void generate();
+ int getConfig();
+
+public:
+
+ bool m_localTarget;
+ bool m_optimize_googlemap;
+ bool m_GPXtracks;
+
+ int m_iconSize;
+ int m_googlemapSize;
+ int m_size;
+ int m_altitudeMode;
+ int m_TimeZone;
+ int m_LineWidth;
+ int m_GPXOpacity;
+ int m_GPXAltitudeMode;
+
+ /** directory used in kmldocument structure */
+ QString m_imageDir;
+ QString m_GPXFile;
+ QString m_UrlDestDir;
+
+ /** temporary directory where everything will be created */
+ QString m_tempDestDir;
+
+ /** directory selected by user*/
+ QString m_baseDestDir;
+
+ QString m_imgdir;
+ QString m_KMLFileName;
+
+ QColor m_GPXColor;
+
+ KIPI::Interface *m_interface;
+
+private:
+
+ /*! the root document, used to create all QDomElements */
+ QDomDocument *kmlDocument;
+
+ /*! the GPS parsed data */
+ KMLGPSDataParser m_gpxParser;
+
+ KIPI::BatchProgressDialog *m_progressDialog;
+
+private:
+
+ void logInfo(const QString& msg);
+ void logError(const QString& msg);
+ void logWarning(const QString& msg);
+
+ /*!
+ * \fn KIPIKMLExport::kmlExport::addKmlElement(QDomElement target, QString tag)
+ * Add a new element
+ * @param target the parent element to which add the element
+ * @param tag the new element name
+ * @return the New element
+ */
+ QDomElement addKmlElement(QDomElement &target, QString tag)
+ {
+ QDomElement kmlElement = kmlDocument->createElement( tag );
+ target.appendChild( kmlElement );
+ return kmlElement;
+ }
+
+ /*!
+ * \fn KIPIKMLExport::kmlExport::addKmlTextElement(QDomElement target, QString tag, QString text)
+ * Add a new element with a text
+ * @param target the parent element to which add the element
+ * @param tag the new element name
+ * @param text the text content of the new element
+ * @return the New element
+ */
+ QDomElement addKmlTextElement(QDomElement &target, QString tag, QString text)
+ {
+ QDomElement kmlElement = kmlDocument->createElement( tag );
+ target.appendChild( kmlElement );
+ QDomText kmlTextElement = kmlDocument->createTextNode( text );
+ kmlElement.appendChild( kmlTextElement );
+ return kmlElement;
+ }
+
+ /*!
+ * \fn KIPIKMLExport::kmlExport::addKmlHtmlElement(QDomElement target, QString tag, QString text)
+ * Add a new element with html content (html entities are escaped and text is wrapped in a CDATA section)
+ * @param target the parent element to which add the element
+ * @param tag the new element name
+ * @param text the HTML content of the new element
+ * @return the New element
+ */
+ QDomElement addKmlHtmlElement(QDomElement &target, QString tag, QString text)
+ {
+ QDomElement kmlElement = kmlDocument->createElement( tag );
+ target.appendChild( kmlElement );
+ QDomText kmlTextElement = kmlDocument->createCDATASection( text );
+ kmlElement.appendChild( kmlTextElement );
+ return kmlElement;
+ }
+};
+
+} // namespace KIPIGPSSyncPlugin
+
+#endif // KIPIKMLEXPORTKMLEXPORT_H
diff --git a/kipi-plugins/gpssync/kmlexportconfig.cpp b/kipi-plugins/gpssync/kmlexportconfig.cpp
new file mode 100644
index 0000000..7e991ef
--- /dev/null
+++ b/kipi-plugins/gpssync/kmlexportconfig.cpp
@@ -0,0 +1,479 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-05-16
+ * Description : a tool to export GPS data to KML file.
+ *
+ * Copyright (C) 2006-2007 by Stephane Pontier <shadow dot walker at free dot fr>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+
+// KDE includes.
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kcolorbutton.h>
+#include <kdialog.h>
+#include <khelpmenu.h>
+#include <klocale.h>
+#include <klineedit.h>
+#include <knuminput.h>
+#include "kpaboutdata.h"
+#include <kpopupmenu.h>
+#include <kstandarddirs.h>
+#include <kurlrequester.h>
+
+// Local includes.
+
+#include "pluginsversion.h"
+#include "kmlexportconfig.h"
+#include "kmlexportconfig.moc"
+
+namespace KIPIGPSSyncPlugin
+{
+
+/*
+ * Constructs a KIPIKMLExport::KMLExportConfig which is a child of 'parent', with the
+ * name 'name'.'
+ */
+KMLExportConfig::KMLExportConfig( QWidget* parent, const char* name)
+ : KDialogBase(Plain, i18n("KML Export"),
+ Help|Ok|Cancel, Ok,
+ parent, 0, true, false)
+{
+ if ( !name ) setName( "KMLExportConfig" );
+ setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)0,
+ (QSizePolicy::SizeType)0, 0, 0, sizePolicy().hasHeightForWidth() ) );
+ KMLExportConfigLayout = new QGridLayout ( plainPage(), 1, 3, 0, spacingHint());
+
+ // --------------------------------------------------------------
+ // Target preferences
+ TargetPreferenceGroupBox = new QGroupBox(0, Qt::Vertical, i18n( "Target Preferences" ), plainPage());
+ TargetPreferenceGroupBoxLayout = new QGridLayout( TargetPreferenceGroupBox->layout(), 6, 5, KDialog::spacingHint());
+ TargetPreferenceGroupBoxLayout->setAlignment( Qt::AlignTop );
+
+ // target type
+ buttonGroupTargetType = new QButtonGroup(0, Qt::Vertical, i18n( "Target Type" ), TargetPreferenceGroupBox, "buttonGroupTargetType" );
+ buttonGroupTargetTypeLayout = new QGridLayout( buttonGroupTargetType->layout(), 2, 1, KDialog::spacingHint() );
+ buttonGroupTargetTypeLayout->setAlignment( Qt::AlignTop );
+
+ LocalTargetRadioButton_ = new QRadioButton( i18n( "&Local or web target used by GoogleEarth" ),
+ buttonGroupTargetType, "LocalTargetRadioButton_" );
+ LocalTargetRadioButton_->setChecked( true );
+ buttonGroupTargetTypeLayout->addWidget( LocalTargetRadioButton_, 0, 0 );
+
+ GoogleMapTargetRadioButton_ = new QRadioButton( i18n( "Web target used by GoogleMap" ),
+ buttonGroupTargetType, "GoogleMapTargetRadioButton_" );
+ buttonGroupTargetTypeLayout->addWidget( GoogleMapTargetRadioButton_, 1, 0 );
+ QToolTip::add( GoogleMapTargetRadioButton_, i18n(
+ "When using GoogleMap, all image must have complete URL, icons are squared and when drawing a track, only linetrack is exported" ) );
+
+ // --------------------------------------------------------------
+ // target preference, suite
+ TargetPreferenceGroupBoxLayout->addMultiCellWidget( buttonGroupTargetType, 0, 1, 0, 4 );
+
+ QLabel *AltitudeLabel_ = new QLabel(i18n("Picture altitude" ),
+ TargetPreferenceGroupBox, "AltitudeLabel_");
+ TargetPreferenceGroupBoxLayout->addMultiCellWidget( AltitudeLabel_, 2, 2, 0, 4 );
+ AltitudeCB_ = new QComboBox( false, TargetPreferenceGroupBox );
+ AltitudeCB_->insertItem(i18n("clamp to ground"));
+ AltitudeCB_->insertItem(i18n("relative to ground"));
+ AltitudeCB_->insertItem(i18n("absolute"));
+ QWhatsThis::add(AltitudeCB_, i18n("<p>Specifies how pictures are displayed"
+ "<dl><dt>clamp to ground (default)</dt>"
+ "<dd>Indicates to ignore an altitude specification</dd>"
+ "<dt>relative to ground</dt>"
+ "<dd>Sets the altitude of the element relative to the actual ground "
+ "elevation of a particular location.</dd>"
+ "<dt>absolute</dt>"
+ "<dd>Sets the altitude of the coordinate relative to sea level, regardless "
+ "of the actual elevation of the terrain beneath the element.</dd></dl>"));
+ TargetPreferenceGroupBoxLayout->addMultiCellWidget( AltitudeCB_, 2, 2, 2, 4 );
+
+ destinationDirectoryLabel_ = new QLabel( i18n( "Destination directory" ),
+ TargetPreferenceGroupBox, "destinationDirectoryLabel_" );
+ TargetPreferenceGroupBoxLayout->addMultiCellWidget( destinationDirectoryLabel_, 3, 3, 0, 2 );
+
+ // DestinationDirectory_ = new QLineEdit( TargetPreferenceGroupBox, "DestinationDirectory_" );
+ DestinationDirectory_= new KURLRequester( TargetPreferenceGroupBox, "DestinationDirectory_");
+ DestinationDirectory_->setCaption(i18n("Select a directory to save the kml file and pictures"));
+ DestinationDirectory_->setMode(KFile::Directory | KFile::LocalOnly );
+ TargetPreferenceGroupBoxLayout->addMultiCellWidget( DestinationDirectory_, 3, 3, 3, 4 );
+
+ DestinationUrlLabel_ = new QLabel( i18n( "Destination URL" ),
+ TargetPreferenceGroupBox, "DestinationUrlLabel_" );
+ TargetPreferenceGroupBoxLayout->addMultiCellWidget( DestinationUrlLabel_, 4, 4, 0, 1 );
+
+ DestinationURL_ = new QLineEdit( TargetPreferenceGroupBox, "DestinationURL_" );
+
+ TargetPreferenceGroupBoxLayout->addMultiCellWidget( DestinationURL_, 4, 4, 2, 4 );
+ FileNameLabel_ = new QLabel( i18n( "File name" ),
+ TargetPreferenceGroupBox, "FileNameLabel_" );
+ TargetPreferenceGroupBoxLayout->addWidget( FileNameLabel_, 5, 0 );
+
+ FileName_ = new QLineEdit( TargetPreferenceGroupBox, "FileName_" );
+ TargetPreferenceGroupBoxLayout->addMultiCellWidget( FileName_, 5, 5, 1, 4 );
+
+ KMLExportConfigLayout->addWidget( TargetPreferenceGroupBox, 0, 0 );
+
+ // --------------------------------------------------------------
+ // Sizes
+ QGroupBox *SizeGroupBox = new QGroupBox(0, Qt::Vertical, i18n( "Sizes" ), plainPage() );
+ SizeGroupBox->setColumnLayout(0, Qt::Vertical );
+ SizeGroupBoxLayout = new QGridLayout( SizeGroupBox->layout(), 2, 3, KDialog::spacingHint() );
+ SizeGroupBoxLayout->setAlignment( Qt::AlignTop );
+
+ IconSizeLabel = new QLabel( i18n( "Icon size" ),
+ SizeGroupBox, "IconSizeLabel" );
+ SizeGroupBoxLayout->addWidget( IconSizeLabel, 0, 0 );
+
+ IconSizeInput_ = new KIntNumInput( SizeGroupBox, "IconSizeInput_" );
+ IconSizeInput_->setValue( 33 );
+ SizeGroupBoxLayout->addWidget( IconSizeInput_, 0, 1 );
+
+ spacer3 = new QSpacerItem( 191, 21, QSizePolicy::Expanding, QSizePolicy::Minimum );
+ SizeGroupBoxLayout->addItem( spacer3, 0, 2 );
+
+ ImageSizeLabel = new QLabel( i18n( "Image size" ),
+ SizeGroupBox, "ImageSizeLabel" );
+ SizeGroupBoxLayout->addWidget( ImageSizeLabel, 1, 0 );
+
+ ImageSizeInput_ = new KIntNumInput( SizeGroupBox, "ImageSizeInput_" );
+ ImageSizeInput_->setValue( 320 );
+ SizeGroupBoxLayout->addWidget( ImageSizeInput_, 1, 1 );
+
+ spacer4 = new QSpacerItem( 191, 20, QSizePolicy::Expanding, QSizePolicy::Minimum );
+ SizeGroupBoxLayout->addItem( spacer4, 1, 2 );
+
+ KMLExportConfigLayout->addWidget( SizeGroupBox, 1, 0 );
+
+ // --------------------------------------------------------------
+ // GPX Tracks
+ QGroupBox *GPXTracksGroupBox = new QGroupBox(0, Qt::Vertical, i18n( "GPX Tracks" ), plainPage());
+ QGridLayout *GPXTracksGroupBoxLayout = new QGridLayout(GPXTracksGroupBox->layout(), 5, 4,
+ KDialog::spacingHint());
+ GPXTracksGroupBoxLayout->setAlignment( Qt::AlignTop );
+
+ // add a gpx track checkbox
+ GPXTracksCheckBox_ = new QCheckBox( i18n( "Draw GPX track" ), GPXTracksGroupBox, "GPXTracksCheckBox");
+ GPXTracksGroupBoxLayout->addMultiCellWidget( GPXTracksCheckBox_, 0, 0, 0, 3);
+
+ // file selector
+ GPXFileLabel_ = new QLabel( i18n( "GPX file" ),
+ GPXTracksGroupBox, "GPXFileLabel_" );
+ GPXTracksGroupBoxLayout->addMultiCellWidget( GPXFileLabel_, 1, 1, 0, 0);
+
+ GPXFileKURLRequester_ = new KURLRequester( GPXTracksGroupBox, "GPXFileKURLRequester" );
+ GPXFileKURLRequester_->setFilter(i18n("%1|GPS Exchange Format").arg("*.gpx"));
+ GPXFileKURLRequester_->setCaption(i18n("Select GPX File to Load"));
+ GPXTracksGroupBoxLayout->addMultiCellWidget( GPXFileKURLRequester_, 1, 1, 1, 3);
+
+ timeZoneLabel_ = new QLabel(i18n("Time zone"), GPXTracksGroupBox);
+ GPXTracksGroupBoxLayout->addMultiCellWidget( timeZoneLabel_, 2, 2, 0, 0);
+ timeZoneCB = new QComboBox( false, GPXTracksGroupBox );
+ timeZoneCB->insertItem(i18n("GMT-12:00"), 0);
+ timeZoneCB->insertItem(i18n("GMT-11:00"), 1);
+ timeZoneCB->insertItem(i18n("GMT-10:00"), 2);
+ timeZoneCB->insertItem(i18n("GMT-09:00"), 3);
+ timeZoneCB->insertItem(i18n("GMT-08:00"), 4);
+ timeZoneCB->insertItem(i18n("GMT-07:00"), 5);
+ timeZoneCB->insertItem(i18n("GMT-06:00"), 6);
+ timeZoneCB->insertItem(i18n("GMT-05:00"), 7);
+ timeZoneCB->insertItem(i18n("GMT-04:00"), 8);
+ timeZoneCB->insertItem(i18n("GMT-03:00"), 9);
+ timeZoneCB->insertItem(i18n("GMT-02:00"), 10);
+ timeZoneCB->insertItem(i18n("GMT-01:00"), 11);
+ timeZoneCB->insertItem(i18n("GMT"), 12);
+ timeZoneCB->insertItem(i18n("GMT+01:00"), 13);
+ timeZoneCB->insertItem(i18n("GMT+02:00"), 14);
+ timeZoneCB->insertItem(i18n("GMT+03:00"), 15);
+ timeZoneCB->insertItem(i18n("GMT+04:00"), 16);
+ timeZoneCB->insertItem(i18n("GMT+05:00"), 17);
+ timeZoneCB->insertItem(i18n("GMT+06:00"), 18);
+ timeZoneCB->insertItem(i18n("GMT+07:00"), 19);
+ timeZoneCB->insertItem(i18n("GMT+08:00"), 20);
+ timeZoneCB->insertItem(i18n("GMT+09:00"), 21);
+ timeZoneCB->insertItem(i18n("GMT+10:00"), 22);
+ timeZoneCB->insertItem(i18n("GMT+11:00"), 23);
+ timeZoneCB->insertItem(i18n("GMT+12:00"), 24);
+ timeZoneCB->insertItem(i18n("GMT+13:00"), 25);
+ timeZoneCB->insertItem(i18n("GMT+14:00"), 26);
+ QWhatsThis::add(timeZoneCB, i18n("<p>Sets the time zone of the camera during "
+ "picture shooting, so that the time stamps of the GPS "
+ "can be converted to match the local time"));
+ GPXTracksGroupBoxLayout->addMultiCellWidget( timeZoneCB, 2, 2, 1, 3);
+
+ GPXLineWidthLabel_ = new QLabel( i18n( "Track width" ),
+ GPXTracksGroupBox, "GPXLineWidthLabel_" );
+ GPXTracksGroupBoxLayout->addMultiCellWidget( GPXLineWidthLabel_, 3, 3, 0, 0);
+ GPXLineWidthInput_ = new KIntNumInput( GPXTracksGroupBox, "GPXLineWidthInput_" );
+ GPXLineWidthInput_->setValue( 4 );
+ GPXTracksGroupBoxLayout->addMultiCellWidget( GPXLineWidthInput_, 3, 3, 1, 3);
+
+ GPXColorLabel_ = new QLabel( i18n( "Track color" ),
+ GPXTracksGroupBox, "GPXColorLabel_" );
+ GPXTracksGroupBoxLayout->addWidget( GPXColorLabel_, 4, 0 );
+ GPXTrackColor_ = new KColorButton(QColor("#ffffff"), GPXTracksGroupBox);
+ GPXTracksGroupBoxLayout->addWidget( GPXTrackColor_, 4, 1 );
+
+ GPXTracksOpacityInput_ = new KIntNumInput( GPXTracksGroupBox , "GPXTracksOpacityInput_" );
+ GPXTracksOpacityInput_->setRange( 0, 100, 1, false );
+ GPXTracksOpacityInput_->setValue( 100 );
+ GPXTracksOpacityInput_->setLabel( i18n( "Opacity:" ), AlignVCenter);
+ GPXTracksOpacityInput_->setSuffix( QString::fromAscii( "%" ) );
+ GPXTracksGroupBoxLayout->addMultiCellWidget( GPXTracksOpacityInput_, 4, 4, 2, 3);
+
+ GPXAltitudeLabel_ = new QLabel( i18n( "Track altitude" ),
+ GPXTracksGroupBox, "GPXAltitudeLabel_" );
+ GPXTracksGroupBoxLayout->addMultiCellWidget( GPXAltitudeLabel_, 5, 5, 0, 0);
+ GPXAltitudeCB_ = new QComboBox( false, GPXTracksGroupBox );
+ GPXAltitudeCB_->insertItem(i18n("clamp to ground"));
+ GPXAltitudeCB_->insertItem(i18n("relative to ground"));
+ GPXAltitudeCB_->insertItem(i18n("absolute"));
+ QWhatsThis::add(GPXAltitudeCB_, i18n("<p>Specifies how the points are displayed"
+ "<dl><dt>clamp to ground (default)</dt>"
+ "<dd>Indicates to ignore an altitude specification</dd>"
+ "<dt>relative to ground</dt>"
+ "<dd>Sets the altitude of the element relative to the actual ground "
+ "elevation of a particular location.</dd>"
+ "<dt>absolute</dt>"
+ "<dd>Sets the altitude of the coordinate relative to sea level, "
+ "regardless of the actual elevation of the terrain beneath "
+ "the element.</dd></dl>"));
+ GPXTracksGroupBoxLayout->addMultiCellWidget( GPXAltitudeCB_, 5, 5, 1, 3);
+
+ KMLExportConfigLayout->addWidget( GPXTracksGroupBox, 2, 0 );
+
+ connect( GoogleMapTargetRadioButton_, SIGNAL( toggled(bool) ),
+ this, SLOT( GoogleMapTargetRadioButton__toggled(bool) ) );
+
+ connect( GPXTracksCheckBox_, SIGNAL( toggled(bool) ),
+ this, SLOT( KMLTracksCheckButton__toggled(bool) ) );
+
+ // --------------------------------------------------------------
+ // About data and help button.
+ m_about = new KIPIPlugins::KPAboutData(I18N_NOOP("KML Export"),
+ 0,
+ KAboutData::License_GPL,
+ I18N_NOOP("A Kipi plugin for kml exporting"),
+ "(c) 2006-2007, Stéphane Pontier");
+
+ m_about->addAuthor("Stéphane Pontier", I18N_NOOP("Author"),
+ "shadow.walker@free.fr");
+
+ KHelpMenu* helpMenu = new KHelpMenu(this, m_about, false);
+ helpMenu->menu()->removeItemAt(0);
+ helpMenu->menu()->insertItem(i18n("Plugin Handbook"), this, SLOT(slotHelp()), 0, -1, 0);
+ actionButton(Help)->setPopup( helpMenu->menu() );
+
+ // --------------------------------------------------------------
+ // Configuration file management
+
+ config_ = new KConfig("kipirc");
+ config_->setGroup("KMLExport Settings");
+
+ readSettings();
+
+ // --------------------------------------------------------------
+ // Just to initialize the UI
+ GoogleMapTargetRadioButton__toggled(true);
+ KMLTracksCheckButton__toggled(false);
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+KMLExportConfig::~KMLExportConfig()
+{
+ // no need to delete child widgets, Qt does it all for us
+ if(config_)
+ delete config_;
+ delete m_about;
+}
+
+void KMLExportConfig::slotOk()
+ //void KMLExportConfig::slotOkClicked()
+{
+ saveSettings();
+
+ emit okButtonClicked();
+ accept();
+}
+
+void KMLExportConfig::slotHelp()
+{
+ KApplication::kApplication()->invokeHelp("KMLExport", "kipi-plugins");
+}
+
+void KMLExportConfig::GoogleMapTargetRadioButton__toggled(bool)
+{
+ if (GoogleMapTargetRadioButton_->isChecked())
+ {
+ DestinationUrlLabel_->setEnabled(true);
+ DestinationURL_->setEnabled(true);
+ IconSizeLabel->setEnabled(false);
+ IconSizeInput_->setEnabled(false);
+ }
+ else
+ {
+ DestinationUrlLabel_->setEnabled(false);
+ DestinationURL_->setEnabled(false);
+ IconSizeLabel->setEnabled(true);
+ IconSizeInput_->setEnabled(true);
+ }
+}
+
+void KMLExportConfig::KMLTracksCheckButton__toggled(bool)
+{
+ if (GPXTracksCheckBox_->isChecked())
+ {
+ GPXFileKURLRequester_->setEnabled(true);
+ GPXFileLabel_->setEnabled(true);
+ timeZoneCB->setEnabled(true);
+ GPXColorLabel_->setEnabled(true);
+ GPXAltitudeLabel_->setEnabled(true);
+ timeZoneLabel_->setEnabled(true);
+ GPXAltitudeCB_->setEnabled(true);
+ GPXTrackColor_->setEnabled(true);
+ GPXLineWidthLabel_->setEnabled(true);
+ GPXLineWidthInput_->setEnabled(true);
+ GPXTracksOpacityInput_->setEnabled(true);
+ }
+ else
+ {
+ GPXFileKURLRequester_->setEnabled(false);
+ GPXFileLabel_->setEnabled(false);
+ timeZoneCB->setEnabled(false);
+ GPXColorLabel_->setEnabled(false);
+ GPXAltitudeLabel_->setEnabled(false);
+ timeZoneLabel_->setEnabled(false);
+ GPXAltitudeCB_->setEnabled(false);
+ GPXTrackColor_->setEnabled(false);
+ GPXLineWidthLabel_->setEnabled(false);
+ GPXLineWidthInput_->setEnabled(false);
+ GPXTracksOpacityInput_->setEnabled(false);
+ }
+}
+
+void KMLExportConfig::saveSettings()
+{
+ if (!config_) return;
+
+ config_->writeEntry("localTarget", LocalTargetRadioButton_->isChecked());
+ config_->writeEntry("optimize_googlemap", GoogleMapTargetRadioButton_->isChecked());
+ config_->writeEntry("iconSize", IconSizeInput_->value());
+ config_->writeEntry("size", ImageSizeInput_->value());
+ QString destination = DestinationDirectory_->url();
+ if (!destination.endsWith("/"))
+ {
+ destination.append("/");
+ }
+ config_->writeEntry("baseDestDir",destination);
+ QString url = DestinationURL_->text();
+ if (!url.endsWith("/"))
+ {
+ url.append("/");
+ }
+ config_->writeEntry("UrlDestDir",url);
+ config_->writeEntry("KMLFileName",FileName_->text());
+ config_->writeEntry("Altitude Mode", AltitudeCB_->currentItem() );
+
+ config_->writeEntry("UseGPXTracks", GPXTracksCheckBox_->isChecked());
+
+ config_->writeEntry("GPXFile", GPXFileKURLRequester_->lineEdit()->originalText());
+ config_->writeEntry("Time Zone", timeZoneCB->currentItem() );
+ config_->writeEntry("Line Width", GPXLineWidthInput_->value());
+ config_->writeEntry("Track Color", GPXTrackColor_->color().name () );
+ config_->writeEntry("Track Opacity", GPXTracksOpacityInput_->value() );
+ config_->writeEntry("GPX Altitude Mode", GPXAltitudeCB_->currentItem() );
+
+ config_->sync();
+}
+
+void KMLExportConfig::readSettings()
+{
+ bool localTarget;
+ bool optimize_googlemap;
+ int iconSize;
+ // int googlemapSize;
+ int size;
+ QString UrlDestDir;
+ QString baseDestDir;
+ QString KMLFileName;
+ int AltitudeMode;
+
+ bool GPXtracks;
+ QString GPXFile;
+ int TimeZone;
+ int LineWidth;
+ QString GPXColor;
+ int GPXOpacity;
+ int GPXAltitudeMode;
+
+ localTarget = config_->readBoolEntry("localTarget", true);
+ optimize_googlemap = config_->readBoolEntry("optimize_googlemap", false);
+ iconSize = config_->readNumEntry("iconSize", 33);
+ // not saving this size as it should not change
+ // googlemapSize = config_->readNumEntry("googlemapSize", 32);
+ size = config_->readNumEntry("size", 320);
+ // UrlDestDir have to have the trailing /
+ baseDestDir = config_->readEntry("baseDestDir", "/tmp/");
+ UrlDestDir = config_->readEntry("UrlDestDir", "http://www.example.com/");
+ KMLFileName = config_->readEntry("KMLFileName", "kmldocument");
+ AltitudeMode = config_->readNumEntry("Altitude Mode", 0);
+
+ GPXtracks = config_->readBoolEntry("UseGPXTracks", false);
+ GPXFile = config_->readEntry("GPXFile", "");
+ TimeZone = config_->readNumEntry("Time Zone", 12);
+ LineWidth = config_->readNumEntry("Line Width", 4);
+ GPXColor = config_->readEntry("Track Color", "#17eeee" );
+ GPXOpacity = config_->readNumEntry("Track Opacity", 64 );
+ GPXAltitudeMode = config_->readNumEntry("GPX Altitude Mode", 0);
+
+ // -- Apply Settings to widgets ------------------------------
+
+ LocalTargetRadioButton_->setChecked(localTarget);
+ GoogleMapTargetRadioButton_->setChecked(optimize_googlemap);
+
+ IconSizeInput_->setValue(iconSize);
+ ImageSizeInput_->setValue(size);
+
+ AltitudeCB_->setCurrentItem(AltitudeMode);
+ DestinationDirectory_->setURL(baseDestDir);
+ DestinationURL_->setText(UrlDestDir);
+ FileName_->setText(KMLFileName);
+
+ timeZoneCB->setCurrentItem(TimeZone);
+ GPXLineWidthInput_->setValue(LineWidth);
+ GPXTrackColor_->setColor(GPXColor);
+ GPXTracksOpacityInput_->setValue(GPXOpacity);
+ GPXAltitudeCB_->setCurrentItem(GPXAltitudeMode);
+}
+
+} //namespace KIPIGPSSyncPlugin
diff --git a/kipi-plugins/gpssync/kmlexportconfig.h b/kipi-plugins/gpssync/kmlexportconfig.h
new file mode 100644
index 0000000..54841b7
--- /dev/null
+++ b/kipi-plugins/gpssync/kmlexportconfig.h
@@ -0,0 +1,138 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-05-16
+ * Description : a tool to export GPS data to KML file.
+ *
+ * Copyright (C) 2006-2007 by Stephane Pontier <shadow dot walker at free dot fr>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+#ifndef KMLEXPORTCONFIG_H
+#define KMLEXPORTCONFIG_H
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+class QButtonGroup;
+class QCheckBox;
+class QComboBox;
+class QGridLayout;
+class QGroupBox;
+class QLabel;
+class QLineEdit;
+class QRadioButton;
+class QSpacerItem;
+
+class KColorButton;
+class KIntNumInput;
+class KURLRequester;
+
+namespace KIPIPlugins
+{
+ class KPAboutData;
+}
+
+namespace KIPIGPSSyncPlugin
+{
+
+class KMLExportConfig : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ explicit KMLExportConfig( QWidget* parent = 0, const char* name = 0);
+ ~KMLExportConfig();
+
+public:
+
+ QLabel *ImageSizeLabel;
+ QLabel *IconSizeLabel;
+ QLabel *destinationDirectoryLabel_;
+ QLabel *FileNameLabel_;
+ QLabel *DestinationUrlLabel_;
+ QLabel *GPXFileLabel_;
+ QLabel *timeZoneLabel_;
+ QLabel *GPXLineWidthLabel_;
+ QLabel *GPXColorLabel_;
+ QLabel *GPXTracksOpacityLabel_;
+ QLabel *GPXAltitudeLabel_;
+
+ QGroupBox *TargetPreferenceGroupBox;
+
+ QButtonGroup *buttonGroupTargetType;
+
+ QRadioButton *LocalTargetRadioButton_;
+ QRadioButton *GoogleMapTargetRadioButton_;
+
+ QLineEdit *DestinationURL_;
+ QLineEdit *FileName_;
+
+ QCheckBox *GPXTracksCheckBox_;
+
+ QComboBox *AltitudeCB_;
+ QComboBox *timeZoneCB;
+ QComboBox *GPXAltitudeCB_;
+
+ KColorButton *GPXTrackColor_;
+
+ KURLRequester *DestinationDirectory_;
+ KURLRequester *GPXFileKURLRequester_;
+
+ KIntNumInput *ImageSizeInput_;
+ KIntNumInput *IconSizeInput_;
+ KIntNumInput *GPXTracksOpacityInput_;
+ KIntNumInput *GPXLineWidthInput_;
+
+public slots:
+
+ void GoogleMapTargetRadioButton__toggled(bool);
+ void KMLTracksCheckButton__toggled(bool);
+
+signals:
+
+ void okButtonClicked(); // Signal needed by plugin_kmlexport class
+
+protected:
+
+ QSpacerItem *spacer3;
+ QSpacerItem *spacer4;
+
+ QGridLayout *KMLExportConfigLayout;
+ QGridLayout *SizeGroupBoxLayout;
+ QGridLayout *TargetPreferenceGroupBoxLayout;
+ QGridLayout *buttonGroupTargetTypeLayout;
+
+ KConfig *config_;
+
+ KIPIPlugins::KPAboutData *m_about;
+
+protected:
+
+ void saveSettings();
+ void readSettings();
+
+protected slots:
+
+ void slotOk();
+ // void slotOkClicked();
+ void slotHelp();
+};
+
+} // namespace
+
+#endif // KMLEXPORTCONFIG_H
diff --git a/kipi-plugins/gpssync/kmlgpsdataparser.cpp b/kipi-plugins/gpssync/kmlgpsdataparser.cpp
new file mode 100644
index 0000000..4a796a9
--- /dev/null
+++ b/kipi-plugins/gpssync/kmlgpsdataparser.cpp
@@ -0,0 +1,141 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-05-16
+ * Description : a tool to export GPS data to KML file.
+ *
+ * Copyright (C) 2006-2007 by Stephane Pontier <shadow dot walker at free dot fr>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+// Local includes.
+
+#include "kmlgpsdataparser.h"
+
+// KDE includes.
+
+#include <kdebug.h>
+#include <klocale.h>
+
+namespace KIPIGPSSyncPlugin
+{
+
+KMLGPSDataParser::KMLGPSDataParser()
+ : GPSDataParser()
+{
+}
+
+KMLGPSDataParser::~KMLGPSDataParser()
+{
+}
+
+QString KMLGPSDataParser::lineString()
+{
+ QString line = "";
+ // cache the end to not recalculate it with large number of points
+ GPSDataMap::ConstIterator end (m_GPSDataMap.constEnd());
+ for (GPSDataMap::ConstIterator it = m_GPSDataMap.constBegin();
+ it != end; ++it )
+ {
+ line += QString("%1,%2,%3 ").arg(it.data().longitude()).arg(it.data().latitude()).arg(it.data().altitude());
+ }
+ return line;
+}
+
+/*!
+\fn void KIPIGPSSyncPlugin::KMLGPSDataParser::CreateTrackLine(QDomElement &parent, QDomDocument &root, int altitudeMode)
+ */
+void KIPIGPSSyncPlugin::KMLGPSDataParser::CreateTrackLine(QDomElement &parent, QDomDocument &root, int altitudeMode)
+{
+ kmlDocument = &root;
+
+ // add the linetrack
+ QDomElement kmlPlacemark = addKmlElement(parent, "Placemark");
+ addKmlTextElement(kmlPlacemark, "name", i18n("Track"));
+ QDomElement kmlLineString = addKmlElement(kmlPlacemark, "LineString");
+ addKmlTextElement(kmlLineString, "coordinates", lineString());
+ addKmlTextElement(kmlPlacemark, "styleUrl", "#linetrack");
+ if (altitudeMode == 2 )
+ {
+ addKmlTextElement(kmlLineString, "altitudeMode", "absolute");
+ }
+ else if (altitudeMode == 1 )
+ {
+ addKmlTextElement(kmlLineString, "altitudeMode", "relativeToGround");
+ }
+ else
+ {
+ addKmlTextElement(kmlLineString, "altitudeMode", "clampToGround");
+ }
+}
+
+/*!
+\fn void KIPIGPSSyncPlugin::KMLGPSDataParser::CreateTrackPoints(QDomElement &parent, QDomDocument &root, int timeZone, int altitudeMode)
+ */
+void KIPIGPSSyncPlugin::KMLGPSDataParser::CreateTrackPoints(QDomElement &parent, QDomDocument &root,
+ int timeZone, int altitudeMode)
+{
+ kmlDocument = &root;
+ kdDebug( 51001 ) << "creation d'un trackpoint" << endl;
+
+ // create the points
+ QDomElement kmlPointsFolder = addKmlElement(parent, "Folder");
+ addKmlTextElement(kmlPointsFolder, "name", i18n("Points"));
+ addKmlTextElement(kmlPointsFolder, "visibility", "0");
+ addKmlTextElement(kmlPointsFolder, "open", "0");
+ int i = 0;
+ // cache the end to not recalculate it with large number of points
+ GPSDataMap::ConstIterator end (m_GPSDataMap.constEnd());
+ for (GPSDataMap::ConstIterator it = m_GPSDataMap.constBegin();
+ it != end; ++it, i++)
+ {
+ QDomElement kmlPointPlacemark = addKmlElement(kmlPointsFolder, "Placemark");
+ addKmlTextElement(kmlPointPlacemark, "name", QString("%1 %2 ").arg(i18n("Point")).arg(i));
+ addKmlTextElement(kmlPointPlacemark, "styleUrl", "#track");
+ QDomElement kmlTimeStamp = addKmlElement(kmlPointPlacemark, "TimeStamp");
+ // GPS device are sync in time by satellite using GMT time.
+ // If the camera time is different than GMT time, we want to
+ // convert the GPS time to localtime of the picture to be display
+ // in the same timeframe
+ QDateTime GPSLocalizedTime = it.key().addSecs(timeZone*3600);
+
+ addKmlTextElement(kmlTimeStamp, "when", GPSLocalizedTime.toString("yyyy-MM-ddThh:mm:ssZ"));
+ QDomElement kmlGeometry = addKmlElement(kmlPointPlacemark, "Point");
+ addKmlTextElement(kmlPointPlacemark, "visibility", "0");
+ if (it.data().latitude())
+ {
+ addKmlTextElement(kmlGeometry, "coordinates",
+ QString("%1,%2,%3").arg(it.data().longitude()).arg(it.data().latitude()).arg(it.data().altitude()));
+ }
+ else
+ {
+ addKmlTextElement(kmlGeometry, "coordinates", QString("%1,%2").arg(it.data().longitude()).arg(it.data().latitude()));
+ }
+ if (altitudeMode == 2 )
+ {
+ addKmlTextElement(kmlGeometry, "altitudeMode", "absolute");
+ }
+ else if (altitudeMode == 1 )
+ {
+ addKmlTextElement(kmlGeometry, "altitudeMode", "relativeToGround");
+ }
+ else
+ {
+ addKmlTextElement(kmlGeometry, "altitudeMode", "clampToGround");
+ }
+ }
+}
+
+} // namespace KIPIGPSSyncPlugin
diff --git a/kipi-plugins/gpssync/kmlgpsdataparser.h b/kipi-plugins/gpssync/kmlgpsdataparser.h
new file mode 100644
index 0000000..e3e271e
--- /dev/null
+++ b/kipi-plugins/gpssync/kmlgpsdataparser.h
@@ -0,0 +1,107 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-05-16
+ * Description : a tool to export GPS data to KML file.
+ *
+ * Copyright (C) 2006-2007 by Stephane Pontier <shadow dot walker at free dot fr>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+#ifndef KIPIGPSSYNCPLUGINKMLGPSDATAPARSER_H
+#define KIPIGPSSYNCPLUGINKMLGPSDATAPARSER_H
+
+// Local includes.
+
+#include "gpsdataparser.h"
+
+// Qt includes.
+
+#include <qdom.h>
+
+namespace KIPIGPSSyncPlugin
+{
+
+/*! a classe derivated from GPSDataParser mainly to transform GPS data to KML
+ * @author Stéphane Pontier shadow.walker@free.fr
+ */
+class KMLGPSDataParser : public GPSDataParser
+{
+
+public:
+
+ KMLGPSDataParser();
+ ~KMLGPSDataParser();
+
+ /*! KIPIGPSSyncPlugin::KMLGPSDataParser::lineString()
+ * @return the string containing the time ordered point (lon,lat,alt)
+ */
+ QString lineString();
+ /*! Create a KML Element that will contain the linetrace of the GPS
+ * @param parent the QDomElement to which the track will be added
+ * @param root the QDomDocument used to create all elements
+ * @param altitudeMode altitude mode of the line and points
+ */
+
+ void CreateTrackLine(QDomElement &parent, QDomDocument &root, int altitudeMode);
+ /*! Create a KML Element that will contain the points and of the GPS
+ * @param parent the QDomElement to which the track will be added
+ * @param root the QDomDocument used to create all elements
+ * @param timeZone the Timezone of the pictures
+ * @param altitudeMode altitude mode of the line and points
+ */
+ void CreateTrackPoints(QDomElement &parent, QDomDocument &root, int timeZone, int altitudeMode);
+
+private:
+
+ /*! @todo maybe initialize it in the constructor */
+ /*! the root document, used to create all QDomElements */
+ QDomDocument *kmlDocument;
+
+ /*!
+ \fn QDomElement KIPIGPSSyncPlugin::KMLGPSDataParser::addKmlElement(QDomElement target, QString tag)
+ * Add a new element
+ * @param target the parent element to which add the element
+ * @param tag the new element name
+ * @return the New element
+ */
+ QDomElement addKmlElement(QDomElement &target, QString tag)
+ {
+ QDomElement kmlElement = kmlDocument->createElement( tag );
+ target.appendChild( kmlElement );
+ return kmlElement;
+ }
+
+ /*!
+ \fn QDomElement KIPIGPSSyncPlugin::KMLGPSDataParser::addKmlTextElement(QDomElement target, QString tag, QString text)
+ * Add a new element with a text
+ * @param target the parent element to which add the element
+ * @param tag the new element name
+ * @param text the text content of the new element
+ * @return the New element
+ */
+ QDomElement addKmlTextElement(QDomElement &target, QString tag, QString text)
+ {
+ QDomElement kmlElement = kmlDocument->createElement( tag );
+ target.appendChild( kmlElement );
+ QDomText kmlTextElement = kmlDocument->createTextNode( text );
+ kmlElement.appendChild( kmlTextElement );
+ return kmlElement;
+ }
+};
+
+} // namespace KIPIGPSSyncPlugin
+
+#endif // KIPIGPSSYNCPLUGINKMLGPSDATAPARSER_H
diff --git a/kipi-plugins/gpssync/plugin_gpssync.cpp b/kipi-plugins/gpssync/plugin_gpssync.cpp
new file mode 100644
index 0000000..15c7f51
--- /dev/null
+++ b/kipi-plugins/gpssync/plugin_gpssync.cpp
@@ -0,0 +1,342 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-05-16
+ * Description : a plugin to synchronize pictures with
+ * a GPS device.
+ *
+ * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qfileinfo.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kaction.h>
+#include <kapplication.h>
+#include <kgenericfactory.h>
+#include <klibloader.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+
+// LibKIPI includes.
+
+#include <libkipi/imagecollection.h>
+
+// LibKExiv2 includes.
+
+#include <libkexiv2/kexiv2.h>
+
+// Local includes.
+
+#include "gpsbabelbinary.h"
+#include "gpsdatacontainer.h"
+#include "gpseditdialog.h"
+#include "gpssyncdialog.h"
+#include "kmlexport.h"
+#include "kmlexportconfig.h"
+#include "plugin_gpssync.h"
+#include "plugin_gpssync.moc"
+
+typedef KGenericFactory<Plugin_GPSSync> Factory;
+
+K_EXPORT_COMPONENT_FACTORY( kipiplugin_gpssync, Factory("kipiplugin_gpssync"))
+
+Plugin_GPSSync::Plugin_GPSSync(QObject *parent, const char*, const QStringList&)
+ : KIPI::Plugin( Factory::instance(), parent, "GPSSync")
+{
+ kdDebug( 51001 ) << "Plugin_GPSSync plugin loaded" << endl;
+}
+
+void Plugin_GPSSync::setup( QWidget* widget )
+{
+ KIPI::Plugin::setup( widget );
+
+ m_action_geolocation = new KActionMenu(i18n("Geolocation"),
+ 0,
+ actionCollection(),
+ "geolocation");
+
+ m_action_geolocation->insert(new KAction (i18n("Correlator..."),
+ "gpsimagetag",
+ 0,
+ this,
+ SLOT(slotGPSSync()),
+ actionCollection(),
+ "gpssync"));
+
+ m_action_geolocation->insert(new KAction (i18n("Edit Coordinates..."),
+ 0,
+ 0,
+ this,
+ SLOT(slotGPSEdit()),
+ actionCollection(),
+ "gpsedit"));
+
+ m_action_geolocation->insert(new KAction (i18n("Remove Coordinates..."),
+ 0,
+ 0,
+ this,
+ SLOT(slotGPSRemove()),
+ actionCollection(),
+ "gpsremove"));
+
+ addAction( m_action_geolocation );
+
+ // this is our action shown in the menubar/toolbar of the mainwindow
+ m_actionKMLExport = new KAction (i18n("KML Export..."),
+ "www", // icon
+ 0, // do never set shortcuts from plugins.
+ this,
+ SLOT(slotKMLExport()),
+ actionCollection(),
+ "kmlexport");
+
+ addAction( m_actionKMLExport );
+
+ m_interface = dynamic_cast< KIPI::Interface* >( parent() );
+
+ if ( !m_interface )
+ {
+ kdError( 51000 ) << "Kipi interface is null!" << endl;
+ return;
+ }
+
+ KIPI::ImageCollection selection = m_interface->currentSelection();
+ m_action_geolocation->setEnabled( selection.isValid() && !selection.images().isEmpty() );
+
+ connect( m_interface, SIGNAL(selectionChanged(bool)),
+ m_action_geolocation, SLOT(setEnabled(bool)));
+}
+
+bool Plugin_GPSSync::checkBinaries(QString &gpsBabelVersion)
+{
+ KIPIGPSSyncPlugin::GPSBabelBinary gpsBabelBinary;
+ gpsBabelVersion = gpsBabelBinary.version();
+
+ if (!gpsBabelBinary.isAvailable())
+ {
+ KMessageBox::information(
+ kapp->activeWindow(),
+ i18n("<qt><p>Unable to find the gpsbabel executable:<br> "
+ "This program is required by this plugin to support GPS data file decoding. "
+ "Please install gpsbabel as a package from your distributor "
+ "or <a href=\"%1\">download the source</a>.</p>"
+ "<p>Note: at least, gpsbabel version %2 is required by this plugin.</p></qt>")
+ .arg("http://www.gpsbabel.org")
+ .arg(gpsBabelBinary.minimalVersion()),
+ QString::null,
+ QString::null,
+ KMessageBox::Notify | KMessageBox::AllowLink);
+ return false;
+ }
+
+ if (!gpsBabelBinary.versionIsRight())
+ {
+ KMessageBox::information(
+ kapp->activeWindow(),
+ i18n("<qt><p>gpsbabel executable is not up to date:<br> "
+ "The version %1 of gpsbabel have been found on your computer. "
+ "This version is too old to run properly with this plugin. "
+ "Please update gpsbabel as a package from your distributor "
+ "or <a href=\"%2\">download the source</a>.</p>"
+ "<p>Note: at least, gpsbabel version %3 is required by this "
+ "plugin</p></qt>")
+ .arg(gpsBabelVersion)
+ .arg("http://www.gpsbabel.org")
+ .arg(gpsBabelBinary.minimalVersion()),
+ QString::null,
+ QString::null,
+ KMessageBox::Notify | KMessageBox::AllowLink);
+ return false;
+ }
+
+ return true;
+}
+
+void Plugin_GPSSync::slotGPSSync()
+{
+ KIPI::ImageCollection images = m_interface->currentSelection();
+
+ if ( !images.isValid() || images.images().isEmpty() )
+ return;
+
+ /* NOTE: this plugin do not use yet GPSBabel to convert GPS data file to GPX
+ QString gpsBabelVersion;
+ if (!checkBinaries(gpsBabelVersion))
+ return;
+ */
+
+ KIPIGPSSyncPlugin::GPSSyncDialog *dialog = new KIPIGPSSyncPlugin::GPSSyncDialog(
+ m_interface, kapp->activeWindow());
+
+ dialog->setImages( images.images() );
+ dialog->show();
+}
+
+void Plugin_GPSSync::slotGPSEdit()
+{
+ KIPI::ImageCollection images = m_interface->currentSelection();
+
+ if ( !images.isValid() || images.images().isEmpty() )
+ return;
+
+ KURL img = images.images().first();
+ KExiv2Iface::KExiv2 exiv2Iface;
+ exiv2Iface.load(img.path());
+ double alt, lat, lng;
+ bool hasGPSInfo = exiv2Iface.getGPSInfo(alt, lat, lng);
+ KIPIGPSSyncPlugin::GPSDataContainer gpsData(alt, lat, lng, false);
+
+ KIPIGPSSyncPlugin::GPSEditDialog dlg(kapp->activeWindow(),
+ gpsData, img.fileName(), hasGPSInfo);
+
+ if (dlg.exec() == KDialogBase::Accepted)
+ {
+ gpsData = dlg.getGPSInfo();
+ KURL::List imageURLs = images.images();
+ KURL::List updatedURLs;
+ QStringList errorFiles;
+
+ for( KURL::List::iterator it = imageURLs.begin() ;
+ it != imageURLs.end(); ++it)
+ {
+ KURL url = *it;
+
+ bool ret = true;
+ ret &= exiv2Iface.load(url.path());
+ if (ret)
+ {
+ ret &= exiv2Iface.setGPSInfo(gpsData.altitude(),
+ gpsData.latitude(),
+ gpsData.longitude());
+ ret &= exiv2Iface.save(url.path());
+ }
+
+ if (!ret)
+ errorFiles.append(url.fileName());
+ else
+ updatedURLs.append(url);
+ }
+
+ // We use kipi interface refreshImages() method to tell to host than
+ // metadata from pictures have changed and need to be re-readed.
+
+ m_interface->refreshImages(updatedURLs);
+
+ if (!errorFiles.isEmpty())
+ {
+ KMessageBox::errorList(
+ kapp->activeWindow(),
+ i18n("Unable to save geographical coordinates into:"),
+ errorFiles,
+ i18n("Edit Geographical Coordinates"));
+ }
+ }
+}
+
+void Plugin_GPSSync::slotGPSRemove()
+{
+ KIPI::ImageCollection images = m_interface->currentSelection();
+
+ if ( !images.isValid() || images.images().isEmpty() )
+ return;
+
+ if (KMessageBox::warningYesNo(
+ kapp->activeWindow(),
+ i18n("Geographical coordinates will be definitively removed from all selected images.\n"
+ "Do you want to continue ?"),
+ i18n("Remove Geographical Coordinates")) != KMessageBox::Yes)
+ return;
+
+ KURL::List imageURLs = images.images();
+ KURL::List updatedURLs;
+ QStringList errorFiles;
+
+ for( KURL::List::iterator it = imageURLs.begin() ;
+ it != imageURLs.end(); ++it)
+ {
+ KURL url = *it;
+
+ bool ret = true;
+ KExiv2Iface::KExiv2 exiv2Iface;
+ ret &= exiv2Iface.load(url.path());
+ ret &= exiv2Iface.removeGPSInfo();
+ ret &= exiv2Iface.save(url.path());
+
+ if (!ret)
+ errorFiles.append(url.fileName());
+ else
+ updatedURLs.append(url);
+ }
+
+ // We use kipi interface refreshImages() method to tell to host than
+ // metadata from pictures have changed and need to be re-readed.
+
+ m_interface->refreshImages(updatedURLs);
+
+ if (!errorFiles.isEmpty())
+ {
+ KMessageBox::errorList(
+ kapp->activeWindow(),
+ i18n("Unable to remove geographical coordinates from:"),
+ errorFiles,
+ i18n("Remove Geographical Coordinates"));
+ }
+}
+
+void Plugin_GPSSync::slotKMLExport()
+{
+ KIPI::ImageCollection selection = m_interface->currentSelection();
+
+ if ( !selection.isValid() )
+ {
+ kdDebug( 51000) << "No Selection!" << endl;
+ }
+ else
+ {
+ KIPIGPSSyncPlugin::KMLExportConfig *kmlExportConfigGui = new KIPIGPSSyncPlugin::KMLExportConfig(
+ kapp->activeWindow(), i18n("KMLExport").ascii());
+ connect(kmlExportConfigGui, SIGNAL(okButtonClicked()),
+ this, SLOT(slotKMLGenerate()));
+ kmlExportConfigGui->show();
+ }
+}
+
+void Plugin_GPSSync::slotKMLGenerate()
+{
+ KIPI::ImageCollection selection = m_interface->currentSelection();
+ KIPIGPSSyncPlugin::kmlExport myExport(m_interface);
+ if(!myExport.getConfig())
+ return;
+ myExport.generate();
+}
+
+KIPI::Category Plugin_GPSSync::category( KAction* action ) const
+{
+ if ( action == m_action_geolocation )
+ return KIPI::IMAGESPLUGIN;
+ if ( action == m_actionKMLExport )
+ return KIPI::EXPORTPLUGIN;
+
+ kdWarning( 51000 ) << "Unrecognized action for plugin category identification" << endl;
+ return KIPI::IMAGESPLUGIN; // no warning from compiler, please
+}
diff --git a/kipi-plugins/gpssync/plugin_gpssync.h b/kipi-plugins/gpssync/plugin_gpssync.h
new file mode 100644
index 0000000..c12105c
--- /dev/null
+++ b/kipi-plugins/gpssync/plugin_gpssync.h
@@ -0,0 +1,66 @@
+/* ============================================================
+ *
+ * This file is a part of kipi-plugins project
+ * http://www.kipi-plugins.org
+ *
+ * Date : 2006-05-16
+ * Description : a plugin to synchronize pictures with
+ * a GPS device.
+ *
+ * Copyright 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * 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 2, 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.
+ *
+ * ============================================================ */
+
+#ifndef PLUGIN_GPSSYNC_H
+#define PLUGIN_GPSSYNC_H
+
+// LibKIPI includes.
+
+#include <libkipi/plugin.h>
+
+class KActionMenu;
+class KAction;
+
+class Plugin_GPSSync : public KIPI::Plugin
+{
+ Q_OBJECT
+
+public:
+
+ Plugin_GPSSync(QObject *parent, const char* name, const QStringList &args);
+
+ virtual KIPI::Category category( KAction* action ) const;
+ virtual void setup( QWidget* );
+
+protected slots:
+
+ void slotGPSSync();
+ void slotGPSEdit();
+ void slotGPSRemove();
+ void slotKMLGenerate();
+ void slotKMLExport();
+
+private:
+
+ bool checkBinaries(QString &gpsBabelVersion);
+
+private:
+
+ KActionMenu *m_action_geolocation;
+ KAction *m_actionKMLExport;
+
+ KIPI::Interface *m_interface;
+};
+
+#endif // PLUGIN_GPSSYNC_H