/******************************************************************************* * Copyright (c) 2002, 2008 Innoopract Informationssysteme GmbH. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Innoopract Informationssysteme GmbH - initial API and implementation ******************************************************************************/ package org.eclipse.swt.internal.widgets.textkit; import java.io.IOException; import org.eclipse.rwt.internal.util.EncodingUtil; import org.eclipse.rwt.lifecycle.*; import org.eclipse.swt.SWT; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.internal.widgets.ITextAdapter; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Text; final class TextLCAUtil { static final String PROP_TEXT = "text"; static final String PROP_TEXT_LIMIT = "textLimit"; static final String PROP_SELECTION = "selection"; static final String PROP_READONLY = "readonly"; static final String PROP_VERIFY_MODIFY_LISTENER = "verifyModifyListener"; static final String PROP_SELECTION_LISTENER = "selectionListener"; static final String PROP_PASSWORD_MODE = "passwordMode"; private static final Integer DEFAULT_TEXT_LIMIT = new Integer( Text.LIMIT ); private static final Point DEFAULT_SELECTION = new Point( 0, 0 ); private static final String JS_PROP_MAX_LENGTH = "maxLength"; private static final String JS_PROP_READ_ONLY = "readOnly"; private static final String JS_PROP_VALUE = "value"; private static final String JS_PROP_TEXT_ALIGN = "textAlign"; private static final String JS_PROP_PASSWORD_MODE = "passwordMode"; private TextLCAUtil() { // prevent instantiation } static void preserveValues( final Text text ) { IWidgetAdapter adapter = WidgetUtil.getAdapter( text ); adapter.preserve( PROP_TEXT, text.getText() ); adapter.preserve( PROP_SELECTION, text.getSelection() ); adapter.preserve( PROP_TEXT_LIMIT, new Integer( text.getTextLimit() ) ); adapter.preserve( PROP_READONLY, Boolean.valueOf( ! text.getEditable() ) ); } static void readTextAndSelection( final Text text ) { final Point selection = readSelection( text ); final String txt = WidgetLCAUtil.readPropertyValue( text, "text" ); if( txt != null ) { if( VerifyEvent.hasListener( text ) ) { // setText needs to be executed in a ProcessAction runnable as it may // fire a VerifyEvent whose fields (text and doit) need to be evaluated // before actually setting the new value ProcessActionRunner.add( new Runnable() { public void run() { ITextAdapter textAdapter = getTextAdapter( text ); textAdapter.setText( txt, selection ); // since text is set in process action, preserved values have to be // replaced IWidgetAdapter adapter = WidgetUtil.getAdapter( text ); adapter.preserve( PROP_TEXT, txt ); if( selection != null ) { adapter.preserve( PROP_SELECTION, selection ); } } } ); } else { text.setText( txt ); if( selection != null ) { text.setSelection( selection ); } } } else if( selection != null ) { // [rst] Apply selection even if text has not changed // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=195171 text.setSelection( selection ); } } private static Point readSelection( final Text text ) { Point result = null; String selStart = WidgetLCAUtil.readPropertyValue( text, "selectionStart" ); String selLength = WidgetLCAUtil.readPropertyValue( text, "selectionLength" ); if( selStart != null || selLength != null ) { result = new Point( 0, 0 ); if( selStart != null ) { result.x = Integer.parseInt( selStart ); } if( selLength != null ) { result.y = result.x + Integer.parseInt( selLength ); } } return result; } static void writeInitialize( final Text text ) throws IOException { JSWriter writer = JSWriter.getWriterFor( text ); writer.callStatic( "org.eclipse.swt.TextUtil.initialize", new Object[] { text } ); } static void writeText( final Text text ) throws IOException { String newValue = text.getText(); JSWriter writer = JSWriter.getWriterFor( text ); if( WidgetLCAUtil.hasChanged( text, PROP_TEXT, newValue, "" ) ) { String value = WidgetLCAUtil.replaceNewLines( newValue, " " ); value = EncodingUtil.removeNonDisplayableChars( value ); writer.set( JS_PROP_VALUE, value ); } } static void writeReadOnly( final Text text ) throws IOException { JSWriter writer = JSWriter.getWriterFor( text ); Boolean newValue = Boolean.valueOf( !text.getEditable() ); writer.set( PROP_READONLY, JS_PROP_READ_ONLY, newValue, Boolean.FALSE ); } static void writeTextLimit( final Text text ) throws IOException { JSWriter writer = JSWriter.getWriterFor( text ); Integer newValue = new Integer( text.getTextLimit() ); Integer defValue = DEFAULT_TEXT_LIMIT; if( WidgetLCAUtil.hasChanged( text, PROP_TEXT_LIMIT, newValue, defValue ) ) { // Negative values are treated as 'no limit' which is achieved by passing // null to the client-side maxLength property if( newValue.intValue() < 0 ) { newValue = null; } writer.set( JS_PROP_MAX_LENGTH, newValue ); } } static void writeWrap( final Text text ) throws IOException { JSWriter writer = JSWriter.getWriterFor( text ); Boolean value = Boolean.valueOf( ( text.getStyle() & SWT.WRAP ) != 0 ); writer.set( "wrap", value ); } static void writeSelection( final Text text ) throws IOException { Point newValue = text.getSelection(); Point defValue = DEFAULT_SELECTION; // TODO [rh] could be optimized: when text was changed and selection is 0,0 // there is no need to write JavaScript since the client resets the // selection as well when the new text is set. if( WidgetLCAUtil.hasChanged( text, PROP_SELECTION, newValue, defValue ) ) { // [rh] Workaround for bug 252462: Changing selection on a hidden text // widget causes exception in FF if( text.isVisible() ) { JSWriter writer = JSWriter.getWriterFor( text ); Integer start = new Integer( newValue.x ); Integer count = new Integer( text.getSelectionCount() ); writer.callStatic( "org.eclipse.swt.TextUtil.setSelection", new Object[] { text, start, count } ); } } } static void writeAlignment( final Text text ) throws IOException { int style = text.getStyle(); if( ( style & SWT.RIGHT ) != 0 ) { JSWriter writer = JSWriter.getWriterFor( text ); writer.set( JS_PROP_TEXT_ALIGN, "right" ); } else if( ( style & SWT.CENTER ) != 0 ) { JSWriter writer = JSWriter.getWriterFor( text ); writer.set( JS_PROP_TEXT_ALIGN, "center" ); } } static void preserveSelectionListener( final Text text ) { IWidgetAdapter adapter = WidgetUtil.getAdapter( text ); adapter.preserve( PROP_SELECTION_LISTENER, Boolean.valueOf( hasSelectionListener( text ) ) ); } static void writeSelectionListener( final Text text ) throws IOException { Boolean newValue = Boolean.valueOf( hasSelectionListener( text ) ); if( WidgetLCAUtil.hasChanged( text, PROP_SELECTION_LISTENER, newValue ) ) { JSWriter writer = JSWriter.getWriterFor( text ); writer.callStatic( "org.eclipse.swt.TextUtil.setHasSelectionListener", new Object[] { text, newValue } ); } } static void preserveVerifyAndModifyListener( final Text text ) { IWidgetAdapter adapter = WidgetUtil.getAdapter( text ); adapter.preserve( PROP_VERIFY_MODIFY_LISTENER, Boolean.valueOf( hasVerifyOrModifyListener( text ) ) ); } static void writeVerifyAndModifyListener( final Text text ) throws IOException { if( ( text.getStyle() & SWT.READ_ONLY ) == 0 ) { Boolean newValue = Boolean.valueOf( hasVerifyOrModifyListener( text ) ); if( WidgetLCAUtil.hasChanged( text, PROP_VERIFY_MODIFY_LISTENER, newValue ) ) { JSWriter writer = JSWriter.getWriterFor( text ); writer.callStatic( "org.eclipse.swt.TextUtil.setHasVerifyOrModifyListener", new Object[] { text, newValue } ); } } } static void preservePasswordMode( final Text text ) { IWidgetAdapter adapter = WidgetUtil.getAdapter( text ); Boolean value = new Boolean( text.getEchoChar() != 0 ); adapter.preserve( PROP_PASSWORD_MODE, value ); } static void writePasswordMode( final Text text ) throws IOException { Boolean newValue = new Boolean( text.getEchoChar() != 0 ); String prop = PROP_PASSWORD_MODE; if( WidgetLCAUtil.hasChanged( text, prop, newValue, Boolean.FALSE ) ) { JSWriter writer = JSWriter.getWriterFor( text ); writer.set( JS_PROP_PASSWORD_MODE, newValue ); } } private static boolean hasSelectionListener( final Text text ) { // Emulate SWT (on Windows) where a default button takes precedence over // a SelectionListener on a text field when both are on the same shell. Button defButton = text.getShell().getDefaultButton(); // TODO [rst] On GTK, the SelectionListener is also off when the default // button is invisible or disabled. Check with Windows and repair. boolean hasDefaultButton = defButton != null && defButton.isVisible(); return !hasDefaultButton && SelectionEvent.hasListener( text ); } private static boolean hasVerifyOrModifyListener( final Text text ) { boolean hasVerifyListener = VerifyEvent.hasListener( text ); boolean hasModifyListener = ModifyEvent.hasListener( text ); return hasModifyListener || hasVerifyListener; } private static ITextAdapter getTextAdapter( final Text text ) { return ( ITextAdapter )text.getAdapter( ITextAdapter.class ); } }