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 }