Skip to content

Commit

Permalink
[DUI3-293] logging poc bindings and bridge (#3515)
Browse files Browse the repository at this point in the history
* Wip changes

* Added top level callback in several places

* extracting some non-controversial changes to be merged first for cleaner diff

* more

* more binding stuff

* More binding alighment

* formatting

* fix merge mistake

* removed lies

* browser bridge concurrency

* More subscriptions

* Small tweaks

* Resolved some PR comments

* last rounds of polish

* local to private function

* More events that are top level

* Interfaced out TopLevelExceptionHandler
  • Loading branch information
JR-Morgan authored Jun 21, 2024
1 parent 2930bcf commit 483fe7d
Show file tree
Hide file tree
Showing 21 changed files with 470 additions and 227 deletions.
1 change: 1 addition & 0 deletions All.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=QL/@EntryIndexedValue">QL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SQ/@EntryIndexedValue">SQ</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=URI/@EntryIndexedValue">URI</s:String>
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpNaming/ApplyAutoDetectedRules/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CustomTools/CustomToolsData/@EntryValue">ExternalToolData|CSharpier|csharpier||csharpier|$FILE$</s:String>
<s:String x:Key="/Default/Environment/StructuredLogging/PropertyNamingType/@EntryValue">CamelCase</s:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ public class ArcGISSelectionBinding : ISelectionBinding
public string Name => "selectionBinding";
public IBridge Parent { get; }

public ArcGISSelectionBinding(IBridge parent)
public ArcGISSelectionBinding(IBridge parent, ITopLevelExceptionHandler topLevelHandler)
{
Parent = parent;

// example: https://github.com/Esri/arcgis-pro-sdk-community-samples/blob/master/Map-Authoring/QueryBuilderControl/DefinitionQueryDockPaneViewModel.cs
// MapViewEventArgs args = new(MapView.Active);
TOCSelectionChangedEvent.Subscribe(OnSelectionChanged, true);
TOCSelectionChangedEvent.Subscribe(_ => topLevelHandler.CatchUnhandled(OnSelectionChanged), true);
}

private void OnSelectionChanged(MapViewEventArgs args)
private void OnSelectionChanged()
{
SelectionInfo selInfo = GetSelection();
Parent.Send(SelectionBindingEvents.SET_SELECTION, selInfo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public sealed class ArcGISSendBinding : ISendBinding
private readonly List<ISendFilter> _sendFilters;
private readonly CancellationManager _cancellationManager;
private readonly ISendConversionCache _sendConversionCache;
private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;

/// <summary>
/// Used internally to aggregate the changed objects' id.
Expand All @@ -45,32 +46,57 @@ public ArcGISSendBinding(
IEnumerable<ISendFilter> sendFilters,
IUnitOfWorkFactory unitOfWorkFactory,
CancellationManager cancellationManager,
ISendConversionCache sendConversionCache
ISendConversionCache sendConversionCache,
ITopLevelExceptionHandler topLevelExceptionHandler
)
{
_store = store;
_unitOfWorkFactory = unitOfWorkFactory;
_sendFilters = sendFilters.ToList();
_cancellationManager = cancellationManager;
_sendConversionCache = sendConversionCache;
_topLevelExceptionHandler = topLevelExceptionHandler;
Parent = parent;
Commands = new SendBindingUICommands(parent);
SubscribeToArcGISEvents();
}

private void SubscribeToArcGISEvents()
{
LayersRemovedEvent.Subscribe(GetIdsForLayersRemovedEvent, true);
StandaloneTablesRemovedEvent.Subscribe(GetIdsForStandaloneTablesRemovedEvent, true);
MapPropertyChangedEvent.Subscribe(GetIdsForMapPropertyChangedEvent, true); // Map units, CRS etc.
MapMemberPropertiesChangedEvent.Subscribe(GetIdsForMapMemberPropertiesChangedEvent, true); // e.g. Layer name

ActiveMapViewChangedEvent.Subscribe(SubscribeToMapMembersDataSourceChange, true);
LayersAddedEvent.Subscribe(GetIdsForLayersAddedEvent, true);
StandaloneTablesAddedEvent.Subscribe(GetIdsForStandaloneTablesAddedEvent, true);
LayersRemovedEvent.Subscribe(
a => _topLevelExceptionHandler.CatchUnhandled(() => GetIdsForLayersRemovedEvent(a)),
true
);

StandaloneTablesRemovedEvent.Subscribe(
a => _topLevelExceptionHandler.CatchUnhandled(() => GetIdsForStandaloneTablesRemovedEvent(a)),
true
);

MapPropertyChangedEvent.Subscribe(
a => _topLevelExceptionHandler.CatchUnhandled(() => GetIdsForMapPropertyChangedEvent(a)),
true
); // Map units, CRS etc.

MapMemberPropertiesChangedEvent.Subscribe(
a => _topLevelExceptionHandler.CatchUnhandled(() => GetIdsForMapMemberPropertiesChangedEvent(a)),
true
); // e.g. Layer name

ActiveMapViewChangedEvent.Subscribe(
_ => _topLevelExceptionHandler.CatchUnhandled(SubscribeToMapMembersDataSourceChange),
true
);

LayersAddedEvent.Subscribe(a => _topLevelExceptionHandler.CatchUnhandled(() => GetIdsForLayersAddedEvent(a)), true);

StandaloneTablesAddedEvent.Subscribe(
a => _topLevelExceptionHandler.CatchUnhandled(() => GetIdsForStandaloneTablesAddedEvent(a)),
true
);
}

private void SubscribeToMapMembersDataSourceChange(ActiveMapViewChangedEventArgs args)
private void SubscribeToMapMembersDataSourceChange()
{
var task = QueuedTask.Run(() =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Desktop.Mapping;
using ArcGIS.Desktop.Mapping.Events;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.Utils;
using Speckle.Newtonsoft.Json;
Expand All @@ -11,34 +12,41 @@ namespace Speckle.Connectors.ArcGIS.Utils;

public class ArcGISDocumentStore : DocumentModelStore
{
public ArcGISDocumentStore(JsonSerializerSettings serializerOption)
public ArcGISDocumentStore(
JsonSerializerSettings serializerOption,
ITopLevelExceptionHandler topLevelExceptionHandler
)
: base(serializerOption, true)
{
ActiveMapViewChangedEvent.Subscribe(OnMapViewChanged);
ProjectSavingEvent.Subscribe(OnProjectSaving);
ProjectClosingEvent.Subscribe(OnProjectClosing);
ActiveMapViewChangedEvent.Subscribe(a => topLevelExceptionHandler.CatchUnhandled(() => OnMapViewChanged(a)));
ProjectSavingEvent.Subscribe(_ =>
{
topLevelExceptionHandler.CatchUnhandled(OnProjectSaving);
return Task.CompletedTask;
});
ProjectClosingEvent.Subscribe(_ =>
{
topLevelExceptionHandler.CatchUnhandled(OnProjectClosing);
return Task.CompletedTask;
});
}

private Task OnProjectClosing(ProjectClosingEventArgs arg)
private void OnProjectClosing()
{
if (MapView.Active is null)
{
return Task.CompletedTask;
return;
}

WriteToFile();
return Task.CompletedTask;
}

private Task OnProjectSaving(ProjectEventArgs arg)
private void OnProjectSaving()
{
if (MapView.Active is null)
if (MapView.Active is not null)
{
return Task.CompletedTask;
WriteToFile();
}

WriteToFile();
return Task.CompletedTask;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@ namespace Speckle.Connectors.Autocad.Bindings;
public class AutocadSelectionBinding : ISelectionBinding
{
private const string SELECTION_EVENT = "setSelection";

private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;
private readonly HashSet<Document> _visitedDocuments = new();

public string Name => "selectionBinding";

public IBridge Parent { get; }

public AutocadSelectionBinding(IBridge parent)
public AutocadSelectionBinding(IBridge parent, ITopLevelExceptionHandler topLevelExceptionHandler)
{
_topLevelExceptionHandler = topLevelExceptionHandler;
Parent = parent;

// POC: Use here Context for doc. In converters it's OK but we are still lacking to use context into bindings.
// It is with the case of if binding created with already a document
// This is valid when user opens acad file directly double clicking
TryRegisterDocumentForSelection(Application.DocumentManager.MdiActiveDocument);
Application.DocumentManager.DocumentActivated += (sender, e) => OnDocumentChanged(e.Document);
Application.DocumentManager.DocumentActivated += (_, e) =>
_topLevelExceptionHandler.CatchUnhandled(() => OnDocumentChanged(e.Document));
}

private void OnDocumentChanged(Document? document) => TryRegisterDocumentForSelection(document);
Expand All @@ -36,9 +40,7 @@ private void TryRegisterDocumentForSelection(Document? document)
if (!_visitedDocuments.Contains(document))
{
document.ImpliedSelectionChanged += (_, _) =>
{
Parent.RunOnMainThread(OnSelectionChanged);
};
_topLevelExceptionHandler.CatchUnhandled(() => Parent.RunOnMainThread(OnSelectionChanged));

_visitedDocuments.Add(document);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public sealed class AutocadSendBinding : ISendBinding
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
private readonly AutocadSettings _autocadSettings;
private readonly ISendConversionCache _sendConversionCache;
private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;

/// <summary>
/// Used internally to aggregate the changed objects' id.
Expand All @@ -43,7 +44,8 @@ public AutocadSendBinding(
CancellationManager cancellationManager,
AutocadSettings autocadSettings,
IUnitOfWorkFactory unitOfWorkFactory,
ISendConversionCache sendConversionCache
ISendConversionCache sendConversionCache,
ITopLevelExceptionHandler topLevelExceptionHandler
)
{
_store = store;
Expand All @@ -53,10 +55,13 @@ ISendConversionCache sendConversionCache
_cancellationManager = cancellationManager;
_sendFilters = sendFilters.ToList();
_sendConversionCache = sendConversionCache;
_topLevelExceptionHandler = topLevelExceptionHandler;
Parent = parent;
Commands = new SendBindingUICommands(parent);

Application.DocumentManager.DocumentActivated += (sender, args) => SubscribeToObjectChanges(args.Document);
Application.DocumentManager.DocumentActivated += (_, args) =>
topLevelExceptionHandler.CatchUnhandled(() => SubscribeToObjectChanges(args.Document));

if (Application.DocumentManager.CurrentDocument != null)
{
// catches the case when autocad just opens up with a blank new doc
Expand All @@ -74,9 +79,14 @@ private void SubscribeToObjectChanges(Document doc)
}

_docSubsTracker.Add(doc.Name);
doc.Database.ObjectAppended += (_, e) => OnChangeChangedObjectIds(e.DBObject);
doc.Database.ObjectErased += (_, e) => OnChangeChangedObjectIds(e.DBObject);
doc.Database.ObjectModified += (_, e) => OnChangeChangedObjectIds(e.DBObject);
doc.Database.ObjectAppended += (_, e) => OnObjectChanged(e.DBObject);
doc.Database.ObjectErased += (_, e) => OnObjectChanged(e.DBObject);
doc.Database.ObjectModified += (_, e) => OnObjectChanged(e.DBObject);
}

void OnObjectChanged(DBObject dbObject)
{
_topLevelExceptionHandler.CatchUnhandled(() => OnChangeChangedObjectIds(dbObject));
}

private void OnChangeChangedObjectIds(DBObject dBObject)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.Utils;
using Speckle.Newtonsoft.Json;
Expand All @@ -12,7 +13,8 @@ public class AutocadDocumentStore : DocumentModelStore

public AutocadDocumentStore(
JsonSerializerSettings jsonSerializerSettings,
AutocadDocumentManager autocadDocumentManager
AutocadDocumentManager autocadDocumentManager,
ITopLevelExceptionHandler topLevelExceptionHandler
)
: base(jsonSerializerSettings, true)
{
Expand All @@ -29,14 +31,15 @@ AutocadDocumentManager autocadDocumentManager
OnDocChangeInternal(Application.DocumentManager.MdiActiveDocument);
}

Application.DocumentManager.DocumentActivated += (_, e) => OnDocChangeInternal(e.Document);
Application.DocumentManager.DocumentActivated += (_, e) =>
topLevelExceptionHandler.CatchUnhandled(() => OnDocChangeInternal(e.Document));

// since below event triggered as secondary, it breaks the logic in OnDocChangeInternal function, leaving it here for now.
// Autodesk.AutoCAD.ApplicationServices.Application.DocumentWindowCollection.DocumentWindowActivated += (_, args) =>
// OnDocChangeInternal((Document)args.DocumentWindow.Document);
}

private void OnDocChangeInternal(Document doc)
private void OnDocChangeInternal(Document? doc)
{
var currentDocName = doc != null ? doc.Name : _nullDocumentName;
if (_previousDocName == currentDocName)
Expand All @@ -54,7 +57,7 @@ public override void ReadFromFile()
Models = new();

// POC: Will be addressed to move it into AutocadContext!
Document doc = Application.DocumentManager.MdiActiveDocument;
Document? doc = Application.DocumentManager.MdiActiveDocument;

if (doc == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
private readonly CancellationManager _cancellationManager;
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
private readonly ISendConversionCache _sendConversionCache;
private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;

public RevitSendBinding(
IRevitIdleManager idleManager,
Expand All @@ -36,7 +37,8 @@ public RevitSendBinding(
IBridge bridge,
IUnitOfWorkFactory unitOfWorkFactory,
RevitSettings revitSettings,
ISendConversionCache sendConversionCache
ISendConversionCache sendConversionCache,
ITopLevelExceptionHandler topLevelExceptionHandler
)
: base("sendBinding", store, bridge, revitContext)
{
Expand All @@ -45,12 +47,15 @@ ISendConversionCache sendConversionCache
_unitOfWorkFactory = unitOfWorkFactory;
_revitSettings = revitSettings;
_sendConversionCache = sendConversionCache;
_topLevelExceptionHandler = topLevelExceptionHandler;

Commands = new SendBindingUICommands(bridge);
// TODO expiry events
// TODO filters need refresh events
revitContext.UIApplication.NotNull().Application.DocumentChanged += (_, e) => DocChangeHandler(e);
Store.DocumentChanged += (_, _) => OnDocumentChanged();
revitContext.UIApplication.NotNull().Application.DocumentChanged += (_, e) =>
_topLevelExceptionHandler.CatchUnhandled(() => DocChangeHandler(e));

Store.DocumentChanged += (_, _) => _topLevelExceptionHandler.CatchUnhandled(OnDocumentChanged);
}

public List<ISendFilter> GetSendFilters()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@ namespace Speckle.Connectors.Revit.Bindings;
internal sealed class SelectionBinding : RevitBaseBinding, ISelectionBinding
{
private readonly IRevitIdleManager _revitIdleManager;
private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;

public SelectionBinding(
RevitContext revitContext,
DocumentModelStore store,
IRevitIdleManager idleManager,
IBridge bridge
IBridge bridge,
ITopLevelExceptionHandler topLevelExceptionHandler
)
: base("selectionBinding", store, bridge, revitContext)
{
_revitIdleManager = idleManager;
_topLevelExceptionHandler = topLevelExceptionHandler;
// POC: we can inject the solution here
// TODO: Need to figure it out equivalent of SelectionChanged for Revit2020
RevitContext.UIApplication.NotNull().SelectionChanged += (_, _) =>
_revitIdleManager.SubscribeToIdle(OnSelectionChanged);
topLevelExceptionHandler.CatchUnhandled(() => _revitIdleManager.SubscribeToIdle(OnSelectionChanged));
}

private void OnSelectionChanged()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Events;
using Revit.Async;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.Revit.Plugin;
using Speckle.Connectors.RevitShared.Helpers;
Expand All @@ -29,7 +30,8 @@ public RevitDocumentStore(
RevitContext revitContext,
JsonSerializerSettings serializerSettings,
DocumentModelStorageSchema documentModelStorageSchema,
IdStorageSchema idStorageSchema
IdStorageSchema idStorageSchema,
ITopLevelExceptionHandler topLevelExceptionHandler
)
: base(serializerSettings, true)
{
Expand All @@ -40,12 +42,15 @@ IdStorageSchema idStorageSchema

UIApplication uiApplication = _revitContext.UIApplication.NotNull();

uiApplication.ViewActivated += OnViewActivated;
uiApplication.ViewActivated += (s, e) => topLevelExceptionHandler.CatchUnhandled(() => OnViewActivated(s, e));

uiApplication.Application.DocumentOpening += (_, _) => IsDocumentInit = false;
uiApplication.Application.DocumentOpened += (_, _) => IsDocumentInit = false;
uiApplication.Application.DocumentOpening += (_, _) =>
topLevelExceptionHandler.CatchUnhandled(() => IsDocumentInit = false);

Models.CollectionChanged += (_, _) => WriteToFile();
uiApplication.Application.DocumentOpened += (_, _) =>
topLevelExceptionHandler.CatchUnhandled(() => IsDocumentInit = false);

Models.CollectionChanged += (_, _) => topLevelExceptionHandler.CatchUnhandled(WriteToFile);

// There is no event that we can hook here for double-click file open...
// It is kind of harmless since we create this object as "SingleInstance".
Expand Down
Loading

0 comments on commit 483fe7d

Please sign in to comment.