diff --git a/SampleLibrary/DocFixture.cs b/SampleLibrary/DocFixture.cs index 54df671..70c918f 100644 --- a/SampleLibrary/DocFixture.cs +++ b/SampleLibrary/DocFixture.cs @@ -1,22 +1,26 @@ -using Autodesk.Revit.DB; -using System; +using System; using System.Collections.Generic; +using Autodesk.Revit.DB; using xUnitRevitUtils; -namespace SampleLibrary { - public sealed class DocFixture : IDisposable { - public Document Doc { get; set; } - public IList Walls { get; set; } +namespace SampleLibrary +{ + public sealed class DocFixture : IDisposable + { + public Document Doc { get; set; } + public IList Walls { get; set; } - public DocFixture() { - var testModel = Utils.GetTestModel("walls.rvt"); - Doc = xru.OpenDoc(testModel); + public DocFixture() + { + var testModel = Utils.GetTestModel("walls.rvt"); + Doc = xru.OpenDoc(testModel); - Walls = new FilteredElementCollector(Doc).WhereElementIsNotElementType().OfCategory(BuiltInCategory.OST_Walls).ToElements(); - } - - public void Dispose() { - } + Walls = new FilteredElementCollector(Doc).WhereElementIsNotElementType().OfCategory(BuiltInCategory.OST_Walls).ToElements(); } + + public void Dispose() + { + } + } } diff --git a/SampleLibrary/SampleTest.cs b/SampleLibrary/SampleTest.cs index c78e334..ded38ab 100644 --- a/SampleLibrary/SampleTest.cs +++ b/SampleLibrary/SampleTest.cs @@ -1,60 +1,68 @@ -using Autodesk.Revit.DB; +using System.Linq; +using Autodesk.Revit.DB; using Autodesk.Revit.DB.IFC; -using System.Linq; using Xunit; using xUnitRevitUtils; -namespace SampleLibrary { - public class SampleTest { - /// - /// Checks whether all walls in the model have a valid volume - /// - [Fact] - public void WallsHaveVolume() { - var testModel = Utils.GetTestModel("walls.rvt"); - var doc = xru.OpenDoc(testModel); +namespace SampleLibrary +{ + public class SampleTest + { + /// + /// Checks whether all walls in the model have a valid volume + /// + [Fact] + public void WallsHaveVolume() + { + var testModel = Utils.GetTestModel("walls.rvt"); + var doc = xru.OpenDoc(testModel); - var walls = new FilteredElementCollector(doc).WhereElementIsNotElementType().OfCategory(BuiltInCategory.OST_Walls).ToElements(); + var walls = new FilteredElementCollector(doc).WhereElementIsNotElementType().OfCategory(BuiltInCategory.OST_Walls).ToElements(); - foreach (var wall in walls) { - var volumeParam = wall.get_Parameter(BuiltInParameter.HOST_VOLUME_COMPUTED); - Assert.NotNull(volumeParam); - Assert.True(volumeParam.AsDouble() > 0); - } - } + foreach (var wall in walls) + { + var volumeParam = wall.get_Parameter(BuiltInParameter.HOST_VOLUME_COMPUTED); + Assert.NotNull(volumeParam); + Assert.True(volumeParam.AsDouble() > 0); + } + } - [Fact] - public void SampleFail() { + [Fact] + public void SampleFail() + { #if pre2021 var feet = UnitUtils.ConvertToInternalUnits(3000, DisplayUnitType.DUT_MILLIMETERS); #else - var feet = UnitUtils.ConvertToInternalUnits(3000, UnitTypeId.Feet); + var feet = UnitUtils.ConvertToInternalUnits(3000, UnitTypeId.Feet); #endif - Assert.Equal(5, feet); - } - - [Fact] - public void GetWallGrossAreaAndRollBack() { - var testModel = Utils.GetTestModel("walls.rvt"); - var doc = xru.OpenDoc(testModel); - var walls = new FilteredElementCollector(doc).WhereElementIsNotElementType().OfCategory(BuiltInCategory.OST_Walls).ToElements(); - var wall = walls[0] as Wall; - double grossArea = 0; - - var inserts = wall.FindInserts(true, true, true, true); - xru.Run(() => { - using (Transaction transaction = new Transaction(doc, "Temporary - only to get gross area")) { - transaction.Start(); - foreach (ElementId insertId in inserts) { doc.Delete(insertId); } - doc.Regenerate(); - var wallFaceReference = HostObjectUtils.GetSideFaces(wall, ShellLayerType.Exterior); - var face = doc.GetElement(wallFaceReference.First()).GetGeometryObjectFromReference(wallFaceReference.First()) as PlanarFace; - var wallFaceEdges = face.GetEdgesAsCurveLoops(); - grossArea = ExporterIFCUtils.ComputeAreaOfCurveLoops(wallFaceEdges); - transaction.RollBack(); - } - }, doc).Wait(); - Assert.True(grossArea > 0); - } + Assert.Equal(5, feet); } + + [Fact] + public void GetWallGrossAreaAndRollBack() + { + var testModel = Utils.GetTestModel("walls.rvt"); + var doc = xru.OpenDoc(testModel); + var walls = new FilteredElementCollector(doc).WhereElementIsNotElementType().OfCategory(BuiltInCategory.OST_Walls).ToElements(); + var wall = walls[0] as Wall; + double grossArea = 0; + + var inserts = wall.FindInserts(true, true, true, true); + xru.Run(() => + { + using (Transaction transaction = new Transaction(doc, "Temporary - only to get gross area")) + { + transaction.Start(); + foreach (ElementId insertId in inserts) { doc.Delete(insertId); } + doc.Regenerate(); + var wallFaceReference = HostObjectUtils.GetSideFaces(wall, ShellLayerType.Exterior); + var face = doc.GetElement(wallFaceReference.First()).GetGeometryObjectFromReference(wallFaceReference.First()) as PlanarFace; + var wallFaceEdges = face.GetEdgesAsCurveLoops(); + grossArea = ExporterIFCUtils.ComputeAreaOfCurveLoops(wallFaceEdges); + transaction.RollBack(); + } + }, doc).Wait(); + Assert.True(grossArea > 0); + } + } } diff --git a/SampleLibrary/TestWithFixture.cs b/SampleLibrary/TestWithFixture.cs index 9574444..e32691c 100644 --- a/SampleLibrary/TestWithFixture.cs +++ b/SampleLibrary/TestWithFixture.cs @@ -1,61 +1,70 @@ -using Autodesk.Revit.DB; -using System.Linq; +using System.Linq; +using Autodesk.Revit.DB; using Xunit; using xUnitRevitUtils; -namespace SampleLibrary { - public class TestWithFixture : IClassFixture { - DocFixture fixture; - public TestWithFixture(DocFixture fixture) { - this.fixture = fixture; - } +namespace SampleLibrary +{ + public class TestWithFixture : IClassFixture + { + DocFixture fixture; + public TestWithFixture(DocFixture fixture) + { + this.fixture = fixture; + } - [Fact] - public void CountWalls() { - Assert.Equal(4, fixture.Walls.Count); - } + [Fact] + public void CountWalls() + { + Assert.Equal(4, fixture.Walls.Count); + } - [Fact] - public void WallOffset() { - var wall = fixture.Doc.GetElement(new ElementId(346573)); - var param = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET); + [Fact] + public void WallOffset() + { + var wall = fixture.Doc.GetElement(new ElementId(346573)); + var param = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET); #if pre2021 var baseOffset = UnitUtils.ConvertFromInternalUnits(param.AsDouble(), param.DisplayUnitType); #else - var baseOffset = UnitUtils.ConvertFromInternalUnits(param.AsDouble(), param.GetUnitTypeId()); + var baseOffset = UnitUtils.ConvertFromInternalUnits(param.AsDouble(), param.GetUnitTypeId()); #endif - Assert.Equal(2000, baseOffset); - } + Assert.Equal(2000, baseOffset); + } - [Fact] - public void MoveWallsUp() { - var walls = fixture.Walls.Where(x => x.Id.IntegerValue != 346573); + [Fact] + public void MoveWallsUp() + { + var walls = fixture.Walls.Where(x => x.Id.IntegerValue != 346573); - xru.RunInTransaction(() => { - foreach (var wall in walls) { - var param = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET); + xru.RunInTransaction(() => + { + foreach (var wall in walls) + { + var param = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET); #if pre2021 var baseOffset = UnitUtils.ConvertToInternalUnits(2000, param.DisplayUnitType); #else - var baseOffset = UnitUtils.ConvertToInternalUnits(2000, param.GetUnitTypeId()); + var baseOffset = UnitUtils.ConvertToInternalUnits(2000, param.GetUnitTypeId()); #endif - param.Set(baseOffset); - } - }, fixture.Doc) - .Wait(); // Important! Wait for action to finish + param.Set(baseOffset); + } + }, fixture.Doc) + .Wait(); // Important! Wait for action to finish - foreach (var wall in walls) { - var param = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET); + foreach (var wall in walls) + { + var param = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET); #if pre2021 var baseOffset = UnitUtils.ConvertFromInternalUnits(param.AsDouble(), param.DisplayUnitType); #else - var baseOffset = UnitUtils.ConvertFromInternalUnits(param.AsDouble(), param.GetUnitTypeId()); + var baseOffset = UnitUtils.ConvertFromInternalUnits(param.AsDouble(), param.GetUnitTypeId()); #endif - Assert.Equal(2000, baseOffset); - } - } + Assert.Equal(2000, baseOffset); + } } + } } diff --git a/SampleLibrary/Utils.cs b/SampleLibrary/Utils.cs index e407b6d..5c56e9d 100644 --- a/SampleLibrary/Utils.cs +++ b/SampleLibrary/Utils.cs @@ -1,16 +1,19 @@ using System.IO; -namespace SampleLibrary { - public static class Utils { - /// - /// Utility method to get models from local folder rather than an absolute path - /// - /// - /// - public static string GetTestModel(string filename) { - var path = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "TestModels", filename); - return path; +namespace SampleLibrary +{ + public static class Utils + { + /// + /// Utility method to get models from local folder rather than an absolute path + /// + /// + /// + public static string GetTestModel(string filename) + { + var path = Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "TestModels", filename); + return path; - } } + } } diff --git a/xUnitRevit/App.cs b/xUnitRevit/App.cs index 7ddf1a3..62428eb 100644 --- a/xUnitRevit/App.cs +++ b/xUnitRevit/App.cs @@ -1,28 +1,33 @@ -#region Namespaces +#region Namespaces using Autodesk.Revit.ApplicationServices; using Autodesk.Revit.UI; #endregion -namespace xUnitRevit { - class App : IExternalApplication { - public Result OnStartup(UIControlledApplication a) { - a.ControlledApplication.ApplicationInitialized += ControlledApplication_ApplicationInitialized; +namespace xUnitRevit +{ + class App : IExternalApplication + { + public Result OnStartup(UIControlledApplication a) + { + a.ControlledApplication.ApplicationInitialized += ControlledApplication_ApplicationInitialized; - return Result.Succeeded; - } - - private void ControlledApplication_ApplicationInitialized(object sender, Autodesk.Revit.DB.Events.ApplicationInitializedEventArgs e) { - Application app = sender as Application; - UIApplication uiapp = new UIApplication(app); - - Runner.ReadConfig(); - - if (Runner.Config.autoStart) - Runner.Launch(uiapp); - } - - public Result OnShutdown(UIControlledApplication a) { - return Result.Succeeded; - } + return Result.Succeeded; } + + private void ControlledApplication_ApplicationInitialized(object sender, Autodesk.Revit.DB.Events.ApplicationInitializedEventArgs e) + { + Application app = sender as Application; + UIApplication uiapp = new UIApplication(app); + + Runner.ReadConfig(); + + if (Runner.Config.autoStart) + Runner.Launch(uiapp); + } + + public Result OnShutdown(UIControlledApplication a) + { + return Result.Succeeded; + } + } } diff --git a/xUnitRevit/CmdAvailabilityViews.cs b/xUnitRevit/CmdAvailabilityViews.cs index 0074b89..5c5da3d 100644 --- a/xUnitRevit/CmdAvailabilityViews.cs +++ b/xUnitRevit/CmdAvailabilityViews.cs @@ -1,19 +1,22 @@ using Autodesk.Revit.DB; using Autodesk.Revit.UI; -namespace xUnitRevit { - internal class CmdAvailabilityViews : IExternalCommandAvailability { +namespace xUnitRevit +{ + internal class CmdAvailabilityViews : IExternalCommandAvailability + { - /// - /// Command Availability - Views - /// - /// - /// - /// - public bool IsCommandAvailable(UIApplication applicationData, CategorySet selectedCategories) { - //Can be run from any view/state - return true; + /// + /// Command Availability - Views + /// + /// + /// + /// + public bool IsCommandAvailable(UIApplication applicationData, CategorySet selectedCategories) + { + //Can be run from any view/state + return true; - } } -} \ No newline at end of file + } +} diff --git a/xUnitRevit/Command.cs b/xUnitRevit/Command.cs index b51db71..19a8465 100644 --- a/xUnitRevit/Command.cs +++ b/xUnitRevit/Command.cs @@ -1,26 +1,29 @@ -#region Namespaces +#region Namespaces +using System.Threading; using Autodesk.Revit.Attributes; using Autodesk.Revit.DB; using Autodesk.Revit.UI; -using System.Threading; #endregion -namespace xUnitRevit { - [Transaction(TransactionMode.Manual)] - public class Command : IExternalCommand { - static object consoleLock = new object(); - static ManualResetEvent finished = new ManualResetEvent(false); - static Result result = Result.Succeeded; +namespace xUnitRevit +{ + [Transaction(TransactionMode.Manual)] + public class Command : IExternalCommand + { + static object consoleLock = new object(); + static ManualResetEvent finished = new ManualResetEvent(false); + static Result result = Result.Succeeded; - public Result Execute( - ExternalCommandData commandData, - ref string message, - ElementSet elements) { - UIApplication uiapp = commandData.Application; - Runner.Launch(uiapp); - return Result.Succeeded; - } + public Result Execute( + ExternalCommandData commandData, + ref string message, + ElementSet elements) + { + UIApplication uiapp = commandData.Application; + Runner.Launch(uiapp); + return Result.Succeeded; } + } } diff --git a/xUnitRevit/Configuration.cs b/xUnitRevit/Configuration.cs index fb5d646..fbd3a59 100644 --- a/xUnitRevit/Configuration.cs +++ b/xUnitRevit/Configuration.cs @@ -1,11 +1,13 @@ using System.Collections.Generic; -namespace xUnitRevit { - /// - /// Simple configuration file for lazy developers - /// - public class Configuration { - public IList StartupAssemblies { get; set; } = new List(); - public bool autoStart { get; set; } = false; - } +namespace xUnitRevit +{ + /// + /// Simple configuration file for lazy developers + /// + public class Configuration + { + public IList StartupAssemblies { get; set; } = new List(); + public bool autoStart { get; set; } = false; + } } diff --git a/xUnitRevit/ExternalEventHandler.cs b/xUnitRevit/ExternalEventHandler.cs index 2b090e3..f972882 100644 --- a/xUnitRevit/ExternalEventHandler.cs +++ b/xUnitRevit/ExternalEventHandler.cs @@ -1,38 +1,43 @@ -using Autodesk.Revit.UI; -using System; +using System; using System.Collections.Generic; using System.Diagnostics; +using Autodesk.Revit.UI; -namespace xUnitRevit { - /// - /// Event invoker. Has a queue of actions that, in theory, this thing should iterate through. - /// Required to run transactions form a non modal window. - /// - public class ExternalEventHandler : IExternalEventHandler { +namespace xUnitRevit +{ + /// + /// Event invoker. Has a queue of actions that, in theory, this thing should iterate through. + /// Required to run transactions form a non modal window. + /// + public class ExternalEventHandler : IExternalEventHandler + { - public bool Running = false; - public IList Queue { get; set; } + public bool Running = false; + public IList Queue { get; set; } - public ExternalEventHandler(IList queue) { - Queue = queue; - } - - public void Execute(UIApplication app) { - Debug.WriteLine("Current queue len is: " + Queue.Count); - if (Running) return; // queue will run itself through - - Running = true; - - Queue[0](); - - Queue.RemoveAt(0); - Running = false; - } - - public string GetName() { - return "xUnit Revit"; - } + public ExternalEventHandler(IList queue) + { + Queue = queue; } + + public void Execute(UIApplication app) + { + Debug.WriteLine("Current queue len is: " + Queue.Count); + if (Running) return; // queue will run itself through + + Running = true; + + Queue[0](); + + Queue.RemoveAt(0); + Running = false; + } + + public string GetName() + { + return "xUnit Revit"; + } + } } diff --git a/xUnitRevit/Runner.cs b/xUnitRevit/Runner.cs index 63f02ac..815f9f3 100644 --- a/xUnitRevit/Runner.cs +++ b/xUnitRevit/Runner.cs @@ -1,51 +1,58 @@ -using Autodesk.Revit.UI; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Threading; using System.Web.Script.Serialization; +using Autodesk.Revit.UI; using Xunit.Runner.Wpf; using Xunit.Runner.Wpf.ViewModel; using xUnitRevitUtils; -namespace xUnitRevit { - /// - /// Responsible for launching the xUnit WPF interface and initializing xru with Revit data - /// - public static class Runner { - internal static Configuration Config = new Configuration(); - internal static void Launch(UIApplication uiapp) { - try { - var queue = new List(); - var eventHandler = ExternalEvent.Create(new ExternalEventHandler(queue)); +namespace xUnitRevit +{ + /// + /// Responsible for launching the xUnit WPF interface and initializing xru with Revit data + /// + public static class Runner + { + internal static Configuration Config = new Configuration(); + internal static void Launch(UIApplication uiapp) + { + try + { + var queue = new List(); + var eventHandler = ExternalEvent.Create(new ExternalEventHandler(queue)); - xru.Initialize(uiapp, SynchronizationContext.Current, eventHandler, queue); + xru.Initialize(uiapp, SynchronizationContext.Current, eventHandler, queue); - var main = new MainWindow(); - main.Title = "xUnit Revit by Speckle"; - main.MaxHeight = 800; + var main = new MainWindow(); + main.Title = "xUnit Revit by Speckle"; + main.MaxHeight = 800; - //pre-load asssemblies, if you're a lazy developer - if (main.DataContext is MainViewModel mainViewModel) - mainViewModel.StartupAssemblies = Config.StartupAssemblies.ToList(); - main.Show(); - } - catch (Exception) { - //fail silently - } - } - - internal static void ReadConfig() { - try { - var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - var path = Path.Combine(dir, "config.json"); - JavaScriptSerializer JavaScriptSerializer = new JavaScriptSerializer(); - var json = File.ReadAllText(path); - Config = JavaScriptSerializer.Deserialize(json); - } - catch { } - } + //pre-load asssemblies, if you're a lazy developer + if (main.DataContext is MainViewModel mainViewModel) + mainViewModel.StartupAssemblies = Config.StartupAssemblies.ToList(); + main.Show(); + } + catch (Exception) + { + //fail silently + } } + + internal static void ReadConfig() + { + try + { + var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + var path = Path.Combine(dir, "config.json"); + JavaScriptSerializer JavaScriptSerializer = new JavaScriptSerializer(); + var json = File.ReadAllText(path); + Config = JavaScriptSerializer.Deserialize(json); + } + catch { } + } + } } diff --git a/xUnitRevitUtilsShared/xru.cs b/xUnitRevitUtilsShared/xru.cs index 66384ff..bc0de7a 100644 --- a/xUnitRevitUtilsShared/xru.cs +++ b/xUnitRevitUtilsShared/xru.cs @@ -2,154 +2,176 @@ using Autodesk.Revit.UI; using Xunit; -namespace xUnitRevitUtils { - /// - /// Utility class with methods and properties used by the xUnit Revit plugin - /// - public static class xru { - public static UIApplication Uiapp { get; set; } - private static IList Queue { get; set; } - private static ExternalEvent EventHandler { get; set; } - public static SynchronizationContext UiContext { get; set; } - public static void Initialize(UIApplication uiapp, SynchronizationContext uiContext, ExternalEvent eventHandler, IList queue) { - Uiapp = uiapp; - UiContext = uiContext; - EventHandler = eventHandler; - Queue = queue; - } - - #region utility methods - - /// - /// Returns the selected elements in the active document - /// - /// - public static IList GetActiveSelection() { - Assert.NotNull(Uiapp); - - if (Uiapp.ActiveUIDocument != null) - return Uiapp.ActiveUIDocument.Selection.GetElementIds().Select(x => Uiapp.ActiveUIDocument.Document.GetElement(x)).ToList(); - return new List(); - } - /// - /// Opens and activates a document if not open already - /// - /// Path to the file to open - public static Document OpenDoc(string filePath) { - Assert.NotNull(Uiapp); - Document doc = null; - //OpenAndActivateDocument only works if run from the current context - UiContext.Send(x => { doc = Uiapp.OpenAndActivateDocument(filePath).Document; }, null); - Assert.NotNull(doc); - return doc; - } - - /// - /// Creates a new empty document - /// - /// Path to the project template - /// Path where to save the new doc - /// If true overwrites existing files with same name - /// - public static Document CreateNewDoc(string templatePath, string filePath, bool overwrite = true) { - Assert.NotNull(Uiapp); - Document doc = null; - - try { - if (overwrite && File.Exists(filePath)) - File.Delete(filePath); - } - catch { } - - //OpenAndActivateDocument only works if run from the current context - UiContext.Send(x => { - //if already open, just use it - if (!File.Exists(filePath)) { - doc = Uiapp.Application.NewProjectDocument(templatePath); - doc.SaveAs(filePath); - doc.Close(); - } - - doc = Uiapp.OpenAndActivateDocument(filePath).Document; - } - , null); - Assert.NotNull(doc); - return doc; - } - - /// - /// Runs an Action in a Revit transaction, uses TaskCompletionSource to communicate when done - /// - /// Action to run - /// Revit Document - /// Transaction Name - /// Enable to swallow all warnings generated by the transaction and prevent them from being raised within Revit - /// - public static Task RunInTransaction(Action action, Document doc, string transactionName = "transaction", bool ignoreWarnings = false) { - var tcs = new TaskCompletionSource(); - Queue.Add(new Action(() => { - try { - using (Transaction transaction = new Transaction(doc, transactionName)) { - transaction.Start(); - - if (ignoreWarnings) { - var options = transaction.GetFailureHandlingOptions(); - options.SetFailuresPreprocessor(new IgnoreAllWarnings()); - transaction.SetFailureHandlingOptions(options); - } - - action.Invoke(); - transaction.Commit(); - } - } - catch (Exception e) { - tcs.TrySetException(e); - } - tcs.TrySetResult(""); - })); - - EventHandler.Raise(); - - return tcs.Task; - } - - /// - /// Runs an Action, uses TaskCompletionSource to communicate when done - /// - /// Action to run - /// Revit Document - /// - public static Task Run(Action action, Document doc) { - var tcs = new TaskCompletionSource(); - Queue.Add(new Action(() => { - try { - action.Invoke(); - } - catch (Exception e) { - tcs.TrySetException(e); - } - tcs.TrySetResult(""); - })); - - EventHandler.Raise(); - - return tcs.Task; - } - - /// - /// A failures preprocesser that clears any failures that occur within a transaction - /// - internal class IgnoreAllWarnings : IFailuresPreprocessor { - public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor) { - var failList = failuresAccessor.GetFailureMessages(); - - foreach (FailureMessageAccessor failure in failList) { - failuresAccessor.DeleteWarning(failure); - } - - return FailureProcessingResult.Continue; - } - } - #endregion +namespace xUnitRevitUtils +{ + /// + /// Utility class with methods and properties used by the xUnit Revit plugin + /// + public static class xru + { + public static UIApplication Uiapp { get; set; } + private static IList Queue { get; set; } + private static ExternalEvent EventHandler { get; set; } + public static SynchronizationContext UiContext { get; set; } + public static void Initialize(UIApplication uiapp, SynchronizationContext uiContext, ExternalEvent eventHandler, IList queue) + { + Uiapp = uiapp; + UiContext = uiContext; + EventHandler = eventHandler; + Queue = queue; } + + #region utility methods + + /// + /// Returns the selected elements in the active document + /// + /// + public static IList GetActiveSelection() + { + Assert.NotNull(Uiapp); + + if (Uiapp.ActiveUIDocument != null) + return Uiapp.ActiveUIDocument.Selection.GetElementIds().Select(x => Uiapp.ActiveUIDocument.Document.GetElement(x)).ToList(); + return new List(); + } + /// + /// Opens and activates a document if not open already + /// + /// Path to the file to open + public static Document OpenDoc(string filePath) + { + Assert.NotNull(Uiapp); + Document doc = null; + //OpenAndActivateDocument only works if run from the current context + UiContext.Send(x => { doc = Uiapp.OpenAndActivateDocument(filePath).Document; }, null); + Assert.NotNull(doc); + return doc; + } + + /// + /// Creates a new empty document + /// + /// Path to the project template + /// Path where to save the new doc + /// If true overwrites existing files with same name + /// + public static Document CreateNewDoc(string templatePath, string filePath, bool overwrite = true) + { + Assert.NotNull(Uiapp); + Document doc = null; + + try + { + if (overwrite && File.Exists(filePath)) + File.Delete(filePath); + } + catch { } + + //OpenAndActivateDocument only works if run from the current context + UiContext.Send(x => + { + //if already open, just use it + if (!File.Exists(filePath)) + { + doc = Uiapp.Application.NewProjectDocument(templatePath); + doc.SaveAs(filePath); + doc.Close(); + } + + doc = Uiapp.OpenAndActivateDocument(filePath).Document; + } + , null); + Assert.NotNull(doc); + return doc; + } + + /// + /// Runs an Action in a Revit transaction, uses TaskCompletionSource to communicate when done + /// + /// Action to run + /// Revit Document + /// Transaction Name + /// Enable to swallow all warnings generated by the transaction and prevent them from being raised within Revit + /// + public static Task RunInTransaction(Action action, Document doc, string transactionName = "transaction", bool ignoreWarnings = false) + { + var tcs = new TaskCompletionSource(); + Queue.Add(new Action(() => + { + try + { + using (Transaction transaction = new Transaction(doc, transactionName)) + { + transaction.Start(); + + if (ignoreWarnings) + { + var options = transaction.GetFailureHandlingOptions(); + options.SetFailuresPreprocessor(new IgnoreAllWarnings()); + transaction.SetFailureHandlingOptions(options); + } + + action.Invoke(); + transaction.Commit(); + } + } + catch (Exception e) + { + tcs.TrySetException(e); + } + tcs.TrySetResult(""); + })); + + EventHandler.Raise(); + + return tcs.Task; + } + + /// + /// Runs an Action, uses TaskCompletionSource to communicate when done + /// + /// Action to run + /// Revit Document + /// + public static Task Run(Action action, Document doc) + { + var tcs = new TaskCompletionSource(); + Queue.Add(new Action(() => + { + try + { + action.Invoke(); + } + catch (Exception e) + { + tcs.TrySetException(e); + } + tcs.TrySetResult(""); + })); + + EventHandler.Raise(); + + return tcs.Task; + } + + /// + /// A failures preprocesser that clears any failures that occur within a transaction + /// + internal class IgnoreAllWarnings : IFailuresPreprocessor + { + public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor) + { + var failList = failuresAccessor.GetFailureMessages(); + + foreach (FailureMessageAccessor failure in failList) + { + failuresAccessor.DeleteWarning(failure); + } + + return FailureProcessingResult.Continue; + } + } + #endregion + } }