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 (-4 / +32 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(getMoveOrigin());
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(getMoveOrigin());
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
    }
190
    
191
    /**
192
     * Describes the origin of the movement, the calling operation. Can be null
193
     * if the origin could not be described. Should identify {@link MoveCaretsOrigin#DIRECT_NAVIGATION}
194
     * actionType for simple navigation actions.
195
     * 
196
     * @return movement description
197
     * @see MoveCaretsOrigin
198
     * @since 2.9
199
     */
200
    public @NonNull MoveCaretsOrigin getMoveOrigin() {
201
        return transaction.getOrigin();
202
    }
175
203
176
}
204
}
(-)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 (-10 / +273 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
162
    
170
    
163
    // -J-Dorg.netbeans.api.editor.caret.EditorCaret.level=FINEST
171
    // -J-Dorg.netbeans.api.editor.caret.EditorCaret.level=FINEST
164
    private static final Logger LOG = Logger.getLogger(EditorCaret.class.getName());
172
    private static final Logger LOG = Logger.getLogger(EditorCaret.class.getName());
Lines 371-376 Link Here
371
     * with the same cursor.
379
     * with the same cursor.
372
     */
380
     */
373
    private boolean showingTextCursor = true;
381
    private boolean showingTextCursor = true;
382
383
    /**    
384
     * Bottom navigation filter, which delegates to the Component.
385
     */
386
    private NavigationFilter chainNavigationFilter;
374
    
387
    
375
    public EditorCaret() {
388
    public EditorCaret() {
376
        caretItems = new GapList<>();
389
        caretItems = new GapList<>();
Lines 504-509 Link Here
504
     * @see Caret#setDot(int) 
517
     * @see Caret#setDot(int) 
505
     */
518
     */
506
    public @Override void setDot(final int offset) {
519
    public @Override void setDot(final int offset) {
520
        setDot(offset, MoveCaretsOrigin.DEFAULT);
521
    }
522
523
    /**
524
     * Assign a new offset to the caret and identify the operation which
525
     * originated the caret movement. 
526
     * <p>
527
     * In addition to {@link #setDot(int)},
528
     * the caller may identify the operation that originated the caret movement.
529
     * This information is received by {@link NavigationFilter}s or {@link ChangeListener}s
530
     * and may be used to react or modify the caret movements.
531
     * </p><p>
532
     * Use {@code null} or {@link MoveCaretsOrigin#DEFAULT} if the operation not known. Use
533
     * {@link MoveCaretsOrigin#DIRECT_NAVIGATION} action type to identify simple navigational
534
     * actions (pg up, pg down, left, right, ...).
535
     * </p>
536
     * @param offset new offset for the caret
537
     * @param orig specifies the operation which caused the caret to move.
538
     * @see #setDot(int) 
539
     * @since 2.9
540
     */
541
    public void setDot(final int offset, MoveCaretsOrigin orig) {
507
        if (LOG.isLoggable(Level.FINE)) {
542
        if (LOG.isLoggable(Level.FINE)) {
508
            LOG.fine("setDot: offset=" + offset); //NOI18N
543
            LOG.fine("setDot: offset=" + offset); //NOI18N
509
            if (LOG.isLoggable(Level.FINEST)) {
544
            if (LOG.isLoggable(Level.FINEST)) {
Lines 523-529 Link Here
523
                    }
558
                    }
524
                }
559
                }
525
            }
560
            }
526
        });
561
        }, orig);
527
    }
562
    }
528
563
529
    /**
564
    /**
Lines 537-542 Link Here
537
     * @see Caret#moveDot(int) 
572
     * @see Caret#moveDot(int) 
538
     */
573
     */
