// Copyright (C) Stichting Deltares 2018. All rights reserved.
//
// This file is part of Ringtoets.
//
// Ringtoets 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 3 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Core.Common.Controls.TreeView;
using Core.Common.Controls.Views;
using Core.Common.Gui.ContextMenu;
using Core.Components.Gis.Data;
using Core.Components.Gis.Data.Removable;
using Core.Components.Gis.Forms;
using Core.Components.Gis.Helpers;
using Core.Plugins.Map.Helpers;
using Core.Plugins.Map.PresentationObjects;
using MapResources = Core.Plugins.Map.Properties.Resources;
using GuiResources = Core.Common.Gui.Properties.Resources;
namespace Core.Plugins.Map.Legend
{
///
/// The view which shows the data that is added to a .
///
public sealed partial class MapLegendView : UserControl, ISelectionProvider, IView
{
private readonly IContextMenuBuilderProvider contextMenuBuilderProvider;
private IMapControl mapControl;
public event EventHandler SelectionChanged;
///
/// Creates a new instance of .
///
/// The to create context menus.
/// Thrown when is null.
public MapLegendView(IContextMenuBuilderProvider contextMenuBuilderProvider)
{
if (contextMenuBuilderProvider == null)
{
throw new ArgumentNullException(nameof(contextMenuBuilderProvider),
$@"Cannot create a {typeof(MapLegendView).Name} when the context menu builder provider is null.");
}
this.contextMenuBuilderProvider = contextMenuBuilderProvider;
InitializeComponent();
Text = MapResources.General_Map;
RegisterTreeNodeInfos();
treeViewControl.SelectedDataChanged += TreeViewControlSelectedDataChanged;
}
///
/// Gets or sets the for which this legend view is configured
/// to show the internal map data for.
///
public IMapControl MapControl
{
private get
{
return mapControl;
}
set
{
mapControl = value;
Data = value?.Data;
}
}
public object Selection
{
get
{
return treeViewControl.SelectedData;
}
}
public object Data
{
get
{
return (MapDataCollectionContext) treeViewControl.Data;
}
set
{
treeViewControl.Data = value != null
? new MapDataCollectionContext((MapDataCollection) value, null)
: null;
}
}
private void TreeViewControlSelectedDataChanged(object sender, EventArgs e)
{
SelectionChanged?.Invoke(this, new EventArgs());
}
private void RegisterTreeNodeInfos()
{
treeViewControl.RegisterTreeNodeInfo(new TreeNodeInfo
{
Text = context => context.WrappedData.Name,
Image = GetImage,
CanDrag = (context, parent) => true,
CanCheck = context => true,
CheckedState = context => context.WrappedData.IsVisible ? TreeNodeCheckedState.Checked : TreeNodeCheckedState.Unchecked,
OnNodeChecked = FeatureBasedMapDataContextOnNodeChecked,
CanRemove = (context, parent) => CanRemoveMapData((FeatureBasedMapData) context.WrappedData, parent),
OnNodeRemoved = (context, parent) => RemoveFromParent((FeatureBasedMapData) context.WrappedData, parent),
ContextMenuStrip = FeatureBasedMapDataContextContextMenuStrip
});
treeViewControl.RegisterTreeNodeInfo(new TreeNodeInfo
{
Text = context => context.WrappedData.Name,
Image = context => GuiResources.folder,
ChildNodeObjects = GetCollectionChildNodeObjects,
CanDrag = (context, parentData) => context.ParentMapData != null,
CanCheck = context => true,
CheckedState = context => context.WrappedData.IsVisible ? TreeNodeCheckedState.Checked : TreeNodeCheckedState.Unchecked,
OnNodeChecked = MapDataCollectionContextOnNodeChecked,
CanDrop = MapDataCollectionCanDropAndInsert,
CanInsert = MapDataCollectionCanDropAndInsert,
OnDrop = MapDataCollectionOnDrop,
ContextMenuStrip = MapDataCollectionContextMenuStrip
});
}
private StrictContextMenuItem CreateZoomToExtentsItem(MapDataContext context)
{
StrictContextMenuItem zoomToExtentsItem = null;
if (context is MapDataCollectionContext)
{
zoomToExtentsItem = CreateZoomToExtentsItem((MapDataCollection) context.WrappedData);
}
if (context is FeatureBasedMapDataContext)
{
zoomToExtentsItem = CreateZoomToExtentsItem((FeatureBasedMapData) context.WrappedData);
}
return zoomToExtentsItem;
}
#region MapData
private StrictContextMenuItem CreateZoomToExtentsItem(FeatureBasedMapData nodeData)
{
bool hasFeatures = nodeData.Features.Any();
bool enabled = nodeData.IsVisible && hasFeatures;
string toolTip;
if (nodeData.IsVisible)
{
toolTip = hasFeatures
? MapResources.MapLegendView_CreateZoomToExtentsItem_ZoomToAll_Tooltip
: MapResources.MapLegendView_CreateZoomToExtentsItem_NoFeatures_ZoomToAllDisabled_Tooltip;
}
else
{
toolTip = MapResources.MapLegendView_CreateZoomToExtentsItem_ZoomToAllDisabled_Tooltip;
}
return CreateZoomToExtentsItem(nodeData, toolTip, enabled);
}
private StrictContextMenuItem CreateZoomToExtentsItem(MapDataCollection nodeData)
{
FeatureBasedMapData[] featureBasedMapDatas = nodeData.GetFeatureBasedMapDataRecursively().ToArray();
var isVisible = false;
var hasFeatures = false;
foreach (FeatureBasedMapData mapData in featureBasedMapDatas)
{
if (mapData.IsVisible)
{
isVisible = true;
if (mapData.Features.Any())
{
hasFeatures = true;
break;
}
}
}
bool enabled = isVisible && hasFeatures;
string toolTip;
if (isVisible)
{
toolTip = hasFeatures
? MapResources.MapLegendView_CreateZoomToExtentsItem_MapDataCollection_ZoomToAll_Tooltip
: MapResources.MapLegendView_CreateZoomToExtentsItem_MapDataCollection_NoFeatures_ZoomToAllDisabled_Tooltip;
}
else
{
toolTip = MapResources.MapLegendView_CreateZoomToExtentsItem_MapDataCollection_ZoomToAllDisabled_Tooltip;
}
return CreateZoomToExtentsItem(nodeData, toolTip, enabled);
}
private StrictContextMenuItem CreateZoomToExtentsItem(MapData nodeData, string toolTip, bool isEnabled)
{
return new StrictContextMenuItem($"&{MapResources.Ribbon_ZoomToAll}",
toolTip,
MapResources.ZoomToAllIcon,
(sender, args) => MapControl?.ZoomToAllVisibleLayers(nodeData))
{
Enabled = isEnabled
};
}
private static void NotifyMapDataParents(MapDataContext context)
{
foreach (MapDataCollection mapDataCollection in MapDataContextHelper.GetParentsFromContext(context))
{
mapDataCollection.NotifyObservers();
}
}
#endregion
#region FeatureBasedMapDataContext
private static Image GetImage(FeatureBasedMapDataContext context)
{
if (context.WrappedData is MapPointData)
{
return MapResources.PointsIcon;
}
if (context.WrappedData is MapLineData)
{
return MapResources.LineIcon;
}
if (context.WrappedData is MapPolygonData)
{
return MapResources.AreaIcon;
}
return GuiResources.folder;
}
private static void FeatureBasedMapDataContextOnNodeChecked(FeatureBasedMapDataContext mapDataContext, object parentData)
{
mapDataContext.WrappedData.IsVisible = !mapDataContext.WrappedData.IsVisible;
mapDataContext.WrappedData.NotifyObservers();
NotifyMapDataParents(mapDataContext);
}
private static bool CanRemoveMapData(FeatureBasedMapData mapData, object parent)
{
return mapData is IRemovable && parent is MapDataCollectionContext;
}
private static void RemoveFromParent(FeatureBasedMapData dataToRemove, object parentData)
{
if (CanRemoveMapData(dataToRemove, parentData))
{
var mapDataCollectionContext = (MapDataCollectionContext) parentData;
var collection = (MapDataCollection) mapDataCollectionContext.WrappedData;
collection.Remove(dataToRemove);
collection.NotifyObservers();
}
}
private ContextMenuStrip FeatureBasedMapDataContextContextMenuStrip(FeatureBasedMapDataContext mapDataContext, object parentData, TreeViewControl treeView)
{
return contextMenuBuilderProvider.Get(mapDataContext, treeView)
.AddCustomItem(CreateZoomToExtentsItem(mapDataContext))
.AddSeparator()
.AddDeleteItem()
.AddSeparator()
.AddPropertiesItem()
.Build();
}
#endregion
#region MapDataCollectionContext
private static object[] GetCollectionChildNodeObjects(MapDataCollectionContext context)
{
var childObjects = new List