]> git.street.me.uk Git - andy/viking.git/blobdiff - src/vikwindow.c
[QA] Move file related function into file.c and rename for general reuse
[andy/viking.git] / src / vikwindow.c
index 0289966c4c57ff91530dcb45eb16ef4d4a951ab6..15ecdbeaa96c35860298ac7f40ad5b886088e8c3 100644 (file)
 #include "mapcache.h"
 #include "print.h"
 #include "preferences.h"
+#include "viklayer_defaults.h"
 #include "icons/icons.h"
 #include "vikexttools.h"
 #include "garminsymbols.h"
 #include "vikmapslayer.h"
+#include "geonamessearch.h"
 
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
@@ -61,6 +63,7 @@
 //   why not be allowed to open a thousand more...
 #define MAX_WINDOWS 1024
 static guint window_count = 0;
+static GSList *window_list = NULL;
 
 #define VIKING_WINDOW_WIDTH      1000
 #define VIKING_WINDOW_HEIGHT     800
@@ -72,6 +75,7 @@ static void window_finalize ( GObject *gob );
 static GObjectClass *parent_class;
 
 static void window_set_filename ( VikWindow *vw, const gchar *filename );
+static const gchar *window_get_filename ( VikWindow *vw );
 
 static VikWindow *window_new ();
 
@@ -154,9 +158,6 @@ struct _VikWindow {
   VikStatusbar *viking_vs;
 
   GtkToolbar *toolbar;
-  GtkComboBox *tb_zoom_combo;
-
-  GtkItemFactory *item_factory;
 
   /* tool management state */
   guint current_tool;
@@ -181,6 +182,7 @@ struct _VikWindow {
   gboolean only_updating_coord_mode_ui; /* hack for a bug in GTK */
   GtkUIManager *uim;
 
+  GThread  *thread;
   /* half-drawn update */
   VikLayer *trigger;
   VikCoord trigger_center;
@@ -188,15 +190,11 @@ struct _VikWindow {
   /* Store at this level for highlighted selection drawing since it applies to the viewport and the layers panel */
   /* Only one of these items can be selected at the same time */
   gpointer selected_vtl; /* notionally VikTrwLayer */
-  gpointer selected_tracks; /* notionally GList */
+  GHashTable *selected_tracks;
   gpointer selected_track; /* notionally VikTrack */
-  gpointer selected_waypoints; /* notionally GList */
+  GHashTable *selected_waypoints;
   gpointer selected_waypoint; /* notionally VikWaypoint */
   /* only use for individual track or waypoint */
-  ////// NEED TO THINK ABOUT VALIDITY OF THESE             //////
-  ////// i.e. what happens when stuff is deleted elsewhere //////
-  ////// Generally seems alright as can not access them    //////
-  ////// containing_vtl now seems unecessary               //////
   /* For track(s) & waypoint(s) it is the layer they are in - this helps refering to the individual item easier */
   gpointer containing_vtl; /* notionally VikTrwLayer */
 };
@@ -359,6 +357,8 @@ static void window_finalize ( GObject *gob )
 
   a_background_remove_window ( vw );
 
+  window_list = g_slist_remove ( window_list, vw );
+
   G_OBJECT_CLASS(parent_class)->finalize(gob);
 }
 
@@ -380,22 +380,17 @@ static void vik_window_class_init ( VikWindowClass *klass )
 
 }
 
-static void set_toolbar_zoom ( VikWindow *vw, gdouble mpp )
+static void zoom_changed (GtkMenuShell *menushell,
+              gpointer      user_data)
 {
-  gint active = 2 + round ( log (mpp) / log (2) );
-  // Can we not hard code size here?
-  if ( active > 17 )
-    active = 17;
-  gtk_combo_box_set_active ( vw->tb_zoom_combo, active );
-}
+  VikWindow *vw = VIK_WINDOW (user_data);
 
-static void zoom_changed ( GtkComboBox *combo, VikWindow *vw )
-{
-  gint active = gtk_combo_box_get_active ( combo );
+  GtkWidget *aw = gtk_menu_get_active ( GTK_MENU (menushell) );
+  gint active = GPOINTER_TO_INT(g_object_get_data ( G_OBJECT (aw), "position" ));
 
-  // But has it really changed?
-  // Unfortunately this function gets invoked even on manual setting of the combo value
   gdouble zoom_request = pow (2, active-2 );
+
+  // But has it really changed?
   gdouble current_zoom = vik_viewport_get_zoom ( vw->viking_vvp );
   if ( current_zoom != 0.0 && zoom_request != current_zoom ) {
     vik_viewport_set_zoom ( vw->viking_vvp, zoom_request );
@@ -404,6 +399,23 @@ static void zoom_changed ( GtkComboBox *combo, VikWindow *vw )
   }
 }
 
