Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ title:
de_de: Gewählte Pläne umbenennen (klein oder GROSS-Buchstaben)
pt_br: Renomear Folhas Selecionadas
tooltip:
en_us: Change the selected sheet names
en_us: Change selected sheet names
fr_fr: Modifier les noms des feuilles sélectionnés
ru: Изменить имена выбранных листов.
chinese_s: 更改选定图纸的名称
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,325 @@
"""Change the selected sheet names."""
"""Rename selected sheet names in batch."""

from pyrevit import revit, DB
from pyrevit import forms


def change_case(sheetlist, upper=True, verbose=False):
with revit.Transaction('Rename Sheets to Upper'):
for el in sheetlist:
sheetnameparam = el.Parameter[DB.BuiltInParameter.SHEET_NAME]
orig_name = sheetnameparam.AsString()
new_name = orig_name.upper() if upper else orig_name.lower()
if verbose:
print('RENAMING:\t{0}\n'
' to:\t{1}\n'.format(orig_name, new_name))
sheetnameparam.Set(new_name)
RENAME_MODES = [
'Find & Replace',
'Add Prefix',
'Add Suffix',
'to UPPERCASE',
'to lowercase',
]


sel_sheets = forms.select_sheets(title='Select Sheets', use_selection=True)
def _get_sheet_name(sheet):
return sheet.Parameter[DB.BuiltInParameter.SHEET_NAME].AsString()

