From ff540caad7b0dca5d1ccd75dcff8dd6994025ec3 Mon Sep 17 00:00:00 2001 From: KatKatKateryna <89912278+KatKatKateryna@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:15:22 +0100 Subject: [PATCH] fix update changed IDs (#209) * fix update changed IDs * better naming * remove initial count * move layer order method also to mapMemberUtils * loop * better names * comment * fix * split layers and tables * refactor layer loop --- .../Bindings/ArcGISSendBinding.cs | 32 +++++++-- .../ArcGISConnectorModule.cs | 2 + .../Send/ArcGISRootObjectBuilder.cs | 39 +++------- .../Utils/MapMembersUtils.cs | 72 +++++++++++++++++++ 4 files changed, 107 insertions(+), 38 deletions(-) create mode 100644 Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/MapMembersUtils.cs diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs index 331a3acc7..145511541 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSendBinding.cs @@ -8,6 +8,7 @@ using ArcGIS.Desktop.Mapping.Events; using Microsoft.Extensions.Logging; using Speckle.Autofac.DependencyInjection; using Speckle.Connectors.ArcGIS.Filters; +using Speckle.Connectors.ArcGIS.Utils; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Exceptions; @@ -38,6 +39,7 @@ public sealed class ArcGISSendBinding : ISendBinding private readonly IOperationProgressManager _operationProgressManager; private readonly ILogger _logger; private readonly ITopLevelExceptionHandler _topLevelExceptionHandler; + private readonly MapMembersUtils _mapMemberUtils; /// /// Used internally to aggregate the changed objects' id. Note we're using a concurrent dictionary here as the expiry check method is not thread safe, and this was causing problems. See: @@ -58,7 +60,8 @@ public sealed class ArcGISSendBinding : ISendBinding CancellationManager cancellationManager, ISendConversionCache sendConversionCache, IOperationProgressManager operationProgressManager, - ILogger logger + ILogger logger, + MapMembersUtils mapMemberUtils ) { _store = store; @@ -69,6 +72,7 @@ public sealed class ArcGISSendBinding : ISendBinding _operationProgressManager = operationProgressManager; _logger = logger; _topLevelExceptionHandler = parent.TopLevelExceptionHandler; + _mapMemberUtils = mapMemberUtils; Parent = parent; Commands = new SendBindingUICommands(parent); @@ -199,23 +203,37 @@ public sealed class ArcGISSendBinding : ISendBinding } // get the path of the edited dataset - var datasetURI = args.Row.GetTable().GetPath(); + Uri datasetPath = args.Row.GetTable().GetPath(); - // find all layers & tables reading from the dataset foreach (Layer layer in MapView.Active.Map.Layers) { - if (layer.GetPath() == datasetURI) + try { - ChangedObjectIds[layer.URI] = 1; + if (layer.GetPath() == datasetPath) + { + ChangedObjectIds[layer.URI] = 1; + } + } + catch (UriFormatException) // layer.GetPath() or table.GetPath() can throw this error, if data source was removed from the hard drive + { + // ignore layers with invalid source URI } } foreach (StandaloneTable table in MapView.Active.Map.StandaloneTables) { - if (table.GetPath() == datasetURI) + try { - ChangedObjectIds[table.URI] = 1; + if (table.GetPath() == datasetPath) + { + ChangedObjectIds[table.URI] = 1; + } + } + catch (UriFormatException) // layer.GetPath() or table.GetPath() can throw this error, if data source was removed from the hard drive + { + // ignore layers with invalid source URI } } + RunExpirationChecks(false); } diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs index 1bf44d3da..3ef5f418e 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/DependencyInjection/ArcGISConnectorModule.cs @@ -68,7 +68,9 @@ public class ArcGISConnectorModule : ISpeckleModule builder.AddScoped>(); builder.AddScoped(); builder.AddScoped, ArcGISRootObjectBuilder>(); + builder.AddScoped(); + builder.AddScoped(); builder.AddScoped(); diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs index 643333b0a..42daa963f 100644 --- a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs @@ -5,6 +5,7 @@ using ArcGIS.Desktop.Internal.Mapping; using ArcGIS.Desktop.Mapping; using Microsoft.Extensions.Logging; using Speckle.Connectors.ArcGIS.HostApp; +using Speckle.Connectors.ArcGIS.Utils; using Speckle.Connectors.Utils.Builders; using Speckle.Connectors.Utils.Caching; using Speckle.Connectors.Utils.Conversion; @@ -30,6 +31,7 @@ public class ArcGISRootObjectBuilder : IRootObjectBuilder private readonly ISendConversionCache _sendConversionCache; private readonly ArcGISColorManager _colorManager; private readonly IConversionContextStack _contextStack; + private readonly MapMembersUtils _mapMemberUtils; private readonly ILogger _logger; public ArcGISRootObjectBuilder( @@ -37,6 +39,7 @@ public class ArcGISRootObjectBuilder : IRootObjectBuilder ArcGISColorManager colorManager, IConversionContextStack contextStack, IRootToSpeckleConverter rootToSpeckleConverter, + MapMembersUtils mapMemberUtils, ILogger logger ) { @@ -44,6 +47,7 @@ public class ArcGISRootObjectBuilder : IRootObjectBuilder _colorManager = colorManager; _contextStack = contextStack; _rootToSpeckleConverter = rootToSpeckleConverter; + _mapMemberUtils = mapMemberUtils; _logger = logger; } @@ -66,7 +70,10 @@ public class ArcGISRootObjectBuilder : IRootObjectBuilder List<(GroupLayer, Collection)> nestedGroups = new(); // reorder selected layers by Table of Content (TOC) order - List<(MapMember, int)> layersWithDisplayPriority = GetLayerDisplayPriority(MapView.Active.Map, objects); + List<(MapMember, int)> layersWithDisplayPriority = _mapMemberUtils.GetLayerDisplayPriority( + MapView.Active.Map, + objects + ); onOperationProgressed?.Invoke("Converting", null); @@ -181,36 +188,6 @@ public class ArcGISRootObjectBuilder : IRootObjectBuilder return new RootObjectBuilderResult(rootObjectCollection, results); } - // Gets the layer display priority for selected layers - public List<(MapMember, int)> GetLayerDisplayPriority(Map map, IReadOnlyList mapMembers) - { - // first get all map layers - Dictionary layersIndices = new(); - int count = 0; - var layers = map.Layers; - count = UnpackLayersOrder(layersIndices, layers, count); - - // iterate through tables - foreach (var layer in map.StandaloneTables) - { - layersIndices[layer] = count + 100; // random number, will be recalculated below - } - - // recalculate selected layer priority from all map layers - List<(MapMember, int)> selectedLayers = new(); - int newCount = 0; - foreach (KeyValuePair valuePair in layersIndices) - { - if (mapMembers.Contains(valuePair.Key)) - { - selectedLayers.Add((valuePair.Key, newCount)); - newCount++; - } - } - - return selectedLayers; - } - private int UnpackLayersOrder( Dictionary layersIndices, IEnumerable layersToUnpack, diff --git a/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/MapMembersUtils.cs b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/MapMembersUtils.cs new file mode 100644 index 000000000..95951cae3 --- /dev/null +++ b/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Utils/MapMembersUtils.cs @@ -0,0 +1,72 @@ +using ArcGIS.Desktop.Internal.Mapping; +using ArcGIS.Desktop.Mapping; + +namespace Speckle.Connectors.ArcGIS.Utils; + +public class MapMembersUtils +{ + /// + /// Returns all Layers and Standalone Tables present on the Map + /// + /// + /// + public List GetAllMapMembers(Map map) + { + // first get all map layers + List mapMembers = new(); + var layerMapMembers = UnpackMapLayers(map.Layers); + mapMembers.AddRange(layerMapMembers); + + // add tables + var standaloneTableMapMembers = UnpackMapLayers(map.StandaloneTables); + mapMembers.AddRange(standaloneTableMapMembers); + return mapMembers; + } + + public List UnpackMapLayers(IEnumerable mapMembersToUnpack) + { + List mapMembers = new(); + foreach (var layer in mapMembersToUnpack) + { + switch (layer) + { + case GroupLayer subGroup: + mapMembers.Add(layer); + var subGroupMapMembers = UnpackMapLayers(subGroup.Layers); + mapMembers.AddRange(subGroupMapMembers); + break; + case ILayerContainerInternal subLayerContainerInternal: + mapMembers.Add(layer); + var subLayerMapMembers = UnpackMapLayers(subLayerContainerInternal.InternalLayers); + mapMembers.AddRange(subLayerMapMembers); + break; + default: + mapMembers.Add(layer); + break; + } + } + + return mapMembers; + } + + // Gets the layer display priority for selected layers + public List<(MapMember, int)> GetLayerDisplayPriority(Map map, IReadOnlyList selectedMapMembers) + { + // first get all map layers + List allMapMembers = GetAllMapMembers(map); + + // recalculate selected layer priority from all map layers + List<(MapMember, int)> selectedLayers = new(); + int newCount = 0; + foreach (MapMember mapMember in allMapMembers) + { + if (selectedMapMembers.Contains(mapMember)) + { + selectedLayers.Add((mapMember, newCount)); + newCount++; + } + } + + return selectedLayers; + } +}