539
    public @Override void moveDot(final int offset) {
574
    public @Override void moveDot(final int offset) {
575
        moveDot(offset, MoveCaretsOrigin.DEFAULT);
576
    }
577
    
578
    /**
579
     * Moves the caret position (dot) to some other position, leaving behind the
580
     * mark. 
581
     * <p>
582
     * In addition to {@link #setDot(int)},
583
     * the caller may identify the operation that originated the caret movement.
584
     * This information is received by {@link NavigationFilter}s or {@link EditorCaretListener}s
585
     * and may be used to react or modify the caret movements.
586
     * </p><p>
587
     * Use {@code null} or {@link MoveCaretsOrigin#DEFAULT} if the operation not known. Use
588
     * {@link MoveCaretsOrigin#DIRECT_NAVIGATION} action type to identify simple navigational
589
     * actions (pg up, pg down, left, right, ...).
590
     * </p>
591
     * 
592
     * @param offset new offset for the caret
593
     * @param orig specifies the operation which caused the caret to move.
594
     * @see #moveDot(int) 
595
     * @since 2.9
596
     */
597
    public void moveDot(final int offset, MoveCaretsOrigin orig) {
540
        if (LOG.isLoggable(Level.FINE)) {
598
        if (LOG.isLoggable(Level.FINE)) {
541
            LOG.fine("moveDot: offset=" + offset); //NOI18N
599
            LOG.fine("moveDot: offset=" + offset); //NOI18N
542
        }
600
        }
Lines 554-560 Link Here
554
                    }
612
                    }
555
                }
613
                }
556
            }
614
            }
557
        });
615
        }, orig);
558
    }
616
    }
559
617
560
    /**
618
    /**
Lines 593-600 Link Here
593
     *  or no document installed in the text component.
651
     *  or no document installed in the text component.
594
     */
652
     */
595
    public int moveCarets(@NonNull CaretMoveHandler moveHandler) {
653
    public int moveCarets(@NonNull CaretMoveHandler moveHandler) {
654
        Parameters.notNull("moveHandler", moveHandler);
596
        return runTransaction(CaretTransaction.RemoveType.NO_REMOVE, 0, null, moveHandler);
655
        return runTransaction(CaretTransaction.RemoveType.NO_REMOVE, 0, null, moveHandler);
597
    }
656
    }
657
    
658
    /**
659
     * Move multiple carets or create/modify selections, specifies the originating operation.
660
     * <p>
661
     * In addition to {@link #moveCarets(org.netbeans.spi.editor.caret.CaretMoveHandler)}, the caller may specify
662
     * what operation causes the caret movements in the `origin' parameter, see {@link MoveCaretsOrigin} class. 
663
     * This information is received by {@link NavigationFilter}s or {@link EditorCaretListener}s
664
     * and may be used to react or modify the caret movements.
665
     * </p><p>
666
     * Use {@code null} or {@link MoveCaretsOrigin#DEFAULT} if the operation not known. Use
667
     * {@link MoveCaretsOrigin#DIRECT_NAVIGATION} action type to identify simple navigational
668
     * actions (pg up, pg down, left, right, ...).
669
     * </p><p>
670
     * See the {@link #moveCarets(org.netbeans.spi.editor.caret.CaretMoveHandler) } for detailed description of
671
     * how carets are moved.
672
     * </p>
673
     * 
674
     * @param moveHandler handler which moves individual carets
675
     * @param origin description of the originating operation. Use {@code null} or {@link MoveCaretsOrigin#DEFAULT} for default/unspecified operation.
676
     * @return difference between number of carets, see {@link #moveCarets(org.netbeans.spi.editor.caret.CaretMoveHandler)}.
677
     * @see #moveCarets(org.netbeans.spi.editor.caret.CaretMoveHandler) 
678
     * @since 2.9
679
     */
680
    public int moveCarets(@NonNull CaretMoveHandler moveHandler, MoveCaretsOrigin origin) {
681
        Parameters.notNull("moveHandler", moveHandler);
682
        if (origin ==  null) {
683
            origin = MoveCaretsOrigin.DEFAULT;
684
        }
685
        return runTransaction(CaretTransaction.RemoveType.NO_REMOVE, 0, null, moveHandler, origin);
686
    }
