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

(-)a/editor.lib/nbproject/project.properties (-1 / +1 lines)
Lines 42-48 Link Here
42
42
43
javac.compilerargs=-Xlint:unchecked
43
javac.compilerargs=-Xlint:unchecked
44
javac.source=1.7
44
javac.source=1.7
45
spec.version.base=4.5.0
45
spec.version.base=4.6.0
46
is.autoload=true
46
is.autoload=true
47
47
48
javadoc.arch=${basedir}/arch.xml
48
javadoc.arch=${basedir}/arch.xml
(-)a/editor.lib/src/org/netbeans/editor/BaseKit.java (-9 / +26 lines)
Lines 122-127 Link Here
122
import org.netbeans.modules.editor.lib.KitsTracker;
122
import org.netbeans.modules.editor.lib.KitsTracker;
123
import org.netbeans.api.editor.NavigationHistory;
123
import org.netbeans.api.editor.NavigationHistory;
124
import org.netbeans.api.editor.caret.CaretMoveContext;
124
import org.netbeans.api.editor.caret.CaretMoveContext;
125
import org.netbeans.api.editor.caret.MoveCaretsOrigin;
125
import org.netbeans.spi.editor.caret.CaretMoveHandler;
126
import org.netbeans.spi.editor.caret.CaretMoveHandler;
126
import org.netbeans.lib.editor.util.swing.PositionRegion;
127
import org.netbeans.lib.editor.util.swing.PositionRegion;
127
import org.netbeans.modules.editor.lib.SettingsConversions;
128
import org.netbeans.modules.editor.lib.SettingsConversions;
Lines 2551-2557 Link Here
2551
                                }
2552
                                }
2552
                            }
2553
                            }
2553
                        }
2554
                        }
2554
                    });
2555
                    }, new MoveCaretsOrigin(
2556
                            MoveCaretsOrigin.DIRECT_NAVIGATION, SwingConstants.NORTH)
2557
                    );
2555
                } else {
2558
                } else {
2556
                try {
2559
                try {
2557
                    int dot = caret.getDot();
2560
                    int dot = caret.getDot();
Lines 2643-2649 Link Here
2643
                                }
2646
                                }
2644
                            }
2647
                            }
2645
                        }
2648
                        }
2646
                    });
2649
                    }, new MoveCaretsOrigin(
2650
                            MoveCaretsOrigin.DIRECT_NAVIGATION, SwingConstants.SOUTH)
2651
                    );
2647
                } else {
2652
                } else {
2648
                try {
2653
                try {
2649
                    int dot = caret.getDot();
2654
                    int dot = caret.getDot();
Lines 2785-2790 Link Here
2785
                                        }
2790
                                        }
2786
2791
2787
                                        // Update magic caret position
2792
                                        // Update magic caret position
2793
                                        newCaretBounds = target.modelToView(caretInfo.getDot());
2788
                                        magicCaretPosition.y = newCaretBounds.y;
2794
                                        magicCaretPosition.y = newCaretBounds.y;
2789
                                        context.setMagicCaretPosition(caretInfo, magicCaretPosition);
2795
                                        context.setMagicCaretPosition(caretInfo, magicCaretPosition);
2790
                                    }
2796
                                    }
Lines 2792-2798 Link Here
2792
                                    target.getToolkit().beep();
2798
                                    target.getToolkit().beep();
2793
                                }
2799
                                }
2794
                            }
2800
                            }
2795
                        });
2801
                        }, new MoveCaretsOrigin(
2802
                            MoveCaretsOrigin.DIRECT_NAVIGATION, SwingConstants.NORTH)
2803
                        );
2796
                    } else {
2804
                    } else {
2797
                    int caretOffset = caret.getDot();
2805
                    int caretOffset = caret.getDot();
2798
                    Rectangle caretBounds = ((BaseTextUI)target.getUI()).modelToView(target, caretOffset);
2806
                    Rectangle caretBounds = ((BaseTextUI)target.getUI()).modelToView(target, caretOffset);
Lines 2929-2935 Link Here
2929
                                    }
2937
                                    }
2930
                                }
2938
                                }
2931
                            }
2939
                            }
2932
                        });
2940
                        }, new MoveCaretsOrigin(
2941
                            MoveCaretsOrigin.DIRECT_NAVIGATION, SwingConstants.EAST)
2942
                        );
2933
                    }
2943
                    }
2934
                } else {
2944
                } else {
2935
                try {
2945
                try {
Lines 3073-3079 Link Here
3073
                                    target.getToolkit().beep();
3083
                                    target.getToolkit().beep();
3074
                                }
3084
                                }
3075
                            }
3085
                            }
3076
                        });
3086
                        }, new MoveCaretsOrigin(
3087
                            MoveCaretsOrigin.DIRECT_NAVIGATION, SwingConstants.SOUTH)
3088
                        );
3077
                    } else {
3089
                    } else {
3078
                    int caretOffset = caret.getDot();
3090
                    int caretOffset = caret.getDot();
3079
                    Rectangle caretBounds = ((BaseTextUI)target.getUI()).modelToView(target, caretOffset);
3091
                    Rectangle caretBounds = ((BaseTextUI)target.getUI()).modelToView(target, caretOffset);
Lines 3205-3211 Link Here
3205
                                    }
3217
                                    }
3206
                                }
3218
                                }
3207
                            }
3219
                            }
3208
                        });
3220
                        }, new MoveCaretsOrigin(
3221
                            MoveCaretsOrigin.DIRECT_NAVIGATION, SwingConstants.WEST)
3222
                        );
3209
                    }
3223
                    }
3210
                } else {
3224
                } else {
3211
                    try {
3225
                    try {
Lines 3343-3349 Link Here
3343
                                }
3357
                                }
3344
                            }
3358
                            }
3345
                        }
3359
                        }
3346
                    });
3360
                    }, new MoveCaretsOrigin(
3361
                            MoveCaretsOrigin.DIRECT_NAVIGATION, SwingConstants.WEST)
3362
                    );
3347
                } else {
3363
                } else {
3348
                try {
3364
                try {
3349
                    int dot = caret.getDot();
3365
                    int dot = caret.getDot();
Lines 3470-3477 Link Here
3470
                                }
3486
                                }
3471
                            }
3487
                            }
3472
                        }
3488
                        }
3473
                    });
3489
                    }, new MoveCaretsOrigin(
3474
                    
3490
                            MoveCaretsOrigin.DIRECT_NAVIGATION, SwingConstants.EAST)
3491
                    );