+static GtkWidget * create_zoom_menu_all_levels ()
+{
+  GtkWidget *menu = gtk_menu_new ();
+  char *itemLabels[] = { "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "32768", NULL };
+
+  int i;
+  for (i = 0 ; itemLabels[i] != NULL ; i++)
+    {
+      GtkWidget *item = gtk_menu_item_new_with_label (itemLabels[i]);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show (item);
+      g_object_set_data (G_OBJECT (item), "position", GINT_TO_POINTER(i));
+    }
+
+  return menu;
+}
+
 static GtkWidget *create_zoom_combo_all_levels ()
 {
   GtkWidget *zoom_combo = gtk_combo_box_new_text();
@@ -431,6 +443,23 @@ static GtkWidget *create_zoom_combo_all_levels ()
   return zoom_combo;
 }
 
+static gint zoom_popup_handler (GtkWidget *widget)
+{
+  GtkMenu *menu;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
+
+  /* The "widget" is the menu that was supplied when
+   * g_signal_connect_swapped() was called.
+   */
+  menu = GTK_MENU (widget);
+
+  gtk_menu_popup (menu, NULL, NULL, NULL, NULL,
+                  1, gtk_get_current_event_time());
+  return TRUE;
+}
+
 static void vik_window_init ( VikWindow *vw )
 {
   GtkWidget *main_vbox;
@@ -452,7 +481,6 @@ static void vik_window_init ( VikWindow *vw )
   gtk_action_activate ( gtk_action_group_get_action ( vw->action_group, "Pan" ) );
 
   vw->filename = NULL;
-  vw->item_factory = NULL;
 
   vw->modified = FALSE;
   vw->only_updating_coord_mode_ui = FALSE;
@@ -471,16 +499,11 @@ static void vik_window_init ( VikWindow *vw )
   gtk_toolbar_set_icon_size (vw->toolbar, GTK_ICON_SIZE_SMALL_TOOLBAR);
   gtk_toolbar_set_style (vw->toolbar, GTK_TOOLBAR_ICONS);
 
-  vik_ext_tools_add_menu_items ( vw, vw->uim );
-
-  vw->tb_zoom_combo = GTK_COMBO_BOX(create_zoom_combo_all_levels());
-
-  g_signal_connect ( G_OBJECT(vw->tb_zoom_combo), "changed", G_CALLBACK(zoom_changed), vw );
-
-  // Add the zoom combo to the toolbar at the end
-  GtkToolItem *tooli = gtk_tool_item_new ();
-  gtk_container_add ( GTK_CONTAINER(tooli), GTK_WIDGET (vw->tb_zoom_combo) );
-  gtk_toolbar_insert ( vw->toolbar, tooli, gtk_toolbar_get_n_items (vw->toolbar) );
+  GtkWidget * zoom_levels = gtk_ui_manager_get_widget (vw->uim, "/MainMenu/View/SetZoom");
+  GtkWidget * zoom_levels_menu = create_zoom_menu_all_levels ();
+  gtk_menu_item_set_submenu (GTK_MENU_ITEM (zoom_levels), zoom_levels_menu);
+  g_signal_connect ( G_OBJECT(zoom_levels_menu), "selection-done", G_CALLBACK(zoom_changed), vw);
+  g_signal_connect_swapped ( G_OBJECT(vw->viking_vs), "clicked", G_CALLBACK(zoom_popup_handler), zoom_levels_menu );
 
   g_signal_connect (G_OBJECT (vw), "delete_event", G_CALLBACK (delete_event), NULL);
 
@@ -509,10 +532,17 @@ static void vik_window_init ( VikWindow *vw )
 
   a_background_add_window ( vw );
 
+  window_list = g_slist_prepend ( window_list, vw);
+
   vw->open_dia = NULL;
   vw->save_dia = NULL;
   vw->save_img_dia = NULL;
   vw->save_img_dir_dia = NULL;
+
+  // Store the thread value so comparisons can be made to determine the gdk update method
+  // Hopefully we are storing the main thread value here :)
+  //  [ATM any window initialization is always be performed by the main thread]
+  vw->thread = g_thread_self();
 }
 
 static VikWindow *window_new ()
@@ -616,7 +646,7 @@ static gboolean delete_event( VikWindow *vw )
       _("Do you want to save the changes you made to the document \"%s\"?\n"
        "\n"
        "Your changes will be lost if you don't save them."),
-      vw->filename ? a_file_basename ( vw->filename ) : _("Untitled") ) );
+      window_get_filename ( vw ) ) );
     gtk_dialog_add_buttons ( dia, _("Don't Save"), GTK_RESPONSE_NO, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_YES, NULL );
     switch ( gtk_dialog_run ( dia ) )
     {
@@ -675,8 +705,6 @@ static void draw_status ( VikWindow *vw )
       g_snprintf ( zoom_level, 22, "%d %s", (int)xmpp, unit );
 
   vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_ZOOM, zoom_level );
