Initial commit from alpha
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"csharpier": {
|
||||
"version": "0.28.2",
|
||||
"commands": [
|
||||
"dotnet-csharpier"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
printWidth: 120
|
||||
useTabs: false
|
||||
tabWidth: 2
|
||||
preprocessorSymbolSets:
|
||||
- ""
|
||||
- "DEBUG"
|
||||
- "DEBUG,CODE_STYLE"
|
||||
@@ -0,0 +1,309 @@
|
||||
root = true
|
||||
# Don't use tabs for indentation.
|
||||
[*]
|
||||
indent_style = space
|
||||
|
||||
# Microsoft .NET properties
|
||||
csharp_using_directive_placement = outside_namespace:silent
|
||||
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
|
||||
dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none
|
||||
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none
|
||||
|
||||
|
||||
# Standard properties
|
||||
insert_final_newline = true
|
||||
|
||||
# (Please don't specify an indent_size here; that has too many unintended consequences.)
|
||||
|
||||
# Code files
|
||||
[*.{cs,csx,vb,vbx}]
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
|
||||
# Xml project files
|
||||
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
|
||||
indent_size = 2
|
||||
space_after_last_pi_attribute = false
|
||||
# Xml config files
|
||||
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
|
||||
indent_size = 2
|
||||
space_after_last_pi_attribute = false
|
||||
|
||||
# JSON files
|
||||
[*.json]
|
||||
indent_size = 2
|
||||
|
||||
# Dotnet code style settings:
|
||||
[*.{cs,vb}]
|
||||
# Sort using and Import directives with System.* appearing first
|
||||
dotnet_sort_system_directives_first = true
|
||||
dotnet_separate_import_directive_groups = false
|
||||
|
||||
# Avoid "this." and "Me." if not necessary
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
|
||||
# Use language keywords instead of framework type names for type references
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
# Parentheses preferences
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:silent
|
||||
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:silent
|
||||
dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:silent
|
||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
|
||||
|
||||
# Modifier preferences
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
|
||||
dotnet_style_readonly_field = true:suggestion
|
||||
|
||||
# Expression-level preferences
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:warning
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
|
||||
|
||||
# CSharp code style settings:
|
||||
[*.cs]
|
||||
# Prefer "var" everywhere
|
||||
csharp_style_var_elsewhere = false:none
|
||||
csharp_style_var_for_built_in_types = false:none
|
||||
csharp_style_var_when_type_is_apparent = false:none
|
||||
|
||||
# Prefer method-like constructs to have a block body
|
||||
csharp_style_expression_bodied_methods = true:suggestion
|
||||
csharp_style_expression_bodied_constructors = false:suggestion
|
||||
csharp_style_expression_bodied_operators = true:suggestion
|
||||
|
||||
# Prefer property-like constructs to have an expression-body
|
||||
csharp_style_expression_bodied_properties = true:suggestion
|
||||
csharp_style_expression_bodied_indexers = true:suggestion
|
||||
csharp_style_expression_bodied_accessors = true:suggestion
|
||||
|
||||
# Suggest more modern language features when available
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
csharp_style_namespace_declarations = file_scoped
|
||||
|
||||
# Newline settings
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
|
||||
# Space preferences
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
|
||||
# Wrapping preferences
|
||||
csharp_preserve_single_line_statements = true
|
||||
csharp_preserve_single_line_blocks = true
|
||||
|
||||
|
||||
|
||||
# SYMBOL NAMING RULES
|
||||
# Copied from https://github.com/dotnet/roslyn/blob/main/.editorconfig
|
||||
# Adapted rules:
|
||||
# - Constants are ALL_UPPER
|
||||
# - Non-private fields are PascalCase
|
||||
|
||||
# Non-private fields are PascalCase
|
||||
dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.severity = warning
|
||||
dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = non_private_readonly_fields
|
||||
dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_readonly_field_style
|
||||
|
||||
dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
|
||||
|
||||
dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case
|
||||
|
||||
# Constants are ALL_UPPER
|
||||
dotnet_naming_rule.constants_should_be_all_upper.severity = warning
|
||||
dotnet_naming_rule.constants_should_be_all_upper.symbols = constants
|
||||
dotnet_naming_rule.constants_should_be_all_upper.style = constant_style
|
||||
|
||||
dotnet_naming_symbols.constants.applicable_kinds = field, local
|
||||
dotnet_naming_symbols.constants.required_modifiers = const
|
||||
|
||||
dotnet_naming_style.constant_style.capitalization = all_upper
|
||||
|
||||
# Private static fields are camelCase and start with s_
|
||||
dotnet_naming_rule.static_fields_should_be_camel_case.severity = warning
|
||||
dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields
|
||||
dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style
|
||||
|
||||
dotnet_naming_symbols.static_fields.applicable_accessibilities = private
|
||||
dotnet_naming_symbols.static_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.static_fields.required_modifiers = static
|
||||
|
||||
dotnet_naming_style.static_field_style.capitalization = camel_case
|
||||
dotnet_naming_style.static_field_style.required_prefix = s_
|
||||
|
||||
|
||||
# Instance fields are camelCase and start with _
|
||||
dotnet_naming_rule.instance_fields_should_be_camel_case.severity = warning
|
||||
dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
|
||||
dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
|
||||
|
||||
dotnet_naming_symbols.instance_fields.applicable_kinds = field
|
||||
|
||||
dotnet_naming_style.instance_field_style.capitalization = camel_case
|
||||
dotnet_naming_style.instance_field_style.required_prefix = _
|
||||
|
||||
# Locals and parameters are camelCase
|
||||
dotnet_naming_rule.locals_should_be_camel_case.severity = warning
|
||||
dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters
|
||||
dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style
|
||||
|
||||
dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local
|
||||
|
||||
dotnet_naming_style.camel_case_style.capitalization = camel_case
|
||||
|
||||
# Local functions are PascalCase
|
||||
dotnet_naming_rule.local_functions_should_be_pascal_case.severity = warning
|
||||
dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
|
||||
dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style
|
||||
|
||||
dotnet_naming_symbols.local_functions.applicable_kinds = local_function
|
||||
|
||||
dotnet_naming_style.local_function_style.capitalization = pascal_case
|
||||
|
||||
# By default, name items with PascalCase
|
||||
dotnet_naming_rule.members_should_be_pascal_case.severity = warning
|
||||
dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members
|
||||
dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style
|
||||
|
||||
dotnet_naming_symbols.all_members.applicable_kinds = *
|
||||
|
||||
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
|
||||
|
||||
|
||||
# Analyzer settings
|
||||
dotnet_analyzer_diagnostic.category-Style.severity = warning # All rules will use this severity unless overriden
|
||||
dotnet_diagnostic.ide0055.severity = none # Formatting rule: Incompatible with CSharpier
|
||||
dotnet_diagnostic.ide0007.severity = none # Use var instead of explicit type: Preference
|
||||
dotnet_diagnostic.ide0009.severity = none # Add this or Me qualification: Preference
|
||||
dotnet_diagnostic.ide0200.severity = none # Remove unnecessary lambda expression: may be performance reasons not to
|
||||
dotnet_diagnostic.ide0058.severity = none # Remove unnecessary expression value: Subjective
|
||||
dotnet_diagnostic.ide0010.severity = none # Add missing cases to switch statement: Too verbose
|
||||
dotnet_diagnostic.ide0200.severity = none # Remove unnecessary lambda expression: may be performance reasons not to
|
||||
dotnet_diagnostic.ide0058.severity = none # Remove unnecessary expression value: Subjective
|
||||
dotnet_diagnostic.ide0001.severity = suggestion # Name can be simplified: Non enforceable in build
|
||||
dotnet_diagnostic.ide0046.severity = suggestion # Use conditional expression for return: Subjective
|
||||
dotnet_diagnostic.ide0045.severity = suggestion # Use conditional expression for assignment: Subjective
|
||||
dotnet_diagnostic.ide0078.severity = suggestion # Use pattern matching: Subjective
|
||||
dotnet_diagnostic.ide0260.severity = suggestion # Use pattern matching: Subjective
|
||||
dotnet_diagnostic.ide0022.severity = suggestion # Use expression body for method: Subjective
|
||||
dotnet_diagnostic.ide0061.severity = suggestion # Use expression body for local functions: Subjective
|
||||
dotnet_diagnostic.ide0063.severity = suggestion # Using directive can be simplified
|
||||
dotnet_diagnostic.ide0066.severity = suggestion # Use switch expression: Subjective
|
||||
dotnet_diagnostic.ide0029.severity = suggestion # Null check can be simplified: Subjective
|
||||
dotnet_diagnostic.ide0030.severity = suggestion # Null check can be simplified: Subjective
|
||||
dotnet_diagnostic.ide0270.severity = suggestion # Null check can be simplified: Subjective
|
||||
dotnet_diagnostic.ide0042.severity = suggestion # Deconstruct variable declaration: Subjective
|
||||
dotnet_diagnostic.ide0039.severity = suggestion # Use local function instead of lambda: Subjective
|
||||
dotnet_diagnostic.ide0029.severity = suggestion # Null check can be simplified: Subjective
|
||||
dotnet_diagnostic.ide0030.severity = suggestion # Null check can be simplified: Subjective
|
||||
dotnet_diagnostic.ide0270.severity = suggestion # Null check can be simplified: Subjective
|
||||
dotnet_diagnostic.ide0042.severity = suggestion # Deconstruct variable declaration: Subjective
|
||||
dotnet_diagnostic.ide0028.severity = suggestion # Use collection initializers: Subjective
|
||||
dotnet_diagnostic.ide0072.severity = suggestion # Populate switch statement: Subjective
|
||||
dotnet_diagnostic.ide0074.severity = suggestion # Use compound assignment: Subjective
|
||||
|
||||
# Maintainability rules
|
||||
dotnet_diagnostic.ca1501.severity = warning # Avoid excessive inheritance
|
||||
dotnet_diagnostic.ca1502.severity = warning # Avoid excessive complexity
|
||||
dotnet_diagnostic.ca1505.severity = warning # Avoid unmaintainable code
|
||||
dotnet_diagnostic.ca1506.severity = warning # Avoid excessive class coupling
|
||||
dotnet_diagnostic.ca1507.severity = warning # Use nameof in place of string
|
||||
dotnet_diagnostic.ca1508.severity = warning # Avoid dead conditional code
|
||||
dotnet_diagnostic.ca1509.severity = warning # Invalid entry in code metrics configuration file
|
||||
dotnet_diagnostic.ca1861.severity = none # Prefer 'static readonly' fields over constant array arguments if the called method is called repeatedly and is not mutating the passed array (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1861)
|
||||
|
||||
dotnet_diagnostic.cs8618.severity = suggestion # nullable problem
|
||||
dotnet_diagnostic.CS0809.severity = suggestion # obsolete errors
|
||||
dotnet_diagnostic.CS0618.severity = suggestion # obsolete errors
|
||||
|
||||
|
||||
# Performance rules
|
||||
dotnet_diagnostic.ca1849.severity = suggestion # Call async methods when in an async method: May decrease performance
|
||||
dotnet_diagnostic.ca1822.severity = suggestion # Mark member as static
|
||||
dotnet_diagnostic.ca1859.severity = suggestion # Use concrete types when possible for improved performance
|
||||
|
||||
# Design rule
|
||||
dotnet_diagnostic.ca1002.severity = suggestion # Do not expose generic lists
|
||||
dotnet_diagnostic.ca1051.severity = warning # Do not declare visible instance fields
|
||||
dotnet_diagnostic.ca1056.severity = suggestion # URI properties should not be strings
|
||||
dotnet_diagnostic.ca1062.severity = none # Public method must check all parameters for null
|
||||
|
||||
# Naming
|
||||
dotnet_diagnostic.ca1707.severity = none # Remove underscores in names
|
||||
|
||||
# Usage
|
||||
dotnet_diagnostic.ca2227.severity = suggestion # Collection props should be read-only
|
||||
|
||||
dotnet_code_quality.ca1051.exclude_structs = true # CA1051 is excluded in structs
|
||||
dotnet_code_quality.dispose_ownership_transfer_at_constructor = true # CA2000 has a lot of false positives without this
|
||||
dotnet_code_quality.dispose_ownership_transfer_at_method_call = true # CA2000 has a lot of false positives without this
|
||||
dotnet_code_quality.dispose_analysis_kind = NonExceptionPathsOnlyNotDisposed # CA2000 has a lot of false positives without this
|
||||
|
||||
# NUnit
|
||||
dotnet_diagnostic.NUnit2001.severity = warning # Consider using Assert.That(expr, Is.False) instead of Assert.False(expr)
|
||||
dotnet_diagnostic.NUnit2002.severity = warning # Consider using Assert.That(expr, Is.False) instead of Assert.IsFalse(expr)
|
||||
dotnet_diagnostic.NUnit2003.severity = warning # Consider using Assert.That(expr, Is.True) instead of Assert.IsTrue(expr)
|
||||
dotnet_diagnostic.NUnit2004.severity = warning # Consider using Assert.That(expr, Is.True) instead of Assert.True(expr)
|
||||
dotnet_diagnostic.NUnit2005.severity = warning # Consider using Assert.That(actual, Is.EqualTo(expected)) instead of Assert.AreEqual(expected, actual)
|
||||
dotnet_diagnostic.NUnit2006.severity = warning # Consider using Assert.That(actual, Is.Not.EqualTo(expected)) instead of Assert.AreNotEqual(expected, actual)
|
||||
|
||||
dotnet_diagnostic.NUnit2010.severity = warning # Use EqualConstraint for better assertion messages in case of failure
|
||||
dotnet_diagnostic.NUnit2011.severity = warning # Use ContainsConstraint for better assertion messages in case of failure
|
||||
dotnet_diagnostic.NUnit2011.severity = warning # Use StartsWithConstraint for better assertion messages in case of failure
|
||||
dotnet_diagnostic.NUnit2011.severity = warning # Use EndsWithConstraint for better assertion messages in case of failure
|
||||
dotnet_diagnostic.NUnit2014.severity = warning # Use SomeItemsConstraint for better assertion messages in case of failure
|
||||
|
||||
dotnet_diagnostic.NUnit2015.severity = warning # Consider using Assert.That(actual, Is.SameAs(expected)) instead of Assert.AreSame(expected, actual)
|
||||
dotnet_diagnostic.NUnit2016.severity = warning # Consider using Assert.That(expr, Is.Null) instead of Assert.Null(expr)
|
||||
dotnet_diagnostic.NUnit2017.severity = warning # Consider using Assert.That(expr, Is.Null) instead of Assert.IsNull(expr)
|
||||
dotnet_diagnostic.NUnit2018.severity = warning # Consider using Assert.That(expr, Is.Not.Null) instead of Assert.NotNull(expr)
|
||||
dotnet_diagnostic.NUnit2028.severity = warning # Consider using Assert.That(actual, Is.GreaterThanOrEqualTo(expected)) instead of Assert.GreaterOrEqual(actual, expected)
|
||||
dotnet_diagnostic.NUnit2027.severity = warning # Consider using Assert.That(actual, Is.GreaterThan(expected)) instead of Assert.Greater(actual, expected)
|
||||
dotnet_diagnostic.NUnit2029.severity = warning # Consider using Assert.That(actual, Is.LessThan(expected)) instead of Assert.Less(actual, expected)
|
||||
dotnet_diagnostic.NUnit2030.severity = warning # Consider using Assert.That(actual, Is.LessThanOrEqualTo(expected)) instead of Assert.LessOrEqual(actual, expected)
|
||||
dotnet_diagnostic.NUnit2031.severity = warning # Consider using Assert.That(actual, Is.Not.SameAs(expected)) instead of Assert.AreNotSame(expected, actual)
|
||||
dotnet_diagnostic.NUnit2032.severity = warning # Consider using Assert.That(expr, Is.Zero) instead of Assert.Zero(expr)
|
||||
dotnet_diagnostic.NUnit2033.severity = warning # Consider using Assert.That(expr, Is.Not.Zero) instead of Assert.NotZero(expr)
|
||||
dotnet_diagnostic.NUnit2034.severity = warning # Consider using Assert.That(expr, Is.NaN) instead of Assert.IsNaN(expr)
|
||||
dotnet_diagnostic.NUnit2035.severity = warning # Consider using Assert.That(collection, Is.Empty) instead of Assert.IsEmpty(collection)
|
||||
dotnet_diagnostic.NUnit2036.severity = warning # Consider using Assert.That(collection, Is.Not.Empty) instead of Assert.IsNotEmpty(collection)
|
||||
dotnet_diagnostic.NUnit2037.severity = warning # Consider using Assert.That(collection, Does.Contain(instance)) instead of Assert.Contains(instance, collection)
|
||||
dotnet_diagnostic.NUnit2038.severity = warning # Consider using Assert.That(actual, Is.InstanceOf(expected)) instead of Assert.IsInstanceOf(expected, actual)
|
||||
dotnet_diagnostic.NUnit2039.severity = warning # Consider using Assert.That(actual, Is.Not.InstanceOf(expected)) instead of Assert.IsNotInstanceOf(expected, actual)
|
||||
|
||||
[*.{appxmanifest,asax,ascx,aspx,axaml,build,c,c++,cc,cginc,compute,cp,cpp,cs,cshtml,cu,cuh,cxx,dtd,fs,fsi,fsscript,fsx,fx,fxh,h,hh,hlsl,hlsli,hlslinc,hpp,hxx,inc,inl,ino,ipp,ixx,master,ml,mli,mpp,mq4,mq5,mqh,nuspec,paml,razor,resw,resx,shader,skin,tpp,usf,ush,vb,xaml,xamlx,xoml,xsd}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
@@ -0,0 +1,5 @@
|
||||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text=auto
|
||||
|
||||
# need original files to be windows
|
||||
*.txt text eol=crlf
|
||||
@@ -0,0 +1,21 @@
|
||||
**/bin/*
|
||||
**/obj/*
|
||||
_ReSharper.SharpCompress/
|
||||
bin/
|
||||
*.suo
|
||||
*.user
|
||||
TestArchives/Scratch/
|
||||
TestArchives/Scratch2/
|
||||
TestResults/
|
||||
*.nupkg
|
||||
packages/*/
|
||||
project.lock.json
|
||||
tests/TestArchives/Scratch
|
||||
.vs
|
||||
tools
|
||||
.vscode
|
||||
.idea/
|
||||
|
||||
.DS_Store
|
||||
*.snupkg
|
||||
coverage.xml
|
||||
@@ -0,0 +1,82 @@
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.DUI.Models.Card;
|
||||
using Speckle.Connectors.Utils;
|
||||
using Speckle.Connectors.Utils.Cancellation;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS.Bindings;
|
||||
|
||||
public sealed class ArcGISReceiveBinding : IReceiveBinding
|
||||
{
|
||||
public string Name { get; } = "receiveBinding";
|
||||
private readonly CancellationManager _cancellationManager;
|
||||
private readonly DocumentModelStore _store;
|
||||
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
|
||||
|
||||
public ReceiveBindingUICommands Commands { get; }
|
||||
public IBridge Parent { get; }
|
||||
|
||||
public ArcGISReceiveBinding(
|
||||
DocumentModelStore store,
|
||||
IBridge parent,
|
||||
CancellationManager cancellationManager,
|
||||
IUnitOfWorkFactory unitOfWorkFactory
|
||||
)
|
||||
{
|
||||
_store = store;
|
||||
_cancellationManager = cancellationManager;
|
||||
Parent = parent;
|
||||
Commands = new ReceiveBindingUICommands(parent);
|
||||
_unitOfWorkFactory = unitOfWorkFactory;
|
||||
}
|
||||
|
||||
public async Task Receive(string modelCardId)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get receiver card
|
||||
if (_store.GetModelById(modelCardId) is not ReceiverModelCard modelCard)
|
||||
{
|
||||
// Handle as GLOBAL ERROR at BrowserBridge
|
||||
throw new InvalidOperationException("No download model card was found.");
|
||||
}
|
||||
|
||||
// Init cancellation token source -> Manager also cancel it if exist before
|
||||
CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId);
|
||||
|
||||
using IUnitOfWork<ReceiveOperation> unitOfWork = _unitOfWorkFactory.Resolve<ReceiveOperation>();
|
||||
|
||||
// Receive host objects
|
||||
var receiveOperationResults = await unitOfWork.Service
|
||||
.Execute(
|
||||
modelCard.AccountId.NotNull(), // POC: I hear -you are saying why we're passing them separately. Not sure pass the DUI3-> Connectors.DUI project dependency to the SDK-> Connector.Utils
|
||||
modelCard.ProjectId.NotNull(),
|
||||
modelCard.ProjectName.NotNull(),
|
||||
modelCard.ModelName.NotNull(),
|
||||
modelCard.SelectedVersionId.NotNull(),
|
||||
cts.Token,
|
||||
(status, progress) =>
|
||||
Commands.SetModelProgress(modelCardId, new ModelCardProgress(modelCardId, status, progress), cts)
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
modelCard.BakedObjectIds = receiveOperationResults.BakedObjectIds.ToList();
|
||||
Commands.SetModelReceiveResult(
|
||||
modelCardId,
|
||||
receiveOperationResults.BakedObjectIds,
|
||||
receiveOperationResults.ConversionResults
|
||||
);
|
||||
}
|
||||
// Catch here specific exceptions if they related to model card.
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// SWALLOW -> UI handles it immediately, so we do not need to handle anything
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelReceive(string modelCardId) => _cancellationManager.CancelOperation(modelCardId);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using ArcGIS.Desktop.Mapping.Events;
|
||||
using ArcGIS.Desktop.Mapping;
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS.Bindings;
|
||||
|
||||
public class ArcGISSelectionBinding : ISelectionBinding
|
||||
{
|
||||
public string Name => "selectionBinding";
|
||||
public IBridge Parent { get; }
|
||||
|
||||
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(_ => topLevelHandler.CatchUnhandled(OnSelectionChanged), true);
|
||||
}
|
||||
|
||||
private void OnSelectionChanged()
|
||||
{
|
||||
SelectionInfo selInfo = GetSelection();
|
||||
Parent.Send(SelectionBindingEvents.SET_SELECTION, selInfo);
|
||||
}
|
||||
|
||||
public SelectionInfo GetSelection()
|
||||
{
|
||||
MapView mapView = MapView.Active;
|
||||
List<MapMember> selectedMembers = new();
|
||||
selectedMembers.AddRange(mapView.GetSelectedLayers());
|
||||
selectedMembers.AddRange(mapView.GetSelectedStandaloneTables());
|
||||
|
||||
List<string> objectTypes = selectedMembers
|
||||
.Select(o => o.GetType().ToString().Split(".").Last())
|
||||
.Distinct()
|
||||
.ToList();
|
||||
return new SelectionInfo(
|
||||
selectedMembers.Select(x => x.URI).ToList(),
|
||||
$"{selectedMembers.Count} layers ({string.Join(", ", objectTypes)})"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,411 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Speckle.Connectors.Utils.Cancellation;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.DUI.Models.Card;
|
||||
using Speckle.Connectors.DUI.Models.Card.SendFilter;
|
||||
using Speckle.Connectors.DUI.Settings;
|
||||
using ArcGIS.Desktop.Mapping.Events;
|
||||
using ArcGIS.Desktop.Mapping;
|
||||
using Speckle.Connectors.ArcGIS.Filters;
|
||||
using ArcGIS.Desktop.Editing.Events;
|
||||
using ArcGIS.Desktop.Framework.Threading.Tasks;
|
||||
using ArcGIS.Core.Data;
|
||||
using Speckle.Connectors.DUI.Exceptions;
|
||||
using Speckle.Connectors.Utils;
|
||||
using Speckle.Connectors.Utils.Caching;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS.Bindings;
|
||||
|
||||
public sealed class ArcGISSendBinding : ISendBinding
|
||||
{
|
||||
public string Name => "sendBinding";
|
||||
public SendBindingUICommands Commands { get; }
|
||||
public IBridge Parent { get; }
|
||||
|
||||
private readonly DocumentModelStore _store;
|
||||
private readonly IUnitOfWorkFactory _unitOfWorkFactory; // POC: unused? :D
|
||||
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.
|
||||
/// </summary>
|
||||
private HashSet<string> ChangedObjectIds { get; set; } = new();
|
||||
private List<FeatureLayer> SubscribedLayers { get; set; } = new();
|
||||
private List<StandaloneTable> SubscribedTables { get; set; } = new();
|
||||
|
||||
public ArcGISSendBinding(
|
||||
DocumentModelStore store,
|
||||
IBridge parent,
|
||||
IEnumerable<ISendFilter> sendFilters,
|
||||
IUnitOfWorkFactory unitOfWorkFactory,
|
||||
CancellationManager cancellationManager,
|
||||
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(
|
||||
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()
|
||||
{
|
||||
var task = QueuedTask.Run(() =>
|
||||
{
|
||||
if (MapView.Active == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// subscribe to layers
|
||||
foreach (Layer layer in MapView.Active.Map.Layers)
|
||||
{
|
||||
if (layer is FeatureLayer featureLayer)
|
||||
{
|
||||
SubscribeToFeatureLayerDataSourceChange(featureLayer);
|
||||
}
|
||||
}
|
||||
// subscribe to tables
|
||||
foreach (StandaloneTable table in MapView.Active.Map.StandaloneTables)
|
||||
{
|
||||
SubscribeToTableDataSourceChange(table);
|
||||
}
|
||||
});
|
||||
task.Wait();
|
||||
}
|
||||
|
||||
private void SubscribeToFeatureLayerDataSourceChange(FeatureLayer layer)
|
||||
{
|
||||
if (SubscribedLayers.Contains(layer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Table layerTable = layer.GetTable();
|
||||
if (layerTable != null)
|
||||
{
|
||||
SubscribeToAnyDataSourceChange(layerTable);
|
||||
SubscribedLayers.Add(layer);
|
||||
}
|
||||
}
|
||||
|
||||
private void SubscribeToTableDataSourceChange(StandaloneTable table)
|
||||
{
|
||||
if (SubscribedTables.Contains(table))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Table layerTable = table.GetTable();
|
||||
if (layerTable != null)
|
||||
{
|
||||
SubscribeToAnyDataSourceChange(layerTable);
|
||||
SubscribedTables.Add(table);
|
||||
}
|
||||
}
|
||||
|
||||
private void SubscribeToAnyDataSourceChange(Table layerTable)
|
||||
{
|
||||
RowCreatedEvent.Subscribe(
|
||||
(args) =>
|
||||
{
|
||||
OnRowChanged(args);
|
||||
},
|
||||
layerTable
|
||||
);
|
||||
RowChangedEvent.Subscribe(
|
||||
(args) =>
|
||||
{
|
||||
OnRowChanged(args);
|
||||
},
|
||||
layerTable
|
||||
);
|
||||
RowDeletedEvent.Subscribe(
|
||||
(args) =>
|
||||
{
|
||||
OnRowChanged(args);
|
||||
},
|
||||
layerTable
|
||||
);
|
||||
}
|
||||
|
||||
private void OnRowChanged(RowChangedEventArgs args)
|
||||
{
|
||||
if (args == null || MapView.Active == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// get the path of the edited dataset
|
||||
var datasetURI = args.Row.GetTable().GetPath();
|
||||
|
||||
// find all layers & tables reading from the dataset
|
||||
foreach (Layer layer in MapView.Active.Map.Layers)
|
||||
{
|
||||
if (layer.GetPath() == datasetURI)
|
||||
{
|
||||
ChangedObjectIds.Add(layer.URI);
|
||||
}
|
||||
}
|
||||
foreach (StandaloneTable table in MapView.Active.Map.StandaloneTables)
|
||||
{
|
||||
if (table.GetPath() == datasetURI)
|
||||
{
|
||||
ChangedObjectIds.Add(table.URI);
|
||||
}
|
||||
}
|
||||
RunExpirationChecks(false);
|
||||
}
|
||||
|
||||
private void GetIdsForLayersRemovedEvent(LayerEventsArgs args)
|
||||
{
|
||||
foreach (Layer layer in args.Layers)
|
||||
{
|
||||
ChangedObjectIds.Add(layer.URI);
|
||||
}
|
||||
RunExpirationChecks(true);
|
||||
}
|
||||
|
||||
private void GetIdsForStandaloneTablesRemovedEvent(StandaloneTableEventArgs args)
|
||||
{
|
||||
foreach (StandaloneTable table in args.Tables)
|
||||
{
|
||||
ChangedObjectIds.Add(table.URI);
|
||||
}
|
||||
RunExpirationChecks(true);
|
||||
}
|
||||
|
||||
private void GetIdsForMapPropertyChangedEvent(MapPropertyChangedEventArgs args)
|
||||
{
|
||||
foreach (Map map in args.Maps)
|
||||
{
|
||||
foreach (MapMember member in map.Layers)
|
||||
{
|
||||
ChangedObjectIds.Add(member.URI);
|
||||
}
|
||||
}
|
||||
RunExpirationChecks(false);
|
||||
}
|
||||
|
||||
private void GetIdsForLayersAddedEvent(LayerEventsArgs args)
|
||||
{
|
||||
foreach (Layer layer in args.Layers)
|
||||
{
|
||||
if (layer is FeatureLayer featureLayer)
|
||||
{
|
||||
SubscribeToFeatureLayerDataSourceChange(featureLayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GetIdsForStandaloneTablesAddedEvent(StandaloneTableEventArgs args)
|
||||
{
|
||||
foreach (StandaloneTable table in args.Tables)
|
||||
{
|
||||
SubscribeToTableDataSourceChange(table);
|
||||
}
|
||||
}
|
||||
|
||||
private void GetIdsForMapMemberPropertiesChangedEvent(MapMemberPropertiesChangedEventArgs args)
|
||||
{
|
||||
// don't subscribe to all events (e.g. expanding group, changing visibility etc.)
|
||||
bool validEvent = false;
|
||||
foreach (var hint in args.EventHints)
|
||||
{
|
||||
if (
|
||||
hint == MapMemberEventHint.DataSource
|
||||
|| hint == MapMemberEventHint.DefinitionQuery
|
||||
|| hint == MapMemberEventHint.LabelClasses
|
||||
|| hint == MapMemberEventHint.LabelVisibility
|
||||
|| hint == MapMemberEventHint.Name
|
||||
|| hint == MapMemberEventHint.Renderer
|
||||
|| hint == MapMemberEventHint.SceneLayerType
|
||||
|| hint == MapMemberEventHint.URL
|
||||
)
|
||||
{
|
||||
validEvent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (validEvent)
|
||||
{
|
||||
foreach (MapMember member in args.MapMembers)
|
||||
{
|
||||
ChangedObjectIds.Add(member.URI);
|
||||
}
|
||||
RunExpirationChecks(false);
|
||||
}
|
||||
}
|
||||
|
||||
public List<ISendFilter> GetSendFilters() => _sendFilters;
|
||||
|
||||
// POC: delete this
|
||||
public List<CardSetting> GetSendSettings()
|
||||
{
|
||||
return new List<CardSetting>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Id = "includeAttributes",
|
||||
Title = "Include Attributes",
|
||||
Value = true,
|
||||
Type = "boolean"
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[SuppressMessage(
|
||||
"Maintainability",
|
||||
"CA1506:Avoid excessive class coupling",
|
||||
Justification = "Being refactored on in parallel, muting this issue so CI can pass initially."
|
||||
)]
|
||||
public async Task Send(string modelCardId)
|
||||
{
|
||||
//poc: dupe code between connectors
|
||||
using var unitOfWork = _unitOfWorkFactory.Resolve<SendOperation<MapMember>>();
|
||||
try
|
||||
{
|
||||
if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard)
|
||||
{
|
||||
// Handle as GLOBAL ERROR at BrowserBridge
|
||||
throw new InvalidOperationException("No publish model card was found.");
|
||||
}
|
||||
|
||||
// Init cancellation token source -> Manager also cancel it if exist before
|
||||
CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId);
|
||||
|
||||
var sendInfo = new SendInfo(
|
||||
modelCard.AccountId.NotNull(),
|
||||
modelCard.ProjectId.NotNull(),
|
||||
modelCard.ModelId.NotNull(),
|
||||
"ArcGIS"
|
||||
);
|
||||
|
||||
var sendResult = await QueuedTask
|
||||
.Run(async () =>
|
||||
{
|
||||
List<MapMember> mapMembers = modelCard.SendFilter
|
||||
.NotNull()
|
||||
.GetObjectIds()
|
||||
.Select(id => (MapMember)MapView.Active.Map.FindLayer(id) ?? MapView.Active.Map.FindStandaloneTable(id))
|
||||
.Where(obj => obj != null)
|
||||
.ToList();
|
||||
|
||||
if (mapMembers.Count == 0)
|
||||
{
|
||||
// Handle as CARD ERROR in this function
|
||||
throw new SpeckleSendFilterException(
|
||||
"No objects were found to convert. Please update your publish filter!"
|
||||
);
|
||||
}
|
||||
|
||||
var result = await unitOfWork.Service
|
||||
.Execute(
|
||||
mapMembers,
|
||||
sendInfo,
|
||||
(status, progress) =>
|
||||
Commands.SetModelProgress(modelCardId, new ModelCardProgress(modelCardId, status, progress), cts),
|
||||
cts.Token
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return result;
|
||||
})
|
||||
.ConfigureAwait(false);
|
||||
|
||||
Commands.SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults);
|
||||
}
|
||||
// Catch here specific exceptions if they related to model card.
|
||||
catch (SpeckleSendFilterException e)
|
||||
{
|
||||
Commands.SetModelError(modelCardId, e);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// SWALLOW -> UI handles it immediately, so we do not need to handle anything
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelSend(string modelCardId) => _cancellationManager.CancelOperation(modelCardId);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if any sender model cards contain any of the changed objects. If so, also updates the changed objects hashset for each model card - this last part is important for on send change detection.
|
||||
/// </summary>
|
||||
private void RunExpirationChecks(bool idsDeleted)
|
||||
{
|
||||
var senders = _store.GetSenders();
|
||||
List<string> expiredSenderIds = new();
|
||||
string[] objectIdsList = ChangedObjectIds.ToArray();
|
||||
|
||||
_sendConversionCache.EvictObjects(objectIdsList);
|
||||
|
||||
foreach (SenderModelCard sender in senders)
|
||||
{
|
||||
var objIds = sender.SendFilter.NotNull().GetObjectIds();
|
||||
var intersection = objIds.Intersect(objectIdsList).ToList();
|
||||
bool isExpired = sender.SendFilter.NotNull().CheckExpiry(ChangedObjectIds.ToArray());
|
||||
if (isExpired)
|
||||
{
|
||||
expiredSenderIds.Add(sender.ModelCardId.NotNull());
|
||||
|
||||
// Update the model card object Ids
|
||||
if (idsDeleted && sender.SendFilter is ArcGISSelectionFilter filter)
|
||||
{
|
||||
List<string> remainingObjIds = objIds.SkipWhile(x => intersection.Contains(x)).ToList();
|
||||
filter.SelectedObjectIds = remainingObjIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Commands.SetModelsExpired(expiredSenderIds);
|
||||
ChangedObjectIds = new HashSet<string>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
using System.Reflection;
|
||||
using ArcGIS.Core.Data;
|
||||
using ArcGIS.Desktop.Framework.Threading.Tasks;
|
||||
using ArcGIS.Desktop.Mapping;
|
||||
using Speckle.Connectors.ArcGIS.HostApp;
|
||||
using Speckle.Connectors.ArcGIS.Utils;
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.DUI.Models.Card;
|
||||
using Speckle.Connectors.Utils;
|
||||
using Speckle.Connectors.Utils.Reflection;
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS.Bindings;
|
||||
|
||||
//poc: dupe code between connectors
|
||||
public class BasicConnectorBinding : IBasicConnectorBinding
|
||||
{
|
||||
public string Name => "baseBinding";
|
||||
public IBridge Parent { get; }
|
||||
|
||||
public BasicConnectorBindingCommands Commands { get; }
|
||||
private readonly DocumentModelStore _store;
|
||||
private readonly ArcGISSettings _settings;
|
||||
|
||||
public BasicConnectorBinding(DocumentModelStore store, ArcGISSettings settings, IBridge parent)
|
||||
{
|
||||
_store = store;
|
||||
_settings = settings;
|
||||
Parent = parent;
|
||||
Commands = new BasicConnectorBindingCommands(parent);
|
||||
|
||||
_store.DocumentChanged += (_, _) =>
|
||||
{
|
||||
Commands.NotifyDocumentChanged();
|
||||
};
|
||||
}
|
||||
|
||||
public string GetSourceApplicationName() => _settings.HostAppInfo.Slug;
|
||||
|
||||
public string GetSourceApplicationVersion() => _settings.HostAppInfo.GetVersion(_settings.HostAppVersion);
|
||||
|
||||
public string GetConnectorVersion() => Assembly.GetAssembly(GetType()).NotNull().GetVersion();
|
||||
|
||||
public DocumentInfo? GetDocumentInfo()
|
||||
{
|
||||
if (MapView.Active is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DocumentInfo(MapView.Active.Map.URI, MapView.Active.Map.Name, MapView.Active.Map.Name);
|
||||
}
|
||||
|
||||
public DocumentModelStore GetDocumentState() => _store;
|
||||
|
||||
public void AddModel(ModelCard model) => _store.Models.Add(model);
|
||||
|
||||
public void UpdateModel(ModelCard model) => _store.UpdateModel(model);
|
||||
|
||||
public void RemoveModel(ModelCard model) => _store.RemoveModel(model);
|
||||
|
||||
public void HighlightObjects(List<string> objectIds) =>
|
||||
HighlightObjectsOnView(objectIds.Select(x => new ObjectID(x)).ToList());
|
||||
|
||||
public void HighlightModel(string modelCardId)
|
||||
{
|
||||
var model = _store.GetModelById(modelCardId);
|
||||
|
||||
if (model is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var objectIds = new List<ObjectID>();
|
||||
|
||||
if (model is SenderModelCard senderModelCard)
|
||||
{
|
||||
objectIds = senderModelCard.SendFilter.NotNull().GetObjectIds().Select(x => new ObjectID(x)).ToList();
|
||||
}
|
||||
|
||||
if (model is ReceiverModelCard receiverModelCard)
|
||||
{
|
||||
objectIds = receiverModelCard.BakedObjectIds.NotNull().Select(x => new ObjectID(x)).ToList();
|
||||
}
|
||||
|
||||
if (objectIds is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
HighlightObjectsOnView(objectIds);
|
||||
}
|
||||
|
||||
private async void HighlightObjectsOnView(List<ObjectID> objectIds)
|
||||
{
|
||||
MapView mapView = MapView.Active;
|
||||
|
||||
await QueuedTask
|
||||
.Run(() =>
|
||||
{
|
||||
List<MapMemberFeature> mapMembersFeatures = GetMapMembers(objectIds, mapView);
|
||||
ClearSelectionInTOC();
|
||||
ClearSelection();
|
||||
SelectMapMembersInTOC(mapMembersFeatures);
|
||||
SelectMapMembersAndFeatures(mapMembersFeatures);
|
||||
mapView.ZoomToSelected();
|
||||
})
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private List<MapMemberFeature> GetMapMembers(List<ObjectID> objectIds, MapView mapView)
|
||||
{
|
||||
// find the layer on the map (from the objectID) and add the featureID is available
|
||||
List<MapMemberFeature> mapMembersFeatures = new();
|
||||
|
||||
foreach (ObjectID objectId in objectIds)
|
||||
{
|
||||
MapMember mapMember = mapView.Map.FindLayer(objectId.MappedLayerURI, true);
|
||||
if (mapMember is null)
|
||||
{
|
||||
mapMember = mapView.Map.FindStandaloneTable(objectId.MappedLayerURI);
|
||||
}
|
||||
if (mapMember is not null)
|
||||
{
|
||||
MapMemberFeature mapMembersFeat = new(mapMember, objectId.FeatureId);
|
||||
mapMembersFeatures.Add(mapMembersFeat);
|
||||
}
|
||||
}
|
||||
return mapMembersFeatures;
|
||||
}
|
||||
|
||||
private void ClearSelection()
|
||||
{
|
||||
List<Layer> mapMembers = MapView.Active.Map.GetLayersAsFlattenedList().ToList();
|
||||
foreach (var member in mapMembers)
|
||||
{
|
||||
if (member is FeatureLayer featureLayer)
|
||||
{
|
||||
featureLayer.ClearSelection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearSelectionInTOC()
|
||||
{
|
||||
MapView.Active.ClearTOCSelection();
|
||||
}
|
||||
|
||||
private void SelectMapMembersAndFeatures(List<MapMemberFeature> mapMembersFeatures)
|
||||
{
|
||||
foreach (MapMemberFeature mapMemberFeat in mapMembersFeatures)
|
||||
{
|
||||
MapMember member = mapMemberFeat.MapMember;
|
||||
if (member is FeatureLayer layer)
|
||||
{
|
||||
if (mapMemberFeat.FeatureId == null)
|
||||
{
|
||||
// select full layer if featureID not specified
|
||||
layer.Select();
|
||||
}
|
||||
else
|
||||
{
|
||||
// query features by ID
|
||||
var objectIDfield = layer.GetFeatureClass().GetDefinition().GetObjectIDField();
|
||||
|
||||
// FeatureID range starts from 0, but auto-assigned IDs in the layer start from 1
|
||||
QueryFilter anotherQueryFilter = new() { WhereClause = $"{objectIDfield} = {mapMemberFeat.FeatureId + 1}" };
|
||||
using (Selection onlyOneSelection = layer.Select(anotherQueryFilter, SelectionCombinationMethod.New)) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectMapMembersInTOC(List<MapMemberFeature> mapMembersFeatures)
|
||||
{
|
||||
List<Layer> layers = new();
|
||||
List<StandaloneTable> tables = new();
|
||||
|
||||
foreach (MapMemberFeature mapMemberFeat in mapMembersFeatures)
|
||||
{
|
||||
MapMember member = mapMemberFeat.MapMember;
|
||||
if (member is Layer layer)
|
||||
{
|
||||
if (member is not GroupLayer) // group layer selection clears other layers selection
|
||||
{
|
||||
layers.Add(layer);
|
||||
}
|
||||
}
|
||||
else if (member is StandaloneTable table)
|
||||
{
|
||||
tables.Add(table);
|
||||
}
|
||||
}
|
||||
MapView.Active.SelectLayers(layers);
|
||||
|
||||
// this step clears previous selection, not clear how to ADD selection instead
|
||||
// this is why, activating it only if no layers are selected
|
||||
if (layers.Count == 0)
|
||||
{
|
||||
MapView.Active.SelectStandaloneTables(tables);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!--
|
||||
|
||||
Copyright 2022 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
|
||||
|
||||
https://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.
|
||||
|
||||
-->
|
||||
<ArcGIS defaultAssembly="Speckle.Connectors.ArcGIS3.dll" defaultNamespace="Speckle.Connectors.ArcGIS" xmlns="http://schemas.esri.com/DADF/Registry" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.esri.com/DADF/Registry file:///C:/Program%20Files/ArcGIS/Pro/bin/ArcGIS.Desktop.Framework.xsd">
|
||||
<AddInInfo id="{6CB1D25C-B8BF-4A33-9099-C1F8D1B32EFC}" version="1.0" desktopVersion="3.0.34047">
|
||||
<Name>Speckle</Name>
|
||||
<Description>Speckle connector for ArcGIS</Description>
|
||||
<Image>Images\AddinDesktop32.png</Image>
|
||||
<Author>Speckle Systems</Author>
|
||||
<Company>Speckle Systems</Company>
|
||||
<Date>8/5/2021 12:24:21 PM</Date>
|
||||
<Subject>Framework</Subject>
|
||||
<!-- Note subject can be one or more of these topics:
|
||||
Content, Framework, Editing, Geodatabase, Geometry, Geoprocessing, Layouts, Map Authoring, Map Exploration -->
|
||||
</AddInInfo>
|
||||
<modules>
|
||||
<insertModule id="ConnectorArcGIS_Module" className="SpeckleModule" autoLoad="false" caption="SpeckleModule">
|
||||
<!-- uncomment to have the control hosted on a separate tab-->
|
||||
<tabs>
|
||||
<!--<tab id="Speckle_Tab1" caption="New Tab">
|
||||
<group refID="Speckle_Group1"/>
|
||||
</tab>-->
|
||||
</tabs>
|
||||
<groups>
|
||||
<!-- comment this out if you have no controls on the Addin tab to avoid
|
||||
an empty group-->
|
||||
<group id="Speckle_Group1" caption="Speckle" appearsOnAddInTab="true" keytip="G1">
|
||||
<!-- host controls within groups -->
|
||||
<button refID="SpeckleDUI3_SpeckleDUI3OpenButton" size="large" />
|
||||
</group>
|
||||
</groups>
|
||||
<controls>
|
||||
<!-- add your controls here -->
|
||||
<button id="SpeckleDUI3_SpeckleDUI3OpenButton" caption="SpeckleNewUI"
|
||||
className="SpeckleDUI3OpenButton" loadOnClick="true"
|
||||
keytip="B1"
|
||||
smallImage="Images/s2logo_16.png"
|
||||
largeImage="Images/s2logo_32.png">
|
||||
<tooltip heading="Speckle Connector for ArcGIS">
|
||||
<disabledText />
|
||||
</tooltip>
|
||||
</button>
|
||||
</controls>
|
||||
|
||||
<dockPanes>
|
||||
<dockPane id="SpeckleDUI3_SpeckleDUI3" caption="SpeckleNewUI" className="SpeckleDUI3ViewModel" keytip="DockPane" initiallyVisible="true" dock="group" dockWith="esri_core_contentsDockPane">
|
||||
<content className="SpeckleDUI3Wrapper" />
|
||||
</dockPane>
|
||||
</dockPanes>
|
||||
|
||||
</insertModule>
|
||||
</modules>
|
||||
</ArcGIS>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 714 B |
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,63 @@
|
||||
using ArcGIS.Desktop.Mapping;
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using Speckle.Connectors.ArcGIS.Bindings;
|
||||
using Speckle.Connectors.ArcGis.Operations.Send;
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.ArcGIS.Utils;
|
||||
using Speckle.Connectors.ArcGIS.Operations.Receive;
|
||||
using Speckle.Connectors.DUI.Models.Card.SendFilter;
|
||||
using Speckle.Connectors.DUI.WebView;
|
||||
using Speckle.Connectors.Utils.Builders;
|
||||
using Speckle.Autofac;
|
||||
using Speckle.Connectors.ArcGIS.Filters;
|
||||
using Speckle.Connectors.ArcGIS.HostApp;
|
||||
using Speckle.Connectors.DUI;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.Utils;
|
||||
using Speckle.Connectors.Utils.Caching;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
using Speckle.Core.Models.GraphTraversal;
|
||||
|
||||
// POC: This is a temp reference to root object senders to tweak CI failing after having generic interfaces into common project.
|
||||
// This should go whenever it is aligned.
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS.DependencyInjection;
|
||||
|
||||
public class ArcGISConnectorModule : ISpeckleModule
|
||||
{
|
||||
public void Load(SpeckleContainerBuilder builder)
|
||||
{
|
||||
builder.AddAutofac();
|
||||
builder.AddConnectorUtils();
|
||||
builder.AddDUI();
|
||||
builder.AddDUIView();
|
||||
|
||||
// POC: Overwriting the SyncToMainThread to SyncToCurrentThread for ArcGIS only!
|
||||
// On SendOperation, once we called QueuedTask, it expect to run everything on same thread.
|
||||
builder.AddSingletonInstance<ISyncToThread, SyncToQueuedTask>();
|
||||
|
||||
builder.AddSingleton<DocumentModelStore, ArcGISDocumentStore>();
|
||||
|
||||
// Register bindings
|
||||
builder.AddSingleton<IBinding, TestBinding>();
|
||||
builder.AddSingleton<IBinding, ConfigBinding>("connectorName", "ArcGIS"); // POC: Easier like this for now, should be cleaned up later
|
||||
builder.AddSingleton<IBinding, AccountBinding>();
|
||||
builder.AddSingleton<IBinding, BasicConnectorBinding>();
|
||||
builder.AddSingleton<IBasicConnectorBinding, BasicConnectorBinding>();
|
||||
builder.AddSingleton<IBinding, ArcGISSelectionBinding>();
|
||||
builder.AddSingleton<IBinding, ArcGISSendBinding>();
|
||||
builder.AddSingleton<IBinding, ArcGISReceiveBinding>();
|
||||
|
||||
builder.AddTransient<ISendFilter, ArcGISSelectionFilter>();
|
||||
builder.AddScoped<IHostObjectBuilder, ArcGISHostObjectBuilder>();
|
||||
builder.AddSingleton(DefaultTraversal.CreateTraversalFunc());
|
||||
|
||||
// register send operation and dependencies
|
||||
builder.AddScoped<SendOperation<MapMember>>();
|
||||
builder.AddScoped<ArcGISRootObjectBuilder>();
|
||||
builder.AddScoped<IRootObjectBuilder<MapMember>, ArcGISRootObjectBuilder>();
|
||||
|
||||
// register send conversion cache
|
||||
builder.AddSingleton<ISendConversionCache, SendConversionCache>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Project>
|
||||
<!-- Code to zip up the files-->
|
||||
|
||||
<UsingTask TaskName="PackageAddIn" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
|
||||
<ParameterGroup>
|
||||
<ZipIntermediatePath ParameterType="System.String" Required="true" />
|
||||
<PackageType ParameterType="System.String" Required="true" />
|
||||
<TargetFolder ParameterType="System.String" Required="true" />
|
||||
<TargetFileName ParameterType="System.String" Required="true" />
|
||||
<RootNamespace ParameterType="System.String" Required="true" />
|
||||
<PackageOutputPath ParameterType="System.String" Output="true"/>
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Using Namespace="System"/>
|
||||
<Using Namespace="System.IO"/>
|
||||
<Using Namespace="System.Xml.Linq"/>
|
||||
<Using Namespace="System.Linq"/>
|
||||
<Using Namespace="System.IO.Compression"/>
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
Success = false;
|
||||
string ConfigNotFound = "{0} was not found. File must be present in the root of the project and its build action set to AddInContent.";
|
||||
string ZipIntermediatePathNotFound = "{0} was not found.";
|
||||
string DefaultAssemblyDoesNotMatch = "Your value of '{0}' for the '{1}' attribute in the {2} does not match the assembly name '{3}' set for your project.";
|
||||
string DefaultNSDoesNotMatch = "Your value of '{0}' for the '{1}' attribute in the {2} does not match the default namespace '{3}' set for your project.";
|
||||
//Create the name of the Config File and extension
|
||||
string extension = "";
|
||||
string config = "";
|
||||
string attrib_asm = "";
|
||||
string attrib_ns = "";
|
||||
var assemblyValMissing = "";
|
||||
var nsValMissing = "";
|
||||
if (PackageType.ToLower() == "plugin")
|
||||
{
|
||||
Log.LogMessage(MessageImportance.Low, "This is an plugin");
|
||||
config = "Config.xml";
|
||||
extension = ".esriPlugin";
|
||||
attrib_asm = "library";
|
||||
attrib_ns = "namespace";
|
||||
assemblyValMissing = "AddIn element 'library' attribute not found";
|
||||
nsValMissing = "AddIn element 'namespace' attribute not found";
|
||||
}
|
||||
else if (PackageType.ToLower() == "configuration")
|
||||
{
|
||||
Log.LogMessage(MessageImportance.Low, "This is an configuration");
|
||||
config = "Config.daml";
|
||||
extension = ".proConfigX";
|
||||
attrib_asm = "defaultAssembly";
|
||||
attrib_ns = "defaultNamespace";
|
||||
assemblyValMissing = "ArcGIS element 'defaultAssembly' attribute not found";
|
||||
nsValMissing = "ArcGIS element 'defaultNamespace' attribute not found";
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.LogMessage(MessageImportance.Low, "This is an addin");
|
||||
config = "Config.daml";
|
||||
bool proSDKProject = File.Exists(Path.Combine(ZipIntermediatePath, config));
|
||||
if (!proSDKProject) //This might be a class library that uses the Pro references only
|
||||
return true;
|
||||
extension = ".esriAddinX";
|
||||
attrib_asm = "defaultAssembly";
|
||||
attrib_ns = "defaultNamespace";
|
||||
assemblyValMissing = "ArcGIS element 'defaultAssembly' attribute not found";
|
||||
nsValMissing = "ArcGIS element 'defaultNamespace' attribute not found";
|
||||
}
|
||||
// Check if Config.daml exists in ZipFolder
|
||||
ZipIntermediatePath = Path.GetFullPath(ZipIntermediatePath);
|
||||
if (!Directory.Exists(ZipIntermediatePath))
|
||||
{
|
||||
Log.LogError(ZipIntermediatePathNotFound, ZipIntermediatePath);
|
||||
return false;
|
||||
}
|
||||
var addInXML = Path.Combine(ZipIntermediatePath, config);
|
||||
Log.LogMessage(MessageImportance.Low, "addInXML: " + addInXML);
|
||||
Log.LogMessage(MessageImportance.High, "PackageType: " + PackageType);
|
||||
if (!File.Exists(addInXML))
|
||||
{
|
||||
Log.LogError(ConfigNotFound, config);
|
||||
return false;
|
||||
}
|
||||
//Verfiy that an assembly with the name defined in the Config.daml
|
||||
//matches the default assembly set in the project. Ditto for the
|
||||
//namespace
|
||||
string DefaultAssembly = "";
|
||||
string DefaultNamespace = "";
|
||||
XDocument xdoc = XDocument.Load(addInXML);
|
||||
XNamespace DefaultNS = "http://schemas.esri.com/DADF/Registry";
|
||||
if (PackageType.ToLower() == "plugin")
|
||||
{
|
||||
var addin = xdoc.Root.Element(DefaultNS + "AddIn");
|
||||
if (addin != null)
|
||||
{
|
||||
var val = addin.Attribute("library");
|
||||
if (val != null)
|
||||
DefaultAssembly = val.Value;
|
||||
val = addin.Attribute("namespace");
|
||||
if (val != null)
|
||||
DefaultNamespace = val.Value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var val = xdoc.Root.Attribute("defaultAssembly");
|
||||
if (val != null)
|
||||
DefaultAssembly = val.Value;
|
||||
val = xdoc.Root.Attribute("defaultNamespace");
|
||||
if (val != null)
|
||||
DefaultNamespace = val.Value;
|
||||
}
|
||||
if (string.IsNullOrEmpty(DefaultAssembly))
|
||||
{
|
||||
Log.LogError(assemblyValMissing);
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrEmpty(DefaultNamespace))
|
||||
{
|
||||
Log.LogError(nsValMissing);
|
||||
return false;
|
||||
}
|
||||
|
||||
//check that the addin assembly and default assembly names match
|
||||
if (DefaultAssembly.ToLower() != TargetFileName.ToLower())
|
||||
{
|
||||
Log.LogWarning(DefaultAssemblyDoesNotMatch, DefaultAssembly, attrib_asm, config, TargetFileName);
|
||||
}
|
||||
//Ditto for namespace
|
||||
if (DefaultNamespace.ToLower() != RootNamespace.ToLower())
|
||||
{
|
||||
Log.LogWarning(DefaultNSDoesNotMatch, DefaultNamespace, attrib_ns, config, RootNamespace);
|
||||
}
|
||||
|
||||
if (!Directory.Exists(TargetFolder))
|
||||
{
|
||||
Directory.CreateDirectory(TargetFolder);
|
||||
}
|
||||
|
||||
string addInAssembly = System.IO.Path.GetFileNameWithoutExtension(DefaultAssembly);
|
||||
string archiveName = addInAssembly + extension;
|
||||
try
|
||||
{
|
||||
string file = Path.Combine(TargetFolder, archiveName);
|
||||
if (File.Exists(file))
|
||||
File.Delete(file);
|
||||
System.IO.Compression.ZipFile.CreateFromDirectory(ZipIntermediatePath, file);
|
||||
PackageOutputPath = Path.GetFullPath(file);
|
||||
Success = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.LogErrorFromException(ex);
|
||||
return false;
|
||||
}
|
||||
return Success;
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
<!-- Code to find relative path-->
|
||||
<UsingTask TaskName="ConvertToRelativePath" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
|
||||
<ParameterGroup>
|
||||
<RelativeTo ParameterType="System.String" Required="true"/>
|
||||
<Paths ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
|
||||
<RelativePaths ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true"/>
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Using Namespace="System"/>
|
||||
<Using Namespace="System.IO"/>
|
||||
<Using Namespace="System.Linq"/>
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
var result = new List<ITaskItem>();
|
||||
System.Uri relativeTo = new Uri(this.RelativeTo);
|
||||
foreach (var i in Paths) {
|
||||
try {
|
||||
System.Uri itemFullPath = new Uri(i.GetMetadata("FullPath"));
|
||||
var relativeUri = relativeTo.MakeRelativeUri(itemFullPath);
|
||||
|
||||
result.Add(new TaskItem(Uri.UnescapeDataString(relativeUri.ToString())));
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
RelativePaths = result.ToArray();
|
||||
foreach (var i in RelativePaths)
|
||||
{
|
||||
Log.LogMessage(MessageImportance.Low, "RelativePaths: " + i.ToString());
|
||||
}
|
||||
return true;
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
<UsingTask TaskName="CleanAddIn" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
|
||||
<ParameterGroup>
|
||||
<ProjectDir ParameterType="System.String" Required="true"/>
|
||||
<AssemblyName ParameterType="System.String" Required="true"/>
|
||||
<PackageType ParameterType="System.String" Required="true"/>
|
||||
<!--<ArcGISFolder ParameterType="System.String" Output="true" /> -->
|
||||
<CleanInfo ParameterType="System.String" Output="true"/>
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Using Namespace="System"/>
|
||||
<Using Namespace="System.IO"/>
|
||||
<Using Namespace="System.Xml.Linq"/>
|
||||
<Using Namespace="System.Linq"/>
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
Success = false;
|
||||
string ConfigNotFound = "{0} was not found. File must be present in the root of the project and its build action set to AddInContent.";
|
||||
|
||||
//Create the name of the Config File and extension
|
||||
string extension = "";
|
||||
string config = "";
|
||||
|
||||
if (PackageType.ToLower() == "plugin")
|
||||
{
|
||||
config = "Config.xml";
|
||||
extension = ".esriPlugin";
|
||||
}
|
||||
else if (PackageType.ToLower() == "configuration")
|
||||
{
|
||||
config = "Config.daml";
|
||||
extension = ".proConfigX";
|
||||
}
|
||||
else
|
||||
{
|
||||
config = "Config.daml";
|
||||
bool proSDKProject = File.Exists(Path.Combine(ProjectDir, config));
|
||||
if (!proSDKProject) //This might be a class library that uses the Pro references only
|
||||
return true;
|
||||
extension = ".esriAddinX";
|
||||
}
|
||||
|
||||
var addInXML = Path.Combine(ProjectDir, config);
|
||||
if (!File.Exists(addInXML))
|
||||
{
|
||||
Log.LogError(ConfigNotFound, config);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Get the add-in id
|
||||
XDocument xdoc = XDocument.Load(addInXML);
|
||||
XNamespace DefaultNS = "http://schemas.esri.com/DADF/Registry";
|
||||
if (PackageType.ToLower() == "plugin")
|
||||
{
|
||||
Log.LogMessage("process plugin");
|
||||
var addInID = xdoc.Root.Element(DefaultNS + "AddInID");
|
||||
CleanInfo = addInID.Value;//let it error if it's missing
|
||||
}
|
||||
else if (PackageType.ToLower() == "addin")
|
||||
{
|
||||
Log.LogMessage("process addin");
|
||||
var addinInfo = xdoc.Root.Element(DefaultNS + "AddInInfo");
|
||||
CleanInfo = addinInfo.Attribute("id").Value;//let it error if it's missing
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.LogMessage("process configuration");
|
||||
CleanInfo = AssemblyName + extension;
|
||||
}
|
||||
Success = true;
|
||||
return Success;
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
<!-- Define additional BuildAction option -->
|
||||
<!-- Set up default zip properties -->
|
||||
<PropertyGroup>
|
||||
<PackageType Condition="'$(PackageType)' == ''">Addin</PackageType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ArcGISFolder>$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\ESRI\ArcGISPro', 'InstallDir', null, RegistryView.Registry64))</ArcGISFolder>
|
||||
<ArcGISFolder Condition="'$(ArcGISFolder)' == ''">$(registry:HKEY_CURRENT_USER\SOFTWARE\ESRI\ArcGISPro@InstallDir)</ArcGISFolder>
|
||||
</PropertyGroup>
|
||||
<Target Name="ArcGISInstallOutput" AfterTargets="Build">
|
||||
<Message Text="IntermediateOutputPath Name: $(IntermediateOutputPath)..." Importance="High"/>
|
||||
<Message Text="CleanFile Name: $(CleanFile)..." Importance="High"/>
|
||||
<Message Text="ProjectDir Name: $(ProjectDir)..." Importance="High"/>
|
||||
<Message Text="AssemblyName Name: $(AssemblyName)..." Importance="High"/>
|
||||
<Message Text="TargetFileName Name: $(TargetFileName)..." Importance="High"/>
|
||||
<Message Text="RootNamespace: $(RootNamespace)..." Importance="High"/>
|
||||
<Message Text="TargetFolder Name: $(OutDir)..." Importance="High"/>
|
||||
<Message Text="PackageType Name: $(PackageType)..." Importance="High"/>
|
||||
<Message Text="Install dir: $(ArcGISFolder)" Importance="High"/>
|
||||
<!-- Get a list of project outputs from the cache file and FileWritesXXX item,
|
||||
excluding those in intermediate output directory -->
|
||||
<!-- Note clean file may miss listing CopyLocal reference -->
|
||||
<ReadLinesFromFile File="$(IntermediateOutputPath)$(CleanFile)">
|
||||
<Output TaskParameter="Lines" ItemName="CacheOutputFiles" />
|
||||
</ReadLinesFromFile>
|
||||
<FindUnderPath Files="@(CacheOutputFiles)" Path="$(OutDir)">
|
||||
<Output TaskParameter="InPath" ItemName="PackageOutputFiles" />
|
||||
</FindUnderPath>
|
||||
<FindUnderPath Files="@(FileWrites->'%(FullPath)')" Path="$(OutDir)">
|
||||
<Output TaskParameter="InPath" ItemName="PackageOutputFiles" />
|
||||
</FindUnderPath>
|
||||
<FindUnderPath Files="@(FileWritesShareable->'%(FullPath)')" Path="$(OutDir)">
|
||||
<Output TaskParameter="InPath" ItemName="PackageOutputFiles" />
|
||||
</FindUnderPath>
|
||||
<RemoveDuplicates Inputs="@(PackageOutputFiles)">
|
||||
<Output TaskParameter="Filtered" ItemName="FilteredPackageOutputFiles" />
|
||||
</RemoveDuplicates>
|
||||
<ConvertToRelativePath Paths="@(FilteredPackageOutputFiles)" RelativeTo="$(TargetDir)">
|
||||
<Output TaskParameter="RelativePaths" ItemName="ConfigBinaries" />
|
||||
</ConvertToRelativePath>
|
||||
<Message Text="ConvertToRelativePath Task, TargetDir: $(TargetDir) " Importance="High"/>
|
||||
</Target>
|
||||
<Target Name="PackageArcGISContents" AfterTargets="ArcGISInstallOutput">
|
||||
<Message Text="Running PackageArcGISContents..." Importance="High"/>
|
||||
<RemoveDir Condition="Exists('$(ZipIntermediatePath)')" Directories="$(ZipIntermediatePath)" />
|
||||
<Message Text="ZipIntermediatePath: $(ZipIntermediatePath)Install..." Importance="High"/>
|
||||
<!-- Copy project output files, preserving folder structure -->
|
||||
<Copy SourceFiles="@(ConfigBinaries->'$(OutDir)%(Identity)')" ContinueOnError="true" DestinationFolder="$(IntermediateOutputPath)temp_archive\Install\%(RelativeDir)" />
|
||||
<!-- Copy items marked with Content as BuildAction, preserving folder structure & handling linked items -->
|
||||
<!-- Only include items that have CopyToOutputDirectory as Never -->
|
||||
<Copy SourceFiles="@(Content)" Condition="'%(Content.Link)' == '' And ('%(Content.CopyToOutputDirectory)' == 'Never' Or '%(Content.CopyToOutputDirectory)' == '')" DestinationFolder="$(IntermediateOutputPath)temp_archive\%(RelativeDir)" ContinueOnError="true" />
|
||||
<Copy SourceFiles="@(Content)" Condition="'%(Content.Link)' != '' And ('%(Content.CopyToOutputDirectory)' == 'Never' Or '%(Content.CopyToOutputDirectory)' == '')" DestinationFiles="$(IntermediateOutputPath)temp_archive\%(Content.Link)" ContinueOnError="true"/>
|
||||
<!-- Zipping up add-in resources -->
|
||||
<PackageAddIn ZipIntermediatePath="$(IntermediateOutputPath)temp_archive\"
|
||||
PackageType="$(PackageType)"
|
||||
TargetFolder="$(OutDir)"
|
||||
TargetFileName="$(TargetFileName)"
|
||||
RootNamespace="$(RootNamespace)">
|
||||
<Output TaskParameter="PackageOutputPath" PropertyName="PackageFile" />
|
||||
</PackageAddIn>
|
||||
<!-- Shell out to RegisterAddIn.exe to install the package -->
|
||||
<Message Text="Deploying $(PackageType)..." Importance="High"/>
|
||||
<Message Text="ArcGISFolder Name: $(ArcGISFolder)..." Importance="High"/>
|
||||
<Message Text="Unable to execute RegisterAddIn.exe. ArcGIS Pro is not installed." Importance="High" Condition="'$(ArcGISFolder)' == ''"/>
|
||||
<Message Text="Execute RegisterAddIn.exe "$(PackageFile)" /s..." Importance="High" Condition="'$(ArcGISFolder)' != ''"/>
|
||||
<Exec IgnoreExitCode="true" WorkingDirectory="$(ArcGISFolder)bin" Command="RegisterAddIn.exe "$(PackageFile)" /s" Condition="'$(ArcGISFolder)' != '' AND $(PackageFile) != '' ">
|
||||
<Output TaskParameter="ExitCode" PropertyName="ESRIRegAddinExitCode" />
|
||||
</Exec>
|
||||
<RemoveDir Condition="Exists('$(ZipIntermediatePath)')" Directories="$(ZipIntermediatePath)" />
|
||||
</Target>
|
||||
<Target Name="CleanArcGISContents" AfterTargets="Clean">
|
||||
<CleanAddIn ProjectDir="$(ProjectDir)"
|
||||
AssemblyName="$(AssemblyName)"
|
||||
PackageType="$(PackageType)">
|
||||
<Output TaskParameter="CleanInfo" PropertyName="CleanInfo" />
|
||||
</CleanAddIn>
|
||||
<Message Text="Clean $(PackageType)..." Importance="High"/>
|
||||
<Message Text="Execute RegisterAddIn.exe "$(CleanInfo)" /u..." Importance="High" Condition="'$(ArcGISFolder)' != ''"/>
|
||||
<Message Text="Unable to execute RegisterAddIn.exe. ArcGIS Pro is not installed." Importance="High" Condition="'$(ArcGISFolder)' == ''"/>
|
||||
<Exec IgnoreExitCode="true" WorkingDirectory="$(ArcGISFolder)bin" Command="RegisterAddIn.exe "$(CleanInfo)" /u /s" Condition="'$(ArcGISFolder)' != '' AND $(CleanInfo) != ''">
|
||||
<Output TaskParameter="ExitCode" PropertyName="ESRIRegAddinExitCode" />
|
||||
</Exec>
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,10 @@
|
||||
using Speckle.Connectors.DUI.Models.Card.SendFilter;
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS.Filters;
|
||||
|
||||
public class ArcGISEverythingFilter : EverythingSendFilter
|
||||
{
|
||||
public override List<string> GetObjectIds() => new(); // TODO
|
||||
|
||||
public override bool CheckExpiry(string[] changedObjectIds) => true;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Speckle.Connectors.DUI.Models.Card.SendFilter;
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS.Filters;
|
||||
|
||||
public class ArcGISSelectionFilter : DirectSelectionSendFilter
|
||||
{
|
||||
public override List<string> GetObjectIds() => SelectedObjectIds;
|
||||
|
||||
public override bool CheckExpiry(string[] changedObjectIds) => SelectedObjectIds.Intersect(changedObjectIds).Any();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.IO;
|
||||
using Speckle.Connectors.Utils;
|
||||
using Speckle.Core.Kits;
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS.HostApp;
|
||||
|
||||
//poc: dupe code bewtween connectors
|
||||
public class ArcGISSettings
|
||||
{
|
||||
public ArcGISSettings(HostApplication hostAppInfo, HostAppVersion hostAppVersion)
|
||||
{
|
||||
HostAppInfo = hostAppInfo;
|
||||
HostAppVersion = hostAppVersion;
|
||||
Modules = new[] { new DirectoryInfo(typeof(ArcGISSettings).Assembly.Location).Parent.NotNull().FullName }; //poc: Net6 requires us to use this `location` property rather than ToString, should we use this everywhere?
|
||||
}
|
||||
|
||||
public HostApplication HostAppInfo { get; private set; }
|
||||
public HostAppVersion HostAppVersion { get; private set; }
|
||||
|
||||
public IReadOnlyList<string> Modules { get; private set; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using ArcGIS.Desktop.Framework.Threading.Tasks;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS.HostApp;
|
||||
|
||||
public class SyncToQueuedTask : ISyncToThread
|
||||
{
|
||||
public Task<T> RunOnThread<T>(Func<T> func) => QueuedTask.Run(func);
|
||||
}
|
||||
|
After Width: | Height: | Size: 524 B |
|
After Width: | Height: | Size: 948 B |
|
After Width: | Height: | Size: 714 B |
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,293 @@
|
||||
using System.Diagnostics.Contracts;
|
||||
using ArcGIS.Desktop.Mapping;
|
||||
using Speckle.Connectors.Utils.Builders;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Core.Logging;
|
||||
using Speckle.Core.Models;
|
||||
using Speckle.Converters.ArcGIS3.Utils;
|
||||
using ArcGIS.Core.Geometry;
|
||||
using Objects.GIS;
|
||||
using Speckle.Connectors.Utils.Conversion;
|
||||
using Speckle.Core.Models.GraphTraversal;
|
||||
using Speckle.Converters.ArcGIS3;
|
||||
using RasterLayer = Objects.GIS.RasterLayer;
|
||||
using Speckle.Connectors.ArcGIS.Utils;
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS.Operations.Receive;
|
||||
|
||||
public class ArcGISHostObjectBuilder : IHostObjectBuilder
|
||||
{
|
||||
private readonly IRootToHostConverter _converter;
|
||||
private readonly INonNativeFeaturesUtils _nonGisFeaturesUtils;
|
||||
|
||||
// POC: figure out the correct scope to only initialize on Receive
|
||||
private readonly IConversionContextStack<ArcGISDocument, Unit> _contextStack;
|
||||
private readonly GraphTraversal _traverseFunction;
|
||||
|
||||
public ArcGISHostObjectBuilder(
|
||||
IRootToHostConverter converter,
|
||||
IConversionContextStack<ArcGISDocument, Unit> contextStack,
|
||||
INonNativeFeaturesUtils nonGisFeaturesUtils,
|
||||
GraphTraversal traverseFunction
|
||||
)
|
||||
{
|
||||
_converter = converter;
|
||||
_contextStack = contextStack;
|
||||
_nonGisFeaturesUtils = nonGisFeaturesUtils;
|
||||
_traverseFunction = traverseFunction;
|
||||
}
|
||||
|
||||
public HostObjectBuilderResult Build(
|
||||
Base rootObject,
|
||||
string projectName,
|
||||
string modelName,
|
||||
Action<string, double?>? onOperationProgressed,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
// Prompt the UI conversion started. Progress bar will swoosh.
|
||||
onOperationProgressed?.Invoke("Converting", null);
|
||||
|
||||
var objectsToConvert = _traverseFunction
|
||||
.Traverse(rootObject)
|
||||
.Where(ctx => ctx.Current is not Collection || IsGISType(ctx.Current))
|
||||
.Where(ctx => HasGISParent(ctx) is false)
|
||||
.ToList();
|
||||
|
||||
int allCount = objectsToConvert.Count;
|
||||
int count = 0;
|
||||
Dictionary<TraversalContext, ObjectConversionTracker> conversionTracker = new();
|
||||
|
||||
// 1. convert everything
|
||||
List<ReceiveConversionResult> results = new(objectsToConvert.Count);
|
||||
List<string> bakedObjectIds = new();
|
||||
foreach (TraversalContext ctx in objectsToConvert)
|
||||
{
|
||||
string[] path = GetLayerPath(ctx);
|
||||
Base obj = ctx.Current;
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
try
|
||||
{
|
||||
if (IsGISType(obj))
|
||||
{
|
||||
string nestedLayerPath = $"{string.Join("\\", path)}";
|
||||
string datasetId = (string)_converter.Convert(obj);
|
||||
conversionTracker[ctx] = new ObjectConversionTracker(obj, nestedLayerPath, datasetId);
|
||||
}
|
||||
else
|
||||
{
|
||||
string nestedLayerPath = $"{string.Join("\\", path)}\\{obj.speckle_type.Split(".")[^1]}";
|
||||
Geometry converted = (Geometry)_converter.Convert(obj);
|
||||
conversionTracker[ctx] = new ObjectConversionTracker(obj, nestedLayerPath, converted);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal()) // DO NOT CATCH SPECIFIC STUFF, conversion errors should be recoverable
|
||||
{
|
||||
results.Add(new(Status.ERROR, obj, null, null, ex));
|
||||
}
|
||||
onOperationProgressed?.Invoke("Converting", (double)++count / allCount);
|
||||
}
|
||||
|
||||
// 2. convert Database entries with non-GIS geometry datasets
|
||||
onOperationProgressed?.Invoke("Writing to Database", null);
|
||||
_nonGisFeaturesUtils.WriteGeometriesToDatasets(conversionTracker);
|
||||
|
||||
// Create main group layer
|
||||
Dictionary<string, GroupLayer> createdLayerGroups = new();
|
||||
Map map = _contextStack.Current.Document.Map;
|
||||
GroupLayer groupLayer = LayerFactory.Instance.CreateGroupLayer(map, 0, $"{projectName}: {modelName}");
|
||||
createdLayerGroups["Basic Speckle Group"] = groupLayer; // key doesn't really matter here
|
||||
|
||||
// 3. add layer and tables to the Table Of Content
|
||||
int bakeCount = 0;
|
||||
Dictionary<string, MapMember> bakedMapMembers = new();
|
||||
onOperationProgressed?.Invoke("Adding to Map", bakeCount);
|
||||
|
||||
foreach (var item in conversionTracker)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var trackerItem = conversionTracker[item.Key]; // updated tracker object
|
||||
|
||||
// BAKE OBJECTS HERE
|
||||
if (trackerItem.Exception != null)
|
||||
{
|
||||
results.Add(new(Status.ERROR, trackerItem.Base, null, null, trackerItem.Exception));
|
||||
}
|
||||
else if (trackerItem.DatasetId == null)
|
||||
{
|
||||
results.Add(
|
||||
new(
|
||||
Status.ERROR,
|
||||
trackerItem.Base,
|
||||
null,
|
||||
null,
|
||||
new ArgumentException($"Unknown error: Dataset not created for {trackerItem.Base.speckle_type}")
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (bakedMapMembers.TryGetValue(trackerItem.DatasetId, out MapMember? value))
|
||||
{
|
||||
// add layer and layer URI to tracker
|
||||
trackerItem.AddConvertedMapMember(value);
|
||||
trackerItem.AddLayerURI(value.URI);
|
||||
conversionTracker[item.Key] = trackerItem; // not necessary atm, but needed if we use conversionTracker further
|
||||
// only add a report item
|
||||
AddResultsFromTracker(trackerItem, results);
|
||||
}
|
||||
else
|
||||
{
|
||||
// add layer to Map
|
||||
MapMember mapMember = AddDatasetsToMap(trackerItem, createdLayerGroups);
|
||||
|
||||
// add layer and layer URI to tracker
|
||||
trackerItem.AddConvertedMapMember(mapMember);
|
||||
trackerItem.AddLayerURI(mapMember.URI);
|
||||
conversionTracker[item.Key] = trackerItem; // not necessary atm, but needed if we use conversionTracker further
|
||||
|
||||
// add layer URI to bakedIds
|
||||
bakedObjectIds.Add(trackerItem.MappedLayerURI == null ? "" : trackerItem.MappedLayerURI);
|
||||
|
||||
// mark dataset as already created
|
||||
bakedMapMembers[trackerItem.DatasetId] = mapMember;
|
||||
|
||||
// add report item
|
||||
AddResultsFromTracker(trackerItem, results);
|
||||
}
|
||||
onOperationProgressed?.Invoke("Adding to Map", (double)++bakeCount / conversionTracker.Count);
|
||||
}
|
||||
bakedObjectIds.AddRange(createdLayerGroups.Values.Select(x => x.URI));
|
||||
|
||||
// TODO: validated a correct set regarding bakedobject ids
|
||||
return new(bakedObjectIds, results);
|
||||
}
|
||||
|
||||
private void AddResultsFromTracker(ObjectConversionTracker trackerItem, List<ReceiveConversionResult> results)
|
||||
{
|
||||
if (trackerItem.MappedLayerURI == null) // should not happen
|
||||
{
|
||||
results.Add(
|
||||
new(
|
||||
Status.ERROR,
|
||||
trackerItem.Base,
|
||||
null,
|
||||
null,
|
||||
new ArgumentException($"Created Layer URI not found for {trackerItem.Base.speckle_type}")
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// encode layer ID and ID of its feature in 1 object represented as string
|
||||
ObjectID objectId = new(trackerItem.MappedLayerURI, trackerItem.DatasetRow);
|
||||
if (trackerItem.HostAppGeom != null) // individual hostAppGeometry
|
||||
{
|
||||
results.Add(
|
||||
new(
|
||||
Status.SUCCESS,
|
||||
trackerItem.Base,
|
||||
objectId.ObjectIdToString(),
|
||||
trackerItem.HostAppGeom.GetType().ToString()
|
||||
)
|
||||
);
|
||||
}
|
||||
else // hostApp Layers
|
||||
{
|
||||
results.Add(
|
||||
new(
|
||||
Status.SUCCESS,
|
||||
trackerItem.Base,
|
||||
objectId.ObjectIdToString(),
|
||||
trackerItem.HostAppMapMember?.GetType().ToString()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private MapMember AddDatasetsToMap(
|
||||
ObjectConversionTracker trackerItem,
|
||||
Dictionary<string, GroupLayer> createdLayerGroups
|
||||
)
|
||||
{
|
||||
// get layer details
|
||||
string? datasetId = trackerItem.DatasetId; // should not ne null here
|
||||
Uri uri = new($"{_contextStack.Current.Document.SpeckleDatabasePath.AbsolutePath.Replace('/', '\\')}\\{datasetId}");
|
||||
string nestedLayerName = trackerItem.NestedLayerName;
|
||||
|
||||
// add group for the current layer
|
||||
string shortName = nestedLayerName.Split("\\")[^1];
|
||||
string nestedLayerPath = string.Join("\\", nestedLayerName.Split("\\").SkipLast(1));
|
||||
|
||||
GroupLayer groupLayer = CreateNestedGroupLayer(nestedLayerPath, createdLayerGroups);
|
||||
|
||||
// Most of the Speckle-written datasets will be containing geometry and added as Layers
|
||||
// although, some datasets might be just tables (e.g. native GIS Tables, in the future maybe Revit schedules etc.
|
||||
// We can create a connection to the dataset in advance and determine its type, but this will be more
|
||||
// expensive, than assuming by default that it's a layer with geometry (which in most cases it's expected to be)
|
||||
try
|
||||
{
|
||||
var layer = LayerFactory.Instance.CreateLayer(uri, groupLayer, layerName: shortName);
|
||||
layer.SetExpanded(true);
|
||||
return layer;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
var table = StandaloneTableFactory.Instance.CreateStandaloneTable(uri, groupLayer, tableName: shortName);
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
||||
private GroupLayer CreateNestedGroupLayer(string nestedLayerPath, Dictionary<string, GroupLayer> createdLayerGroups)
|
||||
{
|
||||
GroupLayer lastGroup = createdLayerGroups.FirstOrDefault().Value;
|
||||
if (lastGroup == null) // if layer not found
|
||||
{
|
||||
throw new InvalidOperationException("Speckle Layer Group not found");
|
||||
}
|
||||
|
||||
// iterate through each nested level
|
||||
string createdGroupPath = "";
|
||||
var allPathElements = nestedLayerPath.Split("\\").Where(x => !string.IsNullOrEmpty(x));
|
||||
foreach (string pathElement in allPathElements)
|
||||
{
|
||||
createdGroupPath += "\\" + pathElement;
|
||||
if (createdLayerGroups.TryGetValue(createdGroupPath, out var existingGroupLayer))
|
||||
{
|
||||
lastGroup = existingGroupLayer;
|
||||
}
|
||||
else
|
||||
{
|
||||
// create new GroupLayer under last found Group, named with last pathElement
|
||||
lastGroup = LayerFactory.Instance.CreateGroupLayer(lastGroup, 0, pathElement);
|
||||
lastGroup.SetExpanded(true);
|
||||
}
|
||||
createdLayerGroups[createdGroupPath] = lastGroup;
|
||||
}
|
||||
return lastGroup;
|
||||
}
|
||||
|
||||
[Pure]
|
||||
private static string[] GetLayerPath(TraversalContext context)
|
||||
{
|
||||
string[] collectionBasedPath = context.GetAscendantOfType<Collection>().Select(c => c.name).ToArray();
|
||||
string[] reverseOrderPath =
|
||||
collectionBasedPath.Length != 0 ? collectionBasedPath : context.GetPropertyPath().ToArray();
|
||||
|
||||
var originalPath = reverseOrderPath.Reverse().ToArray();
|
||||
return originalPath.Where(x => !string.IsNullOrEmpty(x)).ToArray();
|
||||
}
|
||||
|
||||
[Pure]
|
||||
private static bool HasGISParent(TraversalContext context)
|
||||
{
|
||||
List<Base> gisLayers = context.GetAscendants().Where(IsGISType).Where(obj => obj != context.Current).ToList();
|
||||
return gisLayers.Count > 0;
|
||||
}
|
||||
|
||||
[Pure]
|
||||
private static bool IsGISType(Base obj)
|
||||
{
|
||||
return obj is RasterLayer or VectorLayer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using System.Diagnostics;
|
||||
using ArcGIS.Desktop.Mapping;
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using Speckle.Connectors.Utils.Builders;
|
||||
using Speckle.Connectors.Utils.Caching;
|
||||
using Speckle.Connectors.Utils.Conversion;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Core.Logging;
|
||||
using Speckle.Core.Models;
|
||||
|
||||
namespace Speckle.Connectors.ArcGis.Operations.Send;
|
||||
|
||||
/// <summary>
|
||||
/// Stateless builder object to turn an ISendFilter into a <see cref="Base"/> object
|
||||
/// </summary>
|
||||
public class ArcGISRootObjectBuilder : IRootObjectBuilder<MapMember>
|
||||
{
|
||||
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
|
||||
private readonly ISendConversionCache _sendConversionCache;
|
||||
|
||||
public ArcGISRootObjectBuilder(IUnitOfWorkFactory unitOfWorkFactory, ISendConversionCache sendConversionCache)
|
||||
{
|
||||
_unitOfWorkFactory = unitOfWorkFactory;
|
||||
_sendConversionCache = sendConversionCache;
|
||||
}
|
||||
|
||||
public RootObjectBuilderResult Build(
|
||||
IReadOnlyList<MapMember> objects,
|
||||
SendInfo sendInfo,
|
||||
Action<string, double?>? onOperationProgressed = null,
|
||||
CancellationToken ct = default
|
||||
)
|
||||
{
|
||||
// POC: does this feel like the right place? I am wondering if this should be called from within send/rcv?
|
||||
// begin the unit of work
|
||||
using var uow = _unitOfWorkFactory.Resolve<IRootToSpeckleConverter>();
|
||||
var converter = uow.Service;
|
||||
|
||||
int count = 0;
|
||||
|
||||
Collection rootObjectCollection = new(); //TODO: Collections
|
||||
|
||||
List<SendConversionResult> results = new(objects.Count);
|
||||
var cacheHitCount = 0;
|
||||
|
||||
foreach (MapMember mapMember in objects)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
var collectionHost = rootObjectCollection;
|
||||
var applicationId = mapMember.URI;
|
||||
|
||||
try
|
||||
{
|
||||
Base converted;
|
||||
if (_sendConversionCache.TryGetValue(sendInfo.ProjectId, applicationId, out ObjectReference value))
|
||||
{
|
||||
converted = value;
|
||||
cacheHitCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
converted = converter.Convert(mapMember);
|
||||
converted.applicationId = applicationId;
|
||||
}
|
||||
|
||||
// add to host
|
||||
collectionHost.elements.Add(converted);
|
||||
results.Add(new(Status.SUCCESS, applicationId, mapMember.GetType().Name, converted));
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
results.Add(new(Status.ERROR, applicationId, mapMember.GetType().Name, null, ex));
|
||||
// POC: add logging
|
||||
}
|
||||
|
||||
onOperationProgressed?.Invoke("Converting", (double)++count / objects.Count);
|
||||
}
|
||||
|
||||
// POC: Log would be nice, or can be removed.
|
||||
Debug.WriteLine(
|
||||
$"Cache hit count {cacheHitCount} out of {objects.Count} ({(double)cacheHitCount / objects.Count})"
|
||||
);
|
||||
|
||||
return new(rootObjectCollection, results);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Speckle.Connectors.ArcGIS3": {
|
||||
"commandName": "Executable",
|
||||
"executablePath": "C:\\Program Files\\ArcGIS\\Pro\\bin\\ArcGISPro.exe",
|
||||
"commandLineArgs": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<RootNameSpace>Speckle.Connectors.ArcGIS</RootNameSpace>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Config.daml"/>
|
||||
<Content Include="Images\s2logo_16.png"/>
|
||||
<Content Include="Images\s2logo_32.png"/>
|
||||
<Content Include="DarkImages\s2logo_16.png"/>
|
||||
<Content Include="DarkImages\s2logo_32.png"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Esri.ArcGISPro.Extensions30" IncludeAssets="compile"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference
|
||||
Include="..\..\..\Converters\ArcGIS\Speckle.Converters.ArcGIS3.DependencyInjection\Speckle.Converters.ArcGIS3.DependencyInjection.csproj"/>
|
||||
<ProjectReference
|
||||
Include="..\..\..\DUI3\Speckle.Connectors.DUI.WebView\Speckle.Connectors.DUI.WebView.csproj"/>
|
||||
<ProjectReference
|
||||
Include="..\..\..\Sdk\Speckle.Connectors.Utils\Speckle.Connectors.Utils.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="Esri.ArcGISPro.Extensions30.Speckle.targets"/>
|
||||
</Project>
|
||||
@@ -0,0 +1,42 @@
|
||||
using ArcGIS.Desktop.Framework;
|
||||
using ArcGIS.Desktop.Framework.Contracts;
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS;
|
||||
|
||||
internal sealed class SpeckleDUI3ViewModel : DockPane
|
||||
{
|
||||
private const string DOCKPANE_ID = "SpeckleDUI3_SpeckleDUI3";
|
||||
|
||||
internal static void Create()
|
||||
{
|
||||
var pane = FrameworkApplication.DockPaneManager.Find(DOCKPANE_ID);
|
||||
pane?.Activate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the pane is initialized.
|
||||
/// </summary>
|
||||
protected override async Task InitializeAsync()
|
||||
{
|
||||
await base.InitializeAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the pane is uninitialized.
|
||||
/// </summary>
|
||||
protected override async Task UninitializeAsync()
|
||||
{
|
||||
await base.UninitializeAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Button implementation to create a new instance of the pane and activate it.
|
||||
/// </summary>
|
||||
internal sealed class SpeckleDUI3OpenButton : Button
|
||||
{
|
||||
protected override void OnClick()
|
||||
{
|
||||
SpeckleDUI3ViewModel.Create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System.Windows.Controls;
|
||||
using Speckle.Connectors.DUI.WebView;
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS;
|
||||
|
||||
public class SpeckleDUI3Wrapper : UserControl
|
||||
{
|
||||
public SpeckleDUI3Wrapper()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
Content = SpeckleModule.Current.Container.Resolve<DUI3ControlWebView>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Reflection;
|
||||
using ArcGIS.Desktop.Framework;
|
||||
using Speckle.Autofac;
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using Speckle.Connectors.ArcGIS.HostApp;
|
||||
using Speckle.Core.Kits;
|
||||
using Module = ArcGIS.Desktop.Framework.Contracts.Module;
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS;
|
||||
|
||||
/// <summary>
|
||||
/// This sample shows how to implement pane that contains an Edge WebView2 control using the built-in ArcGIS Pro SDK's WebBrowser control. For details on how to utilize the WebBrowser control in an add-in see here: https://github.com/Esri/arcgis-pro-sdk/wiki/ProConcepts-Framework#webbrowser For details on how to utilize the Microsoft Edge web browser control in an add-in see here: https://github.com/Esri/arcgis-pro-sdk/wiki/ProConcepts-Framework#webbrowser-control
|
||||
/// </summary>
|
||||
internal sealed class SpeckleModule : Module
|
||||
{
|
||||
private static SpeckleModule? s_this;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the singleton instance to this module here
|
||||
/// </summary>
|
||||
public static SpeckleModule Current =>
|
||||
s_this ??= (SpeckleModule)FrameworkApplication.FindModule("ConnectorArcGIS_Module");
|
||||
|
||||
public SpeckleContainer Container { get; }
|
||||
|
||||
public SpeckleModule()
|
||||
{
|
||||
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolver.OnAssemblyResolve<SpeckleModule>;
|
||||
|
||||
var builder = SpeckleContainerBuilder.CreateInstance();
|
||||
|
||||
// Register Settings
|
||||
var arcgisSettings = new ArcGISSettings(HostApplications.ArcGIS, HostAppVersion.v3);
|
||||
|
||||
Container = builder
|
||||
.LoadAutofacModules(Assembly.GetExecutingAssembly(), arcgisSettings.Modules)
|
||||
.AddSingleton(arcgisSettings)
|
||||
.Build();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by Framework when ArcGIS Pro is closing
|
||||
/// </summary>
|
||||
/// <returns>False to prevent Pro from closing, otherwise True</returns>
|
||||
protected override bool CanUnload()
|
||||
{
|
||||
//TODO - add your business logic
|
||||
//return false to ~cancel~ Application close
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
using System.Xml.Linq;
|
||||
using ArcGIS.Desktop.Core.Events;
|
||||
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;
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS.Utils;
|
||||
|
||||
public class ArcGISDocumentStore : DocumentModelStore
|
||||
{
|
||||
public ArcGISDocumentStore(
|
||||
JsonSerializerSettings serializerOption,
|
||||
ITopLevelExceptionHandler topLevelExceptionHandler
|
||||
)
|
||||
: base(serializerOption, true)
|
||||
{
|
||||
ActiveMapViewChangedEvent.Subscribe(a => topLevelExceptionHandler.CatchUnhandled(() => OnMapViewChanged(a)), true);
|
||||
ProjectSavingEvent.Subscribe(
|
||||
_ =>
|
||||
{
|
||||
topLevelExceptionHandler.CatchUnhandled(OnProjectSaving);
|
||||
return Task.CompletedTask;
|
||||
},
|
||||
true
|
||||
);
|
||||
ProjectClosingEvent.Subscribe(
|
||||
_ =>
|
||||
{
|
||||
topLevelExceptionHandler.CatchUnhandled(OnProjectClosing);
|
||||
return Task.CompletedTask;
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
// in case plugin was loaded into already opened Map, read metadata from the current Map
|
||||
if (IsDocumentInit == false && MapView.Active != null)
|
||||
{
|
||||
IsDocumentInit = true;
|
||||
ReadFromFile();
|
||||
OnDocumentChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnProjectClosing()
|
||||
{
|
||||
if (MapView.Active is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WriteToFile();
|
||||
}
|
||||
|
||||
private void OnProjectSaving()
|
||||
{
|
||||
if (MapView.Active is not null)
|
||||
{
|
||||
WriteToFile();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// On map view switch, this event trigger twice, first for outgoing view, second for incoming view.
|
||||
/// </summary>
|
||||
private void OnMapViewChanged(ActiveMapViewChangedEventArgs args)
|
||||
{
|
||||
if (args.IncomingView is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IsDocumentInit = true;
|
||||
ReadFromFile();
|
||||
OnDocumentChanged();
|
||||
}
|
||||
|
||||
public override void WriteToFile()
|
||||
{
|
||||
Map map = MapView.Active.Map;
|
||||
QueuedTask.Run(() =>
|
||||
{
|
||||
// Read existing metadata - To prevent messing existing metadata. 🤞 Hope other add-in developers will do same :D
|
||||
var existingMetadata = map.GetMetadata();
|
||||
|
||||
// Parse existing metadata
|
||||
XDocument existingXmlDocument = !string.IsNullOrEmpty(existingMetadata)
|
||||
? XDocument.Parse(existingMetadata)
|
||||
: new XDocument(new XElement("metadata"));
|
||||
|
||||
string serializedModels = Serialize();
|
||||
|
||||
XElement xmlModelCards = new("SpeckleModelCards", serializedModels);
|
||||
|
||||
// Check if SpeckleModelCards element already exists at root and update it
|
||||
var speckleModelCardsElement = existingXmlDocument.Root?.Element("SpeckleModelCards");
|
||||
if (speckleModelCardsElement != null)
|
||||
{
|
||||
speckleModelCardsElement.ReplaceWith(xmlModelCards);
|
||||
}
|
||||
else
|
||||
{
|
||||
existingXmlDocument.Root?.Add(xmlModelCards);
|
||||
}
|
||||
|
||||
map.SetMetadata(existingXmlDocument.ToString());
|
||||
});
|
||||
}
|
||||
|
||||
public override void ReadFromFile()
|
||||
{
|
||||
Map map = MapView.Active.Map;
|
||||
QueuedTask.Run(() =>
|
||||
{
|
||||
var metadata = map.GetMetadata();
|
||||
var root = XDocument.Parse(metadata).Root;
|
||||
var element = root?.Element("SpeckleModelCards");
|
||||
if (element is null)
|
||||
{
|
||||
Models = new();
|
||||
return;
|
||||
}
|
||||
|
||||
string modelsString = element.Value;
|
||||
Models = Deserialize(modelsString).NotNull();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using ArcGIS.Desktop.Mapping;
|
||||
|
||||
namespace Speckle.Connectors.ArcGIS.Utils;
|
||||
|
||||
// bind together a layer object on the map, and auto-assigned ID if the specific feature
|
||||
public readonly struct MapMemberFeature
|
||||
{
|
||||
public int? FeatureId { get; } // unique feature id (start from 0) of a feature in the layer
|
||||
public MapMember MapMember { get; } // layer object on the Map
|
||||
|
||||
public MapMemberFeature(MapMember mapMember, int? featureId)
|
||||
{
|
||||
MapMember = mapMember;
|
||||
FeatureId = featureId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
namespace Speckle.Connectors.ArcGIS.Utils;
|
||||
|
||||
// this struct is needed to be able to parse single-string value into IDs of both a layer, and it's individual feature
|
||||
public struct ObjectID
|
||||
{
|
||||
private const string FEATURE_ID_SEPARATOR = "__speckleFeatureId__";
|
||||
public string MappedLayerURI { get; } // unique ID of the layer on the map
|
||||
public int? FeatureId { get; } // unique feature id (start from 0) of a feature in the layer
|
||||
|
||||
public ObjectID(string encodedId)
|
||||
{
|
||||
List<string> stringParts = encodedId.Split(FEATURE_ID_SEPARATOR).ToList();
|
||||
MappedLayerURI = stringParts[0];
|
||||
FeatureId = null;
|
||||
if (stringParts.Count > 1)
|
||||
{
|
||||
FeatureId = Convert.ToInt32(stringParts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectID(string layerId, int? featureId)
|
||||
{
|
||||
MappedLayerURI = layerId;
|
||||
FeatureId = featureId;
|
||||
}
|
||||
|
||||
public readonly string ObjectIdToString()
|
||||
{
|
||||
if (FeatureId == null)
|
||||
{
|
||||
return $"{MappedLayerURI}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{MappedLayerURI}{FEATURE_ID_SEPARATOR}{FeatureId}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,510 @@
|
||||
{
|
||||
"version": 2,
|
||||
"dependencies": {
|
||||
"net6.0-windows7.0": {
|
||||
"Esri.ArcGISPro.Extensions30": {
|
||||
"type": "Direct",
|
||||
"requested": "[3.2.0.49743, )",
|
||||
"resolved": "3.2.0.49743",
|
||||
"contentHash": "fmnYm+mD14Cz0Uqh1ij37SfLJerkyFHK5581y5tXT/l3H2ZvUmVuuxjYquXzyzj9p7IexQzMW4xCpxe+mD922g=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging.Abstractions": {
|
||||
"type": "Direct",
|
||||
"requested": "[7.0.0, )",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw=="
|
||||
},
|
||||
"Microsoft.SourceLink.GitHub": {
|
||||
"type": "Direct",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Build.Tasks.Git": "8.0.0",
|
||||
"Microsoft.SourceLink.Common": "8.0.0"
|
||||
}
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.14.1, )",
|
||||
"resolved": "1.14.1",
|
||||
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
|
||||
},
|
||||
"Speckle.InterfaceGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[0.9.5, )",
|
||||
"resolved": "0.9.5",
|
||||
"contentHash": "oU/L7pN1R7q8KkbrpQ3WJnHirPHqn+9DEA7asOcUiggV5dzVg1A/VYs7GOSusD24njxXh03tE3a2oTLOjt3cVg=="
|
||||
},
|
||||
"GraphQL.Client": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client.Abstractions": "6.0.0",
|
||||
"GraphQL.Client.Abstractions.Websocket": "6.0.0",
|
||||
"System.Reactive": "5.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Client.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Primitives": "6.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Client.Abstractions.Websocket": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client.Abstractions": "6.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA=="
|
||||
},
|
||||
"Microsoft.AspNetCore.Http": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.2",
|
||||
"contentHash": "BAibpoItxI5puk7YJbIGj95arZueM8B8M5xT1fXBn3hb3L2G3ucrZcYXv1gXdaroLbntUs8qeV8iuBrpjQsrKw==",
|
||||
"dependencies": {
|
||||
"Microsoft.AspNetCore.Http.Abstractions": "2.2.0",
|
||||
"Microsoft.AspNetCore.WebUtilities": "2.2.0",
|
||||
"Microsoft.Extensions.ObjectPool": "2.2.0",
|
||||
"Microsoft.Extensions.Options": "2.2.0",
|
||||
"Microsoft.Net.Http.Headers": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.AspNetCore.Http.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "Nxs7Z1q3f1STfLYKJSVXCs1iBl+Ya6E8o4Oy1bCxJ/rNI44E/0f6tbsrVqAWfB7jlnJfyaAtIalBVxPKUPQb4Q==",
|
||||
"dependencies": {
|
||||
"Microsoft.AspNetCore.Http.Features": "2.2.0",
|
||||
"System.Text.Encodings.Web": "4.5.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.AspNetCore.Http.Features": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "ziFz5zH8f33En4dX81LW84I6XrYXKf9jg6aM39cM+LffN9KJahViKZ61dGMSO2gd3e+qe5yBRwsesvyqlZaSMg==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Primitives": "2.2.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.AspNetCore.WebUtilities": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "9ErxAAKaDzxXASB/b5uLEkLgUWv1QbeVxyJYEHQwMaxXOeFFVkQxiq8RyfVcifLU7NR0QY0p3acqx4ZpYfhHDg==",
|
||||
"dependencies": {
|
||||
"Microsoft.Net.Http.Headers": "2.2.0",
|
||||
"System.Text.Encodings.Web": "4.5.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Build.Tasks.Git": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
|
||||
},
|
||||
"Microsoft.CSharp": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.7.0",
|
||||
"contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA=="
|
||||
},
|
||||
"Microsoft.Data.Sqlite": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.5",
|
||||
"contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Data.Sqlite.Core": "7.0.5",
|
||||
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Data.Sqlite.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.5",
|
||||
"contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.core": "2.1.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "elNeOmkeX3eDVG6pYVeV82p29hr+UKDaBhrZyWvWLw/EVZSYEkZlQdkp0V39k/Xehs2Qa0mvoCvkVj3eQxNQ1Q==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw=="
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "Nw2muoNrOG5U5qa2ZekXwudUn2BJcD41e65zwmDHb1fQegTX66UokLWZkJRpqSSHXDOWZ5V0iqhbxOEky91atA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "7.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "7.0.0",
|
||||
"Microsoft.Extensions.Options": "7.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.ObjectPool": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "gA8H7uQOnM5gb+L0uTNjViHYr+hRDqCdfugheGo/MxQnuHzmhhzCBTIPm19qL1z1Xe0NEMabfcOBGv9QghlZ8g=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
|
||||
"Microsoft.Extensions.Primitives": "7.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q==",
|
||||
"dependencies": {
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Net.Http.Headers": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "iZNkjYqlo8sIOI0bQfpsSoMTmB/kyvmV2h225ihyZT33aTp48ZpF6qYnXxzSXmHt8DpBAwBTX+1s1UFLbYfZKg==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Primitives": "2.2.0",
|
||||
"System.Buffers": "4.5.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.SourceLink.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
|
||||
},
|
||||
"Polly": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.2.3",
|
||||
"contentHash": "DeCY0OFbNdNxsjntr1gTXHJ5pKUwYzp04Er2LLeN3g6pWhffsGuKVfMBLe1lw7x76HrPkLxKEFxBlpRxS2nDEQ=="
|
||||
},
|
||||
"Polly.Contrib.WaitAndRetry": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.1.1",
|
||||
"contentHash": "1MUQLiSo4KDkQe6nzQRhIU05lm9jlexX5BVsbuw0SL82ynZ+GzAHQxJVDPVBboxV37Po3SG077aX8DuSy8TkaA=="
|
||||
},
|
||||
"Polly.Extensions.Http": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.0.0",
|
||||
"contentHash": "drrG+hB3pYFY7w1c3BD+lSGYvH2oIclH8GRSehgfyP5kjnFnHKQuuBhuHLv+PWyFuaTDyk/vfRpnxOzd11+J8g==",
|
||||
"dependencies": {
|
||||
"Polly": "7.1.0"
|
||||
}
|
||||
},
|
||||
"Sentry": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.33.0",
|
||||
"contentHash": "8vbD2o6IR2wrRrkSiRbnodWGWUOqIlwYtzpjvPNOb5raJdOf+zxMwfS8f6nx9bmrTTfDj7KrCB8C/5OuicAc8A=="
|
||||
},
|
||||
"Sentry.Serilog": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.33.0",
|
||||
"contentHash": "V8BU7QGWg2qLYfNPqtuTBhC1opysny5l+Ifp6J6PhOeAxU0FssR7nYfbJVetrnLIoh2rd3DlJ6hHYYQosQYcUQ==",
|
||||
"dependencies": {
|
||||
"Sentry": "3.33.0",
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"Serilog": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.12.0",
|
||||
"contentHash": "xaiJLIdu6rYMKfQMYUZgTy8YK7SMZjB4Yk50C/u//Z4OsvxkUfSPJy4nknfvwAC34yr13q7kcyh4grbwhSxyZg=="
|
||||
},
|
||||
"Serilog.Enrichers.ClientInfo": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "mTc7PM+wC9Hr7LWSwqt5mmnlAr7RJs+eTb3PGPRhwdOackk95MkhUZognuxXEdlW19HAFNmEBTSBY5DfLwM8jQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.AspNetCore.Http": "2.2.2",
|
||||
"Serilog": "2.9.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Exceptions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.4.0",
|
||||
"contentHash": "nc/+hUw3lsdo0zCj0KMIybAu7perMx79vu72w0za9Nsi6mWyNkGXxYxakAjWB7nEmYL6zdmhEQRB4oJ2ALUeug==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.8.0",
|
||||
"System.Reflection.TypeExtensions": "4.7.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Formatting.Compact": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.1.0",
|
||||
"contentHash": "pNroKVjo+rDqlxNG5PXkRLpfSCuDOBY0ri6jp9PLe505ljqwhwZz8ospy2vWhQlFu5GkIesh3FcDs4n7sWZODA==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.8.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.Console": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.1.0",
|
||||
"contentHash": "K6N5q+5fetjnJPvCmkWOpJ/V8IEIoMIB1s86OzBrbxwTyHxdx3pmz4H+8+O/Dc/ftUX12DM1aynx/dDowkwzqg==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.File": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.PeriodicBatching": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.1.0",
|
||||
"contentHash": "NDWR7m3PalVlGEq3rzoktrXikjFMLmpwF0HI4sowo8YDdU+gqPlTHlDQiOGxHfB0sTfjPA9JjA7ctKG9zqjGkw==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.0.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.Seq": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.2.2",
|
||||
"contentHash": "1Csmo5ua7NKUe0yXUx+zsRefjAniPWcXFhUXxXG8pwo0iMiw2gjn9SOkgYnnxbgWqmlGv236w0N/dHc2v5XwMg==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.12.0",
|
||||
"Serilog.Formatting.Compact": "1.1.0",
|
||||
"Serilog.Sinks.File": "5.0.0",
|
||||
"Serilog.Sinks.PeriodicBatching": "3.1.0"
|
||||
}
|
||||
},
|
||||
"SerilogTimings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.0.1",
|
||||
"contentHash": "Zs28eTgszAMwpIrbBnWHBI50yuxL50p/dmAUWmy75+axdZYK/Sjm5/5m1N/CisR8acJUhTVcjPZrsB1P5iv0Uw==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"Speckle.Newtonsoft.Json": {
|
||||
"type": "Transitive",
|
||||
"resolved": "13.0.2",
|
||||
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
|
||||
},
|
||||
"SQLitePCLRaw.bundle_e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.lib.e_sqlite3": "2.1.4",
|
||||
"SQLitePCLRaw.provider.e_sqlite3": "2.1.4"
|
||||
}
|
||||
},
|
||||
"SQLitePCLRaw.core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.3"
|
||||
}
|
||||
},
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg=="
|
||||
},
|
||||
"SQLitePCLRaw.provider.e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "CSlb5dUp1FMIkez9Iv5EXzpeq7rHryVNqwJMWnpq87j9zWZexaEMdisDktMsnnrzKM6ahNrsTkjqNodTBPBxtQ==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.core": "2.1.4"
|
||||
}
|
||||
},
|
||||
"System.Buffers": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.0",
|
||||
"contentHash": "pL2ChpaRRWI/p4LXyy4RgeWlYF2sgfj/pnVMvBqwNFr5cXg7CXNnWZWxrOONLg8VGdFB8oB+EG2Qw4MLgTOe+A=="
|
||||
},
|
||||
"System.DoubleNumerics": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.1.3",
|
||||
"contentHash": "KRKEM/L3KBodjA9VOg3EifFVWUY6EOqaMB05UvPEDm7Zeby/kZW+4kdWUEPzW6xtkwf46p661L9NrbeeQhtLzw==",
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.6.1"
|
||||
}
|
||||
},
|
||||
"System.Memory": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.3",
|
||||
"contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA=="
|
||||
},
|
||||
"System.Reactive": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ=="
|
||||
},
|
||||
"System.Reflection.TypeExtensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.7.0",
|
||||
"contentHash": "VybpaOQQhqE6siHppMktjfGBw1GCwvCqiufqmP8F1nj7fTUNtW35LOEt3UZTEsECfo+ELAl/9o9nJx3U91i7vA=="
|
||||
},
|
||||
"System.Runtime.CompilerServices.Unsafe": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
|
||||
},
|
||||
"System.Text.Encodings.Web": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.0",
|
||||
"contentHash": "Xg4G4Indi4dqP1iuAiMSwpiWS54ZghzR644OtsRCm/m/lBMG8dUBhLVN7hLm8NNrNTR+iGbshCPTwrvxZPlm4g=="
|
||||
},
|
||||
"speckle.autofac": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.dui": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )",
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Connectors.Utils": "[2.0.999-local, )",
|
||||
"Speckle.Core": "[3.0.1-alpha.14, )",
|
||||
"System.Threading.Tasks.Dataflow": "[6.0.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.dui.webview": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Web.WebView2": "[1.0.1823.32, )",
|
||||
"Speckle.Connectors.DUI": "[2.0.999-local, )"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.utils": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Serilog.Extensions.Logging": "[7.0.0, )",
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Core": "[3.0.1-alpha.14, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.arcgis3": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Esri.ArcGISPro.Extensions30": "[3.2.0.49743, )",
|
||||
"Speckle.Converters.Common": "[2.0.999-local, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.arcgis3.dependencyinjection": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Autofac": "[5.2.0, )",
|
||||
"Speckle.Converters.ArcGIS3": "[2.0.999-local, )",
|
||||
"Speckle.Converters.Common.DependencyInjection": "[2.0.999-local, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.common": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Objects": "[3.0.1-alpha.14, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.common.dependencyinjection": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Converters.Common": "[2.0.999-local, )"
|
||||
}
|
||||
},
|
||||
"Autofac": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[5.2.0, )",
|
||||
"resolved": "5.2.0",
|
||||
"contentHash": "V8dBH0dsv75uDzl7Sw+HkhKDPUw2eXnlMjcSVMH+tLo2s67MpTKGyDj1pDcpR+IF2u4YRs0s3/x7R88YJzIWvg=="
|
||||
},
|
||||
"Microsoft.Web.WebView2": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.1823.32, )",
|
||||
"resolved": "1.0.1823.32",
|
||||
"contentHash": "ppRcWBUNggFIqyJp7PfgS4Oe8/7yli/mHcTNDOaqo3ZzJWnv9AOr0WE9ceEP5SPs1M7CQ3QvdGMR7KNz0v09EA=="
|
||||
},
|
||||
"Serilog.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[7.0.0, )",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "9faU0zNQqU7I6soVhLUMYaGNpgWv6cKlKb2S5AnS8gXxzW/em5Ladm/6FMrWTnX41cdbdGPOWNAo6adi4WaJ6A==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging": "7.0.0",
|
||||
"Serilog": "2.12.0"
|
||||
}
|
||||
},
|
||||
"Speckle.Core": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.0.1-alpha.14, )",
|
||||
"resolved": "3.0.1-alpha.14",
|
||||
"contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client": "6.0.0",
|
||||
"Microsoft.CSharp": "4.7.0",
|
||||
"Microsoft.Data.Sqlite": "7.0.5",
|
||||
"Polly": "7.2.3",
|
||||
"Polly.Contrib.WaitAndRetry": "1.1.1",
|
||||
"Polly.Extensions.Http": "3.0.0",
|
||||
"Sentry": "3.33.0",
|
||||
"Sentry.Serilog": "3.33.0",
|
||||
"Serilog": "2.12.0",
|
||||
"Serilog.Enrichers.ClientInfo": "1.3.0",
|
||||
"Serilog.Exceptions": "8.4.0",
|
||||
"Serilog.Sinks.Console": "4.1.0",
|
||||
"Serilog.Sinks.Seq": "5.2.2",
|
||||
"SerilogTimings": "3.0.1",
|
||||
"Speckle.Newtonsoft.Json": "13.0.2",
|
||||
"System.DoubleNumerics": "3.1.3"
|
||||
}
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.0.1-alpha.14, )",
|
||||
"resolved": "3.0.1-alpha.14",
|
||||
"contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==",
|
||||
"dependencies": {
|
||||
"Speckle.Core": "3.0.1-alpha.14"
|
||||
}
|
||||
},
|
||||
"System.Threading.Tasks.Dataflow": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[6.0.0, )",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA=="
|
||||
}
|
||||
},
|
||||
"net6.0-windows7.0/win-x64": {
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg=="
|
||||
},
|
||||
"Microsoft.Web.WebView2": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.1823.32, )",
|
||||
"resolved": "1.0.1823.32",
|
||||
"contentHash": "ppRcWBUNggFIqyJp7PfgS4Oe8/7yli/mHcTNDOaqo3ZzJWnv9AOr0WE9ceEP5SPs1M7CQ3QvdGMR7KNz0v09EA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Speckle.Connectors.Autocad</RootNamespace>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseWpf>true</UseWpf>
|
||||
<StartAction>Program</StartAction>
|
||||
<StartProgram>$(ProgramW6432)\Autodesk\AutoCAD 2023\acad.exe</StartProgram>
|
||||
<DefineConstants>$(DefineConstants);AUTOCAD2023;AUTOCAD</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Converters\Autocad\2023\Speckle.Converters.Autocad2023.DependencyInjection\Speckle.Converters.Autocad2023.DependencyInjection.csproj" />
|
||||
<ProjectReference Include="..\..\..\DUI3\Speckle.Connectors.DUI.WebView\Speckle.Connectors.DUI.WebView.csproj" />
|
||||
<ProjectReference Include="..\..\..\Sdk\Speckle.Autofac\Speckle.Autofac.csproj" />
|
||||
<ProjectReference Include="..\..\..\Sdk\Speckle.Connectors.Utils\Speckle.Connectors.Utils.csproj" />
|
||||
<ProjectReference Include="..\..\..\Sdk\Speckle.Converters.Common.DependencyInjection\Speckle.Converters.Common.DependencyInjection.csproj" />
|
||||
<ProjectReference Include="..\..\..\Sdk\Speckle.Converters.Common\Speckle.Converters.Common.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||
<PackageReference Include="Speckle.AutoCAD.API" VersionOverride="2023.0.0" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\Speckle.Connectors.AutocadShared\Speckle.Connectors.AutocadShared.projitems" Label="Shared" />
|
||||
</Project>
|
||||
@@ -0,0 +1,553 @@
|
||||
{
|
||||
"version": 2,
|
||||
"dependencies": {
|
||||
".NETFramework,Version=v4.8": {
|
||||
"Microsoft.Extensions.Logging.Abstractions": {
|
||||
"type": "Direct",
|
||||
"requested": "[7.0.0, )",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Memory": "4.5.5"
|
||||
}
|
||||
},
|
||||
"Microsoft.SourceLink.GitHub": {
|
||||
"type": "Direct",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Build.Tasks.Git": "8.0.0",
|
||||
"Microsoft.SourceLink.Common": "8.0.0"
|
||||
}
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.14.1, )",
|
||||
"resolved": "1.14.1",
|
||||
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
|
||||
},
|
||||
"Speckle.AutoCAD.API": {
|
||||
"type": "Direct",
|
||||
"requested": "[2023.0.0, )",
|
||||
"resolved": "2023.0.0",
|
||||
"contentHash": "aNfiNw9zRW8pCl8AAQK7afEJuea4bJ4sFNsGVSDrdq1egaonZrwALU01dSyFNCE8tne86eVjlprpOGG6r0+G/A=="
|
||||
},
|
||||
"Speckle.InterfaceGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[0.9.5, )",
|
||||
"resolved": "0.9.5",
|
||||
"contentHash": "oU/L7pN1R7q8KkbrpQ3WJnHirPHqn+9DEA7asOcUiggV5dzVg1A/VYs7GOSusD24njxXh03tE3a2oTLOjt3cVg=="
|
||||
},
|
||||
"GraphQL.Client": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client.Abstractions": "6.0.0",
|
||||
"GraphQL.Client.Abstractions.Websocket": "6.0.0",
|
||||
"System.Net.WebSockets.Client.Managed": "1.0.22",
|
||||
"System.Reactive": "5.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Client.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Primitives": "6.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Client.Abstractions.Websocket": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client.Abstractions": "6.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA=="
|
||||
},
|
||||
"Microsoft.Bcl.AsyncInterfaces": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "3aeMZ1N0lJoSyzqiP03hqemtb1BijhsJADdobn/4nsMJ8V1H+CrpuduUe4hlRdx+ikBQju1VGjMD1GJ3Sk05Eg==",
|
||||
"dependencies": {
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Build.Tasks.Git": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
|
||||
},
|
||||
"Microsoft.CSharp": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.7.0",
|
||||
"contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA=="
|
||||
},
|
||||
"Microsoft.Data.Sqlite": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.5",
|
||||
"contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Data.Sqlite.Core": "7.0.5",
|
||||
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Data.Sqlite.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.5",
|
||||
"contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.core": "2.1.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "elNeOmkeX3eDVG6pYVeV82p29hr+UKDaBhrZyWvWLw/EVZSYEkZlQdkp0V39k/Xehs2Qa0mvoCvkVj3eQxNQ1Q==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "7.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "7.0.0",
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "Nw2muoNrOG5U5qa2ZekXwudUn2BJcD41e65zwmDHb1fQegTX66UokLWZkJRpqSSHXDOWZ5V0iqhbxOEky91atA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "7.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection": "7.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "7.0.0",
|
||||
"Microsoft.Extensions.Options": "7.0.0",
|
||||
"System.Diagnostics.DiagnosticSource": "7.0.0",
|
||||
"System.ValueTuple": "4.5.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
|
||||
"Microsoft.Extensions.Primitives": "7.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.5",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.SourceLink.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
|
||||
},
|
||||
"Polly": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.2.3",
|
||||
"contentHash": "DeCY0OFbNdNxsjntr1gTXHJ5pKUwYzp04Er2LLeN3g6pWhffsGuKVfMBLe1lw7x76HrPkLxKEFxBlpRxS2nDEQ=="
|
||||
},
|
||||
"Polly.Contrib.WaitAndRetry": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.1.1",
|
||||
"contentHash": "1MUQLiSo4KDkQe6nzQRhIU05lm9jlexX5BVsbuw0SL82ynZ+GzAHQxJVDPVBboxV37Po3SG077aX8DuSy8TkaA=="
|
||||
},
|
||||
"Polly.Extensions.Http": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.0.0",
|
||||
"contentHash": "drrG+hB3pYFY7w1c3BD+lSGYvH2oIclH8GRSehgfyP5kjnFnHKQuuBhuHLv+PWyFuaTDyk/vfRpnxOzd11+J8g==",
|
||||
"dependencies": {
|
||||
"Polly": "7.1.0"
|
||||
}
|
||||
},
|
||||
"Sentry": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.33.0",
|
||||
"contentHash": "8vbD2o6IR2wrRrkSiRbnodWGWUOqIlwYtzpjvPNOb5raJdOf+zxMwfS8f6nx9bmrTTfDj7KrCB8C/5OuicAc8A==",
|
||||
"dependencies": {
|
||||
"System.Reflection.Metadata": "5.0.0",
|
||||
"System.Runtime.InteropServices.RuntimeInformation": "4.3.0",
|
||||
"System.Text.Json": "5.0.2"
|
||||
}
|
||||
},
|
||||
"Sentry.Serilog": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.33.0",
|
||||
"contentHash": "V8BU7QGWg2qLYfNPqtuTBhC1opysny5l+Ifp6J6PhOeAxU0FssR7nYfbJVetrnLIoh2rd3DlJ6hHYYQosQYcUQ==",
|
||||
"dependencies": {
|
||||
"Sentry": "3.33.0",
|
||||
"Serilog": "2.7.1"
|
||||
}
|
||||
},
|
||||
"Serilog": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.12.0",
|
||||
"contentHash": "xaiJLIdu6rYMKfQMYUZgTy8YK7SMZjB4Yk50C/u//Z4OsvxkUfSPJy4nknfvwAC34yr13q7kcyh4grbwhSxyZg=="
|
||||
},
|
||||
"Serilog.Enrichers.ClientInfo": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "mTc7PM+wC9Hr7LWSwqt5mmnlAr7RJs+eTb3PGPRhwdOackk95MkhUZognuxXEdlW19HAFNmEBTSBY5DfLwM8jQ==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.4.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Exceptions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.4.0",
|
||||
"contentHash": "nc/+hUw3lsdo0zCj0KMIybAu7perMx79vu72w0za9Nsi6mWyNkGXxYxakAjWB7nEmYL6zdmhEQRB4oJ2ALUeug==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.8.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Formatting.Compact": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.1.0",
|
||||
"contentHash": "pNroKVjo+rDqlxNG5PXkRLpfSCuDOBY0ri6jp9PLe505ljqwhwZz8ospy2vWhQlFu5GkIesh3FcDs4n7sWZODA==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.8.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.Console": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.1.0",
|
||||
"contentHash": "K6N5q+5fetjnJPvCmkWOpJ/V8IEIoMIB1s86OzBrbxwTyHxdx3pmz4H+8+O/Dc/ftUX12DM1aynx/dDowkwzqg==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.File": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.PeriodicBatching": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.1.0",
|
||||
"contentHash": "NDWR7m3PalVlGEq3rzoktrXikjFMLmpwF0HI4sowo8YDdU+gqPlTHlDQiOGxHfB0sTfjPA9JjA7ctKG9zqjGkw==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.0.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.Seq": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.2.2",
|
||||
"contentHash": "1Csmo5ua7NKUe0yXUx+zsRefjAniPWcXFhUXxXG8pwo0iMiw2gjn9SOkgYnnxbgWqmlGv236w0N/dHc2v5XwMg==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.12.0",
|
||||
"Serilog.Formatting.Compact": "1.1.0",
|
||||
"Serilog.Sinks.File": "5.0.0",
|
||||
"Serilog.Sinks.PeriodicBatching": "3.1.0"
|
||||
}
|
||||
},
|
||||
"SerilogTimings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.0.1",
|
||||
"contentHash": "Zs28eTgszAMwpIrbBnWHBI50yuxL50p/dmAUWmy75+axdZYK/Sjm5/5m1N/CisR8acJUhTVcjPZrsB1P5iv0Uw==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"Speckle.Newtonsoft.Json": {
|
||||
"type": "Transitive",
|
||||
"resolved": "13.0.2",
|
||||
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
|
||||
},
|
||||
"SQLitePCLRaw.bundle_e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.lib.e_sqlite3": "2.1.4",
|
||||
"SQLitePCLRaw.provider.dynamic_cdecl": "2.1.4"
|
||||
}
|
||||
},
|
||||
"SQLitePCLRaw.core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.3"
|
||||
}
|
||||
},
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg=="
|
||||
},
|
||||
"SQLitePCLRaw.provider.dynamic_cdecl": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "ZsaKKhgYF9B1fvcnOGKl3EycNAwd9CRWX7v0rEfuPWhQQ5Jjpvf2VEHahiLIGHio3hxi3EIKFJw9KvyowWOUAw==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.core": "2.1.4"
|
||||
}
|
||||
},
|
||||
"System.Buffers": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.1",
|
||||
"contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
|
||||
},
|
||||
"System.Collections.Immutable": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.4"
|
||||
}
|
||||
},
|
||||
"System.Diagnostics.DiagnosticSource": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "9W0ewWDuAyDqS2PigdTxk6jDKonfgscY/hP8hm7VpxYhNHZHKvZTdRckberlFk3VnCmr3xBUyMBut12Q+T2aOw==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.5",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
}
|
||||
},
|
||||
"System.DoubleNumerics": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.1.3",
|
||||
"contentHash": "KRKEM/L3KBodjA9VOg3EifFVWUY6EOqaMB05UvPEDm7Zeby/kZW+4kdWUEPzW6xtkwf46p661L9NrbeeQhtLzw==",
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.6.1"
|
||||
}
|
||||
},
|
||||
"System.Memory": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.5",
|
||||
"contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Numerics.Vectors": "4.5.0",
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||
}
|
||||
},
|
||||
"System.Net.WebSockets.Client.Managed": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "WqEOxPlXjuZrIjUtXNE9NxEfU/n5E35iV2PtoZdJSUC4tlrqwHnTee+wvMIM4OUaJWmwrymeqcgYrE0IkGAgLA==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.4.0",
|
||||
"System.Numerics.Vectors": "4.4.0"
|
||||
}
|
||||
},
|
||||
"System.Numerics.Vectors": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.0",
|
||||
"contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ=="
|
||||
},
|
||||
"System.Reactive": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
|
||||
"dependencies": {
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"System.Reflection.Metadata": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ==",
|
||||
"dependencies": {
|
||||
"System.Collections.Immutable": "5.0.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.CompilerServices.Unsafe": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
|
||||
},
|
||||
"System.Runtime.InteropServices.RuntimeInformation": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
"contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw=="
|
||||
},
|
||||
"System.Text.Encodings.Web": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.1",
|
||||
"contentHash": "KmJ+CJXizDofbq6mpqDoRRLcxgOd2z9X3XoFNULSbvbqVRZkFX3istvr+MUjL6Zw1RT+RNdoI4GYidIINtgvqQ==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Memory": "4.5.4"
|
||||
}
|
||||
},
|
||||
"System.Text.Json": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.2",
|
||||
"contentHash": "I47dVIGiV6SfAyppphxqupertT/5oZkYLDCX6vC3HpOI4ZLjyoKAreUoem2ie6G0RbRuFrlqz/PcTQjfb2DOfQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Memory": "4.5.4",
|
||||
"System.Numerics.Vectors": "4.5.0",
|
||||
"System.Runtime.CompilerServices.Unsafe": "5.0.0",
|
||||
"System.Text.Encodings.Web": "5.0.1",
|
||||
"System.Threading.Tasks.Extensions": "4.5.4",
|
||||
"System.ValueTuple": "4.5.0"
|
||||
}
|
||||
},
|
||||
"System.Threading.Tasks.Extensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.4",
|
||||
"contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
|
||||
"dependencies": {
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||
}
|
||||
},
|
||||
"System.ValueTuple": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.0",
|
||||
"contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
|
||||
},
|
||||
"speckle.autofac": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.dui": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )",
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Connectors.Utils": "[2.0.999-local, )",
|
||||
"Speckle.Core": "[3.0.1-alpha.14, )",
|
||||
"System.Threading.Tasks.Dataflow": "[6.0.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.dui.webview": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Web.WebView2": "[1.0.1823.32, )",
|
||||
"Speckle.Connectors.DUI": "[2.0.999-local, )"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.utils": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Serilog.Extensions.Logging": "[7.0.0, )",
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Core": "[3.0.1-alpha.14, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.autocad2023": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Speckle.AutoCAD.API": "[2023.0.0, )",
|
||||
"Speckle.Converters.Common": "[2.0.999-local, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.autocad2023.dependencyinjection": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Autofac": "[5.2.0, )",
|
||||
"Speckle.Converters.Autocad2023": "[2.0.999-local, )",
|
||||
"Speckle.Converters.Common.DependencyInjection": "[2.0.999-local, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.common": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Objects": "[3.0.1-alpha.14, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.common.dependencyinjection": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Converters.Common": "[2.0.999-local, )"
|
||||
}
|
||||
},
|
||||
"Autofac": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[5.2.0, )",
|
||||
"resolved": "5.2.0",
|
||||
"contentHash": "V8dBH0dsv75uDzl7Sw+HkhKDPUw2eXnlMjcSVMH+tLo2s67MpTKGyDj1pDcpR+IF2u4YRs0s3/x7R88YJzIWvg==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "1.1.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Web.WebView2": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.1823.32, )",
|
||||
"resolved": "1.0.1823.32",
|
||||
"contentHash": "ppRcWBUNggFIqyJp7PfgS4Oe8/7yli/mHcTNDOaqo3ZzJWnv9AOr0WE9ceEP5SPs1M7CQ3QvdGMR7KNz0v09EA=="
|
||||
},
|
||||
"Serilog.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[7.0.0, )",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "9faU0zNQqU7I6soVhLUMYaGNpgWv6cKlKb2S5AnS8gXxzW/em5Ladm/6FMrWTnX41cdbdGPOWNAo6adi4WaJ6A==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging": "7.0.0",
|
||||
"Serilog": "2.12.0"
|
||||
}
|
||||
},
|
||||
"Speckle.Core": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.0.1-alpha.14, )",
|
||||
"resolved": "3.0.1-alpha.14",
|
||||
"contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client": "6.0.0",
|
||||
"Microsoft.CSharp": "4.7.0",
|
||||
"Microsoft.Data.Sqlite": "7.0.5",
|
||||
"Polly": "7.2.3",
|
||||
"Polly.Contrib.WaitAndRetry": "1.1.1",
|
||||
"Polly.Extensions.Http": "3.0.0",
|
||||
"Sentry": "3.33.0",
|
||||
"Sentry.Serilog": "3.33.0",
|
||||
"Serilog": "2.12.0",
|
||||
"Serilog.Enrichers.ClientInfo": "1.3.0",
|
||||
"Serilog.Exceptions": "8.4.0",
|
||||
"Serilog.Sinks.Console": "4.1.0",
|
||||
"Serilog.Sinks.Seq": "5.2.2",
|
||||
"SerilogTimings": "3.0.1",
|
||||
"Speckle.Newtonsoft.Json": "13.0.2",
|
||||
"System.DoubleNumerics": "3.1.3"
|
||||
}
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.0.1-alpha.14, )",
|
||||
"resolved": "3.0.1-alpha.14",
|
||||
"contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==",
|
||||
"dependencies": {
|
||||
"Speckle.Core": "3.0.1-alpha.14"
|
||||
}
|
||||
},
|
||||
"System.Threading.Tasks.Dataflow": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[6.0.0, )",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Sentry.Reflection;
|
||||
using Speckle.Connectors.Autocad.HostApp;
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.DUI.Models.Card;
|
||||
using Speckle.Core.Credentials;
|
||||
using Speckle.Connectors.Autocad.HostApp.Extensions;
|
||||
using Speckle.Connectors.Utils;
|
||||
using Speckle.Core.Logging;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.Bindings;
|
||||
|
||||
public class AutocadBasicConnectorBinding : IBasicConnectorBinding
|
||||
{
|
||||
public string Name { get; set; } = "baseBinding";
|
||||
public IBridge Parent { get; }
|
||||
|
||||
private readonly DocumentModelStore _store;
|
||||
private readonly AutocadSettings _settings;
|
||||
|
||||
public BasicConnectorBindingCommands Commands { get; }
|
||||
|
||||
public AutocadBasicConnectorBinding(DocumentModelStore store, AutocadSettings settings, IBridge parent)
|
||||
{
|
||||
_store = store;
|
||||
_settings = settings;
|
||||
Parent = parent;
|
||||
Commands = new BasicConnectorBindingCommands(parent);
|
||||
_store.DocumentChanged += (_, _) =>
|
||||
{
|
||||
Commands.NotifyDocumentChanged();
|
||||
};
|
||||
}
|
||||
|
||||
public string GetConnectorVersion() =>
|
||||
typeof(AutocadBasicConnectorBinding).Assembly.GetNameAndVersion().Version ?? "No version";
|
||||
|
||||
public string GetSourceApplicationName() => _settings.HostAppInfo.Slug;
|
||||
|
||||
public string GetSourceApplicationVersion() => _settings.HostAppVersion.ToString();
|
||||
|
||||
public Account[] GetAccounts() => AccountManager.GetAccounts().ToArray();
|
||||
|
||||
public DocumentInfo? GetDocumentInfo()
|
||||
{
|
||||
// POC: Will be addressed to move it into AutocadContext!
|
||||
var doc = Application.DocumentManager.MdiActiveDocument;
|
||||
if (doc is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string name = doc.Name.Split(System.IO.Path.PathSeparator).Last();
|
||||
return new DocumentInfo(doc.Name, name, doc.GetHashCode().ToString());
|
||||
}
|
||||
|
||||
public DocumentModelStore GetDocumentState() => _store;
|
||||
|
||||
public void AddModel(ModelCard model) => _store.Models.Add(model);
|
||||
|
||||
public void UpdateModel(ModelCard model) => _store.UpdateModel(model);
|
||||
|
||||
public void RemoveModel(ModelCard model) => _store.RemoveModel(model);
|
||||
|
||||
public void HighlightObjects(List<string> objectIds)
|
||||
{
|
||||
// POC: Will be addressed to move it into AutocadContext!
|
||||
var doc = Application.DocumentManager.MdiActiveDocument;
|
||||
|
||||
var dbObjects = doc.GetObjects(objectIds);
|
||||
var acadObjectIds = dbObjects.Select(tuple => tuple.Root.Id).ToArray();
|
||||
HighlightObjectsOnView(acadObjectIds);
|
||||
}
|
||||
|
||||
public void HighlightModel(string modelCardId)
|
||||
{
|
||||
// POC: Will be addressed to move it into AutocadContext!
|
||||
var doc = Application.DocumentManager.MdiActiveDocument;
|
||||
|
||||
if (doc == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var objectIds = Array.Empty<ObjectId>();
|
||||
|
||||
var model = _store.GetModelById(modelCardId);
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (model is SenderModelCard senderModelCard)
|
||||
{
|
||||
var dbObjects = doc.GetObjects(senderModelCard.SendFilter.NotNull().GetObjectIds());
|
||||
objectIds = dbObjects.Select(tuple => tuple.Root.Id).ToArray();
|
||||
}
|
||||
|
||||
if (model is ReceiverModelCard receiverModelCard)
|
||||
{
|
||||
var dbObjects = doc.GetObjects(receiverModelCard.BakedObjectIds.NotNull());
|
||||
objectIds = dbObjects.Select(tuple => tuple.Root.Id).ToArray();
|
||||
}
|
||||
|
||||
if (objectIds.Length == 0)
|
||||
{
|
||||
Commands.SetModelError(modelCardId, new OperationCanceledException("No objects found to highlight."));
|
||||
return;
|
||||
}
|
||||
|
||||
HighlightObjectsOnView(objectIds, modelCardId);
|
||||
}
|
||||
|
||||
private void HighlightObjectsOnView(ObjectId[] objectIds, string? modelCardId = null)
|
||||
{
|
||||
var doc = Application.DocumentManager.MdiActiveDocument;
|
||||
|
||||
Parent.RunOnMainThread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
doc.Editor.SetImpliedSelection(Array.Empty<ObjectId>()); // Deselects
|
||||
doc.Editor.SetImpliedSelection(objectIds); // Selects
|
||||
doc.Editor.UpdateScreen();
|
||||
|
||||
Extents3d selectedExtents = new();
|
||||
|
||||
var tr = doc.TransactionManager.StartTransaction();
|
||||
foreach (ObjectId objectId in objectIds)
|
||||
{
|
||||
var entity = (Entity)tr.GetObject(objectId, OpenMode.ForRead);
|
||||
if (entity != null)
|
||||
{
|
||||
selectedExtents.AddExtents(entity.GeometricExtents);
|
||||
}
|
||||
}
|
||||
|
||||
doc.Editor.Zoom(selectedExtents);
|
||||
tr.Commit();
|
||||
Autodesk.AutoCAD.Internal.Utils.FlushGraphics();
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
if (modelCardId != null)
|
||||
{
|
||||
Commands.SetModelError(modelCardId, new OperationCanceledException("Failed to highlight objects."));
|
||||
}
|
||||
else
|
||||
{
|
||||
// This will happen, in some cases, where we highlight individual objects. Should be caught by the top level handler and not
|
||||
// crash the host app.
|
||||
throw;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.Utils.Cancellation;
|
||||
using Speckle.Connectors.DUI.Models.Card;
|
||||
using Speckle.Connectors.Utils;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.Bindings;
|
||||
|
||||
public sealed class AutocadReceiveBinding : IReceiveBinding
|
||||
{
|
||||
public string Name => "receiveBinding";
|
||||
public IBridge Parent { get; }
|
||||
|
||||
private readonly DocumentModelStore _store;
|
||||
private readonly CancellationManager _cancellationManager;
|
||||
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
|
||||
|
||||
public ReceiveBindingUICommands Commands { get; }
|
||||
|
||||
public AutocadReceiveBinding(
|
||||
DocumentModelStore store,
|
||||
IBridge parent,
|
||||
CancellationManager cancellationManager,
|
||||
IUnitOfWorkFactory unitOfWorkFactory
|
||||
)
|
||||
{
|
||||
_store = store;
|
||||
_cancellationManager = cancellationManager;
|
||||
_unitOfWorkFactory = unitOfWorkFactory;
|
||||
Parent = parent;
|
||||
Commands = new ReceiveBindingUICommands(parent);
|
||||
}
|
||||
|
||||
public void CancelReceive(string modelCardId) => _cancellationManager.CancelOperation(modelCardId);
|
||||
|
||||
public async Task Receive(string modelCardId)
|
||||
{
|
||||
using var unitOfWork = _unitOfWorkFactory.Resolve<ReceiveOperation>();
|
||||
try
|
||||
{
|
||||
// Get receiver card
|
||||
if (_store.GetModelById(modelCardId) is not ReceiverModelCard modelCard)
|
||||
{
|
||||
// Handle as GLOBAL ERROR at BrowserBridge
|
||||
throw new InvalidOperationException("No download model card was found.");
|
||||
}
|
||||
|
||||
// Init cancellation token source -> Manager also cancel it if exist before
|
||||
CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId);
|
||||
|
||||
// Disable document activation (document creation and document switch)
|
||||
// Not disabling results in DUI model card being out of sync with the active document
|
||||
// The DocumentActivated event isn't usable probably because it is pushed to back of main thread queue
|
||||
Application.DocumentManager.DocumentActivationEnabled = false;
|
||||
|
||||
// Receive host objects
|
||||
var operationResults = await unitOfWork.Service
|
||||
.Execute(
|
||||
modelCard.AccountId.NotNull(), // POC: I hear -you are saying why we're passing them separately. Not sure pass the DUI3-> Connectors.DUI project dependency to the SDK-> Connector.Utils
|
||||
modelCard.ProjectId.NotNull(),
|
||||
modelCard.ProjectName.NotNull(),
|
||||
modelCard.ModelName.NotNull(),
|
||||
modelCard.SelectedVersionId.NotNull(),
|
||||
cts.Token,
|
||||
(status, progress) =>
|
||||
Commands.SetModelProgress(modelCardId, new ModelCardProgress(modelCardId, status, progress), cts)
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
Commands.SetModelReceiveResult(modelCardId, operationResults.BakedObjectIds, operationResults.ConversionResults);
|
||||
}
|
||||
// Catch here specific exceptions if they related to model card.
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// SWALLOW -> UI handles it immediately, so we do not need to handle anything
|
||||
return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// renable document activation
|
||||
Application.DocumentManager.DocumentActivationEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Autodesk.AutoCAD.EditorInput;
|
||||
|
||||
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, 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 += (_, e) =>
|
||||
_topLevelExceptionHandler.CatchUnhandled(() => OnDocumentChanged(e.Document));
|
||||
}
|
||||
|
||||
private void OnDocumentChanged(Document? document) => TryRegisterDocumentForSelection(document);
|
||||
|
||||
private void TryRegisterDocumentForSelection(Document? document)
|
||||
{
|
||||
if (document == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_visitedDocuments.Contains(document))
|
||||
{
|
||||
document.ImpliedSelectionChanged += (_, _) =>
|
||||
_topLevelExceptionHandler.CatchUnhandled(() => Parent.RunOnMainThread(OnSelectionChanged));
|
||||
|
||||
_visitedDocuments.Add(document);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSelectionChanged()
|
||||
{
|
||||
SelectionInfo selInfo = GetSelection();
|
||||
Parent.Send(SELECTION_EVENT, selInfo);
|
||||
}
|
||||
|
||||
public SelectionInfo GetSelection()
|
||||
{
|
||||
// POC: Will be addressed to move it into AutocadContext! https://spockle.atlassian.net/browse/CNX-9319
|
||||
Document? doc = Application.DocumentManager.MdiActiveDocument;
|
||||
List<string> objs = new();
|
||||
List<string> objectTypes = new();
|
||||
if (doc != null)
|
||||
{
|
||||
PromptSelectionResult selection = doc.Editor.SelectImplied();
|
||||
if (selection.Status == PromptStatus.OK)
|
||||
{
|
||||
using var tr = doc.TransactionManager.StartTransaction();
|
||||
foreach (SelectedObject obj in selection.Value)
|
||||
{
|
||||
var dbObject = tr.GetObject(obj.ObjectId, OpenMode.ForRead);
|
||||
if (dbObject == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var handleString = dbObject.Handle.Value.ToString();
|
||||
objectTypes.Add(dbObject.GetType().Name);
|
||||
objs.Add(handleString);
|
||||
}
|
||||
|
||||
tr.Commit();
|
||||
}
|
||||
}
|
||||
List<string> flatObjectTypes = objectTypes.Select(o => o).Distinct().ToList();
|
||||
return new SelectionInfo(objs, $"{objs.Count} objects ({string.Join(", ", flatObjectTypes)})");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Speckle.Connectors.Autocad.HostApp;
|
||||
using Speckle.Connectors.Autocad.HostApp.Extensions;
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.DUI.Models.Card;
|
||||
using Speckle.Connectors.Utils.Cancellation;
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using Speckle.Connectors.Autocad.Operations.Send;
|
||||
using Speckle.Connectors.DUI.Exceptions;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
using Speckle.Connectors.DUI.Models.Card.SendFilter;
|
||||
using Speckle.Connectors.Utils;
|
||||
using Speckle.Connectors.Utils.Caching;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.Bindings;
|
||||
|
||||
public sealed class AutocadSendBinding : ISendBinding
|
||||
{
|
||||
public string Name => "sendBinding";
|
||||
public SendBindingUICommands Commands { get; }
|
||||
public IBridge Parent { get; }
|
||||
|
||||
private readonly DocumentModelStore _store;
|
||||
private readonly AutocadIdleManager _idleManager;
|
||||
private readonly List<ISendFilter> _sendFilters;
|
||||
private readonly CancellationManager _cancellationManager;
|
||||
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.
|
||||
/// </summary>
|
||||
private HashSet<string> ChangedObjectIds { get; set; } = new();
|
||||
|
||||
public AutocadSendBinding(
|
||||
DocumentModelStore store,
|
||||
AutocadIdleManager idleManager,
|
||||
IBridge parent,
|
||||
IEnumerable<ISendFilter> sendFilters,
|
||||
CancellationManager cancellationManager,
|
||||
AutocadSettings autocadSettings,
|
||||
IUnitOfWorkFactory unitOfWorkFactory,
|
||||
ISendConversionCache sendConversionCache,
|
||||
ITopLevelExceptionHandler topLevelExceptionHandler
|
||||
)
|
||||
{
|
||||
_store = store;
|
||||
_idleManager = idleManager;
|
||||
_unitOfWorkFactory = unitOfWorkFactory;
|
||||
_autocadSettings = autocadSettings;
|
||||
_cancellationManager = cancellationManager;
|
||||
_sendFilters = sendFilters.ToList();
|
||||
_sendConversionCache = sendConversionCache;
|
||||
_topLevelExceptionHandler = topLevelExceptionHandler;
|
||||
Parent = parent;
|
||||
Commands = new SendBindingUICommands(parent);
|
||||
|
||||
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
|
||||
SubscribeToObjectChanges(Application.DocumentManager.CurrentDocument);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<string> _docSubsTracker = new();
|
||||
|
||||
private void SubscribeToObjectChanges(Document doc)
|
||||
{
|
||||
if (doc == null || doc.Database == null || _docSubsTracker.Contains(doc.Name))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_docSubsTracker.Add(doc.Name);
|
||||
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)
|
||||
{
|
||||
ChangedObjectIds.Add(dBObject.Handle.Value.ToString());
|
||||
_idleManager.SubscribeToIdle(RunExpirationChecks);
|
||||
}
|
||||
|
||||
private void RunExpirationChecks()
|
||||
{
|
||||
var senders = _store.GetSenders();
|
||||
string[] objectIdsList = ChangedObjectIds.ToArray();
|
||||
List<string> expiredSenderIds = new();
|
||||
|
||||
_sendConversionCache.EvictObjects(objectIdsList);
|
||||
|
||||
foreach (SenderModelCard modelCard in senders)
|
||||
{
|
||||
var intersection = modelCard.SendFilter.NotNull().GetObjectIds().Intersect(objectIdsList).ToList();
|
||||
bool isExpired = intersection.Count != 0;
|
||||
if (isExpired)
|
||||
{
|
||||
expiredSenderIds.Add(modelCard.ModelCardId.NotNull());
|
||||
}
|
||||
}
|
||||
|
||||
Commands.SetModelsExpired(expiredSenderIds);
|
||||
ChangedObjectIds = new HashSet<string>();
|
||||
}
|
||||
|
||||
public List<ISendFilter> GetSendFilters() => _sendFilters;
|
||||
|
||||
public Task Send(string modelCardId)
|
||||
{
|
||||
Parent.RunOnMainThread(async () => await SendInternal(modelCardId).ConfigureAwait(false));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task SendInternal(string modelCardId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard)
|
||||
{
|
||||
// Handle as GLOBAL ERROR at BrowserBridge
|
||||
throw new InvalidOperationException("No publish model card was found.");
|
||||
}
|
||||
|
||||
using var uow = _unitOfWorkFactory.Resolve<SendOperation<AutocadRootObject>>();
|
||||
|
||||
// Init cancellation token source -> Manager also cancel it if exist before
|
||||
CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId);
|
||||
|
||||
// Disable document activation (document creation and document switch)
|
||||
// Not disabling results in DUI model card being out of sync with the active document
|
||||
// The DocumentActivated event isn't usable probably because it is pushed to back of main thread queue
|
||||
Application.DocumentManager.DocumentActivationEnabled = false;
|
||||
|
||||
// Get elements to convert
|
||||
List<AutocadRootObject> autocadObjects = Application.DocumentManager.CurrentDocument.GetObjects(
|
||||
modelCard.SendFilter.NotNull().GetObjectIds()
|
||||
);
|
||||
|
||||
if (autocadObjects.Count == 0)
|
||||
{
|
||||
// Handle as CARD ERROR in this function
|
||||
throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!");
|
||||
}
|
||||
|
||||
var sendInfo = new SendInfo(
|
||||
modelCard.AccountId.NotNull(),
|
||||
modelCard.ProjectId.NotNull(),
|
||||
modelCard.ModelId.NotNull(),
|
||||
_autocadSettings.HostAppInfo.Name
|
||||
);
|
||||
|
||||
var sendResult = await uow.Service
|
||||
.Execute(
|
||||
autocadObjects,
|
||||
sendInfo,
|
||||
(status, progress) =>
|
||||
Commands.SetModelProgress(modelCardId, new ModelCardProgress(modelCardId, status, progress), cts),
|
||||
cts.Token
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
Commands.SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults);
|
||||
}
|
||||
// Catch here specific exceptions if they related to model card.
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// SWALLOW -> UI handles it immediately, so we do not need to handle anything
|
||||
return;
|
||||
}
|
||||
catch (SpeckleSendFilterException e)
|
||||
{
|
||||
Commands.SetModelError(modelCardId, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// renable document activation
|
||||
Application.DocumentManager.DocumentActivationEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelSend(string modelCardId) => _cancellationManager.CancelOperation(modelCardId);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
#if AUTOCAD
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Speckle.Autofac;
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using Speckle.Connectors.Autocad.Bindings;
|
||||
using Speckle.Connectors.Autocad.Filters;
|
||||
using Speckle.Connectors.Autocad.HostApp;
|
||||
using Speckle.Connectors.Autocad.Interfaces;
|
||||
using Speckle.Connectors.Autocad.Operations.Receive;
|
||||
using Speckle.Connectors.Autocad.Operations.Send;
|
||||
using Speckle.Connectors.Autocad.Plugin;
|
||||
using Speckle.Connectors.DUI;
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.DUI.Models.Card.SendFilter;
|
||||
using Speckle.Connectors.DUI.WebView;
|
||||
using Speckle.Connectors.Utils;
|
||||
using Speckle.Connectors.Utils.Builders;
|
||||
using Speckle.Connectors.Utils.Caching;
|
||||
using Speckle.Connectors.Utils.Instances;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
using Speckle.Core.Models.GraphTraversal;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.DependencyInjection;
|
||||
|
||||
public class AutocadConnectorModule : ISpeckleModule
|
||||
{
|
||||
public void Load(SpeckleContainerBuilder builder)
|
||||
{
|
||||
builder.AddAutofac();
|
||||
builder.AddConnectorUtils();
|
||||
builder.AddDUI();
|
||||
builder.AddDUIView();
|
||||
|
||||
// Register other connector specific types
|
||||
builder.AddSingleton<IAutocadPlugin, AutocadPlugin>();
|
||||
builder.AddTransient<TransactionContext>();
|
||||
builder.AddSingleton(new AutocadDocumentManager()); // TODO: Dependent to TransactionContext, can be moved to AutocadContext
|
||||
builder.AddSingleton<DocumentModelStore, AutocadDocumentStore>();
|
||||
builder.AddSingleton<AutocadContext>();
|
||||
builder.AddSingleton<AutocadIdleManager>();
|
||||
|
||||
SharedConnectorModule.LoadShared(builder);
|
||||
|
||||
|
||||
builder.AddScoped<AutocadLayerManager>();
|
||||
|
||||
// Operations
|
||||
builder.AddScoped<SendOperation<AutocadRootObject>>();
|
||||
builder.AddSingleton(DefaultTraversal.CreateTraversalFunc());
|
||||
|
||||
// Object Builders
|
||||
builder.AddScoped<IHostObjectBuilder, AutocadHostObjectBuilder>();
|
||||
builder.AddScoped<IRootObjectBuilder<AutocadRootObject>, AutocadRootObjectBuilder>();
|
||||
|
||||
// Register bindings
|
||||
builder.AddSingleton<IBinding, ConfigBinding>("connectorName", "Autocad"); // POC: Easier like this for now, should be cleaned up later
|
||||
builder.AddSingleton<IBinding, AutocadSendBinding>();
|
||||
builder.AddSingleton<IBinding, AutocadReceiveBinding>();
|
||||
|
||||
// register send filters
|
||||
builder.AddTransient<ISendFilter, AutocadSelectionFilter>();
|
||||
|
||||
// register send conversion cache
|
||||
builder.AddSingleton<ISendConversionCache, SendConversionCache>();
|
||||
builder.AddScoped<IInstanceObjectsManager<AutocadRootObject, List<Entity>>, AutocadInstanceObjectManager>();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
#if CIVIL3D
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using Speckle.Connectors.Autocad.Bindings;
|
||||
using Speckle.Connectors.Autocad.Filters;
|
||||
using Speckle.Connectors.Autocad.Operations.Send;
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Models.Card.SendFilter;
|
||||
using Speckle.Connectors.Utils.Builders;
|
||||
using Speckle.Connectors.Utils.Caching;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.DependencyInjection;
|
||||
|
||||
public class Civil3dConnectorModule : ISpeckleModule
|
||||
{
|
||||
public void Load(SpeckleContainerBuilder builder)
|
||||
{
|
||||
SharedConnectorModule.LoadShared(builder);
|
||||
|
||||
// Operations
|
||||
builder.AddScoped<SendOperation<AutocadRootObject>>();
|
||||
|
||||
// Object Builders
|
||||
builder.AddScoped<IRootObjectBuilder<AutocadRootObject>, AutocadRootObjectBuilder>();
|
||||
|
||||
// Register bindings
|
||||
builder.AddSingleton<IBinding, ConfigBinding>("connectorName", "Civil3d"); // POC: Easier like this for now, should be cleaned up later
|
||||
builder.AddSingleton<IBinding, AutocadSendBinding>();
|
||||
|
||||
// register send filters
|
||||
builder.AddTransient<ISendFilter, AutocadSelectionFilter>();
|
||||
|
||||
// register send conversion cache
|
||||
builder.AddSingleton<ISendConversionCache, SendConversionCache>();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
using Speckle.Autofac;
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using Speckle.Connectors.Autocad.Bindings;
|
||||
using Speckle.Connectors.Autocad.HostApp;
|
||||
using Speckle.Connectors.Autocad.Interfaces;
|
||||
using Speckle.Connectors.Autocad.Plugin;
|
||||
using Speckle.Connectors.DUI;
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.DUI.WebView;
|
||||
using Speckle.Connectors.Utils;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.DependencyInjection;
|
||||
|
||||
public static class SharedConnectorModule
|
||||
{
|
||||
public static void LoadShared(SpeckleContainerBuilder builder)
|
||||
{
|
||||
builder.AddAutofac();
|
||||
builder.AddConnectorUtils();
|
||||
builder.AddDUI();
|
||||
builder.AddDUIView();
|
||||
|
||||
// Register other connector specific types
|
||||
builder.AddSingleton<IAutocadPlugin, AutocadPlugin>();
|
||||
builder.AddTransient<TransactionContext>();
|
||||
builder.AddSingleton(new AutocadDocumentManager()); // TODO: Dependent to TransactionContext, can be moved to AutocadContext
|
||||
builder.AddSingleton<DocumentModelStore, AutocadDocumentStore>();
|
||||
builder.AddSingleton<AutocadContext>();
|
||||
builder.AddSingleton<AutocadLayerManager>();
|
||||
builder.AddSingleton<AutocadIdleManager>();
|
||||
|
||||
// Register bindings
|
||||
builder.AddSingleton<IBinding, TestBinding>();
|
||||
builder.AddSingleton<IBinding, AccountBinding>();
|
||||
builder.AddSingleton<IBinding, AutocadBasicConnectorBinding>();
|
||||
builder.AddSingleton<IBasicConnectorBinding, AutocadBasicConnectorBinding>();
|
||||
builder.AddSingleton<IBinding, AutocadSelectionBinding>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Speckle.Connectors.DUI.Models.Card.SendFilter;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.Filters;
|
||||
|
||||
public class AutocadSelectionFilter : DirectSelectionSendFilter
|
||||
{
|
||||
public override List<string> GetObjectIds() => SelectedObjectIds;
|
||||
|
||||
public override bool CheckExpiry(string[] changedObjectIds) => SelectedObjectIds.Intersect(changedObjectIds).Any();
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
global using Document = Autodesk.AutoCAD.ApplicationServices.Document;
|
||||
global using Application = Autodesk.AutoCAD.ApplicationServices.Core.Application;
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace Speckle.Connectors.Autocad.HostApp;
|
||||
|
||||
public class AutocadContext
|
||||
{
|
||||
// POC: we may want to inject this autocadcontext with the active doc?
|
||||
|
||||
private const string INVALID_CHARS = @"<>/\:;""?*|=,‘";
|
||||
|
||||
// POC: we can move this function into more relevant/general place. Not sure other connectors need similar functionality like this.
|
||||
public string RemoveInvalidChars(string str)
|
||||
{
|
||||
foreach (char c in INVALID_CHARS)
|
||||
{
|
||||
str = str.Replace(c.ToString(), string.Empty);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.HostApp;
|
||||
|
||||
public class AutocadDocumentManager
|
||||
{
|
||||
private const string SPECKLE_KEY = "Speckle_DUI3";
|
||||
private const string SPECKLE_MODEL_CARDS_KEY = "Speckle_DUI3_Model_Cards";
|
||||
|
||||
/// <summary>
|
||||
/// Returns all the speckle model cards present in the current document.
|
||||
/// </summary>
|
||||
/// <param name="doc"></param>
|
||||
/// <returns></returns>
|
||||
public string? ReadModelCards(Document doc)
|
||||
{
|
||||
using (TransactionContext.StartTransaction(doc))
|
||||
{
|
||||
Transaction tr = doc.Database.TransactionManager.TopTransaction;
|
||||
|
||||
var nod = (DBDictionary)tr.GetObject(doc.Database.NamedObjectsDictionaryId, OpenMode.ForRead);
|
||||
if (!nod.Contains(SPECKLE_KEY))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var speckleDict = (DBDictionary)tr.GetObject(nod.GetAt(SPECKLE_KEY), OpenMode.ForRead);
|
||||
if (speckleDict.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ObjectId id = speckleDict.GetAt(SPECKLE_MODEL_CARDS_KEY);
|
||||
if (id == ObjectId.Null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var record = (Xrecord)tr.GetObject(id, OpenMode.ForRead);
|
||||
string value = GetXrecordData(record);
|
||||
|
||||
try
|
||||
{
|
||||
//Try to decode here because there is old data
|
||||
return Base64Decode(value);
|
||||
}
|
||||
catch (ApplicationException e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the model cards to the current document.
|
||||
/// </summary>
|
||||
/// <param name="doc"></param>
|
||||
/// <param name="modelCardsString"></param>
|
||||
public void WriteModelCards(Document doc, string modelCardsString)
|
||||
{
|
||||
if (doc == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (TransactionContext.StartTransaction(doc))
|
||||
{
|
||||
Transaction tr = doc.Database.TransactionManager.TopTransaction;
|
||||
|
||||
var nod = (DBDictionary)tr.GetObject(doc.Database.NamedObjectsDictionaryId, OpenMode.ForRead);
|
||||
DBDictionary speckleDict;
|
||||
if (nod.Contains(SPECKLE_KEY))
|
||||
{
|
||||
speckleDict = (DBDictionary)tr.GetObject(nod.GetAt(SPECKLE_KEY), OpenMode.ForWrite);
|
||||
}
|
||||
else
|
||||
{
|
||||
speckleDict = new DBDictionary();
|
||||
nod.UpgradeOpen();
|
||||
nod.SetAt(SPECKLE_KEY, speckleDict);
|
||||
tr.AddNewlyCreatedDBObject(speckleDict, true);
|
||||
}
|
||||
|
||||
Xrecord xRec = new() { Data = CreateResultBuffer(modelCardsString) };
|
||||
|
||||
speckleDict.SetAt(SPECKLE_MODEL_CARDS_KEY, xRec);
|
||||
tr.AddNewlyCreatedDBObject(xRec, true);
|
||||
}
|
||||
}
|
||||
|
||||
private ResultBuffer CreateResultBuffer(string value)
|
||||
{
|
||||
int size = 1024;
|
||||
var valueEncoded = Base64Encode(value);
|
||||
var valueEncodedList = SplitString(valueEncoded, size);
|
||||
|
||||
ResultBuffer rb = new();
|
||||
|
||||
foreach (string valueEncodedSplit in valueEncodedList)
|
||||
{
|
||||
rb.Add(new TypedValue((int)DxfCode.Text, valueEncodedSplit));
|
||||
}
|
||||
|
||||
return rb;
|
||||
}
|
||||
|
||||
private string GetXrecordData(Xrecord pXrecord)
|
||||
{
|
||||
StringBuilder valueEncoded = new();
|
||||
foreach (TypedValue typedValue in pXrecord.Data)
|
||||
{
|
||||
if (typedValue.TypeCode == (int)DxfCode.Text)
|
||||
{
|
||||
valueEncoded.Append(typedValue.Value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return valueEncoded.ToString();
|
||||
}
|
||||
|
||||
private string Base64Encode(string plainText)
|
||||
{
|
||||
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
|
||||
return Convert.ToBase64String(plainTextBytes);
|
||||
}
|
||||
|
||||
private string Base64Decode(string base64EncodedData)
|
||||
{
|
||||
var base64EncodedBytes = Convert.FromBase64String(base64EncodedData);
|
||||
return Encoding.UTF8.GetString(base64EncodedBytes);
|
||||
}
|
||||
|
||||
private IEnumerable<string> SplitString(string text, int chunkSize)
|
||||
{
|
||||
for (int offset = 0; offset < text.Length; offset += chunkSize)
|
||||
{
|
||||
int size = Math.Min(chunkSize, text.Length - offset);
|
||||
yield return text.Substring(offset, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.Utils;
|
||||
using Speckle.Newtonsoft.Json;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.HostApp;
|
||||
|
||||
public class AutocadDocumentStore : DocumentModelStore
|
||||
{
|
||||
private readonly string _nullDocumentName = "Null Doc";
|
||||
private string _previousDocName;
|
||||
private readonly AutocadDocumentManager _autocadDocumentManager;
|
||||
|
||||
public AutocadDocumentStore(
|
||||
JsonSerializerSettings jsonSerializerSettings,
|
||||
AutocadDocumentManager autocadDocumentManager,
|
||||
ITopLevelExceptionHandler topLevelExceptionHandler
|
||||
)
|
||||
: base(jsonSerializerSettings, true)
|
||||
{
|
||||
_autocadDocumentManager = autocadDocumentManager;
|
||||
_previousDocName = _nullDocumentName;
|
||||
|
||||
// POC: Will be addressed to move it into AutocadContext!
|
||||
if (Application.DocumentManager.MdiActiveDocument != null)
|
||||
{
|
||||
IsDocumentInit = true;
|
||||
// POC: this logic might go when we have document management in context
|
||||
// It is with the case of if binding created with already a document
|
||||
// This is valid when user opens acad file directly double clicking
|
||||
OnDocChangeInternal(Application.DocumentManager.MdiActiveDocument);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var currentDocName = doc != null ? doc.Name : _nullDocumentName;
|
||||
if (_previousDocName == currentDocName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_previousDocName = currentDocName;
|
||||
ReadFromFile();
|
||||
OnDocumentChanged();
|
||||
}
|
||||
|
||||
public override void ReadFromFile()
|
||||
{
|
||||
Models = new();
|
||||
|
||||
// POC: Will be addressed to move it into AutocadContext!
|
||||
Document? doc = Application.DocumentManager.MdiActiveDocument;
|
||||
|
||||
if (doc == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string? serializedModelCards = _autocadDocumentManager.ReadModelCards(doc);
|
||||
if (serializedModelCards == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Models = Deserialize(serializedModelCards).NotNull();
|
||||
}
|
||||
|
||||
public override void WriteToFile()
|
||||
{
|
||||
// POC: Will be addressed to move it into AutocadContext!
|
||||
Document doc = Application.DocumentManager.MdiActiveDocument;
|
||||
|
||||
if (doc == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string modelCardsString = Serialize();
|
||||
_autocadDocumentManager.WriteModelCards(doc, modelCardsString);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.HostApp;
|
||||
|
||||
public class AutocadIdleManager
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, Action> _sCalls = new();
|
||||
private bool _hasSubscribed;
|
||||
|
||||
/// <summary>
|
||||
/// Subscribe deferred action to AutocadIdle event to run it whenever Autocad become idle.
|
||||
/// </summary>
|
||||
/// <param name="action"> Action to call whenever Autocad become Idle.</param>
|
||||
public void SubscribeToIdle(Action action)
|
||||
{
|
||||
_sCalls[action.Method.Name] = action;
|
||||
|
||||
if (_hasSubscribed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_hasSubscribed = true;
|
||||
Application.Idle += OnIdleHandler;
|
||||
}
|
||||
|
||||
private void OnIdleHandler(object sender, EventArgs e)
|
||||
{
|
||||
foreach (var kvp in _sCalls)
|
||||
{
|
||||
kvp.Value();
|
||||
}
|
||||
|
||||
_sCalls.Clear();
|
||||
_hasSubscribed = false;
|
||||
Application.Idle -= OnIdleHandler;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
using System.DoubleNumerics;
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Autodesk.AutoCAD.Geometry;
|
||||
using Speckle.Connectors.Autocad.HostApp.Extensions;
|
||||
using Speckle.Connectors.Autocad.Operations.Send;
|
||||
using Speckle.Connectors.Utils.Conversion;
|
||||
using Speckle.Connectors.Utils.Instances;
|
||||
using Speckle.Core.Kits;
|
||||
using Speckle.Core.Logging;
|
||||
using Speckle.Core.Models;
|
||||
using Speckle.Core.Models.Instances;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.HostApp;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// Expects to be a scoped dependency per send or receive operation.
|
||||
/// </summary>
|
||||
public class AutocadInstanceObjectManager : IInstanceObjectsManager<AutocadRootObject, List<Entity>>
|
||||
{
|
||||
private readonly AutocadLayerManager _autocadLayerManager;
|
||||
private Dictionary<string, InstanceProxy> InstanceProxies { get; set; } = new();
|
||||
private Dictionary<string, List<InstanceProxy>> InstanceProxiesByDefinitionId { get; set; } = new();
|
||||
private Dictionary<string, InstanceDefinitionProxy> DefinitionProxies { get; set; } = new();
|
||||
private Dictionary<string, AutocadRootObject> FlatAtomicObjects { get; set; } = new();
|
||||
|
||||
public AutocadInstanceObjectManager(AutocadLayerManager autocadLayerManager)
|
||||
{
|
||||
_autocadLayerManager = autocadLayerManager;
|
||||
}
|
||||
|
||||
public UnpackResult<AutocadRootObject> UnpackSelection(IEnumerable<AutocadRootObject> objects)
|
||||
{
|
||||
using var transaction = Application.DocumentManager.CurrentDocument.Database.TransactionManager.StartTransaction();
|
||||
|
||||
foreach (var obj in objects)
|
||||
{
|
||||
if (obj.Root is BlockReference blockReference && !blockReference.IsDynamicBlock)
|
||||
{
|
||||
UnpackInstance(blockReference, 0, transaction);
|
||||
}
|
||||
|
||||
FlatAtomicObjects[obj.ApplicationId] = obj;
|
||||
}
|
||||
return new(FlatAtomicObjects.Values.ToList(), InstanceProxies, DefinitionProxies.Values.ToList());
|
||||
}
|
||||
|
||||
private void UnpackInstance(BlockReference instance, int depth, Transaction transaction)
|
||||
{
|
||||
var instanceIdString = instance.Handle.Value.ToString();
|
||||
var definitionId = instance.BlockTableRecord;
|
||||
|
||||
InstanceProxies[instanceIdString] = new InstanceProxy()
|
||||
{
|
||||
applicationId = instanceIdString,
|
||||
DefinitionId = definitionId.ToString(),
|
||||
MaxDepth = depth,
|
||||
Transform = GetMatrix(instance.BlockTransform.ToArray()),
|
||||
Units = Application.DocumentManager.CurrentDocument.Database.Insunits.ToSpeckleString()
|
||||
};
|
||||
|
||||
// For each block instance that has the same definition, we need to keep track of the "maximum depth" at which is found.
|
||||
// This will enable on receive to create them in the correct order (descending by max depth, interleaved definitions and instances).
|
||||
// We need to interleave the creation of definitions and instances, as some definitions may depend on instances.
|
||||
if (
|
||||
!InstanceProxiesByDefinitionId.TryGetValue(
|
||||
definitionId.ToString(),
|
||||
out List<InstanceProxy> instanceProxiesWithSameDefinition
|
||||
)
|
||||
)
|
||||
{
|
||||
instanceProxiesWithSameDefinition = new List<InstanceProxy>();
|
||||
InstanceProxiesByDefinitionId[definitionId.ToString()] = instanceProxiesWithSameDefinition;
|
||||
}
|
||||
|
||||
// We ensure that all previous instance proxies that have the same definition are at this max depth. I kind of have a feeling this can be done more elegantly, but YOLO
|
||||
foreach (var instanceProxy in instanceProxiesWithSameDefinition)
|
||||
{
|
||||
instanceProxy.MaxDepth = depth;
|
||||
}
|
||||
|
||||
instanceProxiesWithSameDefinition.Add(InstanceProxies[instanceIdString]);
|
||||
|
||||
if (DefinitionProxies.TryGetValue(definitionId.ToString(), out InstanceDefinitionProxy value))
|
||||
{
|
||||
value.MaxDepth = depth;
|
||||
return; // exit fast - we've parsed this one so no need to go further
|
||||
}
|
||||
|
||||
var definition = (BlockTableRecord)transaction.GetObject(definitionId, OpenMode.ForRead);
|
||||
// definition.Origin
|
||||
var definitionProxy = new InstanceDefinitionProxy()
|
||||
{
|
||||
applicationId = definitionId.ToString(),
|
||||
Objects = new(),
|
||||
MaxDepth = depth,
|
||||
["name"] = definition.Name,
|
||||
["comments"] = definition.Comments,
|
||||
["units"] = definition.Units // ? not sure needed?
|
||||
};
|
||||
|
||||
// Go through each definition object
|
||||
foreach (ObjectId id in definition)
|
||||
{
|
||||
var obj = transaction.GetObject(id, OpenMode.ForRead);
|
||||
var handleIdString = obj.Handle.Value.ToString();
|
||||
definitionProxy.Objects.Add(handleIdString);
|
||||
|
||||
if (obj is BlockReference blockReference && !blockReference.IsDynamicBlock)
|
||||
{
|
||||
UnpackInstance(blockReference, depth + 1, transaction);
|
||||
}
|
||||
FlatAtomicObjects[handleIdString] = new(obj, handleIdString);
|
||||
}
|
||||
|
||||
DefinitionProxies[definitionId.ToString()] = definitionProxy;
|
||||
}
|
||||
|
||||
public BakeResult BakeInstances(
|
||||
List<(string[] layerPath, IInstanceComponent obj)> instanceComponents,
|
||||
Dictionary<string, List<Entity>> applicationIdMap,
|
||||
string baseLayerName,
|
||||
Action<string, double?>? onOperationProgressed
|
||||
)
|
||||
{
|
||||
var sortedInstanceComponents = instanceComponents
|
||||
.OrderByDescending(x => x.obj.MaxDepth) // Sort by max depth, so we start baking from the deepest element first
|
||||
.ThenBy(x => x.obj is InstanceDefinitionProxy ? 0 : 1) // Ensure we bake the deepest definition first, then any instances that depend on it
|
||||
.ToList();
|
||||
|
||||
var definitionIdAndApplicationIdMap = new Dictionary<string, ObjectId>();
|
||||
|
||||
using var transaction = Application.DocumentManager.CurrentDocument.Database.TransactionManager.StartTransaction();
|
||||
var conversionResults = new List<ReceiveConversionResult>();
|
||||
var createdObjectIds = new List<string>();
|
||||
var consumedObjectIds = new List<string>();
|
||||
var count = 0;
|
||||
|
||||
foreach (var (path, instanceOrDefinition) in sortedInstanceComponents)
|
||||
{
|
||||
try
|
||||
{
|
||||
onOperationProgressed?.Invoke("Converting blocks", (double)++count / sortedInstanceComponents.Count);
|
||||
if (instanceOrDefinition is InstanceDefinitionProxy { applicationId: not null } definitionProxy)
|
||||
{
|
||||
// TODO: create definition (block table record)
|
||||
var constituentEntities = definitionProxy.Objects
|
||||
.Select(id => applicationIdMap.TryGetValue(id, out List<Entity> value) ? value : null)
|
||||
.Where(x => x is not null)
|
||||
.SelectMany(ent => ent)
|
||||
.ToList();
|
||||
|
||||
var record = new BlockTableRecord();
|
||||
var objectIds = new ObjectIdCollection();
|
||||
record.Name = baseLayerName;
|
||||
if (definitionProxy["name"] is string name)
|
||||
{
|
||||
record.Name += name;
|
||||
}
|
||||
else
|
||||
{
|
||||
record.Name += definitionProxy.applicationId;
|
||||
}
|
||||
|
||||
foreach (var entity in constituentEntities)
|
||||
{
|
||||
// record.AppendEntity(entity);
|
||||
objectIds.Add(entity.ObjectId);
|
||||
}
|
||||
|
||||
using var blockTable = (BlockTable)
|
||||
transaction.GetObject(Application.DocumentManager.CurrentDocument.Database.BlockTableId, OpenMode.ForWrite);
|
||||
var id = blockTable.Add(record);
|
||||
record.AssumeOwnershipOf(objectIds);
|
||||
|
||||
definitionIdAndApplicationIdMap[definitionProxy.applicationId] = id;
|
||||
transaction.AddNewlyCreatedDBObject(record, true);
|
||||
var consumedEntitiesHandleValues = constituentEntities.Select(ent => ent.Handle.Value.ToString()).ToArray();
|
||||
consumedObjectIds.AddRange(consumedEntitiesHandleValues);
|
||||
createdObjectIds.RemoveAll(newId => consumedEntitiesHandleValues.Contains(newId));
|
||||
}
|
||||
else if (
|
||||
instanceOrDefinition is InstanceProxy instanceProxy
|
||||
&& definitionIdAndApplicationIdMap.TryGetValue(instanceProxy.DefinitionId, out ObjectId definitionId)
|
||||
)
|
||||
{
|
||||
var matrix3d = GetMatrix3d(instanceProxy.Transform, instanceProxy.Units);
|
||||
var insertionPoint = Point3d.Origin.TransformBy(matrix3d);
|
||||
|
||||
var modelSpaceBlockTableRecord = Application.DocumentManager.CurrentDocument.Database.GetModelSpace(
|
||||
OpenMode.ForWrite
|
||||
);
|
||||
_autocadLayerManager.CreateLayerForReceive(path[0]);
|
||||
var blockRef = new BlockReference(insertionPoint, definitionId)
|
||||
{
|
||||
BlockTransform = matrix3d,
|
||||
Layer = path[0],
|
||||
};
|
||||
|
||||
modelSpaceBlockTableRecord.AppendEntity(blockRef);
|
||||
|
||||
if (instanceProxy.applicationId != null)
|
||||
{
|
||||
applicationIdMap[instanceProxy.applicationId] = new List<Entity> { blockRef };
|
||||
}
|
||||
|
||||
transaction.AddNewlyCreatedDBObject(blockRef, true);
|
||||
conversionResults.Add(
|
||||
new(Status.SUCCESS, instanceProxy, blockRef.Handle.Value.ToString(), "Instance (Block)")
|
||||
);
|
||||
createdObjectIds.Add(blockRef.Handle.Value.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
conversionResults.Add(new(Status.ERROR, instanceOrDefinition as Base ?? new Base(), null, null, ex));
|
||||
}
|
||||
}
|
||||
transaction.Commit();
|
||||
return new(createdObjectIds, consumedObjectIds, conversionResults);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleans up any previously created instances.
|
||||
/// POC: This function will not be able to delete block definitions if the user creates a new one composed out of received definitions.
|
||||
/// </summary>
|
||||
/// <param name="namePrefix"></param>
|
||||
public void PurgeInstances(string namePrefix)
|
||||
{
|
||||
using var transaction = Application.DocumentManager.CurrentDocument.Database.TransactionManager.StartTransaction();
|
||||
var instanceDefinitionsToDelete = new Dictionary<string, BlockTableRecord>();
|
||||
|
||||
// Helper function that recurses through a given block table record's constituent objects and purges inner instances as required.
|
||||
void TraverseAndClean(BlockTableRecord btr)
|
||||
{
|
||||
foreach (var objectId in btr)
|
||||
{
|
||||
var obj = transaction.GetObject(objectId, OpenMode.ForRead) as BlockReference;
|
||||
if (obj == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var definition = (BlockTableRecord)transaction.GetObject(obj.BlockTableRecord, OpenMode.ForRead);
|
||||
if (obj.IsErased)
|
||||
{
|
||||
TraverseAndClean(definition);
|
||||
continue;
|
||||
}
|
||||
|
||||
obj.UpgradeOpen();
|
||||
obj.Erase();
|
||||
TraverseAndClean(definition);
|
||||
instanceDefinitionsToDelete[obj.BlockTableRecord.ToString()] = definition;
|
||||
}
|
||||
}
|
||||
|
||||
using var blockTable = (BlockTable)
|
||||
transaction.GetObject(Application.DocumentManager.CurrentDocument.Database.BlockTableId, OpenMode.ForRead);
|
||||
|
||||
// deep clean definitions
|
||||
foreach (var btrId in blockTable)
|
||||
{
|
||||
var btr = (BlockTableRecord)transaction.GetObject(btrId, OpenMode.ForRead);
|
||||
if (btr.Name.Contains(namePrefix)) // POC: this is tightly coupled with a naming convention for definitions in the instance object manager
|
||||
{
|
||||
TraverseAndClean(btr);
|
||||
instanceDefinitionsToDelete[btr.Name] = btr;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var def in instanceDefinitionsToDelete.Values)
|
||||
{
|
||||
def.UpgradeOpen();
|
||||
def.Erase();
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
|
||||
private Matrix4x4 GetMatrix(double[] t)
|
||||
{
|
||||
return new Matrix4x4(
|
||||
t[0],
|
||||
t[1],
|
||||
t[2],
|
||||
t[3],
|
||||
t[4],
|
||||
t[5],
|
||||
t[6],
|
||||
t[7],
|
||||
t[8],
|
||||
t[9],
|
||||
t[10],
|
||||
t[11],
|
||||
t[12],
|
||||
t[13],
|
||||
t[14],
|
||||
t[15]
|
||||
);
|
||||
}
|
||||
|
||||
private Matrix3d GetMatrix3d(Matrix4x4 matrix, string units)
|
||||
{
|
||||
var sf = Units.GetConversionFactor(
|
||||
units,
|
||||
Application.DocumentManager.CurrentDocument.Database.Insunits.ToSpeckleString()
|
||||
);
|
||||
|
||||
var scaledTransform = new[]
|
||||
{
|
||||
matrix.M11,
|
||||
matrix.M12,
|
||||
matrix.M13,
|
||||
matrix.M14 * sf,
|
||||
matrix.M21,
|
||||
matrix.M22,
|
||||
matrix.M23,
|
||||
matrix.M24 * sf,
|
||||
matrix.M31,
|
||||
matrix.M32,
|
||||
matrix.M33,
|
||||
matrix.M34 * sf,
|
||||
matrix.M41,
|
||||
matrix.M42,
|
||||
matrix.M43,
|
||||
matrix.M44
|
||||
};
|
||||
|
||||
var m3d = new Matrix3d(scaledTransform);
|
||||
if (!m3d.IsScaledOrtho())
|
||||
{
|
||||
m3d = new Matrix3d(MakePerpendicular(m3d));
|
||||
}
|
||||
|
||||
return m3d;
|
||||
}
|
||||
|
||||
// https://forums.autodesk.com/t5/net/set-blocktransform-values/m-p/6452121#M49479
|
||||
private static double[] MakePerpendicular(Matrix3d matrix)
|
||||
{
|
||||
// Get the basis vectors of the matrix
|
||||
Vector3d right = new(matrix[0, 0], matrix[1, 0], matrix[2, 0]);
|
||||
Vector3d up = new(matrix[0, 1], matrix[1, 1], matrix[2, 1]);
|
||||
|
||||
Vector3d newForward = right.CrossProduct(up).GetNormal();
|
||||
Vector3d newUp = newForward.CrossProduct(right).GetNormal();
|
||||
|
||||
return new[]
|
||||
{
|
||||
right.X,
|
||||
newUp.X,
|
||||
newForward.X,
|
||||
matrix[0, 3],
|
||||
right.Y,
|
||||
newUp.Y,
|
||||
newForward.Y,
|
||||
matrix[1, 3],
|
||||
right.Z,
|
||||
newUp.Z,
|
||||
newForward.Z,
|
||||
matrix[2, 3],
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
matrix[3, 3],
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Autodesk.AutoCAD.EditorInput;
|
||||
using Autodesk.AutoCAD.LayerManager;
|
||||
using Speckle.Core.Models;
|
||||
using Speckle.Core.Models.GraphTraversal;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.HostApp;
|
||||
|
||||
/// <summary>
|
||||
/// Expects to be a scoped dependency for a given operation and helps with layer creation and cleanup.
|
||||
/// </summary>
|
||||
public class AutocadLayerManager
|
||||
{
|
||||
private readonly AutocadContext _autocadContext;
|
||||
private readonly string _layerFilterName = "Speckle";
|
||||
|
||||
// POC: Will be addressed to move it into AutocadContext!
|
||||
private Document Doc => Application.DocumentManager.MdiActiveDocument;
|
||||
private readonly HashSet<string> _uniqueLayerNames = new();
|
||||
|
||||
public AutocadLayerManager(AutocadContext autocadContext)
|
||||
{
|
||||
_autocadContext = autocadContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will create a layer with the provided name, or, if it finds an existing one, will "purge" all objects from it.
|
||||
/// This ensures we're creating the new objects we've just received rather than overlaying them.
|
||||
/// </summary>
|
||||
/// <param name="layerName">Name to search layer for purge and create.</param>
|
||||
public void CreateLayerForReceive(string layerName)
|
||||
{
|
||||
if (!_uniqueLayerNames.Add(layerName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Doc.LockDocument();
|
||||
using Transaction transaction = Doc.TransactionManager.StartTransaction();
|
||||
|
||||
LayerTable? layerTable =
|
||||
transaction.TransactionManager.GetObject(Doc.Database.LayerTableId, OpenMode.ForRead) as LayerTable;
|
||||
LayerTableRecord layerTableRecord = new() { Name = layerName };
|
||||
|
||||
bool hasLayer = layerTable != null && layerTable.Has(layerName);
|
||||
if (hasLayer)
|
||||
{
|
||||
TypedValue[] tvs = { new((int)DxfCode.LayerName, layerName) };
|
||||
SelectionFilter selectionFilter = new(tvs);
|
||||
SelectionSet selectionResult = Doc.Editor.SelectAll(selectionFilter).Value;
|
||||
if (selectionResult == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (SelectedObject selectedObject in selectionResult)
|
||||
{
|
||||
transaction.GetObject(selectedObject.ObjectId, OpenMode.ForWrite).Erase();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
layerTable?.UpgradeOpen();
|
||||
layerTable?.Add(layerTableRecord);
|
||||
transaction.AddNewlyCreatedDBObject(layerTableRecord, true);
|
||||
transaction.Commit();
|
||||
}
|
||||
|
||||
public void DeleteAllLayersByPrefix(string prefix)
|
||||
{
|
||||
Doc.LockDocument();
|
||||
using Transaction transaction = Doc.TransactionManager.StartTransaction();
|
||||
|
||||
var layerTable = (LayerTable)transaction.TransactionManager.GetObject(Doc.Database.LayerTableId, OpenMode.ForRead);
|
||||
foreach (var layerId in layerTable)
|
||||
{
|
||||
var layer = (LayerTableRecord)transaction.GetObject(layerId, OpenMode.ForRead);
|
||||
var layerName = layer.Name;
|
||||
if (layer.Name.Contains(prefix))
|
||||
{
|
||||
// Delete objects from this layer
|
||||
TypedValue[] tvs = { new((int)DxfCode.LayerName, layerName) };
|
||||
SelectionFilter selectionFilter = new(tvs);
|
||||
SelectionSet selectionResult = Doc.Editor.SelectAll(selectionFilter).Value;
|
||||
if (selectionResult == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (SelectedObject selectedObject in selectionResult)
|
||||
{
|
||||
transaction.GetObject(selectedObject.ObjectId, OpenMode.ForWrite).Erase();
|
||||
}
|
||||
// Delete layer
|
||||
layer.UpgradeOpen();
|
||||
layer.Erase();
|
||||
}
|
||||
}
|
||||
transaction.Commit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a layer filter for the just received model, grouped under a top level filter "Speckle". Note: manual close and open of the layer properties panel required (it's an acad thing).
|
||||
/// This comes in handy to quickly access the layers created for this specific model.
|
||||
/// </summary>
|
||||
/// <param name="projectName"></param>
|
||||
/// <param name="modelName"></param>
|
||||
public void CreateLayerFilter(string projectName, string modelName)
|
||||
{
|
||||
using var docLock = Doc.LockDocument();
|
||||
string filterName = _autocadContext.RemoveInvalidChars($@"{projectName}-{modelName}");
|
||||
LayerFilterTree layerFilterTree = Doc.Database.LayerFilters;
|
||||
LayerFilterCollection? layerFilterCollection = layerFilterTree.Root.NestedFilters;
|
||||
LayerFilter? groupFilter = null;
|
||||
|
||||
// Find existing layer filter if exists
|
||||
foreach (LayerFilter existingFilter in layerFilterCollection)
|
||||
{
|
||||
if (existingFilter.Name == _layerFilterName)
|
||||
{
|
||||
groupFilter = existingFilter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new one unless exists
|
||||
if (groupFilter == null)
|
||||
{
|
||||
groupFilter = new LayerFilter() { Name = "Speckle", FilterExpression = $"NAME==\"SPK-*\"" };
|
||||
layerFilterCollection.Add(groupFilter);
|
||||
}
|
||||
|
||||
string layerFilterExpression = $"NAME==\"SPK-{filterName}*\"";
|
||||
foreach (LayerFilter lf in groupFilter.NestedFilters)
|
||||
{
|
||||
if (lf.Name == filterName)
|
||||
{
|
||||
lf.FilterExpression = layerFilterExpression;
|
||||
return;
|
||||
}
|
||||
}
|
||||
var layerFilter = new LayerFilter() { Name = filterName, FilterExpression = layerFilterExpression };
|
||||
groupFilter.NestedFilters.Add(layerFilter);
|
||||
Doc.Database.LayerFilters = layerFilterTree;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a valid layer name for a given context.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="baseLayerPrefix"></param>
|
||||
/// <returns></returns>
|
||||
public string GetLayerPath(TraversalContext context, string baseLayerPrefix)
|
||||
{
|
||||
string[] collectionBasedPath = context.GetAscendantOfType<Collection>().Select(c => c.name).Reverse().ToArray();
|
||||
string[] path = collectionBasedPath.Length != 0 ? collectionBasedPath : context.GetPropertyPath().ToArray();
|
||||
|
||||
var name = baseLayerPrefix + string.Join("-", path);
|
||||
return _autocadContext.RemoveInvalidChars(name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.IO;
|
||||
using Speckle.Core.Kits; // POC: Must go https://spockle.atlassian.net/browse/CNX-9325
|
||||
|
||||
namespace Speckle.Connectors.Autocad.HostApp;
|
||||
|
||||
public class AutocadSettings
|
||||
{
|
||||
public AutocadSettings(HostApplication hostAppInfo, HostAppVersion hostAppVersion)
|
||||
{
|
||||
HostAppInfo = hostAppInfo;
|
||||
HostAppVersion = hostAppVersion;
|
||||
Modules = new[] { new DirectoryInfo(typeof(AutocadSettings).Assembly.Location).Parent.FullName };
|
||||
}
|
||||
|
||||
public HostApplication HostAppInfo { get; private set; }
|
||||
public HostAppVersion HostAppVersion { get; private set; }
|
||||
|
||||
public IReadOnlyList<string> Modules { get; private set; }
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Speckle.Core.Kits;
|
||||
using Speckle.Core.Logging;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.HostApp.Extensions;
|
||||
|
||||
public static class AcadUnitsExtension
|
||||
{
|
||||
public static string ToSpeckleString(this UnitsValue units)
|
||||
{
|
||||
switch (units)
|
||||
{
|
||||
case UnitsValue.Millimeters:
|
||||
return Units.Millimeters;
|
||||
case UnitsValue.Centimeters:
|
||||
return Units.Centimeters;
|
||||
case UnitsValue.Meters:
|
||||
return Units.Meters;
|
||||
case UnitsValue.Kilometers:
|
||||
return Units.Kilometers;
|
||||
case UnitsValue.Inches:
|
||||
case UnitsValue.USSurveyInch:
|
||||
return Units.Inches;
|
||||
case UnitsValue.Feet:
|
||||
case UnitsValue.USSurveyFeet:
|
||||
return Units.Feet;
|
||||
case UnitsValue.Yards:
|
||||
case UnitsValue.USSurveyYard:
|
||||
return Units.Yards;
|
||||
case UnitsValue.Miles:
|
||||
case UnitsValue.USSurveyMile:
|
||||
return Units.Miles;
|
||||
case UnitsValue.Undefined:
|
||||
return Units.None;
|
||||
default:
|
||||
throw new SpeckleException($"The Unit System \"{units}\" is unsupported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.HostApp.Extensions;
|
||||
|
||||
public static class DatabaseExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the document model space
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
/// <param name="mode"></param>
|
||||
/// <returns></returns>
|
||||
public static BlockTableRecord GetModelSpace(this Database db, OpenMode mode = OpenMode.ForRead) =>
|
||||
(BlockTableRecord)SymbolUtilityServices.GetBlockModelSpaceId(db).GetObject(mode);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Autodesk.AutoCAD.Runtime;
|
||||
using Speckle.Connectors.Autocad.Operations.Send;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.HostApp.Extensions;
|
||||
|
||||
public static class DocumentExtensions
|
||||
{
|
||||
public static List<AutocadRootObject> GetObjects(this Document doc, IEnumerable<string> objectIds)
|
||||
{
|
||||
List<AutocadRootObject> objects = new();
|
||||
using (TransactionContext.StartTransaction(doc))
|
||||
{
|
||||
Transaction tr = doc.Database.TransactionManager.TopTransaction;
|
||||
|
||||
foreach (string objectIdHandle in objectIds)
|
||||
{
|
||||
if (long.TryParse(objectIdHandle, out long parsedId))
|
||||
{
|
||||
Handle handle = new(parsedId);
|
||||
// Note: Fatal crash happens here when objects are deleted, so we need to catch it.
|
||||
try
|
||||
{
|
||||
if (doc.Database.TryGetObjectId(handle, out ObjectId myObjectId))
|
||||
{
|
||||
if (tr.GetObject(myObjectId, OpenMode.ForRead) is DBObject dbObject)
|
||||
{
|
||||
objects.Add(new(dbObject, objectIdHandle));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Autodesk.AutoCAD.Runtime.Exception e)
|
||||
{
|
||||
if (e.ErrorStatus == ErrorStatus.WasErased) // Note: TBD if we want to catch more things in here. For now maybe not, but it does seem like this function gets into "crashes the host app territory"
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return objects;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Autodesk.AutoCAD.EditorInput;
|
||||
using Autodesk.AutoCAD.Geometry;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.HostApp.Extensions;
|
||||
|
||||
public static class EditorExtensions
|
||||
{
|
||||
public static void Zoom(this Editor editor, Extents3d ext)
|
||||
{
|
||||
if (editor == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(editor));
|
||||
}
|
||||
|
||||
using ViewTableRecord view = editor.GetCurrentView();
|
||||
|
||||
Matrix3d worldToEye =
|
||||
Matrix3d.WorldToPlane(view.ViewDirection)
|
||||
* Matrix3d.Displacement(Point3d.Origin - view.Target)
|
||||
* Matrix3d.Rotation(view.ViewTwist, view.ViewDirection, view.Target);
|
||||
|
||||
ext.TransformBy(worldToEye);
|
||||
view.Width = ext.MaxPoint.X - ext.MinPoint.X;
|
||||
view.Height = ext.MaxPoint.Y - ext.MinPoint.Y;
|
||||
view.CenterPoint = new Point2d((ext.MaxPoint.X + ext.MinPoint.X) / 2.0, (ext.MaxPoint.Y + ext.MinPoint.Y) / 2.0);
|
||||
editor.SetCurrentView(view);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.HostApp.Extensions;
|
||||
|
||||
public static class EntityExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds an entity to the autocad database model space record
|
||||
/// </summary>
|
||||
/// <param name="entity">Entity to add into database.</param>
|
||||
/// <param name="layer"> Layer to append object.</param>
|
||||
/// <exception cref="InvalidOperationException">Throws when there is no top transaction in the document.</exception>
|
||||
public static ObjectId AppendToDb(this Entity entity, string? layer = null)
|
||||
{
|
||||
// POC: Will be addressed to move it into AutocadContext!
|
||||
var db = entity.Database ?? Application.DocumentManager.MdiActiveDocument.Database;
|
||||
Transaction tr = db.TransactionManager.TopTransaction;
|
||||
if (tr == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Document does not have a top transaction.");
|
||||
}
|
||||
|
||||
BlockTableRecord btr = db.GetModelSpace(OpenMode.ForWrite);
|
||||
if (entity.IsNewObject)
|
||||
{
|
||||
if (layer != null)
|
||||
{
|
||||
entity.Layer = layer;
|
||||
}
|
||||
|
||||
var id = btr.AppendEntity(entity);
|
||||
tr.AddNewlyCreatedDBObject(entity, true);
|
||||
return id;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (layer != null)
|
||||
{
|
||||
entity.Layer = layer;
|
||||
}
|
||||
|
||||
return entity.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using Autodesk.AutoCAD.ApplicationServices;
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.HostApp;
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage(
|
||||
"Usage",
|
||||
"CA2213:Disposable fields should be disposed",
|
||||
Justification = "Analyzer false positive with Autocad classes"
|
||||
)]
|
||||
public sealed class TransactionContext : IDisposable
|
||||
{
|
||||
private DocumentLock? _documentLock;
|
||||
private Transaction? _transaction;
|
||||
|
||||
public static TransactionContext StartTransaction(Document document) => new(document);
|
||||
|
||||
private TransactionContext(Document document)
|
||||
{
|
||||
_documentLock = document.LockDocument();
|
||||
_transaction = document.Database.TransactionManager.StartTransaction();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_transaction?.Commit();
|
||||
_transaction = null;
|
||||
|
||||
_documentLock?.Dispose();
|
||||
_documentLock = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Speckle.Connectors.Autocad.Interfaces;
|
||||
|
||||
internal interface IAutocadPlugin
|
||||
{
|
||||
void Initialise();
|
||||
void Shutdown();
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Speckle.Connectors.Autocad.HostApp;
|
||||
using Speckle.Connectors.Autocad.HostApp.Extensions;
|
||||
using Speckle.Connectors.Autocad.Operations.Send;
|
||||
using Speckle.Core.Models;
|
||||
using Speckle.Connectors.Utils.Builders;
|
||||
using Speckle.Connectors.Utils.Conversion;
|
||||
using Speckle.Connectors.Utils.Instances;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Core.Logging;
|
||||
using Speckle.Core.Models.GraphTraversal;
|
||||
using Speckle.Core.Models.Instances;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.Operations.Receive;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Expects to be a scoped dependency per receive operation.</para>
|
||||
/// </summary>
|
||||
public class AutocadHostObjectBuilder : IHostObjectBuilder
|
||||
{
|
||||
private readonly AutocadLayerManager _autocadLayerManager;
|
||||
private readonly IRootToHostConverter _converter;
|
||||
private readonly GraphTraversal _traversalFunction;
|
||||
|
||||
// private readonly HashSet<string> _uniqueLayerNames = new();
|
||||
private readonly IInstanceObjectsManager<AutocadRootObject, List<Entity>> _instanceObjectsManager;
|
||||
|
||||
public AutocadHostObjectBuilder(
|
||||
IRootToHostConverter converter,
|
||||
GraphTraversal traversalFunction,
|
||||
AutocadLayerManager autocadLayerManager,
|
||||
IInstanceObjectsManager<AutocadRootObject, List<Entity>> instanceObjectsManager
|
||||
)
|
||||
{
|
||||
_converter = converter;
|
||||
_traversalFunction = traversalFunction;
|
||||
_autocadLayerManager = autocadLayerManager;
|
||||
_instanceObjectsManager = instanceObjectsManager;
|
||||
}
|
||||
|
||||
public HostObjectBuilderResult Build(
|
||||
Base rootObject,
|
||||
string projectName,
|
||||
string modelName,
|
||||
Action<string, double?>? onOperationProgressed,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
// Prompt the UI conversion started. Progress bar will swoosh.
|
||||
onOperationProgressed?.Invoke("Converting", null);
|
||||
|
||||
// Layer filter for received commit with project and model name
|
||||
_autocadLayerManager.CreateLayerFilter(projectName, modelName);
|
||||
|
||||
//TODO: make the layerManager handle \/ ?
|
||||
string baseLayerPrefix = $"SPK-{projectName}-{modelName}-";
|
||||
|
||||
PreReceiveDeepClean(baseLayerPrefix);
|
||||
|
||||
List<ReceiveConversionResult> results = new();
|
||||
List<string> bakedObjectIds = new();
|
||||
|
||||
// return new(bakedObjectIds, results);
|
||||
|
||||
var objectGraph = _traversalFunction.Traverse(rootObject).Where(obj => obj.Current is not Collection);
|
||||
|
||||
// POC: these are not captured by traversal, so we need to re-add them here
|
||||
var instanceDefinitionProxies = (rootObject["instanceDefinitionProxies"] as List<object>)
|
||||
?.Cast<InstanceDefinitionProxy>()
|
||||
.ToList();
|
||||
|
||||
var instanceComponents = new List<(string[] path, IInstanceComponent obj)>();
|
||||
// POC: these are not captured by traversal, so we need to re-add them here
|
||||
if (instanceDefinitionProxies != null && instanceDefinitionProxies.Count > 0)
|
||||
{
|
||||
var transformed = instanceDefinitionProxies.Select(proxy => (Array.Empty<string>(), proxy as IInstanceComponent));
|
||||
instanceComponents.AddRange(transformed);
|
||||
}
|
||||
|
||||
var atomicObjects = new List<(string layerName, Base obj)>();
|
||||
|
||||
foreach (TraversalContext tc in objectGraph)
|
||||
{
|
||||
var layerName = _autocadLayerManager.GetLayerPath(tc, baseLayerPrefix);
|
||||
if (tc.Current is IInstanceComponent instanceComponent)
|
||||
{
|
||||
instanceComponents.Add((new string[] { layerName }, instanceComponent));
|
||||
}
|
||||
else
|
||||
{
|
||||
atomicObjects.Add((layerName, tc.Current));
|
||||
}
|
||||
}
|
||||
|
||||
// Stage 1: Convert atomic objects
|
||||
Dictionary<string, List<Entity>> applicationIdMap = new();
|
||||
var count = 0;
|
||||
foreach (var (layerName, atomicObject) in atomicObjects)
|
||||
{
|
||||
onOperationProgressed?.Invoke("Converting objects", (double)++count / atomicObjects.Count);
|
||||
try
|
||||
{
|
||||
var convertedObjects = ConvertObject(atomicObject, layerName).ToList();
|
||||
|
||||
if (atomicObject.applicationId != null)
|
||||
{
|
||||
applicationIdMap[atomicObject.applicationId] = convertedObjects;
|
||||
}
|
||||
|
||||
results.AddRange(
|
||||
convertedObjects.Select(
|
||||
e =>
|
||||
new ReceiveConversionResult(
|
||||
Status.SUCCESS,
|
||||
atomicObject,
|
||||
e.Handle.Value.ToString(),
|
||||
e.GetType().ToString()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
bakedObjectIds.AddRange(convertedObjects.Select(e => e.Handle.Value.ToString()));
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
results.Add(new(Status.ERROR, atomicObject, null, null, ex));
|
||||
}
|
||||
}
|
||||
|
||||
// Stage 2: Convert instances
|
||||
var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = _instanceObjectsManager.BakeInstances(
|
||||
instanceComponents,
|
||||
applicationIdMap,
|
||||
baseLayerPrefix,
|
||||
onOperationProgressed
|
||||
);
|
||||
|
||||
bakedObjectIds.RemoveAll(id => consumedObjectIds.Contains(id));
|
||||
bakedObjectIds.AddRange(createdInstanceIds);
|
||||
results.RemoveAll(result => result.ResultId != null && consumedObjectIds.Contains(result.ResultId));
|
||||
results.AddRange(instanceConversionResults);
|
||||
|
||||
return new(bakedObjectIds, results);
|
||||
}
|
||||
|
||||
private void PreReceiveDeepClean(string baseLayerPrefix)
|
||||
{
|
||||
_autocadLayerManager.DeleteAllLayersByPrefix(baseLayerPrefix);
|
||||
_instanceObjectsManager.PurgeInstances(baseLayerPrefix);
|
||||
}
|
||||
|
||||
private IEnumerable<Entity> ConvertObject(Base obj, string layerName)
|
||||
{
|
||||
using TransactionContext transactionContext = TransactionContext.StartTransaction(
|
||||
Application.DocumentManager.MdiActiveDocument
|
||||
);
|
||||
|
||||
_autocadLayerManager.CreateLayerForReceive(layerName);
|
||||
|
||||
object converted;
|
||||
using (var tr = Application.DocumentManager.CurrentDocument.Database.TransactionManager.StartTransaction())
|
||||
{
|
||||
converted = _converter.Convert(obj);
|
||||
tr.Commit();
|
||||
}
|
||||
|
||||
IEnumerable<Entity?> flattened = Utilities.FlattenToHostConversionResult(converted).Cast<Entity>();
|
||||
|
||||
foreach (Entity? conversionResult in flattened)
|
||||
{
|
||||
if (conversionResult == null)
|
||||
{
|
||||
// POC: This needed to be double checked why we check null and continue
|
||||
continue;
|
||||
}
|
||||
|
||||
conversionResult.AppendToDb(layerName);
|
||||
yield return conversionResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.Operations.Send;
|
||||
|
||||
// Note: naming is a bit confusing, Root is similar to base commit object, or root commit object, etc. It might be just in my head (dim)
|
||||
public record AutocadRootObject(DBObject Root, string ApplicationId);
|
||||
@@ -0,0 +1,113 @@
|
||||
using System.Diagnostics;
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Speckle.Connectors.Utils.Builders;
|
||||
using Speckle.Connectors.Utils.Caching;
|
||||
using Speckle.Connectors.Utils.Conversion;
|
||||
using Speckle.Connectors.Utils.Instances;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Core.Logging;
|
||||
using Speckle.Core.Models;
|
||||
using Speckle.Core.Models.Instances;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.Operations.Send;
|
||||
|
||||
public class AutocadRootObjectBuilder : IRootObjectBuilder<AutocadRootObject>
|
||||
{
|
||||
private readonly IRootToSpeckleConverter _converter;
|
||||
private readonly string[] _documentPathSeparator = { "\\" };
|
||||
private readonly ISendConversionCache _sendConversionCache;
|
||||
private readonly IInstanceObjectsManager<AutocadRootObject, List<Entity>> _instanceObjectsManager;
|
||||
|
||||
public AutocadRootObjectBuilder(
|
||||
IRootToSpeckleConverter converter,
|
||||
ISendConversionCache sendConversionCache,
|
||||
IInstanceObjectsManager<AutocadRootObject, List<Entity>> instanceObjectManager
|
||||
)
|
||||
{
|
||||
_converter = converter;
|
||||
_sendConversionCache = sendConversionCache;
|
||||
_instanceObjectsManager = instanceObjectManager;
|
||||
}
|
||||
|
||||
public RootObjectBuilderResult Build(
|
||||
IReadOnlyList<AutocadRootObject> objects,
|
||||
SendInfo sendInfo,
|
||||
Action<string, double?>? onOperationProgressed = null,
|
||||
CancellationToken ct = default
|
||||
)
|
||||
{
|
||||
Collection modelWithLayers =
|
||||
new()
|
||||
{
|
||||
name = Application.DocumentManager.CurrentDocument.Name // POC: https://spockle.atlassian.net/browse/CNX-9319
|
||||
.Split(_documentPathSeparator, StringSplitOptions.None)
|
||||
.Reverse()
|
||||
.First(),
|
||||
collectionType = "root"
|
||||
};
|
||||
|
||||
// Cached dictionary to create Collection for autocad entity layers. We first look if collection exists. If so use it otherwise create new one for that layer.
|
||||
Dictionary<string, Collection> collectionCache = new();
|
||||
int count = 0;
|
||||
|
||||
var (atomicObjects, instanceProxies, instanceDefinitionProxies) = _instanceObjectsManager.UnpackSelection(objects);
|
||||
// POC: until we formalise a bit more the root object
|
||||
modelWithLayers["instanceDefinitionProxies"] = instanceDefinitionProxies;
|
||||
|
||||
List<SendConversionResult> results = new();
|
||||
var cacheHitCount = 0;
|
||||
|
||||
foreach (var (dbObject, applicationId) in atomicObjects)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
try
|
||||
{
|
||||
Base converted;
|
||||
if (dbObject is BlockReference && instanceProxies.TryGetValue(applicationId, out InstanceProxy instanceProxy))
|
||||
{
|
||||
converted = instanceProxy;
|
||||
}
|
||||
else if (_sendConversionCache.TryGetValue(sendInfo.ProjectId, applicationId, out ObjectReference value))
|
||||
{
|
||||
converted = value;
|
||||
cacheHitCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
converted = _converter.Convert(dbObject);
|
||||
converted.applicationId = applicationId;
|
||||
}
|
||||
|
||||
// Create and add a collection for each layer if not done so already.
|
||||
if ((dbObject as Entity)?.Layer is string layer)
|
||||
{
|
||||
if (!collectionCache.TryGetValue(layer, out Collection? collection))
|
||||
{
|
||||
collection = new Collection() { name = layer, collectionType = "layer" };
|
||||
collectionCache[layer] = collection;
|
||||
modelWithLayers.elements.Add(collectionCache[layer]);
|
||||
}
|
||||
|
||||
collection.elements.Add(converted);
|
||||
}
|
||||
|
||||
results.Add(new(Status.SUCCESS, applicationId, dbObject.GetType().ToString(), converted));
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
results.Add(new(Status.ERROR, applicationId, dbObject.GetType().ToString(), null, ex));
|
||||
// POC: add logging
|
||||
}
|
||||
|
||||
onOperationProgressed?.Invoke("Converting", (double)++count / atomicObjects.Count);
|
||||
}
|
||||
|
||||
// POC: Log would be nice, or can be removed.
|
||||
Debug.WriteLine(
|
||||
$"Cache hit count {cacheHitCount} out of {objects.Count} ({(double)cacheHitCount / objects.Count})"
|
||||
);
|
||||
|
||||
return new(modelWithLayers, results);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System.Drawing;
|
||||
using System.Reflection;
|
||||
using Autodesk.AutoCAD.Runtime;
|
||||
using Autodesk.AutoCAD.Windows;
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using Speckle.Connectors.Autocad.HostApp;
|
||||
using Speckle.Core.Kits;
|
||||
using Speckle.Connectors.Autocad.Interfaces;
|
||||
using Speckle.Connectors.DUI.WebView;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.Plugin;
|
||||
|
||||
public class AutocadCommand
|
||||
{
|
||||
private static PaletteSet? PaletteSet { get; set; }
|
||||
private static readonly Guid s_id = new("3223E594-1B09-4E54-B3DD-8EA0BECE7BA5");
|
||||
private IAutocadPlugin? _autocadPlugin;
|
||||
|
||||
public SpeckleContainer? Container { get; private set; }
|
||||
|
||||
[CommandMethod("SpeckleNewUI")]
|
||||
public void Command()
|
||||
{
|
||||
if (PaletteSet != null)
|
||||
{
|
||||
FocusPalette();
|
||||
return;
|
||||
}
|
||||
|
||||
PaletteSet = new PaletteSet("Speckle DUI3", s_id)
|
||||
{
|
||||
Size = new Size(400, 500),
|
||||
DockEnabled = (DockSides)((int)DockSides.Left + (int)DockSides.Right)
|
||||
};
|
||||
|
||||
var builder = SpeckleContainerBuilder.CreateInstance();
|
||||
|
||||
#if CIVIL3D2024
|
||||
AutocadSettings autocadSettings = new (HostApplications.Civil3D, HostAppVersion.v2024);
|
||||
#elif AUTOCAD2023
|
||||
AutocadSettings autocadSettings = new(HostApplications.AutoCAD, HostAppVersion.v2023);
|
||||
#else
|
||||
AutocadSettings autocadSettings = new(HostApplications.AutoCAD, HostAppVersion.v2023);
|
||||
#endif
|
||||
Container = builder
|
||||
.LoadAutofacModules(Assembly.GetExecutingAssembly(), autocadSettings.Modules)
|
||||
.AddSingleton(autocadSettings)
|
||||
.Build();
|
||||
|
||||
// Resolve root plugin object and initialise.
|
||||
_autocadPlugin = Container.Resolve<IAutocadPlugin>();
|
||||
_autocadPlugin.Initialise();
|
||||
|
||||
var panelWebView = Container.Resolve<DUI3ControlWebView>();
|
||||
|
||||
PaletteSet.AddVisual("Speckle DUI3 WebView", panelWebView);
|
||||
|
||||
FocusPalette();
|
||||
}
|
||||
|
||||
private void FocusPalette()
|
||||
{
|
||||
if (PaletteSet != null)
|
||||
{
|
||||
PaletteSet.KeepFocus = true;
|
||||
PaletteSet.Visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Autodesk.AutoCAD.Runtime;
|
||||
using Speckle.Autofac;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.Plugin;
|
||||
|
||||
public class AutocadExtensionApplication : IExtensionApplication
|
||||
{
|
||||
public void Initialize() =>
|
||||
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolver.OnAssemblyResolve<AutocadExtensionApplication>;
|
||||
|
||||
public void Terminate() { }
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Speckle.Connectors.Autocad.HostApp;
|
||||
using Speckle.Connectors.Autocad.Interfaces;
|
||||
using Speckle.Connectors.DUI.WebView;
|
||||
|
||||
namespace Speckle.Connectors.Autocad.Plugin;
|
||||
|
||||
public class AutocadPlugin : IAutocadPlugin
|
||||
{
|
||||
private readonly AutocadIdleManager _idleManager;
|
||||
private readonly DUI3ControlWebView _panel;
|
||||
private readonly AutocadSettings _settings;
|
||||
|
||||
public AutocadPlugin(DUI3ControlWebView panel, AutocadSettings settings, AutocadIdleManager idleManager)
|
||||
{
|
||||
_panel = panel;
|
||||
_settings = settings;
|
||||
_idleManager = idleManager;
|
||||
}
|
||||
|
||||
public void Initialise() { }
|
||||
|
||||
public void Shutdown() { }
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
<HasSharedItems>true</HasSharedItems>
|
||||
<SharedGUID>55E65D72-2FE8-4E61-891C-16A4D551CCF7</SharedGUID>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration">
|
||||
<Import_RootNamespace>Speckle.Connectors.AutocadShared</Import_RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Bindings\AutocadSelectionBinding.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Bindings\AutocadReceiveBinding.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Bindings\AutocadSendBinding.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Bindings\AutocadBasicConnectorBinding.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)DependencyInjection\SharedConnectorModule.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)DependencyInjection\AutocadConnectorModule.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)DependencyInjection\Civil3dConnectorModule.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Filters\AutocadSelectionFilter.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)HostApp\AutocadInstanceObjectManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)HostApp\AutocadContext.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)HostApp\AutocadDocumentManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)HostApp\AutocadDocumentModelStore.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)HostApp\AutocadIdleManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)HostApp\AutocadLayerManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)HostApp\AutocadSettings.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)HostApp\Extensions\AcadUnitsExtension.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)HostApp\Extensions\DatabaseExtensions.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)HostApp\Extensions\DocumentExtensions.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)HostApp\Extensions\EditorExtensions.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)HostApp\Extensions\EntityExtensions.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)HostApp\TransactionContext.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Operations\Receive\AutocadHostObjectBuilder.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\AutocadRootObject.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\AutocadRootObjectBuilder.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Plugin\AutocadExtensionApplication.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Plugin\AutocadPlugin.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Interfaces\IAutocadPlugin.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Plugin\AutocadCommand.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)GlobalUsings.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="$(MSBuildThisFileDirectory)Interfaces\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{41BC679F-887F-44CF-971D-A5502EE87DB0}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props"
|
||||
Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')"/>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props"/>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props"/>
|
||||
<Import Project="Speckle.Connectors.AutocadShared.projitems" Label="Shared"/>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets"/>
|
||||
</Project>
|
||||
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Speckle.Connectors.Civil3d</RootNamespace>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseWpf>true</UseWpf>
|
||||
<StartAction>Program</StartAction>
|
||||
<StartProgram>$(ProgramW6432)\Autodesk\AutoCAD 2024\acad.exe</StartProgram>
|
||||
<DefineConstants>$(DefineConstants);CIVIL3D2024;CIVIL3D;</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Converters\Autocad\2024\Speckle.Converters.Autocad2024.DependencyInjection\Speckle.Converters.Autocad2024.DependencyInjection.csproj" />
|
||||
<ProjectReference Include="..\..\..\DUI3\Speckle.Connectors.DUI.WebView\Speckle.Connectors.DUI.WebView.csproj" />
|
||||
<ProjectReference Include="..\..\..\Sdk\Speckle.Autofac\Speckle.Autofac.csproj" />
|
||||
<ProjectReference Include="..\..\..\Sdk\Speckle.Connectors.Utils\Speckle.Connectors.Utils.csproj" />
|
||||
<ProjectReference Include="..\..\..\Sdk\Speckle.Converters.Common.DependencyInjection\Speckle.Converters.Common.DependencyInjection.csproj" />
|
||||
<ProjectReference Include="..\..\..\Sdk\Speckle.Converters.Common\Speckle.Converters.Common.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||
<PackageReference Include="Speckle.Civil3D.API" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\..\Autocad\Speckle.Connectors.AutocadShared\Speckle.Connectors.AutocadShared.projitems" Label="Shared" />
|
||||
</Project>
|
||||
@@ -0,0 +1,562 @@
|
||||
{
|
||||
"version": 2,
|
||||
"dependencies": {
|
||||
".NETFramework,Version=v4.8": {
|
||||
"Microsoft.Extensions.Logging.Abstractions": {
|
||||
"type": "Direct",
|
||||
"requested": "[7.0.0, )",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Memory": "4.5.5"
|
||||
}
|
||||
},
|
||||
"Microsoft.SourceLink.GitHub": {
|
||||
"type": "Direct",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Build.Tasks.Git": "8.0.0",
|
||||
"Microsoft.SourceLink.Common": "8.0.0"
|
||||
}
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.14.1, )",
|
||||
"resolved": "1.14.1",
|
||||
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
|
||||
},
|
||||
"Speckle.Civil3D.API": {
|
||||
"type": "Direct",
|
||||
"requested": "[2024.0.0, )",
|
||||
"resolved": "2024.0.0",
|
||||
"contentHash": "9Q7M1k0DotN8w7MkiScQezErRdnZ4dAkxBMcPNhHSWoth/lSaT6UPV1aYEdl90RhehJWG4l3O7U2e3OXvVSFdw==",
|
||||
"dependencies": {
|
||||
"Speckle.AutoCAD.API": "2024.0.0"
|
||||
}
|
||||
},
|
||||
"Speckle.InterfaceGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[0.9.5, )",
|
||||
"resolved": "0.9.5",
|
||||
"contentHash": "oU/L7pN1R7q8KkbrpQ3WJnHirPHqn+9DEA7asOcUiggV5dzVg1A/VYs7GOSusD24njxXh03tE3a2oTLOjt3cVg=="
|
||||
},
|
||||
"GraphQL.Client": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client.Abstractions": "6.0.0",
|
||||
"GraphQL.Client.Abstractions.Websocket": "6.0.0",
|
||||
"System.Net.WebSockets.Client.Managed": "1.0.22",
|
||||
"System.Reactive": "5.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Client.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Primitives": "6.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Client.Abstractions.Websocket": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client.Abstractions": "6.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA=="
|
||||
},
|
||||
"Microsoft.Bcl.AsyncInterfaces": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "3aeMZ1N0lJoSyzqiP03hqemtb1BijhsJADdobn/4nsMJ8V1H+CrpuduUe4hlRdx+ikBQju1VGjMD1GJ3Sk05Eg==",
|
||||
"dependencies": {
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Build.Tasks.Git": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
|
||||
},
|
||||
"Microsoft.CSharp": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.7.0",
|
||||
"contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA=="
|
||||
},
|
||||
"Microsoft.Data.Sqlite": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.5",
|
||||
"contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Data.Sqlite.Core": "7.0.5",
|
||||
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Data.Sqlite.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.5",
|
||||
"contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.core": "2.1.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "elNeOmkeX3eDVG6pYVeV82p29hr+UKDaBhrZyWvWLw/EVZSYEkZlQdkp0V39k/Xehs2Qa0mvoCvkVj3eQxNQ1Q==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "7.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "7.0.0",
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "Nw2muoNrOG5U5qa2ZekXwudUn2BJcD41e65zwmDHb1fQegTX66UokLWZkJRpqSSHXDOWZ5V0iqhbxOEky91atA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "7.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection": "7.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "7.0.0",
|
||||
"Microsoft.Extensions.Options": "7.0.0",
|
||||
"System.Diagnostics.DiagnosticSource": "7.0.0",
|
||||
"System.ValueTuple": "4.5.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
|
||||
"Microsoft.Extensions.Primitives": "7.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.5",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.SourceLink.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
|
||||
},
|
||||
"Polly": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.2.3",
|
||||
"contentHash": "DeCY0OFbNdNxsjntr1gTXHJ5pKUwYzp04Er2LLeN3g6pWhffsGuKVfMBLe1lw7x76HrPkLxKEFxBlpRxS2nDEQ=="
|
||||
},
|
||||
"Polly.Contrib.WaitAndRetry": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.1.1",
|
||||
"contentHash": "1MUQLiSo4KDkQe6nzQRhIU05lm9jlexX5BVsbuw0SL82ynZ+GzAHQxJVDPVBboxV37Po3SG077aX8DuSy8TkaA=="
|
||||
},
|
||||
"Polly.Extensions.Http": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.0.0",
|
||||
"contentHash": "drrG+hB3pYFY7w1c3BD+lSGYvH2oIclH8GRSehgfyP5kjnFnHKQuuBhuHLv+PWyFuaTDyk/vfRpnxOzd11+J8g==",
|
||||
"dependencies": {
|
||||
"Polly": "7.1.0"
|
||||
}
|
||||
},
|
||||
"Sentry": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.33.0",
|
||||
"contentHash": "8vbD2o6IR2wrRrkSiRbnodWGWUOqIlwYtzpjvPNOb5raJdOf+zxMwfS8f6nx9bmrTTfDj7KrCB8C/5OuicAc8A==",
|
||||
"dependencies": {
|
||||
"System.Reflection.Metadata": "5.0.0",
|
||||
"System.Runtime.InteropServices.RuntimeInformation": "4.3.0",
|
||||
"System.Text.Json": "5.0.2"
|
||||
}
|
||||
},
|
||||
"Sentry.Serilog": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.33.0",
|
||||
"contentHash": "V8BU7QGWg2qLYfNPqtuTBhC1opysny5l+Ifp6J6PhOeAxU0FssR7nYfbJVetrnLIoh2rd3DlJ6hHYYQosQYcUQ==",
|
||||
"dependencies": {
|
||||
"Sentry": "3.33.0",
|
||||
"Serilog": "2.7.1"
|
||||
}
|
||||
},
|
||||
"Serilog": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.12.0",
|
||||
"contentHash": "xaiJLIdu6rYMKfQMYUZgTy8YK7SMZjB4Yk50C/u//Z4OsvxkUfSPJy4nknfvwAC34yr13q7kcyh4grbwhSxyZg=="
|
||||
},
|
||||
"Serilog.Enrichers.ClientInfo": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "mTc7PM+wC9Hr7LWSwqt5mmnlAr7RJs+eTb3PGPRhwdOackk95MkhUZognuxXEdlW19HAFNmEBTSBY5DfLwM8jQ==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.4.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Exceptions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.4.0",
|
||||
"contentHash": "nc/+hUw3lsdo0zCj0KMIybAu7perMx79vu72w0za9Nsi6mWyNkGXxYxakAjWB7nEmYL6zdmhEQRB4oJ2ALUeug==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.8.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Formatting.Compact": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.1.0",
|
||||
"contentHash": "pNroKVjo+rDqlxNG5PXkRLpfSCuDOBY0ri6jp9PLe505ljqwhwZz8ospy2vWhQlFu5GkIesh3FcDs4n7sWZODA==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.8.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.Console": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.1.0",
|
||||
"contentHash": "K6N5q+5fetjnJPvCmkWOpJ/V8IEIoMIB1s86OzBrbxwTyHxdx3pmz4H+8+O/Dc/ftUX12DM1aynx/dDowkwzqg==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.File": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.PeriodicBatching": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.1.0",
|
||||
"contentHash": "NDWR7m3PalVlGEq3rzoktrXikjFMLmpwF0HI4sowo8YDdU+gqPlTHlDQiOGxHfB0sTfjPA9JjA7ctKG9zqjGkw==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.0.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.Seq": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.2.2",
|
||||
"contentHash": "1Csmo5ua7NKUe0yXUx+zsRefjAniPWcXFhUXxXG8pwo0iMiw2gjn9SOkgYnnxbgWqmlGv236w0N/dHc2v5XwMg==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.12.0",
|
||||
"Serilog.Formatting.Compact": "1.1.0",
|
||||
"Serilog.Sinks.File": "5.0.0",
|
||||
"Serilog.Sinks.PeriodicBatching": "3.1.0"
|
||||
}
|
||||
},
|
||||
"SerilogTimings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.0.1",
|
||||
"contentHash": "Zs28eTgszAMwpIrbBnWHBI50yuxL50p/dmAUWmy75+axdZYK/Sjm5/5m1N/CisR8acJUhTVcjPZrsB1P5iv0Uw==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"Speckle.Newtonsoft.Json": {
|
||||
"type": "Transitive",
|
||||
"resolved": "13.0.2",
|
||||
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
|
||||
},
|
||||
"SQLitePCLRaw.bundle_e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.lib.e_sqlite3": "2.1.4",
|
||||
"SQLitePCLRaw.provider.dynamic_cdecl": "2.1.4"
|
||||
}
|
||||
},
|
||||
"SQLitePCLRaw.core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.3"
|
||||
}
|
||||
},
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg=="
|
||||
},
|
||||
"SQLitePCLRaw.provider.dynamic_cdecl": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "ZsaKKhgYF9B1fvcnOGKl3EycNAwd9CRWX7v0rEfuPWhQQ5Jjpvf2VEHahiLIGHio3hxi3EIKFJw9KvyowWOUAw==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.core": "2.1.4"
|
||||
}
|
||||
},
|
||||
"System.Buffers": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.1",
|
||||
"contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
|
||||
},
|
||||
"System.Collections.Immutable": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.4"
|
||||
}
|
||||
},
|
||||
"System.Diagnostics.DiagnosticSource": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "9W0ewWDuAyDqS2PigdTxk6jDKonfgscY/hP8hm7VpxYhNHZHKvZTdRckberlFk3VnCmr3xBUyMBut12Q+T2aOw==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.5",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
}
|
||||
},
|
||||
"System.DoubleNumerics": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.1.3",
|
||||
"contentHash": "KRKEM/L3KBodjA9VOg3EifFVWUY6EOqaMB05UvPEDm7Zeby/kZW+4kdWUEPzW6xtkwf46p661L9NrbeeQhtLzw==",
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.6.1"
|
||||
}
|
||||
},
|
||||
"System.Memory": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.5",
|
||||
"contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Numerics.Vectors": "4.5.0",
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||
}
|
||||
},
|
||||
"System.Net.WebSockets.Client.Managed": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "WqEOxPlXjuZrIjUtXNE9NxEfU/n5E35iV2PtoZdJSUC4tlrqwHnTee+wvMIM4OUaJWmwrymeqcgYrE0IkGAgLA==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.4.0",
|
||||
"System.Numerics.Vectors": "4.4.0"
|
||||
}
|
||||
},
|
||||
"System.Numerics.Vectors": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.0",
|
||||
"contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ=="
|
||||
},
|
||||
"System.Reactive": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
|
||||
"dependencies": {
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"System.Reflection.Metadata": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ==",
|
||||
"dependencies": {
|
||||
"System.Collections.Immutable": "5.0.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.CompilerServices.Unsafe": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
|
||||
},
|
||||
"System.Runtime.InteropServices.RuntimeInformation": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
"contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw=="
|
||||
},
|
||||
"System.Text.Encodings.Web": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.1",
|
||||
"contentHash": "KmJ+CJXizDofbq6mpqDoRRLcxgOd2z9X3XoFNULSbvbqVRZkFX3istvr+MUjL6Zw1RT+RNdoI4GYidIINtgvqQ==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Memory": "4.5.4"
|
||||
}
|
||||
},
|
||||
"System.Text.Json": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.2",
|
||||
"contentHash": "I47dVIGiV6SfAyppphxqupertT/5oZkYLDCX6vC3HpOI4ZLjyoKAreUoem2ie6G0RbRuFrlqz/PcTQjfb2DOfQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Memory": "4.5.4",
|
||||
"System.Numerics.Vectors": "4.5.0",
|
||||
"System.Runtime.CompilerServices.Unsafe": "5.0.0",
|
||||
"System.Text.Encodings.Web": "5.0.1",
|
||||
"System.Threading.Tasks.Extensions": "4.5.4",
|
||||
"System.ValueTuple": "4.5.0"
|
||||
}
|
||||
},
|
||||
"System.Threading.Tasks.Extensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.4",
|
||||
"contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
|
||||
"dependencies": {
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||
}
|
||||
},
|
||||
"System.ValueTuple": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.0",
|
||||
"contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
|
||||
},
|
||||
"speckle.autofac": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.dui": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )",
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Connectors.Utils": "[2.0.999-local, )",
|
||||
"Speckle.Core": "[3.0.1-alpha.14, )",
|
||||
"System.Threading.Tasks.Dataflow": "[6.0.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.dui.webview": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Web.WebView2": "[1.0.1823.32, )",
|
||||
"Speckle.Connectors.DUI": "[2.0.999-local, )"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.utils": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Serilog.Extensions.Logging": "[7.0.0, )",
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Core": "[3.0.1-alpha.14, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.autocad2024": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Speckle.AutoCAD.API": "[2024.0.0, )",
|
||||
"Speckle.Converters.Common": "[2.0.999-local, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.autocad2024.dependencyinjection": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Autofac": "[5.2.0, )",
|
||||
"Speckle.Converters.Autocad2024": "[2.0.999-local, )",
|
||||
"Speckle.Converters.Common.DependencyInjection": "[2.0.999-local, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.common": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Objects": "[3.0.1-alpha.14, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.common.dependencyinjection": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Converters.Common": "[2.0.999-local, )"
|
||||
}
|
||||
},
|
||||
"Autofac": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[5.2.0, )",
|
||||
"resolved": "5.2.0",
|
||||
"contentHash": "V8dBH0dsv75uDzl7Sw+HkhKDPUw2eXnlMjcSVMH+tLo2s67MpTKGyDj1pDcpR+IF2u4YRs0s3/x7R88YJzIWvg==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "1.1.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Web.WebView2": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.1823.32, )",
|
||||
"resolved": "1.0.1823.32",
|
||||
"contentHash": "ppRcWBUNggFIqyJp7PfgS4Oe8/7yli/mHcTNDOaqo3ZzJWnv9AOr0WE9ceEP5SPs1M7CQ3QvdGMR7KNz0v09EA=="
|
||||
},
|
||||
"Serilog.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[7.0.0, )",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "9faU0zNQqU7I6soVhLUMYaGNpgWv6cKlKb2S5AnS8gXxzW/em5Ladm/6FMrWTnX41cdbdGPOWNAo6adi4WaJ6A==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging": "7.0.0",
|
||||
"Serilog": "2.12.0"
|
||||
}
|
||||
},
|
||||
"Speckle.AutoCAD.API": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2023.0.0, )",
|
||||
"resolved": "2024.0.0",
|
||||
"contentHash": "pZZ5uI+NXhZaQnsqRkgp/rywqBAjDObDJ9XNFGJvemT5k2OthDpHzlK/mKxz8QDCYie7uImQ8dv3uWj2QUFDPw=="
|
||||
},
|
||||
"Speckle.Core": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.0.1-alpha.14, )",
|
||||
"resolved": "3.0.1-alpha.14",
|
||||
"contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client": "6.0.0",
|
||||
"Microsoft.CSharp": "4.7.0",
|
||||
"Microsoft.Data.Sqlite": "7.0.5",
|
||||
"Polly": "7.2.3",
|
||||
"Polly.Contrib.WaitAndRetry": "1.1.1",
|
||||
"Polly.Extensions.Http": "3.0.0",
|
||||
"Sentry": "3.33.0",
|
||||
"Sentry.Serilog": "3.33.0",
|
||||
"Serilog": "2.12.0",
|
||||
"Serilog.Enrichers.ClientInfo": "1.3.0",
|
||||
"Serilog.Exceptions": "8.4.0",
|
||||
"Serilog.Sinks.Console": "4.1.0",
|
||||
"Serilog.Sinks.Seq": "5.2.2",
|
||||
"SerilogTimings": "3.0.1",
|
||||
"Speckle.Newtonsoft.Json": "13.0.2",
|
||||
"System.DoubleNumerics": "3.1.3"
|
||||
}
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.0.1-alpha.14, )",
|
||||
"resolved": "3.0.1-alpha.14",
|
||||
"contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==",
|
||||
"dependencies": {
|
||||
"Speckle.Core": "3.0.1-alpha.14"
|
||||
}
|
||||
},
|
||||
"System.Threading.Tasks.Dataflow": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[6.0.0, )",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"profiles": {
|
||||
"ConnectorRevit2023": {
|
||||
"commandName": "Executable",
|
||||
"executablePath": "C:\\Program Files\\Autodesk\\Revit 2023\\Revit.exe"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseWpf>true</UseWpf>
|
||||
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\Speckle.Connectors.RevitShared\Speckle.Connectors.RevitShared.projitems" Label="Shared" />
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Xaml" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="WindowsBase" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Converters\Revit\Speckle.Converters.Revit2023.DependencyInjection\Speckle.Converters.Revit2023.DependencyInjection.csproj" />
|
||||
<ProjectReference Include="..\..\..\Converters\Revit\Speckle.Converters.Revit2023\Speckle.Converters.Revit2023.csproj" />
|
||||
<ProjectReference Include="..\..\..\DUI3\Speckle.Connectors.DUI\Speckle.Connectors.DUI.csproj" />
|
||||
<ProjectReference Include="..\..\..\Sdk\Speckle.Converters.Common.DependencyInjection\Speckle.Converters.Common.DependencyInjection.csproj" />
|
||||
<ProjectReference Include="..\..\..\Sdk\Speckle.Converters.Common\Speckle.Converters.Common.csproj" />
|
||||
<ProjectReference Include="..\..\..\Sdk\Speckle.Autofac\Speckle.Autofac.csproj" />
|
||||
<ProjectReference Include="..\..\..\Sdk\Speckle.Connectors.Utils\Speckle.Connectors.Utils.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CefSharp.Wpf" IncludeAssets="compile" NoWarn="NU1903" />
|
||||
<PackageReference Include="Revit.Async" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target AfterTargets="Clean" Name="CleanAddinFolder">
|
||||
<RemoveDir Directories="$(TargetDir);$(ProjectDir)\..\Release\Release2023;$(AppData)\Autodesk\Revit\Addins\2023\Speckle.Connectors.Revit2023;" />
|
||||
<Delete Files="$(AppData)\Autodesk\Revit\Addins\2023\Speckle.Connectors.Revit2023.addin" />
|
||||
</Target>
|
||||
|
||||
<Target Name="AfterBuildMigrated" AfterTargets="Build" Condition="$([MSBuild]::IsOsPlatform('Windows'))">
|
||||
<CallTarget Condition="'$(IsDesktopBuild)' == true" Targets="AfterBuildDebug" />
|
||||
</Target>
|
||||
|
||||
<Target Name="AfterBuildDebug">
|
||||
<ItemGroup>
|
||||
<RevitDLLs Include="$(TargetDir)\**\*.*" Exclude="$(TargetDir)*.addin" />
|
||||
<SourceManifest Include="$(TargetDir)\Plugin\*.addin" />
|
||||
</ItemGroup>
|
||||
<Copy DestinationFolder="$(AppData)\Autodesk\REVIT\Addins\2023\Speckle.Connectors.Revit2023\%(RecursiveDir)" SourceFiles="@(RevitDLLs)" />
|
||||
<Copy DestinationFolder="$(AppData)\Autodesk\REVIT\Addins\2023\" SourceFiles="@(SourceManifest)" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,565 @@
|
||||
{
|
||||
"version": 2,
|
||||
"dependencies": {
|
||||
".NETFramework,Version=v4.8": {
|
||||
"CefSharp.Wpf": {
|
||||
"type": "Direct",
|
||||
"requested": "[92.0.260, )",
|
||||
"resolved": "92.0.260",
|
||||
"contentHash": "b0TW/HpHsvz2x3M1IQa/8fbCIRKShOgpmSqj5gKiibXY0v2cHgnWssfEX+3Q3UCpizkBJBQ+0fVp+fN8JCPcNQ==",
|
||||
"dependencies": {
|
||||
"CefSharp.Common": "[92.0.260]"
|
||||
}
|
||||
},
|
||||
"Microsoft.SourceLink.GitHub": {
|
||||
"type": "Direct",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Build.Tasks.Git": "8.0.0",
|
||||
"Microsoft.SourceLink.Common": "8.0.0"
|
||||
}
|
||||
},
|
||||
"PolySharp": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.14.1, )",
|
||||
"resolved": "1.14.1",
|
||||
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
|
||||
},
|
||||
"Revit.Async": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.0.1, )",
|
||||
"resolved": "2.0.1",
|
||||
"contentHash": "B7D5zXznqgxMryBYdGgWob20ALfGSP7hJ6+bh9JdLM/LRkYN5dNf0AaI0+7VID9X7e8MA0koAxv9fIijJnmSnw=="
|
||||
},
|
||||
"Speckle.InterfaceGenerator": {
|
||||
"type": "Direct",
|
||||
"requested": "[0.9.5, )",
|
||||
"resolved": "0.9.5",
|
||||
"contentHash": "oU/L7pN1R7q8KkbrpQ3WJnHirPHqn+9DEA7asOcUiggV5dzVg1A/VYs7GOSusD24njxXh03tE3a2oTLOjt3cVg=="
|
||||
},
|
||||
"cef.redist.x64": {
|
||||
"type": "Transitive",
|
||||
"resolved": "92.0.26",
|
||||
"contentHash": "wwwSGVgO9sdlj5TRnjVdzuCkNuYpTOXT90Z+dasnqGrnihrxKU+1UvulxxJa83O2k+l3kaNlAU9uBhiwGX7YyQ=="
|
||||
},
|
||||
"cef.redist.x86": {
|
||||
"type": "Transitive",
|
||||
"resolved": "92.0.26",
|
||||
"contentHash": "VT93sU6hH7LoUILjfaAxWbLc+m+b9QafeeRkuulnj3twJnb0PQ7nXd8PMUeOmYg96NzZi14G7qBYSY0dkxqztg=="
|
||||
},
|
||||
"CefSharp.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "92.0.260",
|
||||
"contentHash": "0KS5z+kqg+mmB1X2KM17w3S7KQI5UTuJv+UOIQauJPvFYfRGWwTqmBbBxL3kCklGx8WSkaeBjPdSFxdzzXCSew==",
|
||||
"dependencies": {
|
||||
"cef.redist.x64": "[92.0.26]",
|
||||
"cef.redist.x86": "[92.0.26]"
|
||||
}
|
||||
},
|
||||
"GraphQL.Client": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client.Abstractions": "6.0.0",
|
||||
"GraphQL.Client.Abstractions.Websocket": "6.0.0",
|
||||
"System.Net.WebSockets.Client.Managed": "1.0.22",
|
||||
"System.Reactive": "5.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Client.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Primitives": "6.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Client.Abstractions.Websocket": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client.Abstractions": "6.0.0"
|
||||
}
|
||||
},
|
||||
"GraphQL.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA=="
|
||||
},
|
||||
"Microsoft.Bcl.AsyncInterfaces": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "3aeMZ1N0lJoSyzqiP03hqemtb1BijhsJADdobn/4nsMJ8V1H+CrpuduUe4hlRdx+ikBQju1VGjMD1GJ3Sk05Eg==",
|
||||
"dependencies": {
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Build.Tasks.Git": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
|
||||
},
|
||||
"Microsoft.CSharp": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.7.0",
|
||||
"contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA=="
|
||||
},
|
||||
"Microsoft.Data.Sqlite": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.5",
|
||||
"contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Data.Sqlite.Core": "7.0.5",
|
||||
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Data.Sqlite.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.5",
|
||||
"contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.core": "2.1.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "elNeOmkeX3eDVG6pYVeV82p29hr+UKDaBhrZyWvWLw/EVZSYEkZlQdkp0V39k/Xehs2Qa0mvoCvkVj3eQxNQ1Q==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "7.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "7.0.0",
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "Nw2muoNrOG5U5qa2ZekXwudUn2BJcD41e65zwmDHb1fQegTX66UokLWZkJRpqSSHXDOWZ5V0iqhbxOEky91atA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "7.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection": "7.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "7.0.0",
|
||||
"Microsoft.Extensions.Options": "7.0.0",
|
||||
"System.Diagnostics.DiagnosticSource": "7.0.0",
|
||||
"System.ValueTuple": "4.5.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
|
||||
"Microsoft.Extensions.Primitives": "7.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.5",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.SourceLink.Common": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
|
||||
},
|
||||
"Polly": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.2.3",
|
||||
"contentHash": "DeCY0OFbNdNxsjntr1gTXHJ5pKUwYzp04Er2LLeN3g6pWhffsGuKVfMBLe1lw7x76HrPkLxKEFxBlpRxS2nDEQ=="
|
||||
},
|
||||
"Polly.Contrib.WaitAndRetry": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.1.1",
|
||||
"contentHash": "1MUQLiSo4KDkQe6nzQRhIU05lm9jlexX5BVsbuw0SL82ynZ+GzAHQxJVDPVBboxV37Po3SG077aX8DuSy8TkaA=="
|
||||
},
|
||||
"Polly.Extensions.Http": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.0.0",
|
||||
"contentHash": "drrG+hB3pYFY7w1c3BD+lSGYvH2oIclH8GRSehgfyP5kjnFnHKQuuBhuHLv+PWyFuaTDyk/vfRpnxOzd11+J8g==",
|
||||
"dependencies": {
|
||||
"Polly": "7.1.0"
|
||||
}
|
||||
},
|
||||
"Sentry": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.33.0",
|
||||
"contentHash": "8vbD2o6IR2wrRrkSiRbnodWGWUOqIlwYtzpjvPNOb5raJdOf+zxMwfS8f6nx9bmrTTfDj7KrCB8C/5OuicAc8A==",
|
||||
"dependencies": {
|
||||
"System.Reflection.Metadata": "5.0.0",
|
||||
"System.Runtime.InteropServices.RuntimeInformation": "4.3.0",
|
||||
"System.Text.Json": "5.0.2"
|
||||
}
|
||||
},
|
||||
"Sentry.Serilog": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.33.0",
|
||||
"contentHash": "V8BU7QGWg2qLYfNPqtuTBhC1opysny5l+Ifp6J6PhOeAxU0FssR7nYfbJVetrnLIoh2rd3DlJ6hHYYQosQYcUQ==",
|
||||
"dependencies": {
|
||||
"Sentry": "3.33.0",
|
||||
"Serilog": "2.7.1"
|
||||
}
|
||||
},
|
||||
"Serilog": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.12.0",
|
||||
"contentHash": "xaiJLIdu6rYMKfQMYUZgTy8YK7SMZjB4Yk50C/u//Z4OsvxkUfSPJy4nknfvwAC34yr13q7kcyh4grbwhSxyZg=="
|
||||
},
|
||||
"Serilog.Enrichers.ClientInfo": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "mTc7PM+wC9Hr7LWSwqt5mmnlAr7RJs+eTb3PGPRhwdOackk95MkhUZognuxXEdlW19HAFNmEBTSBY5DfLwM8jQ==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.4.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Exceptions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.4.0",
|
||||
"contentHash": "nc/+hUw3lsdo0zCj0KMIybAu7perMx79vu72w0za9Nsi6mWyNkGXxYxakAjWB7nEmYL6zdmhEQRB4oJ2ALUeug==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.8.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Formatting.Compact": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.1.0",
|
||||
"contentHash": "pNroKVjo+rDqlxNG5PXkRLpfSCuDOBY0ri6jp9PLe505ljqwhwZz8ospy2vWhQlFu5GkIesh3FcDs4n7sWZODA==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.8.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.Console": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.1.0",
|
||||
"contentHash": "K6N5q+5fetjnJPvCmkWOpJ/V8IEIoMIB1s86OzBrbxwTyHxdx3pmz4H+8+O/Dc/ftUX12DM1aynx/dDowkwzqg==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.File": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.PeriodicBatching": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.1.0",
|
||||
"contentHash": "NDWR7m3PalVlGEq3rzoktrXikjFMLmpwF0HI4sowo8YDdU+gqPlTHlDQiOGxHfB0sTfjPA9JjA7ctKG9zqjGkw==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.0.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.Seq": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.2.2",
|
||||
"contentHash": "1Csmo5ua7NKUe0yXUx+zsRefjAniPWcXFhUXxXG8pwo0iMiw2gjn9SOkgYnnxbgWqmlGv236w0N/dHc2v5XwMg==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.12.0",
|
||||
"Serilog.Formatting.Compact": "1.1.0",
|
||||
"Serilog.Sinks.File": "5.0.0",
|
||||
"Serilog.Sinks.PeriodicBatching": "3.1.0"
|
||||
}
|
||||
},
|
||||
"SerilogTimings": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.0.1",
|
||||
"contentHash": "Zs28eTgszAMwpIrbBnWHBI50yuxL50p/dmAUWmy75+axdZYK/Sjm5/5m1N/CisR8acJUhTVcjPZrsB1P5iv0Uw==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"Speckle.Newtonsoft.Json": {
|
||||
"type": "Transitive",
|
||||
"resolved": "13.0.2",
|
||||
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
|
||||
},
|
||||
"SQLitePCLRaw.bundle_e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.lib.e_sqlite3": "2.1.4",
|
||||
"SQLitePCLRaw.provider.dynamic_cdecl": "2.1.4"
|
||||
}
|
||||
},
|
||||
"SQLitePCLRaw.core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.3"
|
||||
}
|
||||
},
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg=="
|
||||
},
|
||||
"SQLitePCLRaw.provider.dynamic_cdecl": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.4",
|
||||
"contentHash": "ZsaKKhgYF9B1fvcnOGKl3EycNAwd9CRWX7v0rEfuPWhQQ5Jjpvf2VEHahiLIGHio3hxi3EIKFJw9KvyowWOUAw==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.core": "2.1.4"
|
||||
}
|
||||
},
|
||||
"System.Buffers": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.1",
|
||||
"contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
|
||||
},
|
||||
"System.Collections.Immutable": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.4"
|
||||
}
|
||||
},
|
||||
"System.Diagnostics.DiagnosticSource": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "9W0ewWDuAyDqS2PigdTxk6jDKonfgscY/hP8hm7VpxYhNHZHKvZTdRckberlFk3VnCmr3xBUyMBut12Q+T2aOw==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.5",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
}
|
||||
},
|
||||
"System.DoubleNumerics": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.1.3",
|
||||
"contentHash": "KRKEM/L3KBodjA9VOg3EifFVWUY6EOqaMB05UvPEDm7Zeby/kZW+4kdWUEPzW6xtkwf46p661L9NrbeeQhtLzw==",
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.6.1"
|
||||
}
|
||||
},
|
||||
"System.Memory": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.5",
|
||||
"contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Numerics.Vectors": "4.5.0",
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||
}
|
||||
},
|
||||
"System.Net.WebSockets.Client.Managed": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "WqEOxPlXjuZrIjUtXNE9NxEfU/n5E35iV2PtoZdJSUC4tlrqwHnTee+wvMIM4OUaJWmwrymeqcgYrE0IkGAgLA==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.4.0",
|
||||
"System.Numerics.Vectors": "4.4.0"
|
||||
}
|
||||
},
|
||||
"System.Numerics.Vectors": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.0",
|
||||
"contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ=="
|
||||
},
|
||||
"System.Reactive": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==",
|
||||
"dependencies": {
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"System.Reflection.Metadata": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ==",
|
||||
"dependencies": {
|
||||
"System.Collections.Immutable": "5.0.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.CompilerServices.Unsafe": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
|
||||
},
|
||||
"System.Runtime.InteropServices.RuntimeInformation": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
"contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw=="
|
||||
},
|
||||
"System.Text.Encodings.Web": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.1",
|
||||
"contentHash": "KmJ+CJXizDofbq6mpqDoRRLcxgOd2z9X3XoFNULSbvbqVRZkFX3istvr+MUjL6Zw1RT+RNdoI4GYidIINtgvqQ==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Memory": "4.5.4"
|
||||
}
|
||||
},
|
||||
"System.Text.Json": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.2",
|
||||
"contentHash": "I47dVIGiV6SfAyppphxqupertT/5oZkYLDCX6vC3HpOI4ZLjyoKAreUoem2ie6G0RbRuFrlqz/PcTQjfb2DOfQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Memory": "4.5.4",
|
||||
"System.Numerics.Vectors": "4.5.0",
|
||||
"System.Runtime.CompilerServices.Unsafe": "5.0.0",
|
||||
"System.Text.Encodings.Web": "5.0.1",
|
||||
"System.Threading.Tasks.Extensions": "4.5.4",
|
||||
"System.ValueTuple": "4.5.0"
|
||||
}
|
||||
},
|
||||
"System.Threading.Tasks.Extensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.4",
|
||||
"contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
|
||||
"dependencies": {
|
||||
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||
}
|
||||
},
|
||||
"System.ValueTuple": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.0",
|
||||
"contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
|
||||
},
|
||||
"speckle.autofac": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.dui": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )",
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Connectors.Utils": "[2.0.999-local, )",
|
||||
"Speckle.Core": "[3.0.1-alpha.14, )",
|
||||
"System.Threading.Tasks.Dataflow": "[6.0.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.connectors.utils": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Serilog.Extensions.Logging": "[7.0.0, )",
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Core": "[3.0.1-alpha.14, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.common": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Objects": "[3.0.1-alpha.14, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.common.dependencyinjection": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Speckle.Autofac": "[2.0.999-local, )",
|
||||
"Speckle.Converters.Common": "[2.0.999-local, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.revit2023": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Speckle.Converters.Common": "[2.0.999-local, )",
|
||||
"Speckle.Revit.API": "[2023.0.0, )"
|
||||
}
|
||||
},
|
||||
"speckle.converters.revit2023.dependencyinjection": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Speckle.Converters.Common": "[2.0.999-local, )",
|
||||
"Speckle.Converters.Common.DependencyInjection": "[2.0.999-local, )",
|
||||
"Speckle.Converters.Revit2023": "[2.0.999-local, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[7.0.0, )",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Memory": "4.5.5"
|
||||
}
|
||||
},
|
||||
"Serilog.Extensions.Logging": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[7.0.0, )",
|
||||
"resolved": "7.0.0",
|
||||
"contentHash": "9faU0zNQqU7I6soVhLUMYaGNpgWv6cKlKb2S5AnS8gXxzW/em5Ladm/6FMrWTnX41cdbdGPOWNAo6adi4WaJ6A==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging": "7.0.0",
|
||||
"Serilog": "2.12.0"
|
||||
}
|
||||
},
|
||||
"Speckle.Core": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.0.1-alpha.14, )",
|
||||
"resolved": "3.0.1-alpha.14",
|
||||
"contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==",
|
||||
"dependencies": {
|
||||
"GraphQL.Client": "6.0.0",
|
||||
"Microsoft.CSharp": "4.7.0",
|
||||
"Microsoft.Data.Sqlite": "7.0.5",
|
||||
"Polly": "7.2.3",
|
||||
"Polly.Contrib.WaitAndRetry": "1.1.1",
|
||||
"Polly.Extensions.Http": "3.0.0",
|
||||
"Sentry": "3.33.0",
|
||||
"Sentry.Serilog": "3.33.0",
|
||||
"Serilog": "2.12.0",
|
||||
"Serilog.Enrichers.ClientInfo": "1.3.0",
|
||||
"Serilog.Exceptions": "8.4.0",
|
||||
"Serilog.Sinks.Console": "4.1.0",
|
||||
"Serilog.Sinks.Seq": "5.2.2",
|
||||
"SerilogTimings": "3.0.1",
|
||||
"Speckle.Newtonsoft.Json": "13.0.2",
|
||||
"System.DoubleNumerics": "3.1.3"
|
||||
}
|
||||
},
|
||||
"Speckle.Objects": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[3.0.1-alpha.14, )",
|
||||
"resolved": "3.0.1-alpha.14",
|
||||
"contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==",
|
||||
"dependencies": {
|
||||
"Speckle.Core": "3.0.1-alpha.14"
|
||||
}
|
||||
},
|
||||
"Speckle.Revit.API": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2023.0.0, )",
|
||||
"resolved": "2023.0.0",
|
||||
"contentHash": "tq40eD7psgTbV+epNouYyqfo6+hEi7FmXZqcxEOsAV7zfYyWhL6Rt3vmojkWGNuerGbH6oRI6KIIxrnlCNb8Hw=="
|
||||
},
|
||||
"System.Threading.Tasks.Dataflow": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[6.0.0, )",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 714 B |
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,117 @@
|
||||
using System.Reflection;
|
||||
using Autodesk.Revit.DB;
|
||||
using Revit.Async;
|
||||
using Speckle.Connectors.Utils.Reflection;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.DUI.Models.Card;
|
||||
using Speckle.Connectors.Revit.Plugin;
|
||||
using Speckle.Connectors.Utils;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
using Speckle.Core.Logging;
|
||||
|
||||
namespace Speckle.Connectors.DUI.Bindings;
|
||||
|
||||
internal sealed class BasicConnectorBindingRevit : IBasicConnectorBinding
|
||||
{
|
||||
// POC: name and bridge might be better for them to be protected props?
|
||||
public string Name { get; private set; }
|
||||
public IBridge Parent { get; private set; }
|
||||
|
||||
public BasicConnectorBindingCommands Commands { get; }
|
||||
|
||||
private readonly DocumentModelStore _store;
|
||||
private readonly RevitContext _revitContext;
|
||||
private readonly RevitSettings _revitSettings;
|
||||
|
||||
public BasicConnectorBindingRevit(
|
||||
DocumentModelStore store,
|
||||
RevitSettings revitSettings,
|
||||
IBridge parent,
|
||||
RevitContext revitContext
|
||||
)
|
||||
{
|
||||
Name = "baseBinding";
|
||||
Parent = parent;
|
||||
_store = store;
|
||||
_revitContext = revitContext;
|
||||
_revitSettings = revitSettings;
|
||||
Commands = new BasicConnectorBindingCommands(parent);
|
||||
|
||||
// POC: event binding?
|
||||
_store.DocumentChanged += (_, _) =>
|
||||
{
|
||||
Commands.NotifyDocumentChanged();
|
||||
};
|
||||
}
|
||||
|
||||
public string GetConnectorVersion()
|
||||
{
|
||||
return Assembly.GetAssembly(GetType()).GetVersion();
|
||||
}
|
||||
|
||||
public string GetSourceApplicationName() => _revitSettings.HostSlug.ToLower(); // POC: maybe not right place but... // ANOTHER POC: We should align this naming from somewhere in common DUI projects instead old structs. I know there are other POC comments around this
|
||||
|
||||
public string GetSourceApplicationVersion() => _revitSettings.HostAppVersion; // POC: maybe not right place but...
|
||||
|
||||
public DocumentInfo? GetDocumentInfo()
|
||||
{
|
||||
// POC: not sure why this would ever be null, is this needed?
|
||||
_revitContext.UIApplication.NotNull();
|
||||
|
||||
var doc = _revitContext.UIApplication.ActiveUIDocument?.Document;
|
||||
if (doc is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (doc.IsFamilyDocument)
|
||||
{
|
||||
return new DocumentInfo("", "", "") { Message = "Family environment files not supported by Speckle." };
|
||||
}
|
||||
|
||||
var info = new DocumentInfo(doc.PathName, doc.Title, doc.GetHashCode().ToString());
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public DocumentModelStore GetDocumentState() => _store;
|
||||
|
||||
public void AddModel(ModelCard model) => _store.Models.Add(model);
|
||||
|
||||
public void UpdateModel(ModelCard model) => _store.UpdateModel(model);
|
||||
|
||||
public void RemoveModel(ModelCard model) => _store.RemoveModel(model);
|
||||
|
||||
public void HighlightModel(string modelCardId)
|
||||
{
|
||||
SenderModelCard model = (SenderModelCard)_store.GetModelById(modelCardId);
|
||||
|
||||
var elementIds = model.SendFilter.NotNull().GetObjectIds().Select(ElementId.Parse).ToList();
|
||||
if (elementIds.Count == 0)
|
||||
{
|
||||
Commands.SetModelError(modelCardId, new InvalidOperationException("No objects found to highlight."));
|
||||
return;
|
||||
}
|
||||
|
||||
HighlightObjectsOnView(elementIds);
|
||||
}
|
||||
|
||||
public void HighlightObjects(List<string> objectIds) =>
|
||||
HighlightObjectsOnView(objectIds.Select(ElementId.Parse).ToList());
|
||||
|
||||
private void HighlightObjectsOnView(List<ElementId> objectIds)
|
||||
{
|
||||
// POC: don't know if we can rely on storing the ActiveUIDocument, hence getting it each time
|
||||
var activeUIDoc =
|
||||
_revitContext.UIApplication?.ActiveUIDocument
|
||||
?? throw new SpeckleException("Unable to retrieve active UI document");
|
||||
|
||||
// UiDocument operations should be wrapped into RevitTask, otherwise doesn't work on other tasks.
|
||||
RevitTask.RunAsync(() =>
|
||||
{
|
||||
activeUIDoc.Selection.SetElementIds(objectIds);
|
||||
activeUIDoc.ShowElements(objectIds);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Speckle.Connectors.DUI.Models.Card.SendFilter;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Bindings;
|
||||
|
||||
public class RevitEverythingFilter : EverythingSendFilter
|
||||
{
|
||||
public override List<string> GetObjectIds()
|
||||
{
|
||||
// TODO
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
public override bool CheckExpiry(string[] changedObjectIds)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class RevitSelectionFilter : DirectSelectionSendFilter
|
||||
{
|
||||
public override List<string> GetObjectIds()
|
||||
{
|
||||
return SelectedObjectIds;
|
||||
}
|
||||
|
||||
public override bool CheckExpiry(string[] changedObjectIds)
|
||||
{
|
||||
return SelectedObjectIds.Intersect(changedObjectIds).Any();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Bindings;
|
||||
|
||||
internal abstract class RevitBaseBinding : IBinding
|
||||
{
|
||||
// POC: name and bridge might be better for them to be protected props?
|
||||
public string Name { get; }
|
||||
public IBridge Parent { get; }
|
||||
|
||||
protected readonly DocumentModelStore Store;
|
||||
protected readonly RevitContext RevitContext;
|
||||
|
||||
protected RevitBaseBinding(string name, DocumentModelStore store, IBridge bridge, RevitContext revitContext)
|
||||
{
|
||||
Name = name;
|
||||
Parent = bridge;
|
||||
Store = store;
|
||||
RevitContext = revitContext;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Speckle.Connectors.DUI.Models.Card;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.Utils.Builders;
|
||||
using Speckle.Connectors.Utils.Cancellation;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using Speckle.Connectors.Utils;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Bindings;
|
||||
|
||||
internal class RevitReceiveBinding : IReceiveBinding
|
||||
{
|
||||
public string Name => "receiveBinding";
|
||||
public IBridge Parent { get; }
|
||||
|
||||
private readonly CancellationManager _cancellationManager;
|
||||
private readonly DocumentModelStore _store;
|
||||
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
|
||||
public ReceiveBindingUICommands Commands { get; }
|
||||
|
||||
public RevitReceiveBinding(
|
||||
DocumentModelStore store,
|
||||
CancellationManager cancellationManager,
|
||||
IBridge parent,
|
||||
IUnitOfWorkFactory unitOfWorkFactory
|
||||
)
|
||||
{
|
||||
Parent = parent;
|
||||
_store = store;
|
||||
_unitOfWorkFactory = unitOfWorkFactory;
|
||||
_cancellationManager = cancellationManager;
|
||||
Commands = new ReceiveBindingUICommands(parent);
|
||||
}
|
||||
|
||||
public void CancelReceive(string modelCardId) => _cancellationManager.CancelOperation(modelCardId);
|
||||
|
||||
public async Task Receive(string modelCardId)
|
||||
{
|
||||
using var unitOfWork = _unitOfWorkFactory.Resolve<ReceiveOperation>();
|
||||
try
|
||||
{
|
||||
// Get receiver card
|
||||
if (_store.GetModelById(modelCardId) is not ReceiverModelCard modelCard)
|
||||
{
|
||||
// Handle as GLOBAL ERROR at BrowserBridge
|
||||
throw new InvalidOperationException("No download model card was found.");
|
||||
}
|
||||
|
||||
// Init cancellation token source -> Manager also cancel it if exist before
|
||||
CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId);
|
||||
|
||||
// Receive host objects
|
||||
HostObjectBuilderResult conversionResults = await unitOfWork.Service
|
||||
.Execute(
|
||||
modelCard.AccountId.NotNull(), // POC: I hear -you are saying why we're passing them separately. Not sure pass the DUI3-> Connectors.DUI project dependency to the SDK-> Connector.Utils
|
||||
modelCard.ProjectId.NotNull(),
|
||||
modelCard.ProjectName.NotNull(),
|
||||
modelCard.ModelName.NotNull(),
|
||||
modelCard.SelectedVersionId.NotNull(),
|
||||
cts.Token,
|
||||
(status, progress) =>
|
||||
Commands.SetModelProgress(modelCardId, new ModelCardProgress(modelCardId, status, progress), cts)
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
modelCard.BakedObjectIds = conversionResults.BakedObjectIds.ToList();
|
||||
Commands.SetModelReceiveResult(
|
||||
modelCardId,
|
||||
conversionResults.BakedObjectIds,
|
||||
conversionResults.ConversionResults
|
||||
);
|
||||
}
|
||||
// Catch here specific exceptions if they related to model card.
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// SWALLOW -> UI handles it immediately, so we do not need to handle anything
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
using Autodesk.Revit.DB;
|
||||
using Speckle.Connectors.DUI.Models.Card.SendFilter;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Speckle.Connectors.Revit.Plugin;
|
||||
using Speckle.Connectors.Utils;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
using Speckle.Connectors.DUI.Models.Card;
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using Speckle.Connectors.DUI.Exceptions;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.Utils.Caching;
|
||||
using Speckle.Connectors.Utils.Cancellation;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Bindings;
|
||||
|
||||
internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
|
||||
{
|
||||
// POC:does it need injecting?
|
||||
|
||||
// POC: does it need injecting?
|
||||
private HashSet<string> ChangedObjectIds { get; set; } = new();
|
||||
|
||||
private readonly RevitSettings _revitSettings;
|
||||
private readonly IRevitIdleManager _idleManager;
|
||||
private readonly CancellationManager _cancellationManager;
|
||||
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
|
||||
private readonly ISendConversionCache _sendConversionCache;
|
||||
private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;
|
||||
|
||||
public RevitSendBinding(
|
||||
IRevitIdleManager idleManager,
|
||||
RevitContext revitContext,
|
||||
DocumentModelStore store,
|
||||
CancellationManager cancellationManager,
|
||||
IBridge bridge,
|
||||
IUnitOfWorkFactory unitOfWorkFactory,
|
||||
RevitSettings revitSettings,
|
||||
ISendConversionCache sendConversionCache,
|
||||
ITopLevelExceptionHandler topLevelExceptionHandler
|
||||
)
|
||||
: base("sendBinding", store, bridge, revitContext)
|
||||
{
|
||||
_idleManager = idleManager;
|
||||
_cancellationManager = cancellationManager;
|
||||
_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) =>
|
||||
_topLevelExceptionHandler.CatchUnhandled(() => DocChangeHandler(e));
|
||||
|
||||
Store.DocumentChanged += (_, _) => _topLevelExceptionHandler.CatchUnhandled(OnDocumentChanged);
|
||||
}
|
||||
|
||||
public List<ISendFilter> GetSendFilters()
|
||||
{
|
||||
return new List<ISendFilter> { new RevitSelectionFilter() { IsDefault = true } };
|
||||
}
|
||||
|
||||
public void CancelSend(string modelCardId)
|
||||
{
|
||||
_cancellationManager.CancelOperation(modelCardId);
|
||||
}
|
||||
|
||||
public SendBindingUICommands Commands { get; }
|
||||
|
||||
public async Task Send(string modelCardId)
|
||||
{
|
||||
// Note: removed top level handling thing as it was confusing me
|
||||
try
|
||||
{
|
||||
if (Store.GetModelById(modelCardId) is not SenderModelCard modelCard)
|
||||
{
|
||||
// Handle as GLOBAL ERROR at BrowserBridge
|
||||
throw new InvalidOperationException("No publish model card was found.");
|
||||
}
|
||||
|
||||
// POC: probably the CTS SHOULD be injected as InstancePerLifetimeScope and then
|
||||
// it can be injected where needed instead of passing it around like a bomb :D
|
||||
CancellationTokenSource cts = _cancellationManager.InitCancellationTokenSource(modelCardId);
|
||||
|
||||
using IUnitOfWork<SendOperation<ElementId>> sendOperation = _unitOfWorkFactory.Resolve<
|
||||
SendOperation<ElementId>
|
||||
>();
|
||||
|
||||
List<ElementId> revitObjects = modelCard.SendFilter
|
||||
.NotNull()
|
||||
.GetObjectIds()
|
||||
.Select(id => ElementId.Parse(id))
|
||||
.ToList();
|
||||
|
||||
if (revitObjects.Count == 0)
|
||||
{
|
||||
// Handle as CARD ERROR in this function
|
||||
throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!");
|
||||
}
|
||||
|
||||
var sendInfo = new SendInfo(
|
||||
modelCard.AccountId.NotNull(),
|
||||
modelCard.ProjectId.NotNull(),
|
||||
modelCard.ModelId.NotNull(),
|
||||
_revitSettings.HostSlug.NotNull()
|
||||
);
|
||||
|
||||
var sendResult = await sendOperation.Service
|
||||
.Execute(
|
||||
revitObjects,
|
||||
sendInfo,
|
||||
(status, progress) =>
|
||||
Commands.SetModelProgress(modelCardId, new ModelCardProgress(modelCardId, status, progress), cts),
|
||||
cts.Token
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
Commands.SetModelSendResult(modelCardId, sendResult.RootObjId, sendResult.ConversionResults);
|
||||
}
|
||||
// Catch here specific exceptions if they related to model card.
|
||||
catch (SpeckleSendFilterException e)
|
||||
{
|
||||
Commands.SetModelError(modelCardId, e);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Keeps track of the changed element ids as well as checks if any of them need to trigger
|
||||
/// a filter refresh (e.g., views being added).
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
private void DocChangeHandler(Autodesk.Revit.DB.Events.DocumentChangedEventArgs e)
|
||||
{
|
||||
ICollection<ElementId> addedElementIds = e.GetAddedElementIds();
|
||||
ICollection<ElementId> deletedElementIds = e.GetDeletedElementIds();
|
||||
ICollection<ElementId> modifiedElementIds = e.GetModifiedElementIds();
|
||||
|
||||
foreach (ElementId elementId in addedElementIds)
|
||||
{
|
||||
ChangedObjectIds.Add(elementId.ToString());
|
||||
}
|
||||
|
||||
foreach (ElementId elementId in deletedElementIds)
|
||||
{
|
||||
ChangedObjectIds.Add(elementId.ToString());
|
||||
}
|
||||
|
||||
foreach (ElementId elementId in modifiedElementIds)
|
||||
{
|
||||
ChangedObjectIds.Add(elementId.ToString());
|
||||
}
|
||||
|
||||
// TODO: CHECK IF ANY OF THE ABOVE ELEMENTS NEED TO TRIGGER A FILTER REFRESH
|
||||
_idleManager.SubscribeToIdle(RunExpirationChecks);
|
||||
}
|
||||
|
||||
private void RunExpirationChecks()
|
||||
{
|
||||
var senders = Store.GetSenders();
|
||||
string[] objectIdsList = ChangedObjectIds.ToArray();
|
||||
List<string> expiredSenderIds = new();
|
||||
|
||||
_sendConversionCache.EvictObjects(objectIdsList);
|
||||
|
||||
foreach (SenderModelCard modelCard in senders)
|
||||
{
|
||||
var intersection = modelCard.SendFilter.NotNull().GetObjectIds().Intersect(objectIdsList).ToList();
|
||||
bool isExpired = intersection.Count != 0;
|
||||
if (isExpired)
|
||||
{
|
||||
expiredSenderIds.Add(modelCard.ModelCardId.NotNull());
|
||||
}
|
||||
}
|
||||
|
||||
Commands.SetModelsExpired(expiredSenderIds);
|
||||
ChangedObjectIds = new HashSet<string>();
|
||||
}
|
||||
|
||||
// POC: Will be re-addressed later with better UX with host apps that are friendly on async doc operations.
|
||||
// That's why don't bother for now how to get rid of from dup logic in other bindings.
|
||||
private void OnDocumentChanged()
|
||||
{
|
||||
if (_cancellationManager.NumberOfOperations > 0)
|
||||
{
|
||||
_cancellationManager.CancelAllOperations();
|
||||
Commands.SetGlobalNotification(
|
||||
ToastNotificationType.INFO,
|
||||
"Document Switch",
|
||||
"Operations cancelled because of document swap!"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.Revit.Plugin;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Bindings;
|
||||
|
||||
// POC: we need a base a RevitBaseBinding
|
||||
internal sealed class SelectionBinding : RevitBaseBinding, ISelectionBinding
|
||||
{
|
||||
private readonly IRevitIdleManager _revitIdleManager;
|
||||
private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;
|
||||
|
||||
public SelectionBinding(
|
||||
RevitContext revitContext,
|
||||
DocumentModelStore store,
|
||||
IRevitIdleManager idleManager,
|
||||
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 += (_, _) =>
|
||||
topLevelExceptionHandler.CatchUnhandled(() => _revitIdleManager.SubscribeToIdle(OnSelectionChanged));
|
||||
}
|
||||
|
||||
private void OnSelectionChanged()
|
||||
{
|
||||
Parent.Send(SelectionBindingEvents.SET_SELECTION, GetSelection());
|
||||
}
|
||||
|
||||
public SelectionInfo GetSelection()
|
||||
{
|
||||
// POC: this was also being called on shutdown
|
||||
// probably the bridge needs to be able to know if the plugin has been terminated
|
||||
// also on termination the OnSelectionChanged event needs unwinding
|
||||
var selectionIds = (RevitContext.UIApplication?.ActiveUIDocument?.Selection.GetElementIds())
|
||||
.NotNull()
|
||||
.Select(id => id.ToString())
|
||||
.ToList();
|
||||
return new SelectionInfo(selectionIds, $"{selectionIds.Count} objects selected.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using Autodesk.Revit.DB;
|
||||
using CefSharp;
|
||||
using Speckle.Autofac;
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using Speckle.Connectors.DUI;
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using Speckle.Connectors.DUI.Models;
|
||||
using Speckle.Connectors.Revit.Bindings;
|
||||
using Speckle.Connectors.Revit.HostApp;
|
||||
using Speckle.Connectors.Revit.Operations.Receive;
|
||||
using Speckle.Connectors.Revit.Operations.Send;
|
||||
using Speckle.Connectors.Revit.Plugin;
|
||||
using Speckle.Connectors.Utils;
|
||||
using Speckle.Connectors.Utils.Builders;
|
||||
using Speckle.Connectors.Utils.Caching;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
using Speckle.Core.Models.GraphTraversal;
|
||||
|
||||
namespace Speckle.Connectors.Revit.DependencyInjection;
|
||||
|
||||
// POC: should interface out things that are not
|
||||
public class RevitConnectorModule : ISpeckleModule
|
||||
{
|
||||
public void Load(SpeckleContainerBuilder builder)
|
||||
{
|
||||
builder.AddAutofac();
|
||||
builder.AddConnectorUtils();
|
||||
builder.AddDUI();
|
||||
//builder.AddDUIView();
|
||||
|
||||
builder.AddSingletonInstance<ISyncToThread, RevitContextAccessor>();
|
||||
|
||||
// POC: different versons for different versions of CEF
|
||||
builder.AddSingleton(BindingOptions.DefaultBinder);
|
||||
|
||||
var panel = new CefSharpPanel();
|
||||
panel.Browser.JavascriptObjectRepository.NameConverter = null;
|
||||
|
||||
builder.AddSingleton(panel);
|
||||
builder.AddSingleton<IRevitPlugin, RevitPlugin>();
|
||||
|
||||
// register
|
||||
builder.AddSingleton<DocumentModelStore, RevitDocumentStore>();
|
||||
|
||||
// Storage Schema
|
||||
builder.AddScoped<DocumentModelStorageSchema>();
|
||||
builder.AddScoped<IdStorageSchema>();
|
||||
|
||||
// POC: we need to review the scopes and create a document on what the policy is
|
||||
// and where the UoW should be
|
||||
// register UI bindings
|
||||
builder.AddSingleton<IBinding, TestBinding>();
|
||||
builder.AddSingleton<IBinding, ConfigBinding>("connectorName", "Revit"); // POC: Easier like this for now, should be cleaned up later
|
||||
builder.AddSingleton<IBinding, AccountBinding>();
|
||||
builder.AddSingleton<IBinding, BasicConnectorBindingRevit>();
|
||||
builder.AddSingleton<IBasicConnectorBinding, BasicConnectorBindingRevit>();
|
||||
builder.AddSingleton<IBinding, SelectionBinding>();
|
||||
builder.AddSingleton<IBinding, RevitSendBinding>();
|
||||
builder.AddSingleton<IBinding, RevitReceiveBinding>();
|
||||
builder.AddSingleton<IRevitIdleManager, RevitIdleManager>();
|
||||
|
||||
// send operation and dependencies
|
||||
builder.AddScoped<SendOperation<ElementId>>();
|
||||
builder.AddScoped<IRootObjectBuilder<ElementId>, RevitRootObjectBuilder>();
|
||||
builder.AddSingleton<ISendConversionCache, SendConversionCache>();
|
||||
|
||||
// receive operation and dependencies
|
||||
builder.AddScoped<IHostObjectBuilder, RevitHostObjectBuilder>();
|
||||
builder.AddScoped<ITransactionManager, TransactionManager>();
|
||||
builder.AddSingleton(DefaultTraversal.CreateTraversalFunc());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Autodesk.Revit.DB.ExtensibleStorage;
|
||||
|
||||
namespace Speckle.Connectors.Revit.HostApp;
|
||||
|
||||
public class DocumentModelStorageSchema : IStorageSchema
|
||||
{
|
||||
private readonly Guid _schemaGuid = new("D690F2B4-BDB0-4CB4-8657-17844ADF42AA");
|
||||
|
||||
public Schema GetSchema()
|
||||
{
|
||||
Schema schema = Schema.Lookup(_schemaGuid);
|
||||
if (schema != null)
|
||||
{
|
||||
return schema;
|
||||
}
|
||||
|
||||
using SchemaBuilder builder = new(_schemaGuid);
|
||||
builder.SetSchemaName("DUI3State");
|
||||
builder.AddSimpleField("contents", typeof(string));
|
||||
return builder.Finish();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
namespace Speckle.Connectors.Revit.HostApp;
|
||||
|
||||
// POC: is this really better than injection? :/
|
||||
public static class Elements
|
||||
{
|
||||
public static IEnumerable<Element> GetElements(this Document doc, IEnumerable<string> objectIds)
|
||||
{
|
||||
return objectIds.Select(doc.GetElement).Where(x => x != null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Autodesk.Revit.DB.ExtensibleStorage;
|
||||
|
||||
namespace Speckle.Connectors.Revit.HostApp;
|
||||
|
||||
public interface IStorageSchema
|
||||
{
|
||||
Schema GetSchema();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Autodesk.Revit.DB.ExtensibleStorage;
|
||||
|
||||
namespace Speckle.Connectors.Revit.HostApp;
|
||||
|
||||
public class IdStorageSchema : IStorageSchema
|
||||
{
|
||||
private readonly Guid _schemaGuid = new("D0E2AD18-0DE0-41CF-A2B7-5384267061D7");
|
||||
|
||||
public Schema GetSchema()
|
||||
{
|
||||
Schema schema = Schema.Lookup(_schemaGuid);
|
||||
if (schema != null)
|
||||
{
|
||||
return schema;
|
||||
}
|
||||
|
||||
using SchemaBuilder builder = new(_schemaGuid);
|
||||
builder.SetSchemaName("DataStorageUniqueId");
|
||||
builder.AddSimpleField("Id", typeof(Guid));
|
||||
return builder.Finish();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
using System.Diagnostics;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.DB.ExtensibleStorage;
|
||||
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.Utils;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
using Speckle.Core.Logging;
|
||||
using Speckle.Newtonsoft.Json;
|
||||
|
||||
namespace Speckle.Connectors.Revit.HostApp;
|
||||
|
||||
// POC: should be interfaced out
|
||||
internal sealed class RevitDocumentStore : DocumentModelStore
|
||||
{
|
||||
// POC: move to somewhere central?
|
||||
private static readonly Guid s_revitDocumentStoreId = new("D35B3695-EDC9-4E15-B62A-D3FC2CB83FA3");
|
||||
|
||||
private readonly RevitContext _revitContext;
|
||||
private readonly IRevitIdleManager _idleManager;
|
||||
private readonly DocumentModelStorageSchema _documentModelStorageSchema;
|
||||
private readonly IdStorageSchema _idStorageSchema;
|
||||
|
||||
public RevitDocumentStore(
|
||||
IRevitIdleManager idleManager,
|
||||
RevitContext revitContext,
|
||||
JsonSerializerSettings serializerSettings,
|
||||
DocumentModelStorageSchema documentModelStorageSchema,
|
||||
IdStorageSchema idStorageSchema,
|
||||
ITopLevelExceptionHandler topLevelExceptionHandler
|
||||
)
|
||||
: base(serializerSettings, true)
|
||||
{
|
||||
_idleManager = idleManager;
|
||||
_revitContext = revitContext;
|
||||
_documentModelStorageSchema = documentModelStorageSchema;
|
||||
_idStorageSchema = idStorageSchema;
|
||||
|
||||
UIApplication uiApplication = _revitContext.UIApplication.NotNull();
|
||||
|
||||
uiApplication.ViewActivated += (s, e) => topLevelExceptionHandler.CatchUnhandled(() => OnViewActivated(s, e));
|
||||
|
||||
uiApplication.Application.DocumentOpening += (_, _) =>
|
||||
topLevelExceptionHandler.CatchUnhandled(() => IsDocumentInit = false);
|
||||
|
||||
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".
|
||||
ReadFromFile();
|
||||
OnDocumentChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is the place where we track document switch for new document -> Responsible to Read from new doc
|
||||
/// </summary>
|
||||
private void OnViewActivated(object sender, ViewActivatedEventArgs e)
|
||||
{
|
||||
if (e.Document == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Return only if we are switching views that belongs to same document
|
||||
if (e.PreviousActiveView?.Document != null && e.PreviousActiveView.Document.Equals(e.CurrentActiveView.Document))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IsDocumentInit = true;
|
||||
_idleManager.SubscribeToIdle(() =>
|
||||
{
|
||||
ReadFromFile();
|
||||
OnDocumentChanged();
|
||||
});
|
||||
}
|
||||
|
||||
public override void WriteToFile()
|
||||
{
|
||||
var doc = _revitContext.UIApplication?.ActiveUIDocument.Document;
|
||||
// POC: this can happen? A: Not really, imho (dim)
|
||||
if (doc == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RevitTask.RunAsync(() =>
|
||||
{
|
||||
using Transaction t = new(doc, "Speckle Write State");
|
||||
t.Start();
|
||||
using DataStorage ds = GetSettingsDataStorage(doc) ?? DataStorage.Create(doc);
|
||||
|
||||
using Entity stateEntity = new(_documentModelStorageSchema.GetSchema());
|
||||
string serializedModels = Serialize();
|
||||
stateEntity.Set("contents", serializedModels);
|
||||
|
||||
using Entity idEntity = new(_idStorageSchema.GetSchema());
|
||||
idEntity.Set("Id", s_revitDocumentStoreId);
|
||||
|
||||
ds.SetEntity(idEntity);
|
||||
ds.SetEntity(stateEntity);
|
||||
t.Commit();
|
||||
});
|
||||
}
|
||||
|
||||
public override void ReadFromFile()
|
||||
{
|
||||
try
|
||||
{
|
||||
var stateEntity = GetSpeckleEntity(_revitContext.UIApplication?.ActiveUIDocument?.Document);
|
||||
if (stateEntity == null || !stateEntity.IsValid())
|
||||
{
|
||||
Models = new();
|
||||
return;
|
||||
}
|
||||
|
||||
string modelsString = stateEntity.Get<string>("contents");
|
||||
Models = Deserialize(modelsString).NotNull();
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
Models = new();
|
||||
Debug.WriteLine(ex.Message); // POC: Log here error and notify UI that cards not read succesfully
|
||||
}
|
||||
}
|
||||
|
||||
private DataStorage? GetSettingsDataStorage(Document doc)
|
||||
{
|
||||
using FilteredElementCollector collector = new(doc);
|
||||
FilteredElementCollector dataStorages = collector.OfClass(typeof(DataStorage));
|
||||
|
||||
foreach (Element element in dataStorages)
|
||||
{
|
||||
DataStorage dataStorage = (DataStorage)element;
|
||||
Entity settingIdEntity = dataStorage.GetEntity(_idStorageSchema.GetSchema());
|
||||
if (!settingIdEntity.IsValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Guid id = settingIdEntity.Get<Guid>("Id");
|
||||
if (!id.Equals(s_revitDocumentStoreId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return dataStorage;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Entity? GetSpeckleEntity(Document? doc)
|
||||
{
|
||||
if (doc is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
using FilteredElementCollector collector = new(doc);
|
||||
|
||||
FilteredElementCollector dataStorages = collector.OfClass(typeof(DataStorage));
|
||||
foreach (Element element in dataStorages)
|
||||
{
|
||||
DataStorage dataStorage = (DataStorage)element;
|
||||
Entity settingEntity = dataStorage.GetEntity(_documentModelStorageSchema.GetSchema());
|
||||
if (!settingEntity.IsValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return settingEntity;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Operations.Receive;
|
||||
|
||||
public interface ITransactionManager : IDisposable
|
||||
{
|
||||
TransactionStatus CommitSubtransaction();
|
||||
TransactionStatus CommitTransaction();
|
||||
void RollbackSubTransaction();
|
||||
void RollbackTransaction();
|
||||
void StartSubtransaction();
|
||||
void StartTransaction();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Revit.Async;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Operations.Receive;
|
||||
|
||||
internal class RevitContextAccessor : ISyncToThread
|
||||
{
|
||||
public Task<T> RunOnThread<T>(Func<T> func) => RevitTask.RunAsync(func);
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using Speckle.Connectors.Utils.Builders;
|
||||
using Speckle.Connectors.Utils.Conversion;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Core.Logging;
|
||||
using Speckle.Core.Models.GraphTraversal;
|
||||
using Speckle.Core.Models;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
using Autodesk.Revit.DB;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Operations.Receive;
|
||||
|
||||
/// <summary>
|
||||
/// Potentially consolidate all application specific IHostObjectBuilders
|
||||
/// https://spockle.atlassian.net/browse/DUI3-465
|
||||
/// </summary>
|
||||
internal class RevitHostObjectBuilder : IHostObjectBuilder, IDisposable
|
||||
{
|
||||
private readonly IRootToHostConverter _converter;
|
||||
private readonly IRevitConversionContextStack _contextStack;
|
||||
private readonly GraphTraversal _traverseFunction;
|
||||
private readonly ITransactionManager _transactionManager;
|
||||
|
||||
public RevitHostObjectBuilder(
|
||||
IRootToHostConverter converter,
|
||||
IRevitConversionContextStack contextStack,
|
||||
GraphTraversal traverseFunction,
|
||||
ITransactionManager transactionManager
|
||||
)
|
||||
{
|
||||
_converter = converter;
|
||||
_contextStack = contextStack;
|
||||
_traverseFunction = traverseFunction;
|
||||
_transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
public HostObjectBuilderResult Build(
|
||||
Base rootObject,
|
||||
string projectName,
|
||||
string modelName,
|
||||
Action<string, double?>? onOperationProgressed,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var objectsToConvert = _traverseFunction
|
||||
.TraverseWithProgress(rootObject, onOperationProgressed, cancellationToken)
|
||||
.Where(obj => obj.Current is not Collection);
|
||||
|
||||
using TransactionGroup transactionGroup = new(_contextStack.Current.Document, $"Received data from {projectName}");
|
||||
transactionGroup.Start();
|
||||
_transactionManager.StartTransaction();
|
||||
|
||||
var conversionResults = BakeObjects(objectsToConvert);
|
||||
|
||||
_transactionManager.CommitTransaction();
|
||||
transactionGroup.Assimilate();
|
||||
|
||||
return conversionResults;
|
||||
}
|
||||
|
||||
// POC: Potentially refactor out into an IObjectBaker.
|
||||
private HostObjectBuilderResult BakeObjects(IEnumerable<TraversalContext> objectsGraph)
|
||||
{
|
||||
var conversionResults = new List<ReceiveConversionResult>();
|
||||
var bakedObjectIds = new List<string>();
|
||||
|
||||
foreach (TraversalContext tc in objectsGraph)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = _converter.Convert(tc.Current);
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
conversionResults.Add(new(Status.ERROR, tc.Current, null, null, ex));
|
||||
}
|
||||
}
|
||||
|
||||
return new(bakedObjectIds, conversionResults);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_transactionManager?.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
using Autodesk.Revit.DB;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Operations.Receive;
|
||||
|
||||
/// <summary>
|
||||
/// Is responsible for all functionality regarding subtransactions, transactions, and transaction groups.
|
||||
/// This includes starting, pausing, committing, and rolling back transactions
|
||||
/// </summary>
|
||||
public sealed class TransactionManager : ITransactionManager
|
||||
{
|
||||
private readonly IRevitConversionContextStack _contextStack;
|
||||
private Document Document => _contextStack.Current.Document;
|
||||
|
||||
public TransactionManager(IRevitConversionContextStack contextStack)
|
||||
{
|
||||
_contextStack = contextStack;
|
||||
}
|
||||
|
||||
// poc : these are being disposed. I'm not sure why I need to supress this warning
|
||||
#pragma warning disable CA2213 // Disposable fields should be disposed
|
||||
private Transaction? _transaction;
|
||||
private SubTransaction? _subTransaction;
|
||||
#pragma warning restore CA2213 // Disposable fields should be disposed
|
||||
|
||||
public void StartTransaction()
|
||||
{
|
||||
if (_transaction == null || !_transaction.IsValidObject || _transaction.GetStatus() != TransactionStatus.Started)
|
||||
{
|
||||
_transaction = new Transaction(Document, "Speckle Transaction");
|
||||
var failOpts = _transaction.GetFailureHandlingOptions();
|
||||
// POC: make sure to implement and add the failure preprocessor
|
||||
// https://spockle.atlassian.net/browse/DUI3-461
|
||||
//failOpts.SetFailuresPreprocessor(_errorPreprocessingService);
|
||||
failOpts.SetClearAfterRollback(true);
|
||||
_transaction.SetFailureHandlingOptions(failOpts);
|
||||
_transaction.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public TransactionStatus CommitTransaction()
|
||||
{
|
||||
if (
|
||||
_subTransaction != null
|
||||
&& _subTransaction.IsValidObject
|
||||
&& _subTransaction.GetStatus() == TransactionStatus.Started
|
||||
)
|
||||
{
|
||||
var status = _subTransaction.Commit();
|
||||
if (status != TransactionStatus.Committed)
|
||||
{
|
||||
// POC: handle failed commit
|
||||
//HandleFailedCommit(status);
|
||||
}
|
||||
}
|
||||
if (_transaction != null && _transaction.IsValidObject && _transaction.GetStatus() == TransactionStatus.Started)
|
||||
{
|
||||
var status = _transaction.Commit();
|
||||
if (status != TransactionStatus.Committed)
|
||||
{
|
||||
// POC: handle failed commit
|
||||
//HandleFailedCommit(status);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
return TransactionStatus.Uninitialized;
|
||||
}
|
||||
|
||||
public void RollbackTransaction()
|
||||
{
|
||||
RollbackSubTransaction();
|
||||
if (_transaction != null && _transaction.IsValidObject && _transaction.GetStatus() == TransactionStatus.Started)
|
||||
{
|
||||
_transaction.RollBack();
|
||||
}
|
||||
}
|
||||
|
||||
public void StartSubtransaction()
|
||||
{
|
||||
StartTransaction();
|
||||
if (
|
||||
_subTransaction == null
|
||||
|| !_subTransaction.IsValidObject
|
||||
|| _subTransaction.GetStatus() != TransactionStatus.Started
|
||||
)
|
||||
{
|
||||
_subTransaction = new SubTransaction(Document);
|
||||
_subTransaction.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public TransactionStatus CommitSubtransaction()
|
||||
{
|
||||
if (_subTransaction != null && _subTransaction.IsValidObject)
|
||||
{
|
||||
var status = _subTransaction.Commit();
|
||||
if (status != TransactionStatus.Committed)
|
||||
{
|
||||
// POC: handle failed commit
|
||||
//HandleFailedCommit(status);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
return TransactionStatus.Uninitialized;
|
||||
}
|
||||
|
||||
public void RollbackSubTransaction()
|
||||
{
|
||||
if (
|
||||
_subTransaction != null
|
||||
&& _subTransaction.IsValidObject
|
||||
&& _subTransaction.GetStatus() == TransactionStatus.Started
|
||||
)
|
||||
{
|
||||
_subTransaction.RollBack();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_subTransaction?.Dispose();
|
||||
_transaction?.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
using System.Diagnostics;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Core.Models;
|
||||
using Autodesk.Revit.DB;
|
||||
using Speckle.Connectors.DUI.Exceptions;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
using Speckle.Connectors.Utils.Builders;
|
||||
using Speckle.Connectors.Utils.Caching;
|
||||
using Speckle.Connectors.Utils.Conversion;
|
||||
using Speckle.Connectors.Utils.Operations;
|
||||
using Speckle.Core.Logging;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Operations.Send;
|
||||
|
||||
public class RevitRootObjectBuilder : IRootObjectBuilder<ElementId>
|
||||
{
|
||||
// POC: SendSelection and RevitConversionContextStack should be interfaces, former needs interfaces
|
||||
private readonly IRootToSpeckleConverter _converter;
|
||||
private readonly IRevitConversionContextStack _contextStack;
|
||||
private readonly Dictionary<string, Collection> _collectionCache;
|
||||
private readonly Collection _rootObject;
|
||||
private readonly ISendConversionCache _sendConversionCache;
|
||||
|
||||
public RevitRootObjectBuilder(
|
||||
IRootToSpeckleConverter converter,
|
||||
IRevitConversionContextStack contextStack,
|
||||
ISendConversionCache sendConversionCache
|
||||
)
|
||||
{
|
||||
_converter = converter;
|
||||
_contextStack = contextStack;
|
||||
_sendConversionCache = sendConversionCache;
|
||||
// Note, this class is instantiated per unit of work (aka per send operation), so we can safely initialize what we need in here.
|
||||
_collectionCache = new Dictionary<string, Collection>();
|
||||
_rootObject = new Collection()
|
||||
{
|
||||
name = _contextStack.Current.Document.PathName.Split('\\').Last().Split('.').First()
|
||||
};
|
||||
}
|
||||
|
||||
public RootObjectBuilderResult Build(
|
||||
IReadOnlyList<ElementId> objects,
|
||||
SendInfo sendInfo,
|
||||
Action<string, double?>? onOperationProgressed = null,
|
||||
CancellationToken ct = default
|
||||
)
|
||||
{
|
||||
var doc = _contextStack.Current.Document;
|
||||
|
||||
if (doc.IsFamilyDocument)
|
||||
{
|
||||
throw new SpeckleException("Family Environment documents are not supported.");
|
||||
}
|
||||
|
||||
var revitElements = new List<Element>();
|
||||
|
||||
foreach (var id in objects)
|
||||
{
|
||||
var el = _contextStack.Current.Document.GetElement(id);
|
||||
if (el != null)
|
||||
{
|
||||
revitElements.Add(el);
|
||||
}
|
||||
}
|
||||
|
||||
if (revitElements.Count == 0)
|
||||
{
|
||||
throw new SpeckleSendFilterException("No objects were found. Please update your send filter!");
|
||||
}
|
||||
|
||||
var countProgress = 0; // because for(int i = 0; ...) loops are so last year
|
||||
var cacheHitCount = 0;
|
||||
List<SendConversionResult> results = new(revitElements.Count);
|
||||
var path = new string[2];
|
||||
foreach (Element revitElement in revitElements)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
var cat = revitElement.Category.Name;
|
||||
path[0] = doc.GetElement(revitElement.LevelId) is not Level level ? "No level" : level.Name;
|
||||
path[1] = cat;
|
||||
var collection = GetAndCreateObjectHostCollection(path);
|
||||
|
||||
var applicationId = revitElement.Id.ToString();
|
||||
try
|
||||
{
|
||||
Base converted;
|
||||
if (_sendConversionCache.TryGetValue(sendInfo.ProjectId, applicationId, out ObjectReference value))
|
||||
{
|
||||
converted = value;
|
||||
cacheHitCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
converted = _converter.Convert(revitElement);
|
||||
converted.applicationId = applicationId;
|
||||
}
|
||||
|
||||
collection.elements.Add(converted);
|
||||
results.Add(new(Status.SUCCESS, applicationId, revitElement.GetType().Name, converted));
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
results.Add(new(Status.ERROR, applicationId, revitElement.GetType().Name, null, ex));
|
||||
// POC: add logging
|
||||
}
|
||||
|
||||
onOperationProgressed?.Invoke("Converting", (double)++countProgress / revitElements.Count);
|
||||
}
|
||||
|
||||
// POC: Log would be nice, or can be removed.
|
||||
Debug.WriteLine(
|
||||
$"Cache hit count {cacheHitCount} out of {objects.Count} ({(double)cacheHitCount / objects.Count})"
|
||||
);
|
||||
|
||||
return new(_rootObject, results);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and nests collections based on the provided path within the root collection provided. This will not return a new collection each time is called, but an existing one if one is found.
|
||||
/// For example, you can use this to use (or re-use) a new collection for a path of (level, category) as it's currently implemented.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
private Collection GetAndCreateObjectHostCollection(string[] path)
|
||||
{
|
||||
string fullPathName = string.Concat(path);
|
||||
if (_collectionCache.TryGetValue(fullPathName, out Collection value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
string flatPathName = "";
|
||||
Collection previousCollection = _rootObject;
|
||||
|
||||
foreach (var pathItem in path)
|
||||
{
|
||||
flatPathName += pathItem;
|
||||
Collection childCollection;
|
||||
if (_collectionCache.TryGetValue(flatPathName, out Collection? collection))
|
||||
{
|
||||
childCollection = collection;
|
||||
}
|
||||
else
|
||||
{
|
||||
childCollection = new Collection(pathItem, "layer");
|
||||
previousCollection.elements.Add(childCollection);
|
||||
_collectionCache[flatPathName] = childCollection;
|
||||
}
|
||||
|
||||
previousCollection = childCollection;
|
||||
}
|
||||
|
||||
return previousCollection;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<Page x:Class="Speckle.Connectors.Revit.CefSharpPanel"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:cefSharp="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"
|
||||
xmlns:local="clr-namespace:Speckle.Connectors.DUI;assembly=Speckle.Connectors.DUI"
|
||||
|
||||
mc:Ignorable="d"
|
||||
Title="Panel" Height="450" Width="800">
|
||||
<Grid>
|
||||
<cefSharp:ChromiumWebBrowser
|
||||
Name="Browser"
|
||||
Grid.Row="0"
|
||||
Address="{x:Static local:Url.NetlifyString}" />
|
||||
</Grid>
|
||||
</Page>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Windows.Controls;
|
||||
using Autodesk.Revit.UI;
|
||||
using CefSharp;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Speckle.Connectors.Revit;
|
||||
|
||||
public partial class CefSharpPanel : Page, Autodesk.Revit.UI.IDockablePaneProvider
|
||||
{
|
||||
public CefSharpPanel()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void ExecuteScriptAsync(string script) =>
|
||||
Browser.Dispatcher.Invoke(() => Browser.ExecuteScriptAsync(script), DispatcherPriority.Background);
|
||||
|
||||
public void ShowDevTools() => Browser.ShowDevTools();
|
||||
|
||||
public void SetupDockablePane(Autodesk.Revit.UI.DockablePaneProviderData data)
|
||||
{
|
||||
data.FrameworkElement = this;
|
||||
data.InitialState = new Autodesk.Revit.UI.DockablePaneState
|
||||
{
|
||||
DockPosition = DockPosition.Tabbed,
|
||||
TabBehind = Autodesk.Revit.UI.DockablePanes.BuiltInDockablePanes.ProjectBrowser
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Speckle.Connectors.Revit.Plugin;
|
||||
|
||||
// POC: needs interface
|
||||
// is probably misnamed, perhaps OnIdleCallbackManager
|
||||
internal interface IRevitIdleManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Subscribe deferred action to Idling event to run it whenever Revit becomes idle.
|
||||
/// </summary>
|
||||
/// <param name="action"> Action to call whenever Revit becomes Idle.</param>
|
||||
/// some events in host app are trigerred many times, we might get 10x per object
|
||||
/// Making this more like a deferred action, so we don't update the UI many times
|
||||
void SubscribeToIdle(Action action);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Speckle.Connectors.Revit.Plugin;
|
||||
|
||||
internal interface IRevitPlugin
|
||||
{
|
||||
void Initialise();
|
||||
void Shutdown();
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Autodesk.Revit.Attributes;
|
||||
using Autodesk.Revit.DB;
|
||||
using Autodesk.Revit.UI;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Plugin;
|
||||
|
||||
[Transaction(TransactionMode.Manual)]
|
||||
internal sealed class SpeckleRevitCommand : IExternalCommand
|
||||
{
|
||||
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
|
||||
{
|
||||
DockablePane panel = commandData.Application.GetDockablePane(RevitExternalApplication.DoackablePanelId);
|
||||
panel.Show();
|
||||
|
||||
return Result.Succeeded;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using Autodesk.Revit.UI;
|
||||
using Speckle.Autofac.DependencyInjection;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Speckle.Autofac;
|
||||
using Speckle.Connectors.Utils;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Plugin;
|
||||
|
||||
internal sealed class RevitExternalApplication : IExternalApplication
|
||||
{
|
||||
private IRevitPlugin? _revitPlugin;
|
||||
|
||||
private SpeckleContainer? _container;
|
||||
|
||||
// POC: this is getting hard coded - need a way of injecting it
|
||||
// I am beginning to think the shared project is not the way
|
||||
// and an assembly which is invoked with some specialisation is the right way to go
|
||||
// maybe subclassing, or some hook to inject som configuration
|
||||
private readonly RevitSettings _revitSettings;
|
||||
|
||||
// POC: move to somewhere central?
|
||||
public static readonly DockablePaneId DoackablePanelId = new(new Guid("{f7b5da7c-366c-4b13-8455-b56f433f461e}"));
|
||||
|
||||
public RevitExternalApplication()
|
||||
{
|
||||
// POC: load from JSON file?
|
||||
_revitSettings = new RevitSettings(
|
||||
"Speckle New UI",
|
||||
"Speckle",
|
||||
"Speckle New UI",
|
||||
"2023",
|
||||
"Speckle New UI",
|
||||
"Revit",
|
||||
new[] { Path.GetDirectoryName(typeof(RevitExternalApplication).Assembly.Location) },
|
||||
"Revit Connector",
|
||||
"2023" //POC: app version?
|
||||
);
|
||||
}
|
||||
|
||||
public Result OnStartup(UIControlledApplication application)
|
||||
{
|
||||
try
|
||||
{
|
||||
// POC: not sure what this is doing... could be messing up our Aliasing????
|
||||
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolver.OnAssemblyResolve<RevitExternalApplication>;
|
||||
var containerBuilder = SpeckleContainerBuilder.CreateInstance();
|
||||
// init DI
|
||||
_container = containerBuilder
|
||||
.LoadAutofacModules(Assembly.GetExecutingAssembly(), _revitSettings.ModuleFolders.NotNull())
|
||||
.AddSingleton(_revitSettings) // apply revit settings into DI
|
||||
.AddSingleton(application) // inject UIControlledApplication application
|
||||
.Build();
|
||||
|
||||
// resolve root object
|
||||
_revitPlugin = _container.Resolve<IRevitPlugin>();
|
||||
_revitPlugin.Initialise();
|
||||
}
|
||||
catch (Exception e) when (!e.IsFatal())
|
||||
{
|
||||
// POC: feedback?
|
||||
return Result.Failed;
|
||||
}
|
||||
|
||||
return Result.Succeeded;
|
||||
}
|
||||
|
||||
public Result OnShutdown(UIControlledApplication application)
|
||||
{
|
||||
try
|
||||
{
|
||||
// POC: could this be more a generic Connector Init() Shutdown()
|
||||
// possibly with injected pieces or with some abstract methods?
|
||||
// need to look for commonality
|
||||
_revitPlugin?.Shutdown();
|
||||
}
|
||||
catch (Exception e) when (!e.IsFatal())
|
||||
{
|
||||
// POC: feedback?
|
||||
return Result.Failed;
|
||||
}
|
||||
|
||||
return Result.Succeeded;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Collections.Concurrent;
|
||||
using Autodesk.Revit.UI;
|
||||
using Autodesk.Revit.UI.Events;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Plugin;
|
||||
|
||||
// POC: needs interface
|
||||
// is probably misnamed, perhaps OnIdleCallbackManager
|
||||
internal sealed class RevitIdleManager : IRevitIdleManager
|
||||
{
|
||||
private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;
|
||||
private readonly UIApplication _uiApplication;
|
||||
|
||||
private readonly ConcurrentDictionary<string, Action> _calls = new();
|
||||
|
||||
// POC: still not thread safe
|
||||
private volatile bool _hasSubscribed;
|
||||
|
||||
public RevitIdleManager(RevitContext revitContext, ITopLevelExceptionHandler topLevelExceptionHandler)
|
||||
{
|
||||
_topLevelExceptionHandler = topLevelExceptionHandler;
|
||||
_uiApplication = revitContext.UIApplication!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribe deferred action to Idling event to run it whenever Revit becomes idle.
|
||||
/// </summary>
|
||||
/// <param name="action"> Action to call whenever Revit becomes Idle.</param>
|
||||
/// some events in host app are trigerred many times, we might get 10x per object
|
||||
/// Making this more like a deferred action, so we don't update the UI many times
|
||||
public void SubscribeToIdle(Action action)
|
||||
{
|
||||
// POC: key for method is brittle | thread safe is not this is
|
||||
// I want to be called back ONCE when the host app has become idle once more
|
||||
// would this work "action.Method.Name" with anonymous function, including the SAME function
|
||||
// does this work across class instances? Should it? What about functions of the same name? Fully qualified name might be better
|
||||
_calls[action.Method.Name] = action;
|
||||
|
||||
if (_hasSubscribed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_hasSubscribed = true;
|
||||
_uiApplication.Idling += RevitAppOnIdle;
|
||||
}
|
||||
|
||||
private void RevitAppOnIdle(object sender, IdlingEventArgs e)
|
||||
{
|
||||
_topLevelExceptionHandler.CatchUnhandled(() =>
|
||||
{
|
||||
foreach (KeyValuePair<string, Action> kvp in _calls)
|
||||
{
|
||||
kvp.Value.Invoke();
|
||||
}
|
||||
|
||||
_calls.Clear();
|
||||
_uiApplication.Idling -= RevitAppOnIdle;
|
||||
|
||||
// setting last will delay ntering re-subscritption
|
||||
_hasSubscribed = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
using Autodesk.Revit.UI;
|
||||
using Autodesk.Revit.ApplicationServices;
|
||||
using Revit.Async;
|
||||
using CefSharp;
|
||||
using Speckle.Connectors.DUI.Bridge;
|
||||
using Speckle.Connectors.DUI.Bindings;
|
||||
using System.Diagnostics;
|
||||
using Speckle.Converters.RevitShared.Helpers;
|
||||
using Speckle.Core.Logging;
|
||||
using System.Reflection;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Media;
|
||||
using System.IO;
|
||||
|
||||
namespace Speckle.Connectors.Revit.Plugin;
|
||||
|
||||
internal sealed class RevitPlugin : IRevitPlugin
|
||||
{
|
||||
private readonly UIControlledApplication _uIControlledApplication;
|
||||
private readonly RevitSettings _revitSettings;
|
||||
private readonly IEnumerable<Lazy<IBinding>> _bindings; // should be lazy to ensure the bindings are not created too early
|
||||
private readonly BindingOptions _bindingOptions;
|
||||
private readonly RevitContext _revitContext;
|
||||
private readonly CefSharpPanel _cefSharpPanel;
|
||||
|
||||
public RevitPlugin(
|
||||
UIControlledApplication uIControlledApplication,
|
||||
RevitSettings revitSettings,
|
||||
IEnumerable<Lazy<IBinding>> bindings,
|
||||
BindingOptions bindingOptions,
|
||||
RevitContext revitContext,
|
||||
CefSharpPanel cefSharpPanel
|
||||
)
|
||||
{
|
||||
_uIControlledApplication = uIControlledApplication;
|
||||
_revitSettings = revitSettings;
|
||||
_bindings = bindings;
|
||||
_bindingOptions = bindingOptions;
|
||||
_revitContext = revitContext;
|
||||
_cefSharpPanel = cefSharpPanel;
|
||||
}
|
||||
|
||||
public void Initialise()
|
||||
{
|
||||
// Create and register panels before app initialized. this is needed for double-click file open
|
||||
CreateTabAndRibbonPanel(_uIControlledApplication);
|
||||
RegisterDockablePane();
|
||||
_uIControlledApplication.ControlledApplication.ApplicationInitialized += OnApplicationInitialized;
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
// POC: should we be cleaning up the RibbonPanel etc...
|
||||
// Should we be indicating to any active in-flight functions that we are being closed?
|
||||
}
|
||||
|
||||
// POC: Could be injected but maybe not worthwhile
|
||||
private void CreateTabAndRibbonPanel(UIControlledApplication application)
|
||||
{
|
||||
// POC: some top-level handling and feedback here
|
||||
try
|
||||
{
|
||||
application.CreateRibbonTab(_revitSettings.RevitTabName);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
// exception occurs when the speckle tab has already been created.
|
||||
// this happens when both the dui2 and the dui3 connectors are installed. Can be safely ignored.
|
||||
}
|
||||
|
||||
RibbonPanel specklePanel = application.CreateRibbonPanel(_revitSettings.RevitTabName, _revitSettings.RevitTabTitle);
|
||||
var dui3Button = (PushButton)
|
||||
specklePanel.AddItem(
|
||||
new PushButtonData(
|
||||
_revitSettings.RevitButtonName,
|
||||
_revitSettings.RevitButtonText,
|
||||
typeof(RevitExternalApplication).Assembly.Location,
|
||||
typeof(SpeckleRevitCommand).FullName
|
||||
)
|
||||
);
|
||||
|
||||
string path = typeof(RevitPlugin).Assembly.Location;
|
||||
dui3Button.Image = LoadPngImgSource(
|
||||
$"Speckle.Connectors.Revit{_revitSettings.RevitVersionName}.Assets.logo16.png",
|
||||
path
|
||||
);
|
||||
dui3Button.LargeImage = LoadPngImgSource(
|
||||
$"Speckle.Connectors.Revit{_revitSettings.RevitVersionName}.Assets.logo32.png",
|
||||
path
|
||||
);
|
||||
dui3Button.ToolTipImage = LoadPngImgSource(
|
||||
$"Speckle.Connectors.Revit{_revitSettings.RevitVersionName}.Assets.logo32.png",
|
||||
path
|
||||
);
|
||||
dui3Button.ToolTip = "Speckle Connector for Revit New UI";
|
||||
//dui3Button.AvailabilityClassName = typeof(CmdAvailabilityViews).FullName;
|
||||
dui3Button.SetContextualHelp(new ContextualHelp(ContextualHelpType.Url, "https://speckle.systems"));
|
||||
}
|
||||
|
||||
private void OnApplicationInitialized(object sender, Autodesk.Revit.DB.Events.ApplicationInitializedEventArgs e)
|
||||
{
|
||||
var uiApplication = new UIApplication(sender as Application);
|
||||
_revitContext.UIApplication = uiApplication;
|
||||
|
||||
// POC: might be worth to interface this out, we shall see...
|
||||
RevitTask.Initialize(uiApplication);
|
||||
|
||||
PostApplicationInit(); // for double-click file open
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Actions to run after UiApplication initialized. This is needed for double-click file open issue.
|
||||
/// </summary>
|
||||
private void PostApplicationInit()
|
||||
{
|
||||
// binding the bindings to each bridge
|
||||
foreach (IBinding binding in _bindings.Select(x => x.Value))
|
||||
{
|
||||
Debug.WriteLine(binding.Name);
|
||||
binding.Parent.AssociateWithBinding(
|
||||
binding,
|
||||
_cefSharpPanel.ExecuteScriptAsync,
|
||||
_cefSharpPanel,
|
||||
_cefSharpPanel.ShowDevTools
|
||||
);
|
||||
}
|
||||
|
||||
_cefSharpPanel.Browser.IsBrowserInitializedChanged += (sender, e) =>
|
||||
{
|
||||
if (e.NewValue is false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (IBinding binding in _bindings.Select(x => x.Value))
|
||||
{
|
||||
IBridge bridge = binding.Parent;
|
||||
|
||||
_cefSharpPanel.Browser.JavascriptObjectRepository.Register(
|
||||
bridge.FrontendBoundName,
|
||||
bridge,
|
||||
true,
|
||||
_bindingOptions
|
||||
);
|
||||
}
|
||||
|
||||
// POC: Below line seems unneccesary but not removing just in case we did it like this? Maybe check it later
|
||||
// with some other revit connectors again since CefSharp version is different
|
||||
// _cefSharpPanel.Browser.Load("https://boisterous-douhua-e3cefb.netlify.app/");
|
||||
|
||||
// POC: not sure where this comes from
|
||||
#if REVIT2020
|
||||
// NOTE: Cef65 does not work with DUI3 in yarn dev mode. To test things you need to do `yarn build` and serve the build
|
||||
// folder at port 3000 (or change it to something else if you want to). Guru meditation: Je sais, pas ideal. Mais q'est que nous pouvons faire? Rien. C'est l'autodesk vie.
|
||||
// NOTE: To run the ui from a build, follow these steps:
|
||||
// - run `yarn build` in the DUI3 folder
|
||||
// - run ` PORT=3003 node .output/server/index.mjs` after the build
|
||||
|
||||
CefSharpPanel.Browser.Load("http://localhost:3003");
|
||||
CefSharpPanel.Browser.ShowDevTools();
|
||||
#endif
|
||||
#if REVIT2023
|
||||
CefSharpPanel.Browser.Load("http://localhost:8082");
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
private void RegisterDockablePane()
|
||||
{
|
||||
CefSharpSettings.ConcurrentTaskExecution = true;
|
||||
|
||||
// Registering dockable pane should happen before UiApplication is initialized with RevitTask.
|
||||
// Otherwise pane cannot be registered for double-click file open.
|
||||
_uIControlledApplication.RegisterDockablePane(
|
||||
RevitExternalApplication.DoackablePanelId,
|
||||
_revitSettings.RevitPanelName,
|
||||
_cefSharpPanel
|
||||
);
|
||||
}
|
||||
|
||||
private ImageSource? LoadPngImgSource(string sourceName, string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var assembly = Assembly.LoadFrom(Path.Combine(path));
|
||||
var icon = assembly.GetManifestResourceStream(sourceName);
|
||||
PngBitmapDecoder decoder = new(icon, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
|
||||
ImageSource source = decoder.Frames[0];
|
||||
return source;
|
||||
}
|
||||
catch (Exception ex) when (!ex.IsFatal())
|
||||
{
|
||||
// POC: logging
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||