123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532 |
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Drawing;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Windows;
- using System.Windows.Threading;
- using Comal.Classes;
- using InABox.Clients;
- using InABox.Core;
- using Inflector;
- using Syncfusion.UI.Xaml.Maps;
- using Point = System.Windows.Point;
- namespace PRSDesktop;
- public enum LiveMapView
- {
- All,
- Selected
- }
- public class MapViewModel : DependencyObject
- {
-
- static readonly DependencyProperty ViewProperty =
- DependencyProperty.Register(
- nameof(View),
- typeof(LiveMapView),
- typeof(MapViewModel),
- new PropertyMetadata(LiveMapView.All)
- );
- public LiveMapView View
- {
- get => (LiveMapView)GetValue(ViewProperty);
- set
- {
- SetValue(ViewProperty, value);
- Refresh();
- }
- }
-
- static readonly DependencyProperty StyleProperty =
- DependencyProperty.Register(
- nameof(Style),
- typeof(LiveMapStyle),
- typeof(MapViewModel),
- new PropertyMetadata(LiveMapStyle.OSM)
- );
- public LiveMapStyle Style
- {
- get => (LiveMapStyle)GetValue(StyleProperty);
- set => SetValue(StyleProperty, value);
- }
-
- static readonly DependencyProperty ApiKeyProperty =
- DependencyProperty.Register(
- nameof(ApiKey),
- typeof(string),
- typeof(MapViewModel),
- new PropertyMetadata("")
- );
- public string ApiKey
- {
- get => (string)GetValue(ApiKeyProperty);
- set => SetValue(ApiKeyProperty, value);
- }
-
- static readonly DependencyProperty LayersProperty =
- DependencyProperty.Register(
- nameof(Layers),
- typeof(ObservableCollection<ImageryLayer>),
- typeof(MapViewModel),
- new PropertyMetadata(new ObservableCollection<ImageryLayer>())
- );
- public ObservableCollection<ImageryLayer> Layers => (ObservableCollection<ImageryLayer>)GetValue(LayersProperty);
-
- static readonly DependencyProperty EntityTypesProperty =
- DependencyProperty.Register(
- nameof(EntityTypes),
- typeof(Dictionary<Type, String>),
- typeof(MapViewModel),
- new PropertyMetadata(new Dictionary<Type, String>())
- );
-
- public Dictionary<Type, String> EntityTypes => (Dictionary<Type, String>)GetValue(EntityTypesProperty);
- static readonly DependencyProperty EntityTypeProperty =
- DependencyProperty.Register(
- nameof(EntityType),
- typeof(Type),
- typeof(MapViewModel)
- );
-
- public Type? EntityType
- {
- get => (Type) GetValue(EntityTypeProperty);
- set
- {
- SetValue(EntityTypesProperty, value);
- ResetGroups();
- }
- }
-
- static readonly DependencyProperty EntityGroupsProperty =
- DependencyProperty.Register(
- nameof(EntityGroups),
- typeof(Dictionary<Guid, String>),
- typeof(MapViewModel),
- new PropertyMetadata(new Dictionary<Guid, String>())
- );
-
- public Dictionary<Guid, String> EntityGroups => (Dictionary<Guid, String>)GetValue(EntityGroupsProperty);
- static readonly DependencyProperty EntityGroupProperty =
- DependencyProperty.Register(
- nameof(EntityGroup),
- typeof(Guid),
- typeof(MapViewModel),
- new PropertyMetadata(Guid.Empty)
- );
-
- public Guid EntityGroup
- {
- get => (Guid)GetValue(EntityGroupProperty);
- set
- {
- SetValue(EntityGroupProperty,value);
- Refresh();
- }
- }
-
- //private readonly List<MapMarker> _markers = new();
- //private readonly List<MapMarker> _waypoints = new();
- //private MapMarker? _selected;
-
-
- static readonly DependencyProperty MarkersProperty =
- DependencyProperty.Register(
- nameof(Markers),
- typeof(ObservableCollection<MapMarker>),
- typeof(MapViewModel),
- new PropertyMetadata(new ObservableCollection<MapMarker>())
- );
-
- public ObservableCollection<MapMarker> Markers => (ObservableCollection<MapMarker>)GetValue(MarkersProperty);
-
-
- static readonly DependencyProperty SelectedMarkerProperty =
- DependencyProperty.Register(
- nameof(SelectedMarker),
- typeof(MapMarker),
- typeof(MapViewModel)
- );
-
- public MapMarker? SelectedMarker
- {
- get => GetValue(SelectedMarkerProperty) as MapMarker;
- set => SetValue(SelectedMarkerProperty, value);
- }
- static readonly DependencyProperty WayPointsProperty =
- DependencyProperty.Register(
- nameof(WayPoints),
- typeof(ObservableCollection<PointF>),
- typeof(MapViewModel),
- new PropertyMetadata(new ObservableCollection<PointF>())
- );
-
- public ObservableCollection<PointF> WayPoints => (ObservableCollection<PointF>)GetValue(WayPointsProperty);
- private LiveMapsSettings? _settings;
-
- public void Setup(LiveMapsSettings settings)
- {
- _settings = settings;
-
- LoadEntityTypes();
-
- EntityType = !String.IsNullOrWhiteSpace(_settings.EntityType)
- ? EntityTypes.Any(x => String.Equals(x.Key.EntityName(), _settings.EntityType))
- ? Type.GetType(_settings.EntityType)
- : null
- : null;
-
- EntityGroup = EntityGroups.Any(x => String.Equals(x.Key, _settings.EntityGroup))
- ? _settings.EntityGroup
- : Guid.Empty;
- Style = _settings.MapStyle;
-
- ApiKey = _settings.ApiKey;
- }
-
- private void LoadEntityTypes()
- {
-
- if (ClientFactory.IsSupported<Equipment>())
- EntityTypes[typeof(Equipment)] = typeof(Equipment).GetCaption().Pluralize();
- if (ClientFactory.IsSupported<Job>())
- EntityTypes[typeof(Job)] = typeof(Job).GetCaption().Pluralize();
- if (ClientFactory.IsSupported<TimeSheet>())
- EntityTypes[typeof(TimeSheet)] = typeof(TimeSheet).GetCaption().Pluralize();
- if (ClientFactory.IsSupported<GPSTracker>())
- EntityTypes[typeof(GPSTracker)] = typeof(GPSTracker).GetCaption().Pluralize();
- }
- private void ResetGroups()
- {
- EntityGroups.Clear();
-
- if (Type.Equals(EntityType,typeof(Equipment)))
- LoadGroups<EquipmentGroup>("All Equipment", x => x.Description);
-
- else if (Type.Equals(EntityType,typeof(Job)))
- LoadGroups<JobStatus>("All Jobs", x => x.Description);
-
- else if (Type.Equals(EntityType,typeof(GPSTracker)))
- LoadGroups<GPSTrackerType>("All Trackers", x => x.Description);
-
- else if (Type.Equals(EntityType,typeof(TimeSheet)))
- {
- EntityGroups[Guid.Empty] = "Open TimeSheets";
- EntityGroups[Guid.NewGuid()] = "TimeSheet Starts";
- EntityGroups[CoreUtils.FullGuid] = "TimeSheet Finishes";
- }
- }
-
- private void LoadGroups<TGroup>(string all, Expression<Func<TGroup, string>> description)
- where TGroup : Entity, IRemotable, IPersistent, new()
- {
- EntityGroups.Add(Guid.Empty, all);
- var _groups = new Client<TGroup>().Query(
- LookupFactory.DefineFilter<TGroup>(),
- LookupFactory.DefineColumns<TGroup>(),
- LookupFactory.DefineSort<TGroup>()
- );
- foreach (var _row in _groups.Rows)
- EntityGroups[_row.Get<TGroup, Guid>(x => x.ID)] = _row.Get(description);
- }
-
- public void Refresh()
- {
- Markers.Clear();
- WayPoints.Clear();
- if (View == LiveMapView.All)
- LoadMarkers();
- else if (SelectedMarker != null)
- {
- LoadWayPoints();
- foreach (var waypoint in _waypoints)
- {
- Markers.Add(waypoint);
- WayPoints.Add(new Point(double.Parse(waypoint.Longitude), double.Parse(waypoint.Latitude)));
- }
- }
- }
- public void LoadMarkers()
- {
- if (EntityType != null)
- {
- if (EntityType.Equals("Equipment"))
- {
- var filter = new Filter<Equipment>(x => x.TrackerLink.Location.Timestamp).IsNotEqualTo(DateTime.MinValue);
- if (!Security.IsAllowed<CanViewPrivateEquipment>())
- filter = filter.And(x => x.Private).IsEqualTo(false);
- if (EntityGroup != Guid.Empty)
- filter = filter.And(x => x.GroupLink.ID).IsEqualTo(EntityGroup);
- LoadMarkers(
- filter,
- x => x.ID,
- x => x.Code,
- x => x.Description,
- x => x.TrackerLink.DeviceID,
- x => x.TrackerLink.Location.Latitude,
- x => x.TrackerLink.Location.Longitude,
- x => x.TrackerLink.Description,
- x => x.TrackerLink.Location.Timestamp
- );
- }
- else if (EntityType.Equals("Jobs"))
- {
- var filter = new Filter<Job>(x => x.SiteAddress.Location.Timestamp).IsNotEqualTo(DateTime.MinValue);
- if (EntityGroup != Guid.Empty)
- filter = filter.And(x => x.JobStatus.ID).IsEqualTo(EntityGroup);
- LoadMarkers(
- filter,
- x => x.ID,
- x => x.JobNumber,
- x => x.Name,
- null,
- x => x.SiteAddress.Location.Latitude,
- x => x.SiteAddress.Location.Longitude,
- x => x.LastUpdateBy,
- x => x.SiteAddress.Location.Timestamp
- );
- }
- else if (EntityType.Equals("TimeSheets"))
- {
- if (EntityGroup == Guid.Empty) // Starts
- LoadMarkers(
- new Filter<TimeSheet>(x => x.Date).IsEqualTo(DateTime.Today).And(x => x.StartLocation.Timestamp)
- .IsNotEqualTo(new TimeSpan(0)),
- x => x.EmployeeLink.ID,
- x => x.EmployeeLink.Code,
- x => x.EmployeeLink.Name,
- null,
- x => x.StartLocation.Latitude,
- x => x.StartLocation.Longitude,
- x => x.SoftwareVersion,
- x => x.StartLocation.Timestamp
- );
- else if (EntityGroup == CoreUtils.FullGuid) // Finishes
- LoadMarkers(
- new Filter<TimeSheet>(x => x.Date).IsEqualTo(DateTime.Today).And(x => x.Finish).IsNotEqualTo(new TimeSpan(0))
- .And(x => x.FinishLocation.Timestamp).IsNotEqualTo(new TimeSpan(0)),
- x => x.EmployeeLink.ID,
- x => x.EmployeeLink.Code,
- x => x.EmployeeLink.Name,
- null,
- x => x.FinishLocation.Latitude,
- x => x.FinishLocation.Longitude,
- x => x.SoftwareVersion,
- x => x.FinishLocation.Timestamp
- );
- else // Open
- LoadMarkers(
- new Filter<TimeSheet>(x => x.Date).IsEqualTo(DateTime.Today).And(x => x.Finish).IsEqualTo(new TimeSpan(0))
- .And(x => x.StartLocation.Timestamp).IsNotEqualTo(new TimeSpan(0)),
- x => x.EmployeeLink.ID,
- x => x.EmployeeLink.Code,
- x => x.EmployeeLink.Name,
- null,
- x => x.StartLocation.Latitude,
- x => x.StartLocation.Longitude,
- x => x.SoftwareVersion,
- x => x.StartLocation.Timestamp
- );
- }
- else if (EntityType.Equals("Trackers"))
- {
- var filter = new Filter<GPSTracker>(x => x.Location.Timestamp).IsNotEqualTo(DateTime.MinValue);
- if (EntityGroup != Guid.Empty)
- filter = filter.And(x => x.Type.ID).IsEqualTo(EntityGroup);
- LoadMarkers(
- filter,
- x => x.ID,
- x => x.DeviceID,
- x => x.Description,
- x => x.DeviceID,
- x => x.Location.Latitude,
- x => x.Location.Longitude,
- x => x.LastUpdateBy,
- x => x.Location.Timestamp
- );
- }
- }
- }
- private class DbMarker
- {
- public DbMarker(string code, string description, DateTime timestamp, double latitude, double longitude, string updatedby, string deviceid)
- {
- Code = code;
- Description = description;
- TimeStamp = timestamp;
- Latitude = latitude;
- Longitude = longitude;
- UpdatedBy = updatedby;
- DeviceID = deviceid;
- }
- public string Code { get; }
- public string Description { get; }
- public DateTime TimeStamp { get; }
- public double Latitude { get; }
- public double Longitude { get; }
- public string UpdatedBy { get; }
- public string DeviceID { get; }
- }
-
- private void LoadMarkers<T>(Filter<T> filter, Expression<Func<T, Guid>> guid, Expression<Func<T, string>>? code,
- Expression<Func<T, string>> description, Expression<Func<T, string>>? deviceid, Expression<Func<T, double>> latitude,
- Expression<Func<T, double>> longitude, Expression<Func<T, string>> updatedby, Expression<Func<T, DateTime>> timestamp, bool first = true)
- where T : Entity, IRemotable, IPersistent, new()
- {
- var _columns = new Columns<T>(x=>x.ID)
- .Add(guid)
- .Add(description)
- .Add(latitude)
- .Add(longitude)
- .Add(timestamp)
- .Add(updatedby);
- if (code != null)
- _columns.Add(code);
-
- if (deviceid != null && !_columns.ColumnNames().Contains(CoreUtils.GetFullPropertyName(deviceid, ".")))
- _columns.Add(deviceid);
-
-
- new Client<T>().Query(
- filter,
- _columns,
- null,
- (table, error) =>
- {
- Dispatcher.Invoke(() =>
- {
- if (error != null)
- {
- MessageBox.Show(error.Message);
- }
- else if (table != null)
- {
- var _values = new Dictionary<Guid, DbMarker>();
-
- var _groups = table.Rows
- .OrderBy(x=>x.Get(code ?? description))
- .ThenBy(x=>x.Get(timestamp))
- .Select(x => x.ToObject<T>())
- .GroupBy(x => x.ID);
-
- foreach (var _group in _groups)
- {
- var last = _group.OrderBy(timefunc).LastOrDefault();
- if (last != null)
- Markers.Add(
- new MapMarker
- {
- ID = last.ID,
- Label = last.,
- Latitude = string.Format("{0:F6}", _values[key].Latitude),
- Longitude = string.Format("{0:F6}", _values[key].Longitude),
- Description = _values[key].Description,
- Updated = _values[key].TimeStamp,
- UpdatedBy = _values[key].UpdatedBy,
- DeviceID = _values[key].DeviceID
- }
- );
- }
- foreach (var _row in table.Rows)
- {
- var _id = _row.Get(guid);
- var _time = _row.Get(timestamp);
- if (!_values.ContainsKey(_id) || (first ? _values[_id].TimeStamp < _time : _values[_id].TimeStamp > _time))
- _values[_id] = new DbMarker(
- code != null ? _row.Get(code) : "",
- _row.Get(description),
- _time,
- _row.Get(latitude),
- _row.Get(longitude),
- _row.Get(updatedby),
- deviceid != null ? _row.Get(deviceid) : ""
- );
- }
- foreach (var key in _values.Keys)
- Markers.Add(
- new MapMarker
- {
- ID = key,
- Label = _values[key].Code,
- Latitude = string.Format("{0:F6}", _values[key].Latitude),
- Longitude = string.Format("{0:F6}", _values[key].Longitude),
- Description = _values[key].Description,
- Updated = _values[key].TimeStamp,
- UpdatedBy = _values[key].UpdatedBy,
- DeviceID = _values[key].DeviceID
- }
- );
- }
- ResetZoom();
- LoadMarkerList();
- });
- }
- );
- }
- private void ResetZoom()
- {
- var nwLon = double.MaxValue;
- var nwLat = double.MinValue;
- var seLon = double.MinValue;
- var seLat = double.MaxValue;
- foreach (var marker in _markers)
- {
- var lat = double.Parse(marker.Latitude);
- var lon = double.Parse(marker.Longitude);
- if (lat != 0.0F && lon != 0.00)
- {
- nwLat = lat > nwLat ? lat : nwLat;
- seLat = lat < seLat ? lat : seLat;
- nwLon = lon < nwLon ? lon : nwLon;
- seLon = lon > seLon ? lon : seLon;
- }
- }
-
- var cLat = (nwLat + seLat) / 2.0F;
- var cLon = (nwLon + seLon) / 2.0F;
- Center = new Point(cLat, cLon);
- var nw = new Location { Latitude = nwLat, Longitude = nwLon };
- var c = new Location { Latitude = cLat, Longitude = cLon };
- Radius = c.DistanceTo(nw, UnitOfLength.Kilometers) / 2.0F;
- }
-
- public double Radius { get; set; }
- public Point Center { get; set; }
-
- }
|