You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by eb...@apache.org on 2020/10/12 20:53:37 UTC
[netbeans] branch master updated: [NETBEANS-4857] Prevent property
change events during tree sync
This is an automated email from the ASF dual-hosted git repository.
ebakke pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push:
new 0b03065 [NETBEANS-4857] Prevent property change events during tree sync
0b03065 is described below
commit 0b030658851117088ba280db9458f3799e7817bf
Author: Michael Küttner <cu...@gmx.de>
AuthorDate: Mon Oct 12 22:53:13 2020 +0200
[NETBEANS-4857] Prevent property change events during tree sync
An ExplorerManager can be shared by multiple OutlineViews to synchronize displayed nodes and selection. This works fine for single node selection (ListSelectionModel.SINGLE_SELECTION).
But in case of multiple selection (ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) the ExplorerManager creates way too many PropertyChangeEvents.
Use setValueAdjusting to coalesce these events.
---
.../src/org/openide/explorer/view/OutlineView.java | 7 +
.../view/OutlineViewSynchronizationTest.java | 246 +++++++++++++++++++++
2 files changed, 253 insertions(+)
diff --git a/platform/openide.explorer/src/org/openide/explorer/view/OutlineView.java b/platform/openide.explorer/src/org/openide/explorer/view/OutlineView.java
index 3cf63a5..eb71102 100644
--- a/platform/openide.explorer/src/org/openide/explorer/view/OutlineView.java
+++ b/platform/openide.explorer/src/org/openide/explorer/view/OutlineView.java
@@ -859,6 +859,10 @@ public class OutlineView extends JScrollPane {
invalidate();
validate();
Node[] arr = manager.getSelectedNodes ();
+
+ // [NETBEANS-4857]: prevent property change events during synchronization
+ outline.getSelectionModel().setValueIsAdjusting(true);
+
outline.getSelectionModel().clearSelection();
int size = outline.getRowCount();
int firstSelection = -1;
@@ -876,6 +880,9 @@ public class OutlineView extends JScrollPane {
}
}
}
+ // [NETBEANS-4857]: re-activate property change events
+ outline.getSelectionModel().setValueIsAdjusting(false);
+
// System.err.println("\nOutlineView.synchronizeSelectedNodes("+java.util.Arrays.toString(arr)+"): "+
// "columnModel = "+outline.getColumnModel()+", column selection model = "+outline.getColumnModel().getSelectionModel()+
// ", column lead selection index = "+outline.getColumnModel().getSelectionModel().getLeadSelectionIndex()+"\n");
diff --git a/platform/openide.explorer/test/unit/src/org/openide/explorer/view/OutlineViewSynchronizationTest.java b/platform/openide.explorer/test/unit/src/org/openide/explorer/view/OutlineViewSynchronizationTest.java
new file mode 100644
index 0000000..fc25047
--- /dev/null
+++ b/platform/openide.explorer/test/unit/src/org/openide/explorer/view/OutlineViewSynchronizationTest.java
@@ -0,0 +1,246 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.openide.explorer.view;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyVetoException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.JPanel;
+import javax.swing.ListSelectionModel;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.swing.outline.Outline;
+import org.openide.explorer.ExplorerManager;
+import org.openide.nodes.AbstractNode;
+import org.openide.nodes.ChildFactory;
+import org.openide.nodes.Children;
+import org.openide.nodes.Node;
+import org.openide.util.lookup.AbstractLookup;
+import org.openide.util.lookup.InstanceContent;
+
+/**
+ * Tests fix of Jira issue [NETBEANS-4857]. There should be no additional
+ * property change events during outline view tree synchronization.
+ *
+ * @author Michael Kuettner
+ */
+public final class OutlineViewSynchronizationTest extends NbTestCase {
+
+ public OutlineViewSynchronizationTest(String testName) {
+ super(testName);
+ }
+
+ @Override
+ protected boolean runInEQ() {
+ return true;
+ }
+
+ public void testSingleOutlineSelection() throws InterruptedException, IllegalAccessException, InvocationTargetException, PropertyVetoException {
+
+ MultipleOutlinesPanel outlinesPanel = new MultipleOutlinesPanel(1);
+ outlinesPanel.addNotify();
+
+ Node[] nodes = outlinesPanel.getExplorerManager().getRootContext().getChildren().getNodes();
+
+ LoggingPropertyChangeListener evtLog = new LoggingPropertyChangeListener();
+ ExplorerManager manager = outlinesPanel.getExplorerManager();
+ manager.addPropertyChangeListener(evtLog);
+
+ // select a single node
+ manager.setSelectedNodes(new Node[]{nodes[0]});
+
+ assertEquals(1, evtLog.getEventCount());
+ assertEquals("[] -> [0]", evtLog.getEvent(0));
+ assertEquals(1, outlinesPanel.getOutline(0).getSelectedRowCount());
+
+ // remove already collected events
+ evtLog.clearEvents();
+
+ // select all nodes
+ manager.setSelectedNodes(nodes);
+
+ assertEquals(1, evtLog.getEventCount());
+ assertEquals("[0] -> [0,1,2,3,4,5,6,7,8,9]", evtLog.getEvent(0));
+ assertEquals(10, outlinesPanel.getOutline(0).getSelectedRowCount());
+ }
+
+ public void testMultipleOutlinesSelectionSynchronization() throws InterruptedException, IllegalAccessException, InvocationTargetException, PropertyVetoException {
+
+ MultipleOutlinesPanel outlinesPanel = new MultipleOutlinesPanel(4);
+ outlinesPanel.addNotify();
+
+ Node[] nodes = outlinesPanel.getExplorerManager().getRootContext().getChildren().getNodes();
+
+ LoggingPropertyChangeListener evtLog = new LoggingPropertyChangeListener();
+ ExplorerManager manager = outlinesPanel.getExplorerManager();
+ manager.addPropertyChangeListener(evtLog);
+
+ // select a single node
+ manager.setSelectedNodes(new Node[]{nodes[0]});
+
+ assertEquals(1, evtLog.getEventCount());
+ assertEquals("[] -> [0]", evtLog.getEvent(0));
+ assertEquals(1, outlinesPanel.getOutline(0).getSelectedRowCount());
+ assertEquals(1, outlinesPanel.getOutline(1).getSelectedRowCount());
+ assertEquals(1, outlinesPanel.getOutline(2).getSelectedRowCount());
+ assertEquals(1, outlinesPanel.getOutline(3).getSelectedRowCount());
+
+ // remove already collected events
+ evtLog.clearEvents();
+
+ // select all nodes
+ manager.setSelectedNodes(nodes);
+
+ assertEquals(1, evtLog.getEventCount());
+ assertEquals("[0] -> [0,1,2,3,4,5,6,7,8,9]", evtLog.getEvent(0));
+ assertEquals(10, outlinesPanel.getOutline(0).getSelectedRowCount());
+ assertEquals(10, outlinesPanel.getOutline(1).getSelectedRowCount());
+ assertEquals(10, outlinesPanel.getOutline(2).getSelectedRowCount());
+ assertEquals(10, outlinesPanel.getOutline(3).getSelectedRowCount());
+ }
+
+ /**
+ * A panel that provides an {@link ExplorerManager} and contains multiple
+ * panels with outlines.
+ */
+ public static class MultipleOutlinesPanel extends JPanel implements ExplorerManager.Provider {
+
+ private final ExplorerManager manager = new ExplorerManager();
+
+ public MultipleOutlinesPanel(int numberOfOutlineViews) {
+ setLayout(new FlowLayout(FlowLayout.LEFT));
+ for (int i = 0; i < numberOfOutlineViews; i++) {
+ add(new OutlinePanel());
+ }
+ Node rootNode = new AbstractNode(Children.create(new MultipleTreesNodeFactory(), false));
+ manager.setRootContext(rootNode);
+ }
+
+ public Outline getOutline(int index) {
+ OutlinePanel panel = (OutlinePanel) getComponent(index);
+ return panel.getOutlineView().getOutline();
+ }
+
+ @Override
+ public ExplorerManager getExplorerManager() {
+ return manager;
+ }
+ }
+
+ /**
+ * A panel that contains a single {@link OutlineView}.
+ */
+ private static class OutlinePanel extends JPanel {
+
+ private OutlineView outlineView;
+
+ public OutlinePanel() {
+ setLayout(new BorderLayout());
+
+ outlineView = new OutlineView("tree");
+ outlineView.getOutline().setRootVisible(false);
+ // activate multiple interval selection
+ outlineView.getOutline().getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+ outlineView.getOutline().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+
+ add(outlineView, BorderLayout.CENTER);
+ }
+
+ public OutlineView getOutlineView() {
+ return outlineView;
+ }
+ }
+
+ /**
+ * A simple node factory that creates some String nodes.
+ */
+ private static class MultipleTreesNodeFactory extends ChildFactory<String> {
+
+ @Override
+ protected boolean createKeys(final List<String> values) {
+ for (int i = 0; i < 10; i++) {
+ values.add(Integer.toString(i));
+ }
+ return true;
+ }
+
+ @Override
+ protected Node createNodeForKey(final String key) {
+ return new MultipeTreesNode(key);
+ }
+ }
+
+ /**
+ * A simple node for a String.
+ */
+ private static class MultipeTreesNode extends AbstractNode {
+
+ public MultipeTreesNode(final String value) {
+ super(Children.LEAF, new AbstractLookup(new InstanceContent()));
+ setName(value);
+ }
+ }
+
+ /**
+ * PropertyChangeListener implementation that keeps a string representation
+ * of each ExplorerManager.PROP_SELECTED_NODES event.
+ */
+ private static class LoggingPropertyChangeListener implements PropertyChangeListener {
+
+ private List<String> events = new ArrayList<String>();
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (ExplorerManager.PROP_SELECTED_NODES.equals(evt.getPropertyName())) {
+ Node[] oldNodes = (Node[]) evt.getOldValue();
+ Node[] newNodes = (Node[]) evt.getNewValue();
+ events.add(nodesToString(oldNodes) + " -> " + nodesToString(newNodes));
+ }
+ }
+
+ private String nodesToString(final Node[] nodes) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("[");
+ for (int i = 0; i < nodes.length; i++) {
+ builder.append(nodes[i].getName());
+ if (i != nodes.length - 1) {
+ builder.append(",");
+ }
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+
+ public int getEventCount() {
+ return events.size();
+ }
+
+ public String getEvent(int index) {
+ return events.get(index);
+ }
+
+ public void clearEvents() {
+ events.clear();
+ }
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists