| /******************************************************************************* |
| * Copyright (c) 2008, 2013 Oracle. All rights reserved. |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License 2.0, which accompanies this distribution |
| * and is available at https://www.eclipse.org/legal/epl-2.0/. |
| * |
| * Contributors: |
| * Oracle - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.jpt.common.ui.internal.widgets; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.fieldassist.FieldDecorationRegistry; |
| import org.eclipse.jface.resource.LocalResourceManager; |
| import org.eclipse.jface.resource.ResourceManager; |
| import org.eclipse.jface.viewers.ComboViewer; |
| import org.eclipse.jface.viewers.IBaseLabelProvider; |
| import org.eclipse.jpt.common.ui.WidgetFactory; |
| import org.eclipse.jpt.common.ui.internal.WorkbenchTools; |
| import org.eclipse.jpt.common.ui.internal.plugin.JptCommonUiPlugin; |
| import org.eclipse.jpt.common.ui.internal.swt.ComboModelAdapter; |
| import org.eclipse.jpt.common.ui.internal.swt.DateTimeModelAdapter; |
| import org.eclipse.jpt.common.ui.internal.swt.SpinnerModelAdapter; |
| import org.eclipse.jpt.common.ui.internal.swt.TriStateCheckBoxModelAdapter; |
| import org.eclipse.jpt.common.ui.internal.swt.bindings.SWTBindingTools; |
| import org.eclipse.jpt.common.ui.internal.swt.events.DisposeAdapter; |
| import org.eclipse.jpt.common.ui.internal.swt.listeners.SWTListenerTools; |
| import org.eclipse.jpt.common.utility.internal.model.value.CompositeBooleanPropertyValueModel; |
| import org.eclipse.jpt.common.utility.internal.model.value.NullCheckPropertyValueModelWrapper; |
| import org.eclipse.jpt.common.utility.internal.model.value.PredicatePropertyValueModel; |
| import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel; |
| import org.eclipse.jpt.common.utility.internal.model.value.StaticPropertyValueModel; |
| import org.eclipse.jpt.common.utility.internal.predicate.PredicateTools; |
| import org.eclipse.jpt.common.utility.internal.transformer.TransformerTools; |
| import org.eclipse.jpt.common.utility.model.Model; |
| import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent; |
| import org.eclipse.jpt.common.utility.model.listener.PropertyChangeAdapter; |
| import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener; |
| import org.eclipse.jpt.common.utility.model.value.ListValueModel; |
| import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel; |
| import org.eclipse.jpt.common.utility.model.value.PropertyValueModel; |
| import org.eclipse.jpt.common.utility.transformer.Transformer; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.MouseAdapter; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Combo; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.DateTime; |
| import org.eclipse.swt.widgets.Group; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Layout; |
| import org.eclipse.swt.widgets.List; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Spinner; |
| import org.eclipse.swt.widgets.Table; |
| import org.eclipse.swt.widgets.Text; |
| import org.eclipse.ui.forms.widgets.ExpandableComposite; |
| import org.eclipse.ui.forms.widgets.Hyperlink; |
| import org.eclipse.ui.forms.widgets.Section; |
| import org.eclipse.ui.part.PageBook; |
| |
| /** |
| * The abstract definition of a pane which holds a {@link PropertyValueModel} |
| * that contains the pane's subject. |
| * <p> |
| * This class contains convenience methods for building buttons, labels, check |
| * boxes, radio buttons, etc. |
| * <p> |
| * It is possible to easily listen to any property changes coming from the |
| * subject, {@link #addPropertyNames(Collection)} specifies which properties |
| * are of interest and {@link #propertyChanged(String)} is used to notify the |
| * pane when the property has changed. |
| * |
| * @see DialogPane |
| */ |
| @SuppressWarnings("nls") |
| public abstract class Pane<T extends Model> { |
| /** |
| * This will be <code>null</code> for <em>root</em> panes. |
| */ |
| private final Pane<?> parent; |
| |
| /** |
| * The listener registered with the subject in order to be notified when a |
| * property has changed, the property names are determined by |
| * {@link #getPropertyNames()}. |
| */ |
| private final PropertyChangeListener aspectChangeListener; |
| |
| /** |
| * The container of the pane's composite. |
| */ |
| private final Composite container; |
| |
| /** |
| * Flag used to stop the circular population of widgets. |
| */ |
| private boolean populating; |
| |
| /** |
| * This listener is registered with the {@link #subjectModel} in order to |
| * automatically repopulate this pane when the subject changes. |
| */ |
| private final PropertyChangeListener subjectChangeListener; |
| |
| /** |
| * The pane's subject. |
| */ |
| private final PropertyValueModel<? extends T> subjectModel; |
| |
| /** |
| * The widget factory used by the pane and all its descendant panes to |
| * create various common widgets. |
| * This will be <code>null</code> if the pane has a {@link #parent}. |
| */ |
| private final WidgetFactory widgetFactory; |
| |
| /** |
| * The resource manager used by the pane and all its descendant panes to |
| * allocate resources (images, colors, and fonts). |
| * This will be <code>null</code> if the pane has a {@link #parent}. |
| */ |
| private final ResourceManager resourceManager; |
| |
| /** |
| * The AND of the <em>enabled</em> model passed in via the constructor and |
| * the parent pane's <em>enabled</em> model. |
| */ |
| private final PropertyValueModel<Boolean> enabledModel; |
| private final PropertyChangeListener enabledModelListener; |
| |
| /** |
| * A listener that allows us to stop listening to stuff when the control |
| * is disposed. (Critical for preventing memory leaks.) |
| */ |
| private final DisposeListener controlDisposeListener; |
| |
| |
| /** |
| * Construct a pane that uses the specified parent pane's:<ul> |
| * <li>subject model |
| * <li><em>enabled</em> model |
| * </ul> |
| */ |
| protected Pane( |
| Pane<? extends T> parent, |
| Composite parentComposite |
| ) { |
| this(parent, parent.getSubjectHolder(), parentComposite); |
| } |
| |
| /** |
| * Construct a pane that uses the specified parent pane's:<ul> |
| * <li><em>enabled</em> model |
| * </ul> |
| */ |
| protected Pane( |
| Pane<?> parent, |
| PropertyValueModel<? extends T> subjectModel, |
| Composite parentComposite |
| ) { |
| this(parent, subjectModel, buildDefaultEnabledModel(), parentComposite); |
| } |
| |
| /** |
| * Construct a pane that uses the specified parent pane's:<ul> |
| * <li>subject model |
| * </ul> |
| * The specified <em>enabled</em> model will be ANDed with the parent |
| * pane's <em>enabled</em> model (i.e. the pane can be <em>enabled</em> |
| * only if its parent pane is also <em>enabled</em>). |
| */ |
| protected Pane( |
| Pane<? extends T> parent, |
| Composite parentComposite, |
| PropertyValueModel<Boolean> enabledModel |
| ) { |
| this(parent, parent.getSubjectHolder(), enabledModel, parentComposite); |
| } |
| |
| /** |
| * Construct a pane that uses the specified subject model and |
| * <em>enabled</em> model. |
| * <p> |
| * The specified <em>enabled</em> model will be ANDed with the parent |
| * pane's <em>enabled</em> model (i.e. the pane can be <em>enabled</em> |
| * only if its parent pane is also <em>enabled</em>). |
| */ |
| protected Pane( |
| Pane<?> parent, |
| PropertyValueModel<? extends T> subjectModel, |
| PropertyValueModel<Boolean> enabledModel, |
| Composite parentComposite |
| ) { |
| this(parent, subjectModel, enabledModel, parentComposite, null, null); |
| } |
| |
| /** |
| * Construct a <em>root</em> pane with the specified subject model, widget |
| * factory, and resource manager. |
| * The pane will be <em>disabled</em> whenever the subject is |
| * <code>null</code>. |
| */ |
| protected Pane( |
| PropertyValueModel<? extends T> subjectModel, |
| Composite parentComposite, |
| WidgetFactory widgetFactory, |
| ResourceManager resourceManager |
| ) { |
| this(subjectModel, buildIsNotNullModel(subjectModel), parentComposite, widgetFactory, resourceManager); |
| } |
| |
| /** |
| * Construct a <em>root</em> pane with the specified subject model, |
| * <em>enabled</em> model, widget factory, and resource manager. |
| * <p> |
| * The specified <em>enabled</em> model will be ANDed with the parent |
| * pane's <em>enabled</em> model (i.e. the pane can be <em>enabled</em> |
| * only if its parent pane is also <em>enabled</em>). |
| */ |
| protected Pane( |
| PropertyValueModel<? extends T> subjectModel, |
| PropertyValueModel<Boolean> enabledModel, |
| Composite parentComposite, |
| WidgetFactory widgetFactory, |
| ResourceManager resourceManager |
| ) { |
| this(null, subjectModel, enabledModel, parentComposite, widgetFactory, resourceManager); |
| } |
| |
| /** |
| * This constructor is <code>private</code> so we can enable, but also |
| * require, <em>root</em> panes (i.e. panes without parents) to specify the |
| * following:<ul> |
| * <li>subject model |
| * <li>widget factory |
| * </ul> |
| */ |
| private Pane( |
| Pane<?> parent, |
| PropertyValueModel<? extends T> subjectModel, |
| PropertyValueModel<Boolean> enabledModel, |
| Composite parentComposite, |
| WidgetFactory widgetFactory, |
| ResourceManager resourceManager |
| ) { |
| super(); |
| if ((subjectModel == null) || (enabledModel == null) || (parentComposite == null)) { |
| throw new NullPointerException(); |
| } |
| if (parent == null) { |
| if ((widgetFactory == null) || (resourceManager == null)) { |
| throw new NullPointerException(); |
| } |
| } |
| this.parent = parent; |
| this.subjectModel = subjectModel; |
| |
| this.enabledModel = andEnabledModel(parent, enabledModel); |
| this.enabledModelListener = this.buildEnabledModelListener(); |
| this.enabledModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.enabledModelListener); |
| |
| this.widgetFactory = widgetFactory; |
| this.resourceManager = (resourceManager == null) ? null : new LocalResourceManager(resourceManager); |
| |
| this.aspectChangeListener = this.buildAspectChangeListener(); |
| |
| this.initialize(); |
| |
| if (this.addsComposite()) { |
| this.container = this.addComposite(parentComposite); |
| this.initializeLayout(this.container); |
| } else { |
| this.container = null; |
| this.initializeLayout(parentComposite); |
| } |
| this.controlDisposeListener = this.buildControlDisposeListener(); |
| this.getControl().addDisposeListener(this.controlDisposeListener); |
| |
| this.subjectChangeListener = this.buildSubjectChangeListener(); |
| this.subjectModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.subjectChangeListener); |
| |
| this.engageListeners(getSubject()); |
| this.populate(); |
| } |
| |
| |
| // ********** enabled model ********** |
| |
| /** |
| * Return an <em>enabled</em> model that will result in the pane's |
| * <em>enabled</em> state always matching that of its parent pane. |
| */ |
| private static PropertyValueModel<Boolean> buildDefaultEnabledModel() { |
| return new StaticPropertyValueModel<Boolean>(Boolean.TRUE); |
| } |
| |
| /** |
| * Return a {@link Boolean} value model that will return |
| * {@link Boolean#TRUE} if the value of the specified value model is |
| * <em>not</em> <code>null</code>; |
| * {@link Boolean#FALSE} if the value <em>is</em> <code>null</code>. |
| */ |
| protected static PropertyValueModel<Boolean> buildIsNotNullModel(PropertyValueModel<?> valueModel) { |
| return new PredicatePropertyValueModel<Object>(valueModel, PredicateTools.isNotNull()); |
| } |
| |
| /** |
| * Convenience method for sub-classes. |
| * Wrap the pane's {@link #subjectModel} in a {@link #buildIsNotNullModel(PropertyValueModel)}; |
| * i.e. a model that returns whether the subject is <code>null</code>. |
| */ |
| protected PropertyValueModel<Boolean> buildSubjectIsNotNullModel() { |
| return buildIsNotNullModel(this.subjectModel); |
| } |
| |
| /** |
| * Return a {@link Boolean} value model that will return the AND of the |
| * value of the <em>enabled</em> model of the specified (typically parent) pane |
| * and the value of the specified <em>enabled</em> model. |
| * <p> |
| * This is useful for a pane that is <em>enabled</em> when both its parent |
| * pane is <em>enabled</em> <em>and</em> the pane's model indicates the |
| * pane should be <em>enabled</em>. |
| */ |
| @SuppressWarnings("unchecked") |
| private static PropertyValueModel<Boolean> andEnabledModel(Pane<?> pane, PropertyValueModel<Boolean> enabledModel) { |
| enabledModel = buildNonNullModel(enabledModel); |
| // NB: we fetch private state from the pane |
| return (pane == null) ? enabledModel : CompositeBooleanPropertyValueModel.and(pane.enabledModel, enabledModel); |
| } |
| |
| /** |
| * Return a {@link Boolean} value model that will return the value of the |
| * specified {@link Boolean} value model if it is <em>not</em> |
| * <code>null</code>; |
| * {@link Boolean#FALSE} if the value is <code>null</code>. |
| * <p> |
| * This is useful for <em>enabled</em> models that might return <code>null</code> |
| * (which is typical with aspect adapters etc.). |
| */ |
| private static PropertyValueModel<Boolean> buildNonNullModel(PropertyValueModel<Boolean> booleanModel) { |
| return new NullCheckPropertyValueModelWrapper<Boolean>(booleanModel, Boolean.FALSE); |
| } |
| |
| |
| // ********** initialization ********** |
| |
| private PropertyChangeListener buildEnabledModelListener() { |
| return new EnabledModelListener(); |
| } |
| |
| /* CU private */ class EnabledModelListener |
| extends PropertyChangeAdapter |
| { |
| @Override |
| public void propertyChanged(PropertyChangeEvent event) { |
| Pane.this.enabledModelChanged(((Boolean) event.getOldValue()).booleanValue(), ((Boolean) event.getNewValue()).booleanValue()); |
| } |
| } |
| |
| protected void enabledModelChanged(@SuppressWarnings("unused") boolean oldEnabled, @SuppressWarnings("unused") boolean newEnabled) { |
| // NOP |
| } |
| |
| private PropertyChangeListener buildSubjectChangeListener() { |
| return SWTListenerTools.wrap(this.buildSubjectChangeListener_()); |
| } |
| |
| private PropertyChangeListener buildSubjectChangeListener_() { |
| return new SubjectChangeListener(); |
| } |
| |
| /* CU private */ class SubjectChangeListener |
| extends PropertyChangeAdapter |
| { |
| @Override |
| @SuppressWarnings("unchecked") |
| public void propertyChanged(PropertyChangeEvent e) { |
| Pane.this.subjectChanged((T) e.getOldValue(), (T) e.getNewValue()); |
| } |
| } |
| |
| /** |
| * Initialize the pane's models. This method is called before the pane's |
| * UI widget is built in {@link #initializeLayout(Composite)}. |
| */ |
| protected void initialize() { |
| // do nothing by default |
| } |
| |
| /** |
| * Build the pane's UI widget in the specified composite, using |
| * the models built in {@link #initialize()}. |
| */ |
| protected abstract void initializeLayout(Composite parentComposite); |
| |
| private DisposeListener buildControlDisposeListener() { |
| return new ControlDisposeListener(); |
| } |
| |
| /* CU private */ class ControlDisposeListener |
| extends DisposeAdapter |
| { |
| @Override |
| public void widgetDisposed(DisposeEvent event) { |
| Pane.this.controlDisposed(); |
| } |
| } |
| |
| |
| /** |
| * Adds any property names to the given collection in order to be notified |
| * when the actual property changes in the subject. |
| * |
| * @param propertyNames The collection of property names to register with the |
| * subject |
| */ |
| protected void addPropertyNames(Collection<String> propertyNames) { |
| } |
| |
| private PropertyChangeListener buildAspectChangeListener() { |
| return SWTListenerTools.wrap(buildAspectChangeListener_()); |
| } |
| |
| private PropertyChangeListener buildAspectChangeListener_() { |
| return new PropertyChangeListener() { |
| public void propertyChanged(PropertyChangeEvent e) { |
| //subject() could have changed or is null because of the possibility of |
| //"jumping" on the UI thread here and a selection change occuring |
| if (e.getSource() == getSubject()) { |
| updatePane(e.getPropertyName()); |
| } |
| } |
| }; |
| } |
| |
| /** |
| * Creates a new button using the given information. |
| * |
| * @param parent The parent container |
| * @param buttonText The button's text |
| * @param buttonAction The action to be invoked when the button is pressed |
| * @return The newly created <code>Button</code> |
| * |
| * @category Layout |
| */ |
| protected final Button addButton(Composite container, |
| String text, |
| final Runnable buttonAction) { |
| |
| return this.addButton(container, text, null, buttonAction); |
| } |
| |
| protected final Button addButton(Composite container, |
| String text, |
| final Runnable buttonAction, |
| PropertyValueModel<Boolean> enabledModel) { |
| |
| return this.addButton(container, text, null, buttonAction, enabledModel); |
| } |
| |
| /** |
| * Creates a new unmanaged <code>Button</code> widget. Unmanaged means |
| * that this Pane will not handle the enabling/disabling of this widget. |
| * The owning object will handle it with its own PaneEnabler or ControlEnabler. |
| * |
| * @param parent The parent container |
| * @param buttonText The button's text |
| * @param buttonAction The action to be invoked when the button is pressed |
| * @return The newly created <code>Button</code> |
| * |
| * @category Layout |
| */ |
| protected final Button addUnmanagedButton(Composite container, |
| String text, |
| final Runnable buttonAction) { |
| |
| return this.addUnmanagedButton(container, text, null, buttonAction); |
| } |
| |
| /** |
| * Creates a new button using the given information. |
| * |
| * @param parent The parent container |
| * @param buttonText The button's text |
| * @param helpId The topic help ID to be registered for the new check box |
| * @param buttonAction The action to be invoked when the button is pressed |
| * @return The newly created <code>Button</code> |
| * |
| * @category Layout |
| */ |
| protected final Button addButton(Composite container, |
| String text, |
| String helpId, |
| final Runnable buttonAction) { |
| |
| Button button = addUnmanagedButton(container, text, helpId, buttonAction); |
| this.bindEnabledState(button); |
| |
| return button; |
| } |
| |
| protected final Button addButton(Composite container, |
| String text, |
| String helpId, |
| final Runnable buttonAction, |
| PropertyValueModel<Boolean> enabledModel) { |
| |
| Button button = addUnmanagedButton(container, text, helpId, buttonAction); |
| this.bindEnabledState(enabledModel, button); |
| |
| return button; |
| } |
| |
| /** |
| * Creates a new unmanaged <code>Button</code> widget. Unmanaged means |
| * that this Pane will not handle the enabling/disabling of this widget. |
| * The owning object will handle it with its own PaneEnabler or ControlEnabler. |
| * |
| * @param parent The parent container |
| * @param buttonText The button's text |
| * @param helpId The topic help ID to be registered for the new check box |
| * @param buttonAction The action to be invoked when the button is pressed |
| * @return The newly created <code>Button</code> |
| * |
| * @category Layout |
| */ |
| private Button addUnmanagedButton(Composite container, |
| String text, |
| String helpId, |
| final Runnable buttonAction) { |
| |
| Button button = this.getWidgetFactory().createButton(container, text); |
| button.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| buttonAction.run(); |
| } |
| }); |
| |
| if (helpId != null) { |
| this.setHelp(button, helpId); |
| } |
| |
| GridData gridData = new GridData(); |
| gridData.grabExcessHorizontalSpace = false; |
| gridData.horizontalAlignment = GridData.FILL; |
| button.setLayoutData(gridData); |
| |
| return button; |
| } |
| |
| /** |
| * This layout will leave space for decorations on widgets. |
| * Whether decorated or not, all of the widgets need the same indent |
| * so that they align properly. |
| */ |
| protected GridData getFieldGridData() { |
| int margin = FieldDecorationRegistry.getDefault() |
| .getMaximumDecorationWidth(); |
| GridData data = new GridData(); |
| data.horizontalAlignment = SWT.FILL; |
| data.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH + margin; |
| data.horizontalIndent = margin; |
| data.grabExcessHorizontalSpace = true; |
| return data; |
| } |
| |
| /** |
| * Creates a new check box using the given information. |
| * |
| * @param parent The parent container |
| * @param buttonText The button's text |
| * @param booleanHolder The holder of the selection state |
| * @param helpId The topic help ID to be registered for the new check box |
| * @return The newly created <code>Button</code> |
| * |
| * @category Layout |
| */ |
| protected final Button addCheckBox( |
| Composite parent, |
| String buttonText, |
| ModifiablePropertyValueModel<Boolean> booleanHolder, |
| String helpId) { |
| |
| return this.addToggleButton( |
| parent, |
| buttonText, |
| booleanHolder, |
| helpId, |
| SWT.CHECK); |
| } |
| |
| protected final Button addCheckBox( |
| Composite parent, |
| String buttonText, |
| ModifiablePropertyValueModel<Boolean> booleanHolder, |
| String helpId, |
| PropertyValueModel<Boolean> enabledModel) { |
| |
| Button button = this.addUnmanagedToggleButton(parent, buttonText, booleanHolder, helpId, SWT.CHECK); |
| this.bindEnabledState(enabledModel, button); |
| return button; |
| } |
| |
| /** |
| * Creates a new non-editable <code>Combo</code>. |
| * |
| * @param container The parent container |
| * @return The newly created <code>Combo</code> |
| * |
| * @category Layout |
| */ |
| protected final Combo addCombo(Composite container) { |
| Combo combo = this.addUnmanagedCombo(container); |
| this.bindEnabledState(combo); |
| return combo; |
| } |
| |
| /** |
| * Creates a new non-editable <code>Combo</code>. |
| * |
| * @param container The parent container |
| * @return The newly created <code>Combo</code> |
| * |
| * @category Layout |
| */ |
| protected final Combo addCombo(Composite container, String helpId) { |
| Combo combo = this.addUnmanagedCombo(container); |
| |
| if (helpId != null) { |
| this.setHelp(combo, helpId); |
| } |
| |
| this.bindEnabledState(combo); |
| return combo; |
| } |
| |
| /** |
| * Creates a new non-editable <code>Combo</code>. |
| * |
| * @param container The parent container |
| * @return The newly created <code>Combo</code> |
| * |
| * @category Layout |
| */ |
| private Combo addUnmanagedCombo(Composite container) { |
| Combo combo = this.getWidgetFactory().createCombo(container); |
| combo.setLayoutData(getFieldGridData()); |
| return combo; |
| } |
| |
| /** |
| * Creates a new non-editable <code>Combo</code>. |
| * |
| * @param container The parent container |
| * @param listHolder The <code>ListValueHolder</code> |
| * @param selectedItemHolder The holder of the selected item |
| * @param stringConverter The converter responsible to transform each item |
| * into a string representation |
| * @return The newly created <code>Combo</code> |
| * |
| * @category Layout |
| */ |
| protected final <V> Combo addCombo(Composite container, |
| ListValueModel<V> listHolder, |
| ModifiablePropertyValueModel<V> selectedItemHolder, |
| Transformer<V, String> stringConverter, |
| String helpId) { |
| |
| Combo combo = this.addCombo(container, helpId); |
| |
| ComboModelAdapter.adapt( |
| listHolder, |
| selectedItemHolder, |
| combo, |
| stringConverter |
| ); |
| |
| return combo; |
| } |
| |
| /** |
| * Creates a new non-editable <code>Combo</code>. |
| * |
| * @param container The parent container |
| * @param listHolder The <code>ListValueHolder</code> |
| * @param selectedItemHolder The holder of the selected item |
| * @param stringConverter The converter responsible to transform each item |
| * into a string representation |
| * @return The newly created <code>Combo</code> |
| * |
| * @category Layout |
| */ |
| private <V> Combo addUnmanagedCombo(Composite container, |
| ListValueModel<V> listHolder, |
| ModifiablePropertyValueModel<V> selectedItemHolder, |
| Transformer<V, String> stringConverter) { |
| |
| Combo combo = this.addUnmanagedCombo(container); |
| |
| ComboModelAdapter.adapt( |
| listHolder, |
| selectedItemHolder, |
| combo, |
| stringConverter |
| ); |
| |
| return combo; |
| } |
| |
| protected final <V> Combo addCombo( |
| Composite container, |
| ListValueModel<V> listHolder, |
| ModifiablePropertyValueModel<V> selectedItemHolder, |
| Transformer<V, String> stringConverter, |
| PropertyValueModel<Boolean> enabledModel) { |
| |
| Combo combo = this.addUnmanagedCombo(container, listHolder, selectedItemHolder, stringConverter); |
| this.bindEnabledState(enabledModel, combo); |
| return combo; |
| } |
| |
| /** |
| * Creates a new <code>ComboViewer</code> using a <code>Combo</code>. |
| * |
| * @param container The parent container |
| * @param labelProvider The provider responsible to convert the combo's items |
| * into human readable strings |
| * @return The newly created <code>ComboViewer</code> |
| * |
| * @category Layout |
| */ |
| protected final ComboViewer addComboViewer(Composite container, |
| IBaseLabelProvider labelProvider) { |
| |
| Combo combo = this.addCombo(container); |
| ComboViewer viewer = new ComboViewer(combo); |
| viewer.setLabelProvider(labelProvider); |
| return viewer; |
| } |
| protected final ComboViewer addComboViewer(Composite container, |
| IBaseLabelProvider labelProvider, |
| String helpId) { |
| |
| Combo combo = this.addCombo(container, helpId); |
| ComboViewer viewer = new ComboViewer(combo); |
| viewer.setLabelProvider(labelProvider); |
| return viewer; |
| } |
| |
| /** |
| * Creates the main container of this pane. The layout and layout data are |
| * automatically set. |
| * |
| * @param parent The parent container |
| * @return The newly created <code>Composite</code> that will holds all the |
| * widgets created by this pane through {@link #initializeLayout(Composite)} |
| * |
| * @category Layout |
| */ |
| protected Composite addComposite(Composite parent) { |
| return this.addSubPane(parent); |
| } |
| |
| /** |
| * Return whether this Pane should add a Composite. Using this |
| * to reduce the number of SWT Controls (USER handles in windows) created. |
| * Typically you would return false if the Pane is for only 1 widget. In this case |
| * you need to override {@link #getControl()} to return the appropriate Control |
| */ |
| protected boolean addsComposite() { |
| return true; |
| } |
| |
| protected final <V> Combo addEditableCombo( |
| Composite container, |
| ListValueModel<V> listHolder, |
| ModifiablePropertyValueModel<V> selectedItemHolder, |
| Transformer<V, String> stringConverter, |
| PropertyValueModel<Boolean> enabledModel) { |
| |
| return this.addEditableCombo(container, listHolder, selectedItemHolder, stringConverter, enabledModel, null); |
| } |
| |
| protected final <V> Combo addEditableCombo( |
| Composite container, |
| ListValueModel<V> listHolder, |
| ModifiablePropertyValueModel<V> selectedItemHolder, |
| Transformer<V, String> stringConverter, |
| PropertyValueModel<Boolean> enabledModel, |
| String helpId) { |
| |
| Combo combo = this.addUnmanagedEditableCombo(container, listHolder, selectedItemHolder, stringConverter, helpId); |
| this.bindEnabledState(enabledModel, combo); |
| return combo; |
| } |
| |
| protected final Combo addEditableCombo(Composite container) { |
| return this.addEditableCombo(container, null); |
| } |
| |
| protected final Combo addEditableCombo(Composite container, String helpId) { |
| Combo combo = this.getWidgetFactory().createEditableCombo(container); |
| |
| if (helpId != null) { |
| this.setHelp(combo, helpId); |
| } |
| |
| combo.setLayoutData(getFieldGridData()); |
| this.bindEnabledState(combo); |
| return combo; |
| } |
| |
| protected final <V> Combo addEditableCombo(Composite container, |
| ListValueModel<V> listHolder, |
| ModifiablePropertyValueModel<V> selectedItemHolder) { |
| |
| return this.addEditableCombo( |
| container, |
| listHolder, |
| selectedItemHolder, |
| TransformerTools.<V>objectToStringTransformer(), |
| (String) null); |
| } |
| |
| /** |
| * Creates a new editable <code>Combo</code>. |
| * |
| * @param container The parent container |
| * @param listHolder The <code>ListValueHolder</code> |
| * @param selectedItemHolder The holder of the selected item |
| * @param stringConverter The converter responsible to transform each item |
| * into a string representation |
| * @return The newly created <code>Combo</code> |
| * |
| * @category Layout |
| */ |
| protected final <V> Combo addEditableCombo(Composite container, |
| ListValueModel<V> listHolder, |
| ModifiablePropertyValueModel<V> selectedItemHolder, |
| Transformer<V, String> stringConverter, |
| String helpId) { |
| |
| Combo combo = this.addEditableCombo(container, helpId); |
| |
| ComboModelAdapter.adapt( |
| listHolder, |
| selectedItemHolder, |
| combo, |
| stringConverter |
| ); |
| |
| return combo; |
| } |
| |
| /** |
| * Creates a new editable <code>ComboViewer</code> using a <code>Combo</code>. |
| * |
| * @param container The parent container |
| * @param labelProvider The provider responsible to convert the combo's items |
| * into human readable strings |
| * @return The newly created <code>ComboViewer</code> |
| * |
| * @category Layout |
| */ |
| protected final ComboViewer addEditableComboViewer(Composite container, |
| IBaseLabelProvider labelProvider) { |
| |
| Combo combo = this.addEditableCombo(container); |
| ComboViewer viewer = new ComboViewer(combo); |
| viewer.setLabelProvider(labelProvider); |
| return viewer; |
| } |
| |
| /** |
| * Creates a new <code>Hyperlink</code> that will invoked the given |
| * <code>Runnable</code> when selected. The given action is always invoked |
| * from the UI thread. |
| * |
| * @param parent The parent container |
| * @param text The hyperlink's text |
| * @param hyperLinkAction The action to be invoked when the link was selected |
| * return The newly created <code>Hyperlink</code> |
| * |
| * @category Layout |
| */ |
| protected final Hyperlink addHyperlink(Composite parent, |
| String text, |
| final Runnable hyperLinkAction) { |
| |
| Hyperlink link = this.getWidgetFactory().createHyperlink(parent, text); |
| this.bindEnabledState(link); |
| |
| link.addMouseListener(new MouseAdapter() { |
| @Override |
| public void mouseUp(MouseEvent e) { |
| |
| Hyperlink hyperLink = (Hyperlink) e.widget; |
| |
| if (hyperLink.isEnabled()) { |
| hyperLinkAction.run(); |
| } |
| } |
| }); |
| |
| return link; |
| } |
| |
| protected final Hyperlink addHyperlink(Composite parent, |
| String text) { |
| |
| Hyperlink link = this.getWidgetFactory().createHyperlink(parent, text); |
| this.bindEnabledState(link); |
| |
| return link; |
| } |
| |
| /** |
| * Creates a new label using the given information. |
| * |
| * @param parent The parent container |
| * @param labelText The label's text |
| * |
| * @category Layout |
| */ |
| protected final Label addLabel(Composite container, |
| String labelText) { |
| |
| Label label = this.addUnmanagedLabel(container, labelText); |
| this.bindEnabledState(label); |
| return label; |
| } |
| |
| protected final Label addLabel( |
| Composite container, |
| String labelText, |
| PropertyValueModel<Boolean> enabledModel |
| ) { |
| Label label = this.addUnmanagedLabel(container, labelText); |
| this.bindEnabledState(enabledModel, label); |
| return label; |
| } |
| |
| /** |
| * Creates a new unmanaged <code>Label</code> widget. Unmanaged means |
| * that this Pane will not handle the enabling/disabling of this widget. |
| * The owning object will handle it with its own PaneEnabler or ControlEnabler. |
| * |
| * @param parent The parent container |
| * @param labelText The label's text |
| * |
| * @category Layout |
| */ |
| private Label addUnmanagedLabel(Composite container, |
| String labelText) { |
| |
| return this.getWidgetFactory().createLabel(container, labelText); |
| } |
| |
| /** |
| * Creates a new managed spinner. Managed means that this Pane will |
| * handle enabling/disabling of this widget if a PaneEnabler is used. |
| * |
| * @param parent The parent container |
| * @param numberHolder The holder of the integer value |
| * @param defaultValue The value shown when the holder has <code>null</code> |
| * @param minimumValue The minimum value that the spinner will allow |
| * @param maximumValue The maximum value that the spinner will allow |
| * @param helpId The topic help ID to be registered for the new button |
| * @return The newly created <code>Spinner</code> |
| * |
| * @category Layout |
| */ |
| protected final Spinner addSpinner(Composite parent, |
| ModifiablePropertyValueModel<Integer> numberHolder, |
| int defaultValue, |
| int minimumValue, |
| int maximumValue, |
| String helpId) { |
| |
| Spinner spinner = addUnmanagedSpinner(parent, numberHolder, defaultValue, minimumValue, maximumValue, helpId); |
| this.bindEnabledState(spinner); |
| return spinner; |
| } |
| |
| /** |
| * Creates a new unmanaged spinner. Unmanaged means that this Pane will |
| * not handle the enabling/disabling of this widget. The owning object will handle |
| * it with its own PaneEnabler or ControlEnabler. |
| * |
| * @param parent The parent container |
| * @param numberHolder The holder of the integer value |
| * @param defaultValue The value shown when the holder has <code>null</code> |
| * @param minimumValue The minimum value that the spinner will allow |
| * @param maximumValue The maximum value that the spinner will allow |
| * @param helpId The topic help ID to be registered for the new button |
| * @return The newly created <code>Spinner</code> |
| * |
| * @category Layout |
| */ |
| private Spinner addUnmanagedSpinner(Composite parent, |
| ModifiablePropertyValueModel<Integer> numberHolder, |
| int defaultValue, |
| int minimumValue, |
| int maximumValue, |
| String helpId) { |
| |
| Spinner spinner = this.getWidgetFactory().createSpinner(parent); |
| spinner.setMinimum(minimumValue); |
| spinner.setMaximum(maximumValue); |
| GridData gridData = getFieldGridData(); |
| gridData.grabExcessHorizontalSpace = false; |
| spinner.setLayoutData(gridData); |
| |
| SpinnerModelAdapter.adapt(numberHolder, spinner, defaultValue); |
| |
| if (helpId != null) { |
| this.setHelp(spinner, helpId); |
| } |
| |
| return spinner; |
| } |
| |
| /** |
| * Creates a new managed DateTime of type SWT.TIME. Managed means that this Pane will |
| * handle enabling/disabling of this widget if a PaneEnabler is used. |
| * |
| * @param parent The parent container |
| * @param hoursHolder The holder of the hours integer value |
| * @param minutesHolder The holder of the minutes integer value |
| * @param secondsHolder The holder of the seconds integer value |
| * @param helpId The topic help ID to be registered for the new dateTime |
| * @return The newly created <code>DateTime</code> |
| * |
| * @category Layout |
| */ |
| protected final DateTime addDateTime(Composite parent, |
| ModifiablePropertyValueModel<Integer> hoursHolder, |
| ModifiablePropertyValueModel<Integer> minutesHolder, |
| ModifiablePropertyValueModel<Integer> secondsHolder, |
| String helpId) { |
| |
| DateTime dateTime = this.addUnmanagedDateTime(parent, hoursHolder, minutesHolder, secondsHolder, helpId); |
| this.bindEnabledState(dateTime); |
| |
| return dateTime; |
| } |
| |
| protected final DateTime addDateTime( |
| Composite parent, |
| ModifiablePropertyValueModel<Integer> hoursHolder, |
| ModifiablePropertyValueModel<Integer> minutesHolder, |
| ModifiablePropertyValueModel<Integer> secondsHolder, |
| String helpId, |
| PropertyValueModel<Boolean> enabledModel |
| ) { |
| DateTime dateTime = this.addUnmanagedDateTime(parent, hoursHolder, minutesHolder, secondsHolder, helpId); |
| this.bindEnabledState(enabledModel, dateTime); |
| return dateTime; |
| } |
| |
| /** |
| * Creates a new unmanaged DateTime of type SWT.TIME. Unmanaged means that this Pane will |
| * not handle the enabling/disabling of this widget. The owning object will handle |
| * it with its own PaneEnabler or ControlEnabler. |
| * |
| * @param parent The parent container |
| * @param hoursHolder The holder of the hours integer value |
| * @param minutesHolder The holder of the minutes integer value |
| * @param secondsHolder The holder of the seconds integer value |
| * @param helpId The topic help ID to be registered for the new dateTime |
| * @return The newly created <code>DateTime</code> |
| * |
| * @category Layout |
| */ |
| private DateTime addUnmanagedDateTime(Composite parent, |
| ModifiablePropertyValueModel<Integer> hoursHolder, |
| ModifiablePropertyValueModel<Integer> minutesHolder, |
| ModifiablePropertyValueModel<Integer> secondsHolder, |
| String helpId) { |
| |
| DateTime dateTime = this.getWidgetFactory().createDateTime(parent, SWT.TIME); |
| |
| DateTimeModelAdapter.adapt(hoursHolder, minutesHolder, secondsHolder, dateTime); |
| |
| if (helpId != null) { |
| this.setHelp(dateTime, helpId); |
| } |
| |
| return dateTime; |
| } |
| /** |
| * Creates a new editable <code>Combo</code>. |
| * |
| * @param container The parent container |
| * @param listHolder The <code>ListValueHolder</code> |
| * @param selectedItemHolder The holder of the selected item |
| * @param stringConverter The converter responsible to transform each item |
| * into a string representation |
| * @return The newly created <code>CCombo</code> |
| * |
| * @category Layout |
| */ |
| private <V> Combo addUnmanagedEditableCombo(Composite container, |
| ListValueModel<V> listHolder, |
| ModifiablePropertyValueModel<V> selectedItemHolder, |
| Transformer<V, String> stringConverter, |
| String helpId) { |
| |
| Combo combo = addUnmanagedEditableCombo(container, helpId); |
| |
| ComboModelAdapter.adapt( |
| listHolder, |
| selectedItemHolder, |
| combo, |
| stringConverter |
| ); |
| |
| return combo; |
| } |
| |
| |
| /** |
| * Creates a new editable <code>Combo</code>. |
| * |
| * @param container The parent container |
| * @return The newly created <code>CCombo</code> |
| * |
| * @category Layout |
| */ |
| private Combo addUnmanagedEditableCombo(Composite container, |
| String helpId) { |
| |
| Combo combo = this.getWidgetFactory().createEditableCombo(container); |
| combo.setLayoutData(getFieldGridData()); |
| |
| |
| if (helpId != null) { |
| this.setHelp(container, helpId); |
| } |
| |
| return combo; |
| } |
| |
| /** |
| * Creates a new list and notify the given selection holder when the |
| * selection changes. If the selection count is different than one than the |
| * holder will receive <code>null</code>. |
| * |
| * @param container The parent container |
| * @param helpId The topic help ID to be registered for the new radio button |
| * @return The newly created <code>List</code> |
| * |
| * @category Layout |
| */ |
| protected final List addList(Composite container, String helpId) { |
| |
| return this.addList( |
| container, |
| new SimplePropertyValueModel<String>(), |
| helpId |
| ); |
| } |
| |
| /** |
| * Creates a new list and notify the given selection holder when the |
| * selection changes. If the selection count is different than one than the |
| * holder will receive <code>null</code>. |
| * |
| * @param container The parent container |
| * @param selectionHolder The holder of the unique selected item |
| * @param helpId The topic help ID to be registered for the new radio button |
| * @return The newly created <code>List</code> |
| * |
| * @category Layout |
| */ |
| protected final List addList(Composite container, |
| ModifiablePropertyValueModel<String> selectionHolder, |
| String helpId) { |
| |
| List list = this.addUnmanagedList(container, selectionHolder, helpId); |
| this.bindEnabledState(list); |
| |
| return list; |
| } |
| |
| /** |
| * Creates a new unmanaged list and notify the given selection holder when the |
| * selection changes. If the selection count is different than one than the |
| * holder will receive <code>null</code>. |
| * Unmanaged means that this Pane will not handle the enabling/disabling of this widget. |
| * The owning object will handle it with its own PaneEnabler or ControlEnabler. |
| * |
| * @param container The parent container |
| * @param selectionHolder The holder of the unique selected item |
| * @param helpId The topic help ID to be registered for the new radio button |
| * @return The newly created <code>List</code> |
| * |
| * @category Layout |
| */ |
| private List addUnmanagedList(Composite container, |
| ModifiablePropertyValueModel<String> selectionHolder, |
| String helpId) { |
| |
| List list = this.getWidgetFactory().createList( |
| container, |
| SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI |
| ); |
| |
| list.addSelectionListener(buildSelectionListener(selectionHolder)); |
| list.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| |
| if (helpId != null) { |
| this.setHelp(list, helpId); |
| } |
| |
| return list; |
| } |
| |
| /** |
| * Creates a new <code>Text</code> widget that has multiple lines. |
| * |
| * @param container The parent container |
| * @return The newly created <code>Text</code> widget |
| * |
| */ |
| protected final Text addMultiLineText(Composite container) { |
| |
| Text text = this.getWidgetFactory().createMultiLineText(container); |
| text.setLayoutData(getFieldGridData()); |
| this.bindEnabledState(text); |
| |
| return text; |
| } |
| |
| /** |
| * Creates a new <code>Text</code> widget that has multiple lines. |
| * |
| * @param container The parent container |
| * @param lineCount The number of lines the text area should display |
| * @param helpId The topic help ID to be registered for the new text |
| * @return The newly created <code>Text</code> widget |
| * |
| * @category Layout |
| */ |
| protected final Text addMultiLineText(Composite container, |
| int lineCount, |
| String helpId) { |
| |
| Text text = this.addMultiLineText(container); |
| adjustMultiLineTextLayout(lineCount, text, text.getLineHeight()); |
| |
| if (helpId != null) { |
| this.setHelp(text, helpId); |
| } |
| |
| return text; |
| } |
| |
| /** |
| * Creates a new <code>Text</code> widget that has multiple lines. |
| * |
| * @param container The parent container |
| * @param textHolder The holder of the text field's input |
| * @param lineCount The number of lines the text area should display |
| * @return The newly created <code>Text</code> widget |
| * |
| * @category Layout |
| */ |
| protected final Text addMultiLineText(Composite container, |
| ModifiablePropertyValueModel<String> textHolder, |
| int lineCount) { |
| |
| return this.addMultiLineText(container, textHolder, lineCount, null); |
| } |
| |
| /** |
| * Creates a new <code>Text</code> widget that has multiple lines. |
| * |
| * @param container The parent container |
| * @param textModel The holder of the text field's input |
| * @param helpId The topic help ID to be registered for the new text |
| * @return The newly created <code>Text</code> widget |
| * |
| * @category Layout |
| */ |
| protected final Text addMultiLineText(Composite container, |
| ModifiablePropertyValueModel<String> textModel, |
| int lineCount, |
| String helpId) { |
| |
| Text text = this.addMultiLineText(container, lineCount, helpId); |
| SWTBindingTools.bind(textModel, text); |
| return text; |
| } |
| |
| /** |
| * Adjusts the layout of the given container so that the text control has the correct amount of |
| * lines by default. |
| */ |
| protected final void adjustMultiLineTextLayout(int lineCount, |
| Control text, |
| int lineHeight) { |
| |
| // Specify the number of lines the text area should display |
| GridData gridData = (GridData) text.getLayoutData(); |
| if (gridData == null) { |
| gridData = this.getFieldGridData(); |
| text.setLayoutData(gridData); |
| } |
| gridData.heightHint = lineHeight * lineCount; |
| } |
| /** |
| * Creates a new <code>PageBook</code> and set the proper layout and layout |
| * data. |
| * |
| * @param container The parent container |
| * @return The newly created <code>PageBook</code> |
| * |
| * @category Layout |
| */ |
| protected final PageBook addPageBook(Composite container) { |
| |
| PageBook pageBook = new PageBook(container, SWT.NULL); |
| pageBook.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| return pageBook; |
| } |
| |
| /** |
| * Creates a new container without specifying any layout manager. |
| * |
| * @param container The parent of the new container |
| * @return The newly created <code>Composite</code> |
| * |
| * @category Layout |
| */ |
| protected final Composite addPane(Composite parent) { |
| return this.getWidgetFactory().createComposite(parent); |
| } |
| |
| /** |
| * Creates a new container using the given layout manager. |
| * |
| * @param parent The parent of the new container |
| * @param layout The layout manager of the new container |
| * @return The newly created container |
| * |
| * @category Layout |
| */ |
| protected final Composite addPane(Composite container, Layout layout) { |
| |
| container = this.addPane(container); |
| container.setLayout(layout); |
| container.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| return container; |
| } |
| |
| /** |
| * Creates a new <code>Text</code> widget. |
| * |
| * @param container The parent container |
| * @param textModel The holder of the text field's input |
| * @return The newly created <code>Text</code> widget |
| * |
| * @category Layout |
| */ |
| protected final Text addPasswordText(Composite container, |
| ModifiablePropertyValueModel<String> textModel) { |
| |
| Text text = this.addPasswordText(container); |
| SWTBindingTools.bind(textModel, text); |
| |
| return text; |
| } |
| |
| /** |
| * Creates a new <code>Text</code> widget. |
| * |
| * @param container The parent container |
| * @return The newly created <code>Text</code> widget |
| * |
| * @category Layout |
| */ |
| protected final Text addPasswordText(Composite container) { |
| |
| Text text = this.getWidgetFactory().createPasswordText(container); |
| text.setLayoutData(getFieldGridData()); |
| |
| this.bindEnabledState(text); |
| return text; |
| } |
| |
| /** |
| * Creates a new push button using the given information. |
| * |
| * @param parent The parent container |
| * @param buttonText The button's text |
| * @param buttonAction The action to be invoked when the button is pressed |
| * @return The newly created <code>Button</code> |
| * |
| * @category Layout |
| */ |
| protected final Button addPushButton(Composite parent, |
| String buttonText, |
| final Runnable buttonAction) { |
| |
| return this.addPushButton(parent, buttonText, null, buttonAction); |
| } |
| |
| /** |
| * Creates a new push button using the given information. |
| * |
| * @param parent The parent container |
| * @param buttonText The button's text |
| * @param buttonAction The action to be invoked when the button is pressed |
| * @param helpId The topic help ID to be registered for the new radio button |
| * @return The newly created <code>Button</code> |
| * |
| * @category Layout |
| */ |
| protected final Button addPushButton(Composite parent, |
| String buttonText, |
| String helpId, |
| final Runnable buttonAction) { |
| |
| Button button = this.getWidgetFactory().createPushButton(parent, buttonText); |
| bindEnabledState(button); |
| button.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| buttonAction.run(); |
| } |
| }); |
| |
| button.setLayoutData(new GridData()); |
| |
| if (helpId != null) { |
| this.setHelp(button, helpId); |
| } |
| |
| return button; |
| } |
| |
| /** |
| * Creates a new check box using the given information. |
| * |
| * @param parent The parent container |
| * @param buttonText The button's text |
| * @param booleanHolder The holder of the selection state |
| * @param helpId The topic help ID to be registered for the new radio button |
| * @return The newly created <code>Button</code> |
| * |
| * @category Layout |
| */ |
| protected final Button addRadioButton(Composite parent, |
| String buttonText, |
| ModifiablePropertyValueModel<Boolean> booleanHolder, |
| String helpId) { |
| |
| return this.addToggleButton( |
| parent, |
| buttonText, |
| booleanHolder, |
| helpId, |
| SWT.RADIO |
| ); |
| } |
| |
| /** |
| * Creates a new <code>Section</code>. A sub-pane is automatically added as |
| * its client and is the returned <code>Composite</code>. |
| * |
| * @param container The container of the new widget |
| * @param sectionText The text of the new section |
| * @param description The section's description |
| * @return The <code>Section</code>'s sub-pane |
| * |
| * @category Layout |
| */ |
| protected final Composite addSection(Composite container, |
| String sectionText, |
| String description) { |
| |
| return this.addSection( |
| container, |
| sectionText, |
| description, |
| ExpandableComposite.TITLE_BAR |
| ); |
| } |
| |
| /** |
| * Creates a new <code>Section</code>. A sub-pane is automatically added as |
| * its client and is the returned <code>Composite</code>. |
| * |
| * @param container The container of the new widget |
| * @param sectionText The text of the new section |
| * @param description The section's description or <code>null</code> if none |
| * was provider |
| * @param type The type of section to create |
| * when to expand or collapse the section |
| * @return The <code>Section</code>'s sub-pane |
| * |
| * @category Layout |
| */ |
| private Composite addSection(Composite container, |
| String sectionText, |
| String description, |
| int type) { |
| |
| Section section = this.getWidgetFactory().createSection(container, type | ((description != null) ? Section.DESCRIPTION : SWT.NULL)); |
| section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| section.setText(sectionText); |
| |
| if (description != null) { |
| section.setDescription(description); |
| } |
| |
| Composite subPane = this.addSubPane(section); |
| section.setClient(subPane); |
| |
| return subPane; |
| } |
| |
| private SelectionListener buildSelectionListener(final ModifiablePropertyValueModel<String> selectionHolder) { |
| return new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| List list = (List) e.widget; |
| String[] selectedItems = list.getSelection(); |
| if ((selectedItems == null) || (selectedItems.length != 1)) { |
| selectionHolder.setValue(null); |
| } |
| else { |
| selectionHolder.setValue(selectedItems[0]); |
| } |
| } |
| }; |
| } |
| |
| /** |
| * Creates a new <code>Composite</code> used as a sub-pane. |
| * |
| * @param container The parent container |
| * @return The newly created <code>Composite</code> used as a sub-pane |
| * |
| * @category Layout |
| */ |
| protected final Composite addSubPane(Composite container) { |
| return this.addSubPane(container, 0); |
| } |
| |
| /** |
| * Creates a new <code>Composite</code> used as a sub-pane. |
| * |
| * @param container The parent container |
| * @param topMargin The extra spacing to add at the top of the pane |
| * @return The newly created <code>Composite</code> used as a sub-pane |
| * |
| * @category Layout |
| */ |
| protected final Composite addSubPane(Composite container, int topMargin) { |
| return this.addSubPane(container, topMargin, 0); |
| } |
| |
| /** |
| * Creates a new <code>Composite</code> used as a sub-pane. |
| * |
| * @param container The parent container |
| * @param topMargin The extra spacing to add at the top of the pane |
| * @param leftMargin The extra spacing to add to the left of the pane |
| * @return The newly created <code>Composite</code> used as a sub-pane |
| * |
| * @category Layout |
| */ |
| protected final Composite addSubPane(Composite container, |
| int topMargin, |
| int leftMargin) { |
| |
| return this.addSubPane(container, topMargin, leftMargin, 0, 0); |
| } |
| |
| /** |
| * Creates a new <code>Composite</code> used as a sub-pane, the new widget |
| * will have its layout and layout data already initialized, the layout will |
| * be a <code>GridLayout</code> with 1 column. |
| * |
| * @param container The parent container |
| * @param topMargin The extra spacing to add at the top of the pane |
| * @param leftMargin The extra spacing to add to the left of the pane |
| * @param bottomMargin The extra spacing to add at the bottom of the pane |
| * @param rightMargin The extra spacing to add to the right of the pane |
| * @return The newly created <code>Composite</code> used as a sub-pane |
| * |
| * @category Layout |
| */ |
| protected final Composite addSubPane(Composite container, |
| int topMargin, |
| int leftMargin, |
| int bottomMargin, |
| int rightMargin) { |
| |
| return this.addSubPane( |
| container, |
| 1, |
| topMargin, |
| leftMargin, |
| bottomMargin, |
| rightMargin); |
| } |
| |
| /** |
| * Creates a new <code>Composite</code> used as a sub-pane, the new widget |
| * will have its layout and layout data already initialized, the layout will |
| * be a <code>GridLayout</code> with 1 column. |
| * |
| * @param container The parent container |
| * @param topMargin The extra spacing to add at the top of the pane |
| * @param leftMargin The extra spacing to add to the left of the pane |
| * @param bottomMargin The extra spacing to add at the bottom of the pane |
| * @param rightMargin The extra spacing to add to the right of the pane |
| * @return The newly created <code>Composite</code> used as a sub-pane |
| * |
| * @category Layout |
| */ |
| protected final Composite addSubPane(Composite container, |
| int columnCount, |
| int topMargin, |
| int leftMargin, |
| int bottomMargin, |
| int rightMargin) { |
| |
| GridLayout layout = new GridLayout(columnCount, false); |
| layout.marginHeight = 0; |
| layout.marginWidth = 0; |
| layout.marginTop = topMargin; |
| layout.marginLeft = leftMargin; |
| layout.marginBottom = bottomMargin; |
| layout.marginRight = rightMargin; |
| |
| container = this.addPane(container, layout); |
| |
| return container; |
| } |
| |
| /** |
| * Creates a new table. |
| * |
| * @param container The parent container |
| * @param style The style to apply to the table |
| * @param helpId The topic help ID to be registered for the new table or |
| * <code>null</code> if no help ID is required |
| * @return The newly created <code>Table</code> |
| * |
| * @category Layout |
| */ |
| protected final Table addTable(Composite container, |
| int style, |
| String helpId) { |
| |
| Table table = addUnmanagedTable(container, style, helpId); |
| this.bindEnabledState(table); |
| |
| return table; |
| } |
| /** |
| * Creates a new unmanaged table. Unmanaged means that this Pane will |
| * not handle the enabling/disabling of this widget. The owning object will handle |
| * it with its own PaneEnabler or ControlEnabler. |
| * |
| * @param container The parent container |
| * @param style The style to apply to the table |
| * @param helpId The topic help ID to be registered for the new table or |
| * <code>null</code> if no help ID is required |
| * @return The newly created <code>Table</code> |
| * |
| * @category Layout |
| */ |
| protected final Table addUnmanagedTable(Composite container, |
| int style, |
| String helpId) { |
| |
| Table table = this.getWidgetFactory().createTable(container, style); |
| table.setHeaderVisible(true); |
| table.setLinesVisible(true); |
| |
| GridData gridData = new GridData(GridData.FILL_BOTH); |
| gridData.heightHint = table.getItemHeight() * 4; |
| table.setLayoutData(gridData); |
| |
| if (helpId != null) { |
| this.setHelp(table, helpId); |
| } |
| |
| return table; |
| } |
| |
| /** |
| * Creates a new table. |
| * |
| * @param container The parent container |
| * @param helpId The topic help ID to be registered for the new table or |
| * <code>null</code> if no help ID is required |
| * @return The newly created <code>Table</code> |
| * |
| * @category Layout |
| */ |
| protected final Table addTable(Composite container, String helpId) { |
| |
| return this.addTable( |
| container, |
| SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION | SWT.MULTI, |
| helpId |
| ); |
| } |
| |
| /** |
| * Creates a new unmanaged table. Unmanaged means that this Pane will |
| * not handle the enabling/disabling of this widget. The owning object will handle |
| * it with its own PaneEnabler or ControlEnabler. |
| * |
| * @param container The parent container |
| * @param helpId The topic help ID to be registered for the new table or |
| * <code>null</code> if no help ID is required |
| * @return The newly created <code>Table</code> |
| * |
| * @category Layout |
| */ |
| protected final Table addUnmanagedTable(Composite container, String helpId) { |
| |
| return this.addUnmanagedTable( |
| container, |
| SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION | SWT.MULTI, |
| helpId |
| ); |
| } |
| |
| /** |
| * Creates a new managed <code>Text</code> widget. |
| * |
| * @param container The parent container |
| * @return The newly created <code>Text</code> widget |
| * |
| * @category Layout |
| */ |
| protected final Text addText(Composite container) { |
| Text text = this.addUnmanagedText(container); |
| this.bindEnabledState(text); |
| return text; |
| } |
| |
| /** |
| * Creates a new unmanaged <code>Text</code> widget. Unmanaged means |
| * that this Pane will not handle the enabling/disabling of this widget. |
| * The owning object will handle it with its own PaneEnabler or ControlEnabler. |
| * |
| * @param container The parent container |
| * @return The newly created <code>Text</code> widget |
| * |
| * @category Layout |
| */ |
| private Text addUnmanagedText(Composite container) { |
| Text text = this.getWidgetFactory().createText(container); |
| text.setLayoutData(getFieldGridData()); |
| return text; |
| } |
| |
| /** |
| * Creates a new <code>Text</code> widget. |
| * |
| * @param container The parent container |
| * @param helpId The topic help ID to be registered for the new text |
| * @return The newly created <code>Text</code> widget |
| * |
| * @category Layout |
| */ |
| protected final Text addText(Composite container, String helpId) { |
| |
| Text text = this.addText(container); |
| |
| if (helpId != null) { |
| this.setHelp(text, helpId); |
| } |
| |
| return text; |
| } |
| |
| /** |
| * Creates a new unmanaged <code>Text</code> widget. Unmanaged means |
| * that this Pane will not handle the enabling/disabling of this widget. |
| * The owning object will handle it with its own PaneEnabler or ControlEnabler. |
| * |
| * @param container The parent container |
| * @param helpId The topic help ID to be registered for the new text |
| * @return The newly created <code>Text</code> widget |
| * |
| * @category Layout |
| */ |
| private Text addUnmanagedText(Composite container, String helpId) { |
| |
| Text text = this.addUnmanagedText(container); |
| |
| if (helpId != null) { |
| this.setHelp(text, helpId); |
| } |
| |
| return text; |
| } |
| |
| /** |
| * Creates a new <code>Text</code> widget. |
| * |
| * @param container The parent container |
| * @param textHolder The holder of the text field's input |
| * @return The newly created <code>Text</code> widget |
| * |
| * @category Layout |
| */ |
| protected final Text addText(Composite container, |
| ModifiablePropertyValueModel<String> textHolder) { |
| |
| return this.addText(container, textHolder, null); |
| } |
| |
| /** |
| * Creates a new <code>Text</code> widget. |
| * |
| * @param container The parent container |
| * @param textModel The holder of the text field's input |
| * @param helpId The topic help ID to be registered for the new text |
| * @return The newly created <code>Text</code> widget |
| * |
| * @category Layout |
| */ |
| protected final Text addText(Composite container, |
| ModifiablePropertyValueModel<String> textModel, |
| String helpId) { |
| |
| Text text = this.addText(container, helpId); |
| SWTBindingTools.bind(textModel, text); |
| |
| return text; |
| } |
| |
| protected final Text addText( |
| Composite container, |
| ModifiablePropertyValueModel<String> textHolder, |
| String helpId, |
| PropertyValueModel<Boolean> enabledModel |
| ) { |
| Text text = this.addUnmanagedText(container, textHolder, helpId); |
| this.bindEnabledState(enabledModel, text); |
| return text; |
| } |
| |
| /** |
| * Creates a new unmanaged <code>Text</code> widget. Unmanaged means |
| * that this Pane will not handle the enabling/disabling of this widget. |
| * The owning object will handle it with its own PaneEnabler or ControlEnabler. |
| * |
| * @param container The parent container |
| * @param textModel The holder of the text field's input |
| * @param helpId The topic help ID to be registered for the new text |
| * @return The newly created <code>Text</code> widget |
| * |
| * @category Layout |
| */ |
| private Text addUnmanagedText(Composite container, |
| ModifiablePropertyValueModel<String> textModel, |
| String helpId) { |
| |
| Text text = this.addUnmanagedText(container, helpId); |
| SWTBindingTools.bind(textModel, text); |
| |
| return text; |
| } |
| |
| /** |
| * Creates a new container with a titled border. |
| * |
| * @param title The text of the titled border |
| * @param container The parent container |
| * @return The newly created <code>Composite</code> with a titled border |
| * |
| * @category Layout |
| */ |
| protected final Group addTitledGroup(Composite container, String title) { |
| return this.addTitledGroup(container, title, null); |
| } |
| |
| /** |
| * Creates a new container with a titled border. |
| * |
| * @param title The text of the titled border |
| * @param container The parent container |
| * @param helpId The topic help ID to be registered for the new group |
| * @return The newly created <code>Composite</code> with a titled border |
| * |
| * @category Layout |
| */ |
| protected final Group addTitledGroup(Composite container, |
| String title, |
| String helpId) { |
| |
| return addTitledGroup(container, title, 1, helpId); |
| } |
| |
| /** |
| * Creates a new container with a titled border. |
| * |
| * @param title The text of the titled border |
| * @param container The parent container |
| * @param helpId The topic help ID to be registered for the new group |
| * @return The newly created <code>Composite</code> with a titled border |
| * |
| * @category Layout |
| */ |
| protected final Group addTitledGroup(Composite container, |
| String title, |
| int columnCount, |
| String helpId) { |
| |
| Group group = this.getWidgetFactory().createGroup(container, title); |
| //manageWidget(group); TODO unsure if I want to manage groups, |
| //also should probably rename this addUnmanagedTitledPane |
| group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| |
| GridLayout layout = new GridLayout(columnCount, false); |
| layout.marginHeight = 0; |
| layout.marginWidth = 0; |
| layout.marginTop = 5; |
| layout.marginLeft = 5; |
| layout.marginBottom = 5; |
| layout.marginRight = 5; |
| group.setLayout(layout); |
| |
| if (helpId != null) { |
| this.setHelp(group, helpId); |
| } |
| |
| return group; |
| } |
| |
| /** |
| * Creates a new unmanaged new toggle button (radio button or check box). |
| * Unmanaged means that this Pane will not handle the enabling/disabling |
| * of this widget. The owning object will handle it with its own PaneEnabler |
| * or ControlEnabler. |
| * |
| * @param parent The parent container |
| * @param buttonText The button's text |
| * @param booleanModel The holder of the selection state |
| * @param helpId The topic help ID to be registered for the new button |
| * @return The newly created <code>Button</code> |
| * |
| * @category Layout |
| */ |
| private Button addUnmanagedToggleButton( |
| Composite parent, |
| String buttonText, |
| ModifiablePropertyValueModel<Boolean> booleanModel, |
| String helpId, |
| int toggleButtonType) { |
| |
| Button button; |
| |
| if (toggleButtonType == SWT.PUSH) { |
| button = this.getWidgetFactory().createPushButton(parent, buttonText); |
| } |
| else if (toggleButtonType == SWT.RADIO) { |
| button = this.getWidgetFactory().createRadioButton(parent, buttonText); |
| } |
| else if (toggleButtonType == SWT.CHECK) { |
| button = this.getWidgetFactory().createCheckBox(parent, buttonText); |
| } |
| else { |
| button = this.getWidgetFactory().createButton(parent, buttonText); |
| } |
| |
| button.setLayoutData(new GridData()); |
| SWTBindingTools.bind(booleanModel, button); |
| |
| if (helpId != null) { |
| this.setHelp(button, helpId); |
| } |
| |
| return button; |
| } |
| |
| /** |
| * Creates a new toggle button (radio button or check box) using the given |
| * information. |
| * |
| * @param parent The parent container |
| * @param buttonText The button's text |
| * @param booleanHolder The holder of the selection state |
| * @param helpId The topic help ID to be registered for the new button |
| * @return The newly created <code>Button</code> |
| * |
| * @category Layout |
| */ |
| private Button addToggleButton( |
| Composite parent, |
| String buttonText, |
| ModifiablePropertyValueModel<Boolean> booleanHolder, |
| String helpId, |
| int toggleButtonType) { |
| |
| Button button = addUnmanagedToggleButton( |
| parent, |
| buttonText, |
| booleanHolder, |
| helpId, |
| toggleButtonType); |
| this.bindEnabledState(button); |
| return button; |
| } |
| |
| /** |
| * Creates a new check box that can have 3 selection states (selected, |
| * unselected and partially selected. |
| * |
| * @param parent The parent container |
| * @param text The button's text |
| * @param booleanHolder The holder of the boolean value where <code>null</code> |
| * means partially selected |
| * @param helpId The topic help ID to be registered for the new check box |
| * @return The newly created <code>TriStateCheckBox</code> |
| * |
| * @category Layout |
| */ |
| protected final TriStateCheckBox addTriStateCheckBox(Composite parent, |
| String text, |
| ModifiablePropertyValueModel<Boolean> booleanHolder, |
| String helpId) { |
| |
| TriStateCheckBox checkBox = this.addUnmanagedTriStateCheckBox(parent, text, booleanHolder, helpId); |
| |
| this.bindEnabledState(checkBox.getCheckBox()); |
| |
| return checkBox; |
| } |
| |
| protected final TriStateCheckBox addUnmanagedTriStateCheckBox(Composite parent, |
| String text, |
| ModifiablePropertyValueModel<Boolean> booleanHolder, |
| String helpId) { |
| |
| TriStateCheckBox checkBox = new TriStateCheckBox( |
| parent, |
| text, |
| this.getWidgetFactory() |
| ); |
| |
| TriStateCheckBoxModelAdapter.adapt( |
| booleanHolder, |
| checkBox |
| ); |
| |
| if (helpId != null) { |
| this.setHelp(checkBox.getCheckBox(), helpId); |
| } |
| |
| return checkBox; |
| } |
| |
| /** |
| * Creates a new check box that can have 3 selection states (selected, |
| * unselected and partially selected. |
| * |
| * @param parent The parent container |
| * @param text The button's text |
| * @param booleanHolder The holder of the boolean value where <code>null</code> |
| * means partially selected |
| * @param textModel The holder of the string to put in parenthesis after |
| * the check box's text when it is partially selected |
| * @param helpId The topic help ID to be registered for the new check box |
| * @return The newly created <code>TriStateCheckBox</code> |
| * |
| * @category Layout |
| */ |
| protected final TriStateCheckBox addTriStateCheckBoxWithDefault(Composite parent, |
| String text, |
| ModifiablePropertyValueModel<Boolean> booleanHolder, |
| PropertyValueModel<String> textModel, |
| String helpId) { |
| |
| TriStateCheckBox checkBox = this.addTriStateCheckBox( |
| parent, |
| text, |
| booleanHolder, |
| helpId |
| ); |
| |
| SWTBindingTools.bindTextLabel(textModel, checkBox.getCheckBox()); |
| |
| return checkBox; |
| } |
| |
| protected final TriStateCheckBox addTriStateCheckBoxWithDefault(Composite parent, |
| String text, |
| ModifiablePropertyValueModel<Boolean> booleanHolder, |
| PropertyValueModel<String> textModel, |
| PropertyValueModel<Boolean> enabledModel, |
| String helpId) { |
| |
| TriStateCheckBox checkBox = this.addUnmanagedTriStateCheckBox(parent, text, booleanHolder, helpId); |
| |
| this.bindEnabledState(enabledModel, checkBox.getCheckBox()); |
| |
| SWTBindingTools.bindTextLabel(textModel, checkBox.getCheckBox()); |
| |
| return checkBox; |
| } |
| |
| /** |
| * Requests this pane to populate its widgets with the subject's values. |
| * |
| * @category Populate |
| */ |
| protected void doPopulate() { |
| JptCommonUiPlugin.instance().trace(TRACE_OPTION, "doPopulate"); |
| } |
| |
| |
| // ********** enabled models ********** |
| |
| protected boolean isEnabled() { |
| return this.enabledModel.getValue().booleanValue(); |
| } |
| |
| /** |
| * Control the <em>enabled</em> state of the specified controls with the |
| * pane's {@link #enabledModel}. |
| * <p> |
| * Use {@link #bindEnabledState(PropertyValueModel, Control...)} if the |
| * controls might be disabled when the pane is enabled. |
| */ |
| protected void bindEnabledState(Control... controls) { |
| SWTBindingTools.bindEnabledState(this.enabledModel, controls); |
| } |
| |
| /** |
| * Use the specified boolean model to determine the <em>enabled</em> |
| * state of the specified controls (i.e. when the <em>pane</em> is enabled). |
| * If the specified boolean model returns <code>null</code> (which is |
| * typical of aspect adapters), the controls will be disabled. |
| * <p> |
| * Use {@link #bindEnabledState(Control...)} if the |
| * controls are only enabled when the pane is enabled. |
| */ |
| protected void bindEnabledState(PropertyValueModel<Boolean> controlsEnabledModel, Control... controls) { |
| SWTBindingTools.bindEnabledState(this.andEnabledModel(controlsEnabledModel), controls); |
| } |
| |
| /** |
| * AND the specified boolean model with the pane's {@link #enabledModel}, |
| * resulting in an <em>enabled</em> model that can only be <code>true</code> |
| * when the pane as a whole is enabled. |
| */ |
| private PropertyValueModel<Boolean> andEnabledModel(PropertyValueModel<Boolean> booleanModel) { |
| return andEnabledModel(this, booleanModel); |
| } |
| |
| |
| // ********** subject listeners ********** |
| |
| /** |
| * Engage the specified subject |
| */ |
| private void engageListeners(T subject) { |
| if (subject != null) { |
| this.engageListeners_(subject); |
| } |
| } |
| |
| /** |
| * Pre-condition: the specified subject is not <code>null</code> |
| */ |
| protected void engageListeners_(T subject) { |
| JptCommonUiPlugin.instance().trace(TRACE_OPTION, "engageListeners_({0})", subject); |
| |
| for (String propertyName : this.getPropertyNames()) { |
| subject.addPropertyChangeListener(propertyName, this.aspectChangeListener); |
| } |
| } |
| |
| /** |
| * Disengage the specified subject |
| */ |
| private void disengageListeners(T subject) { |
| if (subject != null) { |
| this.disengageListeners_(subject); |
| } |
| } |
| |
| /** |
| * Pre-condition: the specified subject is not <code>null</code> |
| */ |
| protected void disengageListeners_(T subject) { |
| JptCommonUiPlugin.instance().trace(TRACE_OPTION, "disengageListeners_({0})", subject); |
| |
| for (String propertyName : this.getPropertyNames()) { |
| subject.removePropertyChangeListener(propertyName, this.aspectChangeListener); |
| } |
| } |
| |
| /** |
| * Returns the main <code>Composite</code> of this pane. |
| * |
| * @return The main container |
| * |
| * @category Layout |
| */ |
| public Control getControl() { |
| if (!addsComposite()) { |
| throw new IllegalStateException("Must override getControl() if addsComposite() returns false"); |
| } |
| return this.container; |
| } |
| |
| /** |
| * Returns the subject holder used by this pane. |
| * |
| * @return The holder of the subject |
| * |
| * @category Populate |
| */ |
| protected final PropertyValueModel<? extends T> getSubjectHolder() { |
| return this.subjectModel; |
| } |
| |
| /** |
| * If the pane is a <em>root</em> pane, return its widget factory; |
| * otherwise return the pane's parent's widget factory. |
| */ |
| protected final WidgetFactory getWidgetFactory() { |
| return (this.parent == null) ? this.widgetFactory : this.parent.getWidgetFactory(); |
| } |
| |
| /** |
| * If the pane is a <em>root</em> pane, return its resource manager; |
| * otherwise return the pane's parent's resource manager. |
| */ |
| public final ResourceManager getResourceManager() { |
| return (this.parent == null) ? this.resourceManager : this.parent.getResourceManager(); |
| } |
| |
| protected final void setHelp(Control control, String contextID) { |
| WorkbenchTools.setHelp(control, contextID); |
| } |
| |
| protected final boolean isPopulating() { |
| return this.populating; |
| } |
| |
| /** |
| * Notifies this pane to populate itself using the subject's information. |
| * |
| * @category Populate |
| */ |
| private void populate() { |
| if (!this.getControl().isDisposed()) { |
| JptCommonUiPlugin.instance().trace(TRACE_OPTION, "populate"); |
| this.repopulate(); |
| } |
| } |
| |
| /** |
| * The subject's specified property has changed. |
| */ |
| protected void propertyChanged(@SuppressWarnings("unused") String propertyName) { |
| // NOP |
| } |
| |
| /** |
| * Return the names of the subject's properties we listen to here and notify |
| * via calls to {@link #propertyChanged(String)}. |
| */ |
| private Collection<String> getPropertyNames() { |
| ArrayList<String> propertyNames = new ArrayList<String>(); |
| this.addPropertyNames(propertyNames); |
| return propertyNames; |
| } |
| |
| /** |
| * This method is called (perhaps internally) when this needs to repopulate |
| * but the object of interest has not changed. |
| */ |
| protected final void repopulate() { |
| JptCommonUiPlugin.instance().trace(TRACE_OPTION, "repopulate"); |
| |
| try { |
| this.setPopulating(true); |
| this.doPopulate(); |
| } finally { |
| this.setPopulating(false); |
| } |
| } |
| |
| /** |
| * Sets the internal flag that is used to determine whether the pane is being |
| * populated or not. During population, it is required to not update the |
| * widgets when the model is updated nor to update the model when the widgets |
| * are being synchronized with the model's values. |
| */ |
| protected final void setPopulating(boolean populating) { |
| this.populating = populating; |
| } |
| |
| /** |
| * Either show or hides this pane. |
| */ |
| public void setVisible(boolean visible) { |
| if (this.container != null && !this.container.isDisposed()) { |
| this.container.setVisible(visible); |
| } |
| } |
| |
| /** |
| * @see Control#getShell() |
| */ |
| public final Shell getShell() { |
| return this.getControl().getShell(); |
| } |
| |
| /** |
| * Return the pane's subject. |
| */ |
| public T getSubject() { |
| return this.subjectModel.getValue(); |
| } |
| |
| /** |
| * The pane's subject has changed. Disconnect any listeners from the old |
| * subject and connect those listeners to the new subject. |
| */ |
| /* CU private */ final void subjectChanged(T oldSubject, T newSubject) { |
| if ( ! this.getControl().isDisposed()) { |
| JptCommonUiPlugin.instance().trace(TRACE_OPTION, "subjectChanged({0}, {1})", oldSubject, newSubject); |
| this.disengageListeners(oldSubject); |
| this.repopulate(); |
| this.engageListeners(newSubject); |
| } |
| } |
| |
| private void updatePane(String propertyName) { |
| if (!isPopulating() && !this.getControl().isDisposed()) { |
| this.populating = true; |
| |
| try { |
| propertyChanged(propertyName); |
| } |
| finally { |
| this.populating = false; |
| } |
| } |
| } |
| |
| protected void controlDisposed() { |
| // the control is not yet "disposed" when we receive this event |
| // so we can still remove our listeners |
| JptCommonUiPlugin.instance().trace(TRACE_OPTION, "control disposed"); |
| |
| this.disengageListeners(getSubject()); |
| |
| this.subjectModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.subjectChangeListener); |
| |
| this.enabledModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.enabledModelListener); |
| this.getControl().removeDisposeListener(this.controlDisposeListener); |
| if (this.parent == null) { |
| this.resourceManager.dispose(); |
| } |
| } |
| |
| private static final String TRACE_OPTION = Pane.class.getSimpleName(); |
| } |