/******************************************************************************
* 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 );
}
}