-  // OK maybe not quite in the statusbar - but we have the zoom level so use it
-  set_toolbar_zoom ( vw, xmpp ); // But it's a status of some kind!
 
   draw_status_tool ( vw );  
 }
@@ -934,8 +962,8 @@ static void draw_ruler(VikViewport *vvp, GdkDrawable *d, GdkGC *gc, gint x1, gin
   gdouble len = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
   gdouble dx = (x2-x1)/len*10; 
   gdouble dy = (y2-y1)/len*10;
-  gdouble c = cos(15.0 * M_PI/180.0);
-  gdouble s = sin(15.0 * M_PI/180.0);
+  gdouble c = cos(DEG2RAD(15.0));
+  gdouble s = sin(DEG2RAD(15.0));
   gdouble angle;
   gdouble baseangle = 0;
   gint i;
@@ -960,29 +988,8 @@ static void draw_ruler(VikViewport *vvp, GdkDrawable *d, GdkGC *gc, gint x1, gin
   /* draw compass */
 #define CR 80
 #define CW 4
-  angle = atan2(dy, dx) + M_PI_2;
 
-  if ( vik_viewport_get_drawmode ( vvp ) == VIK_VIEWPORT_DRAWMODE_UTM) {
-    VikCoord test;
-    struct LatLon ll;
-    struct UTM u;
-    gint tx, ty;
-
-    vik_viewport_screen_to_coord ( vvp, x1, y1, &test );
-    vik_coord_to_latlon ( &test, &ll );
-    ll.lat += vik_viewport_get_ympp ( vvp ) * vik_viewport_get_height ( vvp ) / 11000.0; // about 11km per degree latitude
-    a_coords_latlon_to_utm ( &ll, &u );
-    vik_coord_load_from_utm ( &test, VIK_VIEWPORT_DRAWMODE_UTM, &u );
-    vik_viewport_coord_to_screen ( vvp, &test, &tx, &ty );
-
-    baseangle = M_PI - atan2(tx-x1, ty-y1);
-    angle -= baseangle;
-  }
-
-  if (angle<0) 
-    angle+=2*M_PI;
-  if (angle>2*M_PI)
-    angle-=2*M_PI;
+  vik_viewport_compute_bearing ( vvp, x1, y1, x2, y2, &angle, &baseangle );
 
   {
     GdkColor color;
@@ -991,14 +998,14 @@ static void draw_ruler(VikViewport *vvp, GdkDrawable *d, GdkGC *gc, gint x1, gin
     gdk_color_parse("#2255cc", &color);
     gdk_gc_set_rgb_fg_color(thickgc, &color);
   }
-  gdk_draw_arc (d, thickgc, FALSE, x1-CR+CW/2, y1-CR+CW/2, 2*CR-CW, 2*CR-CW, (90 - baseangle*180/M_PI)*64, -angle*180/M_PI*64);
+  gdk_draw_arc (d, thickgc, FALSE, x1-CR+CW/2, y1-CR+CW/2, 2*CR-CW, 2*CR-CW, (90 - RAD2DEG(baseangle))*64, -RAD2DEG(angle)*64);
 
 
   gdk_gc_copy(thickgc, gc);
   gdk_gc_set_line_attributes(thickgc, 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
   for (i=0; i<180; i++) {
-    c = cos(i*M_PI/90.0 + baseangle);
-    s = sin(i*M_PI/90.0 + baseangle);
+    c = cos(DEG2RAD(i)*2 + baseangle);
+    s = sin(DEG2RAD(i)*2 + baseangle);
 
     if (i%5) {
       gdk_draw_line (d, gc, x1 + CR*c, y1 + CR*s, x1 + (CR+CW)*c, y1 + (CR+CW)*s);
@@ -1026,7 +1033,7 @@ static void draw_ruler(VikViewport *vvp, GdkDrawable *d, GdkGC *gc, gint x1, gin
     gint wb, hb, xb, yb;
 
     pl = gtk_widget_create_pango_layout (GTK_WIDGET(vvp), NULL);
-    pango_layout_set_font_description (pl, GTK_WIDGET(vvp)->style->font_desc);
+    pango_layout_set_font_description (pl, gtk_widget_get_style(GTK_WIDGET(vvp))->font_desc);
     pango_layout_set_text(pl, "N", -1);
     gdk_draw_layout(d, gc, x1-5, y1-CR-3*CW-8, pl);
 
@@ -1074,7 +1081,7 @@ static void draw_ruler(VikViewport *vvp, GdkDrawable *d, GdkGC *gc, gint x1, gin
     LABEL(xd, yd, wd, hd);
 
     /* draw label with bearing */
-    g_sprintf(str, "%3.1f°", angle*180.0/M_PI);
+    g_sprintf(str, "%3.1f°", RAD2DEG(angle));
     pango_layout_set_text(pl, str, -1);
     pango_layout_get_pixel_size ( pl, &wb, &hb );
     xb = x1 + CR*cos(angle-M_PI_2);
@@ -1192,13 +1199,13 @@ static VikLayerToolFuncStatus ruler_move (VikLayer *vl, GdkEventMotion *event, r
     vik_coord_to_latlon ( &coord, &ll );
     vik_viewport_coord_to_screen ( vvp, &s->oldcoord, &oldx, &oldy );
 
-    gdk_draw_drawable (buf, GTK_WIDGET(vvp)->style->black_gc, 
+    gdk_draw_drawable (buf, gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc,
                       vik_viewport_get_pixmap(vvp), 0, 0, 0, 0, -1, -1);
-    draw_ruler(vvp, buf, GTK_WIDGET(vvp)->style->black_gc, oldx, oldy, event->x, event->y, vik_coord_diff( &coord, &(s->oldcoord)) );
+    draw_ruler(vvp, buf, gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc, oldx, oldy, event->x, event->y, vik_coord_diff( &coord, &(s->oldcoord)) );
     if (draw_buf_done) {
       static gpointer pass_along[3];
       pass_along[0] = GTK_WIDGET(vvp)->window;
-      pass_along[1] = GTK_WIDGET(vvp)->style->black_gc;
+      pass_along[1] = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
       pass_along[2] = buf;
       g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_buf, pass_along, NULL);
       draw_buf_done = FALSE;
@@ -1384,7 +1391,7 @@ static VikLayerToolFuncStatus zoomtool_move (VikLayer *vl, GdkEventMotion *event
 
     // Blank out currently drawn area
     gdk_draw_drawable ( zts->pixmap,
-                        GTK_WIDGET(zts->vw->viking_vvp)->style->black_gc,
+                        gtk_widget_get_style(GTK_WIDGET(zts->vw->viking_vvp))->black_gc,
                         vik_viewport_get_pixmap(zts->vw->viking_vvp),
                         0, 0, 0, 0, -1, -1);
 
@@ -1408,13 +1415,13 @@ static VikLayerToolFuncStatus zoomtool_move (VikLayer *vl, GdkEventMotion *event
     }
 
     // Draw the box
-    gdk_draw_rectangle (zts->pixmap, GTK_WIDGET(zts->vw->viking_vvp)->style->black_gc, FALSE, xx, yy, width, height);
+    gdk_draw_rectangle (zts->pixmap, gtk_widget_get_style(GTK_WIDGET(zts->vw->viking_vvp))->black_gc, FALSE, xx, yy, width, height);
 
     // Only actually draw when there's time to do so
     if (draw_buf_done) {
       static gpointer pass_along[3];
       pass_along[0] = GTK_WIDGET(zts->vw->viking_vvp)->window;
-      pass_along[1] = GTK_WIDGET(zts->vw->viking_vvp)->style->black_gc;
+      pass_along[1] = gtk_widget_get_style(GTK_WIDGET(zts->vw->viking_vvp))->black_gc;
       pass_along[2] = zts->pixmap;
       g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, draw_buf, pass_along, NULL);
       draw_buf_done = FALSE;
@@ -1767,12 +1774,12 @@ static void draw_refresh_cb ( GtkAction *a, VikWindow *vw )
 
 static void menu_addlayer_cb ( GtkAction *a, VikWindow *vw )
 {
 gint type;
VikLayerTypeEnum type;
   for ( type = 0; type < VIK_LAYER_NUM_TYPES; type++ ) {
     if (!strcmp(vik_layer_get_interface(type)->name, gtk_action_get_name(a))) {
       if ( vik_layers_panel_new_layer ( vw->viking_vlp, type ) ) {
-       draw_update ( vw );
-       vw->modified = TRUE;
+        draw_update ( vw );
+        vw->modified = TRUE;
       }
     }
   }
@@ -2016,7 +2023,7 @@ void vik_window_enable_layer_tool ( VikWindow *vw, gint layer_id, gint tool_id )
 static void menu_tool_cb ( GtkAction *old, GtkAction *a, VikWindow *vw )
 {
   /* White Magic, my friends ... White Magic... */
-  int layer_id, tool_id;
+  gint tool_id;
   const GdkCursor *cursor = NULL;
 
   toolbox_activate(vw->vt, gtk_action_get_name(a));
@@ -2041,6 +2048,7 @@ static void menu_tool_cb ( GtkAction *old, GtkAction *a, VikWindow *vw )
   }
   else {
     /* TODO: only enable tools from active layer */
+    VikLayerTypeEnum layer_id;
     for (layer_id=0; layer_id<VIK_LAYER_NUM_TYPES; layer_id++) {
       for ( tool_id = 0; tool_id < vik_layer_get_interface(layer_id)->tools_count; tool_id++ ) {
        if (!strcmp(vik_layer_get_interface(layer_id)->tools[tool_id].radioActionEntry.name, gtk_action_get_name(a))) {
@@ -2063,18 +2071,24 @@ static void window_set_filename ( VikWindow *vw, const gchar *filename )
   if ( filename == NULL )
   {
     vw->filename = NULL;
-    file = _("Untitled");
   }
   else
   {
     vw->filename = g_strdup(filename);
-    file = a_file_basename ( filename );
   }
+
+  /* Refresh window's title */
+  file = window_get_filename ( vw );
   title = g_strdup_printf( "%s - Viking", file );
   gtk_window_set_title ( GTK_WINDOW(vw), title );
   g_free ( title );
 }
 
+static const gchar *window_get_filename ( VikWindow *vw )
+{
+  return vw->filename ? a_file_basename ( vw->filename ) : _("Untitled");
+}
+
 GtkWidget *vik_window_get_drawmode_button ( VikWindow *vw, VikViewportDrawMode mode )
 {
   GtkWidget *mode_button;
@@ -2383,7 +2397,7 @@ static gboolean save_file_as ( GtkAction *a, VikWindow *vw )
     gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_dia), TRUE );
   }
   // Auto append / replace extension with '.vik' to the suggested file name as it's going to be a Viking File
-  gchar* auto_save_name = strdup ( vw->filename ? a_file_basename ( vw->filename ) : _("Untitled") );
+  gchar* auto_save_name = g_strdup ( window_get_filename ( vw ) );
   if ( ! check_file_ext ( auto_save_name, ".vik" ) )
     auto_save_name = g_strconcat ( auto_save_name, ".vik", NULL );
 
@@ -2457,6 +2471,11 @@ static void acquire_from_osm ( GtkAction *a, VikWindow *vw )
 {
   a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_osm_interface );
 }
+
+static void acquire_from_my_osm ( GtkAction *a, VikWindow *vw )
+{
+  a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_osm_my_traces_interface );
+}
 #endif
 
 #ifdef VIK_CONFIG_GEOCACHES
@@ -2474,6 +2493,13 @@ static void acquire_from_geotag ( GtkAction *a, VikWindow *vw )
 }
 #endif
 
+#ifdef VIK_CONFIG_GEONAMES
+static void acquire_from_wikipedia ( GtkAction *a, VikWindow *vw )
+{
+  a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_wikipedia_interface );
+}
+#endif
+
 static void goto_default_location( GtkAction *a, VikWindow *vw)
 {
   struct LatLon ll;
@@ -2486,7 +2512,8 @@ static void goto_default_location( GtkAction *a, VikWindow *vw)
 
 static void goto_address( GtkAction *a, VikWindow *vw)
 {
-  a_vik_goto(vw, vw->viking_vlp, vw->viking_vvp);
+  a_vik_goto ( vw, vw->viking_vvp );
+  vik_layers_panel_emit_update ( vw->viking_vlp );
 }
 
 static void mapcache_flush_cb ( GtkAction *a, VikWindow *vw )
@@ -2494,17 +2521,52 @@ static void mapcache_flush_cb ( GtkAction *a, VikWindow *vw )
   a_mapcache_flush();
 }
 
+static void layer_defaults_cb ( GtkAction *a, VikWindow *vw )
+{
+  gchar **texts = g_strsplit ( gtk_action_get_name(a), "Layer", 0 );
+
+  if ( !texts[1] )
+    return; // Internally broken :(
+
+  if ( ! a_layer_defaults_show_window ( GTK_WINDOW(vw), texts[1] ) )
+    a_dialog_info_msg ( GTK_WINDOW(vw), _("This layer has no configurable properties.") );
+  // NB no update needed
+
+  g_strfreev ( texts );
+}
+
+static void preferences_change_update ( VikWindow *vw, gpointer data )
+{
+  // Want to update all TrackWaypoint layers
+  GList *layers = vik_layers_panel_get_all_layers_of_type ( vw->viking_vlp, VIK_LAYER_TRW, TRUE );
+
+  GList *iter = g_list_first ( layers );
+  while ( iter ) {
+    // Reset the individual waypoints themselves due to the preferences change
+    VikTrwLayer *vtl = VIK_TRW_LAYER(VIK_LAYER(layers->data));
+    vik_trw_layer_reset_waypoints ( vtl );
+       iter = g_list_next ( iter );
+  }
+
+  g_list_free ( layers );
+
+  draw_update ( vw );
+}
+
 static void preferences_cb ( GtkAction *a, VikWindow *vw )
 {
   gboolean wp_icon_size = a_vik_get_use_large_waypoint_icons();
 
   a_preferences_show_window ( GTK_WINDOW(vw) );
 
-  // Delete icon indexing 'cache' and so automatically regenerates with the new setting when changed
-  if (wp_icon_size != a_vik_get_use_large_waypoint_icons())
+  // Has the waypoint size setting changed?
+  if (wp_icon_size != a_vik_get_use_large_waypoint_icons()) {
+    // Delete icon indexing 'cache' and so automatically regenerates with the new setting when changed
     clear_garmin_icon_syms ();
 
-  draw_update ( vw );
+    // Update all windows
+    g_slist_foreach ( window_list, (GFunc) preferences_change_update, NULL );
+  }
 }
 
 static void default_location_cb ( GtkAction *a, VikWindow *vw )
@@ -2512,21 +2574,25 @@ static void default_location_cb ( GtkAction *a, VikWindow *vw )
   /* Simplistic repeat of preference setting
      Only the name & type are important for setting the preference via this 'external' way */
   VikLayerParam pref_lat[] = {
-    { VIKING_PREFERENCES_NAMESPACE "default_latitude",
+    { VIK_LAYER_NUM_TYPES,
+      VIKING_PREFERENCES_NAMESPACE "default_latitude",
       VIK_LAYER_PARAM_DOUBLE,
       VIK_LOCATION_LAT,
       NULL,
       VIK_LAYER_WIDGET_SPINBUTTON,
       NULL,
+      NULL,
       NULL },
   };
   VikLayerParam pref_lon[] = {
-    { VIKING_PREFERENCES_NAMESPACE "default_longitude",
+    { VIK_LAYER_NUM_TYPES,
+      VIKING_PREFERENCES_NAMESPACE "default_longitude",
       VIK_LAYER_PARAM_DOUBLE,
       VIK_LOCATION_LONG,
       NULL,
       VIK_LAYER_WIDGET_SPINBUTTON,
       NULL,
+      NULL,
       NULL },
   };
 
@@ -3127,12 +3193,16 @@ static GtkActionEntry entries[] = {
 #endif
 #ifdef VIK_CONFIG_OPENSTREETMAP
   { "AcquireOSM",   NULL,                 N_("_OSM Traces..."),          NULL,         N_("Get traces from OpenStreetMap"),            (GCallback)acquire_from_osm       },
+  { "AcquireMyOSM", NULL,                 N_("_My OSM Traces..."),       NULL,         N_("Get Your Own Traces from OpenStreetMap"),   (GCallback)acquire_from_my_osm    },
 #endif
 #ifdef VIK_CONFIG_GEOCACHES
   { "AcquireGC",   NULL,                 N_("Geo_caches..."),            NULL,         N_("Get Geocaches from geocaching.com"),            (GCallback)acquire_from_gc       },
 #endif
 #ifdef VIK_CONFIG_GEOTAG
   { "AcquireGeotag", NULL,               N_("From Geotagged _Images..."), NULL,         N_("Create waypoints from geotagged images"),       (GCallback)acquire_from_geotag   },
+#endif
+#ifdef VIK_CONFIG_GEONAMES
+  { "AcquireWikipedia", NULL,            N_("From _Wikipedia Waypoints"), NULL,         N_("Create waypoints from Wikipedia items in the current view"), (GCallback)acquire_from_wikipedia },
 #endif
   { "Save",      GTK_STOCK_SAVE,         N_("_Save"),                         "<control>S", N_("Save the file"),                                (GCallback)save_file             },
   { "SaveAs",    GTK_STOCK_SAVE_AS,      N_("Save _As..."),                      NULL,  N_("Save the file under different name"),           (GCallback)save_file_as          },
@@ -3156,24 +3226,6 @@ static GtkActionEntry entries[] = {
   { "ZoomIn",    GTK_STOCK_ZOOM_IN,      N_("Zoom _In"),                   "<control>plus", NULL,                                           (GCallback)draw_zoom_cb          },
   { "ZoomOut",   GTK_STOCK_ZOOM_OUT,     N_("Zoom _Out"),                 "<control>minus", NULL,                                           (GCallback)draw_zoom_cb          },
   { "ZoomTo",    GTK_STOCK_ZOOM_FIT,     N_("Zoom _To..."),               "<control>Z", NULL,                                           (GCallback)zoom_to_cb            },
-  { "Zoom0.25",  NULL,                   N_("0.25"),                          NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom0.5",   NULL,                   N_("0.5"),                           NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom1",     NULL,                   N_("1"),                             NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom2",     NULL,                   N_("2"),                             NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom4",     NULL,                   N_("4"),                             NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom8",     NULL,                   N_("8"),                             NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom16",    NULL,                   N_("16"),                            NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom32",    NULL,                   N_("32"),                            NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom64",    NULL,                   N_("64"),                            NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom128",   NULL,                   N_("128"),                           NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom256",   NULL,                   N_("256"),                           NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom512",   NULL,                   N_("512"),                           NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom1024",  NULL,                   N_("1024"),                          NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom2048",  NULL,                   N_("2048"),                          NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom4096",  NULL,                   N_("4096"),                          NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom8192",  NULL,                   N_("8192"),                          NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom16384", NULL,                   N_("16384"),                         NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
-  { "Zoom32768", NULL,                   N_("32768"),                         NULL,         NULL,                                           (GCallback)draw_zoom_cb          },
   { "PanNorth",  NULL,                   N_("Pan _North"),                "<control>Up",    NULL,                                           (GCallback)draw_pan_cb },
   { "PanEast",   NULL,                   N_("Pan _East"),                 "<control>Right", NULL,                                           (GCallback)draw_pan_cb },
   { "PanSouth",  NULL,                   N_("Pan _South"),                "<control>Down",  NULL,                                           (GCallback)draw_pan_cb },
@@ -3188,6 +3240,7 @@ static GtkActionEntry entries[] = {
   { "MapCacheFlush",NULL,                N_("_Flush Map Cache"),              NULL,         NULL,                                           (GCallback)mapcache_flush_cb     },
   { "SetDefaultLocation", GTK_STOCK_GO_FORWARD, N_("_Set the Default Location"), NULL, N_("Set the Default Location to the current position"),(GCallback)default_location_cb },
   { "Preferences",GTK_STOCK_PREFERENCES, N_("_Preferences"),                  NULL,         NULL,                                           (GCallback)preferences_cb              },
+  { "LayerDefaults",GTK_STOCK_PROPERTIES, N_("_Layer Defaults"),             NULL,         NULL,                                           NULL },
   { "Properties",GTK_STOCK_PROPERTIES,   N_("_Properties"),                   NULL,         NULL,                                           (GCallback)menu_properties_cb    },
 
   { "HelpEntry", GTK_STOCK_HELP,         N_("_Help"),                         "F1",         NULL,                                           (GCallback)help_help_cb     },
@@ -3308,6 +3361,22 @@ static void window_create_ui( VikWindow *window )
       // Overwrite with actual number to use
       radio->value = ntools;
     }
+
+    GtkActionEntry action_dl;
+    gtk_ui_manager_add_ui(uim, mid,  "/ui/MainMenu/Edit/LayerDefaults",
+                         vik_layer_get_interface(i)->name,
+                         g_strdup_printf("Layer%s", vik_layer_get_interface(i)->fixed_layer_name),
+                         GTK_UI_MANAGER_MENUITEM, FALSE);
+
+    // For default layers use action names of the form 'Layer<LayerName>'
+    // This is to avoid clashing with just the layer name used above for the tool actions
+    action_dl.name = g_strconcat("Layer", vik_layer_get_interface(i)->fixed_layer_name, NULL);
+    action_dl.stock_id = NULL;
+    action_dl.label = g_strconcat("_", vik_layer_get_interface(i)->name, "...", NULL); // Prepend marker for keyboard accelerator
+    action_dl.accelerator = NULL;
+    action_dl.tooltip = NULL;
+    action_dl.callback = (GCallback)layer_defaults_cb;
+    gtk_action_group_add_actions(action_group, &action_dl, 1, window);
   }
   g_object_unref (icon_factory);
 
@@ -3323,6 +3392,10 @@ static void window_create_ui( VikWindow *window )
       g_object_set(action, "sensitive", FALSE, NULL);
     }
   }
+
+  // This is done last so we don't need to track the value of mid anymore
+  vik_ext_tools_add_action_items ( window, window->uim, action_group, mid );
+
   window->action_group = action_group;
 
   accel_group = gtk_ui_manager_get_accel_group (uim);
@@ -3390,14 +3463,14 @@ void vik_window_set_selected_trw_layer ( VikWindow *vw, gpointer vtl )
   vik_viewport_set_highlight_thickness ( vw->viking_vvp, vik_trw_layer_get_property_tracks_line_thickness (vw->containing_vtl) );
 }
 
-gpointer vik_window_get_selected_tracks ( VikWindow *vw )
+GHashTable *vik_window_get_selected_tracks ( VikWindow *vw )
 {
   return vw->selected_tracks;
 }
 
-void vik_window_set_selected_tracks ( VikWindow *vw, gpointer gl, gpointer vtl )
+void vik_window_set_selected_tracks ( VikWindow *vw, GHashTable *ght, gpointer vtl )
 {
-  vw->selected_tracks = gl;
+  vw->selected_tracks = ght;
   vw->containing_vtl  = vtl;
   /* Clear others */
   vw->selected_vtl       = NULL;
@@ -3426,14 +3499,14 @@ void vik_window_set_selected_track ( VikWindow *vw, gpointer *vt, gpointer vtl )
   vik_viewport_set_highlight_thickness ( vw->viking_vvp, vik_trw_layer_get_property_tracks_line_thickness (vw->containing_vtl) );
 }
 
-gpointer vik_window_get_selected_waypoints ( VikWindow *vw )
+GHashTable *vik_window_get_selected_waypoints ( VikWindow *vw )
 {
   return vw->selected_waypoints;
 }
 
-void vik_window_set_selected_waypoints ( VikWindow *vw, gpointer gl, gpointer vtl )
+void vik_window_set_selected_waypoints ( VikWindow *vw, GHashTable *ght, gpointer vtl )
 {
-  vw->selected_waypoints = gl;
+  vw->selected_waypoints = ght;
   vw->containing_vtl     = vtl;
   /* Clear others */
   vw->selected_vtl       = NULL;
@@ -3483,3 +3556,8 @@ gboolean vik_window_clear_highlight ( VikWindow *vw )
   }
   return need_redraw;
 }
+
+GThread *vik_window_get_thread ( VikWindow *vw )
+{
+  return vw->thread;
+}