public void fireNodeStructureChanged(final GTreeNode changedNode) {
		if (!eventsEnabled || isFiringNodeStructureChanged) {
			return;
		}
		try {
			isFiringNodeStructureChanged = true;
			SystemUtilities.assertThisIsTheSwingThread(
				"GTreeModel.fireNodeStructuredChanged() must be " + "called from the AWT thread");

			// If the tree is filtered and this is called on the original node, we have to
			// translate the node to a view node (one the tree knows).
			GTreeNode viewNode = convertToViewNode(changedNode);
			if (viewNode == null) {
				return;
			}

			if (viewNode != changedNode) {
				// The only time this can happen is when the tree is filtered.  In this case, the
				// view node will be a clone of the changed node.   We need to update the cloned 
				// node to signal that the children have changed.  If we set the children to null,
				// then they will get reloaded when we fire the event.  Instead, if we set the 
				// children to the empty list, the node will simply think there are no children and
				// it will not get reloaded.
				//
				// After the events have been fired, there will eventually be a refilter operation 
				// to update the view node with the correct children for the active filter.
				//
				// Note: this won't cause a second event to the tree because we are protected by 
				// the isFiringNodeStructureChanged flag at the top of this method.
				viewNode.setChildren(Collections.emptyList());
			}

			TreeModelEvent event = new TreeModelEvent(this, viewNode.getTreePath());
			for (TreeModelListener listener : listeners) {
				listener.treeStructureChanged(event);
			}
		}
		finally {
			isFiringNodeStructureChanged = false;
		}
	}
Sets the models root node. NOTE: this is intended to only be called from the {@link GTree}
@param newRoot the new tree model root.  It will either be the actual root or a root
of a filtered sub-tree
Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/internal/GTreeModel.java