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 { |