598
687
599
    /**
688
    /**
600
     * Create a new caret at the given position with a possible selection.
689
     * Create a new caret at the given position with a possible selection.
Lines 855-860 Link Here
855
            }
944
            }
856
            listenerImpl.focusGained(null); // emulate focus gained
945
            listenerImpl.focusGained(null); // emulate focus gained
857
        }
946
        }
947
        
948
        this.chainNavigationFilter = new ChainNavigationFilter(component);
858
949
859
        invalidateCaretBounds(0);
950
        invalidateCaretBounds(0);
860
        dispatchUpdate(false);
951
        dispatchUpdate(false);
Lines 1036-1041 Link Here
1036
            }
1127
            }
1037
        }
1128
        }
1038
    }
1129
    }
1130
    
1131
    /**
1132
     * Returns the navigation filter for a certain operation. 
1133
     * {@link NavigationFilter} can be 
1134
     * registered to receive only limited set of operations. This method returns the filter 
1135
     * for the specified operation. Use {@link MoveCaretsOrigin#DEFAULT} to get text 
1136
     * component's navigation filter (equivalent to {@link JTextComponent#getNavigationFilter() 
1137
     * JTextComponent.getNavigationFilter()}. That filter receives all caret movements.
1138
     * @param origin the operation description
1139
     * @return the current navigation filter.
1140
     * @since 2.9
1141
     */
1142
    public @CheckForNull NavigationFilter getNavigationFilter(@NonNull MoveCaretsOrigin origin) {
1143
        Parameters.notNull("origin", origin);
1144
        if (origin == MoveCaretsOrigin.DEFAULT) {
1145
            return component.getNavigationFilter();
1146
        } 
1147
        NavigationFilter navi = doGetNavigationFilter(origin.getActionType());
1148
        // Note: a special delegator is returned, since the component's navigation filter queue
1149
        // can be manipulated after call to getNavigationFilter. So if we would have returned the global filter instance directly,
1150
        // the calling client may unknowingly bypass certain (global) filters registered after call to this method.
1151
        // In other words, there are two possible insertion points into the navigation filter chanin
1152
        return navi != null ? navi : chainNavigationFilter;
1153
    }
1154
1155
    /**
1156
     * Variant of {@link #getNavigationFilter}, which does not default to chaining navigation
1157
     * filter
1158
     * @param origin operation specifier
1159
     * @return navigation filter or {@code null}
1160
     */
1161
    @CheckForNull NavigationFilter getNavigationFilterNoDefault(@NonNull MoveCaretsOrigin origin) {
1162
        if (origin == MoveCaretsOrigin.DEFAULT) {
1163
            return component.getNavigationFilter();
1164
        } 
1165
        NavigationFilter navi2 = doGetNavigationFilter(origin.getActionType());
1166
        return navi2 != null ? navi2 : component.getNavigationFilter();
1167
    }
1168
1169
    /**
1170
     * Bottom navigation filter which delegates to the main NavigationFilter in the
1171
     * Component (if it exists).
1172
     */
1173
    private static class ChainNavigationFilter extends NavigationFilter {
1174
        private final JTextComponent component;
1175
1176
        public ChainNavigationFilter(JTextComponent component) {
1177
            this.component = component;
1178
        }
1179
        
1180
        @Override
1181
        public int getNextVisualPositionFrom(JTextComponent text, int pos, Position.Bias bias, int direction, Position.Bias[] biasRet) throws BadLocationException {
1182
            NavigationFilter chain = component.getNavigationFilter();
1183
            return chain != null ? chain.getNextVisualPositionFrom(text, pos, bias, direction, biasRet) : super.getNextVisualPositionFrom(text, pos, bias, direction, biasRet);
1184
        }
1185
1186
        @Override
1187
        public void moveDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias) {
1188
            NavigationFilter chain = component.getNavigationFilter();
1189
            if (chain != null) {
1190
                chain.moveDot(fb, dot, bias);
1191
            } else {
1192
                super.moveDot(fb, dot, bias);
1193
            }
1194
        }
1195
1196
        @Override
1197
        public void setDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias) {
1198
            NavigationFilter chain = component.getNavigationFilter();
1199
            if (chain != null) {
1200
                chain.setDot(fb, dot, bias);
1201
            } else {
1202
                super.setDot(fb, dot, bias);
1203
            }
1204
        }
1205
    }
1206
    
