Xrefs panel

Xref Manager

Reload, unload, detach or bind several xrefs at once, picked from a list that shows each one's status and saved path.

On the ribbonButton, Xrefs panel
NeedsAn open drawing (the button is greyed without one)
CommandPYXREFMANAGER
AliasXM

What it does#

Lists every top-level xref in the drawing, sorted by name, with its status and the path saved in the drawing. You tick the ones to work on, pick one action, and the tool applies it to each xref in turn. One xref that fails does not stop the others: they are all tried, and the ones that did not work are listed at the end with the reason.

Each line of the list reads like this:

Site  [loaded]  ..\Xref\site.dwg
Grid  [not found, overlay]  P:\Jobs\1234\Xref\grid.dwg
Logo  [unloaded]  .\logo.dwg

The word in brackets is the xref's status: loaded, unloaded, not found (the file is not at the saved path or on any search path), unresolved or unreferenced (attached but with no reference left in the drawing). An xref attached as an overlay also says overlay. An xref with no saved path shows (no path).

How to use it#

  1. Click Xref Manager, or type PYXREFMANAGER. If the drawing has no xrefs a toast says so and nothing opens.
  2. Tick the xrefs to work on. The search box narrows a long list. Click OK.
  3. Pick what should happen to them: Reload, Unload, Detach or Bind.
  4. For Bind, pick how. Bind keeps each xref's layers and styles apart, renamed in the Site$0$Walls pattern. Insert merges them into the drawing's own layers and styles, the way the INSERT command does.
  5. Detach and Bind ask once more before they start, because both take the xref out of its file's control.
  6. The tool works through the list. When every xref worked, a toast says so (for example "Reloaded 3 xrefs"). When some failed, the toast says how many of how many, and a window lists each failure with its reason. That window shows the first 15; its Copy button puts all of them on the clipboard.

Limitations#

  • Nested xrefs are not listed. Reload, unload or bind the xref that holds them.
  • Only a loaded xref can be bound. An unloaded or missing one is reported as not done, with its status as the reason; reload it (or fix its path with Xref Repath) first.
  • AutoCAD reloads an xref whose file it cannot find without raising an error. The tool reads every xref's status again after a Reload, so one that is still not loaded is reported as failed, for example not found at ..\Xref\site.dwg, rather than counted as done.
  • One action per run. To reload some xrefs and unload others, run the tool twice.
  • The tool does not attach or overlay new xrefs. Use XATTACH for that. Images, PDF underlays and other attachments are not listed: only DWG xrefs.

Good to know#

A ribbon click sends the PYXREFMANAGER command to the drawing, so the whole run is one command and a single U takes it back, Detach and Bind included. Undo is the only way back from either.

The list is a quick status report in its own right: open it, read it, and press Cancel. Nothing changes until you pick an action.

Other uses#

  • Unload the heavy backgrounds before you work on your own layers, and reload them all in one pass before you plot.
  • Reload every xref after a consultant issues new backgrounds, and see at once which ones did not come back.
  • Bind the xrefs into a copy of the drawing for an archive or a transmittal that must open without its reference files.

Source#

The tool's own files, word for word as shipped in Xrefs.panel/Xref_Manager.pushbutton. Every pyACAD tool is an ordinary bundle: copy these into your own extension and change what you like.

script.py Runs on a click. View on GitHub
# -*- coding: utf-8 -*-
"""Reload, unload, detach or bind several of the drawing's xrefs at once.

Lists every top-level xref with its status and saved path, asks what to do
with the ones picked, and does it to each in turn, so one that fails does not
stop the rest. Detach and bind ask first: both take the xref out of the
drawing's control and only Undo brings it back. Nested xrefs are not listed,
since they follow the xref that holds them.
"""

from pyacad import doc, forms, script, toast, xrefs

__title__ = 'Xref Manager'

TITLE = 'Xref Manager'
ACTIONS = ['Reload', 'Unload', 'Detach', 'Bind']
DONE = {'Reload': 'Reloaded', 'Unload': 'Unloaded', 'Detach': 'Detached', 'Bind': 'Bound'}
LIMIT = 15          # failures shown in the alert; Copy carries them all


def run():
    if script.get_document_path() is None:
        toast.warning('Open a drawing first')
        return

    rows = sorted([x for x in xrefs.list() if not x['nested']],
                  key=lambda x: x['name'].lower())
    if not rows:
        toast.info('This drawing has no xrefs')
        return

    labels = xrefs.describe(rows)
    picked = forms.select_from_list(
        [(label, row['name']) for label, row in zip(labels, rows)],
        title=TITLE, multiselect=True, prompt='Pick the xrefs to work on')
    if not picked:
        return

    action = forms.ask_options('What should happen to %s?' % _what(picked),
                               ACTIONS, title=TITLE)
    if action is None:
        return

    insert = False
    if action == 'Bind':
        how = forms.ask_options(
            "Bind keeps each xref's layers and styles apart, renamed like "
            "Site$0$Walls. Insert merges them into the drawing's own, as INSERT does.",
            ['Bind', 'Insert'], title=TITLE)
        if how is None:
            return
        insert = how == 'Insert'

    if action in ('Detach', 'Bind') and not forms.confirm(_warning(action, insert, picked), TITLE):
        return

    status = dict((row['name'], row['status']) for row in rows)
    with doc.lock():
        results = [_apply(action, name, insert, status.get(name)) for name in picked]
        if action == 'Reload':
            # AutoCAD reloads a missing file without complaint; the status says.
            results = xrefs.check_loaded(results, xrefs.list())
    _report(results, DONE[action])


def _apply(action, name, insert, status):
    """(name, error) for one xref; error is None when it worked."""
    if action == 'Bind' and status != 'loaded':
        return name, '%s; only a loaded xref can be bound' % xrefs.status_label(status)
    try:
        if action == 'Reload':
            xrefs.reload([name])
        elif action == 'Unload':
            xrefs.unload([name])
        elif action == 'Detach':
            xrefs.detach(name)
        else:
            xrefs.bind([name], insert=insert)
    except Exception as error:
        return name, str(error) or error.__class__.__name__
    return name, None


def _report(results, verb):
    head = xrefs.headline(results, verb)
    failed = len([1 for name, error in results if error])
    if not failed:
        toast.success(head)
        return
    if failed == len(results):
        toast.error(head)
    else:
        toast.warning(head, '%d not done' % failed)
    forms.alert(xrefs.summarize(results, verb, limit=LIMIT), TITLE,
                copy=xrefs.summarize(results, verb))


def _warning(action, insert, picked):
    if action == 'Detach':
        return ('Detach %s? It leaves the drawing with every reference to it.'
                if len(picked) == 1 else
                'Detach %s? They leave the drawing with every reference to them.') % _what(picked)
    how = ' as inserted blocks' if insert else ''
    return ('Bind %s into the drawing%s? It stops following its file.'
            if len(picked) == 1 else
            'Bind %s into the drawing%s? They stop following their files.') % (_what(picked), how)


def _what(names):
    """'Site' for one xref, '3 xrefs' for more."""
    return names[0] if len(names) == 1 else '%d xrefs' % len(names)


if '__commandpath__' in globals():
    run()
bundle.yaml The bundle contract: the keys pyACAD reads for this tool. View on GitHub
title: Xref Manager
tooltip: Reload, unload, detach or bind several xrefs at once. Pick them from a list that shows each one's status and saved path.
context: doc
keytip: XM
alias: XM