This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 94607
Collapse All | Expand All

(-)apichanges.xml (-1 / +21 lines)
Lines 14-20 Link Here
14
"Portions Copyrighted [year] [name of copyright owner]"
14
"Portions Copyrighted [year] [name of copyright owner]"
15
15
16
The Original Software is NetBeans. The Initial Developer of the Original
16
The Original Software is NetBeans. The Initial Developer of the Original
17
Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
18
Microsystems, Inc. All Rights Reserved.
18
Microsystems, Inc. All Rights Reserved.
19
-->
19
-->
20
<!DOCTYPE apichanges PUBLIC "-//NetBeans//DTD API changes list 1.0//EN" "../../nbbuild/javadoctools/apichanges.dtd">
20
<!DOCTYPE apichanges PUBLIC "-//NetBeans//DTD API changes list 1.0//EN" "../../nbbuild/javadoctools/apichanges.dtd">
Lines 23-28 Link Here
23
<apidef name="text">Text API</apidef>
23
<apidef name="text">Text API</apidef>
24
</apidefs>
24
</apidefs>
25
<changes>
25
<changes>
26
    <change id="Line.SHOW_REUSE">
27
        <api name="text"/>
28
        <summary>Adding Line.SHOW_REUSE and Line.SHOW_REUSE_NEW constants for Line.show method</summary>
29
        <version major="6" minor="14"/>
30
        <date day="5" month="3" year="2007"/>
31
        <author login="pnejedly"/>
32
        <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
33
        <description>
34
            <p>The <code>Line.show()</code> method accepts show mode constant,
35
            that influences the way the Line is displayed on the request.
36
            These additional constants provide new modes for opening the line
37
            in a shared editor window that can be replaced by subsequent calls of
38
            <code>Line.show(SHOW_REUSE)</code> on <code>Line</code>s from different
39
            <code>Document</code>. This is useful for quick source browsing without
40
            cluttering the UI with too many opened editors.
41
            </p>
42
        </description>
43
        <class package="org.openide.text" name="Line"/>
44
        <issue number="94607"/>
45
    </change>
26
    <change id="CloneableEditorSupportRedirector">
46
    <change id="CloneableEditorSupportRedirector">
27
        <api name="text"/>
47
        <api name="text"/>
28
        <summary>CloneableEditorSupportRedirector</summary>
48
        <summary>CloneableEditorSupportRedirector</summary>
(-)manifest.mf (-1 / +1 lines)
Lines 1-5 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.openide.text
2
OpenIDE-Module: org.openide.text
3
OpenIDE-Module-Specification-Version: 6.13
3
OpenIDE-Module-Specification-Version: 6.14
4
OpenIDE-Module-Localizing-Bundle: org/openide/text/Bundle.properties
4
OpenIDE-Module-Localizing-Bundle: org/openide/text/Bundle.properties
5
5
(-)src/org/openide/text/Line.java (-2 / +19 lines)
Lines 13-19 Link Here
13
 * "Portions Copyrighted [year] [name of copyright owner]"
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17
 * Microsystems, Inc. All Rights Reserved.
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
18
 */
19
package org.openide.text;
19
package org.openide.text;
Lines 69-74 Link Here
69
     */
69
     */
70
    public final static int SHOW_TOFRONT = 3;
70
    public final static int SHOW_TOFRONT = 3;
71
71
72
    /** Takes the focus in case the editor is already opened and shows the line.
73
     * Replaces (closes) the last editor opened using SHOW_REUSE in case 
74
     * the user haven't interacted with it much (e.g. haven't modified it).
75
     * Opens a new editor in case there is no such reusable editor
76
     * and marks it for editor reusal. 
77
     * @see #show(int) <code>show</code>
78
     */
79
    public final static int SHOW_REUSE = 4;
80
81
    /** Focuses or opens given editor, marking it as reusable editor if it
82
     * was not opened before. Similar to {@link #SHOW_REUSE) but ignores
83
     * currently reusable editor.
84
     * @see #show(int) <code>show</code>
85
     */
86
    public final static int SHOW_REUSE_NEW = 5;
87
72
    /** Instance of null implementation of Line.Part */
88
    /** Instance of null implementation of Line.Part */
73
    static final private Line.Part nullPart = new Line.NullPart();
89
    static final private Line.Part nullPart = new Line.NullPart();
