Skip to content

Commit

Permalink
Decomposition stack history support. Context finder impl
Browse files Browse the repository at this point in the history
  • Loading branch information
Nice3point committed Jan 22, 2025
1 parent 947a984 commit 8e5da66
Show file tree
Hide file tree
Showing 17 changed files with 197 additions and 199 deletions.
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using RevitLookup.Abstractions.Models.Decomposition;
using RevitLookup.Abstractions.ObservableModels.Decomposition;

namespace RevitLookup.Abstractions.Services.Application;

public interface IRevitLookupUiService : ILookupServiceDependsStage, ILookupServiceRunStage
public interface IRevitLookupUiService : ILookupServiceHistoryStage, ILookupServiceDecomposeStage, ILookupServiceShowStage;

public interface ILookupServiceHistoryStage
{
ILookupServiceParentStage AddParent(IServiceProvider serviceProvider);
}

public interface ILookupServiceParentStage : ILookupServiceDecomposeStage
{
ILookupServiceDependsStage Decompose(KnownDecompositionObject decompositionObject);
ILookupServiceDependsStage Decompose(object? obj);
ILookupServiceDependsStage Decompose(IEnumerable objects);
ILookupServiceDependsStage Decompose(ObservableDecomposedObject decomposedObject);
ILookupServiceDependsStage Decompose(List<ObservableDecomposedObject> decomposedObjects);
ILookupServiceDecomposeStage AddStackHistory(ObservableDecomposedObject item);
}

public interface ILookupServiceDependsStage : ILookupServiceShowStage
public interface ILookupServiceDecomposeStage
{
ILookupServiceShowStage DependsOn(Window parent);
ILookupServiceShowStage Decompose(KnownDecompositionObject knownObject);
ILookupServiceShowStage Decompose(object? input);
ILookupServiceShowStage Decompose(IEnumerable input);
ILookupServiceShowStage Decompose(ObservableDecomposedObject decomposedObject);
ILookupServiceShowStage Decompose(List<ObservableDecomposedObject> decomposedObjects);
}

public interface ILookupServiceShowStage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ namespace RevitLookup.Abstractions.Services.Decomposition;

