Skip to content

Commit

Permalink
Fix(tekla): Read write model cards to/from appdata + fixes double UI (#…
Browse files Browse the repository at this point in the history
…395)

* Fix multiple problems

* Connect windows each other

* Add note
  • Loading branch information
oguzhankoral authored Nov 20, 2024
1 parent a4f27b5 commit c74e92f
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace Speckle.Connector.Tekla2024.Bindings;

public class TeklaBasicConnectorBinding : IBasicConnectorBinding
{
public BasicConnectorBindingCommands Commands { get; }
private readonly ISpeckleApplication _speckleApplication;
private readonly DocumentModelStore _store;
public string Name => "baseBinding";
Expand All @@ -32,6 +33,12 @@ TSM.Model model
Parent = parent;
_logger = logger;
_model = model;
Commands = new BasicConnectorBindingCommands(parent);
_store.DocumentChanged += (_, _) =>
parent.TopLevelExceptionHandler.FireAndForget(async () =>
{
await Commands.NotifyDocumentChanged().ConfigureAwait(false);
});
}

public string GetSourceApplicationName() => _speckleApplication.Slug;
Expand Down Expand Up @@ -141,6 +148,4 @@ await Task.Run(() =>
_logger.LogError(ex, "Failed to highlight objects");
}
}

public BasicConnectorBindingCommands Commands { get; }
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,100 @@
using Speckle.Connectors.DUI.Models;
using System.IO;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.DUI.Models;
using Speckle.Newtonsoft.Json;
using Speckle.Sdk;
using Speckle.Sdk.Helpers;
using Speckle.Sdk.Logging;

namespace Speckle.Connector.Tekla2024.HostApp;

public class TeklaDocumentModelStore : DocumentModelStore
{
private readonly ISpeckleApplication _speckleApplication;
private readonly ILogger<TeklaDocumentModelStore> _logger;
private readonly TSM.Model _model;
private readonly TSM.Events _events;
private string HostAppUserDataPath { get; set; }
private string DocumentStateFile { get; set; }
private string ModelPathHash { get; set; }

public TeklaDocumentModelStore(
JsonSerializerSettings jsonSerializerSettings
// ITopLevelExceptionHandler topLevelExceptionHandler
JsonSerializerSettings jsonSerializerSettings,
ISpeckleApplication speckleApplication,
ILogger<TeklaDocumentModelStore> logger
)
: base(jsonSerializerSettings, true) { }
: base(jsonSerializerSettings, true)
{
_speckleApplication = speckleApplication;
_logger = logger;
_model = new TSM.Model();
SetPaths();
_events = new TSM.Events();
_events.ModelLoad += () =>
{
SetPaths();
ReadFromFile();
OnDocumentChanged();
};
_events.Register();
if (SpeckleTeklaPanelHost.IsInitialized)
{
ReadFromFile();
OnDocumentChanged();
}
}

private void SetPaths()
{
ModelPathHash = Crypt.Md5(_model.GetInfo().ModelPath, length: 32);
HostAppUserDataPath = Path.Combine(
SpecklePathProvider.UserSpeckleFolderPath,
"Connectors",
_speckleApplication.Slug
);
DocumentStateFile = Path.Combine(HostAppUserDataPath, $"{ModelPathHash}.json");
}

public override void WriteToFile()
{
string serializedState = Serialize();
try
{
if (!Directory.Exists(HostAppUserDataPath))
{
Directory.CreateDirectory(HostAppUserDataPath);
}
File.WriteAllText(DocumentStateFile, serializedState);
}
catch (Exception ex) when (!ex.IsFatal())
{
_logger.LogError(ex.Message);
}
}

public override void ReadFromFile()
{
try
{
if (!Directory.Exists(HostAppUserDataPath))
{
Models = new();
return;
}

public override void WriteToFile() { }
if (!File.Exists(DocumentStateFile))
{
Models = new();
return;
}

public override void ReadFromFile() { }
string serializedState = File.ReadAllText(DocumentStateFile);
Models = Deserialize(serializedState) ?? new();
}
catch (Exception ex) when (!ex.IsFatal())
{
Models = new();
_logger.LogError(ex.Message);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
using Microsoft.Extensions.DependencyInjection;
Expand All @@ -14,13 +16,57 @@ namespace Speckle.Connector.Tekla2024;

public class SpeckleTeklaPanelHost : PluginFormBase
{
private ElementHost Host { get; }
private static SpeckleTeklaPanelHost? s_instance;
private ElementHost Host { get; set; }
public Model Model { get; private set; }
public static new ServiceProvider? Container { get; private set; }
private static readonly List<SpeckleTeklaPanelHost> s_instances = new();

// NOTE: Somehow tekla triggers this class twice at the beginning and on first dialog our webview appears
// with small size of render in Host even if we set it as Dock.Fill. But on second trigger dialog initializes as expected.
// So, we do not init our plugin at first attempt, we just close it at first.
// On second, we init plugin and mark plugin as 'Initialized' to handle later init attempts nicely.
// We make 'IsInitialized' as 'false' only whenever our main dialog is closed explicitly by user.
private static bool IsFirst { get; set; } = true;
public static bool IsInitialized { get; private set; }

//window owner call
[DllImport("user32.dll", SetLastError = true)]
[SuppressMessage("Security", "CA5392:Use DefaultDllImportSearchPaths attribute for P/Invokes")]
private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr value);

private const int GWL_HWNDPARENT = -8;

public SpeckleTeklaPanelHost()
{
if (IsFirst)
{
IsFirst = false;
Close();
}
else
{
if (IsInitialized)
{
s_instance?.BringToFront();
Close();
return;
}
IsInitialized = true;
InitializeInstance();
s_instance?.BringToFront();
}
}

protected override void OnClosed(EventArgs e)
{
s_instance?.Dispose();
IsInitialized = false;
}

private void InitializeInstance()
{
s_instance = this; // Assign the current instance to the static field

this.Text = "Speckle (Beta)";
this.Name = "Speckle (Beta)";

Expand All @@ -37,17 +83,6 @@ public SpeckleTeklaPanelHost()
this.Icon = Icon.FromHandle(bmp.GetHicon());
}

// adds instances to tracking list
s_instances.Add(this);

if (s_instances.Count > 1)
{
var firstInstance = s_instances[0];
s_instances.RemoveAt(0);
// hides the first instance if there is more than one
firstInstance.Hide();
}

var services = new ServiceCollection();
services.Initialize(HostApplications.TeklaStructures, GetVersion());
services.AddTekla();
Expand All @@ -66,10 +101,13 @@ public SpeckleTeklaPanelHost()
);
}
var webview = Container.GetRequiredService<DUI3ControlWebView>();
webview.RenderSize = new System.Windows.Size(800, 600);
Host = new() { Child = webview, Dock = DockStyle.Fill };
Controls.Add(Host);
Operation.DisplayPrompt("Speckle connector initialized.");

this.TopLevel = true;
SetWindowLongPtr(Handle, GWL_HWNDPARENT, MainWindow.Frame.Handle);
Show();
Activate();
Focus();
Expand Down

0 comments on commit c74e92f

Please sign in to comment.