/****************************************************************************** * Copyright (c) 2011-2013, Linagora * * 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: * Linagora - initial API and implementation *******************************************************************************/ package com.ebmwebsourcing.petals.common.internal.provisional.swt; import java.util.concurrent.ConcurrentLinkedQueue; import javax.xml.namespace.QName; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import com.ebmwebsourcing.petals.common.internal.provisional.utils.StringUtils; /** * A widget for QNames, made up of two {@link Text}s separated by a {@link Label}. * <p> * We use {@link StyledText} because some OS draw borders around native widgets like Texts. * Styled texts are not native widgets. * </p> * * @author Vincent Zurczak - EBM WebSourcing * FIXME: review the model interaction, the widget and the value might be not synchronized correctly */ public class QNameText extends Composite { private final static String DEFAULT_LOCAL_PART = "local part"; private final static String DEFAULT_NAMESPACE = "http://your.namespace.uri"; private final String defaultLocalPart; private final PhantomText namespacePhantomText; private final StyledText localPartPhantomText; private final Label separatorLabel; private final ConcurrentLinkedQueue<ModifyListener> modifyListeners = new ConcurrentLinkedQueue<ModifyListener> (); /** * Constructor. * @param parent */ public QNameText( Composite parent ) { this( parent, null, null ); } /** * Constructor. * @param parent * @param defaultLocalPart * @param defaultNamespace */ public QNameText( Composite parent, String defaultLocalPart, String defaultNamespace ) { super( parent, SWT.BORDER ); setBackground( getDisplay().getSystemColor( SWT.COLOR_WHITE )); this.defaultLocalPart = defaultLocalPart == null ? DEFAULT_LOCAL_PART : defaultLocalPart; GridLayout layout = new GridLayout( 3, false ); layout.marginHeight = 1; layout.marginWidth = 1; setLayout( layout ); // The local part this.localPartPhantomText = new StyledText( this, SWT.SINGLE ); this.localPartPhantomText.setText( DEFAULT_LOCAL_PART ); this.localPartPhantomText.setLayoutData( new GridData()); this.localPartPhantomText.addModifyListener( new ModifyListener() { @Override public void modifyText( ModifyEvent e ) { int cpt = ((StyledText) e.widget).getText().length() + 1; GC gc = new GC( QNameText.this ); gc.setFont( getFont()); int width = Dialog.convertWidthInCharsToPixels( gc.getFontMetrics(), cpt ); gc.dispose(); ((GridData) ((StyledText) e.widget).getLayoutData()).widthHint = width; layout(); for( ModifyListener listener : QNameText.this.modifyListeners ) listener.modifyText( e ); } }); // The separator this.separatorLabel = new Label( this, SWT.NONE ); this.separatorLabel.setText( "-" ); this.separatorLabel.setBackground( getDisplay().getSystemColor( SWT.COLOR_WHITE )); // The name space this.namespacePhantomText = new PhantomText( this, SWT.SINGLE ); this.namespacePhantomText.setDefaultValue( defaultNamespace == null ? DEFAULT_NAMESPACE : defaultNamespace ); GridData layoutData = new GridData( GridData.FILL_HORIZONTAL ); layoutData.minimumWidth = 60; this.namespacePhantomText.setLayoutData( layoutData ); this.namespacePhantomText.addModifyListener( new ModifyListener() { @Override public void modifyText( ModifyEvent e ) { for( ModifyListener listener : QNameText.this.modifyListeners ) listener.modifyText( e ); } }); // Focus listener Listener listener = new Listener() { @Override public void handleEvent( Event event ) { ((StyledText) event.widget).selectAll(); } }; this.localPartPhantomText.addListener( SWT.MouseDown, listener ); this.localPartPhantomText.addListener( SWT.FocusIn, listener ); this.namespacePhantomText.getTextWidget().addListener( SWT.MouseDown, listener ); this.namespacePhantomText.getTextWidget().addListener( SWT.FocusIn, listener ); // Display default values setValue( null ); } /** * Sets the local part. * @param localPart the local part (can be null) */ public void setLocalPart( String localPart ) { this.localPartPhantomText.setText( localPart != null ? localPart : this.defaultLocalPart ); } /** * Sets the name space. * @param namespace the name space (can be null) */ public void setNamespace( String namespace ) { this.namespacePhantomText.setTextValue( namespace ); } /* * (non-Javadoc) * @see org.eclipse.swt.widgets.Control * #setEnabled(boolean) */ @Override public void setEnabled( boolean enabled ) { this.localPartPhantomText.setEnabled( enabled ); this.namespacePhantomText.setEnabled( enabled ); int colorId = enabled ? SWT.COLOR_WHITE : SWT.COLOR_WIDGET_BACKGROUND; Color color = getDisplay().getSystemColor( colorId ); this.separatorLabel.setBackground( color ); this.localPartPhantomText.setBackground( color ); this.namespacePhantomText.setBackground( color ); setBackground( color ); super.setEnabled( enabled ); } /** * Defines whether the text fields can be edited or not. * @param editable true if they are, false otherwise */ public void setEditable( boolean editable ) { setLocalPartEditable( editable ); setNamespacePartEditable( editable ); } /** * Sets the local part editable. * @param editable */ public void setLocalPartEditable( boolean editable ) { this.localPartPhantomText.setEditable( editable ); Color color = getDisplay().getSystemColor( SWT.COLOR_WHITE ); String tooltip = editable ? null : "This field cannot be edited"; this.localPartPhantomText.setBackground( color ); this.localPartPhantomText.setToolTipText( tooltip ); } /** * Sets the namespace part editable. * @param editable */ public void setNamespacePartEditable( boolean editable ) { this.namespacePhantomText.getTextWidget().setEditable( editable ); Color color = getDisplay().getSystemColor( SWT.COLOR_WHITE ); String tooltip = editable ? null : "This field cannot be edited"; this.namespacePhantomText.getTextWidget().setBackground( color ); this.namespacePhantomText.getTextWidget().setToolTipText( tooltip ); } /** * @param string * @see org.eclipse.swt.widgets.Control * #setToolTipText(java.lang.String) */ @Override public void setToolTipText( String string ) { this.localPartPhantomText.setToolTipText( string ); this.separatorLabel.setToolTipText( string ); this.namespacePhantomText.setToolTipText( string ); } /** * @return the QName described by this widget */ public QName getValue() { QName result; String ns = this.namespacePhantomText.getTextValue(); String name = this.localPartPhantomText.getText(); name = this.defaultLocalPart.equals( name ) ? null : name; if( StringUtils.isEmpty( name )) result = null; else if( ns == null || ns.length() == 0 ) result = new QName( name ); else result = new QName( ns, name ); return result; } /** * @param value the QName to display in this widget */ public void setValue( QName value ) { if( value != null ) { setLocalPart( value.getLocalPart()); setNamespace( value.getNamespaceURI()); } else { setLocalPart( null ); setNamespace( null ); } } /** * @return the text widget for the local part */ public StyledText getLocalPartText() { return this.localPartPhantomText; } /** * @return the text widget for the name space */ public StyledText getNamespaceText() { return this.namespacePhantomText.getTextWidget(); } /** * @param modifyListener */ public void addModifyListener( ModifyListener modifyListener ) { this.modifyListeners.add( modifyListener ); } /** * @param modifyListener */ public void removeModifyListener( ModifyListener modifyListener ) { this.modifyListeners.remove( modifyListener ); } }