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 258798
Collapse All | Expand All

(-)a/editor.document/apichanges.xml (+16 lines)
Lines 112-117 Link Here
112
<!-- ACTUAL CHANGES BEGIN HERE: -->
112
<!-- ACTUAL CHANGES BEGIN HERE: -->
113
113
114
  <changes>
114
  <changes>
115
        <change id="CustomUndoDocument">
116
            <api name="api"/>
117
            <summary>CustomUndoDocument added</summary>
118
            <version major="1" minor="8"/>
119
            <date day="19" month="4" year="2016"/>
120
            <author login="mmetelka"/>
121
            <compatibility binary="compatible" source="compatible" semantic="compatible" addition="yes" deprecation="no" deletion="no" modification="no" />
122
            <description>
123
                <p>
124
                    CustomUndoDocument allows to add extra undoable edits during atomic transactions
125
                    over a document.
126
                </p>
127
            </description>
128
            <class name="CustomUndoDocument" package="org.netbeans.api.editor.document"/>
129
            <issue number="258798"/>
130
        </change>
115
      <change id="ShiftPositions">
131
      <change id="ShiftPositions">
116
          <api name="api"/>
132
          <api name="api"/>
117
          <summary>Added ShiftPositions</summary>
133
          <summary>Added ShiftPositions</summary>
