Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/videos/ColumnFromCadCommand.mp4
Binary file not shown.
20 changes: 14 additions & 6 deletions source/Sonny.Application.Core/Bases/BaseViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,26 @@ protected BaseViewModel(ICommonServices commonServices)
/// <summary>
/// Handle display unit changed event
/// </summary>
private void OnDisplayUnitChanged(object? sender, ForgeTypeId newUnit)
private void OnDisplayUnitChanged(object? sender,
ForgeTypeId newUnit)
{
var oldUnit = DisplayUnit ;
DisplayUnit = newUnit ;
OnPropertyChanged(nameof(DisplayUnit)) ;
OnPropertyChanged(nameof(DisplayUnitName)) ;
OnPropertyChanged(nameof( DisplayUnit )) ;
OnPropertyChanged(nameof( DisplayUnitName )) ;

// Allow derived classes to handle unit conversion
OnDisplayUnitChanged(oldUnit, newUnit) ;
OnDisplayUnitChanged(oldUnit,
newUnit) ;
}

/// <summary>
/// Called when display unit changes, allowing derived classes to convert values
/// </summary>
/// <param name="oldUnit">Previous display unit</param>
/// <param name="newUnit">New display unit</param>
protected virtual void OnDisplayUnitChanged(ForgeTypeId oldUnit, ForgeTypeId newUnit)
protected virtual void OnDisplayUnitChanged(ForgeTypeId oldUnit,
ForgeTypeId newUnit)
{
// Override in derived classes to convert values when unit changes
}
Expand Down Expand Up @@ -148,5 +151,10 @@ protected void LogError(string message,
/// </summary>
protected void ShowInfo(string message) => MessageService.ShowInfo(message) ;

/// <summary>
/// Show warning message to user
/// </summary>
protected void ShowWarning(string message) => MessageService.ShowWarning(message) ;

#endregion
}
95 changes: 95 additions & 0 deletions source/Sonny.Application.Core/Bases/BaseViewModelWithSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using Sonny.Application.Core.Interfaces ;

namespace Sonny.Application.Core.Bases ;

