001 /*
002 * Copyright 2002-2007 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016 package org.springframework.richclient.text;
017
018 import javax.swing.SwingUtilities;
019 import javax.swing.event.DocumentEvent;
020 import javax.swing.event.DocumentListener;
021 import javax.swing.text.JTextComponent;
022
023 import org.springframework.binding.form.FormModel;
024 import org.springframework.richclient.form.builder.FormComponentInterceptor;
025 import org.springframework.richclient.form.builder.FormComponentInterceptorFactory;
026
027 /**
028 * If the text is set in a text component, the caret position is set to the end of the
029 * text.
030 * <p>
031 * This means the beginning of the text will not be visible if the text is too long to fit
032 * in the text component.
033 * <p>
034 * This <code>FormComponentInterceptor</code> "fixes" this behaviour by listening to
035 * <code>Document</code> updates, and setting the caret position to 0 (i.e. the
036 * beginning of the text) if the text is updated when the text component doesn't have the
037 * focus (i.e. the text is not changed by the user).
038 *
039 * @author Peter De Bruycker
040 */
041 public class TextCaretFormComponentInterceptorFactory implements FormComponentInterceptorFactory {
042
043 /**
044 * Create a new <code>TextCaretFixerComponentInterceptor</code> instance
045 *
046 * @return the interceptor
047 */
048 public FormComponentInterceptor getInterceptor( FormModel formModel ) {
049 return new TextCaretComponentInterceptor();
050 }
051
052 /**
053 * The <code>FormComponentInterceptor</code> implementation.
054 */
055 public class TextCaretComponentInterceptor extends TextComponentInterceptor {
056 protected void processComponent( String propertyName, final JTextComponent textComponent ) {
057 textComponent.getDocument().addDocumentListener( new DocumentHandler( textComponent ) );
058 }
059 }
060
061 private static final class DocumentHandler implements DocumentListener {
062 private JTextComponent component;
063
064 private DocumentHandler( JTextComponent component ) {
065 this.component = component;
066 }
067
068 public void removeUpdate( DocumentEvent e ) {
069 fixCaret();
070 }
071
072 public void insertUpdate( DocumentEvent e ) {
073 fixCaret();
074 }
075
076 public void changedUpdate( DocumentEvent e ) {
077 fixCaret();
078 }
079
080 private void fixCaret() {
081 if( !component.hasFocus() ) {
082 // need to invoke later, as the text change also changes the caret
083 // position
084 SwingUtilities.invokeLater( new Runnable() {
085 public void run() {
086 component.setCaretPosition( 0 );
087 }
088 } );
089 }
090 }
091 }
092 }