public interface IDecompositionService
{
Task<ObservableDecomposedObject> DecomposeAsync(object obj);
List<ObservableDecomposedObject> DecompositionStackHistory { get; }
Task<ObservableDecomposedObject> DecomposeAsync(object? obj);
Task<List<ObservableDecomposedObject>> DecomposeAsync(IEnumerable objects);
Task<List<ObservableDecomposedMember>> DecomposeMembersAsync(ObservableDecomposedObject decomposedObject);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;
using RevitLookup.Abstractions.ObservableModels.Decomposition;
Expand All @@ -10,7 +11,7 @@ public sealed class SingleDescriptorLabelConverter : DescriptorLabelConverter
public override object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
var member = (ObservableDecomposedObject) value!;
if (!TryConvertInvalidNames(member.Name, out var name))
if (!TryConvertInvalidNames(member.RawValue, out var name))
{
name = CreateSingleName(member.Name, member.Description);
}
Expand All @@ -29,7 +30,7 @@ public sealed class CombinedDescriptorLabelConverter : DescriptorLabelConverter
public override object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
var member = (ObservableDecomposedMember) value!;
if (!TryConvertInvalidNames(member.Value.Name, out var name))
if (!TryConvertInvalidNames(member.Value.RawValue, out var name))
{
name = CreateCombinedName(member.Value.Name, member.Value.Description);
}
Expand All @@ -48,16 +49,16 @@ private static string CreateCombinedName(string name, string? description)

public abstract class DescriptorLabelConverter : MarkupExtension, IValueConverter
{
protected bool TryConvertInvalidNames(string text, out string result)
protected bool TryConvertInvalidNames(object? value, [MaybeNullWhen(false)] out string result)
{
result = text switch
result = value switch
{
null => "<null>",
"" => "<empty>",
_ => text
string {Length: 0} => "<empty>",
_ => null
};

return text != result;
return result is not null;
}

public abstract object Convert(object? value, Type targetType, object? parameter, CultureInfo culture);
Expand Down
2 changes: 1 addition & 1 deletion source/RevitLookup.UI.Playground/Host.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ private static ServiceProvider RegisterServices()
services.AddSingleton<ISoftwareUpdateService, MockSoftwareUpdateService>();
services.AddSingleton<ISettingsService, MockSettingsService>();
services.AddSingleton<IThemeWatcherService, MockThemeWatcherService>();
services.AddSingleton<IDecompositionService, MockDecompositionService>();
services.AddScoped<IDecompositionService, MockDecompositionService>();
services.AddScoped<IVisualDecompositionService, MockVisualDecompositionService>();
services.AddTransient<IRevitLookupUiService, MockRevitLookupUiService>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@
using RevitLookup.Abstractions.ObservableModels.Decomposition;
using RevitLookup.Abstractions.Services.Application;
using RevitLookup.Abstractions.Services.Decomposition;
using RevitLookup.Abstractions.Services.Presentation;
using RevitLookup.UI.Framework.Views.Windows;
using Wpf.Ui;

namespace RevitLookup.UI.Playground.Mockups.Services.Application;

public sealed class MockRevitLookupUiService : IRevitLookupUiService
public sealed class MockRevitLookupUiService : IRevitLookupUiService, ILookupServiceParentStage, ILookupServiceRunStage
{
private Window? _parent;
private IServiceProvider? _parentProvider;
private readonly Task _activeTask = Task.CompletedTask;
private readonly IServiceScope _scope;
private readonly IVisualDecompositionService _decompositionService;
private readonly IDecompositionService _decompositionService;
private readonly IVisualDecompositionService _visualDecompositionService;
private readonly INavigationService _navigationService;
private readonly Window _host;

Expand All @@ -25,45 +27,55 @@ public MockRevitLookupUiService(IServiceScopeFactory scopeFactory)
_scope = scopeFactory.CreateScope();

_host = _scope.ServiceProvider.GetRequiredService<RevitLookupView>();
_decompositionService = _scope.ServiceProvider.GetRequiredService<IVisualDecompositionService>();
_decompositionService = _scope.ServiceProvider.GetRequiredService<IDecompositionService>();
_visualDecompositionService = _scope.ServiceProvider.GetRequiredService<IVisualDecompositionService>();
_navigationService = _scope.ServiceProvider.GetRequiredService<INavigationService>();

_host.Closed += (_, _) => _scope.Dispose();
}

public ILookupServiceDependsStage Decompose(KnownDecompositionObject decompositionObject)
public ILookupServiceShowStage Decompose(KnownDecompositionObject decompositionObject)
{
_activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(decompositionObject), TaskScheduler.FromCurrentSynchronizationContext());
_activeTask.ContinueWith(_ => _visualDecompositionService.VisualizeDecompositionAsync(decompositionObject), TaskScheduler.FromCurrentSynchronizationContext());
return this;
}

public ILookupServiceDependsStage Decompose(object? obj)
public ILookupServiceShowStage Decompose(object? obj)
{
_activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(obj), TaskScheduler.FromCurrentSynchronizationContext());
_activeTask.ContinueWith(_ => _visualDecompositionService.VisualizeDecompositionAsync(obj), TaskScheduler.FromCurrentSynchronizationContext());
return this;
}

public ILookupServiceDependsStage Decompose(IEnumerable objects)
public ILookupServiceShowStage Decompose(IEnumerable objects)
{
_activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(objects), TaskScheduler.FromCurrentSynchronizationContext());
_activeTask.ContinueWith(_ => _visualDecompositionService.VisualizeDecompositionAsync(objects), TaskScheduler.FromCurrentSynchronizationContext());
return this;
}

public ILookupServiceDependsStage Decompose(ObservableDecomposedObject decomposedObject)
public ILookupServiceShowStage Decompose(ObservableDecomposedObject decomposedObject)
{
_activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(decomposedObject), TaskScheduler.FromCurrentSynchronizationContext());
_activeTask.ContinueWith(_ => _visualDecompositionService.VisualizeDecompositionAsync(decomposedObject), TaskScheduler.FromCurrentSynchronizationContext());
return this;
}