1207
    /**
1208
     * Sets navigation filter for a certain operation type, defined by {@link MoveCaretsOrigin}.
1209
     * <p>
1210
     * The registered filter will receive <b>only those caret movements</b>, which correspond to the
1211
     * passed {@link MoveCaretsOrigin}. To receive all caret movements, register for {@link MoveCaretsOrigin#DEFAULT} 
1212
     * or use {@link JTextComponent#setNavigationFilter}.
1213
     * </p><p>
1214
     * All the key part(s) of MoveCaretOrigin of a caret operation and `origin' parameter in this function must
1215
     * match in order for the filter to be invoked.
1216
     * </p><p>
1217
     * The NavigationFilter implementation <b>may downcast</b> the passed {@link NavigationFilter.FilterBypass FilterBypass}
1218
     * parameter to {@link NavigationFilterBypass} to get full infomration about the movement. 
1219
     * </p>
1220
     * @param origin the origin
1221
     * @param naviFilter the installed filter
1222
     * @see JTextComponent#setNavigationFilter
1223
     * @see NavigationFilterBypass
1224
     * @since 2.9
1225
     */
1226
    public void setNavigationFilter(MoveCaretsOrigin origin, @NullAllowed NavigationFilter naviFilter) {
1227
        if (origin == null) {
1228
            origin = MoveCaretsOrigin.DEFAULT;
1229
        }
1230
        final NavigationFilter prev = getNavigationFilter(origin);
1231
        if (naviFilter != null) {
1232
            // Note:
1233
            // if the caller passes in a non-cascading filter, we would loose the filter chain information.
1234
            // the alien filter is wrapped by CascadingNavigationFilter delegator, so the previous filter
1235
            // link is preserved.
1236
            if (!(naviFilter instanceof CascadingNavigationFilter)) {
1237
                final NavigationFilter del = naviFilter;
1238
                naviFilter = new CascadingNavigationFilter() {
1239
                    @Override
1240
                    public void setDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias) {
1241
                        del.setDot(fb, dot, bias);
1242
                    }
1243
1244
                    @Override
1245
                    public void moveDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias) {
1246
                        del.moveDot(fb, dot, bias);
1247
                    }
1248
1249
                    @Override
1250
                    public int getNextVisualPositionFrom(JTextComponent text, int pos, Position.Bias bias, int direction, Position.Bias[] biasRet) throws BadLocationException {
1251
                        return del.getNextVisualPositionFrom(text, pos, bias, direction, biasRet);
1252
                    }
1253
                };
1254
            }
1255
            ((CascadingNavigationFilter)naviFilter).setOwnerAndPrevious(this, origin, prev);
1256
        }
1257
        if (MoveCaretsOrigin.DEFAULT == origin) {
1258
            component.setNavigationFilter(naviFilter);
1259
        } else {
1260
            doPutNavigationFilter(origin.getActionType(), prev);
1261
        }
1262
    }
1263
    
1264
    /**
1265
     * Records the navigation filter. Note that the filter is stored in the JTextComponent rather than
1266
     * in this Caret. If the Component's UI changes or the caret is recreated for some reason, the 
1267
     * navigation filters remain registered.
1268
     * 
1269
     * @param type type of nav filter
1270
     * @param n the filter instance
1271
     */
1272
    private void doPutNavigationFilter(String type, NavigationFilter n) {
1273
        if (component == null) {
1274
            throw new IllegalStateException("Not attached to a Component");
1275
        }
1276
        Map<String, NavigationFilter> m = (Map<String, NavigationFilter>)component.getClientProperty(NAVIGATION_FILTER_PROPERTY);
1277
        if (m == null) {
1278
            if (n == null) {
1279
                return;
1280
            }
1281
            m = new HashMap<>();
1282
            component.putClientProperty(NAVIGATION_FILTER_PROPERTY, m);
1283
        } 
1284
        if (n == null) {
1285
            m.remove(type);
1286
        } else {
1287
            m.put(type, n);
1288
        }
1289
    }
1290
    
1291
    private NavigationFilter doGetNavigationFilter(String n) {
1292
        if (component == null) {
1293
            throw new IllegalStateException("Not attached to a Component");
1294
        }
1295
        Map<String, NavigationFilter> m = (Map<String, NavigationFilter>)component.getClientProperty(NAVIGATION_FILTER_PROPERTY);
1296
        return m == null ? null : m.get(n);
1297
    }
