Skip to content

Commit

Permalink
Sync Views bugfix, Copy State improvements (#927)
Browse files Browse the repository at this point in the history
* Fix CopyState - ViewZoomPanState

* Fix SyncViews (revit.serialize)

* Paste State script - show only actions with data

* Copy State - allow to copy between projects

* PasteState script - small fixes

* Copy Filter Overrides - support active view, fixes

* PasteState - View template fix

Co-authored-by: Ehsan Iran-Nejad <eirannejad@gmail.com>
  • Loading branch information
melnikovalex and eirannejad authored Jun 28, 2020
1 parent 12ecea9 commit dfb63a0
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Show additional options
"""
from pyrevit import PyRevitException
from pyrevit import forms
from pyrevit import forms, script

import copypastestate

Expand All @@ -16,21 +16,31 @@

# collect actions that are valid in this context
available_actions = [
x for x in copypastestate.get_actions() if x.validate_context()
x for x in copypastestate.get_actions()
if x.validate_context() and script.data_exists(x.__name__,
this_project=x.this_project)
]

if available_actions:
action_options = {x.name: x for x in available_actions}
selected_action = \
forms.CommandSwitchWindow.show(
action_options.keys(),
message='Select property to be pasted:',
name_attr='name'
)

if selected_action:
action = action_options[selected_action]
try:
action().paste()
except PyRevitException as ex:
forms.alert(ex.msg)
if len(available_actions) > 1:
action_options = {x.name: x for x in available_actions}
selected_action = \
forms.CommandSwitchWindow.show(
action_options.keys(),
message='Select property to be pasted:',
name_attr='name'
)
if selected_action:
action = action_options[selected_action]
else:
script.exit()
else:
action = available_actions[0]

try:
action().paste()
except PyRevitException as ex:
forms.alert(ex.msg)
else:
forms.alert('No available actions for this view or no saved'
' data found. Use "Copy State" first.')
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def dir_orient(self):
class ViewZoomPanStateAction(basetypes.CopyPasteStateAction):
name = 'View Zoom/Pan State'
invalid_context_msg = "Type of active view is not supported"
this_project = False

def copy(self):
active_view = revit.active_view
Expand All @@ -60,19 +61,21 @@ def copy(self):
view_type=active_view.ViewType,
corner_pts=active_ui_view.GetZoomCorners(),
dir_orient=dir_orient
)
),
this_project=False
)

def paste(self):
# load data
vzps_data = script.load_data(slot_name=self.__class__.__name__)
vzps_data = script.load_data(slot_name=self.__class__.__name__,
this_project=False)

view_type = vzps_data.view_type
vc1, vc2 = vzps_data.corner_pts
dir_orient = vzps_data.dir_orient

active_ui_view = revit.uidoc.GetOpenUIViews()[0]
if revit.active_view.ViewType == view_type:
if revit.active_view.ViewType != view_type:
raise PyRevitException(
'Saved view type (%s) is different from active view (%s)'
% (vzps_data.view_type, type(revit.active_view).__name__))
Expand Down Expand Up @@ -124,6 +127,7 @@ class SectionBox3DStateAction(basetypes.CopyPasteStateAction):
name = '3D Section Box State'
invalid_context_msg = \
"You must be on a 3D view to copy and paste 3D section box."
this_project = False

def copy(self):
section_box = revit.active_view.GetSectionBox()
Expand All @@ -134,11 +138,13 @@ def copy(self):
data=SectionBox3DStateData(
section_box=section_box,
view_orientation=view_orientation
)
),
this_project=False
)

def paste(self):
sb3d_data = script.load_data(slot_name=self.__class__.__name__)
sb3d_data = script.load_data(slot_name=self.__class__.__name__,
this_project=False)

active_ui_view = revit.uidoc.GetOpenUIViews()[0]
with revit.Transaction('Paste Section Box Settings'):
Expand Down Expand Up @@ -217,6 +223,7 @@ class CropRegionAction(basetypes.CopyPasteStateAction):
name = 'Crop Region'
invalid_context_msg = \
"Activate a view or select at least one cropable viewport"
this_project = False

@staticmethod
def get_cropable_views():
Expand Down Expand Up @@ -252,15 +259,17 @@ def copy(self):
cropregion_curveloop=cropregion_curve_loop,
crop_bbox=crop_bbox,
is_active=view.CropBoxActive
)
),
this_project=False
)
else:
raise PyRevitException(
'Cannot read crop region of selected view'
)

def paste(self):
cr_data = script.load_data(slot_name=self.__class__.__name__)
cr_data = script.load_data(slot_name=self.__class__.__name__,
this_project=False)
crv_loop = cr_data.cropregion_curveloop
with revit.Transaction('Paste Crop Region'):
for view in CropRegionAction.get_cropable_views():
Expand Down Expand Up @@ -326,6 +335,7 @@ def offset_uv(self):
class ViewportPlacementAction(basetypes.CopyPasteStateAction):
name = 'Viewport Placement on Sheet'
invalid_context_msg = "At least one viewport must be selected"
this_project = False

@staticmethod
def calculate_offset(view, offset_uv, alignment):
Expand Down Expand Up @@ -558,11 +568,13 @@ def copy(self):
alignment=alignment,
center=center,
offset_uv=offset_uv if alignment == ALIGNMENT_CROPBOX else None
)
),
this_project=False
)

def paste(self):
vp_data = script.load_data(slot_name=self.__class__.__name__)
vp_data = script.load_data(slot_name=self.__class__.__name__,
this_project=False)

viewports = revit.get_selection().include(DB.Viewport)
align_axis = None
Expand Down Expand Up @@ -660,6 +672,14 @@ class FilterOverridesAction(basetypes.CopyPasteStateAction):
name = 'Filter Overrides'
invalid_context_msg = ""

@staticmethod
def get_suitable_views():
selected_views = revit.get_selection().only_views()
if not selected_views:
selected_views = [revit.active_view]
return [view for view in selected_views
if view.AreGraphicsOverridesAllowed()]

@staticmethod
def controlled_by_template(view):
if view.ViewTemplateId != DB.ElementId.InvalidElementId:
Expand All @@ -673,12 +693,12 @@ def controlled_by_template(view):
return False

def copy(self):
views = revit.get_selection().only_views()
views = FilterOverridesAction.get_suitable_views()
if views:
view = views[0]
view_filters = revit.query.get_view_filters(view)
if not view_filters:
raise PyRevitException('Active view has no fitlers applied')
raise PyRevitException('Active/Selected view has no fitlers applied')

selected_filters = forms.SelectFromList.show(
view_filters,
Expand Down Expand Up @@ -708,13 +728,14 @@ def paste(self):
# to view template or to selected view
mode_templates = \
forms.CommandSwitchWindow.show(
['Active View', 'Select View Templates'],
['Active/Selected View', 'Select View Templates'],
message='Where do you want to paste filters?'
) == 'Select Templates'
) == 'Select View Templates'
if mode_templates:
views = forms.select_viewtemplates()
else:
views = [revit.active_view]
views = FilterOverridesAction.get_suitable_views()
views = [view for view in views if view.Id != source_view.Id]
views_controlled_by_template = \
[x for x in views
if FilterOverridesAction.controlled_by_template(x)]
Expand All @@ -724,7 +745,7 @@ def paste(self):
' They will be skipped'
)
if not views:
raise PyRevitException('Nothing selected')
raise PyRevitException('No suitable views selected or active')

# check if there are views controlled by template
with revit.TransactionGroup('Paste Filter Overrides'):
Expand All @@ -748,4 +769,4 @@ def paste(self):

@staticmethod
def validate_context():
return revit.get_selection().is_empty
return bool(FilterOverridesAction.get_suitable_views())
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class CopyPasteStateAction(object):
"""
name = None
invalid_context_msg = None
this_project = True

def copy(self):
"""Performs copy action.
Expand Down
23 changes: 23 additions & 0 deletions pyrevitlib/pyrevit/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -708,3 +708,26 @@ def load_data(slot_name, this_project=True):

with open(data_file, 'r') as dfile:
return pickle.load(dfile)


def data_exists(slot_name, this_project=True):
"""Checks if data file in a specified slot and for certain project exists.
Args:
slot_name (type): desc
this_project (bool): data belongs to this project only
Returns:
bool: true if the path exists
"""
# for this specific project?
if this_project:
data_file = get_document_data_file(file_id=slot_name,
file_ext=DATAFEXT,
add_cmd_name=False)
# for any project file
else:
data_file = get_data_file(file_id=slot_name,
file_ext=DATAFEXT,
add_cmd_name=False)
return os.path.exists(data_file)

0 comments on commit dfb63a0

Please sign in to comment.