using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Reflection; using System.Windows.Forms; using DelftTools.Controls; using DelftTools.Controls.Swf; using DelftTools.Shell.Gui; using DelftTools.Utils; using DelftTools.Utils.Aop; using DelftTools.Utils.Collections; using DelftTools.Utils.Collections.Generic; using DeltaShell.Plugins.SharpMapGis.Gui.Properties; using DeltaShell.Plugins.SharpMapGis.Tools; using GeoAPI.Extensions.Feature; using GeoAPI.Geometries; using GisSharpBlog.NetTopologySuite.Geometries; using SharpMap; using SharpMap.Api.Layers; using SharpMap.CoordinateSystems.Transformations; using SharpMap.Layers; using SharpMap.UI.Forms; using SharpMap.UI.Tools; namespace DeltaShell.Plugins.SharpMapGis.Gui.Forms { public partial class MapView : UserControl, ICanvasEditor, ICompositeView, ISearchableView { private bool canAddPoint = true; private bool canDeleteItem = true; private bool canMoveItem = true; private bool canMoveItemLinear = true; private bool canSelectItem = true; private bool settingSelection = false; private readonly StackTrace constructorStackTrace; public MapView() { InitializeComponent(); IsAllowSyncWithGuiSelection = true; TabControl = new MapViewTabControl { Size = new Size(300, 250), Dock = DockStyle.Bottom }; Controls.Add(TabControl); MapControl.SelectedFeaturesChanged += (s, e) => SyncMapViewEditorSelection(); Splitter.ControlToHide = TabControl; TabControl.ViewCollectionChanged += OnTabControlOnViewCollectionChanged; // hide for now IsTabControlVisible = false; // add some tools here, to avoid references to DeltaShell projects in SharpMap MapControl.Tools.Add(new ExportMapToImageMapTool()); Map = new Map(MapControl.ClientSize) { Zoom = 100 }; if (Assembly.GetEntryAssembly() == null) // HACK: detecting nasty dispose exceptions when assembly empty - we run from non-exe (test) { constructorStackTrace = new StackTrace(); } } public bool IsTabControlVisible { get { return Splitter.Visible; } set { if (IsTabControlVisible == value) { return; } Splitter.ToggleState(); Splitter.Visible = value; TabControl.SendToBack(); } } /// /// If true, selection in the MapView is synched with Gui.Selection /// public bool IsAllowSyncWithGuiSelection { get; set; } public Map Map { get { return MapControl.Map; } set { if (MapControl.Map == value) { return; } UnsubscribeEvents(); if (MapControl != null) { MapControl.Map = value; } SubscribeEvents(); } } public MapControl MapControl { get; private set; } public MapViewTabControl TabControl { get; private set; } public CollapsibleSplitter Splitter { get; set; } public Func GetDataForLayer { get; set; } public Func GetLayerForData { get; set; } public bool CanSelectItem { get { return canSelectItem; } set { canSelectItem = value; } } public bool IsSelectItemActive { get { return (MapControl.SelectTool.IsActive && (MapControl.SelectTool.MultiSelectionMode == MultiSelectionMode.Rectangle)); } set { if (value) { MapControl.SelectTool.MultiSelectionMode = MultiSelectionMode.Rectangle; MapControl.ActivateTool(MapControl.SelectTool); } } } public bool CanMoveItem { get { return canMoveItem; } set { canMoveItem = value; } } public bool IsMoveItemActive { get { return MapControl.MoveTool.IsActive; } set { // only support setting to true if (value) { MapControl.ActivateTool(MapControl.MoveTool); } } } public bool CanMoveItemLinear { get { return canMoveItemLinear; } set { canMoveItemLinear = value; } } public bool IsMoveItemLinearActive { get { return MapControl.LinearMoveTool.IsActive; } set { if (value) { MapControl.ActivateTool(MapControl.LinearMoveTool); } } } public bool CanDeleteItem { get { return canDeleteItem; } set { canDeleteItem = value; } } public bool IsDeleteItemActive { get { return true; } set {} } public bool CanAddPoint { get { return canAddPoint; } set { canAddPoint = value; } } public bool IsAddPointActive { get { var tool = (CurvePointTool) MapControl.GetToolByName("CurvePoint"); return tool.IsActive && tool.Mode == CurvePointTool.EditMode.Add; } set { if (value) { var tool = (CurvePointTool) MapControl.GetToolByName("CurvePoint"); tool.Mode = CurvePointTool.EditMode.Add; MapControl.ActivateTool(tool); } } } public bool IsRemovePointActive { get { var tool = (CurvePointTool) MapControl.GetToolByName("CurvePoint"); return tool.IsActive && tool.Mode == CurvePointTool.EditMode.Remove; } set { if (value) { var tool = (CurvePointTool) MapControl.GetToolByName("CurvePoint"); tool.Mode = CurvePointTool.EditMode.Remove; MapControl.ActivateTool(tool); } } } public bool CanRemovePoint { get { return true; } } public ViewInfo ViewInfo { get; set; } /// /// Expects a Map /// public object Data { get { return MapControl.Map; } set { Map = (Map) value; } } public Image Image { get { return Resources.Map; } set {} } public IEventedList ChildViews { get { return TabControl.ChildViews; } } public bool HandlesChildViews { get { return true; } } public IView OpenLayerAttributeTable(ILayer layer, Action openViewMethod = null) { if (!(layer is VectorLayer) || !layer.ShowAttributeTable) { return null; } var view = TabControl.ChildViews.OfType().FirstOrDefault(v => v.Data == layer); if (view != null) { TabControl.ActiveView = view; return null; } if (!IsTabControlVisible) { IsTabControlVisible = true; } view = new VectorLayerAttributeTableView { Data = layer, Layer = layer, Text = layer.Name, ZoomToFeature = feature => EnsureVisible(feature), OpenViewMethod = openViewMethod, DeleteSelectedFeatures = () => MapControl.DeleteTool.DeleteSelection() }; TabControl.AddView(view); return view; } public void EnsureVisible(object item) { // recursive to tabs foreach (var view in TabControl.ChildViews) { try { view.EnsureVisible(item); } catch (Exception) { /* gulp */ } } var layer = item as ILayer; if (layer != null) { layer.Visible = true; return; } // try show in map var feature = item as IFeature; if (feature == null) { return; } ILayer featureLayer = MapControl.Map.GetLayerByFeature(feature); if (featureLayer == null) { return; } EnsureFeatureVisible(feature, layer); } public void ActivateChildView(IView childView) { TabControl.ActiveView = childView; if (IsTabControlVisible && Splitter.IsCollapsed) { Splitter.ToggleState(); //re-show tabcontrol now } } public IEnumerable> SearchItemsByText(string text, bool caseSensitive, Func isSearchCancelled, Action setProgressPercentage) { var visibleLayers = Map.GetAllVisibleLayers(false).Where(l => l.DataSource != null && l.DataSource.Features != null).ToList(); if (visibleLayers.Count == 0) { yield break; } var percentageStep = 100.0/visibleLayers.Count; var currentPercentage = 0.0; foreach (var layer in visibleLayers) { if (isSearchCancelled()) { yield break; } var matchingItems = layer.DataSource.Features.OfType(). Where(n => n.Name != null && (caseSensitive ? n.Name.Contains(text) : n.Name.ToLower().Contains(text.ToLower()))); foreach (var item in matchingItems) { yield return new System.Tuple(string.Format("{0} ({1})", item.Name, layer.Name), item); } currentPercentage += percentageStep; setProgressPercentage((int) currentPercentage); } } /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { try { if (disposing) { MapControl.Dispose(); TabControl.Dispose(); } if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } catch (Exception e) { Console.WriteLine("Exception occured during dispose: " + e); Console.WriteLine("Constructor stack trace: " + constructorStackTrace); } } private void EnsureFeatureVisible(IFeature feature, ILayer layer) { var envelope = feature.Geometry.EnvelopeInternal; if (feature.Geometry is IPoint) { var point = (IPoint) feature.Geometry; var envelopeExpansion = 100d; //crap!!!!! envelope = new Envelope(point.X - envelopeExpansion, point.X + envelopeExpansion, point.Y - envelopeExpansion, point.Y + envelopeExpansion); } else { envelope.ExpandBy(envelope.Width*0.05); // 10% bigger } if (layer != null && layer.CoordinateTransformation != null) { envelope = GeometryTransform.TransformBox(envelope, layer.CoordinateTransformation.MathTransform); } Map.ZoomToFit(envelope); MapControl.Refresh(); } private void SubscribeEvents() { if (Map == null) { return; } Map.CollectionChanged += mapCollectionChangedEventHandler; DataBindings.Add("Text", Map, "Name", false, DataSourceUpdateMode.OnPropertyChanged); Text = Map.Name; } private void UnsubscribeEvents() { if (Map == null) { return; } Map.CollectionChanged -= mapCollectionChangedEventHandler; DataBindings.Clear(); } private void mapCollectionChangedEventHandler(object sender, NotifyCollectionChangingEventArgs e) { var layer = e.Item as ILayer; if (e.Action == NotifyCollectionChangeAction.Remove) { RemoveTabFor(layer); } } [InvokeRequired] private void RemoveTabFor(ILayer layer) { var groupLayer = layer as GroupLayer; if (groupLayer != null) { foreach (var subLayer in groupLayer.Layers) { RemoveTabFor(subLayer); } } var dataForLayer = GetDataForLayer != null ? GetDataForLayer(layer) ?? layer : layer; var view = TabControl.ChildViews.FirstOrDefault(v => Equals(v.Data, dataForLayer)); if (view == null) { return; } TabControl.RemoveView(view); } private void MapControlMouseMove(object sender, MouseEventArgs e) { var worldLocation = MapControl.Map.ImageToWorld(e.Location); if (SharpMapGisGuiPlugin.Instance != null && SharpMapGisGuiPlugin.Instance.Gui != null && worldLocation != null) { var coordinateSystem = MapControl.Map.CoordinateSystem != null ? "(" + MapControl.Map.CoordinateSystem.Name + ")" : ""; var message = string.Format("Current map coordinates {0} : {1}, {2}", coordinateSystem, worldLocation.X, worldLocation.Y); // HACK:.... if (SharpMapGisGuiPlugin.Instance.Gui.MainWindow != null) { SharpMapGisGuiPlugin.Instance.Gui.MainWindow.StatusBarMessage = message; } } } private void MapControlMouseLeave(object sender, EventArgs e) { // HACK:.... // HACK, TODO: move to GuiPlugin or some service class if (SharpMapGisGuiPlugin.Instance != null && SharpMapGisGuiPlugin.Instance.Gui != null) { if (SharpMapGisGuiPlugin.Instance.Gui.MainWindow != null) { SharpMapGisGuiPlugin.Instance.Gui.MainWindow.StatusBarMessage = ""; } } } /// /// Bubble MouseEnter to MapView (otherwise that event will never be fired) /// /// /// private void MapControlMouseEnter(object sender, EventArgs e) { OnMouseEnter(e); } private void SyncMapViewEditorSelection() { var features = MapControl.SelectedFeatures; if (features == null || settingSelection) { return; } settingSelection = true; features = features.ToList(); foreach (var mapViewEditor in TabControl.ChildViews.OfType()) { mapViewEditor.SelectedFeatures = features; } settingSelection = false; } private void MapEditorSelectedFeaturesChanged(object sender, EventArgs e) { var mapViewEditor = sender as ILayerEditorView; if (mapViewEditor == null || settingSelection) { return; } settingSelection = true; MapControl.SelectTool.Select(mapViewEditor.SelectedFeatures); settingSelection = false; } private void OnTabControlOnViewCollectionChanged(object s, NotifyCollectionChangedEventArgs e) { if (e.Action == NotifyCollectionChangedAction.Add) { var mapEditor = e.NewItems != null ? e.NewItems.OfType().FirstOrDefault() : null; if (mapEditor != null) { mapEditor.SelectedFeaturesChanged += MapEditorSelectedFeaturesChanged; mapEditor.Layer = GetLayerForData != null ? GetLayerForData(mapEditor.Data) : null; } if (!IsTabControlVisible) { IsTabControlVisible = true; } } if (e.Action == NotifyCollectionChangedAction.Remove) { var mapEditor = e.OldItems != null ? e.OldItems.OfType().FirstOrDefault() : null; if (mapEditor != null) { mapEditor.SelectedFeaturesChanged -= MapEditorSelectedFeaturesChanged; mapEditor.Layer = null; mapEditor.Data = null; mapEditor.Dispose(); } if (IsTabControlVisible && !TabControl.ChildViews.Any()) { IsTabControlVisible = false; } } } } }