diff --git a/application/MilitaryPlanner.application b/application/MilitaryPlanner.application
index 508113b..fac1e0e 100644
--- a/application/MilitaryPlanner.application
+++ b/application/MilitaryPlanner.application
@@ -7,14 +7,14 @@
-
+
- wfO19QTf/faxHsMlkhXLFJbx9h+eWETz1IlR0ayr1E0=
+ EMBPjPlzoXVeFky1SyVEP4NsgoCr3m+Xv+PAJDb8xcU=
diff --git a/application/MilitaryPlanner.exe b/application/MilitaryPlanner.exe
index a607ca8..bc15846 100644
Binary files a/application/MilitaryPlanner.exe and b/application/MilitaryPlanner.exe differ
diff --git a/application/MilitaryPlanner.exe.config b/application/MilitaryPlanner.exe.config
index c09b163..f3e7a96 100644
--- a/application/MilitaryPlanner.exe.config
+++ b/application/MilitaryPlanner.exe.config
@@ -1,5 +1,10 @@
+
+
+
+
+
@@ -12,4 +17,23 @@
+
+
+
+ 200
+
+
+ 100
+
+
+ 900
+
+
+ 480
+
+
+ 0
+
+
+
diff --git a/application/MilitaryPlanner.exe.manifest b/application/MilitaryPlanner.exe.manifest
index 47f44c6..fc129f0 100644
--- a/application/MilitaryPlanner.exe.manifest
+++ b/application/MilitaryPlanner.exe.manifest
@@ -486,14 +486,14 @@
-
+
- a5SKu54QOu2khusYWxVDmu0G8BieM5iulCWWsH8Cup0=
+ RFmclQc6UiyJNvUGBVCnzozRHyEDN7u+/7LWwd8hIxg=
@@ -839,13 +839,13 @@
7p8UwQtRbihveyTowoZ6eDC/QsqKyRt14M9oWkwQocU=
-
+
- JgF8u+SmlekVyttocpovsnMnjGwSmU+c9zec8rkLsgE=
+ rbyHaVCrS1SIk4LeaaXZ4OQJXQWS499dkBdRJJMprms=
\ No newline at end of file
diff --git a/source/MilitaryPlanner/App.xaml b/source/MilitaryPlanner/App.xaml
index e7d2a54..0434cdf 100644
--- a/source/MilitaryPlanner/App.xaml
+++ b/source/MilitaryPlanner/App.xaml
@@ -1,7 +1,8 @@
+ StartupUri="Views\MainWindow.xaml"
+ Exit="Application_Exit">
diff --git a/source/MilitaryPlanner/App.xaml.cs b/source/MilitaryPlanner/App.xaml.cs
index 67b7974..f039368 100644
--- a/source/MilitaryPlanner/App.xaml.cs
+++ b/source/MilitaryPlanner/App.xaml.cs
@@ -30,7 +30,10 @@ private void Application_Startup(object sender, StartupEventArgs e)
}
}
- }
-
+ private void Application_Exit(object sender, ExitEventArgs e)
+ {
+ MilitaryPlanner.Properties.Settings.Default.Save();
+ }
+ }
}
diff --git a/source/MilitaryPlanner/Controllers/BasemapGalleryController.cs b/source/MilitaryPlanner/Controllers/BasemapGalleryController.cs
new file mode 100644
index 0000000..b55b023
--- /dev/null
+++ b/source/MilitaryPlanner/Controllers/BasemapGalleryController.cs
@@ -0,0 +1,109 @@
+// Copyright 2015 Esri
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Windows;
+using Esri.ArcGISRuntime.Layers;
+using Esri.ArcGISRuntime.Portal;
+using Esri.ArcGISRuntime.WebMap;
+using MilitaryPlanner.Helpers;
+using MilitaryPlanner.Views;
+using MapView = Esri.ArcGISRuntime.Controls.MapView;
+
+namespace MilitaryPlanner.Controllers
+{
+ class BasemapGalleryController
+ {
+ private readonly MapView _mapView;
+ private readonly BasemapGalleryView _basemapGalleryView;
+ private ArcGISPortal _arcGisPortal;
+
+ public BasemapGalleryController(MapView mapView)
+ {
+ _mapView = mapView;
+
+ _basemapGalleryView = new BasemapGalleryView { PlacementTarget = mapView, ViewModel = { mapView = mapView } };
+
+ var owner = Window.GetWindow(mapView);
+
+ if (owner != null)
+ {
+ owner.LocationChanged += (sender, e) =>
+ {
+ _basemapGalleryView.HorizontalOffset += 1;
+ _basemapGalleryView.HorizontalOffset -= 1;
+ };
+ }
+
+ InitializeArcGISPortal();
+
+ Mediator.Register(Constants.ACTION_UPDATE_BASEMAP, DoUpdateBasemap);
+ }
+
+ public void Toggle()
+ {
+ _basemapGalleryView.ViewModel.Toggle();
+ }
+
+ private async void InitializeArcGISPortal()
+ {
+ _arcGisPortal = await ArcGISPortal.CreateAsync();
+
+ // Load portal basemaps
+ var result = await _arcGisPortal.ArcGISPortalInfo.SearchBasemapGalleryAsync();
+ _basemapGalleryView.ViewModel.Basemaps = new ObservableCollection(result.Results);
+ }
+
+ private async void DoUpdateBasemap(object obj)
+ {
+ try
+ {
+ var item = obj as ArcGISPortalItem;
+
+ if (item != null)
+ {
+ var webmap = await WebMap.FromPortalItemAsync(item);
+
+ while (_mapView.Map.Layers.Any(l => l.ID == "basemap"))
+ {
+ _mapView.Map.Layers.Remove("basemap");
+ }
+
+ foreach (var s in webmap.Basemap.Layers.Reverse())
+ {
+ switch (s.LayerType)
+ {
+ case WebMapLayerType.ArcGISTiledMapServiceLayer:
+ case WebMapLayerType.Unknown:
+ _mapView.Map.Layers.Insert(0,new ArcGISTiledMapServiceLayer(new Uri(s.Url)){ID="basemap"});
+ break;
+ case WebMapLayerType.OpenStreetMap:
+ var layer = new OpenStreetMapLayer(){ID="basemap"};
+ _mapView.Map.Layers.Insert(0,layer);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ catch (Exception)
+ {
+
+ }
+ }
+ }
+}
diff --git a/source/MilitaryPlanner/Helpers/Constants.cs b/source/MilitaryPlanner/Helpers/Constants.cs
index d19201b..35e12de 100644
--- a/source/MilitaryPlanner/Helpers/Constants.cs
+++ b/source/MilitaryPlanner/Helpers/Constants.cs
@@ -36,6 +36,7 @@ static public class Constants
public const string ACTION_EDIT_MISSION_PHASES = "EditMissionPhases";
public const string ACTION_MISSION_CLONED = "EditMissionCloned";
+ public const string ACTION_CLONE_MISSION = "CloneMission";
public const string MSG_ACTION_UPDATE = "update";
public const string MSG_ACTION_REMOVE = "remove";
@@ -45,6 +46,12 @@ static public class Constants
public const string ACTION_COORDINATE_READOUT_FORMAT_CHANGED = "ActionCoordinateReadoutFormatChanged";
+ public const string ACTION_EDIT_GEOMETRY = "ActionEditGeometry";
+ public const string ACTION_EDIT_UNDO = "ActionEditUndo";
+ public const string ACTION_EDIT_REDO = "ActionEditRedo";
+
+ public const string ACTION_UPDATE_BASEMAP = "ActionUpdateBasemap";
+
public const int SAVE_AS_MISSION = 1;
public const int SAVE_AS_GEOMESSAGES = 2;
public const string SAVE_AS_DELIMITER = "::";
diff --git a/source/MilitaryPlanner/Helpers/SettingBindingExtension.cs b/source/MilitaryPlanner/Helpers/SettingBindingExtension.cs
new file mode 100644
index 0000000..857f096
--- /dev/null
+++ b/source/MilitaryPlanner/Helpers/SettingBindingExtension.cs
@@ -0,0 +1,25 @@
+using System.Windows.Data;
+using MilitaryPlanner.Properties;
+
+namespace MilitaryPlanner.Helpers
+{
+ public class SettingBindingExtension : Binding
+ {
+ public SettingBindingExtension()
+ {
+ Initialize();
+ }
+
+ public SettingBindingExtension(string path)
+ : base(path)
+ {
+ Initialize();
+ }
+
+ private void Initialize()
+ {
+ this.Source = Settings.Default;
+ this.Mode = BindingMode.TwoWay;
+ }
+ }
+}
diff --git a/source/MilitaryPlanner/Helpers/TimeAwareMessageLayer.cs b/source/MilitaryPlanner/Helpers/TimeAwareMessageLayer.cs
index 7012d43..eb8096a 100644
--- a/source/MilitaryPlanner/Helpers/TimeAwareMessageLayer.cs
+++ b/source/MilitaryPlanner/Helpers/TimeAwareMessageLayer.cs
@@ -17,6 +17,7 @@
using System.Xml.Schema;
using System.Xml.Serialization;
using Esri.ArcGISRuntime.Data;
+using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Symbology.Specialized;
namespace MilitaryPlanner.Helpers
@@ -39,6 +40,8 @@ public TimeExtent VisibleTimeExtent
set;
}
+ public Geometry SymbolGeometry { get; set; }
+
public Dictionary PhaseControlPointsDictionary = new Dictionary();
public void StoreControlPoints(string phaseID, MilitaryMessage msg)
diff --git a/source/MilitaryPlanner/MilitaryPlanner.csproj b/source/MilitaryPlanner/MilitaryPlanner.csproj
index 0181f23..56d4d4d 100644
--- a/source/MilitaryPlanner/MilitaryPlanner.csproj
+++ b/source/MilitaryPlanner/MilitaryPlanner.csproj
@@ -136,6 +136,7 @@
+
@@ -144,8 +145,10 @@
+
+
@@ -156,6 +159,9 @@
+
+ BasemapGalleryView.xaml
+
EditMissionPhasesView.xaml
@@ -189,6 +195,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/source/MilitaryPlanner/Properties/Settings.Designer.cs b/source/MilitaryPlanner/Properties/Settings.Designer.cs
index d7a8ab7..5cfa07a 100644
--- a/source/MilitaryPlanner/Properties/Settings.Designer.cs
+++ b/source/MilitaryPlanner/Properties/Settings.Designer.cs
@@ -8,23 +8,79 @@
//
//------------------------------------------------------------------------------
-using System.CodeDom.Compiler;
-using System.Configuration;
-using System.Runtime.CompilerServices;
-
namespace MilitaryPlanner.Properties {
- [CompilerGenerated()]
- [GeneratedCode("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
- internal sealed partial class Settings : ApplicationSettingsBase {
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
- private static Settings defaultInstance = ((Settings)(Synchronized(new Settings())));
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("200")]
+ public double Left {
+ get {
+ return ((double)(this["Left"]));
+ }
+ set {
+ this["Left"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("100")]
+ public double Top {
+ get {
+ return ((double)(this["Top"]));
+ }
+ set {
+ this["Top"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("900")]
+ public double Width {
+ get {
+ return ((double)(this["Width"]));
+ }
+ set {
+ this["Width"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("480")]
+ public double Height {
+ get {
+ return ((double)(this["Height"]));
+ }
+ set {
+ this["Height"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("0")]
+ public string WindowState {
+ get {
+ return ((string)(this["WindowState"]));
+ }
+ set {
+ this["WindowState"] = value;
+ }
+ }
}
}
diff --git a/source/MilitaryPlanner/Properties/Settings.settings b/source/MilitaryPlanner/Properties/Settings.settings
index 033d7a5..ef324b9 100644
--- a/source/MilitaryPlanner/Properties/Settings.settings
+++ b/source/MilitaryPlanner/Properties/Settings.settings
@@ -1,7 +1,21 @@
-
-
-
-
-
+
+
+
+
+ 200
+
+
+ 100
+
+
+ 900
+
+
+ 480
+
+
+ 0
+
+
\ No newline at end of file
diff --git a/source/MilitaryPlanner/ViewModels/BasemapGalleryViewModel.cs b/source/MilitaryPlanner/ViewModels/BasemapGalleryViewModel.cs
new file mode 100644
index 0000000..ad89bcb
--- /dev/null
+++ b/source/MilitaryPlanner/ViewModels/BasemapGalleryViewModel.cs
@@ -0,0 +1,48 @@
+// Copyright 2015 Esri
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Collections.ObjectModel;
+using MilitaryPlanner.Helpers;
+using Esri.ArcGISRuntime.Portal;
+
+namespace MilitaryPlanner.ViewModels
+{
+ public class BasemapGalleryViewModel : BaseToolViewModel
+ {
+ public RelayCommand ChangeBasemapCommand { get; set; }
+
+ public BasemapGalleryViewModel()
+ {
+ ChangeBasemapCommand = new RelayCommand(OnChangeBasemapCommand);
+ }
+
+ private ObservableCollection _basemaps;
+
+ public ObservableCollection Basemaps
+ {
+ get { return _basemaps;}
+
+ set
+ {
+ _basemaps = value;
+ RaisePropertyChanged(() => Basemaps);
+ }
+ }
+
+ private void OnChangeBasemapCommand(object obj)
+ {
+ Mediator.NotifyColleagues(Constants.ACTION_UPDATE_BASEMAP, obj);
+ }
+ }
+}
diff --git a/source/MilitaryPlanner/ViewModels/MainWindowViewModel.cs b/source/MilitaryPlanner/ViewModels/MainWindowViewModel.cs
index 709e0fc..29ffb54 100644
--- a/source/MilitaryPlanner/ViewModels/MainWindowViewModel.cs
+++ b/source/MilitaryPlanner/ViewModels/MainWindowViewModel.cs
@@ -11,7 +11,9 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+
using System;
+using System.Windows;
using Esri.ArcGISRuntime;
using Microsoft.Win32;
using MilitaryPlanner.Helpers;
@@ -133,8 +135,52 @@ public OrderOfBattleView OOBView
}
}
- #endregion
+ private MissionTimeLineView _MTLView;
+ public MissionTimeLineView MTLView
+ {
+ get { return _MTLView; }
+ set
+ {
+ if (_MTLView != value)
+ {
+ _MTLView = value;
+ RaisePropertyChanged(() => MTLView);
+ }
+ }
+ }
+
+ private Visibility _mapViewVisibility = Visibility.Visible;
+ public Visibility MapViewVisibility
+ {
+ get
+ {
+ return _mapViewVisibility;
+ }
+
+ set
+ {
+ _mapViewVisibility = value;
+ RaisePropertyChanged(() => MapViewVisibility);
+ }
+ }
+
+ private Visibility _timeLineViewVisibility = Visibility.Collapsed;
+ public Visibility TimeLineViewVisibility
+ {
+ get
+ {
+ return _timeLineViewVisibility;
+ }
+ set
+ {
+ _timeLineViewVisibility = value;
+ RaisePropertyChanged(() => TimeLineViewVisibility);
+ }
+ }
+
+ #endregion
+
#region Commands
public RelayCommand CancelCommand { get; set; }
@@ -142,6 +188,10 @@ public OrderOfBattleView OOBView
public RelayCommand SaveCommand { get; set; }
public RelayCommand OpenCommand { get; set; }
public RelayCommand EditMissionPhasesCommand { get; set; }
+ public RelayCommand EditGeometryCommand { get; set; }
+ public RelayCommand EditGeometryUndoCommand { get; set; }
+ public RelayCommand EditGeometryRedoCommand { get; set; }
+ public RelayCommand SwitchViewCommand { get; set; }
#endregion
@@ -167,9 +217,44 @@ public MainWindowViewModel()
SaveCommand = new RelayCommand(OnSaveCommand);
OpenCommand = new RelayCommand(OnOpenCommand);
EditMissionPhasesCommand = new RelayCommand(OnEditMissionPhases);
+ EditGeometryCommand = new RelayCommand(OnEditGeometryCommand);
+ EditGeometryRedoCommand = new RelayCommand(OnEditGeometryRedoCommand);
+ EditGeometryUndoCommand = new RelayCommand(OnEditGeometryUndoCommand);
+ SwitchViewCommand = new RelayCommand(OnSwitchViewCommand);
MapView = new MapView();
OOBView = new OrderOfBattleView();
+ MTLView = new MissionTimeLineView();
+ }
+
+ private void OnSwitchViewCommand(object obj)
+ {
+ if (MapViewVisibility == Visibility.Visible)
+ {
+ Mediator.NotifyColleagues(Constants.ACTION_CLONE_MISSION, null);
+ TimeLineViewVisibility = Visibility.Visible;
+ MapViewVisibility = Visibility.Collapsed;
+ }
+ else
+ {
+ TimeLineViewVisibility = Visibility.Collapsed;
+ MapViewVisibility = Visibility.Visible;
+ }
+ }
+
+ private void OnEditGeometryUndoCommand(object obj)
+ {
+ Mediator.NotifyColleagues(Constants.ACTION_EDIT_UNDO, null);
+ }
+
+ private void OnEditGeometryRedoCommand(object obj)
+ {
+ Mediator.NotifyColleagues(Constants.ACTION_EDIT_REDO, null);
+ }
+
+ private void OnEditGeometryCommand(object obj)
+ {
+ Mediator.NotifyColleagues(Constants.ACTION_EDIT_GEOMETRY, null);
}
private void OnEditMissionPhases(object obj)
@@ -210,11 +295,15 @@ private void OnDeleteCommand(object obj)
private void OnSaveCommand(object obj)
{
// file dialog
- var sfd = new SaveFileDialog {Filter = "xml files (*.xml)|*.xml", RestoreDirectory = true};
+ var sfd = new SaveFileDialog
+ {
+ Filter = "Mission xml files (*.xml)|*.xml|Geomessage xml files (*.xml)|*.xml",
+ RestoreDirectory = true
+ };
if (sfd.ShowDialog() == true)
{
- Mediator.NotifyColleagues(Constants.ACTION_SAVE_MISSION, sfd.FileName);
+ Mediator.NotifyColleagues(Constants.ACTION_SAVE_MISSION, String.Format("{0}{1}{2}", sfd.FilterIndex, Constants.SAVE_AS_DELIMITER, sfd.FileName));
}
}
diff --git a/source/MilitaryPlanner/ViewModels/MapViewModel.cs b/source/MilitaryPlanner/ViewModels/MapViewModel.cs
index 649ca8a..bf4d769 100644
--- a/source/MilitaryPlanner/ViewModels/MapViewModel.cs
+++ b/source/MilitaryPlanner/ViewModels/MapViewModel.cs
@@ -47,6 +47,7 @@ private enum EditState
DragDrop,
Move,
Tool,
+ Edit,
None
};
@@ -57,7 +58,7 @@ private enum EditState
private Message _currentMessage;
private EditState _editState = EditState.None;
private MessageLayer _militaryMessageLayer;
- private TimeExtent _currentTimeExtent = null; //new TimeExtent(DateTime.Now, DateTime.Now.AddSeconds(3599));
+ private TimeExtent _currentTimeExtent = null;
private readonly Mission _mission = new Mission("Default Mission");
private int _currentPhaseIndex = 0;
@@ -80,12 +81,14 @@ private enum EditState
public RelayCommand ToggleViewShedToolCommand { get; set; }
public RelayCommand ToggleGotoXYToolCommand { get; set; }
public RelayCommand ToggleNetworkingToolCommand { get; set; }
+ public RelayCommand ToggleBasemapGalleryCommand { get; set; }
// controllers
private GotoXYToolController _gotoXYToolController;
private NetworkingToolController _networkingToolController;
private ViewShedToolController _viewShedToolController;
private CoordinateReadoutController _coordinateReadoutController;
+ private BasemapGalleryController _basemapGalleryController;
public MapViewModel()
{
@@ -98,6 +101,10 @@ public MapViewModel()
Mediator.Register(Constants.ACTION_SAVE_MISSION, DoSaveMission);
Mediator.Register(Constants.ACTION_OPEN_MISSION, DoOpenMission);
Mediator.Register(Constants.ACTION_EDIT_MISSION_PHASES, DoEditMissionPhases);
+ Mediator.Register(Constants.ACTION_EDIT_GEOMETRY, DoEditGeometry);
+ Mediator.Register(Constants.ACTION_EDIT_REDO, DoEditRedo);
+ Mediator.Register(Constants.ACTION_EDIT_UNDO, DoEditUndo);
+ Mediator.Register(Constants.ACTION_CLONE_MISSION, DoCloneMission);
SetMapCommand = new RelayCommand(OnSetMap);
PhaseAddCommand = new RelayCommand(OnPhaseAdd);
@@ -113,6 +120,86 @@ public MapViewModel()
ToggleViewShedToolCommand = new RelayCommand(OnToggleViewShedToolCommand);
ToggleGotoXYToolCommand = new RelayCommand(OnToggleGotoXYToolCommand);
ToggleNetworkingToolCommand = new RelayCommand(OnToggleNetworkingToolCommand);
+ ToggleBasemapGalleryCommand = new RelayCommand(OnToggleBasemapGalleryCommand);
+ }
+
+ private void OnToggleBasemapGalleryCommand(object obj)
+ {
+ _basemapGalleryController.Toggle();
+ }
+
+ private void DoEditUndo(object obj)
+ {
+ if (_mapView.Editor.IsActive && _mapView.Editor.Undo.CanExecute(null))
+ {
+ _mapView.Editor.Undo.Execute(null);
+ }
+ }
+
+ private void DoEditRedo(object obj)
+ {
+ if (_mapView.Editor.IsActive && _mapView.Editor.Redo.CanExecute(null))
+ {
+ _mapView.Editor.Redo.Execute(null);
+ }
+ }
+
+ ///
+ /// On this command the currently selected geometry gets edited if it is a polyline or polygon
+ /// Updates the military message with the new geometry during and after editing
+ ///
+ ///
+ private async void DoEditGeometry(object obj)
+ {
+ if (_mapView.Editor.IsActive)
+ {
+ if (_mapView.Editor.Complete.CanExecute(null))
+ {
+ _mapView.Editor.Complete.Execute(null);
+ _editState = EditState.None;
+ return;
+ }
+ }
+
+ if (_currentMessage != null)
+ {
+ var tam = _mission.MilitaryMessages.FirstOrDefault(msg => msg.Id == _currentMessage.Id);
+
+ if (tam != null)
+ {
+ _editState = EditState.Edit;
+
+ try
+ {
+ var progress = new Progress();
+
+ progress.ProgressChanged += (a, ges) =>
+ {
+ UpdateCurrentMessage(tam, ges.NewGeometry);
+ };
+
+ var resultGeometry = await _mapView.Editor.EditGeometryAsync(tam.SymbolGeometry, null, progress);
+
+ if (resultGeometry != null)
+ {
+ tam.SymbolGeometry = resultGeometry;
+ UpdateCurrentMessage(tam, resultGeometry);
+ }
+ }
+ catch
+ {
+ // ignored
+ }
+ }
+ }
+ }
+
+ private void DoCloneMission(object obj)
+ {
+ Mission cloneMission = _mission.DeepCopy();
+
+ // update mission cloned
+ Mediator.NotifyColleagues(Constants.ACTION_MISSION_CLONED, cloneMission);
}
private void OnToggleNetworkingToolCommand(object obj)
@@ -130,7 +217,7 @@ private void OnSaveCommand(object obj)
// file dialog
var sfd = new SaveFileDialog
{
- Filter = "xml files (*.xml)|*.xml|Geomessage xml files (*.xml)|*.xml",
+ Filter = "Mission xml files (*.xml)|*.xml|Geomessage xml files (*.xml)|*.xml",
RestoreDirectory = true
};
@@ -255,6 +342,7 @@ private void DoOpenMission(object obj)
if (_mission.Load(fileName))
{
InitializeMapWithMission();
+ RaisePropertyChanged(() => PhaseDescription);
}
}
}
@@ -464,7 +552,7 @@ private async void OnMeasureCommand(object param)
// World Topo Map doesn't support mensuration
//var temp = _mapView.Map.Layers["World Topo Map"];
- var temp = _mapView.Map.Layers["TestMapServiceLayer"];
+ var temp = _mapView.Map.Layers["MensurationMapServiceLayer"];
_mensurationTask = new MensurationTask(new Uri((temp as ArcGISTiledMapServiceLayer).ServiceUri));
@@ -500,6 +588,10 @@ private async void OnMeasureCommand(object param)
{
MessageBox.Show(ex.Message, "Mensuration Error");
}
+ finally
+ {
+ _graphicsOverlay.Graphics.Clear();
+ }
}
}
@@ -638,6 +730,7 @@ private void OnSetMap(object param)
_networkingToolController = new NetworkingToolController(mapView, this);
_viewShedToolController = new ViewShedToolController(mapView, this);
_coordinateReadoutController = new CoordinateReadoutController(mapView, this);
+ _basemapGalleryController = new BasemapGalleryController(mapView);
// add default message layer
AddNewMilitaryMessagelayer();
@@ -654,7 +747,7 @@ private void OnSetMap(object param)
void mapView_MouseMove(object sender, MouseEventArgs e)
{
- if (_map == null || _editState == EditState.Tool)
+ if (_map == null || _editState == EditState.Tool || _editState == EditState.Edit)
{
return;
}
@@ -685,7 +778,7 @@ void mapView_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
async void mapView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
- if (_editState == EditState.Create || _editState == EditState.Tool)
+ if (_editState == EditState.Create || _editState == EditState.Tool || _editState == EditState.Edit)
{
return;
}
@@ -820,13 +913,62 @@ private void UpdateCurrentMessage(MapPoint mapPoint)
}
}
+ private void UpdateCurrentMessage(TimeAwareMilitaryMessage tam, Geometry geometry)
+ {
+ var cpts = string.Empty;
+
+ // TODO find a way to determine if polyline map points need adjustment based on symbol being drawn
+
+ List mpList = null;
+
+ var polyline = geometry as Polyline;
+
+ if (polyline != null)
+ {
+ if (tam[MilitaryMessage.SicCodePropertyName].Contains("POLA") ||
+ tam[MilitaryMessage.SicCodePropertyName].Contains("PPA"))
+ {
+ mpList = AdjustMapPoints(polyline, DrawShape.Arrow);
+ }
+ else
+ {
+ mpList = AdjustMapPoints(polyline, DrawShape.Polyline);
+ }
+ }
+ else
+ {
+ var polygon = geometry as Polygon;
+
+ if (polygon != null)
+ {
+ mpList = new List();
+ foreach (var part in polygon.Parts)
+ {
+ mpList.AddRange(part.GetPoints());
+ }
+ }
+ }
+
+ if (mpList != null)
+ {
+ var msg = new MilitaryMessage(tam.Id, MilitaryMessageType.PositionReport, MilitaryMessageAction.Update,
+ mpList);
+
+ tam[MilitaryMessage.ControlPointsPropertyName] = msg[MilitaryMessage.ControlPointsPropertyName];
+
+ if (_militaryMessageLayer.ProcessMessage(msg))
+ {
+ UpdateMilitaryMessageControlPoints(msg);
+ }
+ }
+ }
+
private void UpdateMilitaryMessageControlPoints(MilitaryMessage msg)
{
var tam = _mission.MilitaryMessages.First(m => m.Id == msg.Id);
if (tam != null)
{
- //tam[MilitaryMessage.ControlPointsPropertyName] = msg[MilitaryMessage.ControlPointsPropertyName];
tam.StoreControlPoints(_mission.PhaseList[CurrentPhaseIndex].ID, msg);
}
}
@@ -882,12 +1024,6 @@ private bool ProcessMessage(MessageLayer messageLayer, Message msg)
{
var result = messageLayer.ProcessMessage(msg);
- // add id to messageIDList
- //if (!_messageDictionary.ContainsKey(msg.Id) && result)
- //{
- // _messageDictionary.Add(msg.Id, messageLayer.ID);
- //}
-
if (!_phaseMessageDictionary.ContainsKey(messageLayer.ID))
{
_phaseMessageDictionary.Add(messageLayer.ID, new List());
@@ -908,7 +1044,7 @@ private bool ProcessMessage(MessageLayer messageLayer, Message msg)
private void DoActionDelete(object obj)
{
// remove any selected messages
- if (_currentMessage != null)
+ if (_currentMessage != null && _editState != EditState.Edit)
{
// remove message
RemoveMessage(_currentMessage);
@@ -925,7 +1061,7 @@ private void DoActionCancel(object obj)
}
}
- if (_editState == EditState.Create)
+ if (_editState == EditState.Create || _editState == EditState.Edit)
{
_editState = EditState.None;
}
@@ -995,7 +1131,8 @@ private void ProcessSymbol(SymbolViewModel symbol, Geometry geometry)
{
VisibleTimeExtent = new TimeExtent(_mission.PhaseList[CurrentPhaseIndex].VisibleTimeExtent.Start,
_mission.PhaseList[CurrentPhaseIndex].VisibleTimeExtent.End),
- Id = Guid.NewGuid().ToString("D")
+ Id = Guid.NewGuid().ToString("D"),
+ SymbolGeometry = geometry
};
// set default time extent
@@ -1156,6 +1293,7 @@ private void AddNewMessage(SymbolViewModel symbolViewModel, Point p, string guid
// Construct the Control Points based on the geometry type of the drawn geometry.
var point = _mapView.ScreenToLocation(p);
+ tam.SymbolGeometry = point;
tam.Add(MilitaryMessage.ControlPointsPropertyName, point.X.ToString() + "," + point.Y.ToString());
//Process the message
diff --git a/source/MilitaryPlanner/ViewModels/MissionViewModel.cs b/source/MilitaryPlanner/ViewModels/MissionViewModel.cs
index 5d691d1..dc7053d 100644
--- a/source/MilitaryPlanner/ViewModels/MissionViewModel.cs
+++ b/source/MilitaryPlanner/ViewModels/MissionViewModel.cs
@@ -11,11 +11,16 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
+using System.Windows;
using System.Windows.Data;
+using System.Windows.Media;
+using Esri.ArcGISRuntime.Data;
using Esri.ArcGISRuntime.Symbology.Specialized;
using MilitaryPlanner.Helpers;
using MilitaryPlanner.Models;
@@ -24,7 +29,8 @@ namespace MilitaryPlanner.ViewModels
{
public class MissionViewModel : BaseViewModel
{
- readonly List _symbols = new List();
+ //List _phaseSymbols = new List();
+ readonly ObservableCollection _phaseSymbols = new ObservableCollection();
private Mission _mission = new Mission();
@@ -38,15 +44,19 @@ public Mission CurrentMission
set
{
_mission = value;
+ _phaseSymbols.Clear();
ProcessMission();
RaisePropertyChanged(() => CurrentMission);
RaisePropertyChanged(() => PhaseCount);
RaisePropertyChanged(() => CurrentPhase);
+ RaisePropertyChanged(() => MissionTimeExtent);
+ RaisePropertyChanged(() => PhaseSymbols);
}
}
public RelayCommand PhaseBackCommand { get; set; }
public RelayCommand PhaseNextCommand { get; set; }
+ public RelayCommand DeletePhaseCommand { get; set; }
public MissionViewModel()
{
@@ -61,6 +71,30 @@ public MissionViewModel()
PhaseBackCommand = new RelayCommand(OnPhaseBack);
PhaseNextCommand = new RelayCommand(OnPhaseNext);
+ DeletePhaseCommand = new RelayCommand(OnDeletePhase);
+ }
+
+ private void OnDeletePhase(object obj)
+ {
+ var question = String.Format("Are you sure you want to delete phase?\n\rName : {0}",CurrentPhase.Name);
+ var result = MessageBox.Show(question, "Delete Phase?", MessageBoxButton.YesNo, MessageBoxImage.Warning);
+
+ if (result == MessageBoxResult.Yes)
+ {
+ if (CurrentPhaseIndex < PhaseCount)
+ {
+ // remove phase
+ _mission.PhaseList.RemoveAt(CurrentPhaseIndex);
+ if (CurrentPhaseIndex >= PhaseCount && CurrentPhaseIndex != 0)
+ {
+ CurrentPhaseIndex--;
+ }
+ else
+ {
+ CurrentPhaseIndex = CurrentPhaseIndex;
+ }
+ }
+ }
}
private void OnPhaseIndexChanged(object obj)
@@ -95,11 +129,11 @@ private void OnMissionCloned(object obj)
}
}
- public IReadOnlyCollection Symbols
+ public ObservableCollection PhaseSymbols
{
get
{
- return _symbols;
+ return _phaseSymbols;
}
}
@@ -111,6 +145,14 @@ public int PhaseCount
}
}
+ public TimeExtent MissionTimeExtent
+ {
+ get
+ {
+ return new TimeExtent(_mission.PhaseList.Min(t => t.VisibleTimeExtent.Start), _mission.PhaseList.Max(t => t.VisibleTimeExtent.End));
+ }
+ }
+
private int _currentPhaseIndex = 0;
public int CurrentPhaseIndex
{
@@ -121,10 +163,13 @@ public int CurrentPhaseIndex
set
{
- _currentPhaseIndex = value;
- CurrentPhase = _mission.PhaseList[_currentPhaseIndex];
- RaisePropertyChanged(() => CurrentPhaseIndex);
- RaisePropertyChanged(() => PhaseMessage);
+ if (value < _mission.PhaseList.Count)
+ {
+ _currentPhaseIndex = value;
+ CurrentPhase = _mission.PhaseList[_currentPhaseIndex];
+ RaisePropertyChanged(() => CurrentPhaseIndex);
+ RaisePropertyChanged(() => PhaseMessage);
+ }
}
}
@@ -164,50 +209,80 @@ private void ProcessMission()
int currentStartPhase = 0;
int currentEndPhase = 0;
- foreach (var phase in _mission.PhaseList)
+ foreach (var mm in _mission.MilitaryMessages)
{
- // for each message in the phase
- //TODO revisit
- //foreach (var pm in phase.PersistentMessages)
- //{
- // // for each message, create/update a phase symbol in the symbol list
- // CreateUpdateSymbolWithPM(pm, currentStartPhase, currentEndPhase);
- //}
-
- currentStartPhase++;
- currentEndPhase++;
+ currentStartPhase = 0;
+ currentEndPhase = -1;
+
+ foreach (var phase in _mission.PhaseList)
+ {
+ if (mm.VisibleTimeExtent.Intersects(phase.VisibleTimeExtent))
+ {
+ currentEndPhase = _mission.PhaseList.IndexOf(phase);
+ }
+ else
+ {
+ //if (_mission.PhaseList.IndexOf(phase) <= currentEndPhase)
+ if (currentEndPhase < 0)
+ {
+ //currentStartPhase = _mission.PhaseList.IndexOf(phase);
+ currentStartPhase++;
+ }
+ }
+ }
+
+ var pm = new PersistentMessage() { ID = mm.Id, VisibleTimeExtent = mm.VisibleTimeExtent};
+
+ var piList = new List();
+
+ foreach (var item in mm)
+ {
+ piList.Add(new PropertyItem() { Key = item.Key, Value = item.Value });
+ }
+
+ pm.PropertyItems = piList;
+
+ CreateUpdateSymbolWithPM(pm, currentStartPhase, currentEndPhase);
}
+
}
private void CreateUpdateSymbolWithPM(PersistentMessage pm, int currentStartPhase, int currentEndPhase)
{
// is this an update or a new symbol
- var foundSymbol = _symbols.Where(sl => sl.ItemSVM.Model.Values.ContainsKey(Message.IdPropertyName) && sl.ItemSVM.Model.Values[Message.IdPropertyName] == pm.ID);
+ var foundSymbol = _phaseSymbols.FirstOrDefault(sl => sl.ItemSVM.Model.Values.ContainsKey(Message.IdPropertyName) && sl.ItemSVM.Model.Values[Message.IdPropertyName] == pm.ID);
- if (foundSymbol != null && foundSymbol.Any())
+ //if (foundSymbol != null && foundSymbol.Any())
+ if(foundSymbol != null)
{
// symbol is in list, do an update
- var ps = foundSymbol.ElementAt(0);
+ var ps = foundSymbol;//.ElementAt(0);
ps.EndPhase = currentEndPhase;
}
else
{
// symbol is missing, ADD a new one
- var psvm = new PhaseSymbolViewModel
- {
- StartPhase = currentStartPhase,
- EndPhase = currentEndPhase,
- ItemSVM = SymbolLoader.Search(pm.PropertyItems.Where(pi => pi.Key == "sic").ElementAt(0).Value)
- };
+ PropertyItem first = pm.PropertyItems.FirstOrDefault(pi => pi.Key == "sic");
- // create SVM
- if (!psvm.ItemSVM.Model.Values.ContainsKey(Message.IdPropertyName))
+ if (first != null)
{
- psvm.ItemSVM.Model.Values.Add(Message.IdPropertyName, pm.ID);
+ var psvm = new PhaseSymbolViewModel
+ {
+ StartPhase = currentStartPhase,
+ EndPhase = currentEndPhase,
+ ItemSVM = SymbolLoader.Search(first.Value),
+ VisibleTimeExtent = pm.VisibleTimeExtent
+ };
+
+ // create SVM
+ if (!psvm.ItemSVM.Model.Values.ContainsKey(Message.IdPropertyName))
+ {
+ psvm.ItemSVM.Model.Values.Add(Message.IdPropertyName, pm.ID);
+ }
+
+ _phaseSymbols.Add(psvm);
}
-
- _symbols.Add(psvm);
}
}
@@ -262,6 +337,45 @@ public int ViewWidth
}
}
+ private TimeExtent _visibleTimeExtent = new TimeExtent();
+
+ public TimeExtent VisibleTimeExtent
+ {
+ get
+ {
+ return _visibleTimeExtent;
+ }
+ set
+ {
+ _visibleTimeExtent = value;
+ RaisePropertyChanged(() => VisibleTimeExtent);
+ }
+ }
+
+ }
+
+ public class PadLeftVariableWidthConverter : IMultiValueConverter
+ {
+
+ public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+ {
+ double listWidth = (double)values[0];
+ TimeExtent messageTimeExtent = (TimeExtent)values[1];
+ TimeExtent missionTimeExtent = (TimeExtent)values[2];
+
+ TimeSpan ts = messageTimeExtent.Start.Subtract(missionTimeExtent.Start);
+ TimeSpan mts = missionTimeExtent.End.Subtract(missionTimeExtent.Start);
+
+ var widthFactor = ts.TotalSeconds / mts.TotalSeconds;
+ var width = listWidth * widthFactor;
+
+ return Math.Max(width,0.0);
+ }
+
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
}
public class VariableWidthConverter : IMultiValueConverter
@@ -269,18 +383,43 @@ public class VariableWidthConverter : IMultiValueConverter
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
- int totalPhaseLength = (int)values[0];
- int phaseLength = (int)values[1];
- double listWidth = (double)values[2];
-
- var width = ((listWidth / totalPhaseLength) * phaseLength);
+ double listWidth = (double)values[0];
+ TimeExtent messageTimeExtent = (TimeExtent)values[1];
+ TimeExtent missionTimeExtent = (TimeExtent)values[2];
+
+ TimeSpan ts = messageTimeExtent.End.Subtract(messageTimeExtent.Start);
+ TimeSpan mts = missionTimeExtent.End.Subtract(missionTimeExtent.Start);
+
+ var widthFactor = ts.TotalSeconds / mts.TotalSeconds;
+ var width = listWidth * widthFactor;
+
+ return Math.Max(0.0, width - 12);
+ }
+
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public class PhaseWidthConverter : IMultiValueConverter
+ {
+
+ public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+ {
+ int totalPhaseCount = (int)values[0];
+ double listWidth = (double)values[1];
+
+ var width = (listWidth - (listWidth % totalPhaseCount)) / totalPhaseCount;
- if (phaseLength-1 > 0)
+ var offset = 0;
+
+ while (totalPhaseCount*(width - offset) > listWidth - 3)
{
- width -= 12;
+ offset++;
}
- return width;
+ return Math.Max(0.0,width - offset);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
@@ -288,5 +427,50 @@ public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
throw new NotImplementedException();
}
}
+ public class PhaseHeightConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return (double)value;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public class SIC2BrushConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ var sic = (string) value;
+
+ Brush brush;
+
+ switch (sic[1].ToString().ToLower())
+ {
+ case "f":
+ brush = Brushes.DeepSkyBlue;
+ break;
+ case "n":
+ brush = Brushes.LightGreen;
+ break;
+ case "h":
+ brush = Brushes.Salmon;
+ break;
+ default:
+ brush = Brushes.Yellow;
+ break;
+ }
+
+ return brush;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
}
diff --git a/source/MilitaryPlanner/ViewModels/SymbolViewModel.cs b/source/MilitaryPlanner/ViewModels/SymbolViewModel.cs
index 64e30ff..aa3cdd8 100644
--- a/source/MilitaryPlanner/ViewModels/SymbolViewModel.cs
+++ b/source/MilitaryPlanner/ViewModels/SymbolViewModel.cs
@@ -30,11 +30,6 @@ public string SymbolID
get { return _model.Values["SymbolID"]; }
}
- //public string StyleFile
- //{
- // get { return _model.Values["StyleFile"].ToString(); }
- //}
-
public SymbolProperties Model
{
get { return _model; }
diff --git a/source/MilitaryPlanner/Views/BasemapGalleryView.xaml b/source/MilitaryPlanner/Views/BasemapGalleryView.xaml
new file mode 100644
index 0000000..e0e00a0
--- /dev/null
+++ b/source/MilitaryPlanner/Views/BasemapGalleryView.xaml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/MilitaryPlanner/Views/BasemapGalleryView.xaml.cs b/source/MilitaryPlanner/Views/BasemapGalleryView.xaml.cs
new file mode 100644
index 0000000..98c117e
--- /dev/null
+++ b/source/MilitaryPlanner/Views/BasemapGalleryView.xaml.cs
@@ -0,0 +1,21 @@
+using System.Windows;
+using MilitaryPlanner.ViewModels;
+using System.Windows.Controls.Primitives;
+
+namespace MilitaryPlanner.Views
+{
+ ///
+ /// Interaction logic for BasemapGalleryView.xaml
+ ///
+ public partial class BasemapGalleryView : Popup
+ {
+ public BasemapGalleryView()
+ {
+ InitializeComponent();
+ ViewModel = new BasemapGalleryViewModel();
+ DataContext = ViewModel;
+ }
+
+ public BasemapGalleryViewModel ViewModel { get; set; }
+ }
+}
diff --git a/source/MilitaryPlanner/Views/EditMissionPhasesView.xaml b/source/MilitaryPlanner/Views/EditMissionPhasesView.xaml
index 2bcc1e6..0e89832 100644
--- a/source/MilitaryPlanner/Views/EditMissionPhasesView.xaml
+++ b/source/MilitaryPlanner/Views/EditMissionPhasesView.xaml
@@ -24,6 +24,7 @@
+
diff --git a/source/MilitaryPlanner/Views/GotoXYToolView.xaml b/source/MilitaryPlanner/Views/GotoXYToolView.xaml
index cbebac2..be48bbe 100644
--- a/source/MilitaryPlanner/Views/GotoXYToolView.xaml
+++ b/source/MilitaryPlanner/Views/GotoXYToolView.xaml
@@ -11,7 +11,7 @@
HorizontalOffset="10"
d:DesignHeight="320" d:DesignWidth="300">
-
diff --git a/source/MilitaryPlanner/Views/MainWindow.xaml b/source/MilitaryPlanner/Views/MainWindow.xaml
index b3e020b..7c4304d 100644
--- a/source/MilitaryPlanner/Views/MainWindow.xaml
+++ b/source/MilitaryPlanner/Views/MainWindow.xaml
@@ -2,8 +2,13 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:MilitaryPlanner.ViewModels"
+ xmlns:helper="clr-namespace:MilitaryPlanner.Helpers"
Title="Military Planner"
- WindowState="Maximized"
+ Height="{helper:SettingBinding Height}"
+ Width="{helper:SettingBinding Width}"
+ Left="{helper:SettingBinding Left}"
+ Top="{helper:SettingBinding Top}"
+ WindowState="{helper:SettingBinding WindowState}"
DataContext="{DynamicResource ViewModelMain}">
@@ -13,6 +18,9 @@
+
+
+
@@ -30,9 +38,11 @@
+
-
+
+
diff --git a/source/MilitaryPlanner/Views/MapView.xaml b/source/MilitaryPlanner/Views/MapView.xaml
index d973b5f..2b5cddd 100644
--- a/source/MilitaryPlanner/Views/MapView.xaml
+++ b/source/MilitaryPlanner/Views/MapView.xaml
@@ -50,8 +50,10 @@
-
-
+
+
@@ -112,6 +114,8 @@
ToolTipService.ToolTip="GotoXY Tool" />
+
diff --git a/source/MilitaryPlanner/Views/MissionTimeLineView.xaml b/source/MilitaryPlanner/Views/MissionTimeLineView.xaml
index d06ad92..50fa97f 100644
--- a/source/MilitaryPlanner/Views/MissionTimeLineView.xaml
+++ b/source/MilitaryPlanner/Views/MissionTimeLineView.xaml
@@ -9,44 +9,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
-
+
-
-
+
+
-
-
diff --git a/source/MilitaryPlanner/app.config b/source/MilitaryPlanner/app.config
index c09b163..f3e7a96 100644
--- a/source/MilitaryPlanner/app.config
+++ b/source/MilitaryPlanner/app.config
@@ -1,5 +1,10 @@
+
+
+
+
+
@@ -12,4 +17,23 @@
+
+
+
+ 200
+
+
+ 100
+
+
+ 900
+
+
+ 480
+
+
+ 0
+
+
+