< prev index next >

modules/javafx.controls/src/main/java/javafx/scene/control/TextInputControl.java

Print this page




  48 import javafx.beans.value.ChangeListener;
  49 import javafx.beans.value.ObservableStringValue;
  50 import javafx.beans.value.ObservableValue;
  51 import javafx.beans.value.WritableValue;
  52 import javafx.css.CssMetaData;
  53 import javafx.css.FontCssMetaData;
  54 import javafx.css.PseudoClass;
  55 import javafx.css.StyleOrigin;
  56 import javafx.css.Styleable;
  57 import javafx.css.StyleableObjectProperty;
  58 import javafx.css.StyleableProperty;
  59 import javafx.scene.AccessibleAction;
  60 import javafx.scene.AccessibleAttribute;
  61 import javafx.scene.input.Clipboard;
  62 import javafx.scene.input.ClipboardContent;
  63 import javafx.scene.text.Font;
  64 
  65 import java.text.BreakIterator;
  66 import java.util.ArrayList;
  67 import java.util.Collections;

  68 import java.util.List;
  69 
  70 import com.sun.javafx.util.Utils;
  71 import com.sun.javafx.binding.ExpressionHelper;
  72 import com.sun.javafx.scene.NodeHelper;
  73 import javafx.util.StringConverter;
  74 
  75 /**
  76  * Abstract base class for text input controls.
  77  * @since JavaFX 2.0
  78  */
  79 @DefaultProperty("text")
  80 public abstract class TextInputControl extends Control {
  81     /**
  82      * Interface representing a text input's content. Since it is an ObservableStringValue,
  83      * you can also bind to, or observe the content.
  84      * @since JavaFX 2.0
  85      */
  86     protected interface Content extends ObservableStringValue {
  87         /**


 553                     return;
 554                 }
 555             }
 556 
 557             // Update the content
 558             updateContent(change, oldLength == 0);
 559 
 560         }
 561     }
 562 
 563     private void updateContent(TextFormatter.Change change, boolean forceNewUndoRecord) {
 564         final boolean nonEmptySelection = getSelection().getLength() > 0;
 565         String oldText = getText(change.start, change.end);
 566         int adjustmentAmount = replaceText(change.start, change.end, change.text, change.getAnchor(), change.getCaretPosition());
 567         String newText = getText(change.start, change.start + change.text.length() - adjustmentAmount);
 568         if (newText.equals(oldText)) {
 569             // Undo record not required as there is no change in the text.
 570             return;
 571         }
 572 
 573         // If you select some stuff and type anything, then we need to
 574         // create an undo record. If the range is a single character and
 575         // is right next to the index of the last undo record end index, then
 576         // we don't need to create a new undo record. In all other cases
 577         // we do.








 578         int endOfUndoChange = undoChange == undoChangeHead ? -1 : undoChange.start + undoChange.newText.length();











 579         if (createNewUndoRecord || nonEmptySelection || endOfUndoChange == -1 || forceNewUndoRecord ||
 580                 (endOfUndoChange != change.start && endOfUndoChange != change.end) || change.end - change.start > 1) {

 581             undoChange = undoChange.add(change.start, oldText, newText);
 582         } else if (change.start != change.end && change.text.isEmpty()) {
 583             // I know I am deleting, and am located at the end of the range of the current undo record
 584             if (undoChange.newText.length() > 0) {
 585                 undoChange.newText = undoChange.newText.substring(0, change.start - undoChange.start);
 586                 if (undoChange.newText.isEmpty()) {
 587                     // throw away this undo change record
 588                     undoChange = undoChange.discard();
 589                 }
 590             } else {
 591                 if (change.start == endOfUndoChange) {
 592                     undoChange.oldText += oldText;
 593                 } else { // end == endOfUndoChange
 594                     undoChange.oldText = oldText + undoChange.oldText;
 595                     undoChange.start--;
 596                 }
 597             }
 598         } else {
 599             // I know I am adding, and am located at the end of the range of the current undo record
 600             undoChange.newText += newText;


1450             public void invalidated(Observable valueModel) {
1451                 // We now need to force it to be eagerly recomputed
1452                 // because we need to push these changes to the
1453                 // content model. Because changing the model ends
1454                 // up calling invalidate and markInvalid, the
1455                 // listeners will all be notified.
1456                 doSet(observable.getValue());
1457             }
1458         }
1459     }
1460 
1461     /**
1462      * Used to form a linked-list of Undo / Redo changes. Each UndoRedoChange
1463      * records the old and new text, and the start index. It also has
1464      * the links to the previous and next Changes in the chain. There
1465      * are two special UndoRedoChange objects in this chain representing the
1466      * head and the tail so we can have beforeFirst and afterLast
1467      * behavior as necessary.
1468      */
1469     static class UndoRedoChange {



1470         int start;
1471         String oldText;
1472         String newText;
1473         UndoRedoChange prev;
1474         UndoRedoChange next;
1475 
1476         UndoRedoChange() { }
1477 
1478         public UndoRedoChange add(int start, String oldText, String newText) {
1479             UndoRedoChange c = new UndoRedoChange();
1480             c.start = start;
1481             c.oldText = oldText;
1482             c.newText = newText;
1483             c.prev = this;
1484             next = c;

1485             return c;











1486         }
1487 
1488         public UndoRedoChange discard() {
1489             prev.next = next;
1490             return prev;
1491         }
1492 
1493         // Handy to use when debugging, just put it in undo or redo
1494         // method or replaceText to see what is happening to the undo
1495         // history as it occurs.
1496         void debugPrint() {
1497             UndoRedoChange c = this;
1498             System.out.print("[");
1499             while (c != null) {
1500                 System.out.print(c.toString());
1501                 if (c.next != null) System.out.print(", ");
1502                 c = c.next;
1503             }
1504             System.out.println("]");
1505         }




  48 import javafx.beans.value.ChangeListener;
  49 import javafx.beans.value.ObservableStringValue;
  50 import javafx.beans.value.ObservableValue;
  51 import javafx.beans.value.WritableValue;
  52 import javafx.css.CssMetaData;
  53 import javafx.css.FontCssMetaData;
  54 import javafx.css.PseudoClass;
  55 import javafx.css.StyleOrigin;
  56 import javafx.css.Styleable;
  57 import javafx.css.StyleableObjectProperty;
  58 import javafx.css.StyleableProperty;
  59 import javafx.scene.AccessibleAction;
  60 import javafx.scene.AccessibleAttribute;
  61 import javafx.scene.input.Clipboard;
  62 import javafx.scene.input.ClipboardContent;
  63 import javafx.scene.text.Font;
  64 
  65 import java.text.BreakIterator;
  66 import java.util.ArrayList;
  67 import java.util.Collections;
  68 import java.util.Date;
  69 import java.util.List;
  70 
  71 import com.sun.javafx.util.Utils;
  72 import com.sun.javafx.binding.ExpressionHelper;
  73 import com.sun.javafx.scene.NodeHelper;
  74 import javafx.util.StringConverter;
  75 
  76 /**
  77  * Abstract base class for text input controls.
  78  * @since JavaFX 2.0
  79  */
  80 @DefaultProperty("text")
  81 public abstract class TextInputControl extends Control {
  82     /**
  83      * Interface representing a text input's content. Since it is an ObservableStringValue,
  84      * you can also bind to, or observe the content.
  85      * @since JavaFX 2.0
  86      */
  87     protected interface Content extends ObservableStringValue {
  88         /**


 554                     return;
 555                 }
 556             }
 557 
 558             // Update the content
 559             updateContent(change, oldLength == 0);
 560 
 561         }
 562     }
 563 
 564     private void updateContent(TextFormatter.Change change, boolean forceNewUndoRecord) {
 565         final boolean nonEmptySelection = getSelection().getLength() > 0;
 566         String oldText = getText(change.start, change.end);
 567         int adjustmentAmount = replaceText(change.start, change.end, change.text, change.getAnchor(), change.getCaretPosition());
 568         String newText = getText(change.start, change.start + change.text.length() - adjustmentAmount);
 569         if (newText.equals(oldText)) {
 570             // Undo record not required as there is no change in the text.
 571             return;
 572         }
 573 
 574         /*
 575          * A new undo record is created, if
 576          * 1. createNewUndoRecord is true, currently it is set to true for paste operation
 577          * 2. Text is selected and a character is typed
 578          * 3. This is the first operation to be added to undo record
 579          * 4. forceNewUndoRecord is true, currently it is set to true if there is no text present
 580          * 5. Space character is typed
 581          * 6. 2500 milliseconds are elapsed since the undo record was created
 582          * 7. Cursor position is changed and a character is typed
 583          * 8. A range of text is replaced programmatically using replaceText()
 584          * Otherwise, the last undo record is updated or discarded.
 585          */
 586 
 587         int endOfUndoChange = undoChange == undoChangeHead ? -1 : undoChange.start + undoChange.newText.length();
 588         boolean isNewSpaceChar = false;
 589         if (newText.equals(" ")) {
 590             if (UndoRedoChange.isSpaceCharSequence()) {
 591                 isNewSpaceChar = false;
 592             } else {
 593                 isNewSpaceChar = true;
 594                 UndoRedoChange.setSpaceCharSequence(true);
 595             }
 596         } else {
 597             UndoRedoChange.setSpaceCharSequence(false);
 598         }
 599         if (createNewUndoRecord || nonEmptySelection || endOfUndoChange == -1 || forceNewUndoRecord ||
 600                 isNewSpaceChar || UndoRedoChange.ifChangeDurationElapsed() ||
 601                 (endOfUndoChange != change.start && endOfUndoChange != change.end) || change.end - change.start > 0) {
 602             undoChange = undoChange.add(change.start, oldText, newText);
 603         } else if (change.start != change.end && change.text.isEmpty()) {
 604             // I know I am deleting, and am located at the end of the range of the current undo record
 605             if (undoChange.newText.length() > 0) {
 606                 undoChange.newText = undoChange.newText.substring(0, change.start - undoChange.start);
 607                 if (undoChange.newText.isEmpty()) {
 608                     // throw away this undo change record
 609                     undoChange = undoChange.discard();
 610                 }
 611             } else {
 612                 if (change.start == endOfUndoChange) {
 613                     undoChange.oldText += oldText;
 614                 } else { // end == endOfUndoChange
 615                     undoChange.oldText = oldText + undoChange.oldText;
 616                     undoChange.start--;
 617                 }
 618             }
 619         } else {
 620             // I know I am adding, and am located at the end of the range of the current undo record
 621             undoChange.newText += newText;


1471             public void invalidated(Observable valueModel) {
1472                 // We now need to force it to be eagerly recomputed
1473                 // because we need to push these changes to the
1474                 // content model. Because changing the model ends
1475                 // up calling invalidate and markInvalid, the
1476                 // listeners will all be notified.
1477                 doSet(observable.getValue());
1478             }
1479         }
1480     }
1481 
1482     /**
1483      * Used to form a linked-list of Undo / Redo changes. Each UndoRedoChange
1484      * records the old and new text, and the start index. It also has
1485      * the links to the previous and next Changes in the chain. There
1486      * are two special UndoRedoChange objects in this chain representing the
1487      * head and the tail so we can have beforeFirst and afterLast
1488      * behavior as necessary.
1489      */
1490     static class UndoRedoChange {
1491         static long prevRecordTime;
1492         static final long CHANGE_DURATION = 2500; // milliseconds
1493         static boolean spaceCharSequence = false;
1494         int start;
1495         String oldText;
1496         String newText;
1497         UndoRedoChange prev;
1498         UndoRedoChange next;
1499 
1500         UndoRedoChange() { }
1501 
1502         public UndoRedoChange add(int start, String oldText, String newText) {
1503             UndoRedoChange c = new UndoRedoChange();
1504             c.start = start;
1505             c.oldText = oldText;
1506             c.newText = newText;
1507             c.prev = this;
1508             next = c;
1509             prevRecordTime = (new Date()).getTime();
1510             return c;
1511         }
1512 
1513         static boolean ifChangeDurationElapsed() {
1514             return ((new Date()).getTime() - prevRecordTime > CHANGE_DURATION) ;
1515         }
1516 
1517         static void setSpaceCharSequence(boolean value) {
1518             spaceCharSequence = value;
1519         }
1520         static boolean isSpaceCharSequence() {
1521             return spaceCharSequence;
1522         }
1523 
1524         public UndoRedoChange discard() {
1525             prev.next = next;
1526             return prev;
1527         }
1528 
1529         // Handy to use when debugging, just put it in undo or redo
1530         // method or replaceText to see what is happening to the undo
1531         // history as it occurs.
1532         void debugPrint() {
1533             UndoRedoChange c = this;
1534             System.out.print("[");
1535             while (c != null) {
1536                 System.out.print(c.toString());
1537                 if (c.next != null) System.out.print(", ");
1538                 c = c.next;
1539             }
1540             System.out.println("]");
1541         }


< prev index next >