[gthumb] added a map view to view the geographical position where the picture was taken



commit d15367f7114252406c39b10a21c0ccedac275b90
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Sat Apr 30 17:13:00 2011 +0200

    added a map view to view the geographical position where the picture was taken
    
    [new feature]

 configure.ac                                 |   24 ++
 data/icons/hicolor/16x16/actions/Makefile.am |    1 +
 data/icons/hicolor/16x16/actions/map.png     |  Bin 0 -> 611 bytes
 extensions/Makefile.am                       |    1 +
 extensions/map_view/Makefile.am              |   29 +++
 extensions/map_view/gth-map-view.c           |  322 ++++++++++++++++++++++++++
 extensions/map_view/gth-map-view.h           |   53 +++++
 extensions/map_view/main.c                   |   52 ++++
 extensions/map_view/map_view.extension.in.in |   12 +
 gthumb/Makefile.am                           |    2 +
 gthumb/gth-file-properties.c                 |    2 +-
 gthumb/gth-main.c                            |    1 +
 12 files changed, 498 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 32f7126..0d7c3b5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -56,6 +56,7 @@ UNIQUE_REQUIRED=1.1.2
 LIBSOUP_REQUIRED=2.26
 GNOME_KEYRING_REQUIRED=2.28
 LIBBRASERO_REQUIRED=2.28
+LIBCHAMPLAIN_REQUIRED=0.8.0
 
 dnl ===========================================================================
 
@@ -216,6 +217,27 @@ AM_CONDITIONAL(ENABLE_GSTREAMER, test "x$enable_gstreamer" = xyes)
 
 dnl ===========================================================================
 
+AC_ARG_ENABLE([libchamplain],
+	      [AS_HELP_STRING([--disable-libchamplain],[do not compile code that uses the libchamplain library])],,
+	      [enable_libchamplain=yes])
+
+if test x$enable_libchamplain = xyes ; then
+	PKG_CHECK_MODULES(LIBCHAMPLAIN,
+			  [champlain-0.8 >= $LIBCHAMPLAIN_REQUIRED
+			   champlain-gtk-0.8 >= $LIBCHAMPLAIN_REQUIRED],
+			  [enable_libchamplain=yes],
+			  [enable_libchamplain=no])
+fi
+if test x$enable_libchamplain = xyes ; then
+	AC_DEFINE(HAVE_LIBCHAMPLAIN, 1, [Define to 1 if libchamplain support is included])
+fi
+
+AC_SUBST(LIBCHAMPLAIN_LIBS)
+AC_SUBST(LIBCHAMPLAIN_CFLAGS)
+AM_CONDITIONAL(ENABLE_LIBCHAMPLAIN, test "x$enable_libchamplain" = xyes)
+
+dnl ===========================================================================
+
 IT_PROG_INTLTOOL([0.35.0])
 GETTEXT_PACKAGE=gthumb
 AC_SUBST([GETTEXT_PACKAGE])
@@ -584,6 +606,7 @@ extensions/jpeg_utils/Makefile
 extensions/list_tools/Makefile
 extensions/list_tools/data/Makefile
 extensions/list_tools/data/ui/Makefile
+extensions/map_view/Makefile
 extensions/oauth/Makefile
 extensions/oauth/data/Makefile
 extensions/oauth/data/ui/Makefile
@@ -651,4 +674,5 @@ Configuration:
 	Burn disc support    : ${enable_libbrasero}
 	Web albums           : ${enable_web_albums}
 	SM client support    : ${with_smclient}
+	Map support          : ${enable_libchamplain}
 "
diff --git a/data/icons/hicolor/16x16/actions/Makefile.am b/data/icons/hicolor/16x16/actions/Makefile.am
index f7cb81a..772c06f 100644
--- a/data/icons/hicolor/16x16/actions/Makefile.am
+++ b/data/icons/hicolor/16x16/actions/Makefile.am
@@ -15,6 +15,7 @@ icons_DATA = 				\
 	histogram-linear.png		\
 	histogram-logarithmic.png	\
 	image-navigator.png		\
+	map.png				\
 	photobucket.png			\
 	picasaweb.png			\
 	tool-adjust-colors.png		\
