Project > Models
Link Navigator
From the selected element to the model it comes from: its files, units, transform, freshness and size in the output window, then select, isolate, hide, open the folder, refresh, remove it or show it in Source Files.
Status
Untested Never executed inside Navisworks. Passed the headless checks only.
The public ask
No public source is on record for this tool.
Events it listens to
It needs these Navisworks event hooks, so installing it also copies the shared hooks folder:
model-appended
Files
Paths are relative to the Playground.extension folder.
Project.tab/Models.panel/Link_Navigator.pushbutton/bundle.yamlProject.tab/Models.panel/Link_Navigator.pushbutton/icon.dark.pngProject.tab/Models.panel/Link_Navigator.pushbutton/icon.pngProject.tab/Models.panel/Link_Navigator.pushbutton/icon.small.dark.pngProject.tab/Models.panel/Link_Navigator.pushbutton/icon.small.pngProject.tab/Models.panel/Link_Navigator.pushbutton/script.py
Install
- Only this tool. In Navisworks, click pyNavis > Playground, search for Link Navigator, tick it and click Install.
- The whole extension. Download
Playground.extension.zip, unzip it, put thePlayground.extensionfolder in%APPDATA%\pyNavis\extensions\, and click pyNavis > Reload. Link Navigator is on the Project tab, Models panel.
You need pyNavis 1.3.0 or later.
Tried it? Tell us whether it worked or not. That report is what moves a tool up the status ladder.
ReportSource
The tool's own files, word for word as published in pynavis/Playground. Paths are relative to the Playground.extension folder.
script.py
The script that runs on a click.
Project.tab/Models.panel/Link_Navigator.pushbutton/script.py View on GitHub# -*- coding: utf-8 -*-
"""Shows which model the selection comes from, with its files, units and transform, then acts on that model."""
from namo import mdl_output, modelmgmt, sourcefiles, transforms, ui
from pynavis import app, forms, output, panes, selection, toast
# Items counted before the card shows, shared by every model in the selection: the
# click must answer at once even on a federation of millions of items (the Source Files
# panel counts in full, in the background).
ITEM_BUDGET = 200000
def card(info, stale, doc, total, budget):
doc_units = str(doc.Units)
try:
state = transforms.read_state(info['model'])
factor = transforms.unit_factor(doc_units, state['units'], transforms.convention())
transform = '; '.join(transforms.describe(state, doc_units, factor)[:3])
except Exception:
transform = 'Could not be read'
try:
counted = modelmgmt.count_items(info['root'], budget=max(1, budget[0]))
budget[0] -= counted['items']
items = '{:,} items, {:,} with geometry'.format(counted['items'], counted['geometry'])
if counted['sampled']:
items = ('Over {:,} items (Source Files counts them all)'.format(counted['items'])
if counted['items'] > 1 else 'Not counted (Source Files counts them all)')
except Exception:
items = 'Could not be counted'
file_text = info['file'] or 'none (embedded)'
if stale.get('cache_time') is not None:
file_text += '\n%s, saved %s' % (modelmgmt.format_size(stale.get('cache_size')),
modelmgmt.format_time(stale['cache_time']))
source_text = info['source'] or 'none recorded'
if stale.get('source_time') is not None and info['source'] != info['file']:
source_text += '\n%s, saved %s' % (modelmgmt.format_size(stale.get('source_size')),
modelmgmt.format_time(stale['source_time']))
pairs = [('Model', '%d of %d in the Selection Tree' % (info['index'] + 1, total)),
('Loaded from', file_text), ('Source file', source_text),
('Freshness', '%s. %s' % (stale.get('status', ''), stale.get('detail', ''))),
('Created by', info['creator'] or 'not recorded'), ('Units', info['units'] or 'unknown'),
('Transform', transform), ('Contents', items)]
return mdl_output.heading(info['name'], 2) + mdl_output.kv_table(pairs)
def act(choice, infos, doc):
keys = [i['key'] for i in infos]
names = modelmgmt.join_names([i['name'] for i in infos])
noun = modelmgmt.plural(len(infos), 'model')
if choice.startswith('Select'):
modelmgmt.select_models(keys, doc)
toast.success('Selected %s' % noun, names)
elif choice.startswith('Isolate'):
modelmgmt.isolate_models(keys, doc)
toast.success('Isolated %s' % noun, names)
elif choice.startswith('Hide'):
modelmgmt.set_models_hidden(keys, True, doc)
toast.success('Hid %s' % noun, names)
elif choice == 'Open folder':
target = modelmgmt.model_folder(infos[0])
if not target:
toast.warning('Folder not found', 'Neither the file of %s nor its source is on this computer.'
% infos[0]['name'])
return
ui.show_in_explorer(target)
elif choice == 'Refresh files':
try:
changed = modelmgmt.refresh_files(doc)
except Exception as error:
toast.error('Could not refresh the files', str(error) or type(error).__name__)
return
if changed:
toast.success('Reloaded the changed models')
else:
toast.info('No model files changed', 'Every model is as new as its file.')
elif choice.startswith('Remove'):
question = 'Remove %s from this document?\n\n%s\n\nSave first if you may want %s back.' % (
noun, '\n'.join(i['name'] for i in infos), 'it' if len(infos) == 1 else 'them')
if not forms.confirm(question, 'Link Navigator'):
return
removed, failed = modelmgmt.remove_models(keys, doc)
if failed:
toast.warning('Removed %d, %d failed' % (len(removed), len(failed)),
'Could not remove %s.' % modelmgmt.join_names(failed))
else:
toast.success('Removed %s' % modelmgmt.plural(len(removed), 'model'), modelmgmt.join_names(removed))
elif choice == 'Show in Source Files':
if not panes.show(sourcefiles.PANE_KEY):
toast.warning('The Source Files panel has no slot',
'Every pyNavis panel slot is claimed. Add more with Panel slots on the pyNavis '
'tab, then restart Navisworks.')
return
sourcefiles.show_model(keys[0])
def run():
doc = app.get_doc()
picked = selection.get_items(doc)
if not picked:
toast.info('Nothing selected', 'Select an element to find the model it comes from.')
return
infos = modelmgmt.models_of_items(picked, doc)
if not infos:
toast.warning('Could not find the model of the selection', 'Select an element in the scene or the Selection Tree.')
return
all_infos = modelmgmt.models_info(doc)
stale = dict((r['key'], r) for r in modelmgmt.stale_rows(doc, infos))
shown = infos[:8]
budget = [ITEM_BUDGET]
html = [card(info, stale.get(info['key']) or {}, doc, len(all_infos), budget) for info in shown]
if len(infos) > len(shown):
html.append(mdl_output.note('%d more models are in the selection.' % (len(infos) - len(shown))))
output.print_html(''.join(html))
many = len(infos) > 1
options = ['Select models' if many else 'Select model',
'Isolate models' if many else 'Isolate model',
'Hide models' if many else 'Hide model',
'Open folder', 'Refresh files',
'Remove models' if many else 'Remove model',
'Show in Source Files']
prompt = ('The selection comes from %s. What next?' % modelmgmt.join_names([i['name'] for i in infos])
if many else 'The selection comes from %s. What next?' % infos[0]['name'])
choice = forms.ask_options(prompt, options, 'Link Navigator')
if choice is None:
return
act(choice, infos, doc)
run()
Library modules this tool uses
From the shared namo library, which installs with every tool. Each name opens the module on GitHub.
namo.mdl_outputOutput-window HTML for the Models, Quality and Publish tools (pure string building).namo.modelmgmtAppended models: listing, identifying, file freshness, batch append and model actions.namo.sourcefilesThe Source Files dock pane: a live list of the appended models.namo.transformsModel transforms: read, decompose, move, rotate about Z, presets per model file.namo.uiWPF building blocks for Playground tools, themed from the pyNavis design system.
bundle.yaml
The bundle contract: the keys pyNavis reads for this tool.
Project.tab/Models.panel/Link_Navigator.pushbutton/bundle.yaml View on GitHubtitle: Link\nNavigator
tooltip: From the selected element to the model it comes from: its files, units, transform, freshness and size in the output window, then select, isolate, hide, open the folder, refresh, remove it or show it in Source Files.
context: selection