/// <summary>
/// Base class for ViewModels that need settings management
/// </summary>
/// <typeparam name="TSettings">Settings model type</typeparam>
public abstract class BaseViewModelWithSettings<TSettings> : BaseViewModel where TSettings : class, new()
{
/// <summary>
/// Settings service for loading and saving settings
/// </summary>
private readonly IViewModelSettingsService<TSettings> _settingsService ;

private bool _isLoadingSettings ;

/// <summary>
/// Initializes a new instance of BaseViewModelWithSettings
/// </summary>
/// <param name="commonServices">Common services</param>
/// <param name="settingsService">Settings service</param>
protected BaseViewModelWithSettings(ICommonServices commonServices,
IViewModelSettingsService<TSettings> settingsService) : base(commonServices)
{
_settingsService = settingsService ;
}

/// <summary>
/// Called after all data is initialized, before loading settings.
/// Override this method to initialize ViewModel data (load collections, set defaults, etc.)
/// </summary>
protected abstract void OnDataInitialized() ;

/// <summary>
/// Called to apply loaded settings to ViewModel properties.
/// Override this method to map settings properties to ViewModel properties.
/// </summary>
/// <param name="settings">Settings loaded from storage</param>
protected abstract void ApplySettings(TSettings settings) ;

/// <summary>
/// Called to create settings object from current ViewModel state.
/// Override this method to map ViewModel properties to settings object.
/// </summary>
/// <returns>Settings object with current ViewModel state</returns>
protected abstract TSettings CreateSettings() ;

/// <summary>
/// Initialize data and load settings.
/// Call this method in constructor after setting up dependencies.
/// </summary>
protected void InitializeWithSettings()
{
OnDataInitialized() ;
LoadSettings() ;
}

/// <summary>
/// Loads settings from storage and applies them to the view model
/// </summary>
private void LoadSettings()
{
var settings = _settingsService.LoadSettings() ;
if (settings == null)
{
return ;
}

_isLoadingSettings = true ;
try
{
ApplySettings(settings) ;
}
finally
{
_isLoadingSettings = false ;
}
}

/// <summary>
/// Saves current settings to storage.
/// This method checks if settings are currently being loaded to avoid saving during load.
/// </summary>
protected void SaveSettings()
{
if (_isLoadingSettings)
{
return ; // Don't save while loading
}

var settings = CreateSettings() ;
_settingsService.SaveSettings(settings) ;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Sonny.Application.Core.FailuresPreprocessors ;

/// <summary>
/// Failure preprocessor to delete warnings
/// </summary>
public class SuppressWarningsPreprocessor : IFailuresPreprocessor
{
/// <summary>
/// Preprocesses failures and deletes warnings
/// </summary>
/// <param name="failuresAccessor">The failures accessor</param>
/// <returns>Continue processing result</returns>
public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor)
{
var failures = failuresAccessor.GetFailureMessages() ;
foreach (var failure in failures)
{
var severity = failure.GetSeverity() ;
if (severity == FailureSeverity.Warning)
{
failuresAccessor.DeleteWarning(failure) ;
}
}

return FailureProcessingResult.Continue ;
}
}
5 changes: 5 additions & 0 deletions source/Sonny.Application.Core/Interfaces/IRevitDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ public interface IRevitDocument
/// </summary>
Document Document { get ; }

/// <summary>
/// Gets the Revit UIDocument
/// </summary>
UIDocument UIDocument { get ; }

/// <summary>
/// Gets the active view
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Sonny.Application.Core.Interfaces ;

/// <summary>
/// Generic interface for ViewModel-specific settings management
/// </summary>
/// <typeparam name="TSettings">Settings model type</typeparam>
public interface IViewModelSettingsService<TSettings> where TSettings : class, new()
{
/// <summary>
/// Loads settings from storage
/// </summary>
/// <returns>Settings instance, or new instance if not found</returns>
TSettings? LoadSettings() ;

/// <summary>
/// Saves settings to storage
/// </summary>
/// <param name="settings">Settings to save</param>
void SaveSettings(TSettings settings) ;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Licensed to the.NET Foundation under one or more agreements.
// The.NET Foundation licenses this file to you under the MIT license.

using Autodesk.Revit.UI.Selection ;

namespace Sonny.Application.Core.SelectionFilters ;

public class TypeSelectionFilter : ISelectionFilter
{
private readonly List<Guid> _typeGuid = [] ;

public TypeSelectionFilter(Type type) => _typeGuid.Add(type.GUID) ;

public TypeSelectionFilter(List<Type> types) =>
_typeGuid = types.Select(category => category.GUID)
.ToList() ;

public bool AllowElement(Element elem) =>
_typeGuid.Contains(elem.GetType()
.GUID) ;

public bool AllowReference(Reference reference,
XYZ position) =>
false ;
}
35 changes: 5 additions & 30 deletions source/Sonny.Application.Core/Services/RevitDocumentService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,16 @@

namespace Sonny.Application.Core.Services ;

/// <summary>
/// Implementation of IRevitDocument using Revit API
/// </summary>
public class RevitDocumentService : IRevitDocument
public class RevitDocumentService(IUIDocumentProvider uiDocumentProvider) : IRevitDocument
{
private readonly UIDocument _uiDocument ;
public Document Document => UIDocument.Document ;

/// <summary>
/// Initializes a new instance of RevitDocumentService
/// </summary>
/// <param name="uiDocumentProvider">The UIDocument provider</param>
public RevitDocumentService(IUIDocumentProvider uiDocumentProvider)
{
_uiDocument = uiDocumentProvider.GetUIDocument() ;
}
public UIDocument UIDocument { get ; } = uiDocumentProvider.GetUIDocument() ;

/// <summary>
/// Gets the Revit Document
/// </summary>
public Document Document => _uiDocument.Document ;
public View ActiveView => UIDocument.ActiveView ;

/// <summary>
/// Gets the active view
/// </summary>
public View ActiveView => _uiDocument.ActiveView ;
public UIApplication Application => UIDocument.Application ;

/// <summary>
/// Gets the UIApplication
/// </summary>
public UIApplication Application => _uiDocument.Application ;

/// <summary>
/// Gets dimension types from the document
/// </summary>
/// <returns>List of DimensionType</returns>
public List<DimensionType> GetDimensionTypes() =>
Document.GetAllElements<DimensionType>()
.Where(x => x.StyleType == DimensionStyleType.Linear)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ namespace Sonny.Application.Core.Services ;
/// </summary>
public class UIDocumentProvider : IUIDocumentProvider
{
private UIDocument? _uiDocument ;
private readonly object _lock = new() ;
private UIDocument? _uiDocument ;

/// <summary>
/// Gets the current active UIDocument
Expand Down
65 changes: 65 additions & 0 deletions source/Sonny.Application.Core/Services/ViewModelSettingsService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#if NETCOREAPP
using System.Text.Json ;
#else
using Newtonsoft.Json ;
#endif
using Sonny.Application.Core.Interfaces ;

namespace Sonny.Application.Core.Services ;

public class ViewModelSettingsService<TSettings> : IViewModelSettingsService<TSettings> where TSettings : class, new()
{
private readonly string _settingsFilePath ;

public ViewModelSettingsService(string settingsFileName)
{
var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ;
var sonnyFolder = Path.Combine(appDataPath,
"Sonny") ;
Directory.CreateDirectory(sonnyFolder) ;
_settingsFilePath = Path.Combine(sonnyFolder,
settingsFileName) ;
}

public TSettings? LoadSettings()
{
if (! File.Exists(_settingsFilePath))
{
return null ;
}

try
{
var json = File.ReadAllText(_settingsFilePath) ;
#if NETCOREAPP
return JsonSerializer.Deserialize<TSettings>(json) ?? new TSettings() ;
#else
return JsonConvert.DeserializeObject<TSettings>(json) ?? new TSettings() ;
#endif
}
catch
{
// If deserialization fails, return new instance
return null ;
}
}

public void SaveSettings(TSettings settings)
{
try
{
#if NETCOREAPP
var json = JsonSerializer.Serialize(settings,
new JsonSerializerOptions { WriteIndented = true }) ;
#else
var json = JsonConvert.SerializeObject(settings, Formatting.Indented) ;
#endif
File.WriteAllText(_settingsFilePath,
json) ;
}
catch
{
// Log error but don't throw - settings are not critical
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
<Label Content="{Binding DisplayUnitName}" Grid.Column="2" />
</Grid>

<!-- Run Button -->
<Button Content="{DynamicResource ButtonRun}"
<!-- OK Button -->
<Button Content="{DynamicResource ButtonOK}"
Command="{Binding RunCommand}"
HorizontalAlignment="Right" />
</StackPanel>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace Sonny.Application.Features.ColumnFromCad.Contexts ;

public class ColumnCreationContext
{
public Document Document { get ; set ; }
public Family SelectedRectangularColumnFamily { get ; set ; }
public Family SelectedCircularColumnFamily { get ; set ; }
public string WidthParameter { get ; set ; }
public string HeightParameter { get ; set ; }
public string DiameterParameter { get ; set ; }
public Level BaseLevel { get ; set ; }
public Level TopLevel { get ; set ; }

/// <summary>
/// Base offset in feet
/// </summary>
public double BaseOffset { get ; set ; }

/// <summary>
/// Top offset in feet
/// </summary>
public double TopOffset { get ; set ; }

public Action<int, int>? ProgressCallback { get ; set ; }
}
Loading
Loading