The Line.show()
method accepts show mode constant,
+ that influences the way the Line is displayed on the request.
+ These additional constants provide new modes for opening the line
+ in a shared editor window that can be replaced by subsequent calls of
+ Line.show(SHOW_REUSE)
on Line
s from different
+ Document
. This is useful for quick source browsing without
+ cluttering the UI with too many opened editors.
+
show
+ */
+ public final static int SHOW_REUSE = 4;
+
+ /** Focuses or opens given editor, marking it as reusable editor if it
+ * was not opened before. Similar to {@link #SHOW_REUSE) but ignores
+ * currently reusable editor.
+ * @see #show(int) show
+ */
+ public final static int SHOW_REUSE_NEW = 5;
+
/** Instance of null implementation of Line.Part */
static final private Line.Part nullPart = new Line.NullPart();
@@ -151,7 +167,8 @@
public abstract void show(int kind, int column);
/** Shows the line (at the first column).
- * @param kind one of {@link #SHOW_TRY_SHOW}, {@link #SHOW_SHOW}, or {@link #SHOW_GOTO}
+ * @param kind one of {@link #SHOW_TRY_SHOW}, {@link #SHOW_SHOW}, {@link #SHOW_GOTO},
+ * {@link #SHOW_REUSE} or {@link #SHOW_REUSE_NEW}
* @see #show(int, int)
*/
public void show(int kind) {
Index: src/org/openide/text/EditorSupportLineSet.java
===================================================================
RCS file: /shared/data/ccvs/repository/openide/text/src/org/openide/text/EditorSupportLineSet.java,v
--- src/org/openide/text/EditorSupportLineSet.java 23 Nov 2006 05:26:45 -0000 1.3
+++ src/org/openide/text/EditorSupportLineSet.java 2 Mar 2007 16:31:21 -0000
@@ -13,7 +13,7 @@
* "Portions Copyrighted [year] [name of copyright owner]"
*
* The Original Software is NetBeans. The Initial Developer of the Original
- * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.openide.text;
@@ -81,14 +81,15 @@
return;
}
- CloneableEditorSupport.Pane editor = support.openAt(pos, column);
-
- if (kind == SHOW_GOTO) {
- editor.getComponent().requestActive();
- } else if (kind == SHOW_TOFRONT) {
- editor.getComponent().toFront();
- editor.getComponent().requestActive();
+ CloneableEditorSupport.Pane editor;
+
+ if (kind == SHOW_REUSE || kind == SHOW_REUSE_NEW) {
+ editor = support.openReuse(pos, column, kind);
+ } else {
+ editor = support.openAt(pos, column);
+ if (kind == SHOW_TOFRONT) editor.getComponent().toFront();
}
+ editor.getComponent().requestActive();
}
/** This method will be used for annotation of part of the text on the line.*/
Index: src/org/openide/text/CloneableEditorSupport.java
===================================================================
RCS file: /shared/data/ccvs/repository/openide/text/src/org/openide/text/CloneableEditorSupport.java,v
--- src/org/openide/text/CloneableEditorSupport.java 8 Feb 2007 14:34:02 -0000 1.29
+++ src/org/openide/text/CloneableEditorSupport.java 2 Mar 2007 16:31:22 -0000
@@ -13,7 +13,7 @@
* "Portions Copyrighted [year] [name of copyright owner]"
*
* The Original Software is NetBeans. The Initial Developer of the Original
- * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.openide.text;
@@ -1657,6 +1657,8 @@
return false;
}
+ // source modified, remove it from tab-reusing slot
+ lastReusable.clear();
updateTitles();
return true;
@@ -2023,11 +2025,19 @@
}
}
+ private static ReferenceCloneableEditor
component. */
- private Pane openPane() {
+ private Pane openPane(boolean reuse) {
Pane ce = null;
boolean displayMsgOpened = false;
@@ -2054,8 +2064,19 @@
}
// #36601 - open moved outside getLock() synchronization
- ce.getComponent().open();
-
+ CloneableTopComponent ctc = ce.getComponent();
+ if (reuse && displayMsgOpened) {
+ CloneableTopComponent last = lastReusable.get();
+ if (last != null) {
+ replaceTc(last, ctc);
+ } else {
+ ctc.open();
+ }
+ lastReusable = new WeakReference(ctc);
+ } else {
+ ctc.open();
+ }
+
if (displayMsgOpened) {
String msg = messageOpened();
@@ -2109,19 +2130,36 @@
return null;
}
}
-
+
+ final Pane openReuse(final PositionRef pos, final int column, int mode) {
+ if (mode == Line.SHOW_REUSE_NEW) lastReusable.clear();
+ return openAtImpl(pos, column, true);
+ }
+
/** Forcibly create one editor component. Then set the caret
* to the given position.
* @param pos where to place the caret
+ * @param column where to place the caret
* @return always non-null
editor
* @since 5.2
*/
protected final Pane openAt(final PositionRef pos, final int column) {
+ return openAtImpl(pos, column, false);
+ }
+ /** Forcibly create one editor component. Then set the caret
+ * to the given position.
+ * @param pos where to place the caret
+ * @param column where to place the caret
+ * @param reuse if true, the infrastructure tries to reuse other, already opened editor
+ * for the purpose of opening this file/line.
+ * @return always non-null
editor
+ */
+ private final Pane openAtImpl(final PositionRef pos, final int column, boolean reuse) {
CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this);
if (redirect != null) {
- return redirect.openAt(pos, column);
+ return redirect.openAtImpl(pos, column, reuse);
}
- final Pane e = openPane();
+ final Pane e = openPane(reuse);
final Task t = prepareDocument();
e.ensureVisible();
class Selector implements TaskListener, Runnable {
Index: test/unit/src/org/openide/text/ReusableEditorTest.java
===================================================================
RCS file: test/unit/src/org/openide/text/ReusableEditorTest.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ test/unit/src/org/openide/text/ReusableEditorTest.java 2 Mar 2007 16:31:22 -0000
@@ -0,0 +1,318 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
+ * or http://www.netbeans.org/cddl.txt.
+ *
+ * When distributing Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://www.netbeans.org/cddl.txt.
+ * If applicable, add the following below the CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.openide.text;
+
+
+import java.beans.PropertyChangeListener;
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.JEditorPane;
+import junit.framework.*;
+import org.netbeans.junit.*;
+import org.openide.util.Lookup;
+import org.openide.util.Mutex;
+import org.openide.util.lookup.*;
+
+
+/** Testing the behavior of editor reusal framework.
+ * The behavior was discussed thoroughly at issue 94607.
+ *
+ * @author Petr Nejedly
+ */
+public class ReusableEditorTest extends NbTestCase {
+ CES c1, c2, c3;
+
+ /**
+ * Test ctor
+ * @param testName
+ */
+ public ReusableEditorTest(java.lang.String testName) {
+ super(testName);
+ }
+
+
+ /**
+ * Prepares few editors at the test dispoition.
+ */
+ protected void setUp () {
+ c1 = createSupport("c1");
+ c2 = createSupport("c2");
+ c3 = createSupport("c3");
+ }
+
+ /**
+ * Closes any precreated editors left open.
+ */
+ @Override
+ protected void tearDown() {
+ forceClose(c1);
+ forceClose(c2);
+ forceClose(c3);
+ }
+
+ /**
+ * Test that verifies SHOW_REUSE closes original tab (keeps only one)
+ * Scenario:
+ * 1. Open first file with SHOW_REUSE
+ * 2. Open second file with SHOW_REUSE
+ * 3. Verify first is closed
+ * 4. Open first file with SHOW_REUSE
+ * 5. Verify second is closed
+ */
+ public void testReuse() {
+ openAndCheck(c1, Line.SHOW_REUSE); // 1
+ openAndCheck(c2, Line.SHOW_REUSE); // 2
+ assertClosed(c1); // 3
+ openAndCheck(c1, Line.SHOW_REUSE); // 4
+ assertClosed(c2); // 5
+ }
+
+ /** Test that verifies SHOW_REUSE doesn't reuse modified, even saved tab
+ * 1. Open first file with SHOW_REUSE
+ * 2. Modify it
+ * 3. Open second file with SHOW_REUSE
+ * 4. Verify first still open
+ * 5. Modify second file
+ * 6. Unmodify second file
+ * 7. Open third file with SHOW_REUSE
+ * 8. Verify second still open
+ */
+ public void testKeepTouched() {
+ openAndCheck(c1, Line.SHOW_REUSE); // 1
+ c1.notifyModified(); // 2
+ openAndCheck(c2, Line.SHOW_REUSE); // 3
+ assertOpened(c1); // 4
+ c2.notifyModified(); // 5
+ c2.notifyUnmodified(); // 6
+ openAndCheck(c3, Line.SHOW_REUSE); // 7
+ assertOpened(c2); // 8
+ assertOpened(c1);
+ }
+
+ /** Test that verifies SHOW_REUSE don't consider non-reusable tabs.
+ * There are three things tested:
+ * A) Don't replace ordinary tabs
+ * B) Don't mark ordinary tabs as reusable if switched to
+ * C) Keep reusable tab mark even through (B)
+ *
+ * Scenario:
+ * 1. Open first file using SHOW_GOTO
+ * 2. Open second file using SHOW_REUSE
+ * 3. Verify first still opened (A)
+ * 4. open first using SHOW_REUSE
+ * 5. verify second still opened
+ * 6. open third file using SHOW_REUSE
+ * 7. verify first still opened (B)
+ * 8. verify second closed (C)
+ */
+ public void testLeaveNonreusable() {
+ openAndCheck(c1, Line.SHOW_GOTO); // 1
+ openAndCheck(c2, Line.SHOW_REUSE); // 2
+ assertOpened(c1); // 3
+
+ openAndCheck(c1, Line.SHOW_REUSE); // 4
+ assertOpened(c2); // 5
+ openAndCheck(c3, Line.SHOW_REUSE); // 6
+ assertOpened(c1); // 7
+
+ assertClosed(c2); // 8
+ }
+
+ /** Test that verifies SHOW_REUSE_NEW don't close existing reusable tab,
+ * but can be reused itself
+ *
+ * Scenario:
+ * 1. Open first file using SHOW_REUSE
+ * 2. Open second file using SHOW_REUSE_NEW
+ * 3. Verify first still opened
+ * 4. Open third using SHOW_REUSE
+ * 5. verify second closed
+ */
+ public void testReuseNewKeepsOld() {
+ openAndCheck(c1, Line.SHOW_REUSE); // 1
+ openAndCheck(c2, Line.SHOW_REUSE_NEW); // 2
+ assertOpened(c1); // 3
+ openAndCheck(c3, Line.SHOW_REUSE); // 4
+ assertClosed(c2); // 5
+ }
+
+ /**
+ * Test that specifies behaviour of SHOW_REUSE_NEW in case currently
+ * reusable tab is not the selected one.
+ *
+ * Scenario:
+ * 1. Open first file using SHOW_REUSE
+ * 2. Open second file using SHOW_GOTO
+ * 3. Open third file using SHOW_REUSE_NEW
+ * 4. Verify first still open.
+ */
+ public void testReuseNewKeepsOldEvenWhenNotFocused() {
+ openAndCheck(c1, Line.SHOW_REUSE); // 1
+ openAndCheck(c2, Line.SHOW_GOTO); // 2
+ openAndCheck(c3, Line.SHOW_REUSE_NEW); // 3
+ assertOpened(c1); // 4
+ }
+
+ private CES createSupport(String txt) {
+ Env env = new Env();
+ env.content = txt;
+ CES c = new CES(env, Lookups.singleton(txt));
+ env.support = c;
+ return c;
+ }
+
+ private void openAndCheck(final CES ces, final int mode) {
+ Mutex.EVENT.readAccess(new Mutex.Action