History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/text/DefaultFormatter.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/text/DefaultFormatter.java+760−0
@@ -0,0 +1,760 @@
1+/*
2+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+package javax.swing.text;
26+
27+import java.io.Serializable;
28+import java.lang.reflect.*;
29+import java.text.ParseException;
30+import javax.swing.*;
31+import javax.swing.text.*;
32+
33+/**
34+ * <code>DefaultFormatter</code> formats aribtrary objects. Formatting is done
35+ * by invoking the <code>toString</code> method. In order to convert the
36+ * value back to a String, your class must provide a constructor that
37+ * takes a String argument. If no single argument constructor that takes a
38+ * String is found, the returned value will be the String passed into
39+ * <code>stringToValue</code>.
40+ * <p>
41+ * Instances of <code>DefaultFormatter</code> can not be used in multiple
42+ * instances of <code>JFormattedTextField</code>. To obtain a copy of
43+ * an already configured <code>DefaultFormatter</code>, use the
44+ * <code>clone</code> method.
45+ * <p>
46+ * <strong>Warning:</strong>
47+ * Serialized objects of this class will not be compatible with
48+ * future Swing releases. The current serialization support is
49+ * appropriate for short term storage or RMI between applications running
50+ * the same version of Swing. As of 1.4, support for long term storage
51+ * of all JavaBeans<sup><font size="-2">TM</font></sup>
52+ * has been added to the <code>java.beans</code> package.
53+ * Please see {@link java.beans.XMLEncoder}.
54+ *
55+ * @see javax.swing.JFormattedTextField.AbstractFormatter
56+ *
57+ * @since 1.4
58+ */
59+public class DefaultFormatter extends JFormattedTextField.AbstractFormatter
60+ implements Cloneable, Serializable {
61+ /** Indicates if the value being edited must match the mask. */
62+ private boolean allowsInvalid;
63+
64+ /** If true, editing mode is in overwrite (or strikethough). */
65+ private boolean overwriteMode;
66+
67+ /** If true, any time a valid edit happens commitEdit is invoked. */
68+ private boolean commitOnEdit;
69+
70+ /** Class used to create new instances. */
71+ private Class<?> valueClass;
72+
73+ /** NavigationFilter that forwards calls back to DefaultFormatter. */
74+ private NavigationFilter navigationFilter;
75+
76+ /** DocumentFilter that forwards calls back to DefaultFormatter. */
77+ private DocumentFilter documentFilter;
78+
79+ /** Used during replace to track the region to replace. */
80+ transient ReplaceHolder replaceHolder;
81+
82+
83+ /**
84+ * Creates a DefaultFormatter.
85+ */
86+ public DefaultFormatter() {
87+ overwriteMode = true;
88+ allowsInvalid = true;
89+ }
90+
91+ /**
92+ * Installs the <code>DefaultFormatter</code> onto a particular
93+ * <code>JFormattedTextField</code>.
94+ * This will invoke <code>valueToString</code> to convert the
95+ * current value from the <code>JFormattedTextField</code> to
96+ * a String. This will then install the <code>Action</code>s from
97+ * <code>getActions</code>, the <code>DocumentFilter</code>
98+ * returned from <code>getDocumentFilter</code> and the
99+ * <code>NavigationFilter</code> returned from
100+ * <code>getNavigationFilter</code> onto the
101+ * <code>JFormattedTextField</code>.
102+ * <p>
103+ * Subclasses will typically only need to override this if they
104+ * wish to install additional listeners on the
105+ * <code>JFormattedTextField</code>.
106+ * <p>
107+ * If there is a <code>ParseException</code> in converting the
108+ * current value to a String, this will set the text to an empty
109+ * String, and mark the <code>JFormattedTextField</code> as being
110+ * in an invalid state.
111+ * <p>
112+ * While this is a public method, this is typically only useful
113+ * for subclassers of <code>JFormattedTextField</code>.
114+ * <code>JFormattedTextField</code> will invoke this method at
115+ * the appropriate times when the value changes, or its internal
116+ * state changes.
117+ *
118+ * @param ftf JFormattedTextField to format for, may be null indicating
119+ * uninstall from current JFormattedTextField.
120+ */
121+ public void install(JFormattedTextField ftf) {
122+ super.install(ftf);
123+ positionCursorAtInitialLocation();
124+ }
125+
126+ /**
127+ * Sets when edits are published back to the
128+ * <code>JFormattedTextField</code>. If true, <code>commitEdit</code>
129+ * is invoked after every valid edit (any time the text is edited). On
130+ * the other hand, if this is false than the <code>DefaultFormatter</code>
131+ * does not publish edits back to the <code>JFormattedTextField</code>.
132+ * As such, the only time the value of the <code>JFormattedTextField</code>
133+ * will change is when <code>commitEdit</code> is invoked on
134+ * <code>JFormattedTextField</code>, typically when enter is pressed
135+ * or focus leaves the <code>JFormattedTextField</code>.
136+ *
137+ * @param commit Used to indicate when edits are commited back to the
138+ * JTextComponent
139+ */
140+ public void setCommitsOnValidEdit(boolean commit) {
141+ commitOnEdit = commit;
142+ }
143+
144+ /**
145+ * Returns when edits are published back to the
146+ * <code>JFormattedTextField</code>.
147+ *
148+ * @return true if edits are commited after evey valid edit
149+ */
150+ public boolean getCommitsOnValidEdit() {
151+ return commitOnEdit;
152+ }
153+
154+ /**
155+ * Configures the behavior when inserting characters. If
156+ * <code>overwriteMode</code> is true (the default), new characters
157+ * overwrite existing characters in the model.
158+ *
159+ * @param overwriteMode Indicates if overwrite or overstrike mode is used
160+ */
161+ public void setOverwriteMode(boolean overwriteMode) {
162+ this.overwriteMode = overwriteMode;
163+ }
164+
165+ /**
166+ * Returns the behavior when inserting characters.
167+ *
168+ * @return true if newly inserted characters overwrite existing characters
169+ */
170+ public boolean getOverwriteMode() {
171+ return overwriteMode;
172+ }
173+
174+ /**
175+ * Sets whether or not the value being edited is allowed to be invalid
176+ * for a length of time (that is, <code>stringToValue</code> throws
177+ * a <code>ParseException</code>).
178+ * It is often convenient to allow the user to temporarily input an
179+ * invalid value.
180+ *
181+ * @param allowsInvalid Used to indicate if the edited value must always
182+ * be valid
183+ */
184+ public void setAllowsInvalid(boolean allowsInvalid) {
185+ this.allowsInvalid = allowsInvalid;
186+ }
187+
188+ /**
189+ * Returns whether or not the value being edited is allowed to be invalid
190+ * for a length of time.
191+ *
192+ * @return false if the edited value must always be valid
193+ */
194+ public boolean getAllowsInvalid() {
195+ return allowsInvalid;
196+ }
197+
198+ /**
199+ * Sets that class that is used to create new Objects. If the
200+ * passed in class does not have a single argument constructor that
201+ * takes a String, String values will be used.
202+ *
203+ * @param valueClass Class used to construct return value from
204+ * stringToValue
205+ */
206+ public void setValueClass(Class<?> valueClass) {
207+ this.valueClass = valueClass;
208+ }
209+
210+ /**
211+ * Returns that class that is used to create new Objects.
212+ *
213+ * @return Class used to constuct return value from stringToValue
214+ */
215+ public Class<?> getValueClass() {
216+ return valueClass;
217+ }
218+
219+ /**
220+ * Converts the passed in String into an instance of
221+ * <code>getValueClass</code> by way of the constructor that
222+ * takes a String argument. If <code>getValueClass</code>
223+ * returns null, the Class of the current value in the
224+ * <code>JFormattedTextField</code> will be used. If this is null, a
225+ * String will be returned. If the constructor thows an exception, a
226+ * <code>ParseException</code> will be thrown. If there is no single
227+ * argument String constructor, <code>string</code> will be returned.
228+ *
229+ * @throws ParseException if there is an error in the conversion
230+ * @param string String to convert
231+ * @return Object representation of text
232+ */
233+ public Object stringToValue(String string) throws ParseException {
234+ Class<?> vc = getValueClass();
235+ JFormattedTextField ftf = getFormattedTextField();
236+
237+ if (vc == null && ftf != null) {
238+ Object value = ftf.getValue();
239+
240+ if (value != null) {
241+ vc = value.getClass();
242+ }
243+ }
244+ if (vc != null) {
245+ Constructor cons;
246+
247+ try {
248+ cons = vc.getConstructor(new Class[] { String.class });
249+
250+ } catch (NoSuchMethodException nsme) {
251+ cons = null;
252+ }
253+
254+ if (cons != null) {
255+ try {
256+ return cons.newInstance(new Object[] { string });
257+ } catch (Throwable ex) {
258+ throw new ParseException("Error creating instance", 0);
259+ }
260+ }
261+ }
262+ return string;
263+ }
264+
265+ /**
266+ * Converts the passed in Object into a String by way of the
267+ * <code>toString</code> method.
268+ *
269+ * @throws ParseException if there is an error in the conversion
270+ * @param value Value to convert
271+ * @return String representation of value
272+ */
273+ public String valueToString(Object value) throws ParseException {
274+ if (value == null) {
275+ return "";
276+ }
277+ return value.toString();
278+ }
279+
280+ /**
281+ * Returns the <code>DocumentFilter</code> used to restrict the characters
282+ * that can be input into the <code>JFormattedTextField</code>.
283+ *
284+ * @return DocumentFilter to restrict edits
285+ */
286+ protected DocumentFilter getDocumentFilter() {
287+ if (documentFilter == null) {
288+ documentFilter = new DefaultDocumentFilter();
289+ }
290+ return documentFilter;
291+ }
292+
293+ /**
294+ * Returns the <code>NavigationFilter</code> used to restrict where the
295+ * cursor can be placed.
296+ *
297+ * @return NavigationFilter to restrict navigation
298+ */
299+ protected NavigationFilter getNavigationFilter() {
300+ if (navigationFilter == null) {
301+ navigationFilter = new DefaultNavigationFilter();
302+ }
303+ return navigationFilter;
304+ }
305+
306+ /**
307+ * Creates a copy of the DefaultFormatter.
308+ *
309+ * @return copy of the DefaultFormatter
310+ */
311+ public Object clone() throws CloneNotSupportedException {
312+ DefaultFormatter formatter = (DefaultFormatter)super.clone();
313+
314+ formatter.navigationFilter = null;
315+ formatter.documentFilter = null;
316+ formatter.replaceHolder = null;
317+ return formatter;
318+ }
319+
320+
321+ /**
322+ * Positions the cursor at the initial location.
323+ */
324+ void positionCursorAtInitialLocation() {
325+ JFormattedTextField ftf = getFormattedTextField();
326+ if (ftf != null) {
327+ ftf.setCaretPosition(getInitialVisualPosition());
328+ }
329+ }
330+
331+ /**
332+ * Returns the initial location to position the cursor at. This forwards
333+ * the call to <code>getNextNavigatableChar</code>.
334+ */
335+ int getInitialVisualPosition() {
336+ return getNextNavigatableChar(0, 1);
337+ }
338+
339+ /**
340+ * Subclasses should override this if they want cursor navigation
341+ * to skip certain characters. A return value of false indicates
342+ * the character at <code>offset</code> should be skipped when
343+ * navigating throught the field.
344+ */
345+ boolean isNavigatable(int offset) {
346+ return true;
347+ }
348+
349+ /**
350+ * Returns true if the text in <code>text</code> can be inserted. This
351+ * does not mean the text will ultimately be inserted, it is used if
352+ * text can trivially reject certain characters.
353+ */
354+ boolean isLegalInsertText(String text) {
355+ return true;
356+ }
357+
358+ /**
359+ * Returns the next editable character starting at offset incrementing
360+ * the offset by <code>direction</code>.
361+ */
362+ private int getNextNavigatableChar(int offset, int direction) {
363+ int max = getFormattedTextField().getDocument().getLength();
364+
365+ while (offset >= 0 && offset < max) {
366+ if (isNavigatable(offset)) {
367+ return offset;
368+ }
369+ offset += direction;
370+ }
371+ return offset;
372+ }
373+
374+ /**
375+ * A convenience methods to return the result of deleting
376+ * <code>deleteLength</code> characters at <code>offset</code>
377+ * and inserting <code>replaceString</code> at <code>offset</code>
378+ * in the current text field.
379+ */
380+ String getReplaceString(int offset, int deleteLength,
381+ String replaceString) {
382+ String string = getFormattedTextField().getText();
383+ String result;
384+
385+ result = string.substring(0, offset);
386+ if (replaceString != null) {
387+ result += replaceString;
388+ }
389+ if (offset + deleteLength < string.length()) {
390+ result += string.substring(offset + deleteLength);
391+ }
392+ return result;
393+ }
394+
395+ /*
396+ * Returns true if the operation described by <code>rh</code> will
397+ * result in a legal edit. This may set the <code>value</code>
398+ * field of <code>rh</code>.
399+ */
400+ boolean isValidEdit(ReplaceHolder rh) {
401+ if (!getAllowsInvalid()) {
402+ String newString = getReplaceString(rh.offset, rh.length, rh.text);
403+
404+ try {
405+ rh.value = stringToValue(newString);
406+
407+ return true;
408+ } catch (ParseException pe) {
409+ return false;
410+ }
411+ }
412+ return true;
413+ }
414+
415+ /**
416+ * Invokes <code>commitEdit</code> on the JFormattedTextField.
417+ */
418+ void commitEdit() throws ParseException {
419+ JFormattedTextField ftf = getFormattedTextField();
420+
421+ if (ftf != null) {
422+ ftf.commitEdit();
423+ }
424+ }
425+
426+ /**
427+ * Pushes the value to the JFormattedTextField if the current value
428+ * is valid and invokes <code>setEditValid</code> based on the
429+ * validity of the value.
430+ */
431+ void updateValue() {
432+ updateValue(null);
433+ }
434+
435+ /**
436+ * Pushes the <code>value</code> to the editor if we are to
437+ * commit on edits. If <code>value</code> is null, the current value
438+ * will be obtained from the text component.
439+ */
440+ void updateValue(Object value) {
441+ try {
442+ if (value == null) {
443+ String string = getFormattedTextField().getText();
444+
445+ value = stringToValue(string);
446+ }
447+
448+ if (getCommitsOnValidEdit()) {
449+ commitEdit();
450+ }
451+ setEditValid(true);
452+ } catch (ParseException pe) {
453+ setEditValid(false);
454+ }
455+ }
456+
457+ /**
458+ * Returns the next cursor position from offset by incrementing
459+ * <code>direction</code>. This uses
460+ * <code>getNextNavigatableChar</code>
461+ * as well as constraining the location to the max position.
462+ */
463+ int getNextCursorPosition(int offset, int direction) {
464+ int newOffset = getNextNavigatableChar(offset, direction);
465+ int max = getFormattedTextField().getDocument().getLength();
466+
467+ if (!getAllowsInvalid()) {
468+ if (direction == -1 && offset == newOffset) {
469+ // Case where hit backspace and only characters before
470+ // offset are fixed.
471+ newOffset = getNextNavigatableChar(newOffset, 1);
472+ if (newOffset >= max) {
473+ newOffset = offset;
474+ }
475+ }
476+ else if (direction == 1 && newOffset >= max) {
477+ // Don't go beyond last editable character.
478+ newOffset = getNextNavigatableChar(max - 1, -1);
479+ if (newOffset < max) {
480+ newOffset++;
481+ }
482+ }
483+ }
484+ return newOffset;
485+ }
486+
487+ /**
488+ * Resets the cursor by using getNextCursorPosition.
489+ */
490+ void repositionCursor(int offset, int direction) {
491+ getFormattedTextField().getCaret().setDot(getNextCursorPosition
492+ (offset, direction));
493+ }
494+
495+
496+ /**
497+ * Finds the next navigatable character.
498+ */
499+ int getNextVisualPositionFrom(JTextComponent text, int pos,
500+ Position.Bias bias, int direction,
501+ Position.Bias[] biasRet)
502+ throws BadLocationException {
503+ int value = text.getUI().getNextVisualPositionFrom(text, pos, bias,
504+ direction, biasRet);
505+
506+ if (value == -1) {
507+ return -1;
508+ }
509+ if (!getAllowsInvalid() && (direction == SwingConstants.EAST ||
510+ direction == SwingConstants.WEST)) {
511+ int last = -1;
512+
513+ while (!isNavigatable(value) && value != last) {
514+ last = value;
515+ value = text.getUI().getNextVisualPositionFrom(
516+ text, value, bias, direction,biasRet);
517+ }
518+ int max = getFormattedTextField().getDocument().getLength();
519+ if (last == value || value == max) {
520+ if (value == 0) {
521+ biasRet[0] = Position.Bias.Forward;
522+ value = getInitialVisualPosition();
523+ }
524+ if (value >= max && max > 0) {
525+ // Pending: should not assume forward!
526+ biasRet[0] = Position.Bias.Forward;
527+ value = getNextNavigatableChar(max - 1, -1) + 1;
528+ }
529+ }
530+ }
531+ return value;
532+ }
533+
534+ /**
535+ * Returns true if the edit described by <code>rh</code> will result
536+ * in a legal value.
537+ */
538+ boolean canReplace(ReplaceHolder rh) {
539+ return isValidEdit(rh);
540+ }
541+
542+ /**
543+ * DocumentFilter method, funnels into <code>replace</code>.
544+ */
545+ void replace(DocumentFilter.FilterBypass fb, int offset,
546+ int length, String text,
547+ AttributeSet attrs) throws BadLocationException {
548+ ReplaceHolder rh = getReplaceHolder(fb, offset, length, text, attrs);
549+
550+ replace(rh);
551+ }
552+
553+ /**
554+ * If the edit described by <code>rh</code> is legal, this will
555+ * return true, commit the edit (if necessary) and update the cursor
556+ * position. This forwards to <code>canReplace</code> and
557+ * <code>isLegalInsertText</code> as necessary to determine if
558+ * the edit is in fact legal.
559+ * <p>
560+ * All of the DocumentFilter methods funnel into here, you should
561+ * generally only have to override this.
562+ */
563+ boolean replace(ReplaceHolder rh) throws BadLocationException {
564+ boolean valid = true;
565+ int direction = 1;
566+
567+ if (rh.length > 0 && (rh.text == null || rh.text.length() == 0) &&
568+ (getFormattedTextField().getSelectionStart() != rh.offset ||
569+ rh.length > 1)) {
570+ direction = -1;
571+ }
572+
573+ if (getOverwriteMode() && rh.text != null &&
574+ getFormattedTextField().getSelectedText() == null)
575+ {
576+ rh.length = Math.min(Math.max(rh.length, rh.text.length()),
577+ rh.fb.getDocument().getLength() - rh.offset);
578+ }
579+ if ((rh.text != null && !isLegalInsertText(rh.text)) ||
580+ !canReplace(rh) ||
581+ (rh.length == 0 && (rh.text == null || rh.text.length() == 0))) {
582+ valid = false;
583+ }
584+ if (valid) {
585+ int cursor = rh.cursorPosition;
586+
587+ rh.fb.replace(rh.offset, rh.length, rh.text, rh.attrs);
588+ if (cursor == -1) {
589+ cursor = rh.offset;
590+ if (direction == 1 && rh.text != null) {
591+ cursor = rh.offset + rh.text.length();
592+ }
593+ }
594+ updateValue(rh.value);
595+ repositionCursor(cursor, direction);
596+ return true;
597+ }
598+ else {
599+ invalidEdit();
600+ }
601+ return false;
602+ }
603+
604+ /**
605+ * NavigationFilter method, subclasses that wish finer control should
606+ * override this.
607+ */
608+ void setDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias){
609+ fb.setDot(dot, bias);
610+ }
611+
612+ /**
613+ * NavigationFilter method, subclasses that wish finer control should
614+ * override this.
615+ */
616+ void moveDot(NavigationFilter.FilterBypass fb, int dot,
617+ Position.Bias bias) {
618+ fb.moveDot(dot, bias);
619+ }
620+
621+
622+ /**
623+ * Returns the ReplaceHolder to track the replace of the specified
624+ * text.
625+ */
626+ ReplaceHolder getReplaceHolder(DocumentFilter.FilterBypass fb, int offset,
627+ int length, String text,
628+ AttributeSet attrs) {
629+ if (replaceHolder == null) {
630+ replaceHolder = new ReplaceHolder();
631+ }
632+ replaceHolder.reset(fb, offset, length, text, attrs);
633+ return replaceHolder;
634+ }
635+
636+
637+ /**
638+ * ReplaceHolder is used to track where insert/remove/replace is
639+ * going to happen.
640+ */
641+ static class ReplaceHolder {
642+ /** The FilterBypass that was passed to the DocumentFilter method. */
643+ DocumentFilter.FilterBypass fb;
644+ /** Offset where the remove/insert is going to occur. */
645+ int offset;
646+ /** Length of text to remove. */
647+ int length;
648+ /** The text to insert, may be null. */
649+ String text;
650+ /** AttributeSet to attach to text, may be null. */
651+ AttributeSet attrs;
652+ /** The resulting value, this may never be set. */
653+ Object value;
654+ /** Position the cursor should be adjusted from. If this is -1
655+ * the cursor position will be adjusted based on the direction of
656+ * the replace (-1: offset, 1: offset + text.length()), otherwise
657+ * the cursor position is adusted from this position.
658+ */
659+ int cursorPosition;
660+
661+ void reset(DocumentFilter.FilterBypass fb, int offset, int length,
662+ String text, AttributeSet attrs) {
663+ this.fb = fb;
664+ this.offset = offset;
665+ this.length = length;
666+ this.text = text;
667+ this.attrs = attrs;
668+ this.value = null;
669+ cursorPosition = -1;
670+ }
671+ }
672+
673+
674+ /**
675+ * NavigationFilter implementation that calls back to methods with
676+ * same name in DefaultFormatter.
677+ */
678+ private class DefaultNavigationFilter extends NavigationFilter
679+ implements Serializable {
680+ public void setDot(FilterBypass fb, int dot, Position.Bias bias) {
681+ JTextComponent tc = DefaultFormatter.this.getFormattedTextField();
682+ if (tc.composedTextExists()) {
683+ // bypass the filter
684+ fb.setDot(dot, bias);
685+ } else {
686+ DefaultFormatter.this.setDot(fb, dot, bias);
687+ }
688+ }
689+
690+ public void moveDot(FilterBypass fb, int dot, Position.Bias bias) {
691+ JTextComponent tc = DefaultFormatter.this.getFormattedTextField();
692+ if (tc.composedTextExists()) {
693+ // bypass the filter
694+ fb.moveDot(dot, bias);
695+ } else {
696+ DefaultFormatter.this.moveDot(fb, dot, bias);
697+ }
698+ }
699+
700+ public int getNextVisualPositionFrom(JTextComponent text, int pos,
701+ Position.Bias bias,
702+ int direction,
703+ Position.Bias[] biasRet)
704+ throws BadLocationException {
705+ if (text.composedTextExists()) {
706+ // forward the call to the UI directly
707+ return text.getUI().getNextVisualPositionFrom(
708+ text, pos, bias, direction, biasRet);
709+ } else {
710+ return DefaultFormatter.this.getNextVisualPositionFrom(
711+ text, pos, bias, direction, biasRet);
712+ }
713+ }
714+ }
715+
716+
717+ /**
718+ * DocumentFilter implementation that calls back to the replace
719+ * method of DefaultFormatter.
720+ */
721+ private class DefaultDocumentFilter extends DocumentFilter implements
722+ Serializable {
723+ public void remove(FilterBypass fb, int offset, int length) throws
724+ BadLocationException {
725+ JTextComponent tc = DefaultFormatter.this.getFormattedTextField();
726+ if (tc.composedTextExists()) {
727+ // bypass the filter
728+ fb.remove(offset, length);
729+ } else {
730+ DefaultFormatter.this.replace(fb, offset, length, null, null);
731+ }
732+ }
733+
734+ public void insertString(FilterBypass fb, int offset,
735+ String string, AttributeSet attr) throws
736+ BadLocationException {
737+ JTextComponent tc = DefaultFormatter.this.getFormattedTextField();
738+ if (tc.composedTextExists() ||
739+ Utilities.isComposedTextAttributeDefined(attr)) {
740+ // bypass the filter
741+ fb.insertString(offset, string, attr);
742+ } else {
743+ DefaultFormatter.this.replace(fb, offset, 0, string, attr);
744+ }
745+ }
746+
747+ public void replace(FilterBypass fb, int offset, int length,
748+ String text, AttributeSet attr) throws
749+ BadLocationException {
750+ JTextComponent tc = DefaultFormatter.this.getFormattedTextField();
751+ if (tc.composedTextExists() ||
752+ Utilities.isComposedTextAttributeDefined(attr)) {
753+ // bypass the filter
754+ fb.replace(offset, length, text, attr);
755+ } else {
756+ DefaultFormatter.this.replace(fb, offset, length, text, attr);
757+ }
758+ }
759+ }
760+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t