001package arcommon.ui.component; 002 003import javax.swing.JTextField; 004import javax.swing.text.DefaultCaret; 005 006import arcommon.StringUtil; 007import arcommon.ui.other.MyUndoManager; 008 009/** 010 * A {@link javax.swing.JTextField} with undo. 011 * <br> 012 * Undo is clear (by default) when {@link #setText(String)} is called.<br> 013 * Note: Uses {@link javax.swing.text.DefaultCaret#NEVER_UPDATE} instead of the default {@link javax.swing.text.DefaultCaret#UPDATE_WHEN_ON_EDT} when {@link #setText(String)} is called. 014 */ 015public class MyJTextField extends JTextField { 016 017 private static final long serialVersionUID = 6591496933833049128L; 018 019 private MyUndoManager myUndoManager; 020 private boolean moveCaretInitial; 021 022 public MyJTextField() { 023 init(); 024 } 025 026 public MyJTextField(int columns) { 027 super(columns); 028 init(); 029 } 030 031 public MyJTextField(String text) { 032 super(text); 033 init(); 034 } 035 036 private void init() { 037 myUndoManager = MyUndoManager.addUndoToTextComponent(this); 038 moveCaretInitial = true; 039 } 040 041 /** 042 * See {@link #setText(String, boolean, boolean)} for details 043 */ 044 @Override 045 public void setText(String text) { 046 setText(text, true, moveCaretInitial); 047 } 048 049 /** 050 * Sets the text of the text field without moving the caret. 051 * <br> 052 * If {@code discardsAllEdits} is true the undo history is removed.<br> 053 * if {@code moveCaretInitial} is true the caret to it's initial position ({@code text.length()}).<br> 054 * See {@link arcommon.ui.component.MyJTextArea#setText(String, boolean, boolean)} for at very similar method. 055 */ 056 public void setText(String text, boolean discardsAllEdits, boolean pmoveCaretInitial) { 057 // Code copied from https://stackoverflow.com/questions/1627028/how-to-set-auto-scrolling-of-jtextarea-in-java-gui 058 // and modified a lot 059 if (!StringUtil.stringEquals(text, getText())) { 060 DefaultCaret caret = (DefaultCaret)getCaret(); 061 int updatePolicy = caret.getUpdatePolicy(); 062 // Set UpdatePolicy to DefaultCaret.NEVER_UPDATE to avoid that the caret is moved to end of the text area when setText() is used. 063 caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); 064 065 int oldCaretPosition = getCaretPosition(); 066 if (myUndoManager != null) { // This is null is setText is called in super constructor. 067 myUndoManager.nextUndoIsDouble(); 068 } 069 super.setText(text); 070 int newCaretPosition = getCaretPosition(); 071 if (oldCaretPosition != newCaretPosition) { 072 if (text == null) { 073 oldCaretPosition = 0; 074 } else if (oldCaretPosition > text.length()) { 075 oldCaretPosition = text.length(); 076 } 077 // Move the caret position to the position that the documentation states that is it should be in. 078 setCaretPosition(oldCaretPosition); 079 } 080 081 caret.setUpdatePolicy(updatePolicy); // Set UpdatePolicy back 082 } 083 084 if (pmoveCaretInitial) { 085 if (text != null) { 086 setCaretPosition(text.length()); 087 } 088 moveCaretInitial = false; 089 } 090 091 if (discardsAllEdits && myUndoManager != null) { // myUndoManager is null is setText is called in super constructor. 092 myUndoManager.discardAllEdits(); 093 } 094 } 095}