if sel_sheets:
selected_option, switches = \
forms.CommandSwitchWindow.show(
['to UPPERCASE',
'to lowercase'],
switches=['Show Report'],
message='Select rename option:'

def _set_sheet_name(sheet, name):
sheet.Parameter[DB.BuiltInParameter.SHEET_NAME].Set(name)


def _collect_rename_inputs(mode):
if mode == 'Find & Replace':
find_txt = forms.ask_for_string(
prompt='Find text in current sheet names:',
title='Rename Selected Sheets'
)
if find_txt is None:
return None
if find_txt == '':
forms.alert('Find text cannot be empty.')
return None
Comment on lines +32 to +34
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2c45e3a — changed all three instances of "can not" to "cannot" (lines 33, 53, 66).

replace_txt = forms.ask_for_string(
default='',
prompt='Replace with:',
title='Rename Selected Sheets'
)
if replace_txt is None:
return None
return {'find': find_txt, 'replace': replace_txt}

if mode == 'Add Prefix':
prefix_txt = forms.ask_for_string(
default='',
prompt='Prefix to add to selected sheet names:',
title='Rename Selected Sheets'
)
if prefix_txt is None:
return None
if prefix_txt == '':
forms.alert('Prefix cannot be empty.')
return None
return {'prefix': prefix_txt}

if mode == 'Add Suffix':
suffix_txt = forms.ask_for_string(
default='',
prompt='Suffix to add to selected sheet names:',
title='Rename Selected Sheets'
)
if suffix_txt is None:
return None
if suffix_txt == '':
forms.alert('Suffix cannot be empty.')
return None
return {'suffix': suffix_txt}

return {}


def _build_new_name(old_name, mode, data):
if mode == 'Find & Replace':
return old_name.replace(data['find'], data['replace'])
if mode == 'Add Prefix':
return '{}{}'.format(data['prefix'], old_name)
if mode == 'Add Suffix':
return '{}{}'.format(old_name, data['suffix'])
if mode == 'to UPPERCASE':
return old_name.upper()
if mode == 'to lowercase':
return old_name.lower()
return old_name


def _print_preview(rename_pairs):
print('Rename preview:')
for idx, pair in enumerate(rename_pairs):
if idx >= 25:
print('... and {} more'.format(len(rename_pairs) - 25))
break
print('[{}] {} -> {}'.format(
pair['sheet'].SheetNumber,
pair['old_name'],
pair['new_name']
))


def _report_results(renamed, unchanged, conflicts, failed):
print('Rename Selected Sheets results')
print(' Renamed: {}'.format(len(renamed)))
print(' Unchanged: {}'.format(len(unchanged)))
print(' Conflicts skipped: {}'.format(len(conflicts)))
print(' Failed: {}'.format(len(failed)))
if renamed:
print('\nRenamed sheets:')
for item in renamed:
print(' [{}] {} -> {}'.format(
item['sheet_number'],
item['old_name'],
item['new_name']
))
if conflicts:
print('\nSkipped because target name was not unique:')
for item in conflicts:
print(' [{}] {} -> {} ({})'.format(
item['sheet_number'],
item['old_name'],
item['new_name'],
item['reason']
))
if failed:
print('\nFailed to rename:')
for item in failed:
print(' [{}] {} -> {} ({})'.format(
item['sheet_number'],
item['old_name'],
item['new_name'],
item['reason']
))


def _execute_renames(rename_pairs):
renamed = []
failed = []
temp_name_map = {}

with revit.Transaction('Rename Sheets (Temporary Names)'):
for idx, pair in enumerate(rename_pairs):
sheet = pair['sheet']
temp_name = '__pyrevit_temp_sheet_name_{}_{}__'.format(
sheet.Id.IntegerValue,
idx
)
try:
_set_sheet_name(sheet, temp_name)
temp_name_map[sheet.Id.IntegerValue] = temp_name
except Exception as err:
failed.append({
'sheet_number': pair['sheet'].SheetNumber,
'old_name': pair['old_name'],
'new_name': pair['new_name'],
'reason': 'Could not assign temporary name: {}'.format(err),
})

with revit.Transaction('Rename Sheets'):
for pair in rename_pairs:
sheet = pair['sheet']
if sheet.Id.IntegerValue not in temp_name_map:
continue
try:
_set_sheet_name(sheet, pair['new_name'])
renamed.append({
'sheet_number': pair['sheet'].SheetNumber,
'old_name': pair['old_name'],
'new_name': pair['new_name'],
})
except Exception as err:
restore_reason = ''
try:
_set_sheet_name(sheet, pair['old_name'])
restore_reason = ' Restored original name.'
except Exception as restore_err:
temp_name = temp_name_map[sheet.Id.IntegerValue]
try:
_set_sheet_name(sheet, temp_name)
restore_reason = (
' Could not restore original name: {}. '
'Sheet was kept on temporary name: {}.'
.format(restore_err, temp_name)
)
except Exception as temp_restore_err:
restore_reason = (
' Could not restore original name: {}. '
'Could not restore temporary name {} either: {}.'
.format(restore_err, temp_name, temp_restore_err)
)
failed.append({
'sheet_number': pair['sheet'].SheetNumber,
'old_name': pair['old_name'],
'new_name': pair['new_name'],
'reason': 'Could not assign target name: {}.{}'.format(
err,
restore_reason
),
})

return renamed, failed


def main():
selected_sheets = forms.select_sheets(title='Select Sheets', use_selection=True)
if not selected_sheets:
return

selected_option, switches = forms.CommandSwitchWindow.show(
RENAME_MODES,
switches=['Show Report'],
message='Select rename option:'
)
if not selected_option:
return

rename_inputs = _collect_rename_inputs(selected_option)
if rename_inputs is None:
return

all_sheet_names = {}
all_sheets = DB.FilteredElementCollector(revit.doc) \
.OfClass(DB.ViewSheet) \
.WhereElementIsNotElementType() \
.ToElements()
for sheet in all_sheets:
all_sheet_names[sheet.Id.IntegerValue] = _get_sheet_name(sheet)

rename_pairs = []
unchanged = []
for sheet in selected_sheets:
old_name = _get_sheet_name(sheet)
new_name = _build_new_name(old_name, selected_option, rename_inputs)
if old_name == new_name:
unchanged.append({
'sheet_number': sheet.SheetNumber,
'old_name': old_name,
'new_name': new_name,
})
continue
rename_pairs.append({
'sheet': sheet,
'old_name': old_name,
'new_name': new_name,
})

if not rename_pairs:
forms.alert('No sheet names changed with selected option.')
if switches['Show Report']:
_report_results([], unchanged, [], [])
return

conflicts = []
valid_pairs = []
target_names = {}
for pair in rename_pairs:
target_name = pair['new_name']
target_names.setdefault(target_name, []).append(pair)

for tname, pairs in target_names.items():
if len(pairs) > 1:
for pair in pairs:
conflicts.append({
'sheet_number': pair['sheet'].SheetNumber,
'old_name': pair['old_name'],
'new_name': pair['new_name'],
'reason': 'Target name is repeated in selected sheets',
})
else:
valid_pairs.append(pairs[0])

selected_sheet_ids = set([x['sheet'].Id.IntegerValue for x in valid_pairs])
existing_names = set(
name for sid, name in all_sheet_names.items()
if sid not in selected_sheet_ids
)

unique_pairs = []
for pair in valid_pairs:
if pair['new_name'] in existing_names:
conflicts.append({
'sheet_number': pair['sheet'].SheetNumber,
'old_name': pair['old_name'],
'new_name': pair['new_name'],
'reason': 'Target name already exists in model',
})
else:
unique_pairs.append(pair)

if not unique_pairs:
forms.alert('No valid unique target names. Nothing renamed.')
_report_results([], unchanged, conflicts, [])
return

_print_preview(unique_pairs)
proceed = forms.alert(
'Rename {} selected sheets?\n'
'{} sheets are ready to rename.\n'
'{} sheets will be skipped because of conflicts.\n'
'See output window for preview.'.format(
len(selected_sheets),
len(unique_pairs),
len(conflicts)
),
title='Rename Selected Sheets',
yes=True,
no=True,
ok=False
)
if not proceed:
return

renamed, failed = _execute_renames(unique_pairs)

if switches['Show Report'] or conflicts or failed:
_report_results(renamed, unchanged, conflicts, failed)
forms.alert(
'Done.\nRenamed: {}\nSkipped (unchanged/conflicts): {}\nFailed: {}'.format(
len(renamed),
len(unchanged) + len(conflicts),
len(failed)
),
title='Rename Selected Sheets'
)


if selected_option:
change_case(sel_sheets,
upper=True if selected_option == 'to UPPERCASE' else False,
verbose=switches['Show Report'])
main()