diff --git a/data/icons/hicolor/16x16/actions/map.png b/data/icons/hicolor/16x16/actions/map.png
new file mode 100644
index 0000000..9ecb79a
Binary files /dev/null and b/data/icons/hicolor/16x16/actions/map.png differ
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index a01335e..145412f 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -43,6 +43,7 @@ SUBDIRS = 			\
 	jpeg_utils		\
 	$(JPEG_TOOLS)		\
 	list_tools		\
+	map_view		\
 	oauth			\
 	pixbuf_savers		\
 	raw_files		\
diff --git a/extensions/map_view/Makefile.am b/extensions/map_view/Makefile.am
new file mode 100644
index 0000000..b41c2a0
--- /dev/null
+++ b/extensions/map_view/Makefile.am
@@ -0,0 +1,29 @@
+if ENABLE_LIBCHAMPLAIN
+
+extensiondir = $(pkglibdir)/extensions
+extension_LTLIBRARIES = libmap_view.la
+
+libmap_view_la_SOURCES = 	\
+	gth-map-view.c		\
+	gth-map-view.h		\
+	main.c
+
+libmap_view_la_CPPFLAGS = $(GTHUMB_CFLAGS) $(LIBCHAMPLAIN_CFLAGS) -I$(top_srcdir) -I$(top_builddir)/gthumb 
+libmap_view_la_LDFLAGS = $(EXTENSION_LIBTOOL_FLAGS)
+libmap_view_la_LIBADD = $(GTHUMB_LIBS) $(LIBCHAMPLAIN_LIBS)
+libmap_view_la_DEPENDENCIES = $(top_builddir)/gthumb/gthumb$(EXEEXT)
+
+extensioninidir = $(extensiondir)
+extensionini_DATA = $(extensionini_in_files:.extension.in.in=.extension)
+DISTCLEANFILES = $(extensionini_DATA)
+
+endif
+
+extensionini_in_files = map_view.extension.in.in
+
+ GTHUMB_EXTENSION_IN_RULE@
+ GTHUMB_EXTENSION_RULE@
+
+EXTRA_DIST = $(extensionini_in_files)
+
+-include $(top_srcdir)/git.mk
diff --git a/extensions/map_view/gth-map-view.c b/extensions/map_view/gth-map-view.c
new file mode 100644
index 0000000..6246f0e
--- /dev/null
+++ b/extensions/map_view/gth-map-view.c
@@ -0,0 +1,322 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ *  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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <math.h>
+#include <glib/gi18n.h>
+#include <champlain/champlain.h>
+#include <champlain-gtk/champlain-gtk.h>
+#include <clutter-gtk/clutter-gtk.h>
+#include <gthumb.h>
+#include "gth-map-view.h"
+
+#define GTH_MAP_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTH_TYPE_MAP_VIEW, GthMapViewPrivate))
+#define LABEL_MAX_WIDTH 200
+
+
+static gpointer parent_class = NULL;
+
+
+struct _GthMapViewPrivate {
+	GtkWidget      *no_gps_label;
+	GtkWidget      *embed;
+	ChamplainView  *map_view;
+	ChamplainLayer *marker_layer;
+	ClutterActor   *marker;
+};
+
+
+/* Exif format: %d/%d %d/%d %d/%d */
+static double
+exif_coordinate_to_decimal (const char *raw)
+{
+	double   value;
+	double   factor;
+	char   **raw_values;
+	int      i;
+
+	value = 0.0;
+	factor = 1.0;
+	raw_values = g_strsplit (raw, " ", 3);
+	for (i = 0; i < 3; i++) {
+		int numerator;
+		int denominator;
+
+		if (raw_values[i] == NULL)
+			break; /* Error */
+
+		sscanf (raw_values[i], "%d/%d", &numerator, &denominator);
+		if ((numerator != 0) && (denominator != 0))
+			value += ((double) numerator / denominator) / factor;
+
+		factor *= 60.0;
+	}
+
+	g_strfreev (raw_values);
+
+	return value;
+}
+
+
+static char *
+decimal_to_string (double value)
+{
+	GString *s;
+	double   part;
+
+	s = g_string_new ("");
+	if (value < 0.0)
+		value = - value;
+
+	/* degree */
+
+	part = floor (value);
+	g_string_append_printf (s, "%.0f°", part);
+	value = (value - part) * 60.0;
+
+	/* minutes */
+
+	part = floor (value);
+	g_string_append_printf (s, "%.0fʹ", part);
+	value = (value - part) * 60.0;
+
+	/* seconds */
+
+	g_string_append_printf (s, "%02.3fʺ", value);
+
+	return g_string_free (s, FALSE);
+}
+
+
+static char *
+decimal_coordinates_to_string (double latitude,
+			       double longitude)
+{
+	char *latitude_s;
+	char *longitude_s;
+	char *s;
+
+	latitude_s = decimal_to_string (latitude);
+	longitude_s = decimal_to_string (longitude);
+	s = g_strdup_printf ("%s %s\n%s %s",
+			     latitude_s,
+			     ((latitude < 0.0) ? C_("Cardinal point", "S") : C_("Cardinal point", "N")),
+			     longitude_s,
+			     ((longitude < 0.0) ? C_("Cardinal point", "W") : C_("Cardinal point", "E")));
+
+	g_free (longitude_s);
+	g_free (latitude_s);
+
+	return s;
+}
+
+
+void
+gth_map_view_real_set_file (GthPropertyView *base,
+		 	    GthFileData     *file_data)
+{
+	GthMapView *self = GTH_MAP_VIEW (base);
+	int         coordinates_available;
+	double      latitude;
+	double      longitude;
+
+	coordinates_available = 0;
+
+	if (file_data != NULL) {
+		GthMetadata *metadata;
+
+		metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Exif::GPSInfo::GPSLatitude");
+		if (metadata != NULL) {
+			latitude = exif_coordinate_to_decimal (gth_metadata_get_raw (metadata));
+
+			metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Exif::GPSInfo::GPSLatitudeRef");
+			if (metadata != NULL) {
+				if (g_strcmp0 (gth_metadata_get_raw (metadata), "S") == 0)
+					latitude = - latitude;
+			}
+
+			coordinates_available++;
+		}
+
+		metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Exif::GPSInfo::GPSLongitude");
+		if (metadata != NULL) {
+			longitude = exif_coordinate_to_decimal (gth_metadata_get_raw (metadata));
+
+			metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Exif::GPSInfo::GPSLongitudeRef");
+			if (metadata != NULL) {
+				if (g_strcmp0 (gth_metadata_get_raw (metadata), "W") == 0)
+					longitude = - longitude;
+			}
+
+			coordinates_available++;
+		}
+	}
+
+	if (coordinates_available == 2) {
+		char *position;
+
+		gtk_widget_hide (self->priv->no_gps_label);
+		gtk_widget_show (self->priv->embed);
+
+		position = decimal_coordinates_to_string (latitude, longitude);
+		champlain_marker_set_text (CHAMPLAIN_MARKER (self->priv->marker), position);
+		g_free (position);
+
+		champlain_base_marker_set_position (CHAMPLAIN_BASE_MARKER (self->priv->marker), latitude, longitude);
+		champlain_view_center_on (CHAMPLAIN_VIEW (self->priv->map_view), latitude, longitude);
+	}
+	else {
+		gtk_widget_hide (self->priv->embed);
+		gtk_widget_show (self->priv->no_gps_label);
+	}
+}
+
+
+const char *
+gth_map_view_real_get_name (GthMultipageChild *self)
+{
+	return _("Map");
+}
+
+
+const char *
+gth_map_view_real_get_icon (GthMultipageChild *self)
+{
+	return "map";
+}
+
+
+static void
+gth_map_view_finalize (GObject *base)
+{
+	G_OBJECT_CLASS (parent_class)->finalize (base);
+}
+
+
+static void
+gth_map_view_class_init (GthMapViewClass *klass)
+{
+	parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GthMapViewPrivate));
+
+	G_OBJECT_CLASS (klass)->finalize = gth_map_view_finalize;
+}
+
+
+static void
+gth_map_view_init (GthMapView *self)
+{
+	self->priv = GTH_MAP_VIEW_GET_PRIVATE (self);
+
+	gtk_box_set_spacing (GTK_BOX (self), 6);
+	gtk_container_set_border_width (GTK_CONTAINER (self), 2);
+
+	/* No GPS label */
+
+	self->priv->no_gps_label = gtk_label_new (_("The geographical position information is not available for this image."));
+	g_object_set (G_OBJECT (self->priv->no_gps_label),
+		      "wrap", TRUE,
+		      "wrap-mode", PANGO_WRAP_WORD_CHAR,
+		      "single-line-mode", FALSE,
+		      "justify", GTK_JUSTIFY_CENTER,
+		      "width-request", LABEL_MAX_WIDTH,
+		      NULL);
+	gtk_widget_show (self->priv->no_gps_label);
+	gtk_box_pack_start (GTK_BOX (self), self->priv->no_gps_label, TRUE, TRUE, 0);
+
+	/* The map widget */
+
+	self->priv->embed = gtk_champlain_embed_new ();
+
+	self->priv->map_view = gtk_champlain_embed_get_view (GTK_CHAMPLAIN_EMBED (self->priv->embed));
+	g_object_set (G_OBJECT (self->priv->map_view),
+		      "reactive", TRUE,
+		      "scroll-mode", CHAMPLAIN_SCROLL_MODE_KINETIC,
+		      "zoom-level", 5,
+		      "show-scale", TRUE,
+		      NULL);
+
+	self->priv->marker_layer = champlain_layer_new ();
+	champlain_view_add_layer (self->priv->map_view, self->priv->marker_layer);
+	champlain_layer_show (self->priv->marker_layer);
+
+	self->priv->marker = champlain_marker_new_with_text ("", "Sans 10", NULL, NULL);
+	clutter_actor_show (self->priv->marker);
+	champlain_layer_add_marker (self->priv->marker_layer, CHAMPLAIN_BASE_MARKER (self->priv->marker));
+
+	gtk_widget_show_all (self->priv->embed);
+	gtk_box_pack_start (GTK_BOX (self), self->priv->embed, TRUE, TRUE, 0);
+}
+
+
+static void
+gth_map_view_gth_multipage_child_interface_init (GthMultipageChildIface *iface)
+{
+	iface->get_name = gth_map_view_real_get_name;
+	iface->get_icon = gth_map_view_real_get_icon;
+}
+
+
+static void
+gth_map_view_gth_property_view_interface_init (GthPropertyViewIface *iface)
+{
+	iface->set_file = gth_map_view_real_set_file;
+}
+
+
+GType
+gth_map_view_get_type (void)
+{
+	static GType type = 0;
+
+	if (type == 0) {
+		static const GTypeInfo g_define_type_info = {
+			sizeof (GthMapViewClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gth_map_view_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,
+			sizeof (GthMapView),
+			0,
+			(GInstanceInitFunc) gth_map_view_init,
+			NULL
+		};
+		static const GInterfaceInfo gth_multipage_child_info = {
+			(GInterfaceInitFunc) gth_map_view_gth_multipage_child_interface_init,
+			(GInterfaceFinalizeFunc) NULL,
+			NULL
+		};
+		static const GInterfaceInfo gth_property_view_info = {
+			(GInterfaceInitFunc) gth_map_view_gth_property_view_interface_init,
+			(GInterfaceFinalizeFunc) NULL,
+			NULL
+		};
+		type = g_type_register_static (GTK_TYPE_VBOX,
+					       "GthMapView",
+					       &g_define_type_info,
+					       0);
+		g_type_add_interface_static (type, GTH_TYPE_MULTIPAGE_CHILD, &gth_multipage_child_info);
+		g_type_add_interface_static (type, GTH_TYPE_PROPERTY_VIEW, &gth_property_view_info);
+	}
+
+	return type;
+}
diff --git a/extensions/map_view/gth-map-view.h b/extensions/map_view/gth-map-view.h
new file mode 100644
index 0000000..b79f568
--- /dev/null
+++ b/extensions/map_view/gth-map-view.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ *  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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTH_MAP_VIEW_H
+#define GTH_MAP_VIEW_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_MAP_VIEW            (gth_map_view_get_type ())
+#define GTH_MAP_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_MAP_VIEW, GthMapView))
+#define GTH_MAP_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_MAP_VIEW, GthMapViewClass))
+#define GTH_IS_MAP_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_MAP_VIEW))
+#define GTH_IS_MAP_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_MAP_VIEW))
+#define GTH_MAP_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTH_TYPE_MAP_VIEW, GthMapViewClass))
+
+typedef struct _GthMapView GthMapView;
+typedef struct _GthMapViewClass GthMapViewClass;
+typedef struct _GthMapViewPrivate GthMapViewPrivate;
+
+struct _GthMapView {
+	GtkVBox parent_instance;
+	GthMapViewPrivate *priv;
+};
+
+struct _GthMapViewClass {
+	GtkVBoxClass parent_class;
+};
+
+GType gth_map_view_get_type (void);
+
+G_END_DECLS
+
+#endif /* GTH_MAP_VIEW_H */
diff --git a/extensions/map_view/main.c b/extensions/map_view/main.c
new file mode 100644
index 0000000..979a1fe
--- /dev/null
+++ b/extensions/map_view/main.c
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ *  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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <config.h>
+#include <gtk/gtk.h>
+#include <gthumb.h>
+#include "gth-map-view.h"
+
+
+G_MODULE_EXPORT void
+gthumb_extension_activate (void)
+{
+	gth_main_register_type ("file-properties", GTH_TYPE_MAP_VIEW);
+}
+
+
+G_MODULE_EXPORT void
+gthumb_extension_deactivate (void)
+{
+}
+
+
+G_MODULE_EXPORT gboolean
+gthumb_extension_is_configurable (void)
+{
+	return FALSE;
+}
+
+
+G_MODULE_EXPORT void
+gthumb_extension_configure (GtkWindow *parent)
+{
+}
diff --git a/extensions/map_view/map_view.extension.in.in b/extensions/map_view/map_view.extension.in.in
new file mode 100644
index 0000000..4d2e275
--- /dev/null
+++ b/extensions/map_view/map_view.extension.in.in
@@ -0,0 +1,12 @@
+[Extension]
+_Name=Map
+_Description=View the photo position on the map
+Authors=gthumb development team
+Copyright=Copyright © 2011 The Free Software Foundation, Inc.
+Version=%VERSION%
+Icon=map
+Category=Viewer
+
+[Loader]
+Type=module
+File=%LIBRARY%
diff --git a/gthumb/Makefile.am b/gthumb/Makefile.am
index a1e44a0..7e978a7 100644
--- a/gthumb/Makefile.am
+++ b/gthumb/Makefile.am
@@ -265,6 +265,7 @@ gthumb_LDADD =						\
 	$(LIBBRASERO_LIBS)				\
 	$(LIBOPENRAW_LIBS)				\
 	$(LIBSOUP_LIBS)					\
+	$(LIBCHAMPLAIN_LIBS)				\
 	$(NULL)
 
 if RUN_IN_PLACE
@@ -290,6 +291,7 @@ gthumb_CFLAGS =							\
 	$(LIBBRASERO_CFLAGS)					\
 	$(LIBOPENRAW_CFLAGS)					\
 	$(LIBSOUP_CFLAGS)					\
+	$(LIBCHAMPLAIN_CFLAGS)					\
 	$(SMCLIENT_CFLAGS)					\
 	-I$(top_srcdir)/copy-n-paste/				\
 	-DGTHUMB_LOCALEDIR=\"$(datadir)/locale\"		\
diff --git a/gthumb/gth-file-properties.c b/gthumb/gth-file-properties.c
index ae03162..de7412a 100644
--- a/gthumb/gth-file-properties.c
+++ b/gthumb/gth-file-properties.c
@@ -133,7 +133,7 @@ gth_file_properties_real_set_file (GthPropertyView *base,
 			g_free (value);
 			value = tmp_value;
 		}
-		tooltip = g_markup_printf_escaped ("%s: %s", _(info->display_name), value);
+		tooltip = g_markup_printf_escaped ("%s: %s", _(info->id), value);
 
 		category = g_hash_table_lookup (category_hash, info->category);
 		if (category == NULL) {
diff --git a/gthumb/gth-main.c b/gthumb/gth-main.c
index 1d6022c..6e7ac55 100644
--- a/gthumb/gth-main.c
+++ b/gthumb/gth-main.c
@@ -1271,6 +1271,7 @@ gth_main_activate_extensions (void)
 						"importer",
 						"jpeg_utils",
 						"list_tools",
+						"map_view",
 						"oauth",
 						"photo_importer",
 						"photobucket",



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]