// Copyright 2014-, SharpMapTeam
//
// This file is part of SharpMap.
// SharpMap is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// SharpMap 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 Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public License
// along with SharpMap; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System.ComponentModel;
using System.Drawing.Drawing2D;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
using MouseEventArgs = System.Windows.Forms.MouseEventArgs;
namespace SharpMap.UI.WPF
{
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Drawing;
using System.Linq;
using System.Windows;
using System.Windows.Forms.Integration;
using System.Windows.Input;
using GeoAPI.Geometries;
using Data.Providers;
using Forms;
using Layers;
using Rendering.Decoration;
using Rendering.Decoration.ScaleBar;
using KeyEventArgs = KeyEventArgs;
using MouseEventArgs = MouseEventArgs;
///
/// Extends WindowsFormsHost and encapsulates SharpMap specific code.
///
public class SharpMapHost : WindowsFormsHost, INotifyPropertyChanged
{
// Dependency Property to store MapLayers.
public static readonly DependencyProperty MapLayersProperty =
DependencyProperty.Register("MapLayers", typeof (ObservableCollection), typeof (SharpMapHost), new PropertyMetadata(SetMapLayersCallback));
// Dependency Property store store BackgroundLayer.
public static readonly DependencyProperty BackgroundLayerProperty =
DependencyProperty.Register("BackgroundLayer", typeof (Layer), typeof (SharpMapHost), new PropertyMetadata(SetBackgroundLayerCallback));
// Dependency Property to store ActiveTool.
public static readonly DependencyProperty ActiveToolProperty =
DependencyProperty.Register("ActiveTool", typeof (MapBox.Tools), typeof (SharpMapHost), new PropertyMetadata(SetActiveToolCallback));
// Dependency Property to store MaxExtent.
public static readonly DependencyProperty MaxExtentProperty =
DependencyProperty.Register("MaxExtent", typeof (Envelope), typeof (SharpMapHost), new PropertyMetadata(SetMaxExtentCallback));
// Dependency Property to store MapExtent.
public static readonly DependencyProperty MapExtentProperty =
DependencyProperty.Register("MapExtent", typeof (Envelope), typeof (SharpMapHost), new PropertyMetadata(MapExtentCallback));
// Dependency Property to store Rotation kept in MapTransform
public static readonly DependencyProperty MapRotationProperty =
DependencyProperty.Register("MapRotation", typeof(float), typeof(SharpMapHost), new PropertyMetadata(MapRotationCallback));
// Dependency Property used when a new geometry is defined.
public static readonly DependencyProperty DefinedGeometryProperty =
DependencyProperty.Register("DefinedGeometry", typeof (IGeometry), typeof (SharpMapHost), new PropertyMetadata(GeometryDefinedCallback));
// Dependency Property used when right click in a MapFeature.
public static readonly DependencyProperty FeatureRightClickedCommandProperty =
DependencyProperty.Register("FeatureRightClickedCommand", typeof (ICommand), typeof (SharpMapHost));
private readonly MapBox _mapBox;
private VectorLayer _editLayer;
private GeometryProvider _editLayerGeoProvider;
private Coordinate _currentMouseCoordinate;
///
/// Initializes a new instance of the class.
///
public SharpMapHost()
{
_mapBox = new MapBox{
BackColor = Color.White,
Map = new Map{
SRID = 900913
}
};
Child = _mapBox;
MapLayers = new ObservableCollection();
var scaleBar = new ScaleBar{
Anchor = MapDecorationAnchor.LeftBottom
};
_mapBox.Map.Decorations.Add(scaleBar);
_mapBox.PanOnClick = false;
KeyDown += OnKeyDown;
_mapBox.MouseMove += MapBoxOnMouseMove;
}
public ObservableCollection MapLayers
{
get
{
return (ObservableCollection) GetValue(MapLayersProperty);
}
set
{
SetValue(MapLayersProperty, value);
}
}
public Layer BackgroundLayer
{
get
{
return (Layer) GetValue(BackgroundLayerProperty);
}
set
{
SetValue(BackgroundLayerProperty, value);
}
}
public MapBox.Tools ActiveTool
{
get
{
return (MapBox.Tools) GetValue(ActiveToolProperty);
}
set
{
SetValue(ActiveToolProperty, value);
}
}
public string CurrentMouseCoordinateString
{
get
{
return _currentMouseCoordinate != null ? string.Format("{0:0}, {1:0}", _currentMouseCoordinate.X, _currentMouseCoordinate.Y) : "";
}
}
public Coordinate CurrentMouseCoordinate
{
get
{
return _currentMouseCoordinate;
}
}
public Envelope MaxExtent
{
get
{
return (Envelope) GetValue(MaxExtentProperty);
}
set
{
SetValue(MaxExtentProperty, value);
}
}
public Envelope MapExtent
{
get
{
return _mapBox.Map.Envelope;
}
set
{
SetValue(MapExtentProperty, value);
}
}
public float MapRotation
{
get
{
return _mapBox.Map.MapTransformRotation;
}
set
{
SetValue(MapRotationProperty, value);
}
}
public IGeometry DefinedGeometry
{
get
{
return (IGeometry) GetValue(DefinedGeometryProperty);
}
set
{
SetValue(DefinedGeometryProperty, value);
}
}
///
/// The command that is invoked when a feature is right clicked
///
public ICommand FeatureRightClickedCommand
{
get
{
return GetValue(FeatureRightClickedCommandProperty) as ICommand;
}
set
{
SetValue(FeatureRightClickedCommandProperty, value);
}
}
///
/// Gets called when changes on MapLayers
///
/// The sender object
/// The event arguments
private static void SetMapLayersCallback(object sender, DependencyPropertyChangedEventArgs args)
{
var host = sender as SharpMapHost;
if (host == null)
{
return;
}
var oldLayers = args.OldValue as ObservableCollection;
if (oldLayers != null)
{
oldLayers.CollectionChanged -= host.OnMapLayerChanged;
}
var newLayers = args.NewValue as ObservableCollection;
if (newLayers != null)
{
newLayers.CollectionChanged += host.OnMapLayerChanged;
}
}
///
/// Gets called when changes on BackgroundLayer
///
/// The sender object
/// The event arguments
private static void SetBackgroundLayerCallback(object sender, DependencyPropertyChangedEventArgs args)
{
var host = sender as SharpMapHost;
if (host == null)
{
return;
}
var mapBox = host._mapBox;
var layer = args.NewValue as Layer;
if (layer != null)
{
mapBox.Map.BackgroundLayer.Add(layer);
}
mapBox.Refresh();
}
///
/// Gets called when changes on ActiveTool
///
/// The sender object
/// The event arguments
private static void SetActiveToolCallback(object sender, DependencyPropertyChangedEventArgs args)
{
var host = sender as SharpMapHost;
if (host == null)
{
return;
}
var mapBox = host._mapBox;
var newTool = (MapBox.Tools) args.NewValue;
mapBox.ActiveTool = newTool;
}
///
/// Gets called when changes on MaxExtent
///
/// The sender object
/// The event arguments
private static void SetMaxExtentCallback(object sender, DependencyPropertyChangedEventArgs args)
{
var host = sender as SharpMapHost;
if (host == null)
{
return;
}
var mapBox = host._mapBox;
var extent = (Envelope) args.NewValue;
if (extent != null)
{
mapBox.Map.EnforceMaximumExtents = true;
mapBox.Map.MaximumExtents = extent;
}
}
///
/// Gets called when changes on MapExtent
///
/// The sender object
/// The event arguments
private static void MapExtentCallback(object sender, DependencyPropertyChangedEventArgs args)
{
var host = sender as SharpMapHost;
if (host == null)
{
return;
}
var mapBox = host._mapBox;
var extent = (Envelope) args.NewValue;
mapBox.Map.ZoomToBox(extent);
mapBox.Refresh();
}
///
/// Gets called when changes on MapExtent
///
/// The sender object
/// The event arguments
private static void MapRotationCallback(object sender, DependencyPropertyChangedEventArgs args)
{
var host = sender as SharpMapHost;
if (host == null)
{
return;
}
var mapBox = host._mapBox;
float rotation = (float)args.NewValue;
var mapTransform = new Matrix();
mapTransform.RotateAt(rotation, new PointF(mapBox.Width / 2f, mapBox.Height / 2f));
mapBox.Map.MapTransform = mapTransform;
mapBox.Refresh();
}
///
/// Gets called when changes on GeometryDefined
///
/// The sender object
/// The event arguments
private static void GeometryDefinedCallback(object sender, DependencyPropertyChangedEventArgs args)
{
var host = sender as SharpMapHost;
if (host == null)
{
return;
}
if (host._editLayer == null)
{
host._editLayer = new VectorLayer("EditLayer");
host._editLayerGeoProvider = new GeometryProvider(new List());
host._editLayer.DataSource = host._editLayerGeoProvider;
host.MapLayers.Add(host._editLayer);
}
host._editLayerGeoProvider.Geometries.Clear();
var geom = (IGeometry) args.NewValue;
if (geom != null)
{
host._editLayerGeoProvider.Geometries.Add(geom);
}
host._mapBox.Refresh();
}
///
/// Gets called when keyboard key pressed. Pans the map according to arrow keys.
///
/// The sender object
/// The event arguments
private void OnKeyDown(object sender, KeyEventArgs keyEventArgs)
{
var currentEnvelope = _mapBox.Map.Envelope;
var dX = currentEnvelope.Width/2;
var dY = currentEnvelope.Height/2;
var x = _mapBox.Map.Center.X;
var y = _mapBox.Map.Center.Y;
switch (keyEventArgs.Key)
{
case Key.Left:
x -= dX;
keyEventArgs.Handled = true;
break;
case Key.Right:
x += dX;
keyEventArgs.Handled = true;
break;
case Key.Up:
y += dY;
keyEventArgs.Handled = true;
break;
case Key.Down:
y -= dY;
keyEventArgs.Handled = true;
break;
}
_mapBox.Map.Center = new Coordinate(x, y);
_mapBox.Refresh();
}
///
/// Gets called when changes in MapLayers
///
/// The sender object
/// The event arguments
private void OnMapLayerChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
{
var layers = e.NewItems;
if (layers != null)
{
foreach (var layer in layers)
{
var castedLayer = layer as ILayer;
if (castedLayer != null && _mapBox.Map.Layers.All(l => l.LayerName != castedLayer.LayerName))
_mapBox.Map.Layers.Add(castedLayer);
}
}
}
break;
case NotifyCollectionChangedAction.Remove:
{
var layers = e.OldItems;
if (layers != null)
{
foreach (var layer in layers)
{
var castedLayer = layer as ILayer;
if (castedLayer != null && _mapBox.Map.Layers.Any(l => l.LayerName == castedLayer.LayerName))
_mapBox.Map.Layers.Remove(castedLayer);
}
}
}
break;
case NotifyCollectionChangedAction.Reset:
_mapBox.Map.Layers.Clear();
break;
}
_mapBox.Refresh();
}
public void ZoomToExtents()
{
_mapBox.Map.ZoomToExtents();
_mapBox.Refresh();
}
public void ZoomToEnvelope(Envelope env)
{
_mapBox.Map.ZoomToBox(env);
_mapBox.Refresh();
}
///
/// Gets called when mouse moves over map
///
/// The click coordinate
/// The event arguments
private void MapBoxOnMouseMove(Coordinate worldPos, MouseEventArgs mouseEventArgs)
{
_currentMouseCoordinate = worldPos;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("CurrentMouseCoordinate"));
PropertyChanged(this, new PropertyChangedEventArgs("CurrentMouseCoordinateString"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}