blob: 7d61f49835d30bdbb48a3ac728dd1112a5d1bfa4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 Sybase, Inc. and others.
*
* 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:
* Sybase, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.jsf.common.ui.internal.dialogfield;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.Assert;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Hyperlink;
/**
* Base class of all Dialog fields. Dialog fields manage controls together with
* the model, independed from the creation time of the widgets. - support for
* automated layouting. - enable / disable, set focus a concept of the base
* class. DialogField have a label.
*
* DialogField may be used in two different context:
* <ol>
* <li> In side dialog. In this case, whenever there is anything change in the
* dialog field, such as user type anything, the dialog should listen to the
* dialogFieldChanged() events and do things like validation. When user press
* the "OK" button, dialog should call getXXX to get the value from the dialog
* field and apply them.
* <li> In side form based editor or properties view. In this case, whenever
* there is anything change in the dialog field, such as user type anything, the
* editor/view should listen to the dialogFieldChanged() events and do things
* like validation. When user press "Enter" or move the focus out of the control
* (finish editing), the dialog field will fire out dialogFieldApplied() events,
* and the editor/view should listen to this event and apply the value to the
* underlying model.
* </ol>
*
* The basic idea of the DialogField framework is comming from
* <code>org.eclipse.jface.preference.FieldEditor</code> and
* <code>org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField</code>
*
* @author mengbo
*/
public class DialogFieldBase implements DialogField {
private Label _label;
private Label _requiredLabel;
private String _labelText;
private IDialogFieldChangeListener _dialogFieldChangeListener;
private IDialogFieldApplyListener _dialogFieldApplyListener;
private boolean _enabled;
private FontMetrics _fontMetrics;
private IHyperlinkListener _listener;
private Hyperlink _hyperlink;
private Map _attachedData;
private boolean _isRequired;
private String toolTip;
/**
* default constructor
*/
public DialogFieldBase() {
_enabled = true;
_label = null;
_requiredLabel = null;
_hyperlink = null;
_labelText = ""; //$NON-NLS-1$
}
/**
* this method must be called directly after constructor, in this case,
* system will create a hyper link label, and when the hyper link is
* clicked, the corresponding method on the listene will be called. A
* RuntimeException will throw out if this method is called after the label
* has been created.
*
* @param listener
* can't be null
*/
public void setHyperLink(IHyperlinkListener listener) {
if (_label != null) {
throw new RuntimeException(
"The Label instance does not support the listener"); //$NON-NLS-1$
}
this._listener = listener;
}
/**
* Sets the label of the dialog field.
*/
public void setLabelText(String labeltext) {
_labelText = labeltext == null ? "" : labeltext; //$NON-NLS-1$
// if (_isRequired)
// {
// _labelText = "* " + _labelText;
// }
// else
// {
// _labelText = " " + _labelText;
// }
if (_label != null && !_label.isDisposed()) {
_label.setText(_labelText);
} else if (_hyperlink != null && !_hyperlink.isDisposed()) {
_hyperlink.setText(_labelText);
}
}
/**
* @return return the enclosing Shell or null if one cannot be determined
*/
public Shell getShell() {
if (_label != null && !_label.isDisposed()) {
return _label.getShell();
} else if (_hyperlink != null && !_hyperlink.isDisposed()) {
return _hyperlink.getShell();
}
return null;
}
// ------ change listener
/**
* Defines the listener for this dialog field.
*/
public final void setDialogFieldChangeListener(
IDialogFieldChangeListener listener) {
_dialogFieldChangeListener = listener;
}
public final void setDialogFieldApplyListener(
IDialogFieldApplyListener listener) {
_dialogFieldApplyListener = listener;
}
/**
* fire both dialogFieldChanged and dialogFieldApplied events.
*/
public void dialogFieldChangedAndApplied() {
if (_dialogFieldChangeListener != null) {
_dialogFieldChangeListener.dialogFieldChanged(this);
}
if (_dialogFieldApplyListener != null) {
_dialogFieldApplyListener.dialogFieldApplied(this);
}
}
/**
* fire dialogFieldChanged event.
*
*/
public void dialogFieldChanged() {
if (_dialogFieldChangeListener != null) {
_dialogFieldChangeListener.dialogFieldChanged(this);
}
}
/**
* fire dialogFieldApplied event.
*
*/
public void dialogFieldApplied() {
if (_dialogFieldApplyListener != null) {
_dialogFieldApplyListener.dialogFieldApplied(this);
}
}
// ------- focus management
public boolean setFocus() {
return false;
}
//
// /**
// * Posts <code>setFocus</code> to the display event queue.
// */
// public void postSetFocusOnDialogField(Display display)
// {
// if (display != null)
// {
// display.asyncExec(new Runnable()
// {
// public void run()
// {
// setFocus();
// }
// }
// );
// }
// }
// ------- layout helpers
public Control[] doFillIntoGrid(FormToolkit toolkit, Composite parent,
int nColumns) {
assertEnoughColumns(nColumns);
Control label = getLabelControl(toolkit, parent);
label.setLayoutData(gridDataForLabel(nColumns));
return new Control[] { label };
}
/**
* Initializes the computation of horizontal and vertical dialog units based
* on the size of current font.
* <p>
* This method must be called before any of the dialog unit based conversion
* methods are called.
* </p>
*
* @param control
* a control from which to obtain the current font
* @return the font metrics for control
*/
protected FontMetrics getDialogUnits(Control control) {
if (_fontMetrics == null) {
// Compute and store a font metric
GC gc = new GC(control);
gc.setFont(control.getFont());
_fontMetrics = gc.getFontMetrics();
gc.dispose();
}
return _fontMetrics;
}
/**
* Returns the number of columns of the dialog field. To be reimplemented by
* dialog field implementors.
*/
public int getNumberOfControls() {
return 1;
}
/**
* @param span
* @return a new GridData for the horizontal 'span' value
*/
protected static GridData gridDataForLabel(int span) {
GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gd.horizontalSpan = span;
return gd;
}
// ------- ui creation
/**
* Creates or returns the created label widget.
*
* @param parent
* The parent composite or <code>null</code> if the widget has
* already been created.
*/
public Control getLabelControl(FormToolkit _formToolkit, Composite parent) {
Control control = null;
if ((_label == null || _label.isDisposed()) && (_hyperlink == null || _hyperlink.isDisposed())) {
assertCompositeNotNull(parent);
String label = null;
if (_labelText != null && !"".equals(_labelText)) { //$NON-NLS-1$
//$NON-NLS-1$
label = _labelText;
} else {
label = "."; //$NON-NLS-1$
}
if (_listener == null) {
control = createLabel(_formToolkit, parent, label);
} else {
control = createHyperlink(_formToolkit, parent, label);
}
/**
* if(isRequired) { FontData[] fontData =
* parent.getFont().getFontData(); FontData[] newFontData = new
* FontData[fontData.length]; for(int i=0; i<fontData.length; i++) {
* newFontData[i] = new FontData(fontData[i].getName(),
* fontData[i].getHeight(), fontData[i].getStyle() | SWT.BOLD); }
* final Font font = new Font(control.getDisplay(),newFontData);
* control.setFont(font); control.addDisposeListener(new
* DisposeListener() {
*
* public void widgetDisposed(DisposeEvent e) { font.dispose(); }
* }); } else { control.setFont(parent.getFont()); }
*/
control.setFont(parent.getFont());
control.setEnabled(_enabled);
} else {
if (_label != null) {
control = _label;
} else {
control = _hyperlink;
}
}
return control;
}
/**
* @param _formToolkit
* @param parent
* @return get the Label control for required
*/
public Control getRequiredLabelControl(FormToolkit _formToolkit,
Composite parent) {
if (_requiredLabel == null || _requiredLabel.isDisposed()) {
if (_formToolkit == null) {
_requiredLabel = new Label(parent, SWT.LEFT | SWT.WRAP);
} else {
_requiredLabel = _formToolkit.createLabel(parent, "", SWT.LEFT //$NON-NLS-1$
| SWT.WRAP);
_requiredLabel.setForeground(getLabelColor());
}
if (_isRequired) {
_requiredLabel.setText(DialogFieldResources.getInstance()
.getString("DialogFieldBase.Label.RequiredSymbol")); //$NON-NLS-1$
}
}
return _requiredLabel;
}
private Control createLabel(FormToolkit _formToolkit, Composite parent,
String labelString) {
if (_formToolkit == null) {
_label = new Label(parent, SWT.LEFT | SWT.WRAP);
_label.setText(labelString);
} else {
_label = _formToolkit.createLabel(parent, labelString, SWT.LEFT
| SWT.WRAP);
_label.setForeground(getLabelColor());
}
return _label;
}
/**
* get color for label
*/
private Color getLabelColor() {
String osname = System.getProperty("os.name").toLowerCase(); //$NON-NLS-1$
if (osname.startsWith("mac os")) { //$NON-NLS-1$
return Display.getCurrent().getSystemColor(
SWT.COLOR_LIST_FOREGROUND);
}
return Display.getCurrent()
.getSystemColor(SWT.COLOR_LIST_SELECTION);
}
private Control createHyperlink(FormToolkit _formToolkit, Composite parent,
String label) {
if (_formToolkit == null) {
_hyperlink = new Hyperlink(parent, SWT.LEFT | SWT.WRAP);
_hyperlink.setForeground(getLabelColor());
_hyperlink.setUnderlined(true);
_hyperlink.addMouseTrackListener(new MouseTrackAdapter() {
public void mouseEnter(MouseEvent e) {
_hyperlink.setForeground(Display.getCurrent()
.getSystemColor(SWT.COLOR_BLUE));
}
public void mouseExit(MouseEvent e) {
_hyperlink.setForeground(getLabelColor());
}
});
_hyperlink.setText(label);
} else {
_hyperlink = _formToolkit.createHyperlink(parent, label, SWT.LEFT
| SWT.WRAP);
}
_hyperlink.addHyperlinkListener(_listener);
return _hyperlink;
}
/**
* Creates a spacer control.
* @param toolkit
*
* @param parent
* The parent composite
* @return a spacer control
*/
public Control createEmptySpace(FormToolkit toolkit, Composite parent) {
return createEmptySpace(toolkit, parent, 1);
}
/**
* Creates a spacer control with the given span. The composite is assumed to
* have <code>MGridLayout</code> as layout.
* @param toolkit
*
* @param parent
* The parent composite
* @param span
* @return a label that creates empty space
*/
public Control createEmptySpace(FormToolkit toolkit, Composite parent,
int span) {
Label label;
if (toolkit != null) {
label = toolkit.createLabel(parent, ""); //$NON-NLS-1$
} else {
label = new Label(parent, SWT.LEFT);
}
GridData gd = new GridData();
gd.horizontalAlignment = GridData.BEGINNING;
gd.grabExcessHorizontalSpace = false;
gd.horizontalSpan = span;
gd.horizontalIndent = 0;
gd.widthHint = 0;
gd.heightHint = 0;
label.setLayoutData(gd);
return label;
}
/**
* Tests is the control is not <code>null</code> and not disposed.
* @param control
* @return true if the control is valid for use
*/
protected final boolean isOkToUse(Control control) {
return (control != null) && !(control.isDisposed());
}
// --------- enable / disable management
/**
* Sets the enable state of the dialog field.
*/
public final void setEnabled(boolean enabled) {
if (enabled != _enabled) {
_enabled = enabled;
updateEnableState();
}
}
/**
* Called when the enable state changed. To be extended by dialog field
* implementors.
*/
protected void updateEnableState() {
if (_label != null && !_label.isDisposed()) {
_label.setEnabled(_enabled);
}
if (_hyperlink != null && !_hyperlink.isDisposed()) {
_hyperlink.setEnabled(_enabled);
}
}
/**
* Gets the enable state of the dialog field.
*/
public final boolean isEnabled() {
return _enabled;
}
/**
* @param comp
*/
protected final void assertCompositeNotNull(Composite comp) {
Assert.isNotNull(comp,
"uncreated control requested with composite null"); //$NON-NLS-1$
}
/**
* @param nColumns
*/
protected final void assertEnoughColumns(int nColumns) {
Assert.isTrue(nColumns >= getNumberOfControls(),
"given number of columns is too small"); //$NON-NLS-1$
}
/**
* Get attached data by key.
*
* @param key
* @return the attached data object for key
*/
public Object getAttachedData(Object key) {
if (_attachedData != null) {
return _attachedData.get(key);
}
return null;
}
/**
* You can attach any data to the DialogField, and get it using the
* <code>getAttachedData</code> method.
*
* @param key
* @param value
*/
public void putAttachedData(Object key, Object value) {
if (_attachedData == null) {
_attachedData = new HashMap();
}
_attachedData.put(key, value);
}
/**
* this method give the DialogField a chance to set the correct column to
* grab horizontal space. In the implementation of this method, should only
* change the GridData of control, should not do anything else.
*
* The caller is responsible to make sure the controls for the dialog field
* has been created before calling this method.
*/
public void handleGrabHorizontal() {
// do nothing.
}
public boolean isRequired() {
return _isRequired;
}
/**
* @param isRequired
*/
public void setRequired(boolean isRequired) {
this._isRequired = isRequired;
}
/**
* @return gthe tool tip text
*/
protected String getToolTip() {
return toolTip;
}
public void setToolTip(String toolTip) {
this.toolTip = toolTip;
}
}