diff --git a/openide.explorer/apichanges.xml b/openide.explorer/apichanges.xml
--- a/openide.explorer/apichanges.xml
+++ b/openide.explorer/apichanges.xml
@@ -47,6 +47,24 @@
Explorer API
+
+
+ setSelectedNodes() does partial selection instead of throwing IllegalArgumentException when
+ some of newly selected nodes are not under root context.
+
+
+
+
+ Nodes can be removed outside of AWT thread while e.g. view can
+ try to select them. This generated IllegalArgumentException during checking if
+ such a node is under root context. Now
+ setSelectedNodes()
.
+ does partial selection
+ of valid nodes instead of throwing IllegalArgumentException.
+
+
+
+
Added OutlineView component which is a replacement for buggy TreeTableView.
diff --git a/openide.explorer/manifest.mf b/openide.explorer/manifest.mf
--- a/openide.explorer/manifest.mf
+++ b/openide.explorer/manifest.mf
@@ -1,6 +1,6 @@
Manifest-Version: 1.0
OpenIDE-Module: org.openide.explorer
-OpenIDE-Module-Specification-Version: 6.15
+OpenIDE-Module-Specification-Version: 6.16
OpenIDE-Module-Implementation-Version: 1
OpenIDE-Module-Localizing-Bundle: org/openide/explorer/Bundle.properties
AutoUpdate-Essential-Module: true
diff --git a/openide.explorer/src/org/openide/explorer/ExplorerManager.java b/openide.explorer/src/org/openide/explorer/ExplorerManager.java
--- a/openide.explorer/src/org/openide/explorer/ExplorerManager.java
+++ b/openide.explorer/src/org/openide/explorer/ExplorerManager.java
@@ -51,6 +51,7 @@
import java.io.*;
import java.util.*;
+import java.util.ArrayList;
/**
@@ -204,8 +205,7 @@
/** Set the set of selected nodes.
* @param value the nodes to select; empty (not null
) if none are to be selected
* @exception PropertyVetoException when the given nodes cannot be selected
- * @throws IllegalArgumentException if null
is given, or if any elements
- * of the selection are not within the current root context
+ * @throws IllegalArgumentException if null
is given (array or any element in array)
*/
public final void setSelectedNodes(final Node[] value)
throws PropertyVetoException {
@@ -213,55 +213,60 @@
public PropertyVetoException veto;
private boolean doFire;
private Node[] oldValue;
+ private Node[] newValue;
- /** @return false if no further processing is needed */
- private boolean checkArgumentIsValid() {
+ /** selects only nodes under root context */
+ private void checkAndSet() {
if (value == null) {
throw new IllegalArgumentException(getString("EXC_NodeCannotBeNull"));
}
if (equalNodes(value, selectedNodes)) {
- return false;
+ return;
}
+ List validNodes = null;
for (int i = 0; i < value.length; i++) {
if (value[i] == null) {
throw new IllegalArgumentException(getString("EXC_NoElementOfNodeSelectionMayBeNull"));
}
- // exception means sanity check failed (supplied nodes are not under root)
- // the reason could be that they were deleted meanwhile, so fail gracefuly in production builds
- try {
- checkUnderRoot(value[i], "EXC_NodeSelectionCannotContainNodes");
- } catch (IllegalArgumentException e) {
- boolean dontFailGracefully = false;
- assert dontFailGracefully = true;
- if (dontFailGracefully) {
- throw e;
- } else {
- return false;
+ if (!isUnderRoot(value[i])) {
+ if (validNodes == null) {
+ validNodes = new ArrayList(value.length);
+ for (int j = 0; j < i; j++) {
+ validNodes.add(value[i]);
+ }
}
+ } else if (validNodes != null) {
+ validNodes.add(value[i]);
}
}
+ if (validNodes != null) {
+ newValue = validNodes.toArray(new Node[validNodes.size()]);
+ if (equalNodes(newValue, selectedNodes)) {
+ return;
+ }
+ } else {
+ newValue = value;
+ }
- if ((value.length != 0) && (vetoableSupport != null)) {
+ if ((newValue.length != 0) && (vetoableSupport != null)) {
try {
// we send the vetoable change event only for non-empty selections
- vetoableSupport.fireVetoableChange(PROP_SELECTED_NODES, selectedNodes, value);
+ vetoableSupport.fireVetoableChange(PROP_SELECTED_NODES, selectedNodes, newValue);
} catch (PropertyVetoException ex) {
veto = ex;
-
- return false;
+ return;
}
}
-
- return true;
+ updateSelection();
}
private void updateSelection() {
oldValue = selectedNodes;
addRemoveListeners(false);
- selectedNodes = value;
+ selectedNodes = newValue;
addRemoveListeners(true);
doFire = true;
@@ -274,9 +279,7 @@
}
public void run() {
- if (checkArgumentIsValid()) {
- updateSelection();
- }
+ checkAndSet();
}
}
diff --git a/openide.explorer/test/unit/src/org/openide/explorer/ExplorerManagerTest.java b/openide.explorer/test/unit/src/org/openide/explorer/ExplorerManagerTest.java
--- a/openide.explorer/test/unit/src/org/openide/explorer/ExplorerManagerTest.java
+++ b/openide.explorer/test/unit/src/org/openide/explorer/ExplorerManagerTest.java
@@ -153,13 +153,8 @@
public void testCannotSetNodesNotUnderTheRoot() throws Exception {
final Node a = new AbstractNode(Children.LEAF);
-
- try {
- em.setSelectedNodes(new Node[] { a });
- fail("Should throw IllegalArgumentException as the node is not under root");
- } catch (IllegalArgumentException ex) {
- // ok, a is not under root
- }
+ em.setSelectedNodes(new Node[]{a});
+ assertEquals(0, em.getSelectedNodes().length);
}
diff --git a/openide.explorer/test/unit/src/org/openide/explorer/view/TreeViewTest.java b/openide.explorer/test/unit/src/org/openide/explorer/view/TreeViewTest.java
--- a/openide.explorer/test/unit/src/org/openide/explorer/view/TreeViewTest.java
+++ b/openide.explorer/test/unit/src/org/openide/explorer/view/TreeViewTest.java
@@ -49,6 +49,7 @@
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.Action;
@@ -101,7 +102,7 @@
// public static TreeViewTest suite() {
// return new TreeViewTest("testSetSelectedNodeIsSynchronizedLazy");
// }
-
+
/**
* Tests whether JTree
's property scrollsOnExpand
* is taken into account in
@@ -505,7 +506,7 @@
}
fail("Node shall not be GCed: " + ref.get());
}
-
+
public void testSetSelectedNodeIsSynchronizedEager() throws Exception {
doSetSelectedNodeIsSynchronized(false);
}
@@ -579,6 +580,86 @@
assertEquals("Selection should be updated", Arrays.asList(keys.getNodes()),
Arrays.asList(testWindow.getExplorerManager().getSelectedNodes()));
if (setSel.e != null) {
+ fail();
+ }
+ }
+
+ public void testPartialNodeSelectionEager() throws Exception {
+ doTestPartialNodeSelection(false);
+ }
+
+ public void testPartialNodeSelectionLazy() throws Exception {
+ doTestPartialNodeSelection(true);
+ }
+
+ private void doTestPartialNodeSelection(boolean lazy) throws Exception {
+ assert !EventQueue.isDispatchThread();
+
+ testWindow = new ExplorerWindow();
+ testWindow.getContentPane().add(treeView = new TestTreeView());
+
+ class WindowDisplayer implements Runnable {
+ public void run() {
+ testWindow.pack();
+ testWindow.setVisible(true);
+ }
+
+ void waitShown() throws InterruptedException {
+ while (!testWindow.isShowing()) {
+ Thread.sleep(100);
+ }
+ Thread.sleep(500);
+ }
+ }
+
+ final Keys keys = new Keys(lazy, "A", "B", "-B", "C");
+ AbstractNode node = new AbstractNode(keys);
+ node.setName(getName());
+ final AbstractNode root = node;
+
+ try {
+ WindowDisplayer wd = new WindowDisplayer();
+ testWindow.getExplorerManager().setRootContext(root);
+ EventQueue.invokeAndWait(wd);
+ wd.waitShown();
+ } catch (InvocationTargetException ex) {
+ ex.printStackTrace();
+ }
+
+ waitAWT();
+ testWindow.getExplorerManager().setRootContext(root);
+ assertSame("Root is OK", root, testWindow.getExplorerManager().getRootContext());
+
+ Node[] arr = node.getChildren().getNodes();
+ testWindow.getExplorerManager().setExploredContext(node);
+
+ final Block block1 = new Block();
+ final Block block2 = new Block();
+ final AtomicBoolean exc = new AtomicBoolean(false);
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ public void run() {
+ Node[] arr2 = root.getChildren().getNodes();
+ block1.unblock();
+ block2.block();
+ try {
+ testWindow.getExplorerManager().setSelectedNodes(arr2);
+ } catch (Throwable ex) {
+ ex.printStackTrace();
+ exc.set(true);
+ }
+ }
+ });
+
+ block1.block();
+ keys.keys("B", "D");
+ block2.unblock();
+ waitAWT();
+
+ assertEquals("B should be selected", Arrays.asList(keys.getNodes()[0]),
+ Arrays.asList(testWindow.getExplorerManager().getSelectedNodes()));
+ if (exc.get()) {
fail();
}
}