74
90
Lines 151-157 Link Here
151
    public abstract void show(int kind, int column);
167
    public abstract void show(int kind, int column);
152
168
153
    /** Shows the line (at the first column).
169
    /** Shows the line (at the first column).
154
    * @param kind one of {@link #SHOW_TRY_SHOW}, {@link #SHOW_SHOW}, or {@link #SHOW_GOTO}
170
    * @param kind one of {@link #SHOW_TRY_SHOW}, {@link #SHOW_SHOW}, {@link #SHOW_GOTO},
171
    * {@link #SHOW_REUSE} or {@link #SHOW_REUSE_NEW}
155
    * @see #show(int, int)
172
    * @see #show(int, int)
156
    */
173
    */
157
    public void show(int kind) {
174
    public void show(int kind) {
(-)src/org/openide/text/EditorSupportLineSet.java (-8 / +9 lines)
Lines 13-19 Link Here
13
 * "Portions Copyrighted [year] [name of copyright owner]"
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17
 * Microsystems, Inc. All Rights Reserved.
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
18
 */
19
package org.openide.text;
19
package org.openide.text;
Lines 81-94 Link Here
81
                return;
81
                return;
82
            }
82
            }
83
83
84
            CloneableEditorSupport.Pane editor = support.openAt(pos, column);
84
            CloneableEditorSupport.Pane editor;
85
85
            
86
            if (kind == SHOW_GOTO) {
86
            if (kind == SHOW_REUSE || kind == SHOW_REUSE_NEW) {
87
                editor.getComponent().requestActive();
87
                editor = support.openReuse(pos, column, kind);
88
            } else if (kind == SHOW_TOFRONT) {
88
            } else {
89
                editor.getComponent().toFront();
89
                editor = support.openAt(pos, column);
90
                editor.getComponent().requestActive();
90
                if (kind == SHOW_TOFRONT) editor.getComponent().toFront();
91
            }
91
            }
92
            editor.getComponent().requestActive();
92
        }
93
        }
93
94
94
        /** This method will be used for annotation of part of the text on the line.*/
95
        /** This method will be used for annotation of part of the text on the line.*/
(-)src/org/openide/text/CloneableEditorSupport.java (-7 / +45 lines)
Lines 13-19 Link Here
13
 * "Portions Copyrighted [year] [name of copyright owner]"
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17
 * Microsystems, Inc. All Rights Reserved.
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
18
 */
19
package org.openide.text;
19
package org.openide.text;
Lines 1657-1662 Link Here
1657
            return false;
1657
            return false;
1658
        }
1658
        }
1659
1659
1660
        // source modified, remove it from tab-reusing slot
1661
        lastReusable.clear();
1660
        updateTitles();
1662
        updateTitles();
1661
1663
1662
        return true;
1664
        return true;
Lines 2023-2033 Link Here
2023
        }
2025
        }
2024
    }
2026
    }
2025
2027
2028
    private static Reference<CloneableTopComponent> lastReusable = new WeakReference(null);
2029
    
2030
    // temporal - should be replaced by better impl in winsys
2031
    private static void replaceTc(TopComponent orig, TopComponent open) {
2032
        orig.close();
2033
        open.open();
2034
    }
2035
2026
    // #18981. There could happen a thing also another class type
2036
    // #18981. There could happen a thing also another class type
2027
    // of CloneableTopCoponent then CloneableEditor could be in allEditors.
2037
    // of CloneableTopCoponent then CloneableEditor could be in allEditors.
2028
2038
2029
    /** Opens a <code>CloneableEditor</code> component. */
2039
    /** Opens a <code>CloneableEditor</code> component. */
2030
    private Pane openPane() {
2040
    private Pane openPane(boolean reuse) {
2031
        Pane ce = null;
2041
        Pane ce = null;
2032
        boolean displayMsgOpened = false;
2042
        boolean displayMsgOpened = false;
2033
2043
Lines 2054-2061 Link Here
2054
        }
2064
        }
2055
2065
2056
        // #36601 - open moved outside getLock() synchronization
2066
        // #36601 - open moved outside getLock() synchronization
2057
        ce.getComponent().open();
2067
        CloneableTopComponent ctc = ce.getComponent();
