1 7 package javax.swing.text; 8 9 import java.awt.event.ActionEvent ; 10 import java.io.*; 11 import java.text.*; 12 import java.util.*; 13 import javax.swing.*; 14 import javax.swing.text.*; 15 16 78 public class InternationalFormatter extends DefaultFormatter { 79 82 private static final Format.Field[] EMPTY_FIELD_ARRAY =new Format.Field[0]; 83 84 87 private Format format; 88 91 private Comparable max; 92 95 private Comparable min; 96 97 120 125 private transient BitSet literalMask; 126 129 private transient AttributedCharacterIterator iterator; 130 134 private transient boolean validMask; 135 138 private transient String string; 139 144 private transient boolean ignoreDocumentMutate; 145 146 147 151 public InternationalFormatter() { 152 setOverwriteMode(false); 153 } 154 155 161 public InternationalFormatter(Format format) { 162 this(); 163 setFormat(format); 164 } 165 166 173 public void setFormat(Format format) { 174 this.format = format; 175 } 176 177 183 public Format getFormat() { 184 return format; 185 } 186 187 196 public void setMinimum(Comparable minimum) { 197 if (getValueClass() == null && minimum != null) { 198 setValueClass(minimum.getClass()); 199 } 200 min = minimum; 201 } 202 203 208 public Comparable getMinimum() { 209 return min; 210 } 211 212 221 public void setMaximum(Comparable max) { 222 if (getValueClass() == null && max != null) { 223 setValueClass(max.getClass()); 224 } 225 this.max = max; 226 } 227 228 233 public Comparable getMaximum() { 234 return max; 235 } 236 237 267 public void install(JFormattedTextField ftf) { 268 super.install(ftf); 269 updateMaskIfNecessary(); 270 positionCursorAtInitialLocation(); 272 } 273 274 282 public String valueToString(Object value) throws ParseException { 283 if (value == null) { 284 return ""; 285 } 286 Format f = getFormat(); 287 288 if (f == null) { 289 return value.toString(); 290 } 291 return f.format(value); 292 } 293 294 302 public Object stringToValue(String text) throws ParseException { 303 Object value = stringToValue(text, getFormat()); 304 305 if (value != null && getValueClass() != null && 308 !getValueClass().isInstance(value)) { 309 value = super.stringToValue(value.toString()); 310 } 311 try { 312 if (!isValidValue(value, true)) { 313 throw new ParseException("Value not within min/max range", 0); 314 } 315 } catch (ClassCastException cce) { 316 throw new ParseException("Class cast exception comparing values: " 317 + cce, 0); 318 } 319 return value; 320 } 321 322 332 public Format.Field[] getFields(int offset) { 333 if (getAllowsInvalid()) { 334 updateMask(); 336 } 337 338 Map attrs = getAttributes(offset); 339 340 if (attrs != null && attrs.size() > 0) { 341 ArrayList al = new ArrayList(); 342 343 al.addAll(attrs.keySet()); 344 return (Format.Field[])al.toArray(EMPTY_FIELD_ARRAY); 345 } 346 return EMPTY_FIELD_ARRAY; 347 } 348 349 354 public Object clone() throws CloneNotSupportedException { 355 InternationalFormatter formatter = (InternationalFormatter )super. 356 clone(); 357 358 formatter.literalMask = null; 359 formatter.iterator = null; 360 formatter.validMask = false; 361 formatter.string = null; 362 return formatter; 363 } 364 365 369 protected Action[] getActions() { 370 if (getSupportsIncrement()) { 371 return new Action[] { new IncrementAction("increment", 1), 372 new IncrementAction("decrement", -1) }; 373 } 374 return null; 375 } 376 377 381 Object stringToValue(String text, Format f) throws ParseException { 382 if (f == null) { 383 return text; 384 } 385 return f.parseObject(text); 386 } 387 388 395 boolean isValidValue(Object value, boolean wantsCCE) { 396 Comparable min = getMinimum(); 397 398 try { 399 if (min != null && min.compareTo(value) > 0) { 400 return false; 401 } 402 } catch (ClassCastException cce) { 403 if (wantsCCE) { 404 throw cce; 405 } 406 return false; 407 } 408 409 Comparable max = getMaximum(); 410 try { 411 if (max != null && max.compareTo(value) < 0) { 412 return false; 413 } 414 } catch (ClassCastException cce) { 415 if (wantsCCE) { 416 throw cce; 417 } 418 return false; 419 } 420 return true; 421 } 422 423 426 Map getAttributes(int index) { 427 if (isValidMask()) { 428 AttributedCharacterIterator iterator = getIterator(); 429 430 if (index >= 0 && index <= iterator.getEndIndex()) { 431 iterator.setIndex(index); 432 return iterator.getAttributes(); 433 } 434 } 435 return null; 436 } 437 438 439 444 int getAttributeStart(AttributedCharacterIterator.Attribute id) { 445 if (isValidMask()) { 446 AttributedCharacterIterator iterator = getIterator(); 447 448 iterator.first(); 449 while (iterator.current() != CharacterIterator.DONE) { 450 if (iterator.getAttribute(id) != null) { 451 return iterator.getIndex(); 452 } 453 iterator.next(); 454 } 455 } 456 return -1; 457 } 458 459 463 AttributedCharacterIterator getIterator() { 464 return iterator; 465 } 466 467 470 void updateMaskIfNecessary() { 471 if (!getAllowsInvalid() && (getFormat() != null)) { 472 if (!isValidMask()) { 473 updateMask(); 474 } 475 else { 476 String newString = getFormattedTextField().getText(); 477 478 if (!newString.equals(string)) { 479 updateMask(); 480 } 481 } 482 } 483 } 484 485 492 void updateMask() { 493 if (getFormat() != null) { 494 Document doc = getFormattedTextField().getDocument(); 495 496 validMask = false; 497 if (doc != null) { 498 try { 499 string = doc.getText(0, doc.getLength()); 500 } catch (BadLocationException ble) { 501 string = null; 502 } 503 if (string != null) { 504 try { 505 Object value = stringToValue(string); 506 AttributedCharacterIterator iterator = getFormat(). 507 formatToCharacterIterator(value); 508 509 updateMask(iterator); 510 } 511 catch (ParseException pe) {} 512 catch (IllegalArgumentException iae) {} 513 catch (NullPointerException npe) {} 514 } 515 } 516 } 517 } 518 519 522 int getLiteralCountTo(int index) { 523 int lCount = 0; 524 525 for (int counter = 0; counter < index; counter++) { 526 if (isLiteral(counter)) { 527 lCount++; 528 } 529 } 530 return lCount; 531 } 532 533 537 boolean isLiteral(int index) { 538 if (isValidMask() && index < string.length()) { 539 return literalMask.get(index); 540 } 541 return false; 542 } 543 544 547 char getLiteral(int index) { 548 if (isValidMask() && string != null && index < string.length()) { 549 return string.charAt(index); 550 } 551 return (char)0; 552 } 553 554 559 boolean isNavigatable(int offset) { 560 return !isLiteral(offset); 561 } 562 563 566 void updateValue(Object value) { 567 super.updateValue(value); 568 updateMaskIfNecessary(); 569 } 570 571 575 void replace(DocumentFilter.FilterBypass fb, int offset, 576 int length, String text, 577 AttributeSet attrs) throws BadLocationException { 578 if (ignoreDocumentMutate) { 579 fb.replace(offset, length, text, attrs); 580 return; 581 } 582 super.replace(fb, offset, length, text, attrs); 583 } 584 585 591 private int getNextNonliteralIndex(int index, int direction) { 592 int max = getFormattedTextField().getDocument().getLength(); 593 594 while (index >= 0 && index < max) { 595 if (isLiteral(index)) { 596 index += direction; 597 } 598 else { 599 return index; 600 } 601 } 602 return (direction == -1) ? 0 : max; 603 } 604 605 624 boolean canReplace(ReplaceHolder rh) { 625 if (!getAllowsInvalid()) { 626 String text = rh.text; 627 int tl = (text != null) ? text.length() : 0; 628 629 if (tl == 0 && rh.length == 1 && getFormattedTextField(). 630 getSelectionStart() != rh.offset) { 631 rh.offset = getNextNonliteralIndex(rh.offset, -1); 633 } 634 if (getOverwriteMode()) { 635 StringBuffer replace = null; 636 637 for (int counter = 0, textIndex = 0, 638 max = Math.max(tl, rh.length); counter < max; 639 counter++) { 640 if (isLiteral(rh.offset + counter)) { 641 if (replace != null) { 642 replace.append(getLiteral(rh.offset + 643 counter)); 644 } 645 if (textIndex < tl && text.charAt(textIndex) == 646 getLiteral(rh.offset + counter)) { 647 textIndex++; 648 } 649 else if (textIndex == 0) { 650 rh.offset++; 651 rh.length--; 652 counter--; 653 max--; 654 } 655 else if (replace == null) { 656 replace = new StringBuffer (max); 657 replace.append(text.substring(0, textIndex)); 658 replace.append(getLiteral(rh.offset + 659 counter)); 660 } 661 } 662 else if (textIndex < tl) { 663 if (replace != null) { 664 replace.append(text.charAt(textIndex)); 665 } 666 textIndex++; 667 } 668 else { 669 if (replace == null) { 671 replace = new StringBuffer (max); 672 if (textIndex > 0) { 673 replace.append(text.substring(0, textIndex)); 674 } 675 } 676 if (replace != null) { 677 replace.append(' '); 678 } 679 } 680 } 681 if (replace != null) { 682 rh.text = replace.toString(); 683 } 684 } 685 else if (tl > 0) { 686 rh.offset = getNextNonliteralIndex(rh.offset, 1); 688 } 689 else { 690 rh.offset = getNextNonliteralIndex(rh.offset, -1); 692 } 693 ((ExtendedReplaceHolder)rh).endOffset = rh.offset; 694 ((ExtendedReplaceHolder)rh).endTextLength = (rh.text != null) ? 695 rh.text.length() : 0; 696 } 697 else { 698 ((ExtendedReplaceHolder)rh).endOffset = rh.offset; 699 ((ExtendedReplaceHolder)rh).endTextLength = (rh.text != null) ? 700 rh.text.length() : 0; 701 } 702 boolean can = super.canReplace(rh); 703 if (can && !getAllowsInvalid()) { 704 ((ExtendedReplaceHolder)rh).resetFromValue(this); 705 } 706 return can; 707 } 708 709 715 boolean replace(ReplaceHolder rh) throws BadLocationException { 716 int start = -1; 717 int direction = 1; 718 int literalCount = -1; 719 720 if (rh.length > 0 && (rh.text == null || rh.text.length() == 0) && 721 (getFormattedTextField().getSelectionStart() != rh.offset || 722 rh.length > 1)) { 723 direction = -1; 724 } 725 if (!getAllowsInvalid()) { 726 if ((rh.text == null || rh.text.length() == 0) && rh.length > 0) { 727 start = getFormattedTextField().getSelectionStart(); 729 } 730 else { 731 start = rh.offset; 732 } 733 literalCount = getLiteralCountTo(start); 734 } 735 if (super.replace(rh)) { 736 if (start != -1) { 737 int end = ((ExtendedReplaceHolder)rh).endOffset; 738 739 end += ((ExtendedReplaceHolder)rh).endTextLength; 740 repositionCursor(literalCount, end, direction); 741 } 742 else { 743 start = ((ExtendedReplaceHolder)rh).endOffset; 744 if (direction == 1) { 745 start += ((ExtendedReplaceHolder)rh).endTextLength; 746 } 747 repositionCursor(start, direction); 748 } 749 return true; 750 } 751 return false; 752 } 753 754 761 private void repositionCursor(int startLiteralCount, int end, 762 int direction) { 763 int endLiteralCount = getLiteralCountTo(end); 764 765 if (endLiteralCount != end) { 766 end -= startLiteralCount; 767 for (int counter = 0; counter < end; counter++) { 768 if (isLiteral(counter)) { 769 end++; 770 } 771 } 772 } 773 repositionCursor(end, 1 ); 774 } 775 776 780 char getBufferedChar(int index) { 781 if (isValidMask()) { 782 if (string != null && index < string.length()) { 783 return string.charAt(index); 784 } 785 } 786 return (char)0; 787 } 788 789 792 boolean isValidMask() { 793 return validMask; 794 } 795 796 799 boolean isLiteral(Map attributes) { 800 return ((attributes == null) || attributes.size() == 0); 801 } 802 803 808 private void updateMask(AttributedCharacterIterator iterator) { 809 if (iterator != null) { 810 validMask = true; 811 this.iterator = iterator; 812 813 if (literalMask == null) { 815 literalMask = new BitSet(); 816 } 817 else { 818 for (int counter = literalMask.length() - 1; counter >= 0; 819 counter--) { 820 literalMask.clear(counter); 821 } 822 } 823 824 iterator.first(); 825 while (iterator.current() != CharacterIterator.DONE) { 826 Map attributes = iterator.getAttributes(); 827 boolean set = isLiteral(attributes); 828 int start = iterator.getIndex(); 829 int end = iterator.getRunLimit(); 830 831 while (start < end) { 832 if (set) { 833 literalMask.set(start); 834 } 835 else { 836 literalMask.clear(start); 837 } 838 start++; 839 } 840 iterator.setIndex(start); 841 } 842 } 843 } 844 845 850 boolean canIncrement(Object field, int cursorPosition) { 851 return (field != null); 852 } 853 854 857 void selectField(Object f, int count) { 858 AttributedCharacterIterator iterator = getIterator(); 859 860 if (iterator != null && 861 (f instanceof AttributedCharacterIterator.Attribute)) { 862 AttributedCharacterIterator.Attribute field = 863 (AttributedCharacterIterator.Attribute)f; 864 865 iterator.first(); 866 while (iterator.current() != CharacterIterator.DONE) { 867 while (iterator.getAttribute(field) == null && 868 iterator.next() != CharacterIterator.DONE); 869 if (iterator.current() != CharacterIterator.DONE) { 870 int limit = iterator.getRunLimit(field); 871 872 if (--count <= 0) { 873 getFormattedTextField().select(iterator.getIndex(), 874 limit); 875 break; 876 } 877 iterator.setIndex(limit); 878 iterator.next(); 879 } 880 } 881 } 882 } 883 884 887 Object getAdjustField(int start, Map attributes) { 888 return null; 889 } 890 891 896 private int getFieldTypeCountTo(Object f, int start) { 897 AttributedCharacterIterator iterator = getIterator(); 898 int count = 0; 899 900 if (iterator != null && 901 (f instanceof AttributedCharacterIterator.Attribute)) { 902 AttributedCharacterIterator.Attribute field = 903 (AttributedCharacterIterator.Attribute)f; 904 int index = 0; 905 906 iterator.first(); 907 while (iterator.getIndex() < start) { 908 while (iterator.getAttribute(field) == null && 909 iterator.next() != CharacterIterator.DONE); 910 if (iterator.current() != CharacterIterator.DONE) { 911 iterator.setIndex(iterator.getRunLimit(field)); 912 iterator.next(); 913 count++; 914 } 915 else { 916 break; 917 } 918 } 919 } 920 return count; 921 } 922 923 930 Object adjustValue(Object value, Map attributes, Object field, 931 int direction) throws 932 BadLocationException , ParseException { 933 return null; 934 } 935 936 943 boolean getSupportsIncrement() { 944 return false; 945 } 946 947 951 void resetValue(Object value) throws BadLocationException , ParseException { 952 Document doc = getFormattedTextField().getDocument(); 953 String string = valueToString(value); 954 955 try { 956 ignoreDocumentMutate = true; 957 doc.remove(0, doc.getLength()); 958 doc.insertString(0, string, null); 959 } finally { 960 ignoreDocumentMutate = false; 961 } 962 updateValue(value); 963 } 964 965 969 private void readObject(ObjectInputStream s) 970 throws IOException, ClassNotFoundException { 971 s.defaultReadObject(); 972 updateMaskIfNecessary(); 973 } 974 975 976 979 ReplaceHolder getReplaceHolder(DocumentFilter.FilterBypass fb, int offset, 980 int length, String text, 981 AttributeSet attrs) { 982 if (replaceHolder == null) { 983 replaceHolder = new ExtendedReplaceHolder(); 984 } 985 return super.getReplaceHolder(fb, offset, length, text, attrs); 986 } 987 988 989 994 static class ExtendedReplaceHolder extends ReplaceHolder { 995 997 int endOffset; 998 1000 int endTextLength; 1001 1002 1006 void resetFromValue(InternationalFormatter formatter) { 1007 offset = 0; 1010 try { 1011 text = formatter.valueToString(value); 1012 } catch (ParseException pe) { 1013 text = ""; 1016 } 1017 length = fb.getDocument().getLength(); 1018 } 1019 } 1020 1021 1022 1027 private class IncrementAction extends AbstractAction { 1028 private int direction; 1029 1030 IncrementAction(String name, int direction) { 1031 super(name); 1032 this.direction = direction; 1033 } 1034 1035 public void actionPerformed(ActionEvent ae) { 1036 if (getAllowsInvalid()) { 1037 updateMask(); 1039 } 1040 1041 boolean validEdit = false; 1042 1043 if (isValidMask()) { 1044 int start = getFormattedTextField().getSelectionStart(); 1045 1046 if (start != -1) { 1047 AttributedCharacterIterator iterator = getIterator(); 1048 1049 iterator.setIndex(start); 1050 1051 Map attributes = iterator.getAttributes(); 1052 Object field = getAdjustField(start, attributes); 1053 1054 if (canIncrement(field, start)) { 1055 try { 1056 Object value = stringToValue( 1057 getFormattedTextField().getText()); 1058 int fieldTypeCount = getFieldTypeCountTo( 1059 field, start); 1060 1061 value = adjustValue(value, attributes, 1062 field, direction); 1063 if (value != null && isValidValue(value, false)) { 1064 resetValue(value); 1065 updateMask(); 1066 1067 if (isValidMask()) { 1068 selectField(field, fieldTypeCount); 1069 } 1070 validEdit = true; 1071 } 1072 } 1073 catch (ParseException pe) { } 1074 catch (BadLocationException ble) { } 1075 } 1076 } 1077 } 1078 if (!validEdit) { 1079 invalidEdit(); 1080 } 1081 } 1082 } 1083} 1084 | Popular Tags |