diff --git a/SampleLibrary/SampleLibrary.csproj b/SampleLibrary/SampleLibrary.csproj index d82da80..f103af6 100644 --- a/SampleLibrary/SampleLibrary.csproj +++ b/SampleLibrary/SampleLibrary.csproj @@ -22,7 +22,7 @@ full false bin\Debug\ - DEBUG;TRACE + TRACE;DEBUG prompt 4 @@ -34,6 +34,27 @@ prompt 4 + + + true + full + false + bin\Debug\ + DEBUG;TRACE,post2021 + prompt + 4 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE,pre2021 + prompt + 4 + + ..\packages\ModPlus.Revit.API.2021.1.0.0\lib\AdWindows.dll diff --git a/SampleLibrary/SampleTest.cs b/SampleLibrary/SampleTest.cs index 48e0b0d..379c68d 100644 --- a/SampleLibrary/SampleTest.cs +++ b/SampleLibrary/SampleTest.cs @@ -34,8 +34,12 @@ namespace SampleLibrary [Fact] public void SampleFail() { - var feet = UnitUtils.ConvertToInternalUnits(3000, DisplayUnitType.DUT_MILLIMETERS); - Assert.Equal(5, feet); +#if pre2021 + var feet = UnitUtils.ConvertToInternalUnits(3000, DisplayUnitType.DUT_MILLIMETERS); +#else + var feet = UnitUtils.ConvertToInternalUnits(3000, UnitTypeId.Feet); +#endif + Assert.Equal(5, feet); } [Fact] @@ -60,12 +64,8 @@ namespace SampleLibrary 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 551a6f7..e469a77 100644 --- a/SampleLibrary/TestWithFixture.cs +++ b/SampleLibrary/TestWithFixture.cs @@ -47,9 +47,14 @@ namespace SampleLibrary { var wall = fixture.Doc.GetElement(new ElementId(346573)); var param = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET); - var baseOffset = UnitUtils.ConvertFromInternalUnits(param.AsDouble(), param.DisplayUnitType); - Assert.Equal(2000, baseOffset); +#if pre2021 + var baseOffset = UnitUtils.ConvertFromInternalUnits(param.AsDouble(), param.DisplayUnitType); +#else + var baseOffset = UnitUtils.ConvertFromInternalUnits(param.AsDouble(), param.GetUnitTypeId()); +#endif + + Assert.Equal(2000, baseOffset); } [Fact] @@ -62,8 +67,13 @@ namespace SampleLibrary foreach(var wall in walls) { var param = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET); - var baseOffset = UnitUtils.ConvertToInternalUnits(2000, param.DisplayUnitType); - param.Set(baseOffset); + +#if pre2021 + var baseOffset = UnitUtils.ConvertToInternalUnits(2000, param.DisplayUnitType); +#else + var baseOffset = UnitUtils.ConvertToInternalUnits(2000, param.GetUnitTypeId()); +#endif + param.Set(baseOffset); } }, fixture.Doc) .Wait(); // Important! Wait for action to finish @@ -71,8 +81,12 @@ namespace SampleLibrary foreach (var wall in walls) { var param = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET); - var baseOffset = UnitUtils.ConvertFromInternalUnits(param.AsDouble(), param.DisplayUnitType); - Assert.Equal(2000, baseOffset); +#if pre2021 + var baseOffset = UnitUtils.ConvertFromInternalUnits(param.AsDouble(), param.DisplayUnitType); +#else + var baseOffset = UnitUtils.ConvertFromInternalUnits(param.AsDouble(), param.GetUnitTypeId()); +#endif + Assert.Equal(2000, baseOffset); } } } diff --git a/xUnitRevit.sln b/xUnitRevit.sln index 9061394..3112c70 100644 --- a/xUnitRevit.sln +++ b/xUnitRevit.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30011.22 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32630.192 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "xUnitRevit", "xUnitRevit\xUnitRevit.csproj", "{27A79ACA-7EA8-4406-8BB8-216578CC3AB7}" EndProject @@ -13,12 +13,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xUnitRevitUtils2019", "xUni EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleLibrary", "SampleLibrary\SampleLibrary.csproj", "{C3A8684E-15BB-4B8B-B46C-35ACE3729C35}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xUnitRevitUtils2023", "xUnitRevitUtils2023\xUnitRevitUtils2023.csproj", "{E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xUnitRevitUtils2022", "xUnitRevitUtils2022\xUnitRevitUtils2022.csproj", "{78770414-4F6B-4429-BD8F-F0F64A349551}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug2019|Any CPU = Debug2019|Any CPU Debug2020|Any CPU = Debug2020|Any CPU Debug2021|Any CPU = Debug2021|Any CPU + Debug2022|Any CPU = Debug2022|Any CPU + Debug2023|Any CPU = Debug2023|Any CPU Release|Any CPU = Release|Any CPU Release2019|Any CPU = Release2019|Any CPU Release2020|Any CPU = Release2020|Any CPU @@ -33,6 +39,10 @@ Global {27A79ACA-7EA8-4406-8BB8-216578CC3AB7}.Debug2020|Any CPU.Build.0 = Debug2020|Any CPU {27A79ACA-7EA8-4406-8BB8-216578CC3AB7}.Debug2021|Any CPU.ActiveCfg = Debug2021|Any CPU {27A79ACA-7EA8-4406-8BB8-216578CC3AB7}.Debug2021|Any CPU.Build.0 = Debug2021|Any CPU + {27A79ACA-7EA8-4406-8BB8-216578CC3AB7}.Debug2022|Any CPU.ActiveCfg = Debug2022|Any CPU + {27A79ACA-7EA8-4406-8BB8-216578CC3AB7}.Debug2022|Any CPU.Build.0 = Debug2022|Any CPU + {27A79ACA-7EA8-4406-8BB8-216578CC3AB7}.Debug2023|Any CPU.ActiveCfg = Debug2023|Any CPU + {27A79ACA-7EA8-4406-8BB8-216578CC3AB7}.Debug2023|Any CPU.Build.0 = Debug2023|Any CPU {27A79ACA-7EA8-4406-8BB8-216578CC3AB7}.Release|Any CPU.ActiveCfg = Release2021|Any CPU {27A79ACA-7EA8-4406-8BB8-216578CC3AB7}.Release2019|Any CPU.ActiveCfg = Release2019|Any CPU {27A79ACA-7EA8-4406-8BB8-216578CC3AB7}.Release2019|Any CPU.Build.0 = Release2019|Any CPU @@ -46,6 +56,8 @@ Global {977E0B63-5706-4C2B-9C01-3C02D9EBE377}.Debug2020|Any CPU.ActiveCfg = Debug|Any CPU {977E0B63-5706-4C2B-9C01-3C02D9EBE377}.Debug2021|Any CPU.ActiveCfg = Debug|Any CPU {977E0B63-5706-4C2B-9C01-3C02D9EBE377}.Debug2021|Any CPU.Build.0 = Debug|Any CPU + {977E0B63-5706-4C2B-9C01-3C02D9EBE377}.Debug2022|Any CPU.ActiveCfg = Debug|Any CPU + {977E0B63-5706-4C2B-9C01-3C02D9EBE377}.Debug2023|Any CPU.ActiveCfg = Debug|Any CPU {977E0B63-5706-4C2B-9C01-3C02D9EBE377}.Release|Any CPU.ActiveCfg = Release|Any CPU {977E0B63-5706-4C2B-9C01-3C02D9EBE377}.Release|Any CPU.Build.0 = Release|Any CPU {977E0B63-5706-4C2B-9C01-3C02D9EBE377}.Release2019|Any CPU.ActiveCfg = Release|Any CPU @@ -58,6 +70,8 @@ Global {0DEF0F23-8AE2-461B-B014-8A0DA7494088}.Debug2020|Any CPU.ActiveCfg = Debug|Any CPU {0DEF0F23-8AE2-461B-B014-8A0DA7494088}.Debug2020|Any CPU.Build.0 = Debug|Any CPU {0DEF0F23-8AE2-461B-B014-8A0DA7494088}.Debug2021|Any CPU.ActiveCfg = Debug|Any CPU + {0DEF0F23-8AE2-461B-B014-8A0DA7494088}.Debug2022|Any CPU.ActiveCfg = Debug|Any CPU + {0DEF0F23-8AE2-461B-B014-8A0DA7494088}.Debug2023|Any CPU.ActiveCfg = Debug|Any CPU {0DEF0F23-8AE2-461B-B014-8A0DA7494088}.Release|Any CPU.ActiveCfg = Release|Any CPU {0DEF0F23-8AE2-461B-B014-8A0DA7494088}.Release|Any CPU.Build.0 = Release|Any CPU {0DEF0F23-8AE2-461B-B014-8A0DA7494088}.Release2019|Any CPU.ActiveCfg = Release|Any CPU @@ -70,6 +84,10 @@ Global {02399359-9CA0-4B47-B467-541E290E700F}.Debug2019|Any CPU.Build.0 = Debug|Any CPU {02399359-9CA0-4B47-B467-541E290E700F}.Debug2020|Any CPU.ActiveCfg = Debug|Any CPU {02399359-9CA0-4B47-B467-541E290E700F}.Debug2021|Any CPU.ActiveCfg = Debug|Any CPU + {02399359-9CA0-4B47-B467-541E290E700F}.Debug2022|Any CPU.ActiveCfg = Debug|Any CPU + {02399359-9CA0-4B47-B467-541E290E700F}.Debug2022|Any CPU.Build.0 = Debug|Any CPU + {02399359-9CA0-4B47-B467-541E290E700F}.Debug2023|Any CPU.ActiveCfg = Debug|Any CPU + {02399359-9CA0-4B47-B467-541E290E700F}.Debug2023|Any CPU.Build.0 = Debug|Any CPU {02399359-9CA0-4B47-B467-541E290E700F}.Release|Any CPU.ActiveCfg = Release|Any CPU {02399359-9CA0-4B47-B467-541E290E700F}.Release|Any CPU.Build.0 = Release|Any CPU {02399359-9CA0-4B47-B467-541E290E700F}.Release2019|Any CPU.ActiveCfg = Release|Any CPU @@ -84,6 +102,10 @@ Global {C3A8684E-15BB-4B8B-B46C-35ACE3729C35}.Debug2020|Any CPU.Build.0 = Debug|Any CPU {C3A8684E-15BB-4B8B-B46C-35ACE3729C35}.Debug2021|Any CPU.ActiveCfg = Debug|Any CPU {C3A8684E-15BB-4B8B-B46C-35ACE3729C35}.Debug2021|Any CPU.Build.0 = Debug|Any CPU + {C3A8684E-15BB-4B8B-B46C-35ACE3729C35}.Debug2022|Any CPU.ActiveCfg = Debug|Any CPU + {C3A8684E-15BB-4B8B-B46C-35ACE3729C35}.Debug2022|Any CPU.Build.0 = Debug|Any CPU + {C3A8684E-15BB-4B8B-B46C-35ACE3729C35}.Debug2023|Any CPU.ActiveCfg = Debug|Any CPU + {C3A8684E-15BB-4B8B-B46C-35ACE3729C35}.Debug2023|Any CPU.Build.0 = Debug|Any CPU {C3A8684E-15BB-4B8B-B46C-35ACE3729C35}.Release|Any CPU.ActiveCfg = Release|Any CPU {C3A8684E-15BB-4B8B-B46C-35ACE3729C35}.Release|Any CPU.Build.0 = Release|Any CPU {C3A8684E-15BB-4B8B-B46C-35ACE3729C35}.Release2019|Any CPU.ActiveCfg = Release|Any CPU @@ -92,6 +114,32 @@ Global {C3A8684E-15BB-4B8B-B46C-35ACE3729C35}.Release2020|Any CPU.Build.0 = Release|Any CPU {C3A8684E-15BB-4B8B-B46C-35ACE3729C35}.Release2021|Any CPU.ActiveCfg = Release|Any CPU {C3A8684E-15BB-4B8B-B46C-35ACE3729C35}.Release2021|Any CPU.Build.0 = Release|Any CPU + {E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4}.Debug2019|Any CPU.ActiveCfg = Debug|Any CPU + {E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4}.Debug2020|Any CPU.ActiveCfg = Debug|Any CPU + {E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4}.Debug2021|Any CPU.ActiveCfg = Debug|Any CPU + {E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4}.Debug2022|Any CPU.ActiveCfg = Debug|Any CPU + {E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4}.Debug2023|Any CPU.ActiveCfg = Debug|Any CPU + {E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4}.Debug2023|Any CPU.Build.0 = Debug|Any CPU + {E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4}.Release|Any CPU.Build.0 = Release|Any CPU + {E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4}.Release2019|Any CPU.ActiveCfg = Release|Any CPU + {E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4}.Release2020|Any CPU.ActiveCfg = Release|Any CPU + {E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4}.Release2021|Any CPU.ActiveCfg = Release|Any CPU + {78770414-4F6B-4429-BD8F-F0F64A349551}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {78770414-4F6B-4429-BD8F-F0F64A349551}.Debug|Any CPU.Build.0 = Debug|Any CPU + {78770414-4F6B-4429-BD8F-F0F64A349551}.Debug2019|Any CPU.ActiveCfg = Debug|Any CPU + {78770414-4F6B-4429-BD8F-F0F64A349551}.Debug2020|Any CPU.ActiveCfg = Debug|Any CPU + {78770414-4F6B-4429-BD8F-F0F64A349551}.Debug2021|Any CPU.ActiveCfg = Debug|Any CPU + {78770414-4F6B-4429-BD8F-F0F64A349551}.Debug2022|Any CPU.ActiveCfg = Debug|Any CPU + {78770414-4F6B-4429-BD8F-F0F64A349551}.Debug2022|Any CPU.Build.0 = Debug|Any CPU + {78770414-4F6B-4429-BD8F-F0F64A349551}.Debug2023|Any CPU.ActiveCfg = Debug|Any CPU + {78770414-4F6B-4429-BD8F-F0F64A349551}.Release|Any CPU.ActiveCfg = Release|Any CPU + {78770414-4F6B-4429-BD8F-F0F64A349551}.Release|Any CPU.Build.0 = Release|Any CPU + {78770414-4F6B-4429-BD8F-F0F64A349551}.Release2019|Any CPU.ActiveCfg = Release|Any CPU + {78770414-4F6B-4429-BD8F-F0F64A349551}.Release2020|Any CPU.ActiveCfg = Release|Any CPU + {78770414-4F6B-4429-BD8F-F0F64A349551}.Release2021|Any CPU.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/xUnitRevit/xUnitRevit.csproj b/xUnitRevit/xUnitRevit.csproj index da47d28..67f8d1d 100644 --- a/xUnitRevit/xUnitRevit.csproj +++ b/xUnitRevit/xUnitRevit.csproj @@ -36,7 +36,7 @@ pdbonly - true + false bin\Release\ TRACE prompt @@ -60,7 +60,7 @@ pdbonly - true + false bin\Release\ TRACE prompt @@ -84,7 +84,7 @@ pdbonly - true + false bin\Release\ TRACE prompt @@ -93,6 +93,30 @@ $(ProgramW6432)\Autodesk\Revit 2019\Revit.exe 2019 + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + Program + $(ProgramW6432)\Autodesk\Revit 2022\Revit.exe + 2022 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + Program + $(ProgramW6432)\Autodesk\Revit 2023\Revit.exe + 2023 + @@ -113,12 +137,17 @@ - - Always - Always + + Always + + @@ -165,6 +194,34 @@ + + + + 1.0.0 + runtime + + + + + {78770414-4F6B-4429-BD8F-F0F64A349551} + xUnitRevitUtils2022 + + + + + + + 1.0.0 + runtime + + + + + {E0BF38C2-13BC-4ACC-B0F2-4DFE82965DB4} + xUnitRevitUtils2023 + + + diff --git a/xUnitRevitUtils2022/xUnitRevitUtils2022.csproj b/xUnitRevitUtils2022/xUnitRevitUtils2022.csproj new file mode 100644 index 0000000..63de3a5 --- /dev/null +++ b/xUnitRevitUtils2022/xUnitRevitUtils2022.csproj @@ -0,0 +1,27 @@ + + + + netstandard2.0 + https://github.com/Speckle-Next/xunit-Revit + https://github.com/Speckle-Next/xunit-Revit + xunit revit runner + Speckle + Speckle + xUnit runner utilities for Revit 2021 + https://avatars2.githubusercontent.com/u/2092016 + xunit.png + MIT + true + xUnitRevitUtils + xUnitRevitUtils + xUnitRevitUtils.2021 + 1.0.4 + 1.0.4.0 + + + + + + + + diff --git a/xUnitRevitUtils2022/xUnitRevitUtils2022.nuspec b/xUnitRevitUtils2022/xUnitRevitUtils2022.nuspec new file mode 100644 index 0000000..d628e16 --- /dev/null +++ b/xUnitRevitUtils2022/xUnitRevitUtils2022.nuspec @@ -0,0 +1,22 @@ + + + + xUnitRevitUtils.2023 + $version$ + $title$ + $author$ + $author$ + false + MIT + https://github.com/Speckle-Next/xunit-Revit + https://avatars2.githubusercontent.com/u/2092016 + $description$ + + Copyright 2022 + xunit revit + + + + + + diff --git a/xUnitRevitUtils2022/xru.cs b/xUnitRevitUtils2022/xru.cs new file mode 100644 index 0000000..e24fb25 --- /dev/null +++ b/xUnitRevitUtils2022/xru.cs @@ -0,0 +1,191 @@ +using Autodesk.Revit.DB; +using Autodesk.Revit.UI; +using Autodesk.Revit.UI.Selection; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +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 List 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, List queue) + { + Uiapp = uiapp; + UiContext = uiContext; + EventHandler = eventHandler; + Queue = queue; + } + + #region utility methods + + + /// + /// Returns the selected elements in the active document + /// + /// + public static List 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 + } +} diff --git a/xUnitRevitUtils2023/xUnitRevitUtils2023.csproj b/xUnitRevitUtils2023/xUnitRevitUtils2023.csproj new file mode 100644 index 0000000..1123025 --- /dev/null +++ b/xUnitRevitUtils2023/xUnitRevitUtils2023.csproj @@ -0,0 +1,27 @@ + + + + netstandard2.0 + https://github.com/Speckle-Next/xunit-Revit + https://github.com/Speckle-Next/xunit-Revit + xunit revit runner + Speckle + Speckle + xUnit runner utilities for Revit 2023 + https://avatars2.githubusercontent.com/u/2092016 + xunit.png + MIT + true + xUnitRevitUtils + xUnitRevitUtils + xUnitRevitUtils.2023 + 1.0.4 + 1.0.4.0 + + + + + + + + diff --git a/xUnitRevitUtils2023/xUnitRevitUtils2023.nuspec b/xUnitRevitUtils2023/xUnitRevitUtils2023.nuspec new file mode 100644 index 0000000..d628e16 --- /dev/null +++ b/xUnitRevitUtils2023/xUnitRevitUtils2023.nuspec @@ -0,0 +1,22 @@ + + + + xUnitRevitUtils.2023 + $version$ + $title$ + $author$ + $author$ + false + MIT + https://github.com/Speckle-Next/xunit-Revit + https://avatars2.githubusercontent.com/u/2092016 + $description$ + + Copyright 2022 + xunit revit + + + + + + diff --git a/xUnitRevitUtils2023/xru.cs b/xUnitRevitUtils2023/xru.cs new file mode 100644 index 0000000..e24fb25 --- /dev/null +++ b/xUnitRevitUtils2023/xru.cs @@ -0,0 +1,191 @@ +using Autodesk.Revit.DB; +using Autodesk.Revit.UI; +using Autodesk.Revit.UI.Selection; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +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 List 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, List queue) + { + Uiapp = uiapp; + UiContext = uiContext; + EventHandler = eventHandler; + Queue = queue; + } + + #region utility methods + + + /// + /// Returns the selected elements in the active document + /// + /// + public static List 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 + } +}