1039
1298
1040
    @Override
1299
    @Override
1041
    public int getBlinkRate() {
1300
    public int getBlinkRate() {
Lines 1143-1149 Link Here
1143
                moveDot(newDotOffset); // updates rs and fires state change
1402
                moveDot(newDotOffset); // updates rs and fires state change
1144
            } else {
1403
            } else {
1145
                updateRectangularSelectionPaintRect();
1404
                updateRectangularSelectionPaintRect();
1146
                fireStateChanged();
1405
                fireStateChanged(null);
1147
            }
1406
            }
1148
        } catch (BadLocationException ex) {
1407
        } catch (BadLocationException ex) {
1149
            // Leave selection as is
1408
            // Leave selection as is
Lines 1190-1202 Link Here
1190
     * @return 
1449
     * @return 
1191
     */
1450
     */
1192
    private int runTransaction(CaretTransaction.RemoveType removeType, int offset, CaretItem[] addCarets, CaretMoveHandler moveHandler) {
1451
    private int runTransaction(CaretTransaction.RemoveType removeType, int offset, CaretItem[] addCarets, CaretMoveHandler moveHandler) {
1452
        return runTransaction(removeType, offset, addCarets, moveHandler, MoveCaretsOrigin.DEFAULT);
1453
    }
1454
    
1455
    private int runTransaction(CaretTransaction.RemoveType removeType, int offset, CaretItem[] addCarets, CaretMoveHandler moveHandler, MoveCaretsOrigin org) {
1193
        lock();
1456
        lock();
1194
        try {
1457
        try {
1195
            if (activeTransaction == null) {
1458
            if (activeTransaction == null) {
1196
                JTextComponent c = component;
1459
                JTextComponent c = component;
1197
                Document d = activeDoc;
1460
                Document d = activeDoc;
1198
                if (c != null && d != null) {
1461
                if (c != null && d != null) {
1199
                    activeTransaction = new CaretTransaction(this, c, d);
1462
                    activeTransaction = new CaretTransaction(this, c, d, org);
1200
                    if (LOG.isLoggable(Level.FINE)) {
1463
                    if (LOG.isLoggable(Level.FINE)) {
1201
                        StringBuilder msgBuilder = new StringBuilder(200);
1464
                        StringBuilder msgBuilder = new StringBuilder(200);
1202
                        msgBuilder.append("EditorCaret.runTransaction(): removeType=").append(removeType).
1465
                        msgBuilder.append("EditorCaret.runTransaction(): removeType=").append(removeType).
Lines 1276-1282 Link Here
1276
                        }
1539
                        }
1277
                        if (activeTransaction.isAnyChange()) {
1540
                        if (activeTransaction.isAnyChange()) {
1278
                            // For now clear the lists and use old way TODO update to selective updating and rendering
1541
                            // For now clear the lists and use old way TODO update to selective updating and rendering
1279
                            fireStateChanged();
1542
                            fireStateChanged(activeTransaction.getOrigin());
1280
                            dispatchUpdate(true);
1543
                            dispatchUpdate(true);
1281
                            resetBlink();
1544
                            resetBlink();
1282
                        }
1545
                        }
Lines 1329-1342 Link Here
1329
    /**
1592
    /**
1330
     * Notifies listeners that caret position has changed.
1593
     * Notifies listeners that caret position has changed.
1331
     */
1594
     */
1332
    private void fireStateChanged() {
1595
    private void fireStateChanged(final MoveCaretsOrigin origin) {
1333
        Runnable runnable = new Runnable() {
1596
        Runnable runnable = new Runnable() {
1334
            public @Override void run() {
1597
            public @Override void run() {
1335
                JTextComponent c = component;
1598
                JTextComponent c = component;
1336
                if (c == null || c.getCaret() != EditorCaret.this) {
1599
                if (c == null || c.getCaret() != EditorCaret.this) {
1337
                    return;
1600
                    return;
1338
                }
1601
                }
1339
                fireEditorCaretChange(new EditorCaretEvent(EditorCaret.this, 0, Integer.MAX_VALUE)); // [TODO] temp firing without detailed info
1602
                fireEditorCaretChange(new EditorCaretEvent(EditorCaret.this, 0, Integer.MAX_VALUE, origin)); // [TODO] temp firing without detailed info
1340
                ChangeEvent evt = new ChangeEvent(EditorCaret.this);
1603
                ChangeEvent evt = new ChangeEvent(EditorCaret.this);
1341
                List<ChangeListener> listeners = changeListenerList.getListeners();
1604
                List<ChangeListener> listeners = changeListenerList.getListeners();
1342
                for (ChangeListener l : listeners) {
1605
                for (ChangeListener l : listeners) {
Lines 1883-1889 Link Here
1883
            rsDotRect.x = r.x;
2146
            rsDotRect.x = r.x;
1884
            rsDotRect.width = r.width;
2147
            rsDotRect.width = r.width;
1885
            updateRectangularSelectionPaintRect();
2148
            updateRectangularSelectionPaintRect();
1886
            fireStateChanged();
2149
            fireStateChanged(null);
1887
        }
2150
        }
1888
    }
2151
    }
1889
    
2152
    
Lines 2120-2126 Link Here
2120
                    } else { // No rectangular selection
2383
                    } else { // No rectangular selection
2121
                        RectangularSelectionTransferHandler.uninstall(component);
2384
                        RectangularSelectionTransferHandler.uninstall(component);
2122
                    }
2385
                    }
2123
                    fireStateChanged();
2386
                    fireStateChanged(null);
2124
                }
2387
                }
2125
            }
2388
            }
2126
        }
2389
        }
Lines 2177-2183 Link Here
2177
                    invalidateCaretBounds(offset);
2440
                    invalidateCaretBounds(offset);
2178
                    dispatchUpdate();
2441
                    dispatchUpdate();
2179
                    resetBlink();
2442
                    resetBlink();
2180
                    fireStateChanged();
2443
                    fireStateChanged(null);
2181
                    modified = false;
2444
                    modified = false;
2182
                }
2445
                }
2183
            } else {
2446
            } 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 (+178 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
     * Undefined action type. Use this description when registering for all possible
132
     * caret movements.
133
     */
134
    public static final MoveCaretsOrigin DEFAULT = new MoveCaretsOrigin("default", 0); // NOI18N
135
    private final String actionType;
136
    private final int direction;
137
138
    /**
139
     * Describes the origin by just the action type. 
140
     * @param actionType action type
141
     */
142
    public MoveCaretsOrigin(String actionType) {
143
        this.actionType = actionType;
144
        this.direction = 0;
145
    }
146
147
    /**
148
     * Specifies the origin by action type, and the overall moving direction
149
     * @param actionType action type
150
     * @param direction the intended direction of movement
151
     */
152
    public MoveCaretsOrigin(@NonNull String actionType, int direction) {
153
        Parameters.notNull("actionType", actionType); // NOI18N
154
        this.actionType = actionType;
155
        this.direction = direction;
156
    }
157
158
    /**
159
     * Returns the type of the action which originated the caret movement.
160
     * @return the action type.
161
     */
162
    @NonNull
163
    public String getActionType() {
164
        return actionType;
165
    }
166
167
    /**
168
     * Specifies the desired movement direction. Use {@link javax.swing.SwingConstants}
169
     * compass constants to specify the direction. 0 means the direction
170
     * is unspecified.
171
     *
172
     * @return The initial direction of movemnet
173
     */
174
    public int getDirection() {
175
        return direction;
176
    }
177
    
178
}
(-)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 EditorCaret         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 = owner.getNavigationFilter(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
            owner.setNavigationFilter(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 EditorCaret caret,
159
            @NonNull MoveCaretsOrigin origin) {
160
        Parameters.notNull("caret", caret);
161
        Parameters.notNull("origin", origin);
162
        if (owner != null) {
163
            throw new IllegalStateException();
164
        }
165
        caret.setNavigationFilter(origin, this);
166
    }
167
    
168
    public void setOwnerAndPrevious(EditorCaret ec, MoveCaretsOrigin orig, NavigationFilter prev) {
169
        if (this.owner != null) {
170
            throw new IllegalStateException("Can be registered only once");
171
        }
172
        this.owner = ec;
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