public ILookupServiceDependsStage Decompose(List<ObservableDecomposedObject> decomposedObjects)
public ILookupServiceShowStage Decompose(List<ObservableDecomposedObject> decomposedObjects)
{
_activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(decomposedObjects), TaskScheduler.FromCurrentSynchronizationContext());
_activeTask.ContinueWith(_ => _visualDecompositionService.VisualizeDecompositionAsync(decomposedObjects), TaskScheduler.FromCurrentSynchronizationContext());
return this;
}

public ILookupServiceShowStage DependsOn(Window parent)
public ILookupServiceParentStage AddParent(IServiceProvider parentProvider)
{
_parent = parent;
_parentProvider = parentProvider;

var decompositionService = parentProvider.GetRequiredService<IDecompositionService>();
_decompositionService.DecompositionStackHistory.AddRange(decompositionService.DecompositionStackHistory);
return this;
}

public ILookupServiceDecomposeStage AddStackHistory(ObservableDecomposedObject item)
{
_decompositionService.DecompositionStackHistory.Add(item);
return this;
}

Expand Down Expand Up @@ -91,15 +103,17 @@ private void InvokeService<T>(Action<T> handler) where T : class

private void ShowHost(bool modal)
{
if (_parent is null)
if (_parentProvider is null)
{
_host.WindowStartupLocation = WindowStartupLocation.CenterScreen;
}
else
{
var parentHost = _parentProvider.GetRequiredService<IWindowIntercomService>().GetHost();

_host.WindowStartupLocation = WindowStartupLocation.Manual;
_host.Left = _parent.Left + 47;
_host.Top = _parent.Top + 49;
_host.Left = parentHost.Left + 47;
_host.Top = parentHost.Top + 49;
}

if (modal)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ namespace RevitLookup.UI.Playground.Mockups.Services.Summary;
[SuppressMessage("ReSharper", "ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator")]
public sealed class MockDecompositionService(ISettingsService settingsService) : IDecompositionService
{
public async Task<ObservableDecomposedObject> DecomposeAsync(object obj)
public List<ObservableDecomposedObject> DecompositionStackHistory { get; } = [];

public async Task<ObservableDecomposedObject> DecomposeAsync(object? obj)
{
var options = CreateDecomposeMembersOptions();
return await Task.Run(() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,12 @@ public async Task VisualizeDecompositionAsync(KnownDecompositionObject decomposi

public async Task VisualizeDecompositionAsync(object? obj)
{
var objects = obj switch
summaryViewModel.DecomposedObjects = obj switch
{
ObservableDecomposedValue {Descriptor: IDescriptorEnumerator} decomposedValue => (IEnumerable) decomposedValue.RawValue!,
ObservableDecomposedValue decomposedValue => new[] {decomposedValue.RawValue},
_ => new[] {obj}
ObservableDecomposedValue {Descriptor: IDescriptorEnumerator} decomposedValue => await decompositionService.DecomposeAsync((IEnumerable) decomposedValue.RawValue!),
ObservableDecomposedValue decomposedValue => [await decompositionService.DecomposeAsync(decomposedValue.RawValue)],
_ => [await decompositionService.DecomposeAsync(obj)]
};

summaryViewModel.DecomposedObjects = await decompositionService.DecomposeAsync(objects);
}

public async Task VisualizeDecompositionAsync(IEnumerable objects)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@
DataType="{x:Type decomposition:ObservableDecomposedObject}">
<ui:TextBlock
FontTypography="Caption"
Text="{Binding .,
Converter={valueConverters:SingleDescriptorLabelConverter},
Mode=OneTime}" />
Text="{Binding Converter={valueConverters:SingleDescriptorLabelConverter}, Mode=OneTime}" />
</DataTemplate>

<DataTemplate
Expand All @@ -43,9 +41,7 @@
<ui:TextBlock
FontTypography="Caption"
VerticalAlignment="Center"
Text="{Binding .,
Converter={valueConverters:SingleDescriptorLabelConverter},
Mode=OneTime}" />
Text="{Binding Converter={valueConverters:SingleDescriptorLabelConverter}, Mode=OneTime}" />
<Border
CornerRadius="4"
Padding="4 2"
Expand All @@ -62,9 +58,7 @@
Height="10">
<Border.Background>
<SolidColorBrush
Color="{Binding RawValue,
Converter={converters:ObjectColorConverter},
Mode=OneTime}">
Color="{Binding RawValue, Converter={converters:ObjectColorConverter}, Mode=OneTime}">
</SolidColorBrush>
</Border.Background>
</Border>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using CommunityToolkit.Mvvm.ComponentModel;
using JetBrains.Annotations;
using LookupEngine;
using Microsoft.Extensions.Logging;
using RevitLookup.Abstractions.ObservableModels.Decomposition;
using RevitLookup.Abstractions.Services.Application;
using RevitLookup.Abstractions.Services.Decomposition;
using RevitLookup.Abstractions.Services.Presentation;
using RevitLookup.Abstractions.Services.Settings;
using RevitLookup.Abstractions.ViewModels.Decomposition;
using RevitLookup.UI.Framework.Extensions;
using RevitLookup.UI.Framework.Views.Decomposition;
using RevitLookup.UI.Playground.Mockups.Core.Decomposition;
using RevitLookup.UI.Playground.Mockups.Mappers;
#if NETFRAMEWORK
using RevitLookup.UI.Framework.Extensions;
#endif
Expand All @@ -21,8 +17,8 @@ namespace RevitLookup.UI.Playground.Mockups.ViewModels.Decomposition;

[UsedImplicitly]
public sealed partial class MockDecompositionSummaryViewModel(
ISettingsService settingsService,
IWindowIntercomService intercomService,
IServiceProvider serviceProvider,
IDecompositionService decompositionService,
INotificationService notificationService,
ILogger<MockDecompositionSummaryViewModel> logger)
: ObservableObject, IDecompositionSummaryViewModel
Expand All @@ -35,24 +31,25 @@ public sealed partial class MockDecompositionSummaryViewModel(
public void Navigate(object? value)
{
Host.GetService<IRevitLookupUiService>()
.AddParent(serviceProvider)
.AddStackHistory(SelectedDecomposedObject!)
.Decompose(value)
.DependsOn(intercomService.GetHost())
.Show<DecompositionSummaryPage>();
}

public void Navigate(ObservableDecomposedObject value)
{
Host.GetService<IRevitLookupUiService>()
.AddParent(serviceProvider)
.Decompose(value)
.DependsOn(intercomService.GetHost())
.Show<DecompositionSummaryPage>();
}

public void Navigate(List<ObservableDecomposedObject> values)
{
Host.GetService<IRevitLookupUiService>()
.AddParent(serviceProvider)
.Decompose(values)
.DependsOn(intercomService.GetHost())
.Show<DecompositionSummaryPage>();
}

Expand Down Expand Up @@ -168,37 +165,7 @@ private async Task FetchMembersAsync(ObservableDecomposedObject? value)
if (value is null) return;
if (value.Members.Count > 0) return;

value.Members = await DecomposeMembersAsync(value);
}

[SuppressMessage("ReSharper", "ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator")]
private async Task<List<ObservableDecomposedMember>> DecomposeMembersAsync(ObservableDecomposedObject decomposedObject)
{
var options = new DecomposeOptions
{
IncludeRoot = settingsService.GeneralSettings.IncludeRootHierarchy,
IncludeFields = settingsService.GeneralSettings.IncludeFields,
IncludeEvents = settingsService.GeneralSettings.IncludeEvents,
IncludeUnsupported = settingsService.GeneralSettings.IncludeUnsupported,
IncludePrivateMembers = settingsService.GeneralSettings.IncludePrivate,
IncludeStaticMembers = settingsService.GeneralSettings.IncludeStatic,
EnableExtensions = settingsService.GeneralSettings.IncludeExtensions,
EnableRedirection = true,
TypeResolver = DescriptorsMap.FindDescriptor
};

return await Task.Run(() =>
{
var decomposedMembers = LookupComposer.DecomposeMembers(decomposedObject.RawValue, options);
var members = new List<ObservableDecomposedMember>(decomposedMembers.Count);

foreach (var decomposedMember in decomposedMembers)
{
members.Add(DecompositionResultMapper.Convert(decomposedMember));
}

return members;
});
value.Members = await decompositionService.DecomposeMembersAsync(value);
}

private ObservableCollection<ObservableDecomposedObjectsGroup> ApplyGrouping(List<ObservableDecomposedObject> objects)
Expand Down
Loading

0 comments on commit 8e5da66

Please sign in to comment.