3475
                } else {
3492
                } else {
3476
                try {
3493
                try {
3477
                    // #232675: if bounds are defined, use them rather than line start/end
3494
                    // #232675: if bounds are defined, use them rather than line start/end
(-)a/editor.lib2/apichanges.xml (+24 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="editor-caret-filters">
111
            <summary>Support for Navigation Filters, and caret move origins</summary>
112
            <version major="2" minor="9"/>
113
            <date day="14" month="4" year="2016"/>
114
            <author login="sdedic"/>
115
            <compatibility binary="compatible" semantic="compatible" source="compatible" addition="yes" deprecation="no" deletion="no"/>
116
            <description>
117
                <p>
118
                    Swing NavigationFilters implemented on top of the Caret API. Caret API caller may describe the operation which causes
119
                    the caret to be moved, so that filters and caret listeners can react on specific action groups.
120
                </p>
121
                <p>
122
                    A boilerplate NavigationFilter is provided, that supports chaining of filters on the caret
123
                </p>
124
            </description>
125
            <class name="CaretMoveContext" package="org.netbeans.api.editor.caret"/>
126
            <class name="EditorCaret" package="org.netbeans.api.editor.caret"/>
127
            <class name="EditorCaretEvent" package="org.netbeans.api.editor.caret"/>
128
            <class name="MoveCaretsOrigin" package="org.netbeans.api.editor.caret"/>
129
            <class name="NavigationFilterBypass" package="org.netbeans.spi.editor.caret"/>
130
            <class name="CascadingNavigationFilter" package="org.netbeans.spi.editor.caret"/>
131
            
132
            <issue number="555555555"/>
133
        </change>
110
        <change id="editor-registry-find-component">
134
        <change id="editor-registry-find-component">
111
            <summary>Added EditorRegistry.findComponent</summary>
135
            <summary>Added EditorRegistry.findComponent</summary>
112
            <version major="2" minor="8"/>
136
            <version major="2" minor="8"/>
(-)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.8.0
46
spec.version.base=2.9.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/caret/CaretMoveContext.java (-5 / +20 lines)
Lines 45-55 Link Here
45
import java.util.List;
45
import java.util.List;
46
import javax.swing.text.Document;
46
import javax.swing.text.Document;
47
import javax.swing.text.JTextComponent;
47
import javax.swing.text.JTextComponent;
48
import javax.swing.text.NavigationFilter;
48
import javax.swing.text.Position;
49
import javax.swing.text.Position;
49
import org.netbeans.api.annotations.common.NonNull;
50
import org.netbeans.api.annotations.common.NonNull;
50
51
51
/**
52
/**
52
 * Context for carets moving within {@link CaretMoveHandler}.
53
 * Context for carets moving within {@link org.netbeans.spi.editor.caret.CaretMoveHandler}.
53
 *
54
 *
54
 * @author Miloslav Metelka
55
 * @author Miloslav Metelka
55
 * @since 2.6
56
 * @since 2.6
Lines 113-131 Link Here
113
     *  or true otherwise.
114
     *  or true otherwise.
114
     */
115
     */
115
    public boolean setDot(@NonNull CaretInfo caret, @NonNull Position dotPos) {
116
    public boolean setDot(@NonNull CaretInfo caret, @NonNull Position dotPos) {
116
        return setDotAndMark(caret, dotPos, dotPos);
117
        NavigationFilter naviFilter = transaction.getCaret().getNavigationFilterNoDefault(transaction.getOrigin());
118
        if (naviFilter != null) {
119
            FilterBypassImpl fbi = new FilterBypassImpl(transaction, caret, transaction.getDocument());
120
            naviFilter.setDot(fbi, dotPos.getOffset(), Position.Bias.Forward);
121
            return fbi.getResult();
122
        } else {
123
            return setDotAndMark(caret, dotPos, dotPos);
124
        }
117
    }
125
    }
118
    
126
    
119
    /**
127
    /**
120
     * Move dot of the given getCaret so getCaret selection gets created or changed.
128
     * Move dot of the given getCaret so getCaret selection gets created or changed.
121
     *
129
     *
122
     * @param caret non-null getCaret.
130
     * @param caret Nebnon-null getCaret.
123
     * @param dotPos new dot position.
131
     * @param dotPos new dot position.
124
     * @return false if passed caret is obsolete or invalid (e.g. a member of another {@link EditorCaret})
132
     * @return false if passed caret is obsolete or invalid (e.g. a member of another {@link EditorCaret})
125
     *  or true otherwise.
133
     *  or true otherwise.
126
     */
134
     */
127
    public boolean moveDot(@NonNull CaretInfo caret, @NonNull Position dotPos) {
135
    public boolean moveDot(@NonNull CaretInfo caret, @NonNull Position dotPos) {
128
        return transaction.moveDot(caret.getCaretItem(), dotPos);
136
        NavigationFilter naviFilter = transaction.getCaret().getNavigationFilterNoDefault(transaction.getOrigin());
137
        if (naviFilter != null) {
138
            FilterBypassImpl fbi = new FilterBypassImpl(transaction, caret, transaction.getDocument());
139
            naviFilter.moveDot(fbi, dotPos.getOffset(), Position.Bias.Forward);
140
            return fbi.getResult();
141
        } else {
142
            return transaction.moveDot(caret.getCaretItem(), dotPos);
143
        }
129
    }
144
    }
130
    
145
    
131
    /**
146
    /**
Lines 172-176 Link Here
172
    public Document getDocument() {
187
    public Document getDocument() {
173
        return getComponent().getDocument();
188
        return getComponent().getDocument();
174
    }
189
    }
175
190
    
176
}
191
}
(-)a/editor.lib2/src/org/netbeans/api/editor/caret/CaretTransaction.java (-1 / +7 lines)
Lines 119-130 Link Here
119
    
119
    
120
    private boolean fullResort;
120
    private boolean fullResort;
121
    
121
    
122
    private final MoveCaretsOrigin origin;
122
    
123
    
123
    CaretTransaction(EditorCaret caret, JTextComponent component, Document doc) {
124
    CaretTransaction(EditorCaret caret, JTextComponent component, Document doc, MoveCaretsOrigin origin) {
124
        this.editorCaret = caret;
125
        this.editorCaret = caret;
125
        this.component = component;
126
        this.component = component;
126
        this.doc = doc;
127
        this.doc = doc;
127
        this.origCaretItems = editorCaret.getCaretItems();
128
        this.origCaretItems = editorCaret.getCaretItems();
129
        this.origin = origin;
128
    }
130
    }
129
    
131
    
130
132
Lines 265-270 Link Here
265
        // Current impl ignores possible replaceItems content - see getOriginalCarets()
267
        // Current impl ignores possible replaceItems content - see getOriginalCarets()
266
        return editorCaret.getSortedCarets();
268
        return editorCaret.getSortedCarets();
267
    }
269
    }
270
    
271
    MoveCaretsOrigin getOrigin() {
272
        return origin;
273
    }
268
274
269
    void replaceCarets(RemoveType removeType, int offset, CaretItem[] addCaretItems) {
275
    void replaceCarets(RemoveType removeType, int offset, CaretItem[] addCaretItems) {
270
        int size = origCaretItems.size();
276
        int size = origCaretItems.size();
(-)a/editor.lib2/src/org/netbeans/api/editor/caret/EditorCaret.java (-14 / +282 lines)
Lines 41-46 Link Here
41
 */
41
 */
42
package org.netbeans.api.editor.caret;
42
package org.netbeans.api.editor.caret;
43
43
44
import org.netbeans.spi.editor.caret.CascadingNavigationFilter;
44
import org.netbeans.spi.editor.caret.CaretMoveHandler;
45
import org.netbeans.spi.editor.caret.CaretMoveHandler;
45
import java.awt.AlphaComposite;
46
import java.awt.AlphaComposite;
46
import java.awt.BasicStroke;
47
import java.awt.BasicStroke;
Lines 76-82 Link Here
76
import java.beans.PropertyChangeListener;
77
import java.beans.PropertyChangeListener;
77
import java.io.IOException;
78
import java.io.IOException;
78
import java.util.ArrayList;
79
import java.util.ArrayList;
80
import java.util.HashMap;
79
import java.util.List;
81
import java.util.List;
82
import java.util.Map;
80
import java.util.concurrent.Callable;
83
import java.util.concurrent.Callable;
81
import java.util.logging.Level;
84
import java.util.logging.Level;
82
import java.util.logging.Logger;
85
import java.util.logging.Logger;
Lines 103-112 Link Here
103
import javax.swing.text.Document;
106
import javax.swing.text.Document;
104
import javax.swing.text.Element;
107
import javax.swing.text.Element;
105
import javax.swing.text.JTextComponent;
108
import javax.swing.text.JTextComponent;
109
import javax.swing.text.NavigationFilter;
106
import javax.swing.text.Position;
110
import javax.swing.text.Position;
107
import javax.swing.text.StyleConstants;
111
import javax.swing.text.StyleConstants;
108
import org.netbeans.api.annotations.common.CheckForNull;
112
import org.netbeans.api.annotations.common.CheckForNull;
109
import org.netbeans.api.annotations.common.NonNull;
113
import org.netbeans.api.annotations.common.NonNull;
114
import org.netbeans.api.annotations.common.NullAllowed;
110
import org.netbeans.api.editor.EditorUtilities;
115
import org.netbeans.api.editor.EditorUtilities;
111
import org.netbeans.api.editor.document.AtomicLockDocument;
116
import org.netbeans.api.editor.document.AtomicLockDocument;
112
import org.netbeans.api.editor.document.AtomicLockEvent;
117
import org.netbeans.api.editor.document.AtomicLockEvent;
Lines 133-139 Link Here
133
import org.netbeans.modules.editor.lib2.view.ViewHierarchyEvent;
138
import org.netbeans.modules.editor.lib2.view.ViewHierarchyEvent;
134
import org.netbeans.modules.editor.lib2.view.ViewHierarchyListener;
139
import org.netbeans.modules.editor.lib2.view.ViewHierarchyListener;
135
import org.netbeans.modules.editor.lib2.view.ViewUtils;
140
import org.netbeans.modules.editor.lib2.view.ViewUtils;
141
import org.netbeans.spi.editor.caret.NavigationFilterBypass;
136
import org.openide.util.Exceptions;
142
import org.openide.util.Exceptions;
143
import org.openide.util.Parameters;
137
import org.openide.util.WeakListeners;
144
import org.openide.util.WeakListeners;
138
145
139
/**
146
/**
Lines 159-164 Link Here
159
    // Temporary until rectangular selection gets ported to multi-caret support
166
    // Temporary until rectangular selection gets ported to multi-caret support
160
    private static final String RECTANGULAR_SELECTION_PROPERTY = "rectangular-selection"; // NOI18N
167
    private static final String RECTANGULAR_SELECTION_PROPERTY = "rectangular-selection"; // NOI18N
161
    private static final String RECTANGULAR_SELECTION_REGIONS_PROPERTY = "rectangular-selection-regions"; // NOI18N
168
    private static final String RECTANGULAR_SELECTION_REGIONS_PROPERTY = "rectangular-selection-regions"; // NOI18N
169
    private static final String NAVIGATION_FILTER_PROPERTY = EditorCaret.class.getName() + ".navigationFilters"; // NOI18N
170
    private static final String CHAIN_FILTER_PROPERTY = EditorCaret.class.getName() + ".chainFilter"; // NOI18N
162
    
171
    
163
    // -J-Dorg.netbeans.api.editor.caret.EditorCaret.level=FINEST
172
    // -J-Dorg.netbeans.api.editor.caret.EditorCaret.level=FINEST
164
    private static final Logger LOG = Logger.getLogger(EditorCaret.class.getName());
173
    private static final Logger LOG = Logger.getLogger(EditorCaret.class.getName());
Lines 371-377 Link Here
371
     * with the same cursor.
380
     * with the same cursor.
372
     */
381
     */
373
    private boolean showingTextCursor = true;
382
    private boolean showingTextCursor = true;
374
    
383
375
    public EditorCaret() {
384
    public EditorCaret() {
376
        caretItems = new GapList<>();
385
        caretItems = new GapList<>();
377
        sortedCaretItems = new GapList<>();
386
        sortedCaretItems = new GapList<>();
Lines 504-509 Link Here
504
     * @see Caret#setDot(int) 
513
     * @see Caret#setDot(int) 
505
     */
514
     */
506
    public @Override void setDot(final int offset) {
515
    public @Override void setDot(final int offset) {
516
        setDot(offset, MoveCaretsOrigin.DEFAULT);
517
    }
518
519
    /**
520
     * Assign a new offset to the caret and identify the operation which
521
     * originated the caret movement. 
522
     * <p>
523
     * In addition to {@link #setDot(int)},
524
     * the caller may identify the operation that originated the caret movement.
525
     * This information is received by {@link NavigationFilter}s or {@link ChangeListener}s
526
     * and may be used to react or modify the caret movements.
527
     * </p><p>
528
     * Use {@code null} or {@link MoveCaretsOrigin#DEFAULT} if the operation not known. Use
529
     * {@link MoveCaretsOrigin#DIRECT_NAVIGATION} action type to identify simple navigational
530
     * actions (pg up, pg down, left, right, ...).
531
     * </p>
532
     * @param offset new offset for the caret
533
     * @param orig specifies the operation which caused the caret to move.
534
     * @see #setDot(int) 
535
     * @since 2.9
536
     */
537
    public void setDot(final int offset, MoveCaretsOrigin orig) {
507
        if (LOG.isLoggable(Level.FINE)) {
538
        if (LOG.isLoggable(Level.FINE)) {
508
            LOG.fine("setDot: offset=" + offset); //NOI18N
539
            LOG.fine("setDot: offset=" + offset); //NOI18N
509
            if (LOG.isLoggable(Level.FINEST)) {
540
            if (LOG.isLoggable(Level.FINEST)) {
Lines 523-529 Link Here
523
                    }
554
                    }
524
                }
555
                }
525
            }
556
            }
526
        });
557
        }, orig);
527
    }
558
    }
