From f0e5133be4f585876206aec8b3eed17edb0e7ec1 Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Mon, 11 Feb 2019 17:09:14 -0800 Subject: [PATCH 01/20] Fixed about window sizing --- .../pyRevit.tab/pyRevit.panel/About.pushbutton/AboutWindow.xaml | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/About.pushbutton/AboutWindow.xaml b/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/About.pushbutton/AboutWindow.xaml index 460c9fd38..4e2af0117 100644 --- a/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/About.pushbutton/AboutWindow.xaml +++ b/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/About.pushbutton/AboutWindow.xaml @@ -3,6 +3,7 @@ Title="MainWindow" Foreground="#000" Height="325" Width="690" Margin="0" + SizeToContent="Width" ShowInTaskbar="False" BorderThickness="0" Background="{x:Null}" From 7f6034d106c4cb7568d6079dd26079fc2c6fad4b Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Tue, 12 Feb 2019 09:33:17 -0800 Subject: [PATCH 02/20] Improved tooltip re issue #520 --- .../script.py | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) 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 d6eaee16d..f1034866c 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 @@ -1,13 +1,20 @@ """Print sheets in order from a sheet index. -Shift-Click: +Note: When using the `Combine into one file` option, -the tool adds invisible characters at the start of -the sheet names to push Revit's interenal printing -engine to sort the sheets correctly per the drawing -index order. Shift-Clicking the tool will remove all -these characters from the sheet numbers, in case an error -in the tool causes these characters to remain. +the tool adds non-printable character u'\u200e' +(Left-To-Right Mark) at the start of the sheet names +to push Revit's interenal printing engine to sort +the sheets correctly per the drawing index order. + +Make sure your drawings indices consider this +when filtering for sheet numbers. + +Shift-Click: +Shift-Clicking the tool will remove all +non-printable characters from the sheet numbers, +in case an error in the tool causes these characters +to remain. """ import os.path as op From 6e4bbe31808154288241cec067548a120c965092 Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Thu, 14 Feb 2019 13:13:47 -0800 Subject: [PATCH 03/20] Improvement re issue #513 --- .../pyRevit.panel/tools.stack3/Search.pushbutton/script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/tools.stack3/Search.pushbutton/script.py b/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/tools.stack3/Search.pushbutton/script.py index 308483f3f..ed38df390 100644 --- a/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/tools.stack3/Search.pushbutton/script.py +++ b/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/tools.stack3/Search.pushbutton/script.py @@ -160,7 +160,7 @@ def open_in_editor(editor_name, selected_cmd, altsrc=False): NP_SWITCH, CONFIG_SWITCH, ALT_FLAG], - search_tip='pyRevit Search') + search_tip='type to search') logger.debug('matched command: {}'.format(matched_cmdname)) logger.debug('arguments: {}'.format(matched_cmdargs)) From 351afcb8e839316492e3eb5f27cfe817b442d1e5 Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Wed, 20 Feb 2019 15:30:52 -0800 Subject: [PATCH 04/20] Added log message to report selected material name --- .../Match.splitpushbutton/Match Paint.pushbutton/script.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/Match.splitpushbutton/Match Paint.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/Match.splitpushbutton/Match Paint.pushbutton/script.py index 830bca529..c43b173d2 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/Match.splitpushbutton/Match Paint.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Modify.panel/Match.splitpushbutton/Match Paint.pushbutton/script.py @@ -2,7 +2,9 @@ #pylint: disable=E0401,C0111,W0613,C0103,broad-except from pyrevit import revit, UI from pyrevit import forms +from pyrevit import script +logger = script.get_logger() with forms.WarningBar(title='Pick source object:'): source_face = revit.pick_face() @@ -12,6 +14,8 @@ material_id = source_face.MaterialElementId material = revit.doc.GetElement(material_id) + logger.debug('Selected material id:%s name:%s', material.Id, material.Name) + with forms.WarningBar(title='Pick faces to match materials:'): while True: try: From 472f457224238578b90396ae761475ea2cc4ba04 Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Wed, 20 Feb 2019 16:50:29 -0800 Subject: [PATCH 05/20] Edited keynote manager to be smarter about reloads --- .../Keynotes.pushbutton/script.py | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py index 43efce722..15c909fe4 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py @@ -384,6 +384,7 @@ def __init__(self, xaml_file_name): locked=False, owner='', children=None) + self._needs_update = False self._config = script.get_config() self._used_keysdict = self.get_used_keynote_elements() self.load_config() @@ -694,6 +695,8 @@ def add_category(self, sender, args): kdb.EDIT_MODE_ADD_CATEG).show() if new_cat: self.selected_category = new_cat.key + # make sure to relaod on close + self._needs_update = True except System.TimeoutException as toutex: forms.alert(toutex.Message) except Exception as ex: @@ -715,6 +718,8 @@ def edit_category(self, sender, args): EditRecordWindow(self, self._conn, kdb.EDIT_MODE_EDIT_CATEG, rkeynote=selected_category).show() + # make sure to relaod on close + self._needs_update = True except System.TimeoutException as toutex: forms.alert(toutex.Message) except Exception as ex: @@ -743,6 +748,8 @@ def remove_category(self, sender, args): yes=True, no=True): try: kdb.remove_category(self._conn, selected_category.key) + # make sure to relaod on close + self._needs_update = True except System.TimeoutException as toutex: forms.alert(toutex.Message) except Exception as ex: @@ -771,6 +778,8 @@ def add_keynote(self, sender, args): EditRecordWindow(self, self._conn, kdb.EDIT_MODE_ADD_KEYNOTE, pkey=parent_key).show() + # make sure to relaod on close + self._needs_update = True except System.TimeoutException as toutex: forms.alert(toutex.Message) except Exception as ex: @@ -785,6 +794,8 @@ def add_sub_keynote(self, sender, args): EditRecordWindow(self, self._conn, kdb.EDIT_MODE_ADD_KEYNOTE, pkey=selected_keynote.key).show() + # make sure to relaod on close + self._needs_update = True except System.TimeoutException as toutex: forms.alert(toutex.Message) except Exception as ex: @@ -801,6 +812,8 @@ def duplicate_keynote(self, sender, args): kdb.EDIT_MODE_ADD_KEYNOTE, text=self.selected_keynote.text, pkey=self.selected_keynote.parent_key).show() + # make sure to relaod on close + self._needs_update = True except System.TimeoutException as toutex: forms.alert(toutex.Message) except Exception as ex: @@ -826,6 +839,8 @@ def remove_keynote(self, sender, args): yes=True, no=True): try: kdb.remove_keynote(self._conn, selected_keynote.key) + # make sure to relaod on close + self._needs_update = True except System.TimeoutException as toutex: forms.alert(toutex.Message) except Exception as ex: @@ -841,6 +856,8 @@ def edit_keynote(self, sender, args): self._conn, kdb.EDIT_MODE_EDIT_KEYNOTE, rkeynote=self.selected_keynote).show() + # make sure to relaod on close + self._needs_update = True except System.TimeoutException as toutex: forms.alert(toutex.Message) except Exception as ex: @@ -901,6 +918,8 @@ def show_keynote_history(self, sender, args): def change_keynote_file(self, sender, args): self._change_kfile() + # make sure to relaod on close + self._needs_update = True self.Close() def show_keynote_file(self, sender, args): @@ -948,13 +967,13 @@ def export_visible_keynotes(self, sender, args): except System.TimeoutException as toutex: forms.alert(toutex.Message) - def update_model(self, sender, args): self.Close() def window_closing(self, sender, args): - with revit.Transaction('Update Keynotes'): - revit.update.update_linked_keynotes(doc=revit.doc) + if self._needs_update: + with revit.Transaction('Update Keynotes'): + revit.update.update_linked_keynotes(doc=revit.doc) try: self.save_config() From 0b4a34bd409ffd130806d0a9a1aaa0a7fd780ca0 Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Wed, 20 Feb 2019 17:15:46 -0800 Subject: [PATCH 06/20] Added support for regex keynote search --- .../Keynotes.pushbutton/keynotesdb.py | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/keynotesdb.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/keynotesdb.py index f8dae455c..a77e3e805 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/keynotesdb.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/keynotesdb.py @@ -1,5 +1,6 @@ """Module for managing keynotes using DeffrelDB.""" #pylint: disable=E0401,W0613 +import re import codecs from collections import namedtuple, defaultdict @@ -39,6 +40,7 @@ RKeynoteFilter = namedtuple('RKeynoteFilter', ['name', 'code']) + class RKeynoteFilters(object): """Custom filters for filtering keynotes.""" @@ -46,6 +48,8 @@ class RKeynoteFilters(object): UnusedOnly = RKeynoteFilter(name="Unused Only", code=":unused:") LockedOnly = RKeynoteFilter(name="Locked Only", code=":locked:") UnlockedOnly = RKeynoteFilter(name="Unlocked Only", code=":unlocked:") + UseRegex = RKeynoteFilter(name="Use Regular Expressions (Regex)", + code=":regex:") @classmethod def get_available_filters(cls): @@ -53,7 +57,9 @@ def get_available_filters(cls): return [cls.UsedOnly, cls.UnusedOnly, cls.LockedOnly, - cls.UnlockedOnly,] + cls.UnlockedOnly, + cls.UseRegex + ] @classmethod def remove_filters(cls, source_string): @@ -100,6 +106,10 @@ def children(self): def filter(self, search_term): self._filter = search_term.lower() + + # use regex for string matching? + use_regex = RKeynoteFilters.UseRegex.code in self._filter + self_pass = False if RKeynoteFilters.UsedOnly.code in self._filter: self_pass = self.used @@ -117,15 +127,28 @@ def filter(self, search_term): has_smart_filter = cleaned_sfilter != self._filter if cleaned_sfilter: - sterm = self.key +' '+ self.text +' '+ self.owner + sterm = self.key + ' ' + self.text + ' ' + self.owner + sterm = sterm.lower() + # here is where matching against the string happens - self_pass_keyword = \ - coreutils.fuzzy_search_ratio(sterm.lower(), - cleaned_sfilter) > 80 - if has_smart_filter: - self_pass = self_pass_keyword and self_pass + if use_regex: + # check if pattern is valid + try: + self_pass = re.search( + cleaned_sfilter, + sterm, + re.IGNORECASE + ) + except Exception: + self_pass = False else: - self_pass = self_pass_keyword + self_pass_keyword = \ + coreutils.fuzzy_search_ratio(sterm, cleaned_sfilter) > 80 + + if has_smart_filter: + self_pass = self_pass_keyword and self_pass + else: + self_pass = self_pass_keyword # filter children now self._filtered_children = \ From c58f1f1eb32a16c37ce17da7730083dea639d906 Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Thu, 21 Feb 2019 08:51:43 -0800 Subject: [PATCH 07/20] Resolved issue #522 --- .../Keynotes.pushbutton/script.py | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py index 15c909fe4..9b7eb0eb2 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py @@ -677,10 +677,17 @@ def selected_category_changed(self, sender, args): def selected_keynote_changed(self, sender, args): logger.debug('New keynote selected: %s', self.selected_keynote) - if self.selected_keynote and not self.selected_keynote.locked: - self.keynoteEditButtons.IsEnabled = True + if self.selected_keynote \ + and not self.selected_keynote.locked: + if self.selected_keynote.parent_key: + self.catEditButtons.IsEnabled = False + self.keynoteEditButtons.IsEnabled = True + else: + self.catEditButtons.IsEnabled = True + self.keynoteEditButtons.IsEnabled = False else: self.keynoteEditButtons.IsEnabled = False + self.catEditButtons.IsEnabled = False def refresh(self, sender, args): if self._conn: @@ -704,20 +711,28 @@ def add_category(self, sender, args): def edit_category(self, sender, args): selected_category = self.selected_category + selected_keynote = self.selected_keynote + # determine where the category is coming from + # selected category in drop-down if selected_category: - if selected_category.locked: + target_keynote = selected_category + # or selected category in keynotes list + elif selected_keynote and not selected_keynote.parent_key: + target_keynote = selected_keynote + if target_keynote: + if target_keynote.locked: forms.alert('Category is locked and is being edited by {}. ' 'Wait until their changes are committed. ' 'Meanwhile you can use or modify the keynotes ' 'under this category.' - .format('\"%s\"' % selected_category.owner - if selected_category.owner + .format('\"%s\"' % target_keynote.owner + if target_keynote.owner else 'and unknown user')) else: try: EditRecordWindow(self, self._conn, kdb.EDIT_MODE_EDIT_CATEG, - rkeynote=selected_category).show() + rkeynote=target_keynote).show() # make sure to relaod on close self._needs_update = True except System.TimeoutException as toutex: @@ -726,6 +741,8 @@ def edit_category(self, sender, args): forms.alert(str(ex)) finally: self._update_ktree() + if selected_keynote: + self._update_ktree_knotes() def rekey_category(self, sender, args): forms.alert("Not yet implemented. Coming soon.") From 836fdaebbfe9463761b90dc332747af8a43264ce Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Thu, 21 Feb 2019 08:51:57 -0800 Subject: [PATCH 08/20] Added option to select a different keynote file instead of convert --- .../Drawing Set.panel/Keynotes.pushbutton/script.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py index 9b7eb0eb2..1a0b0a6bd 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py @@ -355,7 +355,9 @@ def __init__(self, xaml_file_name): "with other projects. Users should NOT be making changes to " "the existing keynote file during the conversion process.\n" "Are you sure you want to convert?", - options=["Convert", "Give me more info"]) + options=["Convert", + "Select a different keynote file", + "Give me more info"]) if res: if res == "Convert": try: @@ -370,6 +372,8 @@ def __init__(self, xaml_file_name): logger.debug('Legacy conversion failed | %s' % convex) forms.alert("Conversion failed! %s" % convex, exitscript=True) + elif res == "Select a different keynote file": + self._change_kfile() elif res == "Give me more info": script.open_url('https://eirannejad.github.io/pyRevit') script.exit() From 82ac231c0b1c07bd813947e02ec380449e9370e9 Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Thu, 21 Feb 2019 09:03:23 -0800 Subject: [PATCH 09/20] Added line style query methods --- .../Spy.pulldown/List Elements.pushbutton/script.py | 11 +++++------ pyrevitlib/pyrevit/revit/db/query.py | 11 +++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) 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 5a77d157d..a278bda1a 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 @@ -82,12 +82,11 @@ print(i.Name) elif selected_switch == 'Line Styles': - c = revit.doc.Settings.Categories.get_Item(DB.BuiltInCategory.OST_Lines) - subcats = c.SubCategories - - for lineStyle in subcats: - print("STYLE NAME: {0} ID: {1}".format(lineStyle.Name.ljust(40), - lineStyle.Id.ToString())) + for lineStyle in revit.query.get_line_styles(doc=revit.doc): + print("STYLE NAME: {} ID: {} ({})".format( + lineStyle.Name.ljust(40), + lineStyle.Id.ToString(), + lineStyle)) elif selected_switch == 'Model / Detail / Sketch Lines': cat_list = List[DB.BuiltInCategory]([DB.BuiltInCategory.OST_Lines, diff --git a/pyrevitlib/pyrevit/revit/db/query.py b/pyrevitlib/pyrevit/revit/db/query.py index 8bbffd62b..83cc26b4d 100644 --- a/pyrevitlib/pyrevit/revit/db/query.py +++ b/pyrevitlib/pyrevit/revit/db/query.py @@ -1083,3 +1083,14 @@ def yield_unreferenced_views(doc=None, all_views=None): # if it has NO referring views, yield if len(list(yield_referring_views(view))) == 0: yield view.Id + + +def get_line_categories(doc=None): + doc = doc or HOST_APP.doc + lines_cat = doc.Settings.Categories.get_Item(DB.BuiltInCategory.OST_Lines) + return lines_cat.SubCategories + + +def get_line_styles(doc=None): + return [x.GetGraphicsStyle(DB.GraphicsStyleType.Projection) + for x in get_line_categories(doc=doc)] From 0767105b244546d06acebcb34e0116ac8899e7c8 Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Thu, 21 Feb 2019 11:20:19 -0800 Subject: [PATCH 10/20] Added index grouping option --- .../ReOrderWindow.xaml | 21 +++++++-- .../ReOrder Sheets.pushbutton/script.py | 47 ++++++++++++++++++- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/ReOrder Sheets.pushbutton/ReOrderWindow.xaml b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/ReOrder Sheets.pushbutton/ReOrderWindow.xaml index 4b1a574c0..fdf778eff 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/ReOrder Sheets.pushbutton/ReOrderWindow.xaml +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/ReOrder Sheets.pushbutton/ReOrderWindow.xaml @@ -15,7 +15,7 @@ - + - + + + + Usage: Enter a regular expression pattern in this box. This pattern is used to detect changes in + Sheet Numbers and group indices. For example, to group using the discipline identifier in + Sheet Number (A in A1.00), use "([A-Z])\d". The () in pattern select the discipline identifier as a group + which is used to group sheet ranges. + + See Regexr on how to use Regular Expressions + + + + - List of the sheets (Drag to manually reorder): + List of the sheets (Drag to manually reorder) 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 9c8d88785..6a930eb95 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,5 +1,7 @@ """Print items in order from a sheet index.""" #pylint: disable=W0613,E0401,C0103 +import re + from pyrevit import forms from pyrevit import revit, DB from pyrevit import script @@ -25,8 +27,13 @@ class ReOrderWindow(forms.WPFWindow): def __init__(self, xaml_file_name): forms.WPFWindow.__init__(self, xaml_file_name) + self._config = script.get_config() + self._setup_item_params_combobox() + self.grouping_pattern = \ + self._config.get_option('index_grouping_pattern', r'([A-Z])\d') + @property def items_list(self): return self.items_dg.ItemsSource @@ -41,9 +48,38 @@ def items_list(self, value): def selected_item_param(self): return self.orderparams_cb.SelectedItem + @property + def grouping_pattern(self): + pattern = self.indexgroup_tb.Text + try: + re.compile(pattern) + return pattern + except Exception: + return "" + + @grouping_pattern.setter + def grouping_pattern(self, value): + self.indexgroup_tb.Text = value + def _update_order_indices(self): - for idx, item in enumerate(self.items_list): - item.order_index = idx + if self.grouping_pattern: + last_groupid = '' + grouping_index = 0 + grouping_range = 1000 + for idx, item in enumerate(self.items_list): + match = re.search(self.grouping_pattern, item.number) + if match and match.groups(): + groupid = match.groups()[0] + if groupid != last_groupid: + last_groupid = groupid + grouping_index += 1 + + item.order_index = (grouping_range * grouping_index) + idx + else: + item.order_index = idx + else: + for idx, item in enumerate(self.items_list): + item.order_index = idx def _setup_item_params_combobox(self): items = revit.query.get_sheets() @@ -99,6 +135,11 @@ def sorting_changed(self, sender, args): elif order_param == 'name': self.items_list = sorted(self.items_list, key=lambda x: x.name) + def grouping_pattern_changed(self, sender, args): + existing_items = self.items_list + self.items_list = [] + self.items_list = existing_items + def move_to_top(self, sender, args): selected, non_selected = self._get_selected_nonselected() new_list = self._insert_list_in_list(selected, non_selected, 0) @@ -137,6 +178,8 @@ def move_to_bottom(self, sender, args): def reorder_items(self, sender, args): self.Close() + self._config.set_option('index_grouping_pattern', + self.grouping_pattern) with revit.Transaction('Reorder Sheets'): for item in self.items_list: idx_param = \ From c1b4bc10b4b524e2d50b644eabe47917327f4aae Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Thu, 21 Feb 2019 11:44:28 -0800 Subject: [PATCH 11/20] Moved url handling to base window --- .../Extensions.smartbutton/ExtensionsWindow.xaml | 4 ++++ .../PrintOrderedSheets.xaml | 6 ++++++ .../Print Ordered Sheet Index.pushbutton/script.py | 3 --- .../ReOrder Sheets.pushbutton/ReOrderWindow.xaml | 2 +- pyrevitlib/pyrevit/forms/__init__.py | 5 +++++ 5 files changed, 16 insertions(+), 4 deletions(-) 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 e0f659e26..c09491ea5 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 @@ -10,6 +10,10 @@ + + diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Print.pulldown/Print Ordered Sheet Index.pushbutton/PrintOrderedSheets.xaml b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Print.pulldown/Print Ordered Sheet Index.pushbutton/PrintOrderedSheets.xaml index 1001de0be..41a395ea7 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Print.pulldown/Print Ordered Sheet Index.pushbutton/PrintOrderedSheets.xaml +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Print.pulldown/Print Ordered Sheet Index.pushbutton/PrintOrderedSheets.xaml @@ -22,6 +22,10 @@ + @@ -82,7 +86,9 @@ + Kudos to Ryan McCullough for PrintFromIndex + 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 f1034866c..092c25b6c 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 @@ -375,9 +375,6 @@ def print_sheets(self, sender, args): else: self._print_sheets_in_order() - def handle_url_click(self, sender, args): - script.open_url('https://github.com/McCulloughRT/PrintFromIndex') - def preview_mouse_down(self, sender, args): if isinstance(sender, Windows.Controls.ListViewItem): if sender.DataContext.printable: diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/ReOrder Sheets.pushbutton/ReOrderWindow.xaml b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/ReOrder Sheets.pushbutton/ReOrderWindow.xaml index fdf778eff..71a7ab9a6 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/ReOrder Sheets.pushbutton/ReOrderWindow.xaml +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/ReOrder Sheets.pushbutton/ReOrderWindow.xaml @@ -41,7 +41,7 @@ Sheet Numbers and group indices. For example, to group using the discipline identifier in Sheet Number (A in A1.00), use "([A-Z])\d". The () in pattern select the discipline identifier as a group which is used to group sheet ranges. - + See Regexr on how to use Regular Expressions diff --git a/pyrevitlib/pyrevit/forms/__init__.py b/pyrevitlib/pyrevit/forms/__init__.py index c7a2f78af..0103dd9f3 100644 --- a/pyrevitlib/pyrevit/forms/__init__.py +++ b/pyrevitlib/pyrevit/forms/__init__.py @@ -12,6 +12,7 @@ import threading from functools import wraps import datetime +import webbrowser from pyrevit import HOST_APP, EXEC_PARAMS, BIN_DIR from pyrevit.compat import safe_strtype @@ -210,6 +211,10 @@ def enable_element(*wpf_elements): for wpfel in wpf_elements: wpfel.IsEnabled = True + def handle_url_click(self, sender, args): + """Callback for handling click on package website url""" + return webbrowser.open_new_tab(sender.NavigateUri.AbsoluteUri) + class TemplateUserInputWindow(WPFWindow): """Base class for pyRevit user input standard forms. From bdfb5390204fb945657e851de42f15d1566b40af Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Thu, 21 Feb 2019 11:44:41 -0800 Subject: [PATCH 12/20] Reorder sheets housekeeping --- .../ReOrder Sheets.pushbutton/script.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 6a930eb95..bc494b273 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 @@ -32,7 +32,8 @@ def __init__(self, xaml_file_name): self._setup_item_params_combobox() self.grouping_pattern = \ - self._config.get_option('index_grouping_pattern', r'([A-Z])\d') + self._config.get_option('index_grouping_pattern', + r'([A-Z])\d') @property def items_list(self): @@ -61,6 +62,11 @@ def grouping_pattern(self): def grouping_pattern(self, value): self.indexgroup_tb.Text = value + def _refresh(self): + existing_items = self.items_list + self.items_list = [] + self.items_list = existing_items + def _update_order_indices(self): if self.grouping_pattern: last_groupid = '' @@ -136,9 +142,7 @@ def sorting_changed(self, sender, args): self.items_list = sorted(self.items_list, key=lambda x: x.name) def grouping_pattern_changed(self, sender, args): - existing_items = self.items_list - self.items_list = [] - self.items_list = existing_items + self._refresh() def move_to_top(self, sender, args): selected, non_selected = self._get_selected_nonselected() From c117fb40eb3ee76a59ae075e570d8a3601a2ae86 Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Thu, 21 Feb 2019 11:47:19 -0800 Subject: [PATCH 13/20] Removed url handler --- .../pyRevit.panel/Extensions.smartbutton/script.py | 5 ----- 1 file changed, 5 deletions(-) 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 578588d8c..f507df7ba 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 @@ -337,11 +337,6 @@ def update_ext_info(self, sender, args): else: self.hide_element(self.ext_infopanel) - def handle_url_click(self, sender, args): - """Callback for handling click on package website url - """ - script.open_url(sender.NavigateUri.AbsoluteUri) - def handle_private_repo(self, sender, args): """Callback for updating private status of a package """ From 9fa61a6366972f48987a8e129433fea88462a3da Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Thu, 21 Feb 2019 12:10:33 -0800 Subject: [PATCH 14/20] Added task kill --- pyrevitlib/pyrevit/coreutils/__init__.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pyrevitlib/pyrevit/coreutils/__init__.py b/pyrevitlib/pyrevit/coreutils/__init__.py index 3805c8852..de1fd2cca 100644 --- a/pyrevitlib/pyrevit/coreutils/__init__.py +++ b/pyrevitlib/pyrevit/coreutils/__init__.py @@ -1438,3 +1438,15 @@ def get_reg_key(key, subkey): return wr.OpenKey(key, subkey, 0, wr.KEY_READ) except Exception: return None + + +def kill_tasks(task_name): + """Kill running tasks matching task_name + + Args: + task_name (str): task name + + Example: + >>> kill_tasks('Revit.exe') + """ + os.system("taskkill /f /im %s" % task_name) \ No newline at end of file From ff0ba8a9b3535ecd5cb775f5221e1d1ae615bac9 Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Thu, 21 Feb 2019 15:12:30 -0800 Subject: [PATCH 15/20] Added last edited info to keynote finder --- .../Keynotes.pushbutton/script.py | 38 ++++++++++++------- .../Who Did That.pushbutton/script.py | 11 ++---- pyrevitlib/pyrevit/revit/db/query.py | 13 +++++++ 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py index 1a0b0a6bd..524c51491 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py @@ -892,19 +892,31 @@ def rekey_keynote(self, sender, args): def show_keynote(self, sender, args): if self.selected_keynote: self.Close() - for kkey, kids in self.get_used_keynote_elements().items(): - if kkey == self.selected_keynote.key: - for kid in kids: - source = viewname = '' - kel = revit.doc.GetElement(kid) - if kel: - source = kel.Parameter[ - DB.BuiltInParameter.KEY_SOURCE_PARAM].AsString() - vel = revit.doc.GetElement(kel.OwnerViewId) - if vel: - viewname = revit.query.get_name(vel) - print('{} \"{}\" Keynote @ \"{}\"' - .format(output.linkify(kid), source, viewname)) + kids = self.get_used_keynote_elements() \ + .get(self.selected_keynote.key, []) + for kid in kids: + source = viewname = '' + kel = revit.doc.GetElement(kid) + ehist = revit.query.get_history(kel) + if kel: + source = kel.Parameter[ + DB.BuiltInParameter.KEY_SOURCE_PARAM].AsString() + vel = revit.doc.GetElement(kel.OwnerViewId) + if vel: + viewname = revit.query.get_name(vel) + # prepare report + report = \ + '{} \"{}\" Keynote @ \"{}\"'.format( + output.linkify(kid), + source, + viewname + ) + + if ehist: + report += \ + ' - Last Edited By \"{}\"'.format(ehist.last_changed_by) + + print(report) def place_keynote(self, sender, args): self.Close() diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack3/Team.pulldown/Who Did That.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack3/Team.pulldown/Who Did That.pushbutton/script.py index 5d2b960eb..4fcfcd3c1 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack3/Team.pulldown/Who Did That.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack3/Team.pulldown/Who Did That.pushbutton/script.py @@ -50,16 +50,13 @@ def who_created_selection(): selection = revit.get_selection() if revit.doc.IsWorkshared: if selection and len(selection) == 1: - wti = DB.WorksharingUtils.GetWorksharingTooltipInfo( - revit.doc, - selection.first.Id - ) + eh = revit.query.get_history(selection.first) forms.alert('Creator: {0}\n' 'Current Owner: {1}\n' - 'Last Changed By: {2}'.format(wti.Creator, - wti.Owner, - wti.LastChangedBy)) + 'Last Changed By: {2}'.format(eh.creator, + eh.owner, + eh.last_changed_by)) else: forms.alert('Exactly one element must be selected.') else: diff --git a/pyrevitlib/pyrevit/revit/db/query.py b/pyrevitlib/pyrevit/revit/db/query.py index 83cc26b4d..a98143f84 100644 --- a/pyrevitlib/pyrevit/revit/db/query.py +++ b/pyrevitlib/pyrevit/revit/db/query.py @@ -45,6 +45,9 @@ ['sheet_num', 'sheet_name', 'detail_num', 'ref_viewid']) +ElementHistory = namedtuple('ElementHistory', + ['creator', 'owner', 'last_changed_by']) + def get_name(element, title_on_sheet=False): # grab viewname correctly @@ -1094,3 +1097,13 @@ def get_line_categories(doc=None): def get_line_styles(doc=None): return [x.GetGraphicsStyle(DB.GraphicsStyleType.Projection) for x in get_line_categories(doc=doc)] + + +def get_history(target_element): + doc = target_element.Document + if doc.IsWorkshared: + wti = DB.WorksharingUtils.GetWorksharingTooltipInfo(doc, + target_element.Id) + return ElementHistory(creator=wti.Creator, + owner=wti.Owner, + last_changed_by=wti.LastChangedBy) From da4d6fe8dcce5cf6fa449a1da74caa46b8f0d611 Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Thu, 21 Feb 2019 15:56:14 -0800 Subject: [PATCH 16/20] Added tool to help batch selecting sheets for editing --- .../Sheets.pulldown/Select Sheets.pushbutton/script.py | 10 ++++++++++ .../Drawing Set.panel/Sheets.pulldown/_layout | 1 + 2 files changed, 11 insertions(+) create mode 100644 extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Select Sheets.pushbutton/script.py diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Select Sheets.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Select Sheets.pushbutton/script.py new file mode 100644 index 000000000..9a3d82121 --- /dev/null +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/Select Sheets.pushbutton/script.py @@ -0,0 +1,10 @@ +"""Change the selected sheet names.""" +#pylint: disable=import-error,invalid-name +from pyrevit import revit +from pyrevit import forms + +selection = revit.get_selection() +sel_sheets = forms.select_sheets(title='Select Sheets') + +if sel_sheets: + selection.set_to(sel_sheets) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/_layout b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/_layout index d2dc06df4..904833afa 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/_layout +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Sheets.pulldown/_layout @@ -6,6 +6,7 @@ Reorder Selected Viewport Copy Sheets to Open Documents Batch Sheet Maker ----- +Select Sheets Rename Selected Sheets Select TitleBlocks on Sheets Set Crop Region To Selected Shape From b07144558b5dd8b8d9a0d4f83ed06c9b4631dbcc Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Sun, 24 Feb 2019 19:16:10 -0800 Subject: [PATCH 17/20] Fixed issue with showing loaded keynotes on first run with no cfg --- .../Drawing Set.panel/Keynotes.pushbutton/script.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py index 524c51491..cb1abb166 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/script.py @@ -381,7 +381,6 @@ def __init__(self, xaml_file_name): forms.alert("Keynote file is not yet converted.", exitscript=True) - self._cache = [] self._allcat = kdb.RKeynote(key='', text='-- ALL CATEGORIES --', parent_key='', @@ -548,11 +547,15 @@ def load_config(self): last_category_dict = self._config.get_option('last_category', {}) if last_category_dict and self._kfile in last_category_dict: self._update_ktree(active_catkey=last_category_dict[self._kfile]) + else: + self.selected_category = self._allcat # load last search term last_searchterm_dict = self._config.get_option('last_search_term', {}) if last_searchterm_dict and self._kfile in last_searchterm_dict: self.search_term = last_searchterm_dict[self._kfile] + else: + self.search_term = "" def _convert_existing(self): # make a copy of exsing From 05c37bb52f3dd31d5e8ba2cf57d14ba71b3046db Mon Sep 17 00:00:00 2001 From: Ehsan Iran-Nejad Date: Sun, 24 Feb 2019 19:23:28 -0800 Subject: [PATCH 18/20] Implemented item 1 of issue #529 --- .../Keynotes.pushbutton/KeynoteManagerWindow.xaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/KeynoteManagerWindow.xaml b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/KeynoteManagerWindow.xaml index 0bdcaad1a..2a2c50b59 100644 --- a/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/KeynoteManagerWindow.xaml +++ b/extensions/pyRevitTools.extension/pyRevit.tab/Drawing Set.panel/Keynotes.pushbutton/KeynoteManagerWindow.xaml @@ -150,8 +150,8 @@