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