diff --git a/bin/Nett.dll b/bin/Nett.dll index a03e958fd..568961ee4 100644 Binary files a/bin/Nett.dll and b/bin/Nett.dll differ diff --git a/bin/engines/273/pyRevitLoader.pdb b/bin/engines/273/pyRevitLoader.pdb deleted file mode 100644 index 8c9d08f9e..000000000 Binary files a/bin/engines/273/pyRevitLoader.pdb and /dev/null differ diff --git a/bin/engines/273/pyRevitRunner.pdb b/bin/engines/273/pyRevitRunner.pdb deleted file mode 100644 index 5617bfc10..000000000 Binary files a/bin/engines/273/pyRevitRunner.pdb and /dev/null differ diff --git a/bin/engines/277/pyRevitLoader.dll b/bin/engines/277/pyRevitLoader.dll index 05a480d64..0a504a656 100644 Binary files a/bin/engines/277/pyRevitLoader.dll and b/bin/engines/277/pyRevitLoader.dll differ diff --git a/bin/engines/277/pyRevitLoader.pdb b/bin/engines/277/pyRevitLoader.pdb deleted file mode 100644 index 8c9d08f9e..000000000 Binary files a/bin/engines/277/pyRevitLoader.pdb and /dev/null differ diff --git a/bin/engines/277/pyRevitRunner.pdb b/bin/engines/277/pyRevitRunner.pdb deleted file mode 100644 index 5617bfc10..000000000 Binary files a/bin/engines/277/pyRevitRunner.pdb and /dev/null differ diff --git a/bin/engines/278/pyRevitLoader.pdb b/bin/engines/278/pyRevitLoader.pdb deleted file mode 100644 index 8c9d08f9e..000000000 Binary files a/bin/engines/278/pyRevitLoader.pdb and /dev/null differ diff --git a/bin/engines/278/pyRevitRunner.pdb b/bin/engines/278/pyRevitRunner.pdb deleted file mode 100644 index 5617bfc10..000000000 Binary files a/bin/engines/278/pyRevitRunner.pdb and /dev/null differ diff --git a/bin/engines/279/pyRevitLoader.pdb b/bin/engines/279/pyRevitLoader.pdb deleted file mode 100644 index 8c9d08f9e..000000000 Binary files a/bin/engines/279/pyRevitLoader.pdb and /dev/null differ diff --git a/bin/engines/279/pyRevitRunner.pdb b/bin/engines/279/pyRevitRunner.pdb deleted file mode 100644 index 5617bfc10..000000000 Binary files a/bin/engines/279/pyRevitRunner.pdb and /dev/null differ diff --git a/bin/engines/368/Python.Runtime.dll b/bin/engines/368/Python.Runtime.dll index 2ade26f88..cdbd14209 100644 Binary files a/bin/engines/368/Python.Runtime.dll and b/bin/engines/368/Python.Runtime.dll differ diff --git a/bin/engines/372/Python.Runtime.dll b/bin/engines/372/Python.Runtime.dll index 090a77c04..27e9adad3 100644 Binary files a/bin/engines/372/Python.Runtime.dll and b/bin/engines/372/Python.Runtime.dll differ diff --git a/bin/pyRevitLabs.Common.dll b/bin/pyRevitLabs.Common.dll index 03c4963eb..7c0cd09f0 100644 Binary files a/bin/pyRevitLabs.Common.dll and b/bin/pyRevitLabs.Common.dll differ diff --git a/bin/pyRevitLabs.CommonCLI.dll b/bin/pyRevitLabs.CommonCLI.dll index 6b821264d..7d2cca428 100644 Binary files a/bin/pyRevitLabs.CommonCLI.dll and b/bin/pyRevitLabs.CommonCLI.dll differ diff --git a/bin/pyRevitLabs.CommonWPF.dll b/bin/pyRevitLabs.CommonWPF.dll index 3f8a9e9bc..018a8bc48 100644 Binary files a/bin/pyRevitLabs.CommonWPF.dll and b/bin/pyRevitLabs.CommonWPF.dll differ diff --git a/bin/pyRevitLabs.DeffrelDB.dll b/bin/pyRevitLabs.DeffrelDB.dll index 3f17c7b73..eb28cc105 100644 Binary files a/bin/pyRevitLabs.DeffrelDB.dll and b/bin/pyRevitLabs.DeffrelDB.dll differ diff --git a/bin/pyRevitLabs.Language.dll b/bin/pyRevitLabs.Language.dll index a3191738c..817d735d7 100644 Binary files a/bin/pyRevitLabs.Language.dll and b/bin/pyRevitLabs.Language.dll differ diff --git a/bin/pyRevitLabs.NLog.dll b/bin/pyRevitLabs.NLog.dll new file mode 100644 index 000000000..bebf2e4b0 Binary files /dev/null and b/bin/pyRevitLabs.NLog.dll differ diff --git a/bin/pyRevitLabs.TargetApps.AutoCAD.dll b/bin/pyRevitLabs.TargetApps.AutoCAD.dll index 8eb97fe30..272e96443 100644 Binary files a/bin/pyRevitLabs.TargetApps.AutoCAD.dll and b/bin/pyRevitLabs.TargetApps.AutoCAD.dll differ diff --git a/bin/pyRevitLabs.TargetApps.Navisworks.dll b/bin/pyRevitLabs.TargetApps.Navisworks.dll index 142e8dc54..01f9ce3ff 100644 Binary files a/bin/pyRevitLabs.TargetApps.Navisworks.dll and b/bin/pyRevitLabs.TargetApps.Navisworks.dll differ diff --git a/bin/pyRevitLabs.TargetApps.Revit.dll b/bin/pyRevitLabs.TargetApps.Revit.dll index e74957afc..1a55aeb82 100644 Binary files a/bin/pyRevitLabs.TargetApps.Revit.dll and b/bin/pyRevitLabs.TargetApps.Revit.dll differ diff --git a/bin/pyrevit-updater b/bin/pyrevit-updater index bfea37648..cef8c9d5b 100644 Binary files a/bin/pyrevit-updater and b/bin/pyrevit-updater differ diff --git a/bin/pyrevit.exe b/bin/pyrevit.exe index 064bb8725..b020fd6f0 100644 Binary files a/bin/pyrevit.exe and b/bin/pyrevit.exe differ diff --git a/dev/README.md b/dev/README.md index bb698f1b5..4f6332536 100644 --- a/dev/README.md +++ b/dev/README.md @@ -43,8 +43,20 @@ Changes listed here were made to the Visual Studio project - Refactored `StaticResource` and `DynamicResource` references to `pyRevitLabs.MahAppsMetro` - Renamed project assembly name to `pyRevitLabs.MahAppsMetro` +## NLog + +[See related issues here](https://github.com/eirannejad/pyRevit/issues/579) + +`NLog` (==4.6.4) was recompile to `pyRevitLabs.NLog` (==4.6.4 | .NET 4.5) to avoid the conflict. + +Changes listed here were made to the Visual Studio project + +- Refactored the root namespace to `pyRevitLabs.NLog` +- Changed Package settings to version 4.6.4 +- Renamed project assembly name to `pyRevitLabs.NLog` + ## natsort natsort.natsort.py -wrapped natsort_key.__doc__ (line # 209) in try-except for IronPython 2.7.3 compatibility \ No newline at end of file +wrapped natsort_key.__doc__ (line # 209) in try-except for IronPython 2.7.3 compatibility diff --git a/dev/pyRevitLabs/pyRevitLabs.Common/CommonUtils.cs b/dev/pyRevitLabs/pyRevitLabs.Common/CommonUtils.cs index c682f7d75..2480efff9 100644 --- a/dev/pyRevitLabs/pyRevitLabs.Common/CommonUtils.cs +++ b/dev/pyRevitLabs/pyRevitLabs.Common/CommonUtils.cs @@ -9,7 +9,7 @@ using System.Text.RegularExpressions; using IWshRuntimeLibrary; -using NLog; +using pyRevitLabs.NLog; namespace pyRevitLabs.Common { public static class CommonUtils { diff --git a/dev/pyRevitLabs/pyRevitLabs.Common/Extensions/Extensions.cs b/dev/pyRevitLabs/pyRevitLabs.Common/Extensions/Extensions.cs index 207ed4aea..843764381 100644 --- a/dev/pyRevitLabs/pyRevitLabs.Common/Extensions/Extensions.cs +++ b/dev/pyRevitLabs/pyRevitLabs.Common/Extensions/Extensions.cs @@ -6,8 +6,11 @@ using System.Threading.Tasks; using System.Text.RegularExpressions; using System.Globalization; +using System.CodeDom.Compiler; +using System.CodeDom; +using System.Web; -using NLog; +using pyRevitLabs.NLog; using pyRevitLabs.Json; namespace pyRevitLabs.Common.Extensions { @@ -264,6 +267,55 @@ public static string ConvertToCommaSeparatedString(this IEnumerable sour public static List ConvertFromCommaSeparatedString(this string commaSeparatedValue) { return new List(commaSeparatedValue.Split(',')); } + + public static string ToLiteral(this string input) { + using (var writer = new StringWriter()) { + using (var provider = CodeDomProvider.CreateProvider("CSharp")) { + provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null); + return writer.ToString(); + } + } + } + + public static string ToEscaped(this string input, bool WrapInQuotes = false) { + var literal = new StringBuilder(input.Length + 2); + if (WrapInQuotes) + literal.Append("\""); + + foreach (var c in input) { + switch (c) { + case '\'': literal.Append(@"\'"); break; + case '\"': literal.Append("\\\""); break; + case '\\': literal.Append(@"\\"); break; + case '\0': literal.Append(@"\0"); break; + case '\a': literal.Append(@"\a"); break; + case '\b': literal.Append(@"\b"); break; + case '\f': literal.Append(@"\f"); break; + case '\n': literal.Append(@"\n"); break; + case '\r': literal.Append(@"\r"); break; + case '\t': literal.Append(@"\t"); break; + case '\v': literal.Append(@"\v"); break; + default: + if (Char.GetUnicodeCategory(c) != UnicodeCategory.Control) { + literal.Append(c); + } + else { + literal.Append(@"\u"); + literal.Append(((ushort)c).ToString("x4")); + } + break; + } + } + + if (WrapInQuotes) + literal.Append("\""); + + return literal.ToString(); + } + + public static string PrepareJSONForCSV(this string input) { + return "\"" + input.Replace("\"", "\"\"") + "\""; + } } public static class DateTimeExtensions { diff --git a/dev/pyRevitLabs/pyRevitLabs.Common/GitInstaller.cs b/dev/pyRevitLabs/pyRevitLabs.Common/GitInstaller.cs index 0cc952b17..2bced0d6b 100644 --- a/dev/pyRevitLabs/pyRevitLabs.Common/GitInstaller.cs +++ b/dev/pyRevitLabs/pyRevitLabs.Common/GitInstaller.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; using LibGit2Sharp; -using NLog; +using pyRevitLabs.NLog; namespace pyRevitLabs.Common { // git exceptions diff --git a/dev/pyRevitLabs/pyRevitLabs.Common/UserEnv.cs b/dev/pyRevitLabs/pyRevitLabs.Common/UserEnv.cs index 0784225b0..962aa592a 100644 --- a/dev/pyRevitLabs/pyRevitLabs.Common/UserEnv.cs +++ b/dev/pyRevitLabs/pyRevitLabs.Common/UserEnv.cs @@ -11,6 +11,7 @@ using System.Security.AccessControl; using DotNetVersionFinder; +using pyRevitLabs.NLog; // user default folder implementation from https://stackoverflow.com/a/21953690/2350244 @@ -37,6 +38,8 @@ public enum KnownFolder { } public static class UserEnv { + private static Logger logger = LogManager.GetCurrentClassLogger(); + public static string GetWindowsVersion() { // https://docs.microsoft.com/en-us/windows/desktop/SysInfo/operating-system-version // https://stackoverflow.com/a/37700770/2350244 @@ -66,17 +69,20 @@ public static List GetInstalledDotnetCoreTargetPacks() { } public static string GetLoggedInUserName() { - ConnectionOptions oConn = new ConnectionOptions(); - ManagementScope oMs = new ManagementScope("\\\\localhost", oConn); - - ObjectQuery oQuery = new ObjectQuery("select * from Win32_ComputerSystem"); - ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(oMs, oQuery); - ManagementObjectCollection oReturnCollection = oSearcher.Get(); - - foreach (ManagementObject oReturn in oReturnCollection) { - return oReturn["UserName"].ToString(); + try { + ConnectionOptions oConn = new ConnectionOptions(); + ManagementScope oMs = new ManagementScope("\\\\localhost", oConn); + + ObjectQuery oQuery = new ObjectQuery("select * from Win32_ComputerSystem"); + ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(oMs, oQuery); + ManagementObjectCollection oReturnCollection = oSearcher.Get(); + + foreach (ManagementObject oReturn in oReturnCollection) { + return oReturn["UserName"].ToString(); + } + } catch (Exception ex) { + logger.Debug("Failed to get logged in username. | {0}", ex.Message); } - return null; } diff --git a/dev/pyRevitLabs/pyRevitLabs.Common/pyRevitLabs.Common.csproj b/dev/pyRevitLabs/pyRevitLabs.Common/pyRevitLabs.Common.csproj index b0e20aea3..4d18be802 100644 --- a/dev/pyRevitLabs/pyRevitLabs.Common/pyRevitLabs.Common.csproj +++ b/dev/pyRevitLabs/pyRevitLabs.Common/pyRevitLabs.Common.csproj @@ -40,9 +40,13 @@ true + ..\..\..\bin\pyRevitLabs.Json.dll + + ..\..\..\bin\pyRevitLabs.NLog.dll + @@ -51,6 +55,7 @@ + @@ -82,9 +87,6 @@ 2.0.3 - - 4.6.3 - 2.2.1.3 diff --git a/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/DataBase.cs b/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/DataBase.cs index 22f4f0989..ac4f6f3f1 100644 --- a/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/DataBase.cs +++ b/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/DataBase.cs @@ -3,14 +3,14 @@ using System.Text; using pyRevitLabs.Common; -using NLog.Targets; -using NLog.Config; +using pyRevitLabs.NLog.Targets; +using pyRevitLabs.NLog.Config; #if DEBUG using pyRevitLabs.CommonCLI; #endif -using NLog; +using pyRevitLabs.NLog; // TODO: add log messages diff --git a/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/DataStore.cs b/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/DataStore.cs index 455cf7b79..c5f256f8d 100644 --- a/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/DataStore.cs +++ b/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/DataStore.cs @@ -9,7 +9,7 @@ using pyRevitLabs.Common; -using NLog; +using pyRevitLabs.NLog; namespace pyRevitLabs.DeffrelDB { // datastore diff --git a/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/DefaultDataFormatter.cs b/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/DefaultDataFormatter.cs index f1076cd80..9b61a0c90 100644 --- a/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/DefaultDataFormatter.cs +++ b/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/DefaultDataFormatter.cs @@ -4,7 +4,7 @@ using System.Text; using System.Text.RegularExpressions; -using NLog; +using pyRevitLabs.NLog; namespace pyRevitLabs.DeffrelDB { internal class DefaultDataFormatter: IDataFormatter { diff --git a/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/packages.config b/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/packages.config deleted file mode 100644 index f65ab759e..000000000 --- a/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/pyRevitLabs.DeffrelDB.csproj b/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/pyRevitLabs.DeffrelDB.csproj index 5016461e2..42d8b0a9e 100644 --- a/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/pyRevitLabs.DeffrelDB.csproj +++ b/dev/pyRevitLabs/pyRevitLabs.DeffrelDB/pyRevitLabs.DeffrelDB.csproj @@ -36,8 +36,8 @@ true - - ..\packages\NLog.4.6.3\lib\net45\NLog.dll + + ..\..\..\bin\pyRevitLabs.NLog.dll @@ -75,9 +75,6 @@ pyRevitLabs.Common - - - copy "$(TargetPath)" "$(TargetDir)..\..\..\..\..\bin" diff --git a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/Addons.cs b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/Addons.cs index a208f5379..9b4a5f5aa 100644 --- a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/Addons.cs +++ b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/Addons.cs @@ -8,7 +8,7 @@ using pyRevitLabs.Common; using pyRevitLabs.Common.Extensions; -using NLog; +using pyRevitLabs.NLog; namespace pyRevitLabs.TargetApps.Revit { public class RevitAddonManifest { diff --git a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/Controls/FillPatternViewerControl.cs b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/Controls/FillPatternViewerControl.cs index 466136e09..77f797584 100644 --- a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/Controls/FillPatternViewerControl.cs +++ b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/Controls/FillPatternViewerControl.cs @@ -9,7 +9,7 @@ using pyRevitLabs.CommonWPF.Converters; -using NLog; +using pyRevitLabs.NLog; using Image = System.Drawing.Image; using Matrix = System.Drawing.Drawing2D.Matrix; diff --git a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/Properties/AssemblyInfo.cs b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/Properties/AssemblyInfo.cs index b4548b5de..4e4106eb2 100644 --- a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/Properties/AssemblyInfo.cs +++ b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.19.0.0")] -[assembly: AssemblyFileVersion("0.19.0.0")] +[assembly: AssemblyVersion("0.20.0.0")] +[assembly: AssemblyFileVersion("0.20.0.0")] diff --git a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevit.cs b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevit.cs index 47c4f31ea..e01e0f970 100644 --- a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevit.cs +++ b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevit.cs @@ -11,7 +11,7 @@ using MadMilkman.Ini; using pyRevitLabs.Json.Linq; -using NLog; +using pyRevitLabs.NLog; namespace pyRevitLabs.TargetApps.Revit { // main pyrevit functionality class @@ -434,7 +434,7 @@ public static void UpdateAllClones() { // @handled @logs public static void Attach(int revitYear, PyRevitClone clone, - int engineVer = 000, + int engineVer, bool allUsers = false, bool force = false) { // make the addin manifest file @@ -453,7 +453,7 @@ public static void Attach(int revitYear, allusers: allUsers); } else - throw new pyRevitException(string.Format("Engine \"{0}\" can not be used as runtime.", engineVer)); + throw new pyRevitException(string.Format("Engine {0} can not be used as runtime.", engineVer)); } // attach clone to all installed revit versions diff --git a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitClone.cs b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitClone.cs index e989e857e..d90722456 100644 --- a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitClone.cs +++ b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitClone.cs @@ -9,7 +9,7 @@ using pyRevitLabs.Common.Extensions; using Nett; -using NLog; +using pyRevitLabs.NLog; namespace pyRevitLabs.TargetApps.Revit { // helper struct @@ -164,7 +164,7 @@ public void Rename(string newName) { public List GetEngines() => GetEngines(ClonePath); - public PyRevitEngine GetEngine(int engineVer = 000) => GetEngine(ClonePath, engineVer: engineVer); + public PyRevitEngine GetEngine(int engineVer) => GetEngine(ClonePath, engineVer: engineVer); public List GetConfiguredEngines() => GetConfiguredEngines(ClonePath); @@ -263,17 +263,9 @@ public static bool IsCloneValid(string clonePath) { // get engine from clone path // returns latest with default engineVer value // @handled @logs - public static PyRevitEngine GetEngine(string clonePath, int engineVer = 000) { + public static PyRevitEngine GetEngine(string clonePath, int engineVer) { logger.Debug("Finding engine \"{0}\" path in \"{1}\"", engineVer, clonePath); - - // find latest - if (engineVer == 000) { - return GetEngines(clonePath).OrderByDescending(x => x.Version).First(); - } - // or specified - else { - return GetEngines(clonePath).Where(x => x.Version == engineVer).First(); - } + return GetEngines(clonePath).Where(x => x.Version == engineVer).First(); } // get all engines from clone path @@ -302,7 +294,7 @@ public static List GetConfiguredEngines(string clonePath) { logger.Debug("Engine configuration found: {0}", engineCfg.Key); var infoTable = engineCfg.Value as TomlTable; foreach (KeyValuePair entry in infoTable) - logger.Debug("\"{0}\" : \"{1}\"", entry.Key, entry.Value.TomlType); + logger.Debug("\"{0}\" : \"{1}\"", entry.Key, entry.Value); engines.Add( new PyRevitEngine( diff --git a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitExtension.cs b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitExtension.cs index 47e69194d..ac31adf8c 100644 --- a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitExtension.cs +++ b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitExtension.cs @@ -8,7 +8,7 @@ using pyRevitLabs.Common; using pyRevitLabs.Json.Linq; -using NLog; +using pyRevitLabs.NLog; namespace pyRevitLabs.TargetApps.Revit { public class PyRevitExtensionDefinition { diff --git a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitRelease.cs b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitRelease.cs index 0baa33fed..1dfee9136 100644 --- a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitRelease.cs +++ b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitRelease.cs @@ -10,7 +10,7 @@ using pyRevitLabs.Common; using pyRevitLabs.Common.Extensions; -using NLog; +using pyRevitLabs.NLog; using pyRevitLabs.Json; using pyRevitLabs.Json.Linq; diff --git a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitRunner.cs b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitRunner.cs index a8bdc093d..242226c3e 100644 --- a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitRunner.cs +++ b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/PyRevit/PyRevitRunner.cs @@ -8,7 +8,7 @@ using pyRevitLabs.Common; using pyRevitLabs.Common.Extensions; -using NLog; +using pyRevitLabs.NLog; namespace pyRevitLabs.TargetApps.Revit { public class PyRevitRunnerExecEnv { diff --git a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/RevitController.cs b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/RevitController.cs index 056e311eb..f34cfe84e 100644 --- a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/RevitController.cs +++ b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/RevitController.cs @@ -2,17 +2,18 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.IO.Compression; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Text.RegularExpressions; +using System.Xml; using Microsoft.Win32; using pyRevitLabs.Common; using pyRevitLabs.Common.Extensions; -using NLog; -using System.Xml; +using pyRevitLabs.NLog; namespace pyRevitLabs.TargetApps.Revit { // EXCEPTIONS ==================================================================================================== @@ -88,12 +89,35 @@ public RevitModelFile(string filePath) { else throw new pyRevitException(string.Format("Target is not a valid Revit model \"{0}\"", filePath)); + // extract ProjectInformation (Revit Project Files) + // ProjectInformation is a PK Zip stream + var rawProjectInformationData = CommonUtils.GetStructuredStorageStream(FilePath, "ProjectInformation"); + if (rawProjectInformationData != null) { + Stream zipData = new MemoryStream(rawProjectInformationData); + var zipFile = new ZipArchive(zipData); + foreach (var entry in zipFile.Entries) { + if (entry.FullName.ToLower().EndsWith(".project.xml")) { + logger.Debug("Reading Project Info from: \"{0}\"", entry.FullName); + using (Stream projectInfoXamlData = entry.Open()) { + var projectInfoXmlData = new StreamReader(projectInfoXamlData).ReadToEnd(); + ProcessProjectInfo(projectInfoXmlData); + } + } + } + } else { + ProjectInfoProperties = new Dictionary(); + } + // extract partatom (Revit Family Files) and prepare string - // throws exception if stream doesn't exist + // PartAtom is a Xml stream + // https://ein.sh/pyRevit/pyrevit/updates/2019/01/19/basicfileinfo.html var rawPartAtomData = CommonUtils.GetStructuredStorageStream(FilePath, "PartAtom"); if (rawPartAtomData != null) { IsFamily = true; ProcessPartAtom(Encoding.ASCII.GetString(rawPartAtomData)); + } else { + CategoryName = ""; + HostCategoryName = ""; } } @@ -221,6 +245,37 @@ private void ProcessPartAtom(string rawPartAtom) { } } + private void ProcessProjectInfo(string rawProjectInfoData) { + logger.Debug("Parsing ProjctInformation Data: \"{0}\"", rawProjectInfoData); + var doc = new XmlDocument(); + try { + doc.LoadXml(rawProjectInfoData); + XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable); + nsmgr.AddNamespace("rfa", @"http://www.w3.org/2005/Atom"); + nsmgr.AddNamespace("A", @"urn:schemas-autodesk-com:partatom"); + + // extract project parameters + var projectInfoDict = new Dictionary(); + XmlNodeList propertyGroups = doc.SelectNodes("//rfa:entry/A:features/A:feature/A:group", nsmgr); + foreach(XmlElement properyGroup in propertyGroups) { + foreach(XmlElement child in properyGroup.ChildNodes) { + if (child.HasAttribute("displayName")) { + string propertyName = child.GetAttribute("displayName"); + string propertyValue = child.InnerText; + logger.Debug("\"{0}\" = \"{1}\"", propertyName, propertyValue); + projectInfoDict.Add(propertyName, propertyValue); + } + } + } + + // set the created info dict + ProjectInfoProperties = projectInfoDict; + } + catch (Exception ex) { + logger.Debug("Error parsing PartAtom XML. | {0}", ex.Message); + } + } + public string FilePath { get; private set; } public bool IsFamily { get; private set; } @@ -241,6 +296,8 @@ private void ProcessPartAtom(string rawPartAtom) { public RevitProduct RevitProduct { get; private set; } = null; + public Dictionary ProjectInfoProperties { get; private set; } + public string CategoryName { get; private set; } public string HostCategoryName { get; private set; } @@ -331,7 +388,7 @@ public class RevitProduct { {"20120221_2030", ("12.02.21203", "2013 First Customer Ship")}, {"20120716_1115", ("0.0.0.0", "2013 Update Release 1")}, {"20121003_2115", ("0.0.0.0", "2013 Update Release 2")}, - {"20130531_2115", ("0.0.0.0", "2013 Update Release 3")}, + {"20130531_2115", ("12.11.10090", "2013 Update Release 3")}, // https://github.com/eirannejad/pyRevit/issues/622 {"20120821_1330", ("0.0.0.0", "2013 LT First Customer Ship")}, {"20130531_0300", ("0.0.0.0", "2013 LT Update Release 1")}, @@ -554,7 +611,16 @@ public string InstallLocation { public int LanguageCode { get; set; } // static: - public static string GetBinaryLocation(string installPath) => Path.Combine(installPath, "Revit.exe"); + public static string GetBinaryLocation(string installPath) { + var possibleLocations = new List() { + Path.Combine(installPath, "Revit.exe"), + Path.Combine(installPath, "Program", "Revit.exe") + }; + foreach (var binaryLoc in possibleLocations) + if (File.Exists(binaryLoc)) + return binaryLoc; + return null; + } public static string GetBinaryBuildNumber(string binaryPath) { var fileInfo = FileVersionInfo.GetVersionInfo(binaryPath); @@ -622,9 +688,11 @@ public static List ListInstalledProducts() { logger.Debug("Could not determine Revit Product from version \"{0}\"", regVersion); // try to get product key from binary var binaryLocation = GetBinaryLocation(regPath); - var buildNumber = GetBinaryBuildNumber(binaryLocation); - logger.Debug("Read build number \"{0}\" from binary at \"{1}\"", buildNumber, binaryLocation); - revitProduct = LookupRevitProduct(buildNumber); + if (binaryLocation != null) { + var buildNumber = GetBinaryBuildNumber(binaryLocation); + logger.Debug("Read build number \"{0}\" from binary at \"{1}\"", buildNumber, binaryLocation); + revitProduct = LookupRevitProduct(buildNumber); + } } logger.Debug("Revit Product is : {0}", revitProduct); diff --git a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/pyRevitLabs.TargetApps.Revit.csproj b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/pyRevitLabs.TargetApps.Revit.csproj index fab2dc68e..79def2a1a 100644 --- a/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/pyRevitLabs.TargetApps.Revit.csproj +++ b/dev/pyRevitLabs/pyRevitLabs.TargetApps.Revit/pyRevitLabs.TargetApps.Revit.csproj @@ -44,6 +44,9 @@ ..\..\..\bin\pyRevitLabs.Json.dll + + ..\..\..\bin\pyRevitLabs.NLog.dll + ..\..\..\..\..\..\..\..\Program Files\Autodesk\Revit 2020\RevitAPI.dll @@ -115,10 +118,7 @@ 2.0.3 - 0.11.0 - - - 4.6.3 + 0.12.0 diff --git a/dev/pyRevitLabs/pyRevitManager/Properties/AssemblyInfo.cs b/dev/pyRevitLabs/pyRevitManager/Properties/AssemblyInfo.cs index 147ade850..b760ed9f4 100644 --- a/dev/pyRevitLabs/pyRevitManager/Properties/AssemblyInfo.cs +++ b/dev/pyRevitLabs/pyRevitManager/Properties/AssemblyInfo.cs @@ -12,5 +12,5 @@ [assembly: ComVisible(false)] -[assembly: AssemblyVersion("0.11.0.0")] -[assembly: AssemblyFileVersion("0.11.0.0")] +[assembly: AssemblyVersion("0.13.0.0")] +[assembly: AssemblyFileVersion("0.13.0.0")] diff --git a/dev/pyRevitLabs/pyRevitManager/PyRevitCLI.cs b/dev/pyRevitLabs/pyRevitManager/PyRevitCLI.cs index f361c9228..1a79aebb5 100644 --- a/dev/pyRevitLabs/pyRevitManager/PyRevitCLI.cs +++ b/dev/pyRevitLabs/pyRevitManager/PyRevitCLI.cs @@ -14,9 +14,9 @@ using pyRevitLabs.TargetApps.Revit; using DocoptNet; -using NLog; -using NLog.Config; -using NLog.Targets; +using pyRevitLabs.NLog; +using pyRevitLabs.NLog.Config; +using pyRevitLabs.NLog.Targets; using Console = Colorful.Console; @@ -488,7 +488,11 @@ private static void ProcessArguments() { else if (all("fileinfo")) PyRevitCLIRevitCmds.ProcessFileInfo( targetPath: TryGetValue(""), - outputCSV: TryGetValue("--csv") + outputCSV: TryGetValue("--csv"), + IncludeRVT: arguments["--rvt"].IsTrue, + includeRTE: arguments["--rte"].IsTrue, + includeRFA: arguments["--rfa"].IsTrue, + includeRFT: arguments["--rft"].IsTrue ); else if (all("addons")) { @@ -510,7 +514,9 @@ private static void ProcessArguments() { PyRevitCLIAppHelps.PrintHelp(PyRevitCLICommandType.Revits); else if (arguments["--supported"].IsTrue) - PyRevitCLIRevitCmds.PrintSupportedRevits(); + PyRevitCLIRevitCmds.ProcessBuildInfo( + outputCSV: TryGetValue("--csv") + ); else PyRevitCLIRevitCmds.PrintLocalRevits(running: arguments["--installed"].IsFalse); diff --git a/dev/pyRevitLabs/pyRevitManager/PyRevitCLIAppCmds.cs b/dev/pyRevitLabs/pyRevitManager/PyRevitCLIAppCmds.cs index 279ad1c4d..523276bb5 100644 --- a/dev/pyRevitLabs/pyRevitManager/PyRevitCLIAppCmds.cs +++ b/dev/pyRevitLabs/pyRevitManager/PyRevitCLIAppCmds.cs @@ -13,7 +13,7 @@ using pyRevitLabs.TargetApps.Revit; using pyRevitLabs.Language.Properties; -using NLog; +using pyRevitLabs.NLog; using pyRevitLabs.Json; using pyRevitLabs.Json.Serialization; diff --git a/dev/pyRevitLabs/pyRevitManager/PyRevitCLIAppHelps.cs b/dev/pyRevitLabs/pyRevitManager/PyRevitCLIAppHelps.cs index bc830ef05..353d2cdc8 100644 --- a/dev/pyRevitLabs/pyRevitManager/PyRevitCLIAppHelps.cs +++ b/dev/pyRevitLabs/pyRevitManager/PyRevitCLIAppHelps.cs @@ -301,6 +301,10 @@ internal static void { "", "Target Revit year (major version)" }, { "", "Target file or directory" }, { "--csv=", "Output csv file path" }, + { "--rvt", "Include Revit Project files (default when not provided)" }, + { "--rte", "Include Revit Project Template files" }, + { "--rfa", "Include Revit Family files" }, + { "--rft", "Include Revit Family Template files" }, { "--installed", "Installed Revits only" }, { "--supported", "Supported Revits only" }, }); diff --git a/dev/pyRevitLabs/pyRevitManager/PyRevitCLICloneCmds.cs b/dev/pyRevitLabs/pyRevitManager/PyRevitCLICloneCmds.cs index 0c866de35..b2b3fa98b 100644 --- a/dev/pyRevitLabs/pyRevitManager/PyRevitCLICloneCmds.cs +++ b/dev/pyRevitLabs/pyRevitManager/PyRevitCLICloneCmds.cs @@ -13,7 +13,7 @@ using pyRevitLabs.TargetApps.Revit; using pyRevitLabs.Language.Properties; -using NLog; +using pyRevitLabs.NLog; using pyRevitLabs.Json; using pyRevitLabs.Json.Serialization; @@ -272,14 +272,25 @@ internal static void string revitYear, bool installed, bool attached, bool allUsers) { var clone = PyRevit.GetRegisteredClone(cloneName); + // grab engine version int engineVer = 0; int.TryParse(engineVersion, out engineVer); - if (latest) - engineVer = 0; - else if (dynamoSafe) + if (latest) { + logger.Debug("Attaching on latest engine..."); + var latestCloneEngine = + clone.GetEngines().Where(x => x.Runtime).OrderByDescending(x => x.Version).First(); + logger.Debug(string.Format("Latest engine: {0}", latestCloneEngine)); + if (latestCloneEngine != null) + engineVer = latestCloneEngine.Version; + else + throw new pyRevitException("Can not determine latest runtime engine for this clone."); + } + else if (dynamoSafe) { + logger.Debug("Attaching on dynamo-safe engine"); engineVer = PyRevitConsts.ConfigsDynamoCompatibleEnginerVer; + } // decide targets revits to attach to int revitYearNumber = 0; diff --git a/dev/pyRevitLabs/pyRevitManager/PyRevitCLIConfigCmds.cs b/dev/pyRevitLabs/pyRevitManager/PyRevitCLIConfigCmds.cs index 0a6552072..4117aeff0 100644 --- a/dev/pyRevitLabs/pyRevitManager/PyRevitCLIConfigCmds.cs +++ b/dev/pyRevitLabs/pyRevitManager/PyRevitCLIConfigCmds.cs @@ -13,7 +13,7 @@ using pyRevitLabs.TargetApps.Revit; using pyRevitLabs.Language.Properties; -using NLog; +using pyRevitLabs.NLog; using pyRevitLabs.Json; using pyRevitLabs.Json.Serialization; diff --git a/dev/pyRevitLabs/pyRevitManager/PyRevitCLIExtensionCmds.cs b/dev/pyRevitLabs/pyRevitManager/PyRevitCLIExtensionCmds.cs index 605c62dda..3081e09ef 100644 --- a/dev/pyRevitLabs/pyRevitManager/PyRevitCLIExtensionCmds.cs +++ b/dev/pyRevitLabs/pyRevitManager/PyRevitCLIExtensionCmds.cs @@ -13,7 +13,7 @@ using pyRevitLabs.TargetApps.Revit; using pyRevitLabs.Language.Properties; -using NLog; +using pyRevitLabs.NLog; using pyRevitLabs.Json; using pyRevitLabs.Json.Serialization; diff --git a/dev/pyRevitLabs/pyRevitManager/PyRevitCLIReleaseCmds.cs b/dev/pyRevitLabs/pyRevitManager/PyRevitCLIReleaseCmds.cs index bbb01fd30..1bb2e92e9 100644 --- a/dev/pyRevitLabs/pyRevitManager/PyRevitCLIReleaseCmds.cs +++ b/dev/pyRevitLabs/pyRevitManager/PyRevitCLIReleaseCmds.cs @@ -13,7 +13,7 @@ using pyRevitLabs.TargetApps.Revit; using pyRevitLabs.Language.Properties; -using NLog; +using pyRevitLabs.NLog; using pyRevitLabs.Json; using pyRevitLabs.Json.Serialization; diff --git a/dev/pyRevitLabs/pyRevitManager/PyRevitCLIRevitCmds.cs b/dev/pyRevitLabs/pyRevitManager/PyRevitCLIRevitCmds.cs index 0a7dc4a63..3304a2b3b 100644 --- a/dev/pyRevitLabs/pyRevitManager/PyRevitCLIRevitCmds.cs +++ b/dev/pyRevitLabs/pyRevitManager/PyRevitCLIRevitCmds.cs @@ -13,7 +13,7 @@ using pyRevitLabs.TargetApps.Revit; using pyRevitLabs.Language.Properties; -using NLog; +using pyRevitLabs.NLog; using pyRevitLabs.Json; using pyRevitLabs.Json.Serialization; @@ -37,13 +37,6 @@ internal static void } } - internal static void - PrintSupportedRevits() { - PyRevitCLIAppCmds.PrintHeader("Supported Revits"); - foreach (var revit in RevitProduct.ListSupportedProducts().OrderByDescending(x => x.Version)) - Console.WriteLine(string.Format("{0} | Version: {1} | Build: {2}({3})", revit.ProductName, revit.Version, revit.BuildNumber, revit.BuildTarget)); - } - internal static void KillAllRevits(string revitYear) { int revitYearNumber = 0; @@ -54,7 +47,8 @@ internal static void } internal static void - ProcessFileInfo(string targetPath, string outputCSV) { + ProcessFileInfo(string targetPath, string outputCSV, + bool IncludeRVT=true, bool includeRTE=false, bool includeRFA=false, bool includeRFT=false) { // if targetpath is a single model print the model info if (File.Exists(targetPath)) if (outputCSV != null) @@ -69,20 +63,35 @@ internal static void else { var models = new List(); var errorList = new List<(string, string)>(); + var fileSearchPatterns = new List(); + + // determine search patterns + // if no other file format is specified search for rvt only + if ((!includeRTE && !includeRFA && !includeRFT) || IncludeRVT) + fileSearchPatterns.Add("*.rvt"); + + if (includeRTE) + fileSearchPatterns.Add("*.rte"); + if (includeRFA) + fileSearchPatterns.Add("*.rfa"); + if (includeRFT) + fileSearchPatterns.Add("*.rft"); logger.Info(string.Format("Searching for revit files under \"{0}\"", targetPath)); FileAttributes attr = File.GetAttributes(targetPath); if ((attr & FileAttributes.Directory) == FileAttributes.Directory) { - var files = Directory.EnumerateFiles(targetPath, "*.rvt", SearchOption.AllDirectories); - logger.Info(string.Format(" {0} revit files found under \"{1}\"", files.Count(), targetPath)); - foreach (var file in files) { - try { - logger.Info(string.Format("Revit file found \"{0}\"", file)); - var model = new RevitModelFile(file); - models.Add(model); - } - catch (Exception ex) { - errorList.Add((file, ex.Message)); + foreach(string searchPattern in fileSearchPatterns) { + var files = Directory.EnumerateFiles(targetPath, searchPattern, SearchOption.AllDirectories); + logger.Info(string.Format(" {0} revit files found under \"{1}\"", files.Count(), targetPath)); + foreach (var file in files) { + try { + logger.Info(string.Format("Revit file found \"{0}\"", file)); + var model = new RevitModelFile(file); + models.Add(model); + } + catch (Exception ex) { + errorList.Add((file, ex.Message)); + } } } } @@ -107,6 +116,14 @@ internal static void } } + internal static void + ProcessBuildInfo(string outputCSV) { + if (outputCSV != null) + ExportBuildInfoToCSV(outputCSV); + else + PrintBuildInfo(); + } + internal static void PrepareAddonsDir(string revitYear, bool allUses) { int revitYearNumber = 0; @@ -287,6 +304,12 @@ private static void PrintModelInfo(RevitModelFile model) { Console.WriteLine(string.Format("Open Workset Settings: {0}", model.OpenWorksetConfig)); Console.WriteLine(string.Format("Document Increment: {0}", model.DocumentIncrement)); + // print project information properties + Console.WriteLine("Project Information (Properties):"); + foreach(var item in model.ProjectInfoProperties.OrderBy(x => x.Key)) { + Console.WriteLine("\t{0} = {1}", item.Key, item.Value.ToEscaped()); + } + if (model.IsFamily) { Console.WriteLine("Model is a Revit Family!"); Console.WriteLine(string.Format("Category Name: {0}", model.CategoryName)); @@ -294,6 +317,13 @@ private static void PrintModelInfo(RevitModelFile model) { } } + private static void PrintBuildInfo() { + PyRevitCLIAppCmds.PrintHeader("Supported Revits"); + foreach (var revit in RevitProduct.ListSupportedProducts().OrderByDescending(x => x.Version)) + Console.WriteLine(string.Format("{0} | Version: {1} | Build: {2}({3})", revit.ProductName, revit.Version, revit.BuildNumber, revit.BuildTarget)); + + } + // export model info to csv private static void ExportModelInfoToCSV(IEnumerable models, string outputCSV, @@ -301,9 +331,16 @@ private static void ExportModelInfoToCSV(IEnumerable models, logger.Info(string.Format("Building CSV data to \"{0}\"", outputCSV)); var csv = new StringBuilder(); csv.Append( - "filepath,productname,buildnumber,isworkshared,centralmodelpath,lastsavedpath,uniqueid,error\n" + "filepath,productname,buildnumber,isworkshared,centralmodelpath,lastsavedpath,uniqueid,projectinfo,error\n" ); foreach (var model in models) { + // build project info string + var jsonData = new Dictionary(); + foreach (var item in model.ProjectInfoProperties.OrderBy(x => x.Key)) { + jsonData[item.Key] = item.Value; + } + + // create csv entry var data = new List() { string.Format("\"{0}\"", model.FilePath), string.Format("\"{0}\"", model.RevitProduct != null ? model.RevitProduct.ProductName : ""), @@ -312,6 +349,7 @@ private static void ExportModelInfoToCSV(IEnumerable models, string.Format("\"{0}\"", model.CentralModelPath), string.Format("\"{0}\"", model.LastSavedPath), string.Format("\"{0}\"", model.UniqueId.ToString()), + JsonConvert.SerializeObject(jsonData).PrepareJSONForCSV(), "" }; @@ -319,9 +357,33 @@ private static void ExportModelInfoToCSV(IEnumerable models, } // write list of files with errors - logger.Debug("Adding errors to \"{0}\"", outputCSV); - foreach (var errinfo in errorList) - csv.Append(string.Format("\"{0}\",,,,,,,\"{1}\"\n", errinfo.Item1, errinfo.Item2)); + if (errorList != null) { + logger.Debug("Adding errors to \"{0}\"", outputCSV); + foreach (var errinfo in errorList) + csv.Append(string.Format("\"{0}\",,,,,,,,\"{1}\"\n", errinfo.Item1, errinfo.Item2)); + } + + logger.Info(string.Format("Writing results to \"{0}\"", outputCSV)); + File.WriteAllText(outputCSV, csv.ToString()); + } + + // export build info to csv + private static void ExportBuildInfoToCSV(string outputCSV) { + logger.Info(string.Format("Building CSV data to \"{0}\"", outputCSV)); + var csv = new StringBuilder(); + csv.Append( + "\"buildnum\",\"buildversion\",\"productname\"\n" + ); + foreach (var revit in RevitProduct.ListSupportedProducts().OrderByDescending(x => x.Version)) { + // create csv entry + var data = new List() { + string.Format("\"{0}\"", revit.BuildNumber), + string.Format("\"{0}\"", revit.Version), + string.Format("\"{0}\"", revit.ProductName), + }; + + csv.Append(string.Join(",", data) + "\n"); + } logger.Info(string.Format("Writing results to \"{0}\"", outputCSV)); File.WriteAllText(outputCSV, csv.ToString()); diff --git a/dev/pyRevitLabs/pyRevitManager/PyRevitCLLInitCmds.cs b/dev/pyRevitLabs/pyRevitManager/PyRevitCLLInitCmds.cs index 0293234fa..4e057fb22 100644 --- a/dev/pyRevitLabs/pyRevitManager/PyRevitCLLInitCmds.cs +++ b/dev/pyRevitLabs/pyRevitManager/PyRevitCLLInitCmds.cs @@ -13,7 +13,7 @@ using pyRevitLabs.TargetApps.Revit; using pyRevitLabs.Language.Properties; -using NLog; +using pyRevitLabs.NLog; using pyRevitLabs.Json; using pyRevitLabs.Json.Serialization; diff --git a/dev/pyRevitLabs/pyRevitManager/Resources/UsagePatterns.txt b/dev/pyRevitLabs/pyRevitManager/Resources/UsagePatterns.txt index 13e3d2d41..00fcf8a1f 100644 --- a/dev/pyRevitLabs/pyRevitManager/Resources/UsagePatterns.txt +++ b/dev/pyRevitLabs/pyRevitManager/Resources/UsagePatterns.txt @@ -56,9 +56,10 @@ Usage: pyrevit releases download (installer | archive) [--dest=] [--pre] pyrevit revits pyrevit revits --help - pyrevit revits [(--installed|--supported)] [--log=] + pyrevit revits [--installed] [--log=] + pyrevit revits --supported [--csv=] pyrevit revits killall [] [--log=] - pyrevit revits fileinfo [--csv=] + pyrevit revits fileinfo [--csv=] [--rvt] [--rte] [--rfa] [--rft] pyrevit revits addons [--help] pyrevit revits addons prepare [--allusers] pyrevit revits addons install [--dest=] [--allusers] diff --git a/dev/pyRevitLabs/pyRevitManager/pyRevitManager.csproj b/dev/pyRevitLabs/pyRevitManager/pyRevitManager.csproj index 7a6e6bfbe..f199a91e5 100644 --- a/dev/pyRevitLabs/pyRevitManager/pyRevitManager.csproj +++ b/dev/pyRevitLabs/pyRevitManager/pyRevitManager.csproj @@ -75,6 +75,10 @@ False ..\..\..\bin\pyRevitLabs.Json.dll + + False + ..\..\..\bin\pyRevitLabs.NLog.dll + @@ -177,9 +181,6 @@ 2.0.3 - - 4.6.3 - diff --git a/dev/pyRevitLoader/Resources/python_277_lib.zip b/dev/pyRevitLoader/Resources/python_277_lib.zip index c574a0ff8..b1dc2743d 100644 Binary files a/dev/pyRevitLoader/Resources/python_277_lib.zip and b/dev/pyRevitLoader/Resources/python_277_lib.zip differ diff --git a/dev/pyRevitLoader/pyRevitLoader273/pyRevitLoader273.csproj b/dev/pyRevitLoader/pyRevitLoader273/pyRevitLoader273.csproj index 44d6003bd..d2a8d1b57 100644 --- a/dev/pyRevitLoader/pyRevitLoader273/pyRevitLoader273.csproj +++ b/dev/pyRevitLoader/pyRevitLoader273/pyRevitLoader273.csproj @@ -95,6 +95,7 @@ rd /S /Q "$(ProjectDir)\obj" +del /Q "$(TargetDir)*.pdb" signtool sign /n "Ehsan Iran Nejad" /t http://timestamp.digicert.com /fd sha256 $(TargetPath) \ No newline at end of file diff --git a/dev/pyRevitLoader/pyRevitLoader277/pyRevitLoader277.csproj b/dev/pyRevitLoader/pyRevitLoader277/pyRevitLoader277.csproj index 3edc92bff..82bcf48f6 100644 --- a/dev/pyRevitLoader/pyRevitLoader277/pyRevitLoader277.csproj +++ b/dev/pyRevitLoader/pyRevitLoader277/pyRevitLoader277.csproj @@ -95,6 +95,7 @@ rd /S /Q "$(ProjectDir)\obj" +del /Q "$(TargetDir)*.pdb" signtool sign /n "Ehsan Iran Nejad" /t http://timestamp.digicert.com /fd sha256 $(TargetPath) \ No newline at end of file diff --git a/dev/pyRevitLoader/pyRevitLoader278/pyRevitLoader278.csproj b/dev/pyRevitLoader/pyRevitLoader278/pyRevitLoader278.csproj index 26fb94453..6060ad81e 100644 --- a/dev/pyRevitLoader/pyRevitLoader278/pyRevitLoader278.csproj +++ b/dev/pyRevitLoader/pyRevitLoader278/pyRevitLoader278.csproj @@ -106,6 +106,7 @@ rd /S /Q "$(ProjectDir)\obj" +del /Q "$(TargetDir)*.pdb" signtool sign /n "Ehsan Iran Nejad" /t http://timestamp.digicert.com /fd sha256 $(TargetPath) \ No newline at end of file diff --git a/dev/pyRevitLoader/pyRevitLoader279/pyRevitLoader279.csproj b/dev/pyRevitLoader/pyRevitLoader279/pyRevitLoader279.csproj index 242dbf78d..87a0e9197 100644 --- a/dev/pyRevitLoader/pyRevitLoader279/pyRevitLoader279.csproj +++ b/dev/pyRevitLoader/pyRevitLoader279/pyRevitLoader279.csproj @@ -102,6 +102,7 @@ rd /S /Q "$(ProjectDir)\obj" +del /Q "$(TargetDir)*.pdb" signtool sign /n "Ehsan Iran Nejad" /t http://timestamp.digicert.com /fd sha256 $(TargetPath) \ No newline at end of file diff --git a/docs/articles/scriptanatomy.rst b/docs/articles/scriptanatomy.rst index e531e45c0..cd8604231 100644 --- a/docs/articles/scriptanatomy.rst +++ b/docs/articles/scriptanatomy.rst @@ -112,6 +112,11 @@ Currently, pyRevit support three types of command availability types. # Tool activates when all selected elements are of the given category or categories __context__ = '' __context__ = ['', ''] + + +If category name starts with 'OST_' (e.g. 'OST_Doors') comparison will be made using BuiltInCategory. It allows to use your script in spite of Revit translation + +List of available categories https://www.revitapidocs.com/2020/ba1c5b30-242f-5fdc-8ea9-ec3b61e6e722.htm ```` can be any of the standard Revit element categories. @@ -128,6 +133,7 @@ Here are a few examples: __context__ = 'Doors' __context__ = 'Walls' __context__ = 'Floors' + __context__ = 'OST_Doors' __context__ = ['Space Tags', 'Spaces'] diff --git a/docs/cli.md b/docs/cli.md index 0a3e75135..fbf4e406f 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -1,19 +1,10 @@ # pyRevit Command Line Tool Help -<<<<<<< HEAD:docs/cli.md -##### Version 0.16.0.0 -======= -##### Version 0.9.6.0 ->>>>>>> pr548:README_CLI.md +Version 0.12.0.0 `pyrevit` is the command line tool, developed specifically to install and configure pyRevit in your production/development environment. Each section below showcases a specific set of functionality of the command line tool. - [pyRevit Command Line Tool Help](#pyrevit-command-line-tool-help) -<<<<<<< HEAD:docs/cli.md - - [Version 0.16.0.0](#version-01600) -======= - - [Version 0.9.6.0](#version-0960) ->>>>>>> pr548:README_CLI.md - [Getting Help](#getting-help) - [pyrevit CLI version](#pyrevit-cli-version) - [pyRevit Online Resources](#pyrevit-online-resources) @@ -301,6 +292,7 @@ pyRevit v4.6.12 | Tag: v4.6.12 | Version: 4.6.12 | Url: "https://github.com/eira ``` powershell $ pyrevit releases 4.7 --notes +==> Releases pyRevit v4.7.0-beta (pre-release) | Tag: v4.7.0-beta | Version: 4.7.0 | Url: "https://github.com/eirannejad/pyRevit/releases/tag/v4.7.0-beta" New features: - CPython command execution engine (v3.6.8 and v3.7.2) @@ -317,10 +309,10 @@ $ pyrevit releases open latest ``` powershell # download the archive -$ pyrevit releases download archive 4.6.15 --dest="C:\Users\eirannejad\Downloads" +$ pyrevit releases download archive 4.6.15 --dest="C:\Users\*\Downloads" # or the installer -$ pyrevit releases download installer 4.6.15 --dest="C:\Users\eirannejad\Downloads" +$ pyrevit releases download installer 4.6.15 --dest="C:\Users\*\Downloads" ``` @@ -345,13 +337,12 @@ List all the attachments: $ pyrevit attached ==> Attachments -Autodesk Revit 2013 First Customer Ship | Clone: "dev" | Engine: "277" -Autodesk Revit 2014 First Customer Ship | Clone: "dev" | Engine: "277" -Autodesk Revit 2015 First Customer Ship | Clone: "dev" | Engine: "277" -Autodesk Revit 2016 First Customer Ship | Clone: "dev" | Engine: "277" -Autodesk Revit 2017 First Customer Ship | Clone: "dev" | Engine: "277" -Autodesk Revit 2018.3.1 | Clone: "dev" | Engine: "277" -Autodesk Revit 2019 First Customer Ship | Clone: "dev" | Engine: "277" +dev | Product: "Autodesk Revit 2020.0.1" | Engine: 277 | Path: "C:\pyRevitDev" | Manifest: "C:\..\2020\pyRevit.addin" +dev | Product: "Autodesk Revit 2019.2.1" | Engine: 277 | Path: "C:\pyRevitDev" | Manifest: "C:\..\2019\pyRevit.addin" +dev | Product: "Autodesk Revit 2018.3.3 Security Fix" | Engine: 277 | Path: "C:\pyRevitDev" | Manifest: "C:\..\2018\pyRevit.addin" +dev | Product: "Autodesk Revit 2017.2.5 Security Fix" | Engine: 277 | Path: "C:\pyRevitDev" | Manifest: "C:\..\2017\pyRevit.addin" +dev | Product: "Autodesk Revit 2016 Update 7 for R2" | Engine: 277 | Path: "C:\pyRevitDev" | Manifest: "C:\..\2016\pyRevit.addin" +dev | Product: "Autodesk Revit 2014 First Customer Ship" | Engine: 277 | Path: "C:\pyRevitDev" | Manifest: "C:\..\2014\pyRevit.addin" ``` You can also switch between the attached clones using the switch command: @@ -359,17 +350,10 @@ You can also switch between the attached clones using the switch command: ``` powershell pyrevit switch -$ pyrevit attached - -==> Attachments -Autodesk Revit 2018.3.1 | Clone: "base" | Engine: "279" -Autodesk Revit 2019 First Customer Ship | Clone: "dev" | Engine: "273" - $ pyrevit switch main ==> Attachments -Autodesk Revit 2018.3.1 | Clone: "main" | Engine: "279" -Autodesk Revit 2019 First Customer Ship | Clone: "main" | Engine: "273" +main | Product: "Autodesk Revit 2020.0.1" | Engine: 277 | Path: "C:\pyRevitMain" | Manifest: "C:\..\2020\pyRevit.addin" ``` The switch command with detect all the existing attachments and will remap them to the new clone using the same engine. @@ -411,11 +395,7 @@ $ pyrevit extend pyApex "C:\pyRevit\Extensions" # install pyApex extension To installing your own extensions, you'll need to specify what type if extension you're installing (ui or lib) and provide the url: ``` powershell -<<<<<<< HEAD:docs/cli.md -pyrevit extend (ui | lib | run) [--branch=] [--log=] -======= pyrevit extend (ui | lib) [--dest=] [--branch=] [--log=] ->>>>>>> pr548:README_CLI.md $ pyrevit extend ui MyExtension "https://www.github.com/my-extension.git" "C:\pyRevit\Extensions" ``` @@ -509,99 +489,45 @@ Use `env` command to get info about the current `pyrevit` environment: $ pyrevit env ==> Registered Clones (full git repos) -<<<<<<< HEAD:docs/cli.md -dev | Branch: "develop" | Version: "4.7.0-beta:167b3d7" | Path: "C:\Users\eirannejad\Desktop\gits\pyRevitDev" +... -==> Registered Clones (deployed from archive) -devbase | Deploy: "base" | Branch: "develop" | Version: "4.7.0-beta" | Path: "C:\tmp\devbase" +==> Registered Clones (deployed from archive/image) +... ==> Attachments -Autodesk Revit 2014 First Customer Ship | Clone: "dev" | Engine: "279" | Path: "C:\Users\eirannejad\Desktop\gits\pyRevitDev" | Manifest: "C:\Users\eirannejad\AppData\Roaming\Autodesk\Revit\Addins\2014\pyRevit.addin" -Autodesk Revit 2016 Update 7 for R2 | Clone: "dev" | Engine: "277" | Path: "C:\Users\eirannejad\Desktop\gits\pyRevitDev" | Manifest: "C:\Users\eirannejad\AppData\Roaming\Autodesk\Revit\Addins\2016\pyRevit.addin" -Autodesk Revit 2017.0.4 | Clone: "dev" | Engine: "277" | Path: "C:\Users\eirannejad\Desktop\gits\pyRevitDev" | Manifest: "C:\Users\eirannejad\AppData\Roaming\Autodesk\Revit\Addins\2017\pyRevit.addin" -Autodesk Revit 2018.3.2 | Clone: "dev" | Engine: "277" | Path: "C:\Users\eirannejad\Desktop\gits\pyRevitDev" | Manifest: "C:\Users\eirannejad\AppData\Roaming\Autodesk\Revit\Addins\2018\pyRevit.addin" -Autodesk Revit 2019.2 (Update) | Clone: "dev" | Engine: "277" | Path: "C:\Users\eirannejad\Desktop\gits\pyRevitDev" | Manifest: "C:\Users\eirannejad\AppData\Roaming\Autodesk\Revit\Addins\2019\pyRevit.addin" +... ==> Installed Extensions -Name: "pyApex" | Type: "UIExtension" | Repo: "https://github.com/apex-project/pyApex.git" | Installed: "C:\pyRevit\Extensions\pyApex.extension" -Name: "PyRevitPlus" | Type: "UIExtension" | Repo: "https://github.com/gtalarico/pyrevitplus.git" | Installed: "C:\pyRevit\Extensions\PyRevitPlus.extension" -======= -dev | Branch: "hotfix/clihelp" | Version: "4.6.13:e9da94781a34ecb002ad634fa95b6a075726913c" | Path: "C:\Users\LeoW10\Desktop\gits\pyRevit" - -==> Registered Clones (deployed from archive) -release | Deploy: "basepublic" | Branch: "develop" | Version: "4.6.13" | Path: "C:\tmp\public" -crazy | Deploy: "core" | Branch: "develop" | Version: "Unknown" | Path: "C:\tmp\CrazyUser.??\core" -base | Deploy: "base" | Branch: "develop" | Version: "4.6.13" | Path: "C:\tmp\base" -core | Deploy: "core" | Branch: "develop" | Version: "Unknown" | Path: "C:\tmp\core" - -==> Attachments -Autodesk Revit 2013 First Customer Ship | Clone: "dev" | Engine: "277" -Autodesk Revit 2014 First Customer Ship | Clone: "release" | Engine: "277" -Autodesk Revit 2015 First Customer Ship | Clone: "dev" | Engine: "277" -Autodesk Revit 2016 First Customer Ship | Clone: "dev" | Engine: "277" -Autodesk Revit 2017 First Customer Ship | Clone: "dev" | Engine: "277" -Autodesk Revit 2018.3.1 | Clone: "dev" | Engine: "277" -Autodesk Revit 2019.2 (Update) | Clone: "dev" | Engine: "277" ->>>>>>> pr548:README_CLI.md - -==> Default Extension Search Path -C:\Users\eirannejad\AppData\Roaming\pyRevit\Extensions - -==> Default Extension Search Path -C:\Users\LeoW10\AppData\Roaming\pyRevit\Extensions +... ==> Default Extension Search Path -C:\Users\LeoW10\AppData\Roaming\pyRevit\Extensions +... ==> Extension Search Paths -<<<<<<< HEAD:docs/cli.md -C:\tmp -C:\Users\eirannejad\AppData\Roaming\pyRevit\Extensions -======= -C:\tmp\exts -C:\Users\LeoW10\Desktop\gits -C:\Users\LeoW10\AppData\Roaming\pyRevit\Extensions ->>>>>>> pr548:README_CLI.md +... ==> Extension Sources - Default -https://github.com/eirannejad/pyRevit/raw/master/extensions/extensions.json +... ==> Extension Sources - Additional +... ==> Installed Revits -<<<<<<< HEAD:docs/cli.md -Autodesk Revit 2014 First Customer Ship | Version: 13.3.8151 | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2014\" -Autodesk Revit 2016 Update 7 for R2 | Version: 16.0.1185.0 | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2016\" -Autodesk Revit 2017.0.4 | Version: 17.0.511.0 | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2017\" -Autodesk Revit 2018.3.2 | Version: 18.3.2.7 | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2018\" -======= -Autodesk Revit 2013 First Customer Ship | Version: 12.2.21203 | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2013\" -Autodesk Revit 2014 First Customer Ship | Version: 13.3.8151 | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit Architecture 2014\" -Autodesk Revit 2015 First Customer Ship | Version: 15.0.136.0 | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2015\" -Autodesk Revit 2016 First Customer Ship | Version: 16.0.428.0 | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2016\" -Autodesk Revit 2017 First Customer Ship | Version: 17.0.416.0 | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2017\" -Autodesk Revit 2018.3.1 | Version: 18.3.1.2 | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2018\" ->>>>>>> pr548:README_CLI.md -Autodesk Revit 2019.2 (Update) | Version: 19.2.0.65 | Language: 1033 | Path: "C:\Program Files\Autodesk\Revit 2019\" +... ==> Running Revit Instances -PID: 12236 | Autodesk Revit 2019.2 (Update) | Version: 19.2.0.65 | Language: 0 | Path: "C:\Program Files\Autodesk\Revit 2019" +... ==> User Environment -Microsoft Windows 10 [Version 10.0.17763] -Executing User: DOMAIN\eirannejad -Active User: DOMAIN\eirannejad -Adming Access: Yes -%APPDATA%: "C:\Users\eirannejad\AppData\Roaming" -Latest Installed .Net Framework: "4.7.2" -<<<<<<< HEAD:docs/cli.md -Installed .Net Target Packs: v3.5 v4.0 v4.5 v4.5.1 v4.5.2 v4.6 v4.6.1 v4.7.1 v4.7.2 v4.X -Installed .Net-Core Target Packs: v2.1.401 v2.1.402 v2.1.403 v2.1.500 v2.1.502 v2.1.503 v2.1.504 -pyRevit CLI 0.16.0.0 -======= -Installed .Net Target Packs: v3.5 v4.0 v4.5 v4.5.1 v4.5.2 v4.6 v4.6.1 v4.7.1 v4.X -pyRevit CLI 0.9.0.0 ->>>>>>> pr548:README_CLI.md +Microsoft Windows X [Version X.X.XXXXX] +Executing User: +Active User: +Adming Access: +%APPDATA%: +Latest Installed .Net Framework: +Installed .Net Target Packs: +Installed .Net-Core Target Packs: +pyRevit CLI X.X.X.X ``` ## Configuring pyRevit @@ -740,11 +666,7 @@ You can use the `pyrevit init` commnd to quickly create pyRevit bundles based on Init pyRevit bundles Usage: -<<<<<<< HEAD:docs/cli.md pyrevit init (ui | lib | run) [--usetemplate] [--templates=] -======= - pyrevit init (ui | lib) [--usetemplate] [--templates=] ->>>>>>> pr548:README_CLI.md pyrevit init (tab | panel | panelopt | pull | split | splitpush | push | smart | command) [--usetemplate] [--templates=] # creates MyExtension.extension inside the current directory diff --git a/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/About.pushbutton/aboutscript.py b/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/About.pushbutton/aboutscript.py index 9118f2e6f..57b8803d0 100644 --- a/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/About.pushbutton/aboutscript.py +++ b/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/About.pushbutton/aboutscript.py @@ -18,6 +18,9 @@ 'detailed information on how pyrevit works, updates about the ' \ 'new tools and changes, and a lot of other information there.' + +logger = script.get_logger() + Revit = TargetApps.Revit @@ -39,15 +42,16 @@ def __init__(self, xaml_file_name): self.branch_name = pyrvt_repo.branch self.show_element(self.git_commit) self.show_element(self.git_branch) - except Exception: + except Exception as getbranch_ex: + logger.debug('Error getting branch: %s', getbranch_ex) # other wise try to get deployment name attachment = Revit.PyRevit.GetAttached(int(HOST_APP.version)) if attachment: try: - self.deployname = attachment.Clone.GetDeployment().Name + self.deployname = attachment.Clone.Deployment.Name self.show_element(self.repo_deploy) - except Exception: - pass + except Exception as getdepl_ex: + logger.debug('Error getting depoyment: %s', getdepl_ex) # get cli version pyrvt_cli_version = 'v' + versionmgr.get_pyrevit_cli_version() diff --git a/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/Extensions.smartbutton/ExtensionsWindow.xaml b/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/Extensions.smartbutton/ExtensionsWindow.xaml index c09491ea5..5bad26d8b 100644 --- a/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/Extensions.smartbutton/ExtensionsWindow.xaml +++ b/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/Extensions.smartbutton/ExtensionsWindow.xaml @@ -60,8 +60,9 @@ Developed by: - + + Repository: diff --git a/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/Extensions.smartbutton/script.py b/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/Extensions.smartbutton/script.py index ccc5a78da..d36d41061 100644 --- a/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/Extensions.smartbutton/script.py +++ b/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/Extensions.smartbutton/script.py @@ -58,6 +58,7 @@ def __init__(self, extension_package): self.Name = self.ext_pkg.name self.Desciption = self.ext_pkg.description self.Author = self.ext_pkg.author + self.AuthorProfile = self.ext_pkg.author_profile self.GitURL = self.ext_pkg.url self.URL = self.ext_pkg.website @@ -185,8 +186,15 @@ def _update_ext_info_panel(self, ext_pkg_item): # Update the author and profile link if ext_pkg_item.Author: self.ext_author_t.Text = ext_pkg_item.Author - self.ext_authorlink_hl.NavigateUri = \ - framework.Uri(ext_pkg_item.ext_pkg.author_profile) + self.ext_author_nolink_t.Text = ext_pkg_item.Author + if ext_pkg_item.AuthorProfile: + self.ext_authorlink_hl.NavigateUri = \ + framework.Uri(ext_pkg_item.AuthorProfile) + self.show_element(self.ext_author_t) + self.hide_element(self.ext_author_nolink_t) + else: + self.hide_element(self.ext_author_t) + self.show_element(self.ext_author_nolink_t) else: self.ext_author_t.Text = '' diff --git a/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/tools.stack3/Spy.pulldown/List Elements.pushbutton/script.py b/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/tools.stack3/Spy.pulldown/List Elements.pushbutton/script.py index 7da6260c4..929627747 100644 --- a/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/tools.stack3/Spy.pulldown/List Elements.pushbutton/script.py +++ b/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/tools.stack3/Spy.pulldown/List Elements.pushbutton/script.py @@ -43,7 +43,8 @@ 'Fill Grids', 'Connected Circuits', 'Point Cloud Instances', - 'External Services' + 'External Services', + 'Builtin Categories with No DB.Category', ] selected_switch = \ @@ -449,7 +450,7 @@ def isline(line): '{}{}'.format( '{} ({})'.format( output.linkify(el.Id), - el.Category.Name + el.Category.Name if el.Category else "Unknown" ).ljust(40), schema.SchemaName ) @@ -522,3 +523,9 @@ def isline(line): server.GetName(), server.GetDescription(), sid in bisrvids)) + +elif selected_switch == 'Builtin Categories with No DB.Category': + for bic in coreutils.get_enum_values(DB.BuiltInCategory): + dbcat = revit.query.get_category(bic) + if not dbcat: + print(bic) diff --git a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Misc Tests.pulldown/Test CPython Command.pushbutton/script.py b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Misc Tests.pulldown/Test CPython Command.pushbutton/script.py index b7a859a79..bf53aa6a9 100644 --- a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Misc Tests.pulldown/Test CPython Command.pushbutton/script.py +++ b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Misc Tests.pulldown/Test CPython Command.pushbutton/script.py @@ -1,4 +1,5 @@ #! python3 +# -*- coding: utf-8 -*- # pylint: skip-file # set PYTHONPATH to ....\Lib\site-packages correctly @@ -11,6 +12,13 @@ def print_html(output_str): print("\n## sys.path:") print('\n'.join(sys.path)) +# try tkinter +try: + import tkinter + print('tkinter is included') +except Exception as ex: + print('tkinter load error: {}'.format(ex)) + # test numpy try: import numpy as np @@ -48,3 +56,8 @@ def print_html(output_str): print('\n## list of DB.Walls:') for wall in cl: print(f'{wall} id:{wall.Id.IntegerValue}') + +# test unicode +print(""" +Кириллица (/ sɪˈrɪlɪk /) - это система письма +""") \ No newline at end of file diff --git a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Unit Tests.pulldown/Test Independent Logging.pushbutton/script.py b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Unit Tests.pulldown/Test Independent Logging.pushbutton/script.py new file mode 100644 index 000000000..a9c8bc339 --- /dev/null +++ b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Unit Tests.pulldown/Test Independent Logging.pushbutton/script.py @@ -0,0 +1,39 @@ +import os.path as op +import logging +#pylint: disable=import-error,invalid-name,broad-except +from pyrevit import USER_SYS_TEMP +from pyrevit import coreutils +from pyrevit import script + + +slogger = script.get_logger() + + +# create own logger +LOG_REC_FORMAT_FILE = "%(asctime)s %(levelname)s: [%(name)s] %(message)s" +LOG_FILEPATH = op.join(USER_SYS_TEMP, 'indeplog.log') +file_hndlr = logging.FileHandler(LOG_FILEPATH, mode='a') +file_formatter = logging.Formatter(LOG_REC_FORMAT_FILE) +file_hndlr.setFormatter(file_formatter) +logger = logging.getLogger('MyIndependentLogger') # type: LoggerWrapper +logger.addHandler(file_hndlr) + +slogger.info('logget type: %s', type(slogger)) +slogger.critical('testing CRITICAL') +slogger.error('testing ERROR') +slogger.warning('testing WARNING') +slogger.info('testing INFO') +slogger.debug('testing DEBUG') + + +logger.info('logget type: %s', type(logger)) +logger.critical('testing CRITICAL') +logger.error('testing ERROR') +logger.warning('testing WARNING') +logger.info('testing INFO') +logger.debug('testing DEBUG') + + +coreutils.show_entry_in_explorer(LOG_FILEPATH) + +del logger \ No newline at end of file diff --git a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Unit Tests.pulldown/Test pyRevit Button.pushbutton/script.py b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Unit Tests.pulldown/Test pyRevit Button.pushbutton/script.py index 334d8b979..06cf19b9c 100644 --- a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Unit Tests.pulldown/Test pyRevit Button.pushbutton/script.py +++ b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Unit Tests.pulldown/Test pyRevit Button.pushbutton/script.py @@ -23,9 +23,10 @@ selected_switch, switches = \ forms.CommandSwitchWindow.show( - ['Option 1', 'Option 2', 'Option 3', 'Option 4', 'Option 5'], + ['Option_1', 'Option 2', 'Option 3', 'Option 4', 'Option 5'], switches=['Switch 1', 'Switch 2'], - message='Select Option:' + message='Select Option:', + recognize_access_key=True ) if selected_switch: diff --git a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Unit Tests.pulldown/_layout b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Unit Tests.pulldown/_layout index 4dc5b0d1c..9e18bf54d 100644 --- a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Unit Tests.pulldown/_layout +++ b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Unit Tests.pulldown/_layout @@ -14,6 +14,7 @@ Test FullFrame Engine Test pyRevit Button Test Output Stream Test Multiple Outputs +Test Independent Logging Test Progressbar Test Charts Test D3 diff --git a/extensions/pyRevitTags.extension/lib/pkgcfg.py b/extensions/pyRevitTags.extension/lib/pkgcfg.py index 36f7723fe..4bc5dd8e5 100644 --- a/extensions/pyRevitTags.extension/lib/pkgcfg.py +++ b/extensions/pyRevitTags.extension/lib/pkgcfg.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- """Manage package configurations.""" +from collections import OrderedDict + from pkgcommits import CommitTypes @@ -12,13 +14,16 @@ class CommitConfigs(object): # return CommitConfigs._singleton def __init__(self): - self._value_dict = {CommitTypes.Created: '■', - CommitTypes.Issued: '◊', - CommitTypes.IssuedRe: '□', - CommitTypes.Updated: '●', - CommitTypes.Revised: '●', - CommitTypes.Merged: '∩', - CommitTypes.Deleted: 'X'} + commit_types = OrderedDict() + commit_types[CommitTypes.Created] = '■' + commit_types[CommitTypes.Issued] = '◊' + commit_types[CommitTypes.IssuedRe] = '□' + commit_types[CommitTypes.Updated] = '●' + commit_types[CommitTypes.Revised] = '●' + commit_types[CommitTypes.Merged] = '∩' + commit_types[CommitTypes.Deleted] = 'X' + + self._value_dict = commit_types def get_commit_type(self, value): for ctype, cfg_value in self._value_dict.items(): diff --git a/extensions/pyRevitTags.extension/pyRevit.tab/Packages & Tags.panel/Manage Packages.pushbutton/script.py b/extensions/pyRevitTags.extension/pyRevit.tab/Packages & Tags.panel/Manage Packages.pushbutton/script.py index 77bb508ad..40e161bc9 100644 --- a/extensions/pyRevitTags.extension/pyRevit.tab/Packages & Tags.panel/Manage Packages.pushbutton/script.py +++ b/extensions/pyRevitTags.extension/pyRevit.tab/Packages & Tags.panel/Manage Packages.pushbutton/script.py @@ -378,6 +378,7 @@ def edit_commit(self, sender, args): self.sheets_dg.CommitEdit() self.sheets_dg.Focus() self.sheets_dg.Items.Refresh() + args.Cancel = True def update_sheets(self, sender, args): self.Close() diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Analysis.panel/Tools.stack2/Inspect.pulldown/Find Linked Elements.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Analysis.panel/Tools.stack2/Inspect.pulldown/Find Referenced Elements.pushbutton/script.py similarity index 100% rename from extensions/pyRevitTools.extension/pyRevit.tab/Analysis.panel/Tools.stack2/Inspect.pulldown/Find Linked Elements.pushbutton/script.py rename to extensions/pyRevitTools.extension/pyRevit.tab/Analysis.panel/Tools.stack2/Inspect.pulldown/Find Referenced Elements.pushbutton/script.py diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Analysis.panel/Tools.stack2/Inspect.pulldown/ListElementsOfSelectedLevel.pushbutton/ListElementsOfSelectedLevel_script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Analysis.panel/Tools.stack2/Inspect.pulldown/ListElementsOfSelectedLevel.pushbutton/ListElementsOfSelectedLevel_script.py index ce0fb1428..8def562d6 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Analysis.panel/Tools.stack2/Inspect.pulldown/ListElementsOfSelectedLevel.pushbutton/ListElementsOfSelectedLevel_script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Analysis.panel/Tools.stack2/Inspect.pulldown/ListElementsOfSelectedLevel.pushbutton/ListElementsOfSelectedLevel_script.py @@ -38,7 +38,7 @@ levels = [] for el in selection: - if el.Category.Name == 'Levels': + if el.Category.Id.IntegerValue == int(DB.BuiltInCategory.OST_Levels): levels.append(el) if not levels: @@ -65,7 +65,7 @@ str(len(element_categories[category])))) for elem_cat in element_categories[category]: - print('├ id: ' + elem_cat.Id.ToString()) + print('├ id: {}'.format(output.linkify(elem_cat.Id))) print('├────────── {} Categories found in {}:' .format(str(len(element_categories)), diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Print.pulldown/Print Ordered Sheet Index.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Print.pulldown/Print Ordered Sheet Index.pushbutton/script.py index 2e463d1f2..8941eaa32 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Print.pulldown/Print Ordered Sheet Index.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Print.pulldown/Print Ordered Sheet Index.pushbutton/script.py @@ -16,7 +16,7 @@ in case an error in the tool causes these characters to remain. """ - +import re import os.path as op import codecs @@ -54,13 +54,15 @@ class PrintSheetsWindow(forms.WPFWindow): def __init__(self, xaml_file_name): forms.WPFWindow.__init__(self, xaml_file_name) - for cat in revit.doc.Settings.Categories: - if cat.Name == 'Sheets': - self.sheet_cat_id = cat.Id + self.sheet_cat_id = \ + revit.query.get_category(DB.BuiltInCategory.OST_Sheets).Id self._setup_printers() self._setup_print_settings() self.schedules_cb.ItemsSource = self._get_sheet_index_list() + if not self.schedules_cb.ItemsSource: + forms.alert("No Sheet Lists (Schedules) found in current project", + exitscript=True) self.schedules_cb.SelectedIndex = 0 item_cstyle = self.sheets_lb.ItemContainerStyle @@ -153,9 +155,13 @@ def _order_sheets_by_schedule_data(self, schedule_view, sheet_list): ordered_sheets_dict = {} for sheet in sheet_list: + logger.debug('finding index for: %s', sheet.SheetNumber) for line_no, data_line in enumerate(sched_data): + match_pattern = r'(^|.*\t){}\t.*'.format(sheet.SheetNumber) + matches_sheet = re.match(match_pattern, data_line) + logger.debug('match: %s', matches_sheet) try: - if sheet.SheetNumber in data_line: + if matches_sheet: ordered_sheets_dict[line_no] = sheet break if not sheet.CanBePrinted: diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Copy Sheets to Open Documents.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Copy Sheets to Open Documents.pushbutton/script.py index d75088dc2..3c7baca89 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Copy Sheets to Open Documents.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Copy Sheets to Open Documents.pushbutton/script.py @@ -343,6 +343,12 @@ def copy_sheet_viewports(activedoc, source_sheet, dest_doc, dest_sheet): new_view = copy_view(activedoc, vport_view, dest_doc) if new_view: + ref_info = revit.query.get_view_sheetrefinfo(new_view) + if ref_info and ref_info.sheet_num != dest_sheet.SheetNumber: + logger.error('View is already placed on sheet \"%s - %s\"', + ref_info.sheet_num, ref_info.sheet_name) + continue + if new_view.Id not in existing_views: print('\t\t\tPlacing copied view on sheet.') with revit.Transaction('Place View on Sheet', doc=dest_doc): diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Decrement Selected Sheet Numbers.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Decrement Selected Sheet Numbers.pushbutton/script.py index 9f2c5ee08..6d7b24eff 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Decrement Selected Sheet Numbers.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Decrement Selected Sheet Numbers.pushbutton/script.py @@ -1,6 +1,6 @@ #pylint: disable=W0703,E0401,C0103,C0111 from pyrevit import coreutils -from pyrevit import revit +from pyrevit import revit, DB from pyrevit import forms from pyrevit import script @@ -28,9 +28,10 @@ with revit.Transaction('Shift Single Sheet'): try: cur_sheet_num = sheet.SheetNumber - sheet_num_param = sheet.LookupParameter('Sheet Number') - sheet_num_param.Set(coreutils.decrement_str(sheet.SheetNumber, - shift)) + sheetnum_p = sheet.Parameter[DB.BuiltInParameter.SHEET_NUMBER] + sheetnum_p.Set( + coreutils.decrement_str(sheet.SheetNumber, shift) + ) new_sheet_num = sheet.SheetNumber logger.info('{} -> {}'.format(cur_sheet_num, new_sheet_num)) except Exception as shift_err: diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Increment Selected Sheet Numbers.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Increment Selected Sheet Numbers.pushbutton/script.py index 9ec1d0ac7..c35147d4a 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Increment Selected Sheet Numbers.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Increment Selected Sheet Numbers.pushbutton/script.py @@ -1,6 +1,6 @@ #pylint: disable=W0703,E0401,C0103,C0111 from pyrevit import coreutils -from pyrevit import revit +from pyrevit import revit, DB from pyrevit import forms from pyrevit import script @@ -29,9 +29,10 @@ with revit.Transaction('Shift Single Sheet'): try: cur_sheet_num = sheet.SheetNumber - sheet_num_param = sheet.LookupParameter('Sheet Number') - sheet_num_param.Set(coreutils.increment_str(sheet.SheetNumber, - shift)) + sheetnum_p = sheet.Parameter[DB.BuiltInParameter.SHEET_NUMBER] + sheetnum_p.Set( + coreutils.increment_str(sheet.SheetNumber, shift) + ) new_sheet_num = sheet.SheetNumber logger.info('{} -> {}'.format(cur_sheet_num, new_sheet_num)) except Exception as shift_err: diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/ReOrder Sheets.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/ReOrder Sheets.pushbutton/script.py index 239854d51..ae52b803e 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/ReOrder Sheets.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/ReOrder Sheets.pushbutton/script.py @@ -1,4 +1,8 @@ -"""Print items in order from a sheet index.""" +"""Print items in order from a sheet index. + +This tool looks for project parameters (on Sheets) that are +Instance, of type Integer, and have "Order" in their names. +""" #pylint: disable=W0613,E0401,C0103 import re @@ -93,6 +97,7 @@ def _setup_item_params_combobox(self): item_sample = items[0] item_params = [x.Definition.Name for x in item_sample.Parameters if x.StorageType == DB.StorageType.Integer] + order_params = [x for x in item_params if 'order' in x.lower()] self.orderparams_cb.ItemsSource = sorted(order_params) self.orderparams_cb.SelectedIndex = 0 diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/views.stack3/Legends.pulldown/Copy Legends to Other Documents.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/views.stack3/Legends.pulldown/Copy Legends to Other Documents.pushbutton/script.py index 06eb7c839..71340e919 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/views.stack3/Legends.pulldown/Copy Legends to Other Documents.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/views.stack3/Legends.pulldown/Copy Legends to Other Documents.pushbutton/script.py @@ -88,12 +88,13 @@ def OnDuplicateTypeNamesFound(self, args): ) # matching view name and scale - new_name = revit.query.get_name(src_legend) - if new_name in all_legend_names: - new_name += ' (Duplicate)' + src_name = revit.query.get_name(src_legend) + count = 0 + new_name = src_name + while new_name in all_legend_names: + count += 1 + new_name = src_name + ' (Duplicate %s)' % count logger.warning( - 'Legend already exists. Renaming to: "%s"', - new_name - ) + 'Legend already exists. Renaming to: "%s"', new_name) revit.update.set_name(dest_view, new_name) dest_view.Scale = src_legend.Scale diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/views.stack3/Views.pulldown/Add Views to Sheets.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/views.stack3/Views.pulldown/Add Views to Sheets.pushbutton/script.py index b6563aa1a..a3dfe7d12 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/views.stack3/Views.pulldown/Add Views to Sheets.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/views.stack3/Views.pulldown/Add Views to Sheets.pushbutton/script.py @@ -26,7 +26,7 @@ if not selection.is_empty: logger.debug('Getting views from selection.') for el in selection: - if el.Category and el.Category.Name == 'Views': + if el.Category and el.Category.Id.IntegerValue == int(DB.BuiltInCategory.OST_Views): logger.debug('Selected element referencing: {}' .format(el.Name)) target_view = revit.query.get_view_by_name(el.Name) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/views.stack3/Views.pulldown/Find Views By Filter.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/views.stack3/Views.pulldown/Find Views By Filter.pushbutton/script.py index 3c4fef305..403639f13 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/views.stack3/Views.pulldown/Find Views By Filter.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/views.stack3/Views.pulldown/Find Views By Filter.pushbutton/script.py @@ -14,8 +14,13 @@ .WhereElementIsNotElementType()\ .ToElements() +ELEMENT_ID_NULL = DB.ElementId(-1) -def find_views_with_underlay(): +def elementid_has_value(p): + return p.AsElementId() != ELEMENT_ID_NULL + + +def find_views_with_underlay(invert=False): for v in views: try: if HOST_APP.is_newer_than(2016, or_equal=True): @@ -23,15 +28,16 @@ def find_views_with_underlay(): v.Parameter[DB.BuiltInParameter.VIEW_UNDERLAY_BOTTOM_ID] top_underlay_param = \ v.Parameter[DB.BuiltInParameter.VIEW_UNDERLAY_TOP_ID] - if base_underlay_param \ + if (base_underlay_param \ and top_underlay_param \ - and base_underlay_param.AsValueString() != 'None' \ - and top_underlay_param.AsValueString() != 'None': + and elementid_has_value(base_underlay_param) \ + and elementid_has_value(top_underlay_param) + ) != invert: print('TYPE: {1}\n' 'ID: {2}\n' 'TEMPLATE: {3}\n' - 'UNDERLAY (BASE):{4}\n' - 'UNDERLAY (TOP):{5}\n' + 'UNDERLAY (BASE): {4}\n' + 'UNDERLAY (TOP): {5}\n' '{0}\n\n' .format(revit.query.get_name(v), str(v.ViewType).ljust(20), @@ -41,27 +47,34 @@ def find_views_with_underlay(): top_underlay_param.AsValueString().ljust(25))) else: underlayp = v.Parameter[DB.BuiltInParameter.VIEW_UNDERLAY_ID] - if underlayp and underlayp.AsValueString() != 'None': + if (underlayp and elementid_has_value(underlayp) + ) != invert: print('TYPE: {1}\n' 'ID: {2}\n' 'TEMPLATE: {3}\n' - 'UNDERLAY:{4}\n' + 'UNDERLAY: {4}\n' '{0}\n\n'.format(revit.query.get_name(v), str(v.ViewType).ljust(20), output.linkify(v.Id), str(v.IsTemplate).ljust(10), underlayp.AsValueString().ljust(25))) + print("\n\n") except Exception: continue -def find_view_with_template(): - for v in views: +def find_view_with_template(invert=False): + views_sorted = sorted(views, key=lambda v: v.IsTemplate) + for v in views_sorted: vtid = v.ViewTemplateId vt = revit.doc.GetElement(vtid) - if vt: + if bool(vt) != invert: phasep = v.Parameter[DB.BuiltInParameter.VIEW_PHASE] - print('TYPE: {1} ID: {2} TEMPLATE: {3} PHASE:{4} {0}'.format( + print('TYPE: {1}\n' + 'ID: {2}\n' + 'TEMPLATE: {3}\n' + 'PHASE:{4}\n' + '{0}'.format( revit.query.get_name(v), str(v.ViewType).ljust(20), output.linkify(v.Id), @@ -70,16 +83,23 @@ def find_view_with_template(): if phasep else '---'.ljust(25) ) ) + print("\n\n") selected_option = \ forms.CommandSwitchWindow.show( ['with underlay', - 'with template'], + 'without underlay', + 'with template', + 'without template'], message='Select search option:' ) if selected_option == 'with underlay': find_views_with_underlay() +elif selected_option == 'without underlay': + find_views_with_underlay(True) elif selected_option == 'with template': find_view_with_template() +elif selected_option == 'without template': + find_view_with_template(True) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Groups.pulldown/Explode And Remove Selected Groups.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Groups.pulldown/Explode And Remove Selected Groups.pushbutton/script.py index 8242a8499..ee91c6252 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Groups.pulldown/Explode And Remove Selected Groups.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Groups.pulldown/Explode And Remove Selected Groups.pushbutton/script.py @@ -1,39 +1,48 @@ -from pyrevit import revit, DB, UI +"""Explodes all instances of the selected groups and removes +the group definition from project browser. +""" +#pylint: disable=import-error,invalid-name,broad-except +from pyrevit import revit, DB from pyrevit import forms +from pyrevit import script __context__ = 'selection' -__doc__ = 'Explodes all instances of the selected groups and removes '\ - 'the group definition from project browser.' -selection = revit.get_selection() +logger = script.get_logger() -with revit.Transaction('Explode and Purge Selected Groups'): - grpTypes = set() - grps = [] - attachedGrps = [] - - for el in selection: - if isinstance(el, DB.GroupType): - grpTypes.add(el) - elif isinstance(el, DB.Group): - grpTypes.add(el.GroupType) - if len(grpTypes) == 0: - forms.alert('At least one group type must be selected.') +group_types = set() +for el in revit.get_selection(): + if isinstance(el, DB.GroupType): + group_types.add(el) + elif isinstance(el, DB.Group): + group_types.add(el.GroupType) - for gt in grpTypes: - for grp in gt.Groups: - grps.append(grp) +# find all groups +all_groups = [x for gt in group_types for x in gt.Groups] +logger.debug('all groups: %s', all_groups) - for g in grps: - if g.Parameter[DB.BuiltInParameter.GROUP_ATTACHED_PARENT_NAME]: - attachedGrps.append(g.GroupType) - g.UngroupMembers() +# grab all group types to be deleted +group_type_ids = {x.Id.IntegerValue for x in group_types} +group_type_ids.update( + [x.GroupType.Id.IntegerValue for x in all_groups + if x.Parameter[DB.BuiltInParameter.GROUP_ATTACHED_PARENT_NAME]] +) +logger.debug('group types: %s', group_type_ids) +if not group_type_ids: + forms.alert( + 'At least one group type must be selected.', + exitscript=True + ) - for agt in attachedGrps: - revit.doc.Delete(agt.Id) - - for gt in grpTypes: - revit.doc.Delete(gt.Id) +with revit.Transaction('Explode and Purge Selected Groups'): + # ungroup groups + for grp in all_groups: + logger.debug('Ungrouping %s', grp.Id) + grp.UngroupMembers() + + for grpt_id in group_type_ids: + logger.debug('Deleting %s', grpt_id) + revit.doc.Delete(DB.ElementId(grpt_id)) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Override.pulldown/Override Dims.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Override.pulldown/Override Dims.pushbutton/script.py index f954f15e1..6e083fd6c 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Override.pulldown/Override Dims.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Override.pulldown/Override Dims.pushbutton/script.py @@ -8,7 +8,7 @@ __author__ = 'Ehsan Iran-Nejad; SILMAN' -__context__ = 'Dimensions' +__context__ = 'OST_Dimensions' def grab_dims(): diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Override.pulldown/Override Text.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Override.pulldown/Override Text.pushbutton/script.py index ed83dc086..136a5fc90 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Override.pulldown/Override Text.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Override.pulldown/Override Text.pushbutton/script.py @@ -5,7 +5,7 @@ from pyrevit import forms -__context__ = 'Text Notes' +__context__ = 'OST_TextNotes' selection = revit.get_selection() diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Override.pulldown/Override VG.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Override.pulldown/Override VG.pushbutton/script.py index c11cb9230..c2ddb39f7 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Override.pulldown/Override VG.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/edit2.stack3/Override.pulldown/Override VG.pushbutton/script.py @@ -1,6 +1,5 @@ """Provides options for overriding Visibility/Graphics on selected elements.""" #pylint: disable=E0401,C0103 -import re from collections import OrderedDict from pyrevit import revit, DB @@ -19,14 +18,12 @@ def find_solid_fillpat(): - solid_fill_regex = re.compile('[<]?solid fill[>]?') existing_pats = DB.FilteredElementCollector(revit.doc)\ .OfClass(DB.FillPatternElement)\ .ToElements() for pat in existing_pats: fpat = pat.GetFillPattern() - if solid_fill_regex.match(fpat.Name.lower()) \ - and fpat.Target == DB.FillPatternTarget.Drafting: + if fpat.IsSolidFill and fpat.Target == DB.FillPatternTarget.Drafting: return pat @@ -39,14 +36,17 @@ def colorvg(r, g, b, projline_only=False, xacn_name=None): selection.append(revit.doc.GetElement(mem)) ogs = DB.OverrideGraphicSettings() ogs.SetProjectionLineColor(color) + ogs.SetCutLineColor(color) if not projline_only: ogs.SetProjectionFillColor(color) + ogs.SetCutFillColor(color) solid_fpattern = find_solid_fillpat() if solid_fpattern: ogs.SetProjectionFillPatternId(solid_fpattern.Id) + ogs.SetCutFillPatternId(solid_fpattern.Id) else: logger.warning('Can not find solid fill pattern in model' - 'to assign as projection pattern.') + 'to assign as projection/cut pattern.') revit.doc.ActiveView.SetElementOverrides(el.Id, ogs) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/Cycle Family Types.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/Cycle Family Types.pushbutton/script.py index edaca0b02..06ddbc183 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/Cycle Family Types.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/Cycle Family Types.pushbutton/script.py @@ -11,13 +11,14 @@ family_mgr = revit.doc.FamilyManager family_types = sorted([x.Name for x in family_mgr.Types]) -current_idx = family_types.index(family_mgr.CurrentType.Name) -current_idx += 1 -if current_idx >= len(family_types): - current_idx = 0 +if family_mgr.CurrentType: + current_idx = family_types.index(family_mgr.CurrentType.Name) + current_idx += 1 + if current_idx >= len(family_types): + current_idx = 0 -with revit.Transaction('Cycle Famiy Type'): - for ftype in family_mgr.Types: - if ftype.Name == family_types[current_idx]: - family_mgr.CurrentType = ftype - revit.ui.set_statusbar_text(ftype.Name) + with revit.Transaction('Cycle Famiy Type'): + for ftype in family_mgr.Types: + if ftype.Name == family_types[current_idx]: + family_mgr.CurrentType = ftype + revit.ui.set_statusbar_text(ftype.Name) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/Wipe.pulldown/Wipe Data Schema.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/Wipe.pulldown/Wipe Data Schema.pushbutton/script.py index 51b03f9f2..934c88f6d 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/Wipe.pulldown/Wipe Data Schema.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/Wipe.pulldown/Wipe Data Schema.pushbutton/script.py @@ -19,6 +19,6 @@ def name(self): if sschema: with revit.Transaction("Remove Schema"): DB.ExtensibleStorage.Schema.EraseSchemaAndAllEntities( - sschema, - True + schema=sschema, + overrideWriteAccessWithUserPermission=True ) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack3/Family.pulldown/Export Family Config.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack3/Family.pulldown/Export Family Config.pushbutton/script.py index 7f438dee9..13144ad79 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack3/Family.pulldown/Export Family Config.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack3/Family.pulldown/Export Family Config.pushbutton/script.py @@ -10,7 +10,9 @@ type: category: instance: + reporting: formula: + default: types: : : @@ -23,15 +25,15 @@ parameters: Shelf Height (Upper): type: Length - category: PG_GEOMETRY + group: PG_GEOMETRY instance: false types: 24D"x36H": Shelf Height (Upper): 3'-0" """ #pylint: disable=import-error,invalid-name,broad-except -# TODO: fix parameter ordering -# TODO: export defautl param values +# TODO: export parameter ordering +from collections import OrderedDict from pyrevit import revit, DB from pyrevit import forms @@ -50,8 +52,11 @@ PARAM_SECTION_NAME = 'parameters' PARAM_SECTION_TYPE = 'type' PARAM_SECTION_CAT = 'category' +PARAM_SECTION_GROUP = 'group' PARAM_SECTION_INST = 'instance' +PARAM_SECTION_REPORT = 'reporting' PARAM_SECTION_FORMULA = 'formula' +PARAM_SECTION_DEFAULT = 'default' TYPES_SECTION_NAME = 'types' @@ -59,7 +64,20 @@ FAMILY_SYMBOL_FORMAT = '{} : {}' +class SortableParam(object): + def __init__(self, fparam): + self.fparam = fparam + + def __lt__(self, other_sortableparam): + formula = other_sortableparam.fparam.Formula + if formula: + return self.fparam.Definition.Name in formula + + def get_symbol_name(symbol_id): + # get family-symbol formatted name for export + # current implementation matches the repr to how Revit shows the value + # famil-name : symbol-name for fsym in DB.FilteredElementCollector(revit.doc)\ .OfClass(DB.FamilySymbol)\ .ToElements(): @@ -70,58 +88,112 @@ def get_symbol_name(symbol_id): ) -def include_type_configs(cfgs_dict, fparams): +def get_param_typevalue(ftype, fparam): + fparam_value = None + # extract value by param type + if fparam.StorageType == DB.StorageType.ElementId \ + and fparam.Definition.ParameterType == \ + DB.ParameterType.FamilyType: + fparam_value = get_symbol_name(ftype.AsElementId(fparam)) + + elif fparam.StorageType == DB.StorageType.String: + fparam_value = ftype.AsString(fparam) + + elif fparam.StorageType == DB.StorageType.Integer \ + and fparam.Definition.ParameterType.YesNo: + fparam_value = \ + 'true' if ftype.AsInteger(fparam) == 1 else 'false' + + else: + fparam_value = ftype.AsValueString(fparam) + + return fparam_value + + +def include_type_configs(cfgs_dict, sparams): + # add the parameter values for all types into the configs dict fm = revit.doc.FamilyManager - # grab param values for types + # grab param values for each family type for ftype in fm.Types: + # param value dict for this type type_config = {} - for fparam in fparams: - fparam_name = fparam.Definition.Name - fparam_value = None - if fparam.StorageType == DB.StorageType.ElementId \ - and fparam.Definition.ParameterType == \ - DB.ParameterType.FamilyType: - fparam_value = get_symbol_name(ftype.AsElementId(fparam)) - elif fparam.StorageType == DB.StorageType.String: - fparam_value = ftype.AsString(fparam) - elif fparam.StorageType == DB.StorageType.Integer \ - and fparam.Definition.ParameterType.YesNo: - fparam_value = \ - 'true' if ftype.AsInteger(fparam) == 1 else 'false' - else: - fparam_value = ftype.AsValueString(fparam) - - type_config[fparam_name] = fparam_value - + # grab value from each param + for sparam in sparams: + fparam_name = sparam.fparam.Definition.Name + # add the value to this type config + type_config[fparam_name] = \ + get_param_typevalue(ftype, sparam.fparam) + + # add the type config to overall config dict cfgs_dict[TYPES_SECTION_NAME][ftype.Name] = type_config -def read_configs(selected_fparam_names, include_types=False): - cfgs_dict = {PARAM_SECTION_NAME: {}, TYPES_SECTION_NAME: {}} +def add_default_values(cfgs_dict, sparams): + # add the parameter values for all types into the configs dict + fm = revit.doc.FamilyManager + + # grab value from each param + for sparam in sparams: + fparam_name = sparam.fparam.Definition.Name + param_config = cfgs_dict[PARAM_SECTION_NAME][fparam_name] + # grab current param value + fparam_value = get_param_typevalue(fm.CurrentType, sparam.fparam) + if fparam_value: + param_config[PARAM_SECTION_DEFAULT] = fparam_value + +def get_famtype_famcat(fparam): + # grab the family category from para with type DB.ParameterType.FamilyType + # these parameters point to a family and symbol but the Revit API + # does not provide info on what family categories they are assinged to fm = revit.doc.FamilyManager + famtype = revit.doc.GetElement(fm.CurrentType.AsElementId(fparam)) + return famtype.Category.Name + + +def read_configs(selected_fparam_names, + include_types=False, include_defaults=False): + # read parameter and type configurations into a dictionary + cfgs_dict = OrderedDict({PARAM_SECTION_NAME: {}, TYPES_SECTION_NAME: {}}) - export_fparams = [x for x in fm.GetParameters() + fm = revit.doc.FamilyManager + + # pick the param objects from list of param names + # params are wrapped by SortableParam + # SortableParam helps sorting parameters based on their formula + # dependencies. A parameter that is being used inside another params + # formula is considered smaller (lower on the output) than that param + export_sparams = [SortableParam(x) for x in fm.GetParameters() if x.Definition.Name in selected_fparam_names] # grab all parameter defs - for fparam in export_fparams: - fparam_name = fparam.Definition.Name - fparam_type = str(fparam.Definition.ParameterType) - fparam_group = str(fparam.Definition.ParameterGroup) - fparam_isinst = fparam.IsInstance - fparam_formula = fparam.Formula + for sparam in sorted(export_sparams, reverse=True): + fparam_name = sparam.fparam.Definition.Name + fparam_type = sparam.fparam.Definition.ParameterType + fparam_group = sparam.fparam.Definition.ParameterGroup + fparam_isinst = sparam.fparam.IsInstance + fparam_isreport = sparam.fparam.IsReporting + fparam_formula = sparam.fparam.Formula cfgs_dict[PARAM_SECTION_NAME][fparam_name] = { - PARAM_SECTION_TYPE: fparam_type, - PARAM_SECTION_CAT: fparam_group, + PARAM_SECTION_TYPE: str(fparam_type), + PARAM_SECTION_GROUP: str(fparam_group), PARAM_SECTION_INST: fparam_isinst, + PARAM_SECTION_REPORT: fparam_isreport, PARAM_SECTION_FORMULA: fparam_formula } + # get the family category if param is FamilyType selector + if fparam_type == DB.ParameterType.FamilyType: + cfgs_dict[PARAM_SECTION_NAME][fparam_name][PARAM_SECTION_CAT] = \ + get_famtype_famcat(sparam.fparam) + + # include type configs? if include_types: - include_type_configs(cfgs_dict, export_fparams) + include_type_configs(cfgs_dict, export_sparams) + elif include_defaults: + add_default_values(cfgs_dict, export_sparams) return cfgs_dict @@ -137,6 +209,7 @@ def save_configs(configs_dict, parma_file): def get_parameters(): + # get list of parameters to be exported from user fm = revit.doc.FamilyManager return forms.SelectFromList.show( [x.Definition.Name for x in fm.GetParameters()], @@ -152,10 +225,26 @@ def get_parameters(): if family_cfg_file: family_params = get_parameters() if family_params: + inctypes = incdefault = False + # ask user to include family type definitions inctypes = forms.alert( "Do you want to export family types as well?", yes=True, no=True ) - family_configs = read_configs(family_params, include_types=inctypes) + # if said no, ask if the current param values should be included + if not inctypes: + incdefault = forms.alert( + "Do you want to include the current parameter values as " + "default? Otherwise the parameters will not include any " + "value and their default value will be assigned " + "by Revit at import.", + yes=True, no=True + ) + + family_configs = \ + read_configs(family_params, + include_types=inctypes, + include_defaults=incdefault) + logger.debug(family_configs) save_configs(family_configs, family_cfg_file) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack3/Family.pulldown/Import Family Config.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack3/Family.pulldown/Import Family Config.pushbutton/script.py index c4fac9b07..3b4ab0452 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack3/Family.pulldown/Import Family Config.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack3/Family.pulldown/Import Family Config.pushbutton/script.py @@ -10,7 +10,9 @@ type: category: instance: + reporting: formula: + default: types: : : @@ -30,7 +32,8 @@ Shelf Height (Upper): 3'-0" """ #pylint: disable=import-error,invalid-name,broad-except -# TODO: fix parameter ordering +# TODO: import parameter ordering +# TODO: merge configs on identical parameters from collections import namedtuple from pyrevit import coreutils @@ -52,15 +55,24 @@ DEFAULT_BIP_CATEGORY = 'PG_CONSTRUCTION' PARAM_SECTION_NAME = 'parameters' -TYPES_SECTION_NAME = 'types' +PARAM_SECTION_TYPE = 'type' +PARAM_SECTION_CAT = 'category' +PARAM_SECTION_GROUP = 'group' +PARAM_SECTION_INST = 'instance' +PARAM_SECTION_REPORT = 'reporting' +PARAM_SECTION_FORMULA = 'formula' +PARAM_SECTION_DEFAULT = 'default' +TYPES_SECTION_NAME = 'types' FAMILY_SYMBOL_SEPARATOR = ' : ' +TEMP_TYPENAME = "Default" ParamConfig = \ namedtuple( 'ParamConfig', - ['name', 'bicat', 'bitype', 'isinst', 'formula'] + ['name', 'bigroup', 'bitype', 'famcat', + 'isinst', 'isreport', 'formula', 'default'] ) @@ -78,7 +90,13 @@ ) -def get_symbol(symbol_name): +failed_params = [] + + +def get_symbol_id(symbol_name): + # translate family-symbol formatted name and find the loaded symbol + # current implementation matches the repr to how Revit shows the value + # famil-name : symbol-name if FAMILY_SYMBOL_SEPARATOR not in symbol_name: logger.warning( 'Family type parameter value must be formatted as ' @@ -102,14 +120,23 @@ def get_param_config(param_name, param_opts): # extract configured values param_bip_cat = coreutils.get_enum_value( DB.BuiltInParameterGroup, - param_opts.get('category', DEFAULT_BIP_CATEGORY) + param_opts.get(PARAM_SECTION_GROUP, DEFAULT_BIP_CATEGORY) ) param_type = coreutils.get_enum_value( DB.ParameterType, - param_opts.get('type', DEFAULT_TYPE) + param_opts.get(PARAM_SECTION_TYPE, DEFAULT_TYPE) ) - param_isinst = param_opts.get('instance', 'false').lower() == 'true' - param_formula = param_opts.get('formula', None) + param_famtype = None + if param_type == DB.ParameterType.FamilyType: + param_famtype = param_opts.get(PARAM_SECTION_CAT, None) + if param_famtype: + param_famtype = revit.query.get_category(param_famtype) + param_isinst = \ + param_opts.get(PARAM_SECTION_INST, 'false').lower() == 'true' + param_isreport = \ + param_opts.get(PARAM_SECTION_REPORT, 'false').lower() == 'true' + param_formula = param_opts.get(PARAM_SECTION_FORMULA, None) + param_default = param_opts.get(PARAM_SECTION_DEFAULT, None) if not param_bip_cat: logger.critical( @@ -122,15 +149,49 @@ def get_param_config(param_name, param_opts): ) return + # return a bundle with extracted values return ParamConfig( name=param_name, - bicat=param_bip_cat, + bigroup=param_bip_cat, bitype=param_type, + famcat=param_famtype, isinst=param_isinst, - formula=param_formula + isreport=param_isreport, + formula=param_formula, + default=param_default ) +def set_fparam_value(pvcfg, fparam): + # set param name:value on given param object + # it is smart about the type and can resolve FamilyType values + fm = revit.doc.FamilyManager + + if fparam.Formula: + logger.debug( + 'can not set parameter value with formula: %s', pvcfg.name + ) + return + + if not pvcfg.value: + logger.debug('skipping parameter with no value: %s', pvcfg.name) + return + + if fparam.StorageType == DB.StorageType.ElementId \ + and fparam.Definition.ParameterType == \ + DB.ParameterType.FamilyType: + # resolve FamilyType value and get the symbol id + fsym_id = get_symbol_id(pvcfg.value) + fm.Set(fparam, fsym_id) + elif fparam.StorageType == DB.StorageType.String: + fm.Set(fparam, pvcfg.value) + elif fparam.StorageType == DB.StorageType.Integer \ + and fparam.Definition.ParameterType.YesNo: + fm.Set(fparam, 1 if pvcfg.value.lower() == 'true' else 0) + else: + fm.SetValueString(fparam, pvcfg.value) + + def ensure_param(param_name, param_opts): # Create family parameter based on name and options fm = revit.doc.FamilyManager @@ -141,24 +202,79 @@ def ensure_param(param_name, param_opts): pcfg = get_param_config(param_name, param_opts) if pcfg: - logger.debug('%s %s %s', pcfg.bicat, pcfg.bitype, pcfg.isinst) + logger.debug( + '%s %s %s %s %s', + pcfg.bigroup, + pcfg.bitype, + '"%s"' % pcfg.famcat.Name if pcfg.famcat else None, + pcfg.isinst, + pcfg.formula + ) fparam = revit.query.get_family_parameter(param_name, revit.doc) if not fparam: # create param in family doc - fparam = fm.AddParameter( - pcfg.name, - pcfg.bicat, - pcfg.bitype, - pcfg.isinst - ) - + try: + fparam = fm.AddParameter( + pcfg.name, + pcfg.bigroup, + pcfg.famcat if pcfg.famcat else pcfg.bitype, + pcfg.isinst + ) + except Exception as addparam_ex: + if pcfg.famcat: + failed_params.append(pcfg.name) + logger.error( + 'Error creating parameter: %s\n' + 'This parameter is a nested family selector. ' + 'Make sure at least one nested family of type "%s" ' + 'is already loaded in this family. | %s', + pcfg.name, + pcfg.famcat.Name, + addparam_ex + ) + + logger.debug('Created: %s', fparam) + + # either set the formula if pcfg.formula: - fm.SetFormula(fparam, pcfg.formula) + try: + if any([x in pcfg.formula for x in failed_params]): + logger.error( + 'Can not set formula for: %s\n' + 'One of the failed parameters is used in formula.', + pcfg.name, + ) + else: + fm.SetFormula(fparam, pcfg.formula) + except Exception as formula_ex: + logger.error('Failed to set formula on: %s | %s', + pcfg.name, formula_ex) + # or the default value if any + elif pcfg.default: + try: + set_fparam_value( + ParamValueConfig(name=pcfg.name, value=pcfg.default), + fparam + ) + except Exception as defaultval_ex: + logger.error('Failed to set default value for: %s | %s', + pcfg.name, defaultval_ex) + + # is it reporting? + # if param has default value, it is already set + # value can not be set on reporting params + if pcfg.isreport and not pcfg.formula: + try: + fm.MakeReporting(fparam) + except Exception as makereport_ex: + logger.error('Failed to make reporting: %s | %s', + pcfg.name, makereport_ex) return fparam def ensure_params(fconfig): + # ensure all defined parameters exist param_cfgs = fconfig.get(PARAM_SECTION_NAME, None) if param_cfgs: for pname, popts in param_cfgs.items(): @@ -166,6 +282,7 @@ def ensure_params(fconfig): def get_type_config(type_name, type_opts): + # get defined param:value configs from input if type_name and type_opts: pvalue_cfgs = [] for pname, pvalue in type_opts.items(): @@ -175,6 +292,7 @@ def get_type_config(type_name, type_opts): def ensure_type(type_config): + # ensure given family type exist fm = revit.doc.FamilyManager # extract type config from dict logger.debug('%s %s', type_config.name, type_config.param_values) @@ -186,34 +304,8 @@ def ensure_type(type_config): return ftype -def set_fparam_value(pvcfg, fparam): - fm = revit.doc.FamilyManager - - if fparam.Formula: - logger.debug( - 'can not set parameter value with formula: %s', pvcfg.name - ) - return - - if not pvcfg.value: - logger.debug('skipping parameter with no value: %s', pvcfg.name) - return - - if fparam.StorageType == DB.StorageType.ElementId \ - and fparam.Definition.ParameterType == \ - DB.ParameterType.FamilyType: - fsym_id = get_symbol(pvcfg.value) - fm.Set(fparam, fsym_id) - elif fparam.StorageType == DB.StorageType.String: - fm.Set(fparam, pvcfg.value) - elif fparam.StorageType == DB.StorageType.Integer \ - and fparam.Definition.ParameterType.YesNo: - fm.Set(fparam, 1 if pvcfg.value.lower() == 'true' else 0) - else: - fm.SetValueString(fparam, pvcfg.value) - - def ensure_types(fconfig): + # ensure all defined family types exist fm = revit.doc.FamilyManager type_cfgs = fconfig.get(TYPES_SECTION_NAME, None) if type_cfgs: @@ -255,14 +347,20 @@ def load_configs(parma_file): family_cfg_file = get_config_file() if family_cfg_file: + family_mgr = revit.doc.FamilyManager family_configs = load_configs(family_cfg_file) logger.debug(family_configs) with revit.Transaction('Import Params from Config'): # remember current type - ctype = revit.doc.FamilyManager.CurrentType + # if family does not have type, create a temp type + # otherwise setting formula will fail + ctype = family_mgr.CurrentType + if not ctype: + ctype = family_mgr.NewType(TEMP_TYPENAME) ensure_params(family_configs) ensure_types(family_configs) # restore current type - revit.doc.FamilyManager.CurrentType = ctype + if ctype.Name != TEMP_TYPENAME: + family_mgr.CurrentType = ctype diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools2.stack3/Get RVT Info.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools2.stack3/Get RVT Info.pushbutton/script.py index 2888abbd9..bc9f0b39f 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools2.stack3/Get RVT Info.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools2.stack3/Get RVT Info.pushbutton/script.py @@ -24,6 +24,10 @@ print("Open Workset Settings: {0}".format(mfile.OpenWorksetConfig)) print("Document Increment: {0}".format(mfile.DocumentIncrement)) + print("Project Information (Properties):") + for k, v in sorted(dict(mfile.ProjectInfoProperties).items()): + print('\t{} = {}'.format(k, v)) + if mfile.IsFamily: print("Model is a Revit Family!") print("Category Name: {0}".format(mfile.CategoryName)) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/Pick.splitpushbutton/Pick.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/Pick.splitpushbutton/Pick.pushbutton/script.py index 9f9081493..7e1a4d747 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/Pick.splitpushbutton/Pick.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/Pick.splitpushbutton/Pick.pushbutton/script.py @@ -3,9 +3,10 @@ Shift-Click: Pick from all available categories. """ +# pylint: disable=E0401,W0703,C0103 +from collections import namedtuple -#pylint: disable=E0401,W0703,C0103 -from pyrevit import revit, UI +from pyrevit import revit, UI, DB from pyrevit import forms from pyrevit import script @@ -13,26 +14,55 @@ logger = script.get_logger() +# somehow DB.BuiltInCategory.OST_Truss does not have a corresponding DB.Category +FREQUENTLY_SELECTED_CATEGORIES = [ + DB.BuiltInCategory.OST_Areas, + DB.BuiltInCategory.OST_AreaTags, + DB.BuiltInCategory.OST_AreaSchemeLines, + DB.BuiltInCategory.OST_Columns, + DB.BuiltInCategory.OST_StructuralColumns, + DB.BuiltInCategory.OST_Dimensions, + DB.BuiltInCategory.OST_Doors, + DB.BuiltInCategory.OST_Floors, + DB.BuiltInCategory.OST_StructuralFraming, + DB.BuiltInCategory.OST_Furniture, + DB.BuiltInCategory.OST_Grids, + DB.BuiltInCategory.OST_Rooms, + DB.BuiltInCategory.OST_RoomTags, + DB.BuiltInCategory.OST_Truss, + DB.BuiltInCategory.OST_Walls, + DB.BuiltInCategory.OST_Windows, + DB.BuiltInCategory.OST_Ceilings, + DB.BuiltInCategory.OST_SectionBox, + DB.BuiltInCategory.OST_ElevationMarks, + DB.BuiltInCategory.OST_Parking +] + + +CategoryOption = namedtuple('CategoryOption', ['name', 'revit_cat']) + + class PickByCategorySelectionFilter(UI.Selection.ISelectionFilter): - def __init__(self, catname): - self.category = catname + def __init__(self, category_opt): + self.category_opt = category_opt # standard API override function def AllowElement(self, element): - if self.category in element.Category.Name: + if element.Category \ + and self.category_opt.revit_cat.Id == element.Category.Id: return True else: return False # standard API override function - def AllowReference(self, refer, point): #pylint: disable=W0613 + def AllowReference(self, refer, point): # pylint: disable=W0613 return False -def pickbycategory(catname): +def pick_by_category(category_opt): try: selection = revit.get_selection() - msfilter = PickByCategorySelectionFilter(catname) + msfilter = PickByCategorySelectionFilter(category_opt) selection_list = revit.pick_rectangle(pick_filter=msfilter) filtered_list = [] for element in selection_list: @@ -41,33 +71,23 @@ def pickbycategory(catname): except Exception as err: logger.debug(err) +source_categories = \ + [revit.query.get_category(x) for x in FREQUENTLY_SELECTED_CATEGORIES] +if __shiftclick__: # pylint: disable=E0602 + source_categories = revit.doc.Settings.Categories +# cleanup source categories +source_categories = filter(None, source_categories) +category_opts = \ + [CategoryOption(name=x.Name, revit_cat=x) for x in source_categories] +selected_category = \ + forms.CommandSwitchWindow.show( + sorted([x.name for x in category_opts]), + message='Pick only elements of type:' + ) -if __shiftclick__: #pylint: disable=E0602 - options = sorted([x.Name for x in revit.doc.Settings.Categories]) -else: - options = sorted(['Area', - 'Area Boundary', - 'Column', - 'Dimension', - 'Door', - 'Floor', - 'Framing', - 'Furniture', - 'Grid', - 'Rooms', - 'Room Tag', - 'Truss', - 'Wall', - 'Window', - 'Ceiling', - 'Section Box', - 'Elevation Mark', - 'Parking']) - -selected_switch = \ - forms.CommandSwitchWindow.show(options, - message='Pick only elements of type:') - -if selected_switch: - pickbycategory(selected_switch) +if selected_category: + selected_category_opt = \ + next(x for x in category_opts if x.name == selected_category) + logger.debug(selected_category_opt) + pick_by_category(selected_category_opt) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/select.stack3/Select.pulldown/Invert Selection.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/select.stack3/Select.pulldown/Invert Selection.pushbutton/script.py index 7c6039a2e..57f52ca62 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/select.stack3/Select.pulldown/Invert Selection.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Selection.panel/select.stack3/Select.pulldown/Invert Selection.pushbutton/script.py @@ -1,8 +1,11 @@ -"""Inverts selection in active view.""" +"""Inverts selection in active view. +Shift-Click: +Select group members instead of parent group elements. +""" +#pylint: disable=import-error,invalid-name,broad-except from pyrevit import revit, DB - __context__ = 'selection' @@ -10,15 +13,32 @@ viewelements = DB.FilteredElementCollector(revit.doc, revit.activeview.Id)\ .WhereElementIsNotElementType()\ .ToElements() +# remove anything that is a direct DB.Element obj +# these are the weird internal objects that Revit uses like a camera obj +view_element_ids = \ + {x.Id.IntegerValue for x in viewelements if x.GetType() is not DB.Element} # get current selection selection = revit.get_selection() +selected_element_ids = {x.Id.IntegerValue for x in selection} -# remove anything that is a direct DB.Element obj -# these are the weird internal objects that Revit uses like a camera obj -filtered_selection = [x for x in viewelements - if x not in selection - and type(x) is not DB.Element] +# find elements that are not selected +invert_ids = view_element_ids.difference(selected_element_ids) + + +# if shiftclick, select all the invert elements +# otherwise do not select elements inside a group +filtered_invert_ids = invert_ids.copy() +if not __shiftclick__: #pylint: disable=undefined-variable + # collect ids of elements inside a group + grouped_element_ids = \ + [x.Id.IntegerValue for x in viewelements + if x.GetType() is not DB.Element + and x.GroupId != DB.ElementId.InvalidElementId] + + for element_id in invert_ids: + if element_id in grouped_element_ids: + filtered_invert_ids.remove(element_id) # set selection -selection.set_to(filtered_selection) +selection.set_to([DB.ElementId(x) for x in filtered_invert_ids]) diff --git a/pyrevitlib/pyrevit/coreutils/configparser.py b/pyrevitlib/pyrevit/coreutils/configparser.py index d0aa4c5bc..e338aa4ad 100644 --- a/pyrevitlib/pyrevit/coreutils/configparser.py +++ b/pyrevitlib/pyrevit/coreutils/configparser.py @@ -1,5 +1,6 @@ """Base module for pyRevit config parsing.""" import json +import codecs import ConfigParser from ConfigParser import NoOptionError, NoSectionError @@ -74,7 +75,8 @@ def __setattr__(self, param_name, value): return self._parser.set(self._section_name, param_name, json.dumps(value, - separators=(',', ':'))) + separators=(',', ':'), + ensure_ascii=False)) except Exception as set_err: raise PyRevitException('Error setting parameter value. ' '| {}'.format(set_err)) @@ -144,7 +146,7 @@ def __init__(self, cfg_file_path=None): self._parser = ConfigParser.ConfigParser() if self._cfg_file_path: try: - with open(self._cfg_file_path, 'r') as cfg_file: + with codecs.open(self._cfg_file_path, 'r', 'utf-8') as cfg_file: self._parser.readfp(cfg_file) except (OSError, IOError): raise PyRevitIOError() @@ -163,7 +165,7 @@ def __getattr__(self, section_name): def get_config_file_hash(self): """Get calculated unique hash for this config.""" - with open(self._cfg_file_path, 'r') as cfg_file: + with codecs.open(self._cfg_file_path, 'r', 'utf-8') as cfg_file: cfg_hash = coreutils.get_str_hash(cfg_file.read()) return cfg_hash @@ -214,7 +216,8 @@ def remove_section(self, section_name): def reload(self, cfg_file_path=None): """Reload config from original or given file.""" try: - with open(cfg_file_path or self._cfg_file_path, 'r') as cfg_file: + with codecs.open(cfg_file_path \ + or self._cfg_file_path, 'r', 'utf-8') as cfg_file: self._parser.readfp(cfg_file) except (OSError, IOError): raise PyRevitIOError() @@ -222,7 +225,8 @@ def reload(self, cfg_file_path=None): def save(self, cfg_file_path=None): """Save config to original or given file.""" try: - with open(cfg_file_path or self._cfg_file_path, 'w') as cfg_file: + with codecs.open(cfg_file_path \ + or self._cfg_file_path, 'w', 'utf-8') as cfg_file: self._parser.write(cfg_file) except (OSError, IOError): raise PyRevitIOError() diff --git a/pyrevitlib/pyrevit/forms/CommandSwitchWindow.xaml b/pyrevitlib/pyrevit/forms/CommandSwitchWindow.xaml index 6cf115c26..a8cb04f35 100644 --- a/pyrevitlib/pyrevit/forms/CommandSwitchWindow.xaml +++ b/pyrevitlib/pyrevit/forms/CommandSwitchWindow.xaml @@ -32,7 +32,7 @@ Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" - RecognizesAccessKey="True" + RecognizesAccessKey="{DynamicResource pyRevitRecognizesAccessKey}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> diff --git a/pyrevitlib/pyrevit/forms/__init__.py b/pyrevitlib/pyrevit/forms/__init__.py index 8ca7a661c..60a1f53b3 100644 --- a/pyrevitlib/pyrevit/forms/__init__.py +++ b/pyrevitlib/pyrevit/forms/__init__.py @@ -42,7 +42,7 @@ DEFAULT_SEARCHWND_HEIGHT = 100 DEFAULT_INPUTWINDOW_WIDTH = 500 DEFAULT_INPUTWINDOW_HEIGHT = 400 - +DEFAULT_RECOGNIZE_ACCESS_KEY = False WPF_HIDDEN = framework.Windows.Visibility.Hidden WPF_COLLAPSED = framework.Windows.Visibility.Collapsed @@ -71,7 +71,10 @@ class WPFWindow(framework.Windows.Window): Example: >>> from pyrevit import forms - >>> layout = '>> layout = '>> 'xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" ' \ + >>> 'xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" ' \ + >>> 'ShowInTaskbar="False" ResizeMode="NoResize" ' \ >>> 'WindowStartupLocation="CenterScreen" ' \ >>> 'HorizontalContentAlignment="Center">' \ >>> '' @@ -127,6 +130,9 @@ def __init__(self, xaml_source, literal_string=False, handle_esc=True): self.Resources['pyRevitButtonForgroundBrush'] = \ Media.SolidColorBrush(self.Resources['pyRevitButtonColor']) + self.Resources['pyRevitRecognizesAccessKey'] = \ + DEFAULT_RECOGNIZE_ACCESS_KEY + def handle_input_key(self, sender, args): #pylint: disable=W0613 """Handle keyboard input and close the window on Escape.""" if args.Key == Input.Key.Escape: @@ -277,8 +283,8 @@ def show(cls, context, #pylint: disable=W0221 Args: context (any): window context element(s) title (str): window title - width (str): window width - height (str): window height + width (int): window width + height (int): window height **kwargs (any): other arguments to be passed to window """ dlg = cls(context, title, width, height, **kwargs) @@ -638,6 +644,7 @@ class CommandSwitchWindow(TemplateUserInputWindow): switches (list[str]): list of on/off switches message (str): window title message config (dict): dictionary of config dicts for options or switches + recognize_access_key (bool): recognize '_' as mark of access key Returns: str: name of selected option @@ -665,7 +672,8 @@ class CommandSwitchWindow(TemplateUserInputWindow): ... ops, ... switches=switches ... message='Select Option', - ... config=cfgs + ... config=cfgs, + ... recognize_access_key=False ... ) >>> rops 'option2' @@ -690,6 +698,9 @@ def _setup(self, **kwargs): self.message_label.Content = \ message if message else 'Pick a command option:' + self.Resources['pyRevitRecognizesAccessKey'] = \ + kwargs.get('recognize_access_key', DEFAULT_RECOGNIZE_ACCESS_KEY) + # creates the switches first for switch, state in self._switches.items(): my_togglebutton = framework.Controls.Primitives.ToggleButton() diff --git a/pyrevitlib/pyrevit/labs.py b/pyrevitlib/pyrevit/labs.py index 907423d0d..d666616c5 100644 --- a/pyrevitlib/pyrevit/labs.py +++ b/pyrevitlib/pyrevit/labs.py @@ -10,9 +10,9 @@ # try loading pyrevitlabs clr.AddReference('Nett') -clr.AddReference('Nlog') clr.AddReference('MadMilkman.Ini') clr.AddReference('OpenMcdf') +clr.AddReference('pyRevitLabs.NLog') clr.AddReference('pyRevitLabs.MahAppsMetro') clr.AddReference('pyRevitLabs.Common') clr.AddReference('pyRevitLabs.CommonCLI') @@ -21,7 +21,7 @@ clr.AddReference('pyRevitLabs.DeffrelDB') clr.AddReference('pyRevitLabs.TargetApps.Revit') import Nett -import NLog +import pyRevitLabs.NLog as NLog import MadMilkman.Ini import OpenMcdf import pyRevitLabs.MahAppsMetro @@ -78,7 +78,7 @@ def convert_level(self, nlog_level): target = PyRevitOutputTarget() target.Name = __name__ target.Layout = "${level:uppercase=true}: [${logger}] ${message}" - config.AddTarget(target) + config.AddTarget(__name__, target) config.AddRuleForAllLevels(target) NLog.LogManager.Configuration = config diff --git a/pyrevitlib/pyrevit/loader/basetypes/baseclasses.cs b/pyrevitlib/pyrevit/loader/basetypes/baseclasses.cs index 37488ca7e..8e44ff80f 100644 --- a/pyrevitlib/pyrevit/loader/basetypes/baseclasses.cs +++ b/pyrevitlib/pyrevit/loader/basetypes/baseclasses.cs @@ -272,85 +272,112 @@ public Result Execute(ExternalCommandData commandData, ref string message, Eleme public abstract class PyRevitCommandExtendedAvail : IExternalCommandAvailability { - private string originalContextString; - private bool selectionRequired = false; // is any selection required? - private HashSet activeViewTypes = new HashSet(); // list of acceptable view types - private string _contextCatNameCompareString = null; // category comparison string (e.g. wallsdoors) + // category name separator for comparisons + const string SEP = "|"; + + // is any selection required? + private bool selectionRequired = false; + + // list of acceptable view types + private HashSet _activeViewTypes = new HashSet(); + + // category comparison string (e.g. wallsdoors) + private string _contextCatNameHash = null; + // builtin category comparison list + private HashSet _contextCatIdsHash = new HashSet(); public PyRevitCommandExtendedAvail(string contextString) { - // keep a backup - originalContextString = contextString; + // NOTE: + // docs have builtin categories + // docs might have custom categories with non-english names + // the compare mechanism is providing methods to cover both conditions + // compare mechanism stores integer ids for builtin categories + // compare mechanism stores strings for custom category names + // avail methods don't have access to doc object so the category names must be stored as string // get the tokens out of the string (it could only have one token) + // contextString in a ;-separated list of tokens List contextTokens = new List(); - foreach (string catName in contextString.Split(';')) - contextTokens.Add(catName.ToLower()); - - // go thru the tokens and extract the custom (non-element-category) tokens - List contextTokensCopy = new List(contextTokens); - foreach (string token in contextTokensCopy) { + foreach (string contextToken in contextString.Split(';')) + contextTokens.Add(contextToken.ToLower()); + // keep them sorted for comparison + contextTokens.Sort(); + + // first process the tokens for custom directives + // remove processed tokens and move to next step + foreach (string token in new List(contextTokens)) { switch (token.ToLower()) { + // selection token requires selected elements case "selection": selectionRequired = true; contextTokens.Remove(token); break; + // active-* tokens require a certain type of active view case "active-drafting-view": - activeViewTypes.Add(ViewType.DraftingView); + _activeViewTypes.Add(ViewType.DraftingView); contextTokens.Remove(token); break; case "active-detail-view": - activeViewTypes.Add(ViewType.Detail); + _activeViewTypes.Add(ViewType.Detail); contextTokens.Remove(token); break; case "active-plan-view": - activeViewTypes.Add(ViewType.FloorPlan); - activeViewTypes.Add(ViewType.CeilingPlan); - activeViewTypes.Add(ViewType.AreaPlan); - activeViewTypes.Add(ViewType.EngineeringPlan); + _activeViewTypes.Add(ViewType.FloorPlan); + _activeViewTypes.Add(ViewType.CeilingPlan); + _activeViewTypes.Add(ViewType.AreaPlan); + _activeViewTypes.Add(ViewType.EngineeringPlan); contextTokens.Remove(token); break; case "active-floor-plan": - activeViewTypes.Add(ViewType.FloorPlan); + _activeViewTypes.Add(ViewType.FloorPlan); contextTokens.Remove(token); break; case "active-rcp-plan": - activeViewTypes.Add(ViewType.CeilingPlan); + _activeViewTypes.Add(ViewType.CeilingPlan); contextTokens.Remove(token); break; case "active-structural-plan": - activeViewTypes.Add(ViewType.EngineeringPlan); + _activeViewTypes.Add(ViewType.EngineeringPlan); contextTokens.Remove(token); break; case "active-area-plan": - activeViewTypes.Add(ViewType.AreaPlan); + _activeViewTypes.Add(ViewType.AreaPlan); contextTokens.Remove(token); break; case "active-elevation-view": - activeViewTypes.Add(ViewType.Elevation); + _activeViewTypes.Add(ViewType.Elevation); contextTokens.Remove(token); break; case "active-section-view": - activeViewTypes.Add(ViewType.Section); + _activeViewTypes.Add(ViewType.Section); contextTokens.Remove(token); break; case "active-3d-view": - activeViewTypes.Add(ViewType.ThreeD); + _activeViewTypes.Add(ViewType.ThreeD); contextTokens.Remove(token); break; case "active-sheet": - activeViewTypes.Add(ViewType.DrawingSheet); + _activeViewTypes.Add(ViewType.DrawingSheet); contextTokens.Remove(token); break; case "active-legend": - activeViewTypes.Add(ViewType.Legend); + _activeViewTypes.Add(ViewType.Legend); contextTokens.Remove(token); break; case "active-schedule": - activeViewTypes.Add(ViewType.PanelSchedule); - activeViewTypes.Add(ViewType.ColumnSchedule); - activeViewTypes.Add(ViewType.Schedule); + _activeViewTypes.Add(ViewType.PanelSchedule); + _activeViewTypes.Add(ViewType.ColumnSchedule); + _activeViewTypes.Add(ViewType.Schedule); contextTokens.Remove(token); break; case "active-panel-schedule": - activeViewTypes.Add(ViewType.PanelSchedule); + _activeViewTypes.Add(ViewType.PanelSchedule); contextTokens.Remove(token); break; case "active-column-schedule": - activeViewTypes.Add(ViewType.ColumnSchedule); + _activeViewTypes.Add(ViewType.ColumnSchedule); contextTokens.Remove(token); break; } } - // assume that the remaining tokens are category names and create a comparison string - if (contextTokens.Count > 0) { - contextTokens.Sort(); - _contextCatNameCompareString = string.Join("", contextTokens); + // first pass processed and removed the processed tokens + // second, process tokens for builtin categories + // if any tokens left + foreach (string token in new List(contextTokens)) { + BuiltInCategory bic = BuiltInCategory.INVALID; + if (Enum.TryParse(token, true, out bic) && bic != 0 && bic != BuiltInCategory.INVALID) { + _contextCatIdsHash.Add((int)bic); + contextTokens.Remove(token); + } } + + // assume that the remaining tokens are category names and create a comparison string + _contextCatNameHash = string.Join(SEP, contextTokens); } public bool IsCommandAvailable(UIApplication uiApp, CategorySet selectedCategories) { @@ -358,35 +385,65 @@ public bool IsCommandAvailable(UIApplication uiApp, CategorySet selectedCategori if (selectionRequired && selectedCategories.IsEmpty) return false; - // check active views - if (activeViewTypes.Count > 0) { - if (uiApp != null && uiApp.ActiveUIDocument != null - && !activeViewTypes.Contains(uiApp.ActiveUIDocument.ActiveGraphicalView.ViewType)) - return false; - } + try { + // check active views + if (_activeViewTypes.Count > 0) { + if (uiApp != null && uiApp.ActiveUIDocument != null + && !_activeViewTypes.Contains(uiApp.ActiveUIDocument.ActiveGraphicalView.ViewType)) + return false; + } - // check element categories - if (_contextCatNameCompareString != null) { + // the rest are category comparisons so if no categories are selected return false if (selectedCategories.IsEmpty) return false; - try { - var selectedCategoryNames = new List(); - foreach (Category rvt_cat in selectedCategories) - selectedCategoryNames.Add(rvt_cat.Name.ToLower()); - - selectedCategoryNames.Sort(); - string selectedCatNameCompareString = string.Join("", selectedCategoryNames); - - if (selectedCatNameCompareString != _contextCatNameCompareString) + // make a hash of selected category ids + var selectedCatIdsHash = new HashSet(); + foreach (Category rvt_cat in selectedCategories) + selectedCatIdsHash.Add(rvt_cat.Id.IntegerValue); + + // make a hash of selected category names + var selectedCategoryNames = new List(); + foreach (Category rvt_cat in selectedCategories) + selectedCategoryNames.Add(rvt_cat.Name.ToLower()); + selectedCategoryNames.Sort(); + string selectedCatNameHash = string.Join(SEP, selectedCategoryNames); + + // user might have added a combination of category names and builtin categories + // test each possibility + // if both builtin categories and category names are specified + if (_contextCatIdsHash.Count > 0 && _contextCatNameHash != null) { + // test select inclusion in context (test selected is not bigger than context) + foreach(Category rvt_cat in selectedCategories) { + if (!_contextCatIdsHash.Contains(rvt_cat.Id.IntegerValue) + && !_contextCatNameHash.Contains(rvt_cat.Name.ToLower())) + return false; + } + + // test context inclusion in selected (test context is not bigger than selected) + foreach (int catId in _contextCatIdsHash) + if (!selectedCatIdsHash.Contains(catId)) + return false; + foreach (string catName in _contextCatNameHash.Split(SEP.ToCharArray())) + if (!selectedCatNameHash.Contains(catName)) + return false; + } + // if only builtin categories + else if (_contextCatIdsHash.Count > 0 && _contextCatNameHash == null) { + if (!_contextCatIdsHash.SetEquals(selectedCatIdsHash)) return false; } - catch (Exception) { - return false; + // if only category names + else if (_contextCatIdsHash.Count == 0 && _contextCatNameHash != null) { + if (selectedCatNameHash != _contextCatNameHash) + return false; } - } - return true; + return true; + } + // say no if any errors occured, otherwise Revit will not call this method again if exceptions + // are bubbled up + catch { return false; } } } diff --git a/pyrevitlib/pyrevit/revit/db/query.py b/pyrevitlib/pyrevit/revit/db/query.py index 89fbcc5cc..c713d31ea 100644 --- a/pyrevitlib/pyrevit/revit/db/query.py +++ b/pyrevitlib/pyrevit/revit/db/query.py @@ -36,19 +36,28 @@ DB.ViewType.PanelSchedule, DB.ViewType.Walkthrough, DB.ViewType.Rendering - ] +] -DETAIL_CURVES = (DB.DetailLine, - DB.DetailArc, - DB.DetailEllipse, - DB.DetailNurbSpline) +DETAIL_CURVES = ( + DB.DetailLine, + DB.DetailArc, + DB.DetailEllipse, + DB.DetailNurbSpline +) -MODEL_CURVES = (DB.ModelLine, - DB.ModelArc, - DB.ModelEllipse, - DB.ModelNurbSpline) +MODEL_CURVES = ( + DB.ModelLine, + DB.ModelArc, + DB.ModelEllipse, + DB.ModelNurbSpline +) +BUILTINCATEGORIES_VIEW = [ + DB.BuiltInCategory.OST_Views, + DB.BuiltInCategory.OST_ReferenceViewer, + DB.BuiltInCategory.OST_Viewers +] GridPoint = namedtuple('GridPoint', ['point', 'grids']) @@ -596,7 +605,7 @@ def get_all_referencing_elements(doc=None): .ToElements(): if el.Category \ and isinstance(el, DB.Element) \ - and str(el.Category.Name).startswith('View'): + and get_builtincategory(el.Category) in BUILTINCATEGORIES_VIEW: all_referencing_elements.append(el.Id) return all_referencing_elements @@ -608,7 +617,7 @@ def get_all_referencing_elements_in_view(view): .ToElements(): if el.Category \ and isinstance(el, DB.Element) \ - and str(el.Category.Name).startswith('View'): + and get_builtincategory(el.Category) in BUILTINCATEGORIES_VIEW: all_referencing_elements_in_view.append(el.Id) return all_referencing_elements_in_view diff --git a/pyrevitlib/pyrevit/version b/pyrevitlib/pyrevit/version index 0338bc0dc..3557e79a1 100644 --- a/pyrevitlib/pyrevit/version +++ b/pyrevitlib/pyrevit/version @@ -1 +1 @@ -4.6.23 \ No newline at end of file +4.6.24 \ No newline at end of file diff --git a/release/pyRevit CLI.aip b/release/pyRevit CLI.aip index 0b6c1b4d3..1f0cccace 100644 --- a/release/pyRevit CLI.aip +++ b/release/pyRevit CLI.aip @@ -22,10 +22,10 @@ - + - + @@ -56,7 +56,7 @@ - + @@ -80,6 +80,7 @@ + @@ -91,7 +92,7 @@ - + @@ -116,6 +117,7 @@ + @@ -125,7 +127,7 @@ - + diff --git a/release/pyRevit.aip b/release/pyRevit.aip index 83135e67d..7d5cce5f2 100644 --- a/release/pyRevit.aip +++ b/release/pyRevit.aip @@ -28,10 +28,10 @@ - + - + @@ -127,9 +127,9 @@ - + @@ -448,7 +448,7 @@ - + @@ -833,6 +833,7 @@ + @@ -866,6 +867,7 @@ + @@ -884,7 +886,6 @@ - @@ -910,7 +911,7 @@ - + @@ -1751,7 +1752,7 @@ - + @@ -5188,26 +5189,19 @@ + - - - - - - - - + + + + - - - - - - - - + + + + @@ -5336,8 +5330,7 @@ - - + @@ -5477,6 +5470,7 @@ +