(-)a/editor.document/manifest.mf (-1 / +1 lines)
Lines 1-4 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.netbeans.modules.editor.document
2
OpenIDE-Module: org.netbeans.modules.editor.document
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/editor/document/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/editor/document/Bundle.properties
4
OpenIDE-Module-Implementation-Version: 1
4
OpenIDE-Module-Implementation-Version: 2
(-)a/editor.document/nbproject/project.properties (-1 / +1 lines)
Lines 1-6 Link Here
1
javac.source=1.7
1
javac.source=1.7
2
javac.compilerargs=-Xlint -Xlint:-serial
2
javac.compilerargs=-Xlint -Xlint:-serial
3
spec.version.base=1.7.0
3
spec.version.base=1.8.0
4
javadoc.arch=${basedir}/arch.xml
4
javadoc.arch=${basedir}/arch.xml
5
javadoc.apichanges=${basedir}/apichanges.xml
5
javadoc.apichanges=${basedir}/apichanges.xml
6
is.autoload=true
6
is.autoload=true
(-)a/editor.document/src/org/netbeans/api/editor/document/CustomUndoDocument.java (+76 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2016 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2016 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.api.editor.document;
43
44
import javax.swing.undo.UndoableEdit;
45
46
/**
47
 * Document that allows adding of a custom undoable edit during atomic transaction.
48
 * <br/>
49
 * To obtain CustomUndoDocument instance the {@link LineDocumentUtils#as(javax.swing.text.Document, java.lang.Class) }
50
 * or {@link LineDocumentUtils#asRequired(javax.swing.text.Document, java.lang.Class) } may be used:
51
 * <code>
52
 * <pre>
53
 *   Document doc = ...
54
 *   CustomUndoDocument customUndoDoc = LineDocumentUtils.asRequired(doc, CustomUndoDocument.class);
55
 * </pre>
56
 * </code>
57
 *
58
 * @author Miloslav Metelka
59
 * @since 1.8
60
 */
61
public interface CustomUndoDocument {
62
    
63
    /**
64
     * Add a custom undoable edit to the undoable edits being created
65
     * during an atomic transaction over the document.
66
     * <br/>
67
     * For example editor caret may add an undo edit allowing to restore caret(s) positions
68
     * before (or after) modifications during the atomic lock.
69
     *
70
     * @param edit non-null undoable edit.
71
     * @throws IllegalStateException if the document is not under atomic lock.
72
     * @since 1.8
73
     */
74
    public void addUndoableEdit(UndoableEdit edit);
75
    
76
}
(-)a/editor.lib/src/org/netbeans/editor/BaseDocument.java (-1 / +2 lines)
Lines 86-91 Link Here
86
import javax.swing.undo.CannotRedoException;
86
import javax.swing.undo.CannotRedoException;
87
import javax.swing.undo.CannotUndoException;
87
import javax.swing.undo.CannotUndoException;
88
import javax.swing.undo.UndoableEdit;
88
import javax.swing.undo.UndoableEdit;
89
import org.netbeans.api.editor.document.CustomUndoDocument;
89
import org.netbeans.api.editor.document.LineDocument;
90
import org.netbeans.api.editor.document.LineDocument;
90
import org.netbeans.api.editor.mimelookup.MimeLookup;
91
import org.netbeans.api.editor.mimelookup.MimeLookup;
91
import org.netbeans.api.editor.mimelookup.MimePath;
92
import org.netbeans.api.editor.mimelookup.MimePath;
Lines 130-136 Link Here
130
*/
131
*/
131
132
132
@SuppressWarnings("ClassWithMultipleLoggers")
133
@SuppressWarnings("ClassWithMultipleLoggers")
133
public class BaseDocument extends AbstractDocument implements AtomicLockDocument, LineDocument {
134
public class BaseDocument extends AbstractDocument implements AtomicLockDocument, LineDocument, CustomUndoDocument {
134
135
135
    static {
136
    static {
136
        EditorPackageAccessor.register(new Accessor());
137
        EditorPackageAccessor.register(new Accessor());
(-)a/editor.lib/src/org/netbeans/editor/BaseKit.java (-50 / +11 lines)
Lines 105-110 Link Here
105
import org.netbeans.api.editor.caret.CaretInfo;
105
import org.netbeans.api.editor.caret.CaretInfo;
106
import org.netbeans.api.editor.EditorActionRegistration;
106
import org.netbeans.api.editor.EditorActionRegistration;
107
import org.netbeans.api.editor.EditorActionRegistrations;
107
import org.netbeans.api.editor.EditorActionRegistrations;
108
import org.netbeans.api.editor.EditorUtilities;
108
import org.netbeans.api.editor.caret.EditorCaret;
109
import org.netbeans.api.editor.caret.EditorCaret;
109
import org.netbeans.api.editor.mimelookup.MimeLookup;
110
import org.netbeans.api.editor.mimelookup.MimeLookup;
110
import org.netbeans.api.editor.mimelookup.MimePath;
111
import org.netbeans.api.editor.mimelookup.MimePath;
Lines 1170-1180 Link Here
1170
                                        boolean alreadyBeeped = false;
1171
                                        boolean alreadyBeeped = false;
1171
                                        DocumentUtilities.setTypingModification(doc, true);
1172
                                        DocumentUtilities.setTypingModification(doc, true);
1172
                                        try {
1173
                                        try {
1173
                                            // Store current state of caret(s) for undo
1174
                                            EditorUtilities.addCaretUndoableEdit(doc, caret);
1174
                                            UndoableEdit caretUndoEdit = CaretUndo.createCaretUndoEdit(caret, doc, false);
1175
                                            if (caretUndoEdit != null) {
1176
                                                doc.addUndoableEdit(caretUndoEdit);
1177
                                            }
1178
                                        for (CaretInfo c : carets) {
1175
                                        for (CaretInfo c : carets) {
1179
                                            if (c.isSelection()) { // valid selection
1176
                                            if (c.isSelection()) { // valid selection
1180
                                                int p0 = Math.min(c.getDot(), c.getMark());
1177
                                                int p0 = Math.min(c.getDot(), c.getMark());
Lines 1231-1241 Link Here
1231
                                                }
1228
                                                }
1232
                                            }
1229
                                            }
1233
                                        }
1230
                                        }
1234
                                            // Store current state of caret(s) for redo
1231
                                            EditorUtilities.addCaretUndoableEdit(doc, caret);
1235
                                            UndoableEdit caretRedoEdit = CaretUndo.createCaretUndoEdit(caret, doc, true);
1236
                                            if (caretRedoEdit != null) {
1237
                                                doc.addUndoableEdit(caretRedoEdit);
1238
                                            }
1239
1232
1240
                                        } finally {
1233
                                        } finally {
1241
                                            DocumentUtilities.setTypingModification(doc, false);
1234
                                            DocumentUtilities.setTypingModification(doc, false);
Lines 1262-1272 Link Here
1262
                                doc.runAtomicAsUser(new Runnable() {
1255
                                doc.runAtomicAsUser(new Runnable() {
1263
                                    public void run() {
1256
                                    public void run() {
1264
                                        boolean alreadyBeeped = false;
1257
                                        boolean alreadyBeeped = false;
1265
                                        // Store current state of caret(s) for undo
1258
                                        EditorUtilities.addCaretUndoableEdit(doc, caret);
1266
                                        UndoableEdit caretUndoEdit = CaretUndo.createCaretUndoEdit(caret, doc, false);
1267
                                        if (caretUndoEdit != null) {
1268
                                            doc.addUndoableEdit(caretUndoEdit);
1269
                                        }
1270
                                        if (target.getCaret().isSelectionVisible() && caret.getDot() != caret.getMark()) { // valid selection
1259
                                        if (target.getCaret().isSelectionVisible() && caret.getDot() != caret.getMark()) { // valid selection
1271
                                            EditorUI editorUI = Utilities.getEditorUI(target);
1260
                                            EditorUI editorUI = Utilities.getEditorUI(target);
1272
                                            Boolean overwriteMode = (Boolean) editorUI.getProperty(EditorUI.OVERWRITE_MODE_PROPERTY);
1261
                                            Boolean overwriteMode = (Boolean) editorUI.getProperty(EditorUI.OVERWRITE_MODE_PROPERTY);
Lines 1296-1306 Link Here
1296
                                                target.getToolkit().beep();
1285
                                                target.getToolkit().beep();
1297
                                            }
1286
                                            }
1298
                                        }
1287
                                        }
1299
                                        // Store current state of caret(s) for redo
1288
                                        EditorUtilities.addCaretUndoableEdit(doc, caret);
1300
                                        UndoableEdit caretRedoEdit = CaretUndo.createCaretUndoEdit(caret, doc, true);
1301
                                        if (caretRedoEdit != null) {
1302
                                            doc.addUndoableEdit(caretRedoEdit);
1303
                                        }
1304
                                    }
1289
                                    }
1305
                                });
1290
                                });
1306
1291
Lines 2021-2031 Link Here
2021
                            public void run() {
2006
                            public void run() {
2022
                                    boolean alreadyBeeped = false;
2007
                                    boolean alreadyBeeped = false;
2023
                                    DocumentUtilities.setTypingModification(doc, true);
2008
                                    DocumentUtilities.setTypingModification(doc, true);
2024
                                    // Store current state of caret(s) for undo
2009
                                    EditorUtilities.addCaretUndoableEdit(doc, caret);
2025
                                    UndoableEdit caretUndoEdit = CaretUndo.createCaretUndoEdit(caret, doc, false);
2026
                                    if (caretUndoEdit != null) {
2027
                                        doc.addUndoableEdit(caretUndoEdit);
2028
                                    }
2029
                                    try {
2010
                                    try {
2030
                                        for (CaretInfo c : carets) {
2011
                                        for (CaretInfo c : carets) {
2031
                                            if (c.isSelection()) {
2012
                                            if (c.isSelection()) {
Lines 2068-2078 Link Here
2068
                                                }
2049
                                                }
2069
                                            }
2050
                                            }
2070
                                        }
2051
                                        }
2071
                                        // Store current state of caret(s) for redo
2052
                                        EditorUtilities.addCaretUndoableEdit(doc, caret);
2072
                                        UndoableEdit caretRedoEdit = CaretUndo.createCaretUndoEdit(caret, doc, true);
2073
                                        if (caretRedoEdit != null) {
2074
                                            doc.addUndoableEdit(caretRedoEdit);
2075
                                        }
2076
2053
2077
                                    } finally {
2054
                                    } finally {
2078
                                        DocumentUtilities.setTypingModification(doc, false);
2055
                                        DocumentUtilities.setTypingModification(doc, false);
Lines 2093-2103 Link Here
2093
                    doc.runAtomicAsUser (new Runnable () {
2070
                    doc.runAtomicAsUser (new Runnable () {
2094
                        public void run () {
2071
                        public void run () {
2095
                            DocumentUtilities.setTypingModification(doc, true);
2072
                            DocumentUtilities.setTypingModification(doc, true);
2096
                            // Store current state of caret(s) for undo
2073
                            EditorUtilities.addCaretUndoableEdit(doc, caret);
2097
                            UndoableEdit caretUndoEdit = CaretUndo.createCaretUndoEdit(caret, doc, false);
2098
                            if (caretUndoEdit != null) {
2099
                                doc.addUndoableEdit(caretUndoEdit);
2100
                            }
2101
                            try {
2074
                            try {
2102
                                List<Position> dotAndMarkPosPairs = new ArrayList<>(2);
2075
                                List<Position> dotAndMarkPosPairs = new ArrayList<>(2);
2103
                                dotAndMarkPosPairs.add(doc.createPosition(caret.getDot()));
2076
                                dotAndMarkPosPairs.add(doc.createPosition(caret.getDot()));
Lines 2112-2122 Link Here
2112
                                } else {
2085
                                } else {
2113
                                    doc.remove(Math.min(dot, mark), Math.abs(dot - mark));
2086
                                    doc.remove(Math.min(dot, mark), Math.abs(dot - mark));
2114
                                }
2087
                                }
2115
                                // Store current state of caret(s) for redo
2088
                                EditorUtilities.addCaretUndoableEdit(doc, caret);
2116
                                UndoableEdit caretRedoEdit = CaretUndo.createCaretUndoEdit(caret, doc, true);
2117
                                if (caretRedoEdit != null) {
2118
                                    doc.addUndoableEdit(caretRedoEdit);
2119
                                }
2120
                            } catch (BadLocationException e) {
2089
                            } catch (BadLocationException e) {
2121
                                target.getToolkit().beep();
2090
                                target.getToolkit().beep();
2122
                            } finally {
2091
                            } finally {
Lines 2144-2154 Link Here
2144
                                doc.runAtomicAsUser (new Runnable () {
2113
                                doc.runAtomicAsUser (new Runnable () {
2145
                                    public void run () {
2114
                                    public void run () {
2146
                                        DocumentUtilities.setTypingModification(doc, true);
2115
                                        DocumentUtilities.setTypingModification(doc, true);
2147
                                        // Store current state of caret(s) for undo
2116
                                        EditorUtilities.addCaretUndoableEdit(doc, caret);
2148
                                        UndoableEdit caretUndoEdit = CaretUndo.createCaretUndoEdit(caret, doc, false);
2149
                                        if (caretUndoEdit != null) {
2150
                                            doc.addUndoableEdit(caretUndoEdit);
2151
                                        }
2152
                                        try {
2117
                                        try {
2153
                                            if (nextChar) { // remove next char
2118
                                            if (nextChar) { // remove next char
2154
                                                doc.remove(dot, 1);
2119
                                                doc.remove(dot, 1);
Lines 2170-2180 Link Here
2170
                                        } finally {
2135
                                        } finally {
2171
                                            DocumentUtilities.setTypingModification(doc, false);
2136
                                            DocumentUtilities.setTypingModification(doc, false);
2172
                                        }
2137
                                        }
2173
                                        // Store current state of caret(s) for redo
2138
                                        EditorUtilities.addCaretUndoableEdit(doc, caret);
2174
                                        UndoableEdit caretRedoEdit = CaretUndo.createCaretUndoEdit(caret, doc, true);
2175
                                        if (caretRedoEdit != null) {
2176
                                            doc.addUndoableEdit(caretRedoEdit);
2177
                                        }
2178
                                    }
2139
                                    }
2179
                                });
2140
                                });
2180
2141
(-)a/editor.lib2/apichanges.xml (+15 lines)
Lines 107-112 Link Here
107
    <!-- ACTUAL CHANGES BEGIN HERE: -->
107
    <!-- ACTUAL CHANGES BEGIN HERE: -->
108
108
109
    <changes>
109
    <changes>
110
        <change id="EditorUtilities.addCaretUndoableEdit">
111
            <summary>EditorUtilities.addCaretUndoableEdit added</summary>
112
            <version major="2" minor="10"/>
113
            <date day="19" month="4" year="2016"/>
114
            <author login="mmetelka"/>
115
            <compatibility binary="compatible" source="compatible" semantic="compatible" addition="yes" deprecation="no" deletion="no" modification="no" />
116
            <description>
117
                <p>
118
                    EditorUtilities.addCaretUndoableEdit allows actions to remember caret position
119
                    during an atomic transaction over a document.
120
                </p>
121
            </description>
122
            <class name="EditorUtilities" package="org.netbeans.api.editor"/>
123
            <issue number="258798"/>
124
        </change>
110
        <change id="StickyWindowSupport">
125
        <change id="StickyWindowSupport">
111
            <summary>Support for sticky windows in the editor</summary>
126
            <summary>Support for sticky windows in the editor</summary>
112
            <version major="2" minor="9"/>
127
            <version major="2" minor="9"/>
(-)a/editor.lib2/manifest.mf (-1 / +1 lines)
Lines 1-6 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.netbeans.modules.editor.lib2/1
2
OpenIDE-Module: org.netbeans.modules.editor.lib2/1
3
OpenIDE-Module-Implementation-Version: 45
3
OpenIDE-Module-Implementation-Version: 46
4
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/editor/lib2/Bundle.properties
4
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/editor/lib2/Bundle.properties
5
OpenIDE-Module-Layer: org/netbeans/modules/editor/lib2/resources/layer.xml
5
OpenIDE-Module-Layer: org/netbeans/modules/editor/lib2/resources/layer.xml
6
OpenIDE-Module-Needs: org.netbeans.modules.editor.actions
6
OpenIDE-Module-Needs: org.netbeans.modules.editor.actions
(-)a/editor.lib2/nbproject/project.properties (-1 / +1 lines)
Lines 43-49 Link Here
43
is.autoload=true
43
is.autoload=true
44
javac.source=1.7
44
javac.source=1.7
45
javac.compilerargs=-Xlint:unchecked
45
javac.compilerargs=-Xlint:unchecked
46
spec.version.base=2.9.0
46
spec.version.base=2.10.0
47
47
48
javadoc.arch=${basedir}/arch.xml
48
javadoc.arch=${basedir}/arch.xml
49
javadoc.apichanges=${basedir}/apichanges.xml
49
javadoc.apichanges=${basedir}/apichanges.xml
(-)a/editor.lib2/src/org/netbeans/api/editor/EditorUtilities.java (+40 lines)
Lines 45-51 Link Here
45
package org.netbeans.api.editor;
45
package org.netbeans.api.editor;
46
46
47
import javax.swing.Action;
47
import javax.swing.Action;
48
import javax.swing.text.Caret;
49
import javax.swing.text.Document;
48
import javax.swing.text.EditorKit;
50
import javax.swing.text.EditorKit;
51
import javax.swing.undo.UndoableEdit;
52
import org.netbeans.api.editor.document.AtomicLockDocument;
53
import org.netbeans.api.editor.document.CustomUndoDocument;
54
import org.netbeans.api.editor.document.LineDocumentUtils;
55
import org.netbeans.modules.editor.lib2.CaretUndo;
49
import org.netbeans.modules.editor.lib2.actions.EditorActionUtilities;
56
import org.netbeans.modules.editor.lib2.actions.EditorActionUtilities;
50
57
51
58
Lines 82-87 Link Here
82
        return EditorActionUtilities.getAction(editorKit, actionName);
89
        return EditorActionUtilities.getAction(editorKit, actionName);
83
    }
90
    }
84
91
92
    /**
93
     * Add an undoable edit describing current state of caret(s) during document's atomic section.
94
     * <br>
95
     * This method is typically called at the beginning of the atomic section over the document
96
     * so that a subsequent undo would restore original caret offsets that were not yet modified
97
     * by the actual changes performed during the atomic section.
98
     * <br>
99
     * The method may also be called at the end of the atomic section
100
     * in case the atomic section performed explicit caret movements.
101
     * <br>
102
     * The created undoable edit will be added to document's compound undoable edit created for the atomic section.
103
     * That edit will be fired by the document to an undo manager's listener upon completion of the atomic section.
104
     * Therefore the document should adhere to {@link CustomUndoDocument} otherwise the method would do nothing.
105
     *
106
     * @param doc document to which the created undoable edit will be added.
107
     *   Null may be passed then the method has no effect.
108
     * @param caret non-null caret which state should be stored
109
     * @see CustomUndoDocument
110
     * @see AtomicLockDocument
111
     * @throws IllegalStateException if this method is called outside of an atomic section.
112
     * @since 2.10
113
     */
114
    public static void addCaretUndoableEdit(Document doc, Caret caret) {
115
        CustomUndoDocument customUndoDocument = LineDocumentUtils.as(doc, CustomUndoDocument.class);
116
        if (customUndoDocument != null) {
117
            UndoableEdit caretUndoEdit = CaretUndo.createCaretUndoEdit(caret, doc);
118
            if (caretUndoEdit != null) {
119
                customUndoDocument.addUndoableEdit(caretUndoEdit);
120
            } // Might be null if caret is not installed in a text component and its document
121
        }
122
    }
123
    
124
85
//    /**
125
//    /**
86
//     * Reset caret's magic position.
126
//     * Reset caret's magic position.
87
//     * @param component target text component.
127
//     * @param component target text component.
(-)a/editor.lib2/src/org/netbeans/modules/editor/lib2/CaretUndo.java (-11 / +11 lines)
Lines 61-77 Link Here
61
    /**
61
    /**
62
     * Create undoable edit that returns caret to its original state when the edit is undone.
62
     * Create undoable edit that returns caret to its original state when the edit is undone.
63
     * <br/>
63
     * <br/>
64
     * This edit is typically created both at the begining of an action that does some document modifications
64
     * This edit is typically created both at the begining and end of an action that does some document modifications.
65
     * for purpose of undo and at its end for redo purpose.
66
     *
65
     *
67
     * @param caret non-null caret.
66
     * @param caret non-null caret.
68
     * @param doc non-null document to which the undoable edit will be added.
67
     * @param doc non-null document to which the undoable edit will be added.
69
     * @param forRedo whether the edit is created for undo purpose (at action's begining) or for redo purpose
70
     *  (at action's end).
71
     * @return edit allowing to restore caret state upon undo call on the returned edit or null
68
     * @return edit allowing to restore caret state upon undo call on the returned edit or null
72
     *  if caret is not installed in a valid document.
69
     *  if caret is not installed in a valid document.
70
     *  <br>
71
     *  Future optimizations may return null edit also in case when there was no change in carets
72
     *  since the preceding call to this method inside the same atomic transaction over the document.
73
     */
73
     */
74
    public static UndoableEdit createCaretUndoEdit(@NonNull Caret caret, @NonNull Document doc, boolean forRedo) {
74
    public static UndoableEdit createCaretUndoEdit(@NonNull Caret caret, @NonNull Document doc) {
75
        UndoableEdit ret;
75
        UndoableEdit ret;
76
        if (caret instanceof EditorCaret) {
76
        if (caret instanceof EditorCaret) {
77
            EditorCaret eCaret = (EditorCaret) caret;
77
            EditorCaret eCaret = (EditorCaret) caret;
Lines 92-103 Link Here
92
                if (caretsSize == 1) { // Single-caret case
92
                if (caretsSize == 1) { // Single-caret case
93
                    if (!complexPos) { // Regular positions
93
                    if (!complexPos) { // Regular positions
94
                        if (dotOffset == markOffset) { // No selection
94
                        if (dotOffset == markOffset) { // No selection
95
                            ret = new CaretUndoEdit(doc, forRedo, dotOffset);
95
                            ret = new CaretUndoEdit(doc, dotOffset);
96
                        } else { // Selection
96
                        } else { // Selection
97
                            ret = new CaretUndoEdit.ComplexEdit(doc, forRedo, dotOffset, markOffset, null);
97
                            ret = new CaretUndoEdit.ComplexEdit(doc, dotOffset, markOffset, null);
98
                        }
98
                        }
99
                    } else { // Complex positions
99
                    } else { // Complex positions
100
                        ret = new CaretUndoEdit.ComplexEdit(doc, forRedo, dotOffset, -1, new int[] {
100
                        ret = new CaretUndoEdit.ComplexEdit(doc, dotOffset, -1, new int[] {
101
                            dotSplitOffset, markOffset, markSplitOffset
101
                            dotSplitOffset, markOffset, markSplitOffset
102
                        });
102
                        });
103
                    }
103
                    }
Lines 155-161 Link Here
155
                        offsets[i++] = ShiftPositions.getShift(dotPos);
155
                        offsets[i++] = ShiftPositions.getShift(dotPos);
156
                        offsets[i++] = ShiftPositions.getShift(markPos);
156
                        offsets[i++] = ShiftPositions.getShift(markPos);
157
                    }
157
                    }
158
                    ret = new CaretUndoEdit.ComplexEdit(doc, forRedo, dotOffset, markOffset, offsets);
158
                    ret = new CaretUndoEdit.ComplexEdit(doc, dotOffset, markOffset, offsets);
159
                }
159
                }
160
160
161
            } else { // dotPos == null => return null edit
161
            } else { // dotPos == null => return null edit
Lines 166-174 Link Here
166
            int dotOffset = caret.getDot();
166
            int dotOffset = caret.getDot();
167
            int markOffset = caret.getMark();
167
            int markOffset = caret.getMark();
168
            if (markOffset != dotOffset) {
168
            if (markOffset != dotOffset) {
169
                ret = new CaretUndoEdit.ComplexEdit(doc, forRedo, dotOffset, markOffset, null);
169
                ret = new CaretUndoEdit.ComplexEdit(doc, dotOffset, markOffset, null);
170
            } else {
170
            } else {
171
                ret = new CaretUndoEdit(doc, forRedo, dotOffset);
171
                ret = new CaretUndoEdit(doc, dotOffset);
172
            }
172
            }
173
        }
173
        }
174
        return ret;
174
        return ret;
(-)a/editor.lib2/src/org/netbeans/modules/editor/lib2/CaretUndoEdit.java (-42 / +24 lines)
Lines 63-70 Link Here
63
 */
63
 */
64
class CaretUndoEdit extends AbstractUndoableEdit {
64
class CaretUndoEdit extends AbstractUndoableEdit {
65
    
65
    
66
    private static final int FOR_REDO_BIT = (1 << 31);
67
68
    final Document doc; // (16=super)+4=20 bytes
66
    final Document doc; // (16=super)+4=20 bytes
69
    
67
    
70
    /**
68
    /**
Lines 72-78 Link Here
72
     */
70
     */
73
    private int dotOffset; // 24 bytes
71
    private int dotOffset; // 24 bytes
74
    
72
    
75
    CaretUndoEdit(Document doc, boolean forRedo, int dotOffset) {
73
    CaretUndoEdit(Document doc, int dotOffset) {
76
        if (doc == null) {
74
        if (doc == null) {
77
            throw new IllegalArgumentException("doc parameter must not be null"); // NOI18N
75
            throw new IllegalArgumentException("doc parameter must not be null"); // NOI18N
78
        }
76
        }
Lines 80-133 Link Here
80
            throw new IllegalStateException("Negative dotOffset=" + dotOffset + " not supported here"); // NOI18N
78
            throw new IllegalStateException("Negative dotOffset=" + dotOffset + " not supported here"); // NOI18N
81
        }
79
        }
82
        this.doc = doc;
80
        this.doc = doc;
83
        this.dotOffset = forRedo ? (FOR_REDO_BIT | dotOffset) : dotOffset;
81
        this.dotOffset = dotOffset;
84
    }
82
    }
85
83
86
    @Override
84
    @Override
87
    public void undo() throws CannotUndoException {
85
    public void undo() throws CannotUndoException {
88
        super.undo();
86
        super.undo();
89
        if (!isForRedo()) {
87
        restoreCaret();
90
            JTextComponent c = EditorRegistry.findComponent(doc);
91
            if (c != null) {
92
                Caret caret = c.getCaret();
93
                if (caret instanceof EditorCaret) {
94
                    try {
95
                        restoreEditorCaret((EditorCaret) caret);
96
                    } catch (BadLocationException ex) {
97
                        // Ignore caret restoration
98
                    }
99
                } else {
100
                    restoreLegacyCaret(caret);
101
                }
102
            }
103
        }
104
    }
88
    }
105
    
89
    
106
    @Override
90
    @Override
107
    public void redo() throws CannotRedoException {
91
    public void redo() throws CannotRedoException {
108
        super.redo();
92
        super.redo();
109
        if (isForRedo()) {
93
        restoreCaret();
110
            JTextComponent c = EditorRegistry.findComponent(doc);
111
            if (c != null) {
112
                Caret caret = c.getCaret();
113
                if (caret instanceof EditorCaret) {
114
                    try {
115
                        restoreEditorCaret((EditorCaret) caret);
116
                    } catch (BadLocationException ex) {
117
                        // Ignore caret restoration
118
                    }
119
                } else {
120
                    restoreLegacyCaret(caret);
121
                }
122
            }
123
        }
124
    }
94
    }
125
95
    
126
    @Override
96
    @Override
127
    public boolean isSignificant() {
97
    public boolean isSignificant() {
128
        return super.isSignificant();
98
        return super.isSignificant();
129
    }
99
    }
130
    
100
    
101
    private void restoreCaret() {
102
        JTextComponent c = EditorRegistry.findComponent(doc);
103
        if (c != null) {
104
            Caret caret = c.getCaret();
105
            if (caret instanceof EditorCaret) {
106
                try {
107
                    restoreEditorCaret((EditorCaret) caret);
108
                } catch (BadLocationException ex) {
109
                    // Ignore caret restoration
110
                }
111
            } else {
112
                restoreLegacyCaret(caret);
113
            }
114
        }
115
    }
116
131
    protected void restoreEditorCaret(EditorCaret caret) throws BadLocationException {
117
    protected void restoreEditorCaret(EditorCaret caret) throws BadLocationException {
132
        Position dotPos = doc.createPosition(getDotOffset());
118
        Position dotPos = doc.createPosition(getDotOffset());
133
        caret.replaceCarets(Arrays.asList(dotPos, dotPos));
119
        caret.replaceCarets(Arrays.asList(dotPos, dotPos));
Lines 137-148 Link Here
137
        caret.setDot(getDotOffset());
123
        caret.setDot(getDotOffset());
138
    }
124
    }
139
125
140
    boolean isForRedo() {
141
        return (dotOffset & FOR_REDO_BIT) != 0;
142
    }
143
    
144
    int getDotOffset() {
126
    int getDotOffset() {
145
        return (dotOffset & ~FOR_REDO_BIT);
127
        return dotOffset;
146
    }
128
    }
147
129
148
    static final class ComplexEdit extends CaretUndoEdit {
130
    static final class ComplexEdit extends CaretUndoEdit {
Lines 157-164 Link Here
157
        
139
        
158
        int[] extraDotAndMarkOffsets; // 32 bytes
140
        int[] extraDotAndMarkOffsets; // 32 bytes
159
        
141
        
160
        ComplexEdit(Document doc, boolean forRedo, int dotOffset, int markOffset, int[] extraDotAndMarkOffsets) {
142
        ComplexEdit(Document doc, int dotOffset, int markOffset, int[] extraDotAndMarkOffsets) {
161
            super(doc, forRedo, dotOffset);
143
            super(doc, dotOffset);
162
            this.markOffset = markOffset;
144
            this.markOffset = markOffset;
163
            this.extraDotAndMarkOffsets = extraDotAndMarkOffsets;
145
            this.extraDotAndMarkOffsets = extraDotAndMarkOffsets;
164
        }
146
        }
(-)a/editor.lib2/test/unit/src/org/netbeans/api/editor/EditorUtilitiesTest.java (+31 lines)
Lines 43-52 Link Here
43
package org.netbeans.api.editor;
43
package org.netbeans.api.editor;
44
44
45
import javax.swing.Action;
45
import javax.swing.Action;
46
import javax.swing.JEditorPane;
47
import javax.swing.SwingUtilities;
46
import javax.swing.text.DefaultEditorKit;
48
import javax.swing.text.DefaultEditorKit;
49
import javax.swing.text.Document;
47
import javax.swing.text.EditorKit;
50
import javax.swing.text.EditorKit;
51
import javax.swing.undo.CompoundEdit;
52
import javax.swing.undo.UndoableEdit;
48
import org.junit.Test;
53
import org.junit.Test;
49
import static org.junit.Assert.*;
54
import static org.junit.Assert.*;
55
import org.netbeans.api.editor.caret.EditorCaret;
56
import org.netbeans.api.editor.document.CustomUndoDocument;
50
57
51
/**
58
/**
52
 *
59
 *
Lines 71-74 Link Here
71
        fail("Action " + actionName + " not found.");
78
        fail("Action " + actionName + " not found.");
72
    }
79
    }
73
80
81
    @Test
82
    public void testAddCaretUndoableEdit() throws Exception {
83
        final JEditorPane pane = new JEditorPane("text/plain", "Haf");
84
        //final CompoundEdit compoundEdit = new CompoundEdit();
85
        final boolean[] editAdded = { false };
86
        final Document doc = pane.getDocument();
87
        doc.putProperty(CustomUndoDocument.class, new CustomUndoDocument() {
88
            @Override
89
            public void addUndoableEdit(UndoableEdit edit) {
90
                editAdded[0] = true;
91
            }
92
        });
93
        final EditorCaret editorCaret = new EditorCaret();
94
        SwingUtilities.invokeAndWait(new Runnable() {
95
            @Override
96
            public void run() {
97
                pane.setCaret(editorCaret);
98
                EditorUtilities.addCaretUndoableEdit(doc, editorCaret);
99
            }
100
        });
101
        
102
        assertTrue(editAdded[0]);
103
    }
104
74
}
105
}

Return to bug 258798