As part of the general threading rework, the
presentation-oriented APIs of Nodes, Looks, and Explorer could be run entirely
in the AWT event queue (EQ), rather than partially in EQ and partially in
other threads as now. This change should simplify the code in these APIs; make
their intended behavior more apparent to module writers; simplify testing; and
remove some overhead from the rendering cycle.
Most methods in Node, Children, and
Look (and subclasses) are no longer thread-safe or synchronized:
during construction they may be called in a single thread only, and after
display only in EQ. However some event firing methods which were commonly
called from other threads can continue to be called in this way; after display
they will be automatically replanned to EQ. All methods called on
module code will be called in EQ. Incompatible for some modules using
Nodes. However most callers of methods that have been incompatibility
restricted were failing to honor the separation between model and view and
would better have been rewritten anyway.
// Thread-safe in Node:
protectedfinalvoidfirePropertyChange(Stringname, Objecto, Objectn);
protectedfinalvoidfireNameChange(Stringo, Stringn);
protectedfinalvoidfireDisplayNameChange(Stringo, Stringn);
protectedfinalvoidfireShortDescriptionChange(Stringo, Stringn);
protectedfinalvoidfireIconChange();
protectedfinalvoidfireOpenedIconChange();
protectedfinalvoidfirePropertySetsChange(Node.PropertySet[] o,
Node.PropertySet[] n);
protectedfinalvoidfireCookieChange();
// Thread-safe in Children.Keys:
protectedfinalvoidrefreshKey(Objectkey);
protectedfinalvoidsetKeys(CollectionkeysSet);
protectedfinalvoidsetKeys(Object[] keys);
// Thread-safe in Look:
protectedfinalvoidfireChange(ObjectrepresentedObject, longmask);
protectedfinalvoidfirePropertyChange(ObjectrepresentedObject,
StringpropertyName);
Visualizer and the entire associated layer of
“visualizers” between Explorer and Nodes has been deprecated and
is unused. Explorer views now directly render Nodes. Explorer
view implementations using only Visualizer.findNode(Object) to
map supplied TreePath elements to Nodes should
continue to work. NodeListModel and NodeTableModel
continue to work; the Object parameters are now instances of
Node. NodeTreeModel, however, no longer works and is
deprecated (because it extends DefaultTreeModel and the new tree
model cannot). Overriding TreeView.createModel() no longer has
any effect; there is no longer a way to override the tree model externally.
Incompatible for modules casting elements of TreePaths to
TreeNode, or supplying a custom NodeTreeModel.
Children.MUTEX is now just Mutex.EVENT and is
deprecated. Compatible
Two overridable methods added to Children, with default
implementations that should be accurate, if not optimal. Compatible
/**
* Get a child node at the specified index.
* Subclasses may implement this more efficiently than getting all nodes
* and returning the requested one.
* @parami the (zero-based) index, less than {@link #getNodesCount}
* @return the node at that index
* @throws IndexOutOfBoundsException if the index is invalid
*/publicNodegetNodeAt(inti) throwsIndexOutOfBoundsException {
return getNodes()[i];
}
/**
* Get the index at which a given child node occurs.
* Subclasses may implement this more efficiently than getting all nodes
* and doing a linear search.
* @paramn a possible child node
* @return the index of that node, or -1 if it is not a child
*/publicintgetIndexOfNode(Noden) {
Node[] nodes = getNodes();
for (inti = 0; i < nodes.length; i++) {
if (nodes[i] == n) {
return i;
}
}
return -1;
}
Some methods in Children that used to be final now are
overridable. Compatible
A final method was added to Children to allow cleanroom
implementation of Children subclass outside of the
org.openide.nodes package. Compatible
protectedfinalvoidattachNode(Noden, intidx);
A final method was added to Node to allow cleanroom and more
effective implementation of Children subclass outside of the
org.openide.nodes package. Compatible
This is currently disabled - since getNodes(true) can only be
called from EQ, it is impossible to set the wait cursor, forcibly get all the
nodes, then reset to the normal cursor, since the EQ is occupied the whole
time.
Possible solution: introduce methods on Node or
Children which would signal (1) that getNodes(false)
did not in fact return all the available children, (2) that at some later
point (in EQ) that getNodes(true) may be called to get a full set
of children without blocking for a significant amount of time.
Children subclasses such as those used for folder children would
need to take advantage of these calls.
Unit tests fail off EQ, hard to make nodes off EQ
Currently assertions check that all methods must be called on EQ, except for
some that were experimentally found to be called often while constructing
nodes (which is common to do off EQ before displaying them); otherwise an
assertion failure is thrown, or the method call is replanned to EQ.
Node-related unit tests tend to fail as a result, and seemingly harmless code
patterns are problematic.
Possible solution: make explorer views notify node trees when they are
displayed (and possibly undisplayed). Force EQ-only access only when
displayed, and single-threaded (utility-like) access otherwise. Unit tests
would run in undisplayed mode.