Skip to content

Commit

Permalink
Add new LibraryViewExtension project based on System.Windows.Controls…
Browse files Browse the repository at this point in the history
….WebBrowser (#10241)

* add new project
add make core internals visible
add duplicate files as required

* build of libjswebview seems to work
added package references

* add resource files as links so dont duplicate them in repo

* move to .net 4.7.2 to avoid package ref issues
namespace adds dynamo
use new namespace to reference resources that are embedded.

* move back to 4.7 to see if we can get a build on self serve

* log msbuild version in appyveyor

* try using buildxml which restores a bit differently

* image should not be under env - bah

* revet back to nuget restore and build dynamo all

* working branch in acad

* icons from host registered streams supported now

* this functions but startup time is slow.
visibility fixed with startPage
loads acad icons from resource streams that are registered using existing resource dict

* add some stopwatch logging to resource loading
remove superflous resourcestream handler
add cache to main iconProvider entrypoint as first step in resolving icon data
use string builder to construct base64 data strings

* missed changes

* semi working lazy load - small change made to librariejs to raise event whenever any item is clicked
we also cache the original url before falling back to the default icon so we can load the real icon later.

* some cleanup

* update namespace to reflect what components are actually used
update some todos
update comments

* drop back to packges config
rename project, rename folder
rename extension class

* assembly and type names changed

* remove value tuple use
set version number to auto increment for now - keep at 1.0.x until we have a longer term plan for this project

* get rid of value tuple

* recase some methods
comments
add readme

* address review comments
  • Loading branch information
mjkkirschner committed Jan 9, 2020
1 parent bde6733 commit 35c9497
Show file tree
Hide file tree
Showing 26 changed files with 4,052 additions and 1 deletion.
5 changes: 4 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ platform: Any CPU

configuration: Release

image: Visual Studio 2017

before_build:
- nuget restore .\src\Dynamo.All.sln

environment:
dynamo_solution: src/Dynamo.All.sln
image: Visual Studio 2017


build_script:
- where msbuild
- msbuild %dynamo_solution%


Expand Down
11 changes: 11 additions & 0 deletions src/Dynamo.All.sln
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkspaceDependencyViewExtension", "WorkspaceDependencyViewExtension\WorkspaceDependencyViewExtension.csproj", "{5E76AAB3-6302-473E-9655-081B53FB1419}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibraryViewExtensionMSWebBrowser", "LibraryViewExtensionMSWebBrowser\LibraryViewExtensionMSWebBrowser.csproj", "{1A5DC90A-477E-4D4A-87BD-0BFB01F056CE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -811,6 +813,14 @@ Global
{5E76AAB3-6302-473E-9655-081B53FB1419}.Release|Any CPU.Build.0 = Release|Any CPU
{5E76AAB3-6302-473E-9655-081B53FB1419}.Release|x64.ActiveCfg = Release|Any CPU
{5E76AAB3-6302-473E-9655-081B53FB1419}.Release|x64.Build.0 = Release|Any CPU
{1A5DC90A-477E-4D4A-87BD-0BFB01F056CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A5DC90A-477E-4D4A-87BD-0BFB01F056CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A5DC90A-477E-4D4A-87BD-0BFB01F056CE}.Debug|x64.ActiveCfg = Debug|Any CPU
{1A5DC90A-477E-4D4A-87BD-0BFB01F056CE}.Debug|x64.Build.0 = Debug|Any CPU
{1A5DC90A-477E-4D4A-87BD-0BFB01F056CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A5DC90A-477E-4D4A-87BD-0BFB01F056CE}.Release|Any CPU.Build.0 = Release|Any CPU
{1A5DC90A-477E-4D4A-87BD-0BFB01F056CE}.Release|x64.ActiveCfg = Release|Any CPU
{1A5DC90A-477E-4D4A-87BD-0BFB01F056CE}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -883,6 +893,7 @@ Global
{C0D6DEE5-5532-4345-9C66-4C00D7FDB8BE} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13}
{47D2166C-5261-4093-9660-E72B7035E666} = {88D45B00-E564-41DB-B57C-9509646CAA49}
{5E76AAB3-6302-473E-9655-081B53FB1419} = {88D45B00-E564-41DB-B57C-9509646CAA49}
{1A5DC90A-477E-4D4A-87BD-0BFB01F056CE} = {88D45B00-E564-41DB-B57C-9509646CAA49}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {89CB19C6-BF0A-4E6A-BFDA-79D143EAB59D}
Expand Down
2 changes: 2 additions & 0 deletions src/DynamoCore/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@
// Internals are visible to the Package Manager extension
// For workspace package dependency collection
[assembly: InternalsVisibleTo("WorkspaceDependencyViewExtension")]

[assembly: InternalsVisibleTo("LibraryViewExtensionMSWebBrowser")]
167 changes: 167 additions & 0 deletions src/LibraryViewExtensionMSWebBrowser/EventObserver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
using System;
using System.Threading;

namespace Dynamo.LibraryViewExtensionMSWebBrowser
{
/// <summary>
/// A class that observes an event and notifies the clients with a transformed
/// data as configured using reduce function.
/// </summary>
/// <typeparam name="TValue">Type of value passed when event is raised</typeparam>
/// <typeparam name="TResult">Type of transformed data to notify to the client</typeparam>
class EventObserver<TValue, TResult> : IDisposable
{
private Timer throttler = null;
private TimeSpan duetime;
private bool accumulate = false;
private bool disposed = false;

private TResult result;
private Func<TResult, TValue, TResult> reducer;
private Action<TResult> observer;

private object root = new object();

/// <summary>
/// This event is fired when this object is disposed, clients can
/// register a callback for Dispose.
/// </summary>
public event Action Disposed;

/// <summary>
/// Creates the event observer with a registered observe action and
/// a reduce function for notification.
/// </summary>
/// <param name="observe">This action will be invoked to notify the client</param>
/// <param name="reduce">This function will be invoked to reduce the
/// actual event parameter together with last reduced value returned by this reducer.</param>
public EventObserver(Action<TResult> observe, Func<TResult, TValue, TResult> reduce)
{
observer = observe;
reducer = reduce;
accumulate = true;
result = default(TResult);
}

/// <summary>
/// Creates the event observer with a registered observe action and
/// a reduce function for notification.
/// </summary>
/// <param name="observe">This action will be invoked to notify the client</param>
/// <param name="transform">This function will be invoked to transform the
/// actual event parameter.</param>
public EventObserver(Action<TResult> observe, Func<TValue, TResult> transform)
{
observer = observe;
reducer = (x, y) => transform(y);
result = default(TResult);
}

public static TValue Identity(TValue last, TValue current)
{
return current;
}

/// <summary>
/// The client need to register this method as an event callback for
/// the event that needs to be observed.
/// </summary>
/// <param name="value">Event parameter passed</param>
public void OnEvent(TValue value)
{
if (disposed) return;

lock (root) { result = reducer(result, value); }

OnEventCore(value);
}

/// <summary>
/// The core implementation for OnEvent, if throttle is active it will
/// update the throttle timer with the due time, so that if no subsequent
/// event is raised within the given throttle due time, the client will
/// be notified.
/// </summary>
/// <param name="value"></param>
protected virtual void OnEventCore(TValue value)
{
if (throttler != null)
{
throttler.Change(duetime, TimeSpan.FromMilliseconds(0));
}
else
{
Notify(this);
}
}

/// <summary>
/// Creates an observer that throttle the stream of notification
/// for a given duetime i.e. notification will be fired only if duetime
/// is ellapsed from the last event trigger, if the event trigger is
/// sooner then the observer will again wait for the given duetime
/// to notify the client.
/// </summary>
/// <param name="duetime">Due time for throttle</param>
/// <returns>The modified event Observer which throttle the events</returns>
public EventObserver<TValue, TResult> Throttle(TimeSpan duetime)
{
if (disposed) throw new ObjectDisposedException("EventObserver");

this.duetime = duetime;
this.throttler = new Timer(Notify, this, Timeout.Infinite, Timeout.Infinite);
//when throttled, reset the result after notification is fired.
accumulate = false;
return this;
}

/// <summary>
/// Notify the client, could be triggered from throttle timer or
/// called directly by passing this object as state.
/// </summary>
/// <param name="state"></param>
protected void Notify(object state)
{
if (disposed) throw new ObjectDisposedException("EventObserver");

TResult r;
lock (root)
{
r = result;
if (!accumulate) result = default(TResult);
}
observer(r);
}

public void Dispose()
{
if (!disposed)
{
disposed = true;
if (Disposed != null) { Disposed(); }
Disposed = null;
observer = null;
reducer = null;
}
}
}

/// <summary>
/// Implements IDisposable to invoke a given dispose action on Dispose().
/// </summary>
class AnonymousDisposable : IDisposable
{
private Action dispose;

public AnonymousDisposable(Action dispose)
{
this.dispose = dispose;
}

public void Dispose()
{
if(dispose != null) { dispose(); }
dispose = null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Dynamo.LibraryViewExtensionMSWebBrowser.Handlers
{
/// <summary>
/// A simple DllResourceProvider, which provides embedded resources from the dll.
/// </summary>
public class DllResourceProvider : ResourceProviderBase
{
/// <summary>
/// Creates a resource provider to get embedded resources from a given assembly.
/// </summary>
/// <param name="baseUrl">The base url from where the request is served.</param>
/// <param name="rootNamespace">Root namespace for this resource provider.</param>
/// <param name="assembly">Assembly from where the resources are to be obtained.</param>
public DllResourceProvider(string baseUrl, string rootNamespace, Assembly assembly = null)
{
RootNamespace = rootNamespace;
BaseUrl = baseUrl;
Assembly = assembly;
if (Assembly == null)
Assembly = Assembly.GetExecutingAssembly();
}

/// <summary>
/// Root namespace for this resource provider. For an example, if this provider
/// serves resources at "Dynamo.LibraryUI.Web.Xxxx" (where "Xxxx" is the actual
/// name of the resource), then root namespace would be "Dynamo.LibraryUI.Web".
/// </summary>
public string RootNamespace { get; private set; }

/// <summary>
/// The base url from where the request is served. For example, if this provider
/// serves requests at http://localhost/dist/v0.0.1/Xxxx (where "Xxxx" is the name
/// of the request), then the base url is "http://localhost/dist/v0.0.1".
/// </summary>
public string BaseUrl { get; private set; }

/// <summary>
/// Assembly from where the resources are to be obtained.
/// </summary>
public Assembly Assembly { get; private set; }

/// <summary>
/// Call this method to get the stream for a given requested resource.
/// </summary>
/// <param name="url">The requested url.</param>
/// <param name="extension">Output parameter whose value is the extension
/// of the requested resource. This extension does not contain "." character.</param>
/// <returns>Returns the stream if the requested resource can be found, or null
/// otherwise.</returns>
public override Stream GetResource(string url, out string extension)
{
extension = "txt";
var uri = new Uri(url);
string resourceName;
var assembly = GetResourceAssembly(uri, out resourceName);
if (null == assembly)
{
return null;
}

var stream = assembly.GetManifestResourceStream(resourceName);
var idx = resourceName.LastIndexOf('.');
if (idx > 0)
{
extension = resourceName.Substring(idx + 1);
}

return stream;
}

protected virtual Assembly GetResourceAssembly(Uri url, out string resourceName)
{
var path = url.AbsoluteUri.Replace(BaseUrl, "").Replace('/', '.');
resourceName = RootNamespace + path;
return this.Assembly;
}
}
}
Loading

0 comments on commit 35c9497

Please sign in to comment.