528
559
529
    /**
560
    /**
Lines 537-542 Link Here
537
     * @see Caret#moveDot(int) 
568
     * @see Caret#moveDot(int) 
538
     */
569
     */
539
    public @Override void moveDot(final int offset) {
570
    public @Override void moveDot(final int offset) {
571
        moveDot(offset, MoveCaretsOrigin.DEFAULT);
572
    }
573
    
574
    /**
575
     * Moves the caret position (dot) to some other position, leaving behind the
576
     * mark. 
577
     * <p>
578
     * In addition to {@link #setDot(int)},
579
     * the caller may identify the operation that originated the caret movement.
580
     * This information is received by {@link NavigationFilter}s or {@link EditorCaretListener}s
581
     * and may be used to react or modify the caret movements.
582
     * </p><p>
583
     * Use {@code null} or {@link MoveCaretsOrigin#DEFAULT} if the operation not known. Use
584
     * {@link MoveCaretsOrigin#DIRECT_NAVIGATION} action type to identify simple navigational
585
     * actions (pg up, pg down, left, right, ...).
586
     * </p>
587
     * 
588
     * @param offset new offset for the caret
589
     * @param orig specifies the operation which caused the caret to move.
590
     * @see #moveDot(int) 
591
     * @since 2.9
592
     */
593
    public void moveDot(final int offset, MoveCaretsOrigin orig) {
540
        if (LOG.isLoggable(Level.FINE)) {
594
        if (LOG.isLoggable(Level.FINE)) {
541
            LOG.fine("moveDot: offset=" + offset); //NOI18N
595
            LOG.fine("moveDot: offset=" + offset); //NOI18N
542
        }
596
        }
Lines 554-560 Link Here
554
                    }
608
                    }
555
                }
609
                }
556
            }
610
            }
557
        });
611
        }, orig);
558
    }
612
    }
559
613
560
    /**
614
    /**
Lines 593-600 Link Here
593
     *  or no document installed in the text component.
647
     *  or no document installed in the text component.
594
     */
648
     */
595
    public int moveCarets(@NonNull CaretMoveHandler moveHandler) {
649
    public int moveCarets(@NonNull CaretMoveHandler moveHandler) {
650
        Parameters.notNull("moveHandler", moveHandler);
596
        return runTransaction(CaretTransaction.RemoveType.NO_REMOVE, 0, null, moveHandler);
651
        return runTransaction(CaretTransaction.RemoveType.NO_REMOVE, 0, null, moveHandler);
597
    }
652
    }
653
    
654
    /**
655
     * Move multiple carets or create/modify selections, specifies the originating operation.
656
     * <p>
657
     * In addition to {@link #moveCarets(org.netbeans.spi.editor.caret.CaretMoveHandler)}, the caller may specify
658
     * what operation causes the caret movements in the `origin' parameter, see {@link MoveCaretsOrigin} class. 
659
     * This information is received by {@link NavigationFilter}s or {@link EditorCaretListener}s
660
     * and may be used to react or modify the caret movements.
661
     * </p><p>
662
     * Use {@code null} or {@link MoveCaretsOrigin#DEFAULT} if the operation not known. Use
663
     * {@link MoveCaretsOrigin#DIRECT_NAVIGATION} action type to identify simple navigational
664
     * actions (pg up, pg down, left, right, ...).
665
     * </p><p>
666
     * See the {@link #moveCarets(org.netbeans.spi.editor.caret.CaretMoveHandler) } for detailed description of
667
     * how carets are moved.
668
     * </p>
669
     * 
670
     * @param moveHandler handler which moves individual carets
671
     * @param origin description of the originating operation. Use {@code null} or {@link MoveCaretsOrigin#DEFAULT} for default/unspecified operation.
672
     * @return difference between number of carets, see {@link #moveCarets(org.netbeans.spi.editor.caret.CaretMoveHandler)}.
673
     * @see #moveCarets(org.netbeans.spi.editor.caret.CaretMoveHandler) 
674
     * @since 2.9
675
     */
676
    public int moveCarets(@NonNull CaretMoveHandler moveHandler, MoveCaretsOrigin origin) {
677
        Parameters.notNull("moveHandler", moveHandler);
678
        if (origin ==  null) {
679
            origin = MoveCaretsOrigin.DEFAULT;
680
        }
681
        return runTransaction(CaretTransaction.RemoveType.NO_REMOVE, 0, null, moveHandler, origin);
682
    }
598
683
599
    /**
684
    /**
600
     * Create a new caret at the given position with a possible selection.
685
     * Create a new caret at the given position with a possible selection.
Lines 855-866 Link Here
855
            }
940
            }
856
            listenerImpl.focusGained(null); // emulate focus gained
941
            listenerImpl.focusGained(null); // emulate focus gained
857
        }
942
        }
858
859
        invalidateCaretBounds(0);
943
        invalidateCaretBounds(0);
860
        dispatchUpdate(false);
944
        dispatchUpdate(false);
861
        resetBlink();
945
        resetBlink();
862
    }
946
    }
863
947
    
864
    @Override
948
    @Override
865
    public void deinstall(JTextComponent c) {
949
    public void deinstall(JTextComponent c) {
866
        if (LOG.isLoggable(Level.FINE)) {
950
        if (LOG.isLoggable(Level.FINE)) {
Lines 1036-1041 Link Here
1036
            }
1120
            }
1037
        }
1121
        }
1038
    }
1122
    }
1123
    
1124
    /**
1125
     * Returns the navigation filter for a certain operation. 
1126
     * {@link NavigationFilter} can be 
1127
     * registered to receive only limited set of operations. This method returns the filter 
1128
     * for the specified operation. Use {@link MoveCaretsOrigin#DEFAULT} to get text 
1129
     * component's navigation filter (equivalent to {@link JTextComponent#getNavigationFilter() 
1130
     * JTextComponent.getNavigationFilter()}. That filter receives all caret movements.
1131
     * @param origin the operation description
1132
     * @return the current navigation filter.
1133
     * @since 2.9
1134
     */