2058
2068
        if (reuse && displayMsgOpened) {
2069
            CloneableTopComponent last = lastReusable.get();
2070
            if (last != null) {
2071
                replaceTc(last, ctc);
2072
            } else {
2073
                ctc.open();
2074
            }
2075
            lastReusable = new WeakReference(ctc);
2076
        } else {
2077
            ctc.open();
2078
        }
2079
        
2059
        if (displayMsgOpened) {
2080
        if (displayMsgOpened) {
2060
            String msg = messageOpened();
2081
            String msg = messageOpened();
2061
2082
Lines 2109-2127 Link Here
2109
            return null;
2130
            return null;
2110
        }
2131
        }
2111
    }
2132
    }
2112
2133
   
2134
    final Pane openReuse(final PositionRef pos, final int column, int mode) {
2135
        if (mode == Line.SHOW_REUSE_NEW) lastReusable.clear();
2136
        return openAtImpl(pos, column, true);
2137
    }
2138
    
2113
    /** Forcibly create one editor component. Then set the caret
2139
    /** Forcibly create one editor component. Then set the caret
2114
    * to the given position.
2140
    * to the given position.
2115
    * @param pos where to place the caret
2141
    * @param pos where to place the caret
2142
    * @param column where to place the caret
2116
    * @return always non-<code>null</code> editor
2143
    * @return always non-<code>null</code> editor
2117
    * @since 5.2
2144
    * @since 5.2
2118
    */
2145
    */
