83efebfed9
* Remove Dataflow usage * format and remove dep * merge fixes * Fix serializer * Add MainThreadContext * add some main context detection * add RevitMainThreadContext * remove revit async? * formatting * use mainThreadContext * Use more MainThreadContext * some rearranging * renaming * Revit needs new run async * merge fixes * gather on worker, convert on main * operations know threading but not host apps * rhino options * revit can receive * autocad in progress * need to yield for UI thread async * revamp yield * Found APIContext and removed it * ArcGIS runs all workers on MCT thread * Refactor ThreadContext and ArcGIS saving is always on a worker * Revit threading is simplier? * ArcGIS can not always go to the queued task * format * fix tekla compile errors * Use EventAggregator to decouple exception handler and UI * it's ALIVE * regenerate locks * Add Prism Evening to DUI * clean up * always run on background thread * Clean up to be specific * update etabs * thread context * autocad threading? * merge fixes * remove more async * clean up * fix build issues * Do top level handling in event aggregator * add some rhino events * add more Rhino events and do Idle as OneTime with Id * fix up rhino idle usages * fmt * can build agian * Use valuetask * fmt * fix up some bridge execution to be sync * cleanup * add some non async paths for progress * format * remove needless selection * Fixes * Convert tekla * selection event is used without idle * Build fixes from merge * Fix tests and clean up * Add new events * Properly dispose one time events * Minor tekla updates
140 lines
3.4 KiB
C#
140 lines
3.4 KiB
C#
using System.Diagnostics;
|
|
using Speckle.Connectors.DUI.Models.Card;
|
|
using Speckle.Connectors.DUI.Utils;
|
|
using Speckle.Sdk;
|
|
using Speckle.Sdk.Common;
|
|
|
|
namespace Speckle.Connectors.DUI.Models;
|
|
|
|
/// <summary>
|
|
/// Encapsulates the state Speckle needs to persist in the host app's document.
|
|
/// </summary>
|
|
public abstract class DocumentModelStore(IJsonSerializer serializer)
|
|
{
|
|
private readonly List<ModelCard> _models = new();
|
|
|
|
//needed for javascript UI
|
|
public IReadOnlyList<ModelCard> Models
|
|
{
|
|
get
|
|
{
|
|
lock (_models)
|
|
{
|
|
return _models.AsReadOnly();
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual Task OnDocumentStoreInitialized() => Task.CompletedTask;
|
|
|
|
public virtual bool IsDocumentInit { get; set; }
|
|
|
|
// TODO: not sure about this, throwing an exception, needs some thought...
|
|
// Further note (dim): If we reach to the stage of throwing an exception here because a model is not found, there's a huge misalignment between the UI's list of model cards and the host app's.
|
|
// In theory this should never really happen, but if it does
|
|
public ModelCard GetModelById(string id)
|
|
{
|
|
var model = _models.First(model => model.ModelCardId == id) ?? throw new ModelNotFoundException();
|
|
return model;
|
|
}
|
|
|
|
public void AddModel(ModelCard model)
|
|
{
|
|
lock (_models)
|
|
{
|
|
_models.Add(model);
|
|
SaveState();
|
|
}
|
|
}
|
|
|
|
public void ClearAndSave()
|
|
{
|
|
lock (_models)
|
|
{
|
|
_models.Clear();
|
|
SaveState();
|
|
}
|
|
}
|
|
|
|
public void UpdateModel(ModelCard model)
|
|
{
|
|
lock (_models)
|
|
{
|
|
var index = _models.FindIndex(m => m.ModelCardId == model.ModelCardId);
|
|
if (index == -1)
|
|
{
|
|
throw new ModelNotFoundException("Model card not found to update.");
|
|
}
|
|
_models[index] = model;
|
|
SaveState();
|
|
}
|
|
}
|
|
|
|
public void RemoveModel(ModelCard model)
|
|
{
|
|
lock (_models)
|
|
{
|
|
var index = _models.FindIndex(m => m.ModelCardId == model.ModelCardId);
|
|
if (index == -1)
|
|
{
|
|
throw new ModelNotFoundException("Model card not found to update.");
|
|
}
|
|
_models.RemoveAt(index);
|
|
SaveState();
|
|
}
|
|
}
|
|
|
|
public IEnumerable<SenderModelCard> GetSenders()
|
|
{
|
|
lock (_models)
|
|
{
|
|
return _models
|
|
.Where(model => model.TypeDiscriminator == nameof(SenderModelCard))
|
|
.Cast<SenderModelCard>()
|
|
.ToList();
|
|
}
|
|
}
|
|
|
|
protected string Serialize() => serializer.Serialize(Models);
|
|
|
|
// POC: this seemms more like a IModelsDeserializer?, seems disconnected from this class
|
|
protected List<ModelCard> Deserialize(string models) => serializer.Deserialize<List<ModelCard>>(models).NotNull();
|
|
|
|
protected void SaveState()
|
|
{
|
|
lock (_models)
|
|
{
|
|
var state = Serialize();
|
|
HostAppSaveState(state);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Implement this method according to the host app's specific ways of reading custom data from its file.
|
|
/// </summary>
|
|
protected abstract void HostAppSaveState(string modelCardState);
|
|
|
|
protected abstract void LoadState();
|
|
|
|
protected void LoadFromString(string? models)
|
|
{
|
|
try
|
|
{
|
|
lock (_models)
|
|
{
|
|
_models.Clear();
|
|
if (string.IsNullOrEmpty(models))
|
|
{
|
|
return;
|
|
}
|
|
_models.AddRange(Deserialize(models.NotNull()).NotNull());
|
|
}
|
|
}
|
|
catch (Exception ex) when (!ex.IsFatal())
|
|
{
|
|
ClearAndSave();
|
|
Debug.WriteLine(ex.Message); // POC: Log here error and notify UI that cards not read succesfully
|
|
}
|
|
}
|
|
}
|