1135
    public static @CheckForNull NavigationFilter getNavigationFilter(@NonNull JTextComponent component, @NonNull MoveCaretsOrigin origin) {
1136
        Parameters.notNull("origin", origin);
1137
        if (origin == MoveCaretsOrigin.DEFAULT) {
1138
            return component.getNavigationFilter();
1139
        } else if (origin == MoveCaretsOrigin.DISABLE_FILTERS) {
1140
            return null;
1141
        }
1142
        NavigationFilter navi = doGetNavigationFilter(component, origin.getActionType());
1143
        // Note: a special delegator is returned, since the component's navigation filter queue
1144
        // can be manipulated after call to getNavigationFilter. So if we would have returned the global filter instance directly,
1145
        // the calling client may unknowingly bypass certain (global) filters registered after call to this method.
1146
        // In other words, there are two possible insertion points into the navigation filter chanin
1147
        return navi != null ? navi : getChainNavigationFilter(component);
1148
    }
1149
1150
    /**
1151
     * Variant of {@link #getNavigationFilter}, which does not default to chaining navigation
1152
     * filter
1153
     * @param origin operation specifier
1154
     * @return navigation filter or {@code null}
1155
     */
1156
    @CheckForNull NavigationFilter getNavigationFilterNoDefault(@NonNull MoveCaretsOrigin origin) {
1157
        if (origin == MoveCaretsOrigin.DEFAULT) {
1158
            return component.getNavigationFilter();
1159
        } else if (origin == MoveCaretsOrigin.DISABLE_FILTERS) {
1160
            return null;
1161
        }
1162
        NavigationFilter navi2 = doGetNavigationFilter(component, origin.getActionType());
1163
        return navi2 != null ? navi2 : component.getNavigationFilter();
1164
    }
1165
1166
    /**
1167
     * Bottom navigation filter which delegates to the main NavigationFilter in the
1168
     * Component (if it exists).
1169
     */
1170
    private static class ChainNavigationFilter extends NavigationFilter {
1171
        private final JTextComponent component;
1172
1173
        public ChainNavigationFilter(JTextComponent component) {
1174
            this.component = component;
1175
        }
1176
        
1177
        @Override
1178
        public int getNextVisualPositionFrom(JTextComponent text, int pos, Position.Bias bias, int direction, Position.Bias[] biasRet) throws BadLocationException {
1179
            NavigationFilter chain = component.getNavigationFilter();
1180
            return chain != null ? chain.getNextVisualPositionFrom(text, pos, bias, direction, biasRet) : super.getNextVisualPositionFrom(text, pos, bias, direction, biasRet);
1181
        }
1182
1183
        @Override
1184
        public void moveDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias) {
1185
            NavigationFilter chain = component.getNavigationFilter();
1186
            if (chain != null) {
1187
                chain.moveDot(fb, dot, bias);
1188
            } else {
1189
                super.moveDot(fb, dot, bias);
1190
            }
1191
        }
1192
1193
        @Override
1194
        public void setDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias) {
1195
            NavigationFilter chain = component.getNavigationFilter();
1196
            if (chain != null) {
1197
                chain.setDot(fb, dot, bias);
1198
            } else {
1199
                super.setDot(fb, dot, bias);
1200
            }
1201
        }
1202
    }
1203
    
1204
    /**
1205
     * Sets navigation filter for a certain operation type, defined by {@link MoveCaretsOrigin}.
1206
     * <p>
1207
     * The registered filter will receive <b>only those caret movements</b>, which correspond to the
1208
     * passed {@link MoveCaretsOrigin}. To receive all caret movements, register for {@link MoveCaretsOrigin#DEFAULT} 
1209
     * or use {@link JTextComponent#setNavigationFilter}.
1210
     * </p><p>
1211
     * All the key part(s) of MoveCaretOrigin of a caret operation and `origin' parameter in this function must
1212
     * match in order for the filter to be invoked.
1213
     * </p><p>
1214
     * The NavigationFilter implementation <b>may downcast</b> the passed {@link NavigationFilter.FilterBypass FilterBypass}
1215
     * parameter to {@link NavigationFilterBypass} to get full infomration about the movement. 
1216
     * </p>
1217
     * @param origin the origin
1218
     * @param naviFilter the installed filter
1219
     * @see JTextComponent#setNavigationFilter
1220
     * @see NavigationFilterBypass
1221
     * @since 2.9
1222
     */
1223
    public static void setNavigationFilter(JTextComponent component, MoveCaretsOrigin origin, @NullAllowed NavigationFilter naviFilter) {
1224
        if (origin == null) {
1225
            origin = MoveCaretsOrigin.DEFAULT;
1226
        }
1227
        final NavigationFilter prev = getNavigationFilter(component, origin);
1228
        if (naviFilter != null) {
1229
            // Note:
1230
            // if the caller passes in a non-cascading filter, we would loose the filter chain information.
1231
            // the alien filter is wrapped by CascadingNavigationFilter delegator, so the previous filter
1232
            // link is preserved.
1233
            if (!(naviFilter instanceof CascadingNavigationFilter)) {
1234
                final NavigationFilter del = naviFilter;
1235
                naviFilter = new CascadingNavigationFilter() {
1236
                    @Override
1237
                    public void setDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias) {
1238
                        del.setDot(fb, dot, bias);
1239
                    }
1240
1241
                    @Override
1242
                    public void moveDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias) {
1243
                        del.moveDot(fb, dot, bias);
1244
                    }
1245
1246
                    @Override
1247
                    public int getNextVisualPositionFrom(JTextComponent text, int pos, Position.Bias bias, int direction, Position.Bias[] biasRet) throws BadLocationException {
1248
                        return del.getNextVisualPositionFrom(text, pos, bias, direction, biasRet);
1249
                    }
1250
                };
1251
            }
1252
            ((CascadingNavigationFilter)naviFilter).setOwnerAndPrevious(component, origin, prev);
1253
        }
1254
        if (MoveCaretsOrigin.DEFAULT == origin) {
1255
            component.setNavigationFilter(naviFilter);
1256
        } else {
1257
            doPutNavigationFilter(component, origin.getActionType(), prev);
1258
        }
1259
    }
1260
    
1261
    private static NavigationFilter getChainNavigationFilter(JTextComponent component) {
1262
        NavigationFilter chain = (NavigationFilter)component.getClientProperty(CHAIN_FILTER_PROPERTY);
1263
        if (chain == null) {
1264
            component.putClientProperty(CHAIN_FILTER_PROPERTY, chain = new ChainNavigationFilter(component));
1265
        }
1266
        return chain;
1267
    }
1268
    
1269
    /**
1270
     * Records the navigation filter. Note that the filter is stored in the JTextComponent rather than
1271
     * in this Caret. If the Component's UI changes or the caret is recreated for some reason, the 
1272
     * navigation filters remain registered.
1273
     * 
1274
     * @param type type of nav filter
1275
     * @param n the filter instance
1276
     */
1277
    private static void doPutNavigationFilter(JTextComponent component, String type, NavigationFilter n) {
1278
        if (component == null) {
1279
            throw new IllegalStateException("Not attached to a Component");
1280
        }
1281
        Map<String, NavigationFilter> m = (Map<String, NavigationFilter>)component.getClientProperty(NAVIGATION_FILTER_PROPERTY);
1282
        if (m == null) {
1283
            if (n == null) {
1284
                return;
1285
            }
1286
            m = new HashMap<>();
1287
            component.putClientProperty(NAVIGATION_FILTER_PROPERTY, m);
1288
        } 
1289
        if (n == null) {
1290
            m.remove(type);
1291
        } else {
1292
            m.put(type, n);
1293
        }
1294
    }
1295
    
1296
    private static NavigationFilter doGetNavigationFilter(JTextComponent component, String n) {
1297
        if (component == null) {
1298
            throw new IllegalStateException("Not attached to a Component");
1299
        }
1300
        Map<String, NavigationFilter> m = (Map<String, NavigationFilter>)component.getClientProperty(NAVIGATION_FILTER_PROPERTY);
1301
        return m == null ? null : m.get(n);
1302
    }
1039
1303
1040
    @Override
1304
    @Override
1041
    public int getBlinkRate() {
1305
    public int getBlinkRate() {
Lines 1143-1149 Link Here
1143
                moveDot(newDotOffset); // updates rs and fires state change
1407
                moveDot(newDotOffset); // updates rs and fires state change
1144
            } else {
1408
            } else {
1145
                updateRectangularSelectionPaintRect();
1409
                updateRectangularSelectionPaintRect();
1146
                fireStateChanged();
1410
                fireStateChanged(null);
1147
            }
1411
            }
1148
        } catch (BadLocationException ex) {
1412
        } catch (BadLocationException ex) {
1149
            // Leave selection as is
1413
            // Leave selection as is
Lines 1190-1202 Link Here
1190
     * @return 
1454
     * @return 
1191
     */
1455
     */
1192
    private int runTransaction(CaretTransaction.RemoveType removeType, int offset, CaretItem[] addCarets, CaretMoveHandler moveHandler) {
1456
    private int runTransaction(CaretTransaction.RemoveType removeType, int offset, CaretItem[] addCarets, CaretMoveHandler moveHandler) {
1457
        return runTransaction(removeType, offset, addCarets, moveHandler, MoveCaretsOrigin.DEFAULT);
1458
    }
1459
    
1460
    private int runTransaction(CaretTransaction.RemoveType removeType, int offset, CaretItem[] addCarets, CaretMoveHandler moveHandler, MoveCaretsOrigin org) {
1193
        lock();
1461
        lock();
1194
        try {
1462
        try {
1195
            if (activeTransaction == null) {
1463
            if (activeTransaction == null) {
1196
                JTextComponent c = component;
1464
                JTextComponent c = component;
1197
                Document d = activeDoc;
1465
                Document d = activeDoc;
1198
                if (c != null && d != null) {
1466
                if (c != null && d != null) {
1199
                    activeTransaction = new CaretTransaction(this, c, d);
1467
                    activeTransaction = new CaretTransaction(this, c, d, org);
1200
                    if (LOG.isLoggable(Level.FINE)) {
1468
                    if (LOG.isLoggable(Level.FINE)) {
1201
                        StringBuilder msgBuilder = new StringBuilder(200);
1469
                        StringBuilder msgBuilder = new StringBuilder(200);
1202
                        msgBuilder.append("EditorCaret.runTransaction(): removeType=").append(removeType).
1470
                        msgBuilder.append("EditorCaret.runTransaction(): removeType=").append(removeType).
Lines 1276-1282 Link Here
1276
                        }
1544
                        }
1277
                        if (activeTransaction.isAnyChange()) {
1545
                        if (activeTransaction.isAnyChange()) {
1278
                            // For now clear the lists and use old way TODO update to selective updating and rendering
1546
                            // For now clear the lists and use old way TODO update to selective updating and rendering
1279
                            fireStateChanged();
1547
                            fireStateChanged(activeTransaction.getOrigin());
1280
                            dispatchUpdate(true);
1548
                            dispatchUpdate(true);
1281
                            resetBlink();
1549
                            resetBlink();
1282
                        }
1550
                        }
Lines 1329-1342 Link Here
1329
    /**
1597
    /**
1330
     * Notifies listeners that caret position has changed.
1598
     * Notifies listeners that caret position has changed.
1331
     */
1599
     */
1332
    private void fireStateChanged() {
1600
    private void fireStateChanged(final MoveCaretsOrigin origin) {
1333
        Runnable runnable = new Runnable() {
1601
        Runnable runnable = new Runnable() {
1334
            public @Override void run() {
1602
            public @Override void run() {
1335
                JTextComponent c = component;
1603
                JTextComponent c = component;
1336
                if (c == null || c.getCaret() != EditorCaret.this) {
1604
                if (c == null || c.getCaret() != EditorCaret.this) {
1337
                    return;
1605
                    return;
1338
                }
1606
                }
1339
                fireEditorCaretChange(new EditorCaretEvent(EditorCaret.this, 0, Integer.MAX_VALUE)); // [TODO] temp firing without detailed info
1607
                fireEditorCaretChange(new EditorCaretEvent(EditorCaret.this, 0, Integer.MAX_VALUE, origin)); // [TODO] temp firing without detailed info
1340
                ChangeEvent evt = new ChangeEvent(EditorCaret.this);
1608
                ChangeEvent evt = new ChangeEvent(EditorCaret.this);
1341
                List<ChangeListener> listeners = changeListenerList.getListeners();
1609
                List<ChangeListener> listeners = changeListenerList.getListeners();
1342
                for (ChangeListener l : listeners) {
1610
                for (ChangeListener l : listeners) {
Lines 1883-1889 Link Here
1883
            rsDotRect.x = r.x;
2151
            rsDotRect.x = r.x;
1884
            rsDotRect.width = r.width;
2152
            rsDotRect.width = r.width;
1885
            updateRectangularSelectionPaintRect();
2153
            updateRectangularSelectionPaintRect();
1886
            fireStateChanged();
2154
            fireStateChanged(null);
1887
        }
2155
        }
1888
    }
2156
    }
1889
    
2157
    
Lines 2120-2126 Link Here
2120
                    } else { // No rectangular selection
2388
                    } else { // No rectangular selection
2121
                        RectangularSelectionTransferHandler.uninstall(component);
2389
                        RectangularSelectionTransferHandler.uninstall(component);
2122
                    }
2390
                    }
2123
                    fireStateChanged();
2391
                    fireStateChanged(null);
2124
                }
2392
                }
2125
            }
2393
            }
2126
        }
2394
        }
Lines 2132-2138 Link Here
2132
                int offset = evt.getOffset();
2400
                int offset = evt.getOffset();
2133
                if (offset == 0) {
2401
                if (offset == 0) {
2134
                    // Manually shift carets at offset zero - do this always even when inside atomic lock
2402
                    // Manually shift carets at offset zero - do this always even when inside atomic lock
2135
                    runTransaction(CaretTransaction.RemoveType.DOCUMENT_INSERT_ZERO_OFFSET, evt.getLength(), null, null);
2403
                    runTransaction(CaretTransaction.RemoveType.DOCUMENT_INSERT_ZERO_OFFSET, evt.getLength(), null, null, MoveCaretsOrigin.DISABLE_FILTERS);
2136
                }
2404
                }
2137
                modified = true;
2405
                modified = true;
2138
                modifiedUpdate(true, offset);
2406
                modifiedUpdate(true, offset);
Lines 2177-2183 Link Here
2177
                    invalidateCaretBounds(offset);
2445
                    invalidateCaretBounds(offset);
2178
                    dispatchUpdate();
2446
                    dispatchUpdate();
2179
                    resetBlink();
2447
                    resetBlink();
2180
                    fireStateChanged();
2448
                    fireStateChanged(null);
2181
                    modified = false;
2449
                    modified = false;
2182
                }
2450
                }
2183
            } else {
2451
            } else {
(-)a/editor.lib2/src/org/netbeans/api/editor/caret/EditorCaretEvent.java (-1 / +16 lines)
Lines 41-46 Link Here
41
 */
41
 */
42
package org.netbeans.api.editor.caret;
42
package org.netbeans.api.editor.caret;
43
43
44
import org.netbeans.api.annotations.common.CheckForNull;
44
import org.netbeans.api.annotations.common.NonNull;
45
import org.netbeans.api.annotations.common.NonNull;
45
46
46
/**
47
/**
Lines 55-64 Link Here
55
    
56
    
56
    private final int affectedEndOffset;
57
    private final int affectedEndOffset;
57
    
58
    
58
    EditorCaretEvent(EditorCaret source, int affectedStartOffset, int affectedEndOffset) {
59
    private final MoveCaretsOrigin origin;
60
    
61
    EditorCaretEvent(EditorCaret source, int affectedStartOffset, int affectedEndOffset, MoveCaretsOrigin origin) {
59
        super(source);
62
        super(source);
60
        this.affectedStartOffset = affectedStartOffset;
63
        this.affectedStartOffset = affectedStartOffset;
61
        this.affectedEndOffset = affectedEndOffset;
64
        this.affectedEndOffset = affectedEndOffset;
65
        this.origin = origin;
62
    }
66
    }
63
    
67
    
64
    /**
68
    /**
Lines 91-94 Link Here
91
    public int getAffectedEndOffset() {
95
    public int getAffectedEndOffset() {
92
        return affectedEndOffset;
96
        return affectedEndOffset;
93
    }
97
    }
98
    
99
    /**
100
     * Describes the origin of the movement command. May not be filled, if the movement
101
     * does not originate form an user-triggered editor action.
102
     * 
103
     * @return the original reason for caret movement, or {@code null}.
104
     * @since 2.9
105
     */
106
    public @CheckForNull MoveCaretsOrigin getOrigin() {
107
        return origin;
108
    }
94
}
109
}
(-)a/editor.lib2/src/org/netbeans/api/editor/caret/FilterBypassImpl.java (+244 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.caret;
43
44
import org.netbeans.spi.editor.caret.NavigationFilterBypass;
45
import java.awt.Graphics;
46
import java.awt.Point;
47
import javax.swing.event.ChangeListener;
48
import javax.swing.text.BadLocationException;
49
import javax.swing.text.Caret;
50
import javax.swing.text.Document;
51
import javax.swing.text.JTextComponent;
52
import javax.swing.text.Position;
53
import org.openide.util.Exceptions;
54
55
/**
56
 * Implementation of the FilterBypass suitable for multi-caret environment.
57
 * Provides a special {@link Caret} implementatio, which works with the current
58
 * {@link CaretItem} being manipulated, so that if client calls {@link Caret#setDot}
59
 * or the like, the instruction will be executed and bypasses all NavigationFilters.
60
 * 
61
 * @author sdedic
62
 */
63
class FilterBypassImpl extends NavigationFilterBypass {
64
    private final CaretTransaction transaction;
65
    private final CaretInfo        item;
66
    private final Document         doc;
67
    private Caret                  itemCaret;
68
    private boolean                result;
69
70
    public FilterBypassImpl(CaretTransaction transaction, CaretInfo item, Document doc) {
71
        this.transaction = transaction;
72
        this.item = item;
73
        this.doc = doc;
74
    }
75
    
76
    @Override
77
    public CaretInfo getCaretItem() {
78
        return item;
79
    }
80
81
    @Override
82
    public EditorCaret getEditorCaret() {
83
        return transaction.getCaret();
84
    }
85
86
    @Override
87
    public Caret getCaret() {
88
        if (itemCaret == null) {
89
            itemCaret = new ItemCaret();
90
        }
91
        return itemCaret;
92
    }
93
94
    @Override
95
    public MoveCaretsOrigin getOrigin() {
96
        return transaction.getOrigin();
97
    }
98
    
99
    boolean getResult() {
100
        return result;
101
    }
102
    
103
    @Override
104
    public void setDot(final int dot, Position.Bias bias) {
105
        Position dotPos = createPosition(dot, bias);
106
        result = transaction.setDotAndMark(item.getCaretItem(),
107
                dotPos, dotPos);
108
    }
109
    
110
    private Position createPosition(final int dot, Position.Bias bias) {
111
        final Position[] p = new Position[1];
112
        
113
        doc.render(new Runnable() {
114
            public void run() {
115
                p[0] = createPosition0(dot, null);
116
            }
117
        });
118
        return p[0];
119
    }
120
    
121
    private Position createPosition0(int dot, Position.Bias bias) {
122
        try {
123
            // FIXME: bias is not used. LineDocument should be used
124
            // in preference to document to create biased positions.
125
            // bypass handlers
126
            if (dot < 0) {
127
                return doc.createPosition(0);
128
            } else if (dot > doc.getLength()) {
129
                return doc.createPosition(doc.getLength());
130
            } else {
131
                return doc.createPosition(dot);
132
            }
133
        } catch (BadLocationException ex) {
134
            // should not happen, checked under doc lock
135
            Exceptions.printStackTrace(ex);
136
            return item.getDotPosition();
137
        }
138
    }
139
140
    @Override
141
    public void moveDot(int dot, Position.Bias bias) {
142
        result = transaction.setDotAndMark(item.getCaretItem(), 
143
                createPosition(dot, bias),
144
                item.getMarkPosition()
145
        );
146
    }
147
    
148
    /**
149
     * Custom caret implementation, which cleverly delegates to CaretItem
150
     * and transaction to carry out most of Caret API tasks against the current
151
     * CaretItem.
152
     * Unsupported operations throw an exception.
153
     */
154
    private class ItemCaret implements Caret {
155
        private void notPermitted() {
156
            throw new UnsupportedOperationException("Disallowed in NavigationFilter"); // NOI18N
157
        }
158
        @Override
159
        public void install(JTextComponent c) {
160
            notPermitted();
161
        }
162
163
        @Override
164
        public void deinstall(JTextComponent c) {
165
            notPermitted();
166
        }
167
168
        @Override
169
        public void paint(Graphics g) {
170
            notPermitted();
171
        }
172
173
        @Override
174
        public void addChangeListener(ChangeListener l) {
175
            transaction.getCaret().addChangeListener(l);
176
        }
177
178
        @Override
179
        public void removeChangeListener(ChangeListener l) {
180
            transaction.getCaret().removeChangeListener(l);
181
        }
182
183
        @Override
184
        public boolean isVisible() {
185
            return transaction.getCaret().isVisible();
186
        }
187
188
        @Override
189
        public void setVisible(boolean v) {
190
            transaction.getCaret().setVisible(v);
191
        }
192
193
        @Override
194
        public boolean isSelectionVisible() {
195
            return transaction.getCaret().isSelectionVisible();
196
        }
197
198
        @Override
199
        public void setSelectionVisible(boolean v) {
200
            transaction.getCaret().setSelectionVisible(v);
201
        }
202
203
        @Override
204
        public void setMagicCaretPosition(Point p) {
205
            transaction.setMagicCaretPosition(item.getCaretItem(), p);
206
        }
207
208
        @Override
209
        public Point getMagicCaretPosition() {
210
            return item.getMagicCaretPosition();
211
        }
212
213
        @Override
214
        public void setBlinkRate(int rate) {
215
            transaction.getCaret().setBlinkRate(rate);
216
        }
217
218
        @Override
219
        public int getBlinkRate() {
220
            return transaction.getCaret().getBlinkRate();
221
        }
222
223
        @Override
224
        public int getDot() {
225
            return item.getDot();
226
        }
227
228
        @Override
229
        public int getMark() {
230
            return item.getMark();
231
        }
232
233
        @Override
234
        public void setDot(int dot) {
235
            FilterBypassImpl.this.setDot(dot, Position.Bias.Forward);
236
        }
237
238
        @Override
239
        public void moveDot(int dot) {
240
            FilterBypassImpl.this.moveDot(dot, Position.Bias.Forward);
241
        }
242
        
243
    }
244
}
(-)a/editor.lib2/src/org/netbeans/api/editor/caret/MoveCaretsOrigin.java (+186 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.caret;
43
44
import org.netbeans.api.annotations.common.NonNull;
45
import org.netbeans.spi.editor.caret.NavigationFilterBypass;
46
import org.openide.util.Parameters;
47
48
/**
49
 * Describes the operation which initiated the caret navigation. 
50
 * <p>
51
 * The core implementation
52
 * supports operation type (token) as a key and original intended movement direction as a hint
53
 * for possible filtering. Future API versions may define more details.
54
 * </p><p>
55
 * This class is used in two modes: 
56
 * </p>
57
 * <ol>
58
 * <li>When moving a caret ({@link EditorCaret#setDot(int, org.netbeans.api.editor.caret.MoveCaretsOrigin) setDot(pos, origin)},
59
 * {@link EditorCaret#moveDot(int, org.netbeans.api.editor.caret.MoveCaretsOrigin) moveDot(pos, origin)}, 
60
 * {@link EditorCaret#moveCarets(org.netbeans.spi.editor.caret.CaretMoveHandler, org.netbeans.api.editor.caret.MoveCaretsOrigin) moveCarets(handler, origin)}),
61
 * as a information on the originating operation ({@link #getActionType getActionType()}) and possibly additional
62
 * hints that describes the intended caret move ({@link #getDirection() getDirection()}).
63
 * </li>
64
 * <li>
65
 * When {@link EditorCaret#setNavigationFilter(org.netbeans.api.editor.caret.MoveCaretsOrigin, javax.swing.text.NavigationFilter) registering a NavigationFilter}
66
 * as a filtering template. 
67
 * </li>
68
 * </ol>
69
 * 
70
 * <div class="nonnormative">
71
 * <p>
72
 * The intended usage in caret moving code (actions) is as follows:
73
 * </p>
74
 * <code><pre>
75
 * // Action perform method
76
 * editorCaret.moveCarets(new CaretMoveHandler() {
77
 *      &#64;Override
78
 *      public void moveCarets(CaretMoveContext context) {
79
 *          ...
80
 *      }
81
 *  }, new MoveCaretsOrigin(
82
 *          // The action is a raw movement command
83
 *          MoveCaretsOrigin.DIRECT_NAVIGATION, 
84
 *          // The approximate direction of the movement; can be 0.
85
 *          SwingConstants.NORTH)
86
 *  );
87
 * </pre></code>
88
 * <p>
89
 * If a {@link javax.swing.text.NavigationFilter} only wants to intercept certain type of moevements, it can register as follows:
90
 * </p>
91
 * <code><pre>
92
 * EditorCaret eCaret = .... ; // obtain EditorCaret
93
 * eCaret.setNavigationFilter(
94
 *   new NavigationFilter() {
95
 *          // navigation filter implementation, not important for the example
96
 *   }, 
97
 *   new MoveCaretsOrigin(MoveCaretsOrigin.DIRECT_NAVIGATION)
98
 * );
99
 * </pre></code>
100
 * <p>
101
 * If the NavigationFilter implementation wants to obtain the extended information for the caret movement,
102
 * it can downcast the received FilterBypass:
103
 * </p>
104
 * <code><pre>
105
 *  public void setDot(FilterBypass fb, int dot, Position.Bias bias) {
106
 *    if (fb instanceof NavigationFilterBypass) {
107
 *      NavigationFilterBypass nfb = (NavigationFilterBypass)fb;
108
 * 
109
 *      // get the Origin object created by the caret-moving operation, can query the details
110
 *      MoveCaretsOrigin origin = nfb.getOrigin();
111
 * 
112
 *      // get the individual caret in multi-caret scenario
113
 *      CaretInfo info = nfb.getCaretInfo();
114
 * 
115
 *      // get the whole EditorCaret
116
 *      EditorCaret eCaret = nfb.getEditorCaret();
117
 *    }
118
 *  }
119
 * </pre></code>
120
 * </div>
121
 * @see NavigationFilterBypass
122
 * @since 2.9
123
 */
124
public final class MoveCaretsOrigin {
125
    /**
126
     * Actions, which are defined as moving or setting the caret. Do not user for actions
127
     * like search (moves caret to the found string), goto type (moves to the definition) etc.
128
     */
129
    public static final String DIRECT_NAVIGATION = "navigation.action"; // NOI18N
130
    
131
    /**
132
     * Undefined action type. Use this description when registering for all possible
133
     * caret movements.
134
     */
135
    public static final MoveCaretsOrigin DEFAULT = new MoveCaretsOrigin("default", 0); // NOI18N
136
    
137
    /**
138
     * Actions which must avoid caret filters. Use this special instance to indicate that the
139
     * infrastructure should bypass all caret filters.
140
     */
141
    public static final MoveCaretsOrigin DISABLE_FILTERS = new MoveCaretsOrigin("disable-filters", 0); // NOI18N
142
    
143
    private final String actionType;
144
    private final int direction;
145
146
    /**
147
     * Describes the origin by just the action type. 
148
     * @param actionType action type
149
     */
150
    public MoveCaretsOrigin(String actionType) {
151
        this.actionType = actionType;
152
        this.direction = 0;
153
    }
154
155
    /**
156
     * Specifies the origin by action type, and the overall moving direction
157
     * @param actionType action type
158
     * @param direction the intended direction of movement
159
     */
160
    public MoveCaretsOrigin(@NonNull String actionType, int direction) {
161
        Parameters.notNull("actionType", actionType); // NOI18N
162
        this.actionType = actionType;
163
        this.direction = direction;
164
    }
165
166
    /**
167
     * Returns the type of the action which originated the caret movement.
168
     * @return the action type.
169
     */
170
    @NonNull
171
    public String getActionType() {
172
        return actionType;
173
    }
174
175
    /**
176
     * Specifies the desired movement direction. Use {@link javax.swing.SwingConstants}
177
     * compass constants to specify the direction. 0 means the direction
178
     * is unspecified.
179
     *
180
     * @return The initial direction of movemnet
181
     */
182
    public int getDirection() {
183
        return direction;
184
    }
185
    
186
}
(-)a/editor.lib2/src/org/netbeans/api/editor/caret/package.html (-1 / +93 lines)
Lines 131-143 Link Here
131
  concurrently.
131
  concurrently.
132
  </p>
132
  </p>
133
  
133
  
134
  <h3><a name="movement-origins">Reason of Caret Movement</a></h3>
135
  <p>
136
      It may be desirable (especially for <a href="@JDK@/javax/swing/text/NavigationListener.html">NavigationListeners</a>, but possibly for 
137
      <a href="EditorCaretListener.html">EditorCaretListeners</a> too) to determine
138
  what was the reason leading to caret movement. The caller of Caret API which intends to position the caret
139
  may provide an optional <a href="MoveCaretsOrigin.html">MoveCaretsOrigin</a> instance to Caret API methods to indicate
140
  type of action leading to the movement. 
141
  This description is used to select <i>NavigationFilters</i> which receive and can modify the movement, and is available
142
  to all invoked <i>NavigationFilters</i> or <i>EditorCaretListeners</i> contacted by the Caret API operation.
143
  </p>
144
  <p>
145
  Only one action type is currently defined by the 
146
  API - <a href="MoveCaretsOrigin.html#DIRECT_NAVIGATION">DIRECT_NAVIGATION</a>. This type identifies operations
147
  actions, whose only task is to reposition the caret (i.e. left/right, page-up, document-begin) from actions,
148
  which position caret as a part of larger task (i.e. search, goto type, ...).
149
  </p>
150
  
151
  <h3><a name="navigation-filters">Navigation Filters</a></h3>
152
  <p>
153
  The Caret API implements and extends the concept of swing 
154
  <a href="@JDK@/javax/swing/text/NavigationFilter.html">NavigationFilters</a>. The Filter
155
  gets notified on <code>CaretInfo</code> movement; so if more Carets are present, 
156
  a <code>NavigationFilter</code> will see all their moves. Navigation Filters are
157
  called with a special instance of <a href="@JDK@/javax/swing/text/NavigationFilter.FilterBypass.html">
158
  FilterBypass</a> extending <a href="../../../spi/editor/caret/NavigationFilterBypass.html">
159
    NavigationFilterBypass</a>. The Filter <b>can downcast the FilterBypass to access extended information</b>
160
  about the current caret's movement:
161
  </p>
162
   <div class="nonnormative">
163
    <pre><code>
164
    public void setDot(FilterBypass fb, int dot, Position.Bias bias) {
165
      if (fb instanceof NavigationFilterBypass) {
166
        NavigationFilterBypass nfb = (NavigationFilterBypass)fb;
167
   
168
        // get the Origin object created by the caret-moving operation, can query the details
169
        MoveCaretsOrigin origin = nfb.getOrigin();
170
   
171
        // get the individual caret in multi-caret scenario
172
        CaretInfo info = nfb.getCaretInfo();
173
   
174
        // get the whole EditorCaret
175
        EditorCaret eCaret = nfb.getEditorCaret();
176
      }
177
    }
178
    </code></pre>
179
   </div>
180
  <p>
181
  Navigation filters can be also selectively registered for only certain type of actions described by
182
  <a href="MoveCaretsOrigin.html">MoveCaretsOrigin</a> instance. 
183
  </p>
184
  <div class="nonnormative">
185
    <pre><code>
186
        EditorCaret eCaret = .... ; // obtain EditorCaret
187
        eCaret.setNavigationFilter(
188
          new NavigationFilter() {
189
                 // navigation filter implementation, not important for the example
190
          }, 
191
          new MoveCaretsOrigin(MoveCaretsOrigin.DIRECT_NAVIGATION)
192
        );
193
    </code></pre>
194
  </div>
195
  <p>
196
  Such filters are only called if the caller of Caret API provides a suitable <i>MoveCaretsOrigin</i> description of the move operatoion.
197
  </p>
198
  <div class="nonnormative">
199
      <pre>
200
          <code>
201
        // Action perform method
202
        editorCaret.moveCarets(new CaretMoveHandler() {
203
             &#64;Override
204
             public void moveCarets(CaretMoveContext context) {
205
                 ...
206
             }
207
         }, new MoveCaretsOrigin(
208
                 // The action is a raw movement command
209
                 MoveCaretsOrigin.DIRECT_NAVIGATION, 
210
                 // The approximate direction of the movement; can be 0.
211
                 SwingConstants.NORTH)
212
         );
213
        </code>
214
      </pre>
215
  </div>
216
  Swing NavigationFilters, specified by <a href="@JDK@/javax/swing/text/JTextComponent#setNavigationFilter(javax.swing.text.NavigationFilter)">TextComponent.setNavigationFilter()</a>
217
  are called for all caret movements.
218
  <p>
219
  Abstract boilerplate for <code>NavigationFilters</code> is created, 
220
  <a href="../../../spi/editor/caret/CascadingNavigationFilter.html">CascadingNavigationFilter</a>
221
  which allows to chain individual filters. Implementors are encouraged to use it, or otherwise
222
  pass the control to previously registered <code>NavigationFilter</code> in case the movement
223
  event is not handled by the custom implementation.
224
  <p/>
225
  
134
  <h3><a name="compatibilty">Backwards compatibility</a></h3>
226
  <h3><a name="compatibilty">Backwards compatibility</a></h3>
135
  <p>
227
  <p>
136
  As a technical limitation, <code>EditorCaret</code> has to implement <code>Caret</code>
228
  As a technical limitation, <code>EditorCaret</code> has to implement <code>Caret</code>
137
  to be able to work with Swings Text API. The <code>Caret</code> interface is not
229
  to be able to work with Swings Text API. The <code>Caret</code> interface is not
138
  aware of multiple carets and a call to <code>setDot(int)</code> will only retain
230
  aware of multiple carets and a call to <code>setDot(int)</code> will only retain
139
  a single caret. For multiple carets a call to <code>moveDot(int)</code> will move the last
231
  a single caret. For multiple carets a call to <code>moveDot(int)</code> will move the last
140
  caret only (but it retains other existing carets).
232
  caret only (but it retains other existing carets).+
141
  <br>
233
  <br>
142
  <code>editorTextComponent.getCaret()</code> will now always return <code>EditorCaret</code>
234
  <code>editorTextComponent.getCaret()</code> will now always return <code>EditorCaret</code>
143
  instance instead of the original caret implementation <code>org.netbeans.editor.BaseCaret</code>.
235
  instance instead of the original caret implementation <code>org.netbeans.editor.BaseCaret</code>.
(-)a/editor.lib2/src/org/netbeans/spi/editor/caret/CascadingNavigationFilter.java (+176 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.spi.editor.caret;
43
44
import javax.swing.text.BadLocationException;
45
import javax.swing.text.JTextComponent;
46
import javax.swing.text.NavigationFilter;
47
import javax.swing.text.Position;
48
import org.netbeans.api.annotations.common.NonNull;
49
import org.netbeans.api.editor.caret.EditorCaret;
50
import org.netbeans.api.editor.caret.MoveCaretsOrigin;
51
import org.openide.util.Parameters;
52
53
/**
54
 * Boilerplate {@link NavigationFilter}, which supports chaining of filters
55
 * on an JTextComponent. 
56
 * <p>
57
 * The implementation should call super methods to 
58
 * allow lower-precedence filters to react. If the implementation desires to
59
 * disable the filters and take the movement action directly, it can still use
60
 * the {@link FilterBypass} instance passed.
61
 * </p><p>
62
 * There are helper {@link #register} and {@link #unregister} methods which 
63
 * ensure the chain of filters is correctly maintained. After registering, methods
64
 * implemented by this class will delegate to the remembered formerly-toplevel filter.
65
 * Implementor of this class may safely call super.* methods to delegate to filters
66
 * further in the chain.
67
 * </p>
68
 * 
69
 * @author sdedic
70
 * @since 2.9
71
 */
72
public abstract class CascadingNavigationFilter extends NavigationFilter {
73
    private NavigationFilter    previous;
74
    private JTextComponent      owner;
75
    private MoveCaretsOrigin    regKey;
76
77
    /**
78
     * Returns the next filter in the chain. This class' implementations of NavigationFilter
79
     * API methods delegate to that filter, if non-null. Results after this Filter is
80
     * unregistered (removed from the NavigationFilter) chain
81
     * are undefined.
82
     * 
83
     * @return next NavigationFilter.
84
     */
85
    protected final NavigationFilter getNextFilter() {
86
        return previous;
87
    }
88
    
89
    @Override
90
    public int getNextVisualPositionFrom(JTextComponent text, int pos, Position.Bias bias, int direction, Position.Bias[] biasRet) throws BadLocationException {
91
        return previous != null ?
92
                previous.getNextVisualPositionFrom(text, pos, bias, direction, biasRet) :
93
                super.getNextVisualPositionFrom(text, pos, bias, direction, biasRet);
94
    }
95
96
    @Override
97
    public void moveDot(FilterBypass fb, int dot, Position.Bias bias) {
98
        if (previous != null) {
99
            previous.moveDot(fb, dot, bias);
100
        } else {
101
            super.moveDot(fb, dot, bias);
102
        }
103
    }
104
105
    @Override
106
    public void setDot(FilterBypass fb, int dot, Position.Bias bias) {
107
        if (previous != null) {
108
            previous.setDot(fb, dot, bias);
109
        } else {
110
            super.setDot(fb, dot, bias);
111
        }
112
    }
113
114
    /**
115
     * Removes this NavigationFilter from the chain; preceding filter will
116
     * be connected to the following one, so the chain will not be broken.
117
     */
118
    public final void unregister() {
119
        if (regKey == null) {
120
            // not registered
121
            return;
122
        }
123
        NavigationFilter f = EditorCaret.getNavigationFilter(owner, regKey);
124
        CascadingNavigationFilter next = null;
125
        
126
        while (f instanceof CascadingNavigationFilter && f != this) {
127
            next = (CascadingNavigationFilter)f;
128
            f = next.getNextFilter();
129
        }
130
        if (f != this) {
131
            return;
132
        }
133
        if (next == null) {
134
            EditorCaret.setNavigationFilter(owner, regKey, previous);
135
        } else {
136
            next.previous = previous;
137
        }
138
        // reset state
139
        this.owner = null;
140
        this.previous = null;
141
    }
142
143
    /**
144
     * Registers this Filter into the NavigationFilter chain. 
145
     * <p>
146
     * This filter will
147
     * be placed on top of the filter's chain and the formerly-toplevel filter will
148
     * be remembered for delegation.
149
     * </p><p>
150
     * It is not permitted to register with more carets; make multiple instances of
151
     * the filter for that case.
152
     * </p>
153
     * 
154
     * @param caret where this Filter should be registered.
155
     * @param origin operation specifier
156
     */
157
    public final void register(
158
            @NonNull JTextComponent component,
159
            @NonNull MoveCaretsOrigin origin) {
160
        Parameters.notNull("caret", component);
161
        Parameters.notNull("origin", origin);
162
        if (owner != null) {
163
            throw new IllegalStateException();
164
        }
165
        EditorCaret.setNavigationFilter(component, origin, this);
166
    }
167
    
168
    public void setOwnerAndPrevious(JTextComponent component, MoveCaretsOrigin orig, NavigationFilter prev) {
169
        if (this.owner != null) {
170
            throw new IllegalStateException("Can be registered only once");
171
        }
172
        this.owner = component;
173
        this.previous = prev;
174
        this.regKey = orig;
175
    }
176
}
(-)a/editor.lib2/src/org/netbeans/spi/editor/caret/NavigationFilterBypass.java (+82 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.spi.editor.caret;
43
44
import javax.swing.text.NavigationFilter;
45
import org.netbeans.api.annotations.common.NonNull;
46
import org.netbeans.api.editor.caret.CaretInfo;
47
import org.netbeans.api.editor.caret.EditorCaret;
48
import org.netbeans.api.editor.caret.MoveCaretsOrigin;
49
50
/**
51
 * Enhanced FilterBypass which understands multicaret. 
52
 * <p>
53
 * Implementations of
54
 * {@link NavigationFilter} may check if the FilterBypass is instanceof this class,
55
 * and if so, they can access extended information.
56
 * </p><p>
57
 * If the caret move operation is initiated by new caret APIs, the FilterBypass passed
58
 * to NavigationFilters always satisfies this interface.
59
 * </p>
60
 * @author sdedic
61
 * @since 2.9
62
 */
63
public abstract class NavigationFilterBypass extends NavigationFilter.FilterBypass {
64
    /**
65
     * Returns the currently changing CaretItem.
66
     * 
67
     * @return CaretItem the caret instance being changed
68
     */
69
    public abstract @NonNull CaretInfo           getCaretItem();
70
    
71
    /**
72
     * Access to the entire EditorCaret abstraction
73
     * @return the editor caret
74
     */
75
    public abstract @NonNull EditorCaret         getEditorCaret();
76
    
77
    /**
78
     * Describes the origin / reason of the movement.
79
     * @return The origin object provided by the caret movement initiator.
80
     */
81
    public abstract @NonNull MoveCaretsOrigin    getOrigin();
82
}
(-)a/editor.lib2/src/org/netbeans/spi/editor/caret/package.html (-1 / +17 lines)
Lines 70-76 Link Here
70
    });
70
    });
71
  </code>
71
  </code>
72
  </pre>
72
  </pre>
73
73
  
74
  <h3><a name="navigation-filters">Navigation Filters</a></h3>
75
  <p>
76
  A boilerplate <a href="CascadingNavigationFilter.html">CascadingNavigationFilter</a> is provided to 
77
  make implementation of <a href="@JDK@/javax/swing/text/NavigationFilter.html">NavigationFilters</a> easier. The boilerplate
78
  remembers the preceding filter and will delegate to it. If you create a subclass, you may call <code>super</code> methods 
79
  <code>moveDot</code> and <code>setDot</code> to delegate to that previous filter and ultimately perform the action. Calling
80
  methods of <a href="@JDK@/javax/swing/text/NavigationFilter.FilterBypass.html">FilterBypass</a> will perform the caret action
81
  directly.
82
  </p>
83
  <p>
84
  The filter can find out the <a href="../../../api/editor/caret/package-summary.html#movement-origins">origin of the movement</a> or
85
  the <a href="../../../api/editor/caret/CaretItem.html">info for actual caret</a> being moved. The 
86
  <a href="@JDK@/javax/swing/text/NavigationFilter.FilterBypass.html">FilterBypass</a> implementation passed to 
87
  <a href="@JDK@/javax/swing/text/NavigationFilter.html">NavigationFilter</a> can be downcasted to <a href="NavigationFilterBypass.html">NavigationFilterBypass</a>,
88
  which provides this extended information.
89
  </p>
74
  <h3><a name="compatibilty">Backwards compatibility</a></h3>
90
  <h3><a name="compatibilty">Backwards compatibility</a></h3>
75
  
91
  
76
  <h3><a name="usecases">Use cases</a></h3>
92
  <h3><a name="usecases">Use cases</a></h3>

Return to bug 258824