2119
    protected final Pane openAt(final PositionRef pos, final int column) {
2146
    protected final Pane openAt(final PositionRef pos, final int column) {
2147
        return openAtImpl(pos, column, false);
2148
    }
2149
    /** Forcibly create one editor component. Then set the caret
2150
    * to the given position.
2151
    * @param pos where to place the caret
2152
    * @param column where to place the caret
2153
    * @param reuse if true, the infrastructure tries to reuse other, already opened editor
2154
     * for the purpose of opening this file/line. 
2155
    * @return always non-<code>null</code> editor
2156
    */
2157
    private final Pane openAtImpl(final PositionRef pos, final int column, boolean reuse) {
2120
        CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this);
2158
        CloneableEditorSupport redirect = CloneableEditorSupportRedirector.findRedirect(this);
2121
        if (redirect != null) {
2159
        if (redirect != null) {
2122
            return redirect.openAt(pos, column);
2160
            return redirect.openAtImpl(pos, column, reuse);
2123
        }
2161
        }
2124
        final Pane e = openPane();
2162
        final Pane e = openPane(reuse);
2125
        final Task t = prepareDocument();
2163
        final Task t = prepareDocument();
2126
        e.ensureVisible();
2164
        e.ensureVisible();
2127
        class Selector implements TaskListener, Runnable {
2165
        class Selector implements TaskListener, Runnable {
(-)test/unit/src/org/openide/text/ReusableEditorTest.java (+318 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.openide.text;
21
22
23
import java.beans.PropertyChangeListener;
24
import java.io.*;
25
import java.util.ArrayList;
26
import java.util.List;
27
import javax.swing.JEditorPane;
28
import junit.framework.*;
29
import org.netbeans.junit.*;
30
import org.openide.util.Lookup;
31
import org.openide.util.Mutex;
32
import org.openide.util.lookup.*;
33
34
35
/** Testing the behavior of editor reusal framework.
36
 * The behavior was discussed thoroughly at issue 94607.
37
 *
38
 * @author Petr Nejedly
39
 */
40
public class ReusableEditorTest extends NbTestCase {
41
    CES c1, c2, c3;
42
    
43
    /**
44
     * Test ctor
45
     * @param testName 
46
     */
47
    public ReusableEditorTest(java.lang.String testName) {
48
        super(testName);
49
    }
50
            
51
52
    /**
53
     * Prepares few editors at the test dispoition.
54
     */
55
    protected void setUp () {
56
        c1 = createSupport("c1");
57
        c2 = createSupport("c2");
58
        c3 = createSupport("c3");
59
    }
60
61
    /**
62
     * Closes any precreated editors left open.
63
     */
64
    @Override
65
    protected void tearDown() {
66
        forceClose(c1);
67
        forceClose(c2);
68
        forceClose(c3);
69
    }
70
    
71
    /**
72
     * Test that verifies SHOW_REUSE closes original tab (keeps only one)
73
     * Scenario:
74
     * 1. Open first file with SHOW_REUSE
75
     * 2. Open second file with SHOW_REUSE
76
     * 3. Verify first is closed
77
     * 4. Open first file with SHOW_REUSE
78
     * 5. Verify second is closed
79
     */
80
    public void testReuse() {
81
        openAndCheck(c1, Line.SHOW_REUSE); // 1
82
        openAndCheck(c2, Line.SHOW_REUSE); // 2
83
        assertClosed(c1); // 3
84
        openAndCheck(c1, Line.SHOW_REUSE); // 4
85
        assertClosed(c2); // 5
86
    }
87
    
88
    /** Test that verifies SHOW_REUSE doesn't reuse modified, even saved tab
89
     * 1. Open first file with SHOW_REUSE
90
     * 2. Modify it
91
     * 3. Open second file with SHOW_REUSE
92
     * 4. Verify first still open
93
     * 5. Modify second file
94
     * 6. Unmodify second file
95
     * 7. Open third file with SHOW_REUSE
96
     * 8. Verify second still open
97
     */
98
    public void testKeepTouched() {
99
        openAndCheck(c1, Line.SHOW_REUSE); // 1
100
        c1.notifyModified(); // 2
101
        openAndCheck(c2, Line.SHOW_REUSE); // 3
102
        assertOpened(c1); // 4
103
        c2.notifyModified(); // 5
104
        c2.notifyUnmodified(); // 6
105
        openAndCheck(c3, Line.SHOW_REUSE); // 7
106
        assertOpened(c2); // 8
107
        assertOpened(c1);
108
    }
109
    
110
    /** Test that verifies SHOW_REUSE don't consider non-reusable tabs.
111
     * There are three things tested:
112
     * A) Don't replace ordinary tabs
113
     * B) Don't mark ordinary tabs as reusable if switched to
114
     * C) Keep reusable tab mark even through (B)
115
     * 
116
     * Scenario:
117
     * 1. Open first file using SHOW_GOTO
118
     * 2. Open second file using SHOW_REUSE
119
     * 3. Verify first still opened (A)
120
     * 4. open first using SHOW_REUSE
121
     * 5. verify second still opened
122
     * 6. open third file using SHOW_REUSE
123
     * 7. verify first still opened (B)
124
     * 8. verify second closed (C)
125
     */
126
    public void testLeaveNonreusable() {
127
        openAndCheck(c1, Line.SHOW_GOTO); // 1
128
        openAndCheck(c2, Line.SHOW_REUSE); // 2
129
        assertOpened(c1); // 3
130
        
131
        openAndCheck(c1, Line.SHOW_REUSE); // 4
132
        assertOpened(c2); // 5
133
        openAndCheck(c3, Line.SHOW_REUSE); // 6
134
        assertOpened(c1); // 7
135
        
136
        assertClosed(c2); // 8
137
    }
138
    
139
    /** Test that verifies SHOW_REUSE_NEW don't close existing reusable tab,
140
     * but can be reused itself
141
     * 
142
     * Scenario:
143
     * 1. Open first file using SHOW_REUSE
144
     * 2. Open second file using SHOW_REUSE_NEW
145
     * 3. Verify first still opened
146
     * 4. Open third using SHOW_REUSE
147
     * 5. verify second closed
148
     */
149
    public void testReuseNewKeepsOld() {
150
        openAndCheck(c1, Line.SHOW_REUSE); // 1
151
        openAndCheck(c2, Line.SHOW_REUSE_NEW); // 2
152
        assertOpened(c1); // 3
153
        openAndCheck(c3, Line.SHOW_REUSE); // 4
154
        assertClosed(c2); // 5
155
    }
156
157
    /**
158
     * Test that specifies behaviour of SHOW_REUSE_NEW in case currently
159
     * reusable tab is not the selected one.
160
     * 
161
     * Scenario:
162
     * 1. Open first file using SHOW_REUSE
163
     * 2. Open second file using SHOW_GOTO
164
     * 3. Open third file using SHOW_REUSE_NEW
165
     * 4. Verify first still open.
166
     */
167
    public void testReuseNewKeepsOldEvenWhenNotFocused() {
168
        openAndCheck(c1, Line.SHOW_REUSE); // 1
169
        openAndCheck(c2, Line.SHOW_GOTO); // 2
170
        openAndCheck(c3, Line.SHOW_REUSE_NEW); // 3
171
        assertOpened(c1); // 4
172
    }
173
     
174
    private CES createSupport(String txt) {
175
        Env env = new Env();
176
        env.content = txt;
177
        CES c = new CES(env, Lookups.singleton(txt));
178
        env.support = c;
179
        return c;
180
    }
181
    
182
    private void openAndCheck(final CES ces, final int mode) {
183
        Mutex.EVENT.readAccess(new Mutex.Action<Void>() {
184
            public Void run() {
185
                ces.getLineSet().getCurrent(0).show(mode);
186
                return null;
187
            }
188
189
        });
190
        assertOpened(ces);
191
    }
192
193
    private void forceClose(CES ces) {
194
        if (ces.isModified()) ces.notifyUnmodified();
195
        ces.close();
196
    }
197
198
    private void assertClosed(CES ces) {
199
        assertEquals(0, getOpenedCount(ces));
200
    }
201
202
    private void assertOpened(CES ces) {
203
        assertEquals(1, getOpenedCount(ces));
204
    }
205
206
    private int getOpenedCount(final CES ces) {
207
        return Mutex.EVENT.readAccess(new Mutex.Action<Integer>() {
208
            public Integer run() {
209
                JEditorPane[] panes = ces.getOpenedPanes();
210
                return panes == null ? 0 : panes.length;
211
            }
212
        });
213
    }
214
    
215
    
216
    
217
    //
218
    // Implementation of the CloneableEditorSupport.Env
219
    //
220
    private class Env implements CloneableEditorSupport.Env {
221
        // Env variables
222
        private String content = "";
223
        private boolean valid = true;
224
        private boolean modified = false;
225
        private java.util.Date date = new java.util.Date ();
226
        private List<PropertyChangeListener> propL = new ArrayList<PropertyChangeListener>();
227
        private java.beans.VetoableChangeListener vetoL;
228
        /** the support to work with */
229
        CloneableEditorSupport support;
230
231
        public synchronized void addPropertyChangeListener(PropertyChangeListener l) {
232
            propL.add (l);
233
        }    
234
        public synchronized void removePropertyChangeListener(PropertyChangeListener l) {
235
            propL.remove (l);
236
        }
237
238
        public synchronized void addVetoableChangeListener(java.beans.VetoableChangeListener l) {
239
            assertNull ("This is the first veto listener", vetoL);
240
            vetoL = l;
241
        }
242
        public void removeVetoableChangeListener(java.beans.VetoableChangeListener l) {
243
            assertEquals ("Removing the right veto one", vetoL, l);
244
            vetoL = null;
245
        }
246
    
247
        public org.openide.windows.CloneableOpenSupport findCloneableOpenSupport() {
248
            return support;
249
        }
250
    
251
        public String getMimeType() {
252
            return "text/plain";
253
        }
254
    
255
        public java.util.Date getTime() {
256
            return date;
257
        }
258
    
259
        public java.io.InputStream inputStream() throws java.io.IOException {
260
            return new java.io.ByteArrayInputStream (content.getBytes ());
261
        }
262
        public java.io.OutputStream outputStream() throws java.io.IOException {
263
            class ContentStream extends java.io.ByteArrayOutputStream {
264
                public void close () throws java.io.IOException {
265
                    super.close ();
266
                    content = new String (toByteArray ());
267
                }
268
            }
269
270
            return new ContentStream ();
271
        }
272
273
        public boolean isValid() {
274
            return valid;
275
        }
276
277
        public boolean isModified() {
278
            return modified;
279
        }
280
281
        public void markModified() throws java.io.IOException {
282
            modified = true;
283
        }
284
285
        public void unmarkModified() {
286
            modified = false;
287
        }
288
    }
289
    
290
    /** Implementation of the CES */
291
    private static final class CES extends CloneableEditorSupport {
292
        public CES (Env env, Lookup l) {
293
            super (env, l);
294
        }
295
        
296
        protected String messageName() {
297
            return "Name";
298
        }
299
        
300
        protected String messageOpened() {
301
            return "Opened";
302
        }
303
        
304
        protected String messageOpening() {
305
            return "Opening";
306
        }
307
        
308
        protected String messageSave() {
309
            return "Save";
310
        }
311
        
312
        protected String messageToolTip() {
313
            return "ToolTip";
314
        }
315
        
316
    }
317
318
}

Return to bug 94607