diff options
author | Brian Vosburgh | 2013-06-24 19:47:20 +0000 |
---|---|---|
committer | Brian Vosburgh | 2013-06-24 19:47:20 +0000 |
commit | 27c014ac463bc3b4646c67fb9e50e3c482e29ae9 (patch) | |
tree | 76ef0b782d9c889d43e8771ebda240211bd44c20 /common/plugins/org.eclipse.jpt.common.ui | |
parent | 365b25a68a1638d0492143603da9409125b3d185 (diff) | |
download | webtools.dali-27c014ac463bc3b4646c67fb9e50e3c482e29ae9.tar.gz webtools.dali-27c014ac463bc3b4646c67fb9e50e3c482e29ae9.tar.xz webtools.dali-27c014ac463bc3b4646c67fb9e50e3c482e29ae9.zip |
clean up SWT bindings
Diffstat (limited to 'common/plugins/org.eclipse.jpt.common.ui')
18 files changed, 866 insertions, 892 deletions
diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/AbstractListWidgetAdapter.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/AbstractListWidgetAdapter.java index c0c0597fc5..ddc19626ea 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/AbstractListWidgetAdapter.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/AbstractListWidgetAdapter.java @@ -10,14 +10,16 @@ package org.eclipse.jpt.common.ui.internal.swt.bindings; import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Widget; /** * All the "list widgets" are subclasses of {@link Widget}; so we can provide * a smidgen of common behavior here. + * @param <W> the type of the widget to be adapted */ -abstract class AbstractListWidgetAdapter<W extends Widget> - implements ListWidgetModelBinding.ListWidget +abstract class AbstractListWidgetAdapter<E, W extends Widget> + implements ListWidgetModelBinding.ListWidget<E> { final W widget; @@ -26,6 +28,10 @@ abstract class AbstractListWidgetAdapter<W extends Widget> this.widget = widget; } + public Display getDisplay() { + return this.widget.getDisplay(); + } + public boolean isDisposed() { return this.widget.isDisposed(); } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/BooleanButtonModelBinding.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/BooleanButtonModelBinding.java index 5c7e1680d4..ba93c5226f 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/BooleanButtonModelBinding.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/BooleanButtonModelBinding.java @@ -10,37 +10,40 @@ package org.eclipse.jpt.common.ui.internal.swt.bindings; import org.eclipse.jpt.common.ui.internal.listeners.SWTListenerWrapperTools; +import org.eclipse.jpt.common.ui.internal.swt.events.DisposeAdapter; +import org.eclipse.jpt.common.ui.internal.swt.events.SelectionAdapter; import org.eclipse.jpt.common.utility.internal.ObjectTools; 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.ModifiablePropertyValueModel; import org.eclipse.jpt.common.utility.model.value.PropertyValueModel; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Button; /** * This binding can be used to keep a check-box, toggle button, or radio button - * "selection" synchronized with a model boolean. + * <em>selection</em> synchronized with a model <code>boolean</code>. + * <p> + * <strong>NB:</strong> This binding is bi-directional. * * @see ModifiablePropertyValueModel * @see Button */ -@SuppressWarnings("nls") final class BooleanButtonModelBinding { // ***** model - /** A value model on the underlying model boolean. */ + /** A value model on the underlying model <code>boolean</code>. */ private final ModifiablePropertyValueModel<Boolean> booleanModel; /** * A listener that allows us to synchronize the button's selection state with - * the model boolean. + * the model <code>boolean</code>. */ - private final PropertyChangeListener booleanChangeListener; + private final PropertyChangeListener booleanListener; /** * The default setting for the check-box/toggle button/radio button; @@ -51,11 +54,14 @@ final class BooleanButtonModelBinding { private final boolean defaultValue; // ***** UI - /** The check-box/toggle button/radio button we synchronize with the model boolean. */ + /** + * The check-box/toggle button/radio button we synchronize with + * the model <code>boolean</code>. + */ private final Button button; /** - * A listener that allows us to synchronize the model boolean with + * A listener that allows us to synchronize the model <code>boolean</code> with * the button's selection state. */ private final SelectionListener buttonSelectionListener; @@ -70,7 +76,7 @@ final class BooleanButtonModelBinding { // ********** constructor ********** /** - * Constructor - the boolean model and button are required. + * Constructor - the boolean <code>boolean</code> and button are required. */ BooleanButtonModelBinding(ModifiablePropertyValueModel<Boolean> booleanModel, Button button, boolean defaultValue) { super(); @@ -81,8 +87,8 @@ final class BooleanButtonModelBinding { this.button = button; this.defaultValue = defaultValue; - this.booleanChangeListener = this.buildBooleanChangeListener(); - this.booleanModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.booleanChangeListener); + this.booleanListener = this.buildBooleanListener(); + this.booleanModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.booleanListener); this.buttonSelectionListener = this.buildButtonSelectionListener(); this.button.addSelectionListener(this.buttonSelectionListener); @@ -96,45 +102,43 @@ final class BooleanButtonModelBinding { // ********** initialization ********** - private PropertyChangeListener buildBooleanChangeListener() { - return SWTListenerWrapperTools.wrap(this.buildBooleanChangeListener_(), this.button); + private PropertyChangeListener buildBooleanListener() { + return SWTListenerWrapperTools.wrap(new BooleanListener(), this.button); } - private PropertyChangeListener buildBooleanChangeListener_() { - return new PropertyChangeListener() { - public void propertyChanged(PropertyChangeEvent event) { - BooleanButtonModelBinding.this.booleanChanged(event); - } - @Override - public String toString() { - return "boolean listener"; - } - }; + /* CU private */ class BooleanListener + extends PropertyChangeAdapter + { + @Override + public void propertyChanged(PropertyChangeEvent event) { + BooleanButtonModelBinding.this.booleanChanged(event); + } } private SelectionListener buildButtonSelectionListener() { - return new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent event) { - BooleanButtonModelBinding.this.buttonSelected(); - } - @Override - public String toString() { - return "button selection listener"; - } - }; + return new ButtonSelectionListener(); + } + + /* CU private */ class ButtonSelectionListener + extends SelectionAdapter + { + @Override + public void widgetSelected(SelectionEvent event) { + BooleanButtonModelBinding.this.buttonSelected(); + } } private DisposeListener buildButtonDisposeListener() { - return new DisposeListener() { - public void widgetDisposed(DisposeEvent event) { - BooleanButtonModelBinding.this.buttonDisposed(); - } - @Override - public String toString() { - return "button dispose listener"; - } - }; + return new ButtonDisposeListener(); + } + + /* CU private */ class ButtonDisposeListener + extends DisposeAdapter + { + @Override + public void widgetDisposed(DisposeEvent event) { + BooleanButtonModelBinding.this.buttonDisposed(); + } } @@ -142,17 +146,17 @@ final class BooleanButtonModelBinding { /** * The model has changed - synchronize the button. - * If the new model value is null, use the binding's default value - * (which is typically false). + * If the new model value is <code>null</code>, use the binding's <em>default value</em> + * (which is typically <code>false</code>). */ /* CU private */ void booleanChanged(PropertyChangeEvent event) { - this.setButtonSelection((Boolean) event.getNewValue()); + if ( ! this.button.isDisposed()) { + this.setButtonSelection((Boolean) event.getNewValue()); + } } private void setButtonSelection(Boolean b) { - if ( ! this.button.isDisposed()) { - this.button.setSelection(this.booleanValue(b)); - } + this.button.setSelection(this.booleanValue(b)); } private boolean booleanValue(Boolean b) { @@ -166,9 +170,7 @@ final class BooleanButtonModelBinding { * The button has been "selected" - synchronize the model. */ /* CU private */ void buttonSelected() { - if ( ! this.button.isDisposed()) { - this.booleanModel.setValue(Boolean.valueOf(this.button.getSelection())); - } + this.booleanModel.setValue(Boolean.valueOf(this.button.getSelection())); } /* CU private */ void buttonDisposed() { @@ -176,7 +178,7 @@ final class BooleanButtonModelBinding { // so we can still remove our listeners this.button.removeSelectionListener(this.buttonSelectionListener); this.button.removeDisposeListener(this.buttonDisposeListener); - this.booleanModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.booleanChangeListener); + this.booleanModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.booleanListener); } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/BooleanStateController.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/BooleanControlStateModelBinding.java index 1ff4f87c7a..675a86e4cc 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/BooleanStateController.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/BooleanControlStateModelBinding.java @@ -11,9 +11,7 @@ package org.eclipse.jpt.common.ui.internal.swt.bindings; import org.eclipse.jpt.common.ui.internal.listeners.SWTListenerWrapperTools; import org.eclipse.jpt.common.ui.internal.swt.events.DisposeAdapter; -import org.eclipse.jpt.common.ui.internal.swt.widgets.DisplayTools; import org.eclipse.jpt.common.utility.internal.ObjectTools; -import org.eclipse.jpt.common.utility.internal.RunnableAdapter; 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; @@ -23,85 +21,88 @@ import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.widgets.Control; /** - * This controller enables a boolean model to control either the + * This binding enables a <code>boolean</code> model to control either the * <em>enabled</em> or <em>visible</em> properties of SWT controls; i.e. the - * controls' properties are kept in synch with the boolean model, + * controls' properties are kept in sync with the <code>boolean</code> model, * but <em>not</em> vice-versa. * <p> * Subclasses must manage the listeners; i.e. the engaging and disengaging of - * the boolean model and the control(s). + * the <code>boolean</code> model and the control(s). + * + * @param <C> the type of the control * * @see PropertyValueModel * @see Control#setEnabled(boolean) * @see Control#setVisible(boolean) */ -abstract class BooleanStateController { +abstract class BooleanControlStateModelBinding<C extends Control> { /** - * The controlling boolean model. + * The controlling <code>boolean</code> model. */ private final PropertyValueModel<Boolean> booleanModel; /** * A listener that allows us to synchronize the control states with - * changes in the value of the boolean model. + * changes in the value of the <code>boolean</code> model. */ - private final PropertyChangeListener booleanChangeListener; + private final PropertyChangeListener booleanListener; /** - * A listener that allows us to stop listening to stuff when all the - * controls are disposed. (Critical for preventing memory leaks.) + * Cache the <code>boolean</code> value. */ - private final DisposeListener controlDisposeListener; + boolean booleanValue; /** - * The default setting for the state; for when the underlying boolean model is - * <code>null</code>. The default [default value] is <code>false<code>. + * The default setting for the state; for when the underlying + * <code>boolean</code> model is <code>null</code>. + * The default [default value] is <code>false<code>. */ private final boolean defaultValue; /** - * The adapter determines whether the 'enabled' or 'visible' property is - * controlled. + * The adapter determines whether the <em>enabled</em> or <em>visible</em> + * property is controlled. */ - private final Adapter adapter; + private final Adapter<C> adapter; + /** + * A listener that allows us to stop listening to stuff when all the + * controls are disposed. (Critical for preventing memory leaks.) + */ + private final DisposeListener controlDisposeListener; - // ********** constructor ********** /** - * Constructor - the boolean model and the adapter are required. + * Constructor - the <code>boolean</code> model and the adapter are required. */ - BooleanStateController(PropertyValueModel<Boolean> booleanModel, boolean defaultValue, Adapter adapter) { + BooleanControlStateModelBinding(PropertyValueModel<Boolean> booleanModel, boolean defaultValue, Adapter<C> adapter) { super(); if ((booleanModel == null) || (adapter == null)) { throw new NullPointerException(); } this.booleanModel = booleanModel; this.defaultValue = defaultValue; + this.booleanValue = this.booleanValue(null); this.adapter = adapter; - this.booleanChangeListener = this.buildBooleanChangeListener(); + this.booleanListener = this.buildBooleanListener(); this.controlDisposeListener = this.buildControlDisposeListener(); } // ********** initialization ********** - private PropertyChangeListener buildBooleanChangeListener() { - return SWTListenerWrapperTools.wrap(this.buildBooleanChangeListener_()); - } - - private PropertyChangeListener buildBooleanChangeListener_() { - return new BooleanChangeListener(); + private PropertyChangeListener buildBooleanListener() { + return SWTListenerWrapperTools.wrap(new BooleanListener()); } - /* CU private */ class BooleanChangeListener + /* CU private */ class BooleanListener extends PropertyChangeAdapter { @Override public void propertyChanged(PropertyChangeEvent event) { - BooleanStateController.this.booleanChanged(event); + BooleanControlStateModelBinding.this.booleanChanged(event); } } @@ -116,7 +117,9 @@ abstract class BooleanStateController { public void widgetDisposed(DisposeEvent event) { // the control is not yet "disposed" when we receive this event // so we can still remove our listener - BooleanStateController.this.controlDisposed((Control) event.widget); + @SuppressWarnings("unchecked") + C control = (C) event.widget; + BooleanControlStateModelBinding.this.controlDisposed(control); } } @@ -124,25 +127,29 @@ abstract class BooleanStateController { // ********** boolean model ********** void engageBooleanModel() { - this.booleanModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.booleanChangeListener); + this.booleanModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.booleanListener); + this.booleanValue = this.booleanValue(this.booleanModel.getValue()); } void disengageBooleanModel() { - this.booleanModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.booleanChangeListener); + this.booleanModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.booleanListener); + this.booleanValue = this.booleanValue(null); } /** - * The boolean model has changed - synchronize the controls. - * If the new boolean model value is <code>null</code>, use the controller's - * default value (which is typically false). + * The <code>boolean</code> model has changed - synchronize the controls. + * If the new <code>boolean</code> model value is <code>null</code>, use + * the controller's default value (which is typically <code>false</code>). */ /* CU private */ void booleanChanged(PropertyChangeEvent event) { - this.setControlState((Boolean) event.getNewValue()); + if ( ! this.controlIsDisposed()) { + this.booleanChanged((Boolean) event.getNewValue()); + } } - - boolean getBooleanValue() { - return this.booleanValue(this.booleanModel.getValue()); + private void booleanChanged(Boolean b) { + this.booleanValue = this.booleanValue(b); + this.setControlState(); } private boolean booleanValue(Boolean b) { @@ -152,53 +159,35 @@ abstract class BooleanStateController { // ********** control ********** - void engageControl(Control control) { + void engageControl(C control) { control.addDisposeListener(this.controlDisposeListener); } - void disengageControl(Control control) { + void disengageControl(C control) { control.removeDisposeListener(this.controlDisposeListener); } - private void setControlState(Boolean controlState) { - this.setControlState(this.booleanValue(controlState)); - } - - abstract void setControlState(boolean controlState); - - void setControlState(Control control, boolean controlState) { - DisplayTools.execute(new SetControlStateRunnable(control, controlState)); - } - - /* CU private */ class SetControlStateRunnable - extends RunnableAdapter - { - private final Control control; - private final boolean controlState; - SetControlStateRunnable(Control control, boolean controlState) { - super(); - this.control = control; - this.controlState = controlState; - } - @Override - public void run() { - BooleanStateController.this.setControlState_(this.control, this.controlState); - } - } + /** + * Set the state of the control(s). + * @see #setControlState(Control) + */ + abstract void setControlState(); - /* CU private */ void setControlState_(Control control, boolean controlState) { + void setControlState(C control) { if ( ! control.isDisposed()) { - this.adapter.setState(control, controlState); + this.adapter.setState(control, this.booleanValue); } } - void controlDisposed(Control control) { + void controlDisposed(C control) { this.disengageControl(control); } // ********** misc ********** + abstract boolean controlIsDisposed(); + @Override public String toString() { return ObjectTools.toString(this, this.booleanModel); @@ -207,7 +196,7 @@ abstract class BooleanStateController { // ********** adapter interface ********** - interface Adapter { - void setState(Control control, boolean controlState); + interface Adapter<C extends Control> { + void setState(C control, boolean controlState); } } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/CompositeBooleanControlStateModelBinding.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/CompositeBooleanControlStateModelBinding.java new file mode 100644 index 0000000000..f016ea30fc --- /dev/null +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/CompositeBooleanControlStateModelBinding.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2009, 2013 Oracle. 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: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.common.ui.internal.swt.bindings; + +import java.util.HashSet; +import org.eclipse.jpt.common.utility.model.value.PropertyValueModel; +import org.eclipse.swt.widgets.Control; + +/** + * This controller enables a <code>boolean</code> model to control either the + * <em>enabled</em> or <em>visible</em> properties of a set of SWT controls; + * i.e. the controls' properties are kept in sync with the <code>boolean</code> + * model, but <em>not</em> vice-versa. + * <p> + * Once all the controls are disposed, this controller is kaput. + * <p> + * <strong>NB:</strong> This controller assumes all the controls will be, + * effectively, disposed at the same time. + * + * @see PropertyValueModel + * @see Control#setEnabled(boolean) + * @see Control#setVisible(boolean) + */ +final class CompositeBooleanControlStateModelBinding<C extends Control> + extends BooleanControlStateModelBinding<C> +{ + private final HashSet<C> controls = new HashSet<C>(); + + + /** + * Constructor - the <code>boolean</code> model, the set of controls, + * and the adapter are required. + */ + CompositeBooleanControlStateModelBinding( + PropertyValueModel<Boolean> booleanModel, + Iterable<C> controls, + boolean defaultValue, + Adapter<C> adapter + ) { + super(booleanModel, defaultValue, adapter); + if (controls == null) { + throw new NullPointerException(); + } + for (C control : controls) { + if (control == null) { + throw new NullPointerException(); + } + if ( ! this.controls.add(control)) { + throw new IllegalArgumentException("duplicate control: " + control); //$NON-NLS-1$ + } + } + if (this.controls.isEmpty()) { + throw new IllegalArgumentException("no controls"); //$NON-NLS-1$ + } + this.engageBooleanModel(); + for (C control : this.controls) { + this.engageControl(control); + } + this.setControlState(); + } + + + @Override + void setControlState() { + for (C control : this.controls) { + this.setControlState(control); + } + } + + @Override + void controlDisposed(C control) { + super.controlDisposed(control); + this.controls.remove(control); + if (this.controls.isEmpty()) { + this.disengageBooleanModel(); + } + } + + @Override + boolean controlIsDisposed() { + for (C control : this.controls) { + if (control.isDisposed()) { + return true; + } + } + return false; + } +} diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/DropDownListBoxSelectionBinding.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/DropDownListBoxSelectionBinding.java index 6cce0fea22..fc4a77cdce 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/DropDownListBoxSelectionBinding.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/DropDownListBoxSelectionBinding.java @@ -9,32 +9,37 @@ ******************************************************************************/ package org.eclipse.jpt.common.ui.internal.swt.bindings; +import java.util.ArrayList; import org.eclipse.jpt.common.ui.internal.listeners.SWTListenerWrapperTools; +import org.eclipse.jpt.common.ui.internal.swt.events.SelectionAdapter; import org.eclipse.jpt.common.utility.internal.ObjectTools; 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.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.widgets.Display; /** * This binding can be used to keep a drop-down list box's selection - * synchronized with a model. The selection can be modified by either the - * drop-down list box or the model, so changes must be coordinated. + * synchronized with a model. * <p> - * <strong>NB:</strong> A selected item value of <code>null</code> can be used + * <strong>NB:</strong> This binding is bi-directional. + * <p> + * <strong>NB2:</strong> A selected item value of <code>null</code> can be used * to clear the drop-down list box's selection. If <code>null</code> is a * valid item in the model list, an invalid selected item can be used to clear * the selection. + * <p> + * <strong>NB3:</strong> See the class comment for + * {@link ListBoxSelectionBinding}. * - * @see ListValueModel * @see ModifiablePropertyValueModel * @see DropDownListBox * @see SWTBindingTools */ -@SuppressWarnings("nls") final class DropDownListBoxSelectionBinding<E> implements ListWidgetModelBinding.SelectionBinding { @@ -42,18 +47,23 @@ final class DropDownListBoxSelectionBinding<E> /** * The underlying list model. */ - private final ListValueModel<E> listModel; + private final ArrayList<E> list; /** - * A writable value model on the underlying model selection. + * A modifiable value model on the underlying model selection. */ private final ModifiablePropertyValueModel<E> selectedItemModel; /** + * Cache of model selection. + */ + private E selectedItem; + + /** * A listener that allows us to synchronize the drop-down list box's * selection with the model selection. */ - private final PropertyChangeListener selectedItemChangeListener; + private final PropertyChangeListener selectedItemListener; // ***** UI /** @@ -63,91 +73,94 @@ final class DropDownListBoxSelectionBinding<E> private final DropDownListBox dropdownListBox; /** - * A listener that allows us to synchronize our selected item holder + * A listener that allows us to synchronize our selected item model * with the drop-down list box's selection. */ private final SelectionListener dropdownListBoxSelectionListener; - // ********** constructor ********** - /** * Constructor - all parameters are required. */ DropDownListBoxSelectionBinding( - ListValueModel<E> listModel, + ArrayList<E> list, ModifiablePropertyValueModel<E> selectedItemModel, DropDownListBox dropdownListBox ) { super(); - if ((listModel == null) || (selectedItemModel == null) || (dropdownListBox == null)) { + if ((list == null) || (selectedItemModel == null) || (dropdownListBox == null)) { throw new NullPointerException(); } - this.listModel = listModel; + this.list = list; this.selectedItemModel = selectedItemModel; this.dropdownListBox = dropdownListBox; - this.selectedItemChangeListener = this.buildSelectedItemChangeListener(); - this.selectedItemModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.selectedItemChangeListener); + this.selectedItemListener = this.buildSelectedItemListener(); + this.selectedItemModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.selectedItemListener); this.dropdownListBoxSelectionListener = this.buildDropDownListBoxSelectionListener(); this.dropdownListBox.addSelectionListener(this.dropdownListBoxSelectionListener); + + this.selectedItem = this.selectedItemModel.getValue(); } // ********** initialization ********** - private PropertyChangeListener buildSelectedItemChangeListener() { - return SWTListenerWrapperTools.wrap(this.buildSelectedItemChangeListener_()); + private PropertyChangeListener buildSelectedItemListener() { + return SWTListenerWrapperTools.wrap(new SelectedItemListener(), this.dropdownListBox.getDisplay()); } - private PropertyChangeListener buildSelectedItemChangeListener_() { - return new PropertyChangeListener() { - public void propertyChanged(PropertyChangeEvent event) { - DropDownListBoxSelectionBinding.this.selectedItemChanged(event); - } - @Override - public String toString() { - return "selected item listener"; - } - }; + /* CU private */ class SelectedItemListener + extends PropertyChangeAdapter + { + @Override + public void propertyChanged(PropertyChangeEvent event) { + DropDownListBoxSelectionBinding.this.selectedItemChanged(event); + } } private SelectionListener buildDropDownListBoxSelectionListener() { - return new SelectionListener() { - public void widgetSelected(SelectionEvent event) { - DropDownListBoxSelectionBinding.this.dropDownListBoxSelectionChanged(event); - } - public void widgetDefaultSelected(SelectionEvent event) { - DropDownListBoxSelectionBinding.this.dropDownListBoxDoubleClicked(event); - } - @Override - public String toString() { - return "drop-down list box selection listener"; - } - }; + return new DropDownListBoxSelectionListener(); + } + + /* CU private */ class DropDownListBoxSelectionListener + extends SelectionAdapter + { + @Override + public void widgetSelected(SelectionEvent event) { + DropDownListBoxSelectionBinding.this.dropDownListBoxSelectionChanged(); + } + @Override + public void widgetDefaultSelected(SelectionEvent event) { + DropDownListBoxSelectionBinding.this.dropDownListBoxDoubleClicked(); + } } // ********** ListWidgetModelBinding.SelectionBinding implementation ********** /** - * Modifying the drop-down lisb box's selected item programmatically does - * not trigger a SelectionEvent. + * <strong>NB:</strong> The elements in the selection model may be out of + * sync with the underlying list model. (See the class comment.) + * <p> + * Modifying the drop-down list box's selected item programmatically does + * not trigger a {@link SelectionEvent}. * <p> * Pre-condition: The drop-down list box is not disposed. */ public void synchronizeListWidgetSelection() { int oldIndex = this.dropdownListBox.getSelectionIndex(); - E value = this.selectedItemModel.getValue(); - int newIndex = this.indexOf(value); - if ((oldIndex != -1) && (newIndex != -1) && (newIndex != oldIndex)) { - this.dropdownListBox.deselect(oldIndex); - } + int newIndex = this.indexOf(this.selectedItem); if (newIndex == -1) { - this.dropdownListBox.deselectAll(); + if (oldIndex != -1) { + this.dropdownListBox.deselectAll(); + } } else { if (newIndex != oldIndex) { + if (oldIndex != -1) { + this.dropdownListBox.deselect(oldIndex); + } this.dropdownListBox.select(newIndex); } } @@ -155,7 +168,8 @@ final class DropDownListBoxSelectionBinding<E> public void dispose() { this.dropdownListBox.removeSelectionListener(this.dropdownListBoxSelectionListener); - this.selectedItemModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.selectedItemChangeListener); + this.selectedItemModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.selectedItemListener); + this.selectedItem = null; } @@ -169,60 +183,44 @@ final class DropDownListBoxSelectionBinding<E> /** * Modifying the drop-down list box's selected item programmatically does - * not trigger a SelectionEvent. + * not trigger a {@link SelectionEvent}. */ - private void selectedItemChanged_(@SuppressWarnings("unused") PropertyChangeEvent event) { + private void selectedItemChanged_(PropertyChangeEvent event) { + @SuppressWarnings("unchecked") + E item = (E) event.getNewValue(); + this.selectedItem = item; this.synchronizeListWidgetSelection(); } + /** + * <strong>NB:</strong> an index of <code>-1</code> is ignored by + * {@link org.eclipse.swt.widgets.Combo} (lucky for us). + */ private int indexOf(E item) { - int len = this.listModel.size(); - for (int i = 0; i < len; i++) { - if (ObjectTools.equals(this.listModel.get(i), item)) { + int i = 0; + for (E each : this.list) { + if (ObjectTools.equals(each, item)) { return i; } + i++; } - // if 'null' is not in the list, use it to clear the selection - if (item == null) { - return -1; - } - // We can get here via one of the following: - // 1. The selected item model is invalid and not in sync with the list - // model. This is not good and we don't make this (programming - // error) obvious (e.g. via an exception). :-( - // 2. If both the selected item model and the list model are dependent - // on the same underlying model, the selected item model may receive - // its event first, resulting in a missing item. This will resolve - // itself once the list model receives its event and synchronizes - // with the same underlying model. This situation is acceptable. return -1; - -// This is what we used to do: -// throw new IllegalStateException("selected item not found: " + item); } // ********** combo-box events ********** - void dropDownListBoxSelectionChanged(SelectionEvent event) { - if ( ! this.dropdownListBox.isDisposed()) { - this.dropDownListBoxSelectionChanged_(event); - } - } - - void dropDownListBoxDoubleClicked(SelectionEvent event) { - if ( ! this.dropdownListBox.isDisposed()) { - this.dropDownListBoxSelectionChanged_(event); - } + void dropDownListBoxSelectionChanged() { + this.selectedItemModel.setValue(this.getDropDownListBoxSelectedItem()); } - private void dropDownListBoxSelectionChanged_(@SuppressWarnings("unused") SelectionEvent event) { - this.selectedItemModel.setValue(this.getDropDownListBoxSelectedItem()); + void dropDownListBoxDoubleClicked() { + this.dropDownListBoxSelectionChanged(); } private E getDropDownListBoxSelectedItem() { - int selectionIndex = this.dropdownListBox.getSelectionIndex(); - return (selectionIndex == -1) ? null : this.listModel.get(selectionIndex); + int index = this.dropdownListBox.getSelectionIndex(); + return (index == -1) ? null : this.list.get(index); } @@ -230,7 +228,7 @@ final class DropDownListBoxSelectionBinding<E> @Override public String toString() { - return ObjectTools.toString(this, this.selectedItemModel); + return ObjectTools.toString(this, this.selectedItem); } @@ -241,39 +239,43 @@ final class DropDownListBoxSelectionBinding<E> * the drop-down list box. */ interface DropDownListBox { + /** + * Return the list widget's display. + */ + Display getDisplay(); /** - * Return whether the combo-box is "disposed". + * Return whether the drop-down list box is <em>disposed</em>. */ boolean isDisposed(); /** - * Add the specified selection listener to the combo-box. + * Add the specified selection listener to the drop-down list box. */ void addSelectionListener(SelectionListener listener); /** - * Remove the specified selection listener from the combo-box. + * Remove the specified selection listener from the drop-down list box. */ void removeSelectionListener(SelectionListener listener); /** - * Return the index of the combo-box's selection. + * Return the index of the drop-down list box's selection. */ int getSelectionIndex(); /** - * Select the item at the specified index in the combo-box. + * Select the item at the specified index in the drop-down list box. */ void select(int index); /** - * Deselect the item at the specified index in the combo-box. + * Deselect the item at the specified index in the drop-down list box. */ void deselect(int index); /** - * Clear the combo-box's selection. + * Clear the drop-down list box's selection. */ void deselectAll(); } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/HyperlinkLabelAdapter.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/HyperlinkLabelAdapter.java index 5d7c4afea8..4652c40cd6 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/HyperlinkLabelAdapter.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/HyperlinkLabelAdapter.java @@ -24,7 +24,7 @@ final class HyperlinkLabelAdapter } @Override - public void setImage_(Image image) { + protected void setImage_(Image image) { // NOP } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/LabelModelBinding.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/LabelModelBinding.java index 9e55afb306..5a913ae7d6 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/LabelModelBinding.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/LabelModelBinding.java @@ -24,7 +24,7 @@ import org.eclipse.swt.widgets.Widget; /** * This binding can be used to keep a <em>label</em> - * synchronized with a image and text models. + * synchronized with image and text models. * * @see PropertyValueModel * @see WidgetLabelAdapter @@ -97,7 +97,7 @@ class LabelModelBinding { { @Override public void propertyChanged(PropertyChangeEvent event) { - LabelModelBinding.this.setImage((Image) event.getNewValue()); + LabelModelBinding.this.imageChanged(event); } } @@ -110,7 +110,7 @@ class LabelModelBinding { { @Override public void propertyChanged(PropertyChangeEvent event) { - LabelModelBinding.this.setText((String) event.getNewValue()); + LabelModelBinding.this.textChanged(event); } } @@ -130,18 +130,26 @@ class LabelModelBinding { // ********** model events ********** - /* CU private */ void setImage(Image image) { + /* CU private */ void imageChanged(PropertyChangeEvent event) { if ( ! this.getWidget().isDisposed()) { - this.labelAdapter.setImage(image); + this.setImage((Image) event.getNewValue()); } } - /* CU private */ void setText(String text) { + private void setImage(Image image) { + this.labelAdapter.setImage(image); + } + + /* CU private */ void textChanged(PropertyChangeEvent event) { if ( ! this.getWidget().isDisposed()) { - this.labelAdapter.setText((text != null) ? text : StringTools.EMPTY_STRING); + this.setText((String) event.getNewValue()); } } + private void setText(String text) { + this.labelAdapter.setText((text != null) ? text : StringTools.EMPTY_STRING); + } + private Widget getWidget() { return this.labelAdapter.getWidget(); } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/LinkLabelAdapter.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/LinkLabelAdapter.java index 1e60c8ce39..db9feb3e5e 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/LinkLabelAdapter.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/LinkLabelAdapter.java @@ -24,7 +24,7 @@ final class LinkLabelAdapter } @Override - public void setImage_(Image image) { + protected void setImage_(Image image) { // NOP } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/ListBoxSelectionBinding.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/ListBoxSelectionBinding.java index cf2a4fb355..acbed4ba42 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/ListBoxSelectionBinding.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/ListBoxSelectionBinding.java @@ -12,15 +12,17 @@ package org.eclipse.jpt.common.ui.internal.swt.bindings; import java.util.ArrayList; import java.util.Arrays; import org.eclipse.jpt.common.ui.internal.listeners.SWTListenerWrapperTools; +import org.eclipse.jpt.common.ui.internal.swt.events.SelectionAdapter; import org.eclipse.jpt.common.utility.internal.ArrayTools; import org.eclipse.jpt.common.utility.internal.ObjectTools; +import org.eclipse.jpt.common.utility.internal.collection.CollectionTools; import org.eclipse.jpt.common.utility.model.event.CollectionAddEvent; import org.eclipse.jpt.common.utility.model.event.CollectionChangeEvent; import org.eclipse.jpt.common.utility.model.event.CollectionClearEvent; import org.eclipse.jpt.common.utility.model.event.CollectionRemoveEvent; +import org.eclipse.jpt.common.utility.model.listener.CollectionChangeAdapter; import org.eclipse.jpt.common.utility.model.listener.CollectionChangeListener; import org.eclipse.jpt.common.utility.model.value.CollectionValueModel; -import org.eclipse.jpt.common.utility.model.value.ListValueModel; import org.eclipse.jpt.common.utility.model.value.ModifiableCollectionValueModel; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; @@ -28,139 +30,181 @@ import org.eclipse.swt.widgets.List; /** * This binding can be used to keep a list box's selection - * synchronized with a model. The selection can be modified by either the list - * box or the model, so changes must be coordinated. + * synchronized with a model. + * <p> + * <strong>NB:</strong> This binding is bi-directional. As a result, we modify + * our {@link #selectedItems cached list} <em>only</em> via + * the {@link #selectedItemsModel model collection} change events; + * and we {@link #listBoxSelectionChanged() simply pass through} the list box + * selection events (by calling + * {@link ModifiableCollectionValueModel#setValues(Iterable)}, + * which will loop back to us as a collection change event). + * <p> + * <strong>NB2:</strong> Changes to the underlying list model can imply changes + * to the selection collection model. But these changes occur + * <em>asynchronously</em> (as do their resulting events). + * If the models are designed correctly, the selection model will be modified, + * if necessary, whenever the underlying list model changes + * (typically when elements are removed from the underlying list model). + * But <em>all</em> changes to the underlying list model can cause changes to + * the <em>indices</em> of the selected items; so all changes to the underlying + * list model result in calls to {@link #synchronizeListWidgetSelection()}. + * Unfortunately, since the <em>selection</em> change event might not have + * arrived yet, the selection item list can contain elements that are not in + * the underlying list. So we must gracefully handle missing elements, even + * though this may hide coding errors (i.e. something that should <em>not</em> + * happen and should trigger an exception). Likewise, we can receive + * <em>selection</em> change events before the underlying list model is updated, + * resulting, again, in temporarily invalid state (which will be rectified once + * the underlying list model is updated and the binding calls + * {@link #synchronizeListWidgetSelection()}). * - * @see ListValueModel * @see ModifiableCollectionValueModel * @see List * @see SWTBindingTools */ -@SuppressWarnings("nls") final class ListBoxSelectionBinding<E> implements ListWidgetModelBinding.SelectionBinding { // ***** model /** - * The underlying list model. + * The underlying list (maintained by {@link ListWidgetModelBinding}). */ - private final ListValueModel<E> listModel; + private final ArrayList<E> list; /** - * A writable value model on the underlying model selections. + * A modifiable value model on the underlying model selections. */ private final ModifiableCollectionValueModel<E> selectedItemsModel; /** + * Cache of model selections. + */ + private final ArrayList<E> selectedItems = new ArrayList<E>(); + + /** * A listener that allows us to synchronize the list box's selection with * the model selections. */ - private final CollectionChangeListener selectedItemsChangeListener; + private final CollectionChangeListener selectedItemsListener; // ***** UI /** - * The list box whose selection we keep synchronized with the model selections. + * The list box whose selection we keep synchronized + * with the model selections. */ private final List listBox; /** - * A listener that allows us to synchronize our selected items holder + * A listener that allows us to synchronize our selected items model * with the list box's selection. */ private final SelectionListener listBoxSelectionListener; - // ********** constructor ********** - /** * Constructor - all parameters are required. */ ListBoxSelectionBinding( - ListValueModel<E> listModel, + ArrayList<E> list, ModifiableCollectionValueModel<E> selectedItemsModel, List listBox ) { super(); - if ((listModel == null) || (selectedItemsModel == null) || (listBox == null)) { + if ((list == null) || (selectedItemsModel == null) || (listBox == null)) { throw new NullPointerException(); } - this.listModel = listModel; + this.list = list; this.selectedItemsModel = selectedItemsModel; this.listBox = listBox; - this.selectedItemsChangeListener = this.buildSelectedItemsChangeListener(); - this.selectedItemsModel.addCollectionChangeListener(CollectionValueModel.VALUES, this.selectedItemsChangeListener); + this.selectedItemsListener = this.buildSelectedItemsListener(); + this.selectedItemsModel.addCollectionChangeListener(CollectionValueModel.VALUES, this.selectedItemsListener); this.listBoxSelectionListener = this.buildListBoxSelectionListener(); this.listBox.addSelectionListener(this.listBoxSelectionListener); + + this.selectedItems.ensureCapacity(this.selectedItemsModel.size()); + CollectionTools.addAll(this.selectedItems, this.selectedItemsModel); } // ********** initialization ********** - private CollectionChangeListener buildSelectedItemsChangeListener() { - return SWTListenerWrapperTools.wrap(this.buildSelectedItemsChangeListener_(), this.listBox); + private CollectionChangeListener buildSelectedItemsListener() { + return SWTListenerWrapperTools.wrap(new SelectedItemsListener(), this.listBox); } - private CollectionChangeListener buildSelectedItemsChangeListener_() { - return new CollectionChangeListener() { - public void itemsAdded(CollectionAddEvent event) { - ListBoxSelectionBinding.this.selectedItemsAdded(event); - } - public void itemsRemoved(CollectionRemoveEvent event) { - ListBoxSelectionBinding.this.selectedItemsRemoved(event); - } - public void collectionCleared(CollectionClearEvent event) { - ListBoxSelectionBinding.this.selectedItemsCleared(event); - } - public void collectionChanged(CollectionChangeEvent event) { - ListBoxSelectionBinding.this.selectedItemsChanged(event); - } - @Override - public String toString() { - return "selected items listener"; - } - }; + /* CU private */ class SelectedItemsListener + extends CollectionChangeAdapter + { + @Override + public void itemsAdded(CollectionAddEvent event) { + ListBoxSelectionBinding.this.selectedItemsAdded(event); + } + @Override + public void itemsRemoved(CollectionRemoveEvent event) { + ListBoxSelectionBinding.this.selectedItemsRemoved(event); + } + @Override + public void collectionCleared(CollectionClearEvent event) { + ListBoxSelectionBinding.this.selectedItemsCleared(); + } + @Override + public void collectionChanged(CollectionChangeEvent event) { + ListBoxSelectionBinding.this.selectedItemsChanged(event); + } } private SelectionListener buildListBoxSelectionListener() { - return new SelectionListener() { - public void widgetSelected(SelectionEvent event) { - ListBoxSelectionBinding.this.listBoxSelectionChanged(event); - } - public void widgetDefaultSelected(SelectionEvent event) { - ListBoxSelectionBinding.this.listBoxDoubleClicked(event); - } - @Override - public String toString() { - return "list box selection listener"; - } - }; + return new ListBoxSelectionListener(); + } + + /* CU private */ class ListBoxSelectionListener + extends SelectionAdapter + { + @Override + public void widgetSelected(SelectionEvent event) { + ListBoxSelectionBinding.this.listBoxSelectionChanged(); + } + @Override + public void widgetDefaultSelected(SelectionEvent event) { + ListBoxSelectionBinding.this.listBoxDoubleClicked(); + } } // ********** ListWidgetModelBinding.SelectionBinding implementation ********** /** + * <strong>NB:</strong> The elements in the selection model may be out of + * sync with the underlying list model. (See the class comment.) + * <p> * Modifying the list box's selected items programmatically does not - * trigger a SelectionEvent. - * + * trigger a {@link SelectionEvent}. + * <p> * Pre-condition: The list-box is not disposed. */ public void synchronizeListWidgetSelection() { - int selectedItemsSize = this.selectedItemsModel.size(); - int[] select = new int[selectedItemsSize]; - int i = 0; - for (E item : this.selectedItemsModel) { - select[i++] = this.indexOf(item); + int selectedItemsSize = this.selectedItems.size(); + int[] select = ArrayTools.EMPTY_INT_ARRAY; + if (selectedItemsSize > 0) { + select = new int[selectedItemsSize]; + int i = 0; + for (E item : this.selectedItems) { + select[i++] = this.indexOf(item); + } } - int listSize = this.listModel.size(); - int[] deselect = new int[listSize - selectedItemsSize]; - i = 0; - for (int j = 0; j < listSize; j++) { - if ( ! ArrayTools.contains(select, j)) { - deselect[i++] = j; + int listSize = this.list.size(); + int[] deselect = ArrayTools.EMPTY_INT_ARRAY; + if (listSize > 0) { + deselect = ArrayTools.fill(new int[listSize], -1); + int i = 0; + for (int j = 0; j < listSize; j++) { + if ( ! ArrayTools.contains(select, j)) { + deselect[i++] = j; + } } } @@ -174,13 +218,14 @@ final class ListBoxSelectionBinding<E> public void dispose() { this.listBox.removeSelectionListener(this.listBoxSelectionListener); - this.selectedItemsModel.removeCollectionChangeListener(CollectionValueModel.VALUES, this.selectedItemsChangeListener); + this.selectedItemsModel.removeCollectionChangeListener(CollectionValueModel.VALUES, this.selectedItemsListener); + this.selectedItems.clear(); } // ********** selected items ********** - void selectedItemsAdded(CollectionAddEvent event) { + /* CU private */ void selectedItemsAdded(CollectionAddEvent event) { if ( ! this.listBox.isDisposed()) { this.selectedItemsAdded_(event); } @@ -188,24 +233,23 @@ final class ListBoxSelectionBinding<E> /** * Modifying the list box's selected items programmatically does not - * trigger a SelectionEvent. + * trigger a {@link SelectionEvent}. */ private void selectedItemsAdded_(CollectionAddEvent event) { + @SuppressWarnings("unchecked") + Iterable<E> items = (Iterable<E>) event.getItems(); + this.selectedItems.ensureCapacity(this.selectedItems.size() + event.getItemsSize()); + CollectionTools.addAll(this.selectedItems, items); + int[] indices = new int[event.getItemsSize()]; int i = 0; - for (E item : this.getItems(event)) { + for (E item : items) { indices[i++] = this.indexOf(item); } this.listBox.select(indices); } - // minimized scope of suppressed warnings - @SuppressWarnings("unchecked") - private Iterable<E> getItems(CollectionAddEvent event) { - return (Iterable<E>) event.getItems(); - } - - void selectedItemsRemoved(CollectionRemoveEvent event) { + /* CU private */ void selectedItemsRemoved(CollectionRemoveEvent event) { if ( ! this.listBox.isDisposed()) { this.selectedItemsRemoved_(event); } @@ -213,83 +257,83 @@ final class ListBoxSelectionBinding<E> /** * Modifying the list box's selected items programmatically does not - * trigger a SelectionEvent. + * trigger a {@link SelectionEvent}. */ private void selectedItemsRemoved_(CollectionRemoveEvent event) { + @SuppressWarnings("unchecked") + Iterable<E> items = (Iterable<E>) event.getItems(); + CollectionTools.removeAll(this.selectedItems, items); + int[] indices = new int[event.getItemsSize()]; int i = 0; - for (E item : this.getItems(event)) { + for (E item : items) { indices[i++] = this.indexOf(item); } this.listBox.deselect(indices); } - // minimized scope of suppressed warnings - @SuppressWarnings("unchecked") - private Iterable<E> getItems(CollectionRemoveEvent event) { - return (Iterable<E>) event.getItems(); - } - - void selectedItemsCleared(CollectionClearEvent event) { + /* CU private */ void selectedItemsCleared() { if ( ! this.listBox.isDisposed()) { - this.selectedItemsCleared_(event); + this.selectedItemsCleared_(); } } /** * Modifying the list box's selected items programmatically does not - * trigger a SelectionEvent. + * trigger a {@link SelectionEvent}. */ - private void selectedItemsCleared_(@SuppressWarnings("unused") CollectionClearEvent event) { + private void selectedItemsCleared_() { + this.selectedItems.clear(); this.listBox.deselectAll(); } - void selectedItemsChanged(CollectionChangeEvent event) { + /* CU private */ void selectedItemsChanged(CollectionChangeEvent event) { if ( ! this.listBox.isDisposed()) { this.selectedItemsChanged_(event); } } - private void selectedItemsChanged_(@SuppressWarnings("unused") CollectionChangeEvent event) { + private void selectedItemsChanged_(CollectionChangeEvent event) { + this.selectedItems.clear(); + this.selectedItems.ensureCapacity(event.getCollectionSize()); + @SuppressWarnings("unchecked") + Iterable<E> eventCollection = (Iterable<E>) event.getCollection(); + CollectionTools.addAll(this.selectedItems, eventCollection); this.synchronizeListWidgetSelection(); } + /** + * <strong>NB:</strong> an index of <code>-1</code> is ignored by + * {@link List} (lucky for us). + */ private int indexOf(E item) { - int len = this.listModel.size(); - for (int i = 0; i < len; i++) { - if (ObjectTools.equals(this.listModel.get(i), item)) { + int i = 0; + for (E each : this.list) { + if (ObjectTools.equals(each, item)) { return i; } + i++; } - // see comment in DropDownListBoxSelectionBinding.indexOf(E) return -1; } // ********** list box events ********** - void listBoxSelectionChanged(SelectionEvent event) { - if ( ! this.listBox.isDisposed()) { - this.listBoxSelectionChanged_(event); - } - } - - void listBoxDoubleClicked(SelectionEvent event) { - if ( ! this.listBox.isDisposed()) { - this.listBoxSelectionChanged_(event); - } + /* CU private */ void listBoxSelectionChanged() { + this.selectedItemsModel.setValues(this.getListBoxSelectedItems()); } - private void listBoxSelectionChanged_(@SuppressWarnings("unused") SelectionEvent event) { - this.selectedItemsModel.setValues(this.getListBoxSelectedItems()); + /* CU private */ void listBoxDoubleClicked() { + this.listBoxSelectionChanged(); } private Iterable<E> getListBoxSelectedItems() { - ArrayList<E> selectedItems = new ArrayList<E>(this.listBox.getSelectionCount()); + ArrayList<E> lbSelectedItems = new ArrayList<E>(this.listBox.getSelectionCount()); for (int selectionIndex : this.listBox.getSelectionIndices()) { - selectedItems.add(this.listModel.get(selectionIndex)); + lbSelectedItems.add(this.list.get(selectionIndex)); } - return selectedItems; + return lbSelectedItems; } @@ -297,6 +341,6 @@ final class ListBoxSelectionBinding<E> @Override public String toString() { - return ObjectTools.toString(this, this.selectedItemsModel); + return ObjectTools.toString(this, this.selectedItems); } } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/ListWidgetModelBinding.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/ListWidgetModelBinding.java index d4599d1c16..db992d4b24 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/ListWidgetModelBinding.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/ListWidgetModelBinding.java @@ -11,24 +11,31 @@ package org.eclipse.jpt.common.ui.internal.swt.bindings; import java.util.ArrayList; import org.eclipse.jpt.common.ui.internal.listeners.SWTListenerWrapperTools; +import org.eclipse.jpt.common.ui.internal.swt.events.DisposeAdapter; import org.eclipse.jpt.common.utility.internal.ArrayTools; import org.eclipse.jpt.common.utility.internal.ObjectTools; +import org.eclipse.jpt.common.utility.internal.collection.CollectionTools; +import org.eclipse.jpt.common.utility.internal.collection.ListTools; import org.eclipse.jpt.common.utility.model.event.ListAddEvent; import org.eclipse.jpt.common.utility.model.event.ListChangeEvent; import org.eclipse.jpt.common.utility.model.event.ListClearEvent; import org.eclipse.jpt.common.utility.model.event.ListMoveEvent; import org.eclipse.jpt.common.utility.model.event.ListRemoveEvent; import org.eclipse.jpt.common.utility.model.event.ListReplaceEvent; +import org.eclipse.jpt.common.utility.model.listener.ListChangeAdapter; import org.eclipse.jpt.common.utility.model.listener.ListChangeListener; import org.eclipse.jpt.common.utility.model.value.ListValueModel; import org.eclipse.jpt.common.utility.transformer.Transformer; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.widgets.Display; /** - * This binding can be used to keep a list widget's contents + * This binding can be used to keep a list widget's contents and selection * synchronized with a model. The list widget never alters * its contents directly; all changes are driven by the model. + * <p> + * <strong>NB:</strong> The selection binding is bi-directional. * * @see ListValueModel * @see Transformer @@ -36,7 +43,6 @@ import org.eclipse.swt.events.DisposeListener; * @see SelectionBinding * @see SWTBindingTools */ -@SuppressWarnings("nls") final class ListWidgetModelBinding<E> { // ***** model @@ -49,7 +55,12 @@ final class ListWidgetModelBinding<E> { * A listener that allows us to synchronize the list widget's contents with * the model list. */ - private final ListChangeListener listChangeListener; + private final ListChangeListener listListener; + + /** + * Cache of model list. Shared with the {@link #selectionBinding}. + */ + final ArrayList<E> list = new ArrayList<E>(); /** * A transformer that converts items in the model list @@ -59,9 +70,10 @@ final class ListWidgetModelBinding<E> { // ***** UI /** - * An adapter on the list widget we keep synchronized with the model list. + * An adapter on the SWT list widget we keep synchronized + * with the model list. */ - private final ListWidget listWidget; + private final ListWidget<E> listWidget; /** * A listener that allows us to stop listening to stuff when the list widget @@ -76,108 +88,106 @@ final class ListWidgetModelBinding<E> { private final SelectionBinding selectionBinding; - // ********** constructor ********** - /** * Constructor - all parameters are required. */ ListWidgetModelBinding( ListValueModel<E> listModel, - ListWidget listWidget, - Transformer<E, String> transformer, - SelectionBinding selectionBinding + Object selectionModel, + ListWidget<E> listWidget, + Transformer<E, String> transformer ) { super(); - if ((listModel == null) || (listWidget == null) || (transformer == null) || (selectionBinding == null)) { + if ((listModel == null) || (selectionModel == null) || (listWidget == null) || (transformer == null)) { throw new NullPointerException(); } this.listModel = listModel; this.listWidget = listWidget; this.transformer = transformer; - this.selectionBinding = selectionBinding; + this.selectionBinding = listWidget.buildSelectionBinding(this.list, selectionModel); - this.listChangeListener = this.buildListChangeListener(); - this.listModel.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener); + this.listListener = this.buildListListener(); + this.listModel.addListChangeListener(ListValueModel.LIST_VALUES, this.listListener); this.listWidgetDisposeListener = this.buildListWidgetDisposeListener(); this.listWidget.addDisposeListener(this.listWidgetDisposeListener); + this.list.ensureCapacity(this.listModel.size()); + CollectionTools.addAll(this.list, this.listModel); this.synchronizeListWidget(); } // ********** initialization ********** - private ListChangeListener buildListChangeListener() { - return SWTListenerWrapperTools.wrap(this.buildListChangeListener_()); + private ListChangeListener buildListListener() { + return SWTListenerWrapperTools.wrap(new ListListener(), this.listWidget.getDisplay()); } - private ListChangeListener buildListChangeListener_() { - return new ListChangeListener() { - public void itemsAdded(ListAddEvent event) { - ListWidgetModelBinding.this.listItemsAdded(event); - } - public void itemsRemoved(ListRemoveEvent event) { - ListWidgetModelBinding.this.listItemsRemoved(event); - } - public void itemsMoved(ListMoveEvent event) { - ListWidgetModelBinding.this.listItemsMoved(event); - } - public void itemsReplaced(ListReplaceEvent event) { - ListWidgetModelBinding.this.listItemsReplaced(event); - } - public void listCleared(ListClearEvent event) { - ListWidgetModelBinding.this.listCleared(event); - } - public void listChanged(ListChangeEvent event) { - ListWidgetModelBinding.this.listChanged(event); - } - @Override - public String toString() { - return "list listener"; - } - }; + /* CU private */ class ListListener + extends ListChangeAdapter + { + @Override + public void itemsAdded(ListAddEvent event) { + ListWidgetModelBinding.this.listItemsAdded(event); + } + @Override + public void itemsRemoved(ListRemoveEvent event) { + ListWidgetModelBinding.this.listItemsRemoved(event); + } + @Override + public void itemsMoved(ListMoveEvent event) { + ListWidgetModelBinding.this.listItemsMoved(event); + } + @Override + public void itemsReplaced(ListReplaceEvent event) { + ListWidgetModelBinding.this.listItemsReplaced(event); + } + @Override + public void listCleared(ListClearEvent event) { + ListWidgetModelBinding.this.listCleared(); + } + @Override + public void listChanged(ListChangeEvent event) { + ListWidgetModelBinding.this.listChanged(event); + } } private DisposeListener buildListWidgetDisposeListener() { - return new DisposeListener() { - public void widgetDisposed(DisposeEvent event) { - ListWidgetModelBinding.this.listWidgetDisposed(event); - } - @Override - public String toString() { - return "list widget dispose listener"; - } - }; + return new ListWidgetDisposeListener(); + } + + /* CU private */ class ListWidgetDisposeListener + extends DisposeAdapter + { + @Override + public void widgetDisposed(DisposeEvent event) { + ListWidgetModelBinding.this.listWidgetDisposed(); + } } // ********** list ********** /** - * Brute force synchronization of list widget with the model list. + * Brute force synchronization of list widget with the list. */ private void synchronizeListWidget() { - if ( ! this.listWidget.isDisposed()) { - this.synchronizeListWidget_(); + String[] items = new String[this.list.size()]; + int i = 0; + for (E item : this.list) { + items[i++] = this.transformer.transform(item); } - } + this.listWidget.setItems(items); - private void synchronizeListWidget_() { - ArrayList<String> items = new ArrayList<String>(this.listModel.size()); - for (E item : this.listModel) { - items.add(this.transform(item)); - } - this.listWidget.setItems(items.toArray(new String[items.size()])); - - // now that the list has changed, we need to synch the selection + // now that the list has changed, we need to synchronize the selection this.selectionBinding.synchronizeListWidgetSelection(); } /** * The model has changed - synchronize the list widget. */ - void listItemsAdded(ListAddEvent event) { + /* CU private */ void listItemsAdded(ListAddEvent event) { if ( ! this.listWidget.isDisposed()) { this.listItemsAdded_(event); } @@ -185,40 +195,42 @@ final class ListWidgetModelBinding<E> { private void listItemsAdded_(ListAddEvent event) { int i = event.getIndex(); - for (E item : this.getItems(event)) { - this.listWidget.add(this.transform(item), i++); + this.list.ensureCapacity(this.list.size() + event.getItemsSize()); + @SuppressWarnings("unchecked") + Iterable<E> items = (Iterable<E>) event.getItems(); + for (E item : items) { + this.list.add(i, item); + this.listWidget.add(this.transformer.transform(item), i); + i++; } - // now that the list has changed, we need to synch the selection + // now that the list has changed, we need to synchronize the selection this.selectionBinding.synchronizeListWidgetSelection(); } - // minimized scope of suppressed warnings - @SuppressWarnings("unchecked") - private Iterable<E> getItems(ListAddEvent event) { - return (Iterable<E>) event.getItems(); - } - /** * The model has changed - synchronize the list widget. */ - void listItemsRemoved(ListRemoveEvent event) { + /* CU private */ void listItemsRemoved(ListRemoveEvent event) { if ( ! this.listWidget.isDisposed()) { this.listItemsRemoved_(event); } } private void listItemsRemoved_(ListRemoveEvent event) { - this.listWidget.remove(event.getIndex(), event.getIndex() + event.getItemsSize() - 1); + int start = event.getIndex(); + int end = start + event.getItemsSize(); + this.list.subList(start, end).clear(); + this.listWidget.remove(start, end - 1); // widget range is *inclusive* - // now that the list has changed, we need to synch the selection + // now that the list has changed, we need to synchronize the selection this.selectionBinding.synchronizeListWidgetSelection(); } /** * The model has changed - synchronize the list widget. */ - void listItemsMoved(ListMoveEvent event) { + /* CU private */ void listItemsMoved(ListMoveEvent event) { if ( ! this.listWidget.isDisposed()) { this.listItemsMoved_(event); } @@ -230,24 +242,31 @@ final class ListWidgetModelBinding<E> { int len = event.getLength(); int loStart = Math.min(target, source); int hiStart = Math.max(target, source); + int hiEnd = hiStart + len; // make a copy of the affected items... - String[] subArray = ArrayTools.subArray(this.listWidget.getItems(), loStart, hiStart + len); + ArrayList<E> subList = new ArrayList<E>(this.list.subList(loStart, hiEnd)); + String[] subArray = ArrayTools.subArray(this.listWidget.getItems(), loStart, hiEnd); // ...move them around... - subArray = ArrayTools.move(subArray, target - loStart, source - loStart, len); + int subTarget = target - loStart; + int subSource = source - loStart; + subList = ListTools.move(subList, subTarget, subSource, len); + subArray = ArrayTools.move(subArray, subTarget, subSource, len); // ...and then put them back - int i = loStart; - for (String item : subArray) { - this.listWidget.setItem(i++, item); + int subIndex = 0; + for (int i = loStart; i < hiEnd; i++) { + this.list.set(i, subList.get(subIndex)); + this.listWidget.setItem(i, subArray[subIndex]); + subIndex++; } - // now that the list has changed, we need to synch the selection + // now that the list has changed, we need to synchronize the selection this.selectionBinding.synchronizeListWidgetSelection(); } /** * The model has changed - synchronize the list widget. */ - void listItemsReplaced(ListReplaceEvent event) { + /* CU private */ void listItemsReplaced(ListReplaceEvent event) { if ( ! this.listWidget.isDisposed()) { this.listItemsReplaced_(event); } @@ -255,63 +274,60 @@ final class ListWidgetModelBinding<E> { private void listItemsReplaced_(ListReplaceEvent event) { int i = event.getIndex(); - for (E item : this.getNewItems(event)) { - this.listWidget.setItem(i++, this.transform(item)); + @SuppressWarnings("unchecked") + Iterable<E> newItems = (Iterable<E>) event.getNewItems(); + for (E item : newItems) { + this.list.set(i, item); + this.listWidget.setItem(i, this.transformer.transform(item)); + i++; } - // now that the list has changed, we need to synch the selection + // now that the list has changed, we need to synchronize the selection this.selectionBinding.synchronizeListWidgetSelection(); } - // minimized scope of suppressed warnings - @SuppressWarnings("unchecked") - private Iterable<E> getNewItems(ListReplaceEvent event) { - return (Iterable<E>) event.getNewItems(); - } - /** * The model has changed - synchronize the list widget. */ - void listCleared(ListClearEvent event) { + /* CU private */ void listCleared() { if ( ! this.listWidget.isDisposed()) { - this.listCleared_(event); + this.listCleared_(); } } - private void listCleared_(@SuppressWarnings("unused") ListClearEvent event) { + private void listCleared_() { + this.list.clear(); this.listWidget.removeAll(); } /** * The model has changed - synchronize the list widget. */ - void listChanged(ListChangeEvent event) { + /* CU private */ void listChanged(ListChangeEvent event) { if ( ! this.listWidget.isDisposed()) { this.listChanged_(event); } } - private void listChanged_(@SuppressWarnings("unused") ListChangeEvent event) { - this.synchronizeListWidget_(); - } - - /** - * Use the {@link #transformer} to convert the specified item to a - * string that can be added to the list widget. - */ - private String transform(E item) { - return this.transformer.transform(item); + private void listChanged_(ListChangeEvent event) { + this.list.clear(); + this.list.ensureCapacity(event.getListSize()); + @SuppressWarnings("unchecked") + Iterable<E> eventList = (Iterable<E>) event.getList(); + CollectionTools.addAll(this.list, eventList); + this.synchronizeListWidget(); } // ********** list widget events ********** - void listWidgetDisposed(@SuppressWarnings("unused") DisposeEvent event) { + /* CU private */ void listWidgetDisposed() { // the list widget is not yet "disposed" when we receive this event // so we can still remove our listeners this.listWidget.removeDisposeListener(this.listWidgetDisposeListener); - this.listModel.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener); + this.listModel.removeListChangeListener(ListValueModel.LIST_VALUES, this.listListener); this.selectionBinding.dispose(); + this.list.clear(); } @@ -319,20 +335,28 @@ final class ListWidgetModelBinding<E> { @Override public String toString() { - return ObjectTools.toString(this, this.listModel); + return ObjectTools.toString(this, this.list); } // ********** adapter interfaces ********** /** - * Adapter used by the list widget model binding to query and manipulate - * the widget. + * Adapter used by the binding to query and manipulate the SWT widget. */ - interface ListWidget { + interface ListWidget<E> { + /** + * Build a selection binding for the widget. + */ + SelectionBinding buildSelectionBinding(ArrayList<E> list, Object selectionModel); /** - * Return whether the list widget is "disposed". + * Return the list widget's display. + */ + Display getDisplay(); + + /** + * Return whether the list widget is <em>disposed</em>. */ boolean isDisposed(); @@ -368,6 +392,7 @@ final class ListWidgetModelBinding<E> { /** * Remove the specified range of items from the list widget's items. + * Both indices are <em>inclusive</em>. */ void remove(int start, int end); @@ -379,11 +404,9 @@ final class ListWidgetModelBinding<E> { /** - * Widget-specific selection binding that is controlled by the list widget - * model binding. + * Widget-specific selection binding that is controlled by the binding. */ interface SelectionBinding { - /** * Synchronize the selection binding's widget with the selection model. * <p> @@ -395,30 +418,5 @@ final class ListWidgetModelBinding<E> { * The widget has been disposed; dispose the selection binding. */ void dispose(); - - - /** - * Useful for list boxes that ignore the selection. - */ - final class Null implements SelectionBinding { - public static final SelectionBinding INSTANCE = new Null(); - public static SelectionBinding instance() { - return INSTANCE; - } - // ensure single instance - private Null() { - super(); - } - public void synchronizeListWidgetSelection() { - // do nothing - } - public void dispose() { - // do nothing - } - @Override - public String toString() { - return "SelectionBinding.Null"; //$NON-NLS-1$ - } - } } } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/MultiControlBooleanStateController.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/MultiControlBooleanStateController.java deleted file mode 100644 index 152e28694e..0000000000 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/MultiControlBooleanStateController.java +++ /dev/null @@ -1,160 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2013 Oracle. 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: - * Oracle - initial API and implementation - ******************************************************************************/ -package org.eclipse.jpt.common.ui.internal.swt.bindings; - -import java.util.HashSet; -import org.eclipse.jpt.common.utility.internal.iterable.IterableTools; -import org.eclipse.jpt.common.utility.model.event.CollectionAddEvent; -import org.eclipse.jpt.common.utility.model.event.CollectionChangeEvent; -import org.eclipse.jpt.common.utility.model.event.CollectionClearEvent; -import org.eclipse.jpt.common.utility.model.event.CollectionRemoveEvent; -import org.eclipse.jpt.common.utility.model.listener.CollectionChangeAdapter; -import org.eclipse.jpt.common.utility.model.listener.CollectionChangeListener; -import org.eclipse.jpt.common.utility.model.value.CollectionValueModel; -import org.eclipse.jpt.common.utility.model.value.PropertyValueModel; -import org.eclipse.swt.widgets.Control; - -/** - * This controller enables a boolean model to control either the - * <em>enabled</em> or <em>visible</em> properties of a set of SWT controls; - * i.e. the controls' properties are kept in synch with the boolean model, - * but <em>not</em> vice-versa. - * - * @see PropertyValueModel - * @see CollectionValueModel - * @see Control#setEnabled(boolean) - * @see Control#setVisible(boolean) - */ -final class MultiControlBooleanStateController - extends BooleanStateController -{ - /** - * The set of controls whose state is kept in sync with the boolean model. - */ - private final CollectionValueModel<? extends Control> controlsModel; - - /** - * A listener that allows clients to add/remove controls. - */ - private final CollectionChangeListener controlsListener; - - /** - * Cache of controls. - */ - private final HashSet<Control> controls = new HashSet<Control>(); - - - // ********** constructor ********** - - /** - * Constructor - the boolean model, the controls model, and the adapter are required. - */ - MultiControlBooleanStateController( - PropertyValueModel<Boolean> booleanModel, - CollectionValueModel<? extends Control> controlsModel, - boolean defaultValue, - Adapter adapter - ) { - super(booleanModel, defaultValue, adapter); - if (controlsModel == null) { - throw new NullPointerException(); - } - this.controlsModel = controlsModel; - this.controlsListener = this.buildControlsListener(); - this.addControls(controlsModel); - } - - - // ********** initialization ********** - - private CollectionChangeListener buildControlsListener() { - return new ControlsListener(); - } - - /* CU private */ class ControlsListener - extends CollectionChangeAdapter - { - @Override - @SuppressWarnings("unchecked") - public void itemsAdded(CollectionAddEvent event) { - MultiControlBooleanStateController.this.addControls((Iterable<? extends Control>) event.getItems()); - } - @Override - @SuppressWarnings("unchecked") - public void itemsRemoved(CollectionRemoveEvent event) { - MultiControlBooleanStateController.this.removeControls((Iterable<? extends Control>) event.getItems()); - } - @Override - public void collectionCleared(CollectionClearEvent event) { - MultiControlBooleanStateController.this.clearControls(); - } - @Override - @SuppressWarnings("unchecked") - public void collectionChanged(CollectionChangeEvent event) { - MultiControlBooleanStateController.this.clearControls(); - MultiControlBooleanStateController.this.addControls((Iterable<? extends Control>) event.getCollection()); - } - } - - - // ********** controls ********** - - @Override - void setControlState(boolean controlState) { - for (Control control : this.controls) { - this.setControlState(control, controlState); - } - } - - /* CU private */ void addControls(Iterable<? extends Control> controls_) { - for (Control control : controls_) { - this.addControl(control); - } - } - - private void addControl(Control control) { - if (this.controls.isEmpty()) { - this.engageBooleanModel(); - this.controlsModel.addCollectionChangeListener(CollectionValueModel.VALUES, this.controlsListener); - } - if (this.controls.add(control)) { - this.engageControl(control); - // wait until the models are engaged to get the boolean value... :-) - this.setControlState(control, this.getBooleanValue()); - } else { - throw new IllegalArgumentException("duplicate control: " + control); //$NON-NLS-1$ - } - } - - /* CU private */ void clearControls() { - this.removeControls(IterableTools.cloneSnapshot(this.controls)); - } - - /* CU private */ void removeControls(Iterable<? extends Control> controls_) { - for (Control control : controls_) { - this.disengageControl(control); - this.removeControl(control); - } - } - - private void removeControl(Control control) { - this.controls.remove(control); - if (this.controls.isEmpty()) { - this.controlsModel.removeCollectionChangeListener(CollectionValueModel.VALUES, this.controlsListener); - this.disengageBooleanModel(); - } - } - - @Override - void controlDisposed(Control control) { - super.controlDisposed(control); - this.removeControl(control); - } -} diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/PageBookModelBinding.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/PageBookModelBinding.java index 21a9370a24..d9643b0b1d 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/PageBookModelBinding.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/PageBookModelBinding.java @@ -42,13 +42,13 @@ final class PageBookModelBinding<T> { * A listener that allows us to synchronize the page book's current page * with the value model. */ - private final PropertyChangeListener valueModelListener; + private final PropertyChangeListener valueListener; // ***** transformer /** * The transformer that converts the model's value to the control * to be displayed by the page book. If the transformer returns - * <code>null</code>, the page book will display the null page. + * <code>null</code>, the page book will display the <em>null</em> page. */ private final Transformer<? super T, Control> transformer; @@ -90,8 +90,8 @@ final class PageBookModelBinding<T> { throw new IllegalArgumentException("The null page's parent must be the page book: " + defaultPage); //$NON-NLS-1$ } - this.valueModelListener = this.buildValueModelListener(); - this.valueModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.valueModelListener); + this.valueListener = this.buildValueListener(); + this.valueModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.valueListener); this.pageBookDisposeListener = this.buildPageBookDisposeListener(); this.pageBook.addDisposeListener(this.pageBookDisposeListener); @@ -104,17 +104,16 @@ final class PageBookModelBinding<T> { return new Label(this.pageBook, SWT.SEPARATOR | SWT.SHADOW_NONE | SWT.HORIZONTAL); } - private PropertyChangeListener buildValueModelListener() { - return SWTListenerWrapperTools.wrap(new ValueModelListener(), this.pageBook); + private PropertyChangeListener buildValueListener() { + return SWTListenerWrapperTools.wrap(new ValueListener(), this.pageBook); } - /* CU private */ class ValueModelListener + /* CU private */ class ValueListener extends PropertyChangeAdapter { @Override - @SuppressWarnings("unchecked") public void propertyChanged(PropertyChangeEvent event) { - PageBookModelBinding.this.showPage((T) event.getNewValue()); + PageBookModelBinding.this.valueChanged(event); } } @@ -134,13 +133,18 @@ final class PageBookModelBinding<T> { // ********** model events ********** + /* CU private */ void valueChanged(PropertyChangeEvent event) { + if ( ! this.pageBook.isDisposed()) { + @SuppressWarnings("unchecked") + T value = (T) event.getNewValue(); + this.showPage(value); + } + } + /** * Show the page corresponding to the specified model value. */ - /* CU private */ void showPage(T value) { - if (this.pageBook.isDisposed()) { - return; - } + private void showPage(T value) { Control page = this.transformer.transform(value); this.pageBook.showPage((page != null) ? page : this.defaultPage); ControlTools.reflow(this.pageBook); @@ -153,7 +157,7 @@ final class PageBookModelBinding<T> { // the page book is not yet "disposed" when we receive this event // so we can still remove our listener this.pageBook.removeDisposeListener(this.pageBookDisposeListener); - this.valueModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.valueModelListener); + this.valueModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.valueListener); } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SWTBindingTools.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SWTBindingTools.java index 4fa84d5893..d121c5bd10 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SWTBindingTools.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SWTBindingTools.java @@ -11,11 +11,12 @@ package org.eclipse.jpt.common.ui.internal.swt.bindings; import java.util.Arrays; import org.eclipse.jpt.common.utility.internal.BitTools; +import org.eclipse.jpt.common.utility.internal.ObjectTools; import org.eclipse.jpt.common.utility.internal.model.value.ModifiablePropertyCollectionValueModelAdapter; import org.eclipse.jpt.common.utility.internal.model.value.NullPropertyValueModel; +import org.eclipse.jpt.common.utility.internal.model.value.SimpleCollectionValueModel; import org.eclipse.jpt.common.utility.internal.model.value.StaticCollectionValueModel; import org.eclipse.jpt.common.utility.internal.transformer.TransformerTools; -import org.eclipse.jpt.common.utility.model.value.CollectionValueModel; import org.eclipse.jpt.common.utility.model.value.ListValueModel; import org.eclipse.jpt.common.utility.model.value.ModifiableCollectionValueModel; import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel; @@ -340,7 +341,7 @@ public final class SWTBindingTools { * to be displayed in the list box. */ public static <E> void bind(ListValueModel<E> listModel, List listBox, Transformer<E, String> transformer) { - bind(listModel, new SWTListAdapter(listBox), transformer); + bind(listModel, new SWTListListWidgetAdapter<E>(listBox), transformer); } /** @@ -381,9 +382,9 @@ public final class SWTBindingTools { public static <E> void bind(ListValueModel<E> listModel, ModifiableCollectionValueModel<E> selectedItemsModel, List listBox, Transformer<E, String> transformer) { bind( listModel, - new SWTListAdapter(listBox), - transformer, - new ListBoxSelectionBinding<E>(listModel, selectedItemsModel, listBox) + selectedItemsModel, + new SWTListListWidgetAdapter<E>(listBox), + transformer ); } @@ -413,12 +414,11 @@ public final class SWTBindingTools { */ public static <E> void bind(ListValueModel<E> listModel, ModifiablePropertyValueModel<E> selectedItemModel, Combo dropDownListBox, Transformer<E, String> transformer) { checkForReadOnlyStyle(dropDownListBox); - SWTComboAdapter comboAdapter = new SWTComboAdapter(dropDownListBox); bind( listModel, - comboAdapter, - transformer, - new DropDownListBoxSelectionBinding<E>(listModel, selectedItemModel, comboAdapter) + selectedItemModel, + new SWTComboListWidgetAdapter<E>(dropDownListBox), + transformer ); } @@ -437,20 +437,19 @@ public final class SWTBindingTools { * Use the specified string converter to convert the model items to strings * to be displayed in the list box. */ - private static <E> void bind(ListValueModel<E> listModel, ListWidgetModelBinding.ListWidget listWidget, Transformer<E, String> transformer) { - bind(listModel, listWidget, transformer, ListWidgetModelBinding.SelectionBinding.Null.instance()); + private static <E> void bind(ListValueModel<E> listModel, ListWidgetModelBinding.ListWidget<E> listWidget, Transformer<E, String> transformer) { + bind(listModel, new SimpleCollectionValueModel<E>(), listWidget, transformer); } /** - * Bind the specified model list to the specified list widget. - * Use the specified selection binding to control the list widget's selection. + * Bind the specified model list and selectedions to the specified list widget. * Use the specified string converter to convert the model items to strings * to be displayed in the list box. */ @SuppressWarnings("unused") - private static <E> void bind(ListValueModel<E> listModel, ListWidgetModelBinding.ListWidget listWidget, Transformer<E, String> transformer, ListWidgetModelBinding.SelectionBinding selectionBinding) { + private static <E> void bind(ListValueModel<E> listModel, Object selectionModel, ListWidgetModelBinding.ListWidget<E> listWidget, Transformer<E, String> transformer) { // the new binding will add itself as a listener to the value models and the list box - new ListWidgetModelBinding<E>(listModel, listWidget, transformer, selectionBinding); + new ListWidgetModelBinding<E>(listModel, selectionModel, listWidget, transformer); } @@ -501,215 +500,204 @@ public final class SWTBindingTools { // ********** 'enabled' state ********** /** - * Control the <em>enabled</em> state of the specified controls with the + * Bind the <em>enabled</em> state of the specified controls with the * specified boolean. If the boolean is <code>null<code>, the controls' * <em>enabled</em> states will be <code>false<code>. */ - public static void controlEnabledState(PropertyValueModel<Boolean> booleanModel, Control... controls) { - controlEnabledState(booleanModel, controls, false); + public static void bindEnabledState(PropertyValueModel<Boolean> booleanModel, Control... controls) { + bindEnabledState(booleanModel, controls, false); } /** - * Control the <em>enabled</em> state of the specified controls with the + * Bind the <em>enabled</em> state of the specified controls with the * specified boolean. If the boolean is <code>null<code>, the controls' * <em>enabled</em> states will be the specified default value. */ - public static void controlEnabledState(PropertyValueModel<Boolean> booleanModel, Control[] controls, boolean defaultValue) { + public static void bindEnabledState(PropertyValueModel<Boolean> booleanModel, Control[] controls, boolean defaultValue) { switch (controls.length) { case 0: throw new IllegalArgumentException("empty controls array: " + Arrays.toString(controls)); case 1: - controlEnabledState(booleanModel, controls[0], defaultValue); + bindEnabledState(booleanModel, controls[0], defaultValue); break; default: - controlEnabledState(booleanModel, new StaticCollectionValueModel<Control>(controls), defaultValue); + bindEnabledState(booleanModel, new StaticCollectionValueModel<Control>(controls), defaultValue); break; } } /** - * Control the <em>enabled</em> state of the specified controls with the - * specified boolean. If the boolean is <code>null<code>, the controls' - * <em>enabled</em> states will be <code>false<code>. - */ - public static void controlEnabledState(PropertyValueModel<Boolean> booleanModel, Iterable<? extends Control> controls) { - controlEnabledState(booleanModel, controls, false); - } - - /** - * Control the <em>enabled</em> state of the specified controls with the - * specified boolean. If the boolean is <code>null<code>, the controls' - * <em>enabled</em> states will be the specified default value. - */ - public static void controlEnabledState(PropertyValueModel<Boolean> booleanModel, Iterable<? extends Control> controls, boolean defaultValue) { - controlEnabledState(booleanModel, new StaticCollectionValueModel<Control>(controls), defaultValue); - } - - /** - * Control the <em>enabled</em> state of the specified controls with the + * Bind the <em>enabled</em> state of the specified controls with the * specified boolean. If the boolean is <code>null<code>, the controls' * <em>enabled</em> states will be <code>false<code>. */ - public static void controlEnabledState(PropertyValueModel<Boolean> booleanModel, CollectionValueModel<? extends Control> controlsModel) { - controlEnabledState(booleanModel, controlsModel, false); + public static void bindEnabledState(PropertyValueModel<Boolean> booleanModel, Iterable<? extends Control> controls) { + bindEnabledState(booleanModel, controls, false); } /** - * Control the <em>enabled</em> state of the specified controls with the + * Bind the <em>enabled</em> state of the specified controls with the * specified boolean. If the boolean is <code>null<code>, the controls' * <em>enabled</em> states will be the specified default value. */ - public static void controlEnabledState(PropertyValueModel<Boolean> booleanModel, CollectionValueModel<? extends Control> controlsModel, boolean defaultValue) { - control(booleanModel, controlsModel, defaultValue, ENABLED_ADAPTER); + public static <C extends Control> void bindEnabledState(PropertyValueModel<Boolean> booleanModel, Iterable<C> controls, boolean defaultValue) { + BooleanControlStateModelBinding.Adapter<C> adapter = enabledAdapter(); + bindState(booleanModel, controls, defaultValue, adapter); } /** - * Control the <em>enabled</em> state of the specified control with the + * Bind the <em>enabled</em> state of the specified control with the * specified boolean. If the boolean is <code>null<code>, the control's * <em>enabled</em> state will be the specified default value. */ - public static void controlEnabledState(PropertyValueModel<Boolean> booleanModel, Control control, boolean defaultValue) { - control(booleanModel, control, defaultValue, ENABLED_ADAPTER); + public static void bindEnabledState(PropertyValueModel<Boolean> booleanModel, Control control, boolean defaultValue) { + bindState(booleanModel, control, defaultValue, enabledAdapter()); } - private static final BooleanStateController.Adapter ENABLED_ADAPTER = - new BooleanStateController.Adapter() { - public void setState(Control control, boolean b) { - control.setEnabled(b); - } - }; + @SuppressWarnings("unchecked") + private static <C extends Control> BooleanControlStateModelBinding.Adapter<C> enabledAdapter() { + return ENABLED_ADAPTER; + } + @SuppressWarnings("rawtypes") + private static final BooleanControlStateModelBinding.Adapter ENABLED_ADAPTER = new EnabledAdapter(); + /** CU private */ static class EnabledAdapter<C extends Control> + implements BooleanControlStateModelBinding.Adapter<C> + { + public void setState(Control control, boolean b) { + control.setEnabled(b); + } + @Override + public String toString() { + return ObjectTools.singletonToString(this); + } + } // ********** 'visible' state ********** /** - * Control the <em>visible</em> state of the specified controls with the + * Bind the <em>visible</em> state of the specified controls with the * specified boolean. If the boolean is <code>null<code>, the controls' * <em>visible</em> states will be <code>false<code>. */ - public static void controlVisibleState(PropertyValueModel<Boolean> booleanModel, Control... controls) { - controlVisibleState(booleanModel, controls, false); + public static void bindVisibleState(PropertyValueModel<Boolean> booleanModel, Control... controls) { + bindVisibleState(booleanModel, controls, false); } /** - * Control the <em>visible</em> state of the specified controls with the + * Bind the <em>visible</em> state of the specified controls with the * specified boolean. If the boolean is <code>null<code>, the controls' * <em>visible</em> states will be the specified default value. */ - public static void controlVisibleState(PropertyValueModel<Boolean> booleanModel, Control[] controls, boolean defaultValue) { + public static void bindVisibleState(PropertyValueModel<Boolean> booleanModel, Control[] controls, boolean defaultValue) { switch (controls.length) { case 0: throw new IllegalArgumentException("empty controls array: " + Arrays.toString(controls)); case 1: - controlVisibleState(booleanModel, controls[0], defaultValue); + bindVisibleState(booleanModel, controls[0], defaultValue); break; default: - controlVisibleState(booleanModel, new StaticCollectionValueModel<Control>(controls), defaultValue); + bindVisibleState(booleanModel, new StaticCollectionValueModel<Control>(controls), defaultValue); break; } } /** - * Control the <em>visible</em> state of the specified controls with the + * Bind the <em>visible</em> state of the specified controls with the * specified boolean. If the boolean is <code>null<code>, the controls' * <em>visible</em> states will be <code>false<code>. */ - public static void controlVisibleState(PropertyValueModel<Boolean> booleanModel, Iterable<? extends Control> controls) { - controlVisibleState(booleanModel, controls, false); + public static void bindVisibleState(PropertyValueModel<Boolean> booleanModel, Iterable<? extends Control> controls) { + bindVisibleState(booleanModel, controls, false); } /** - * Control the <em>visible</em> state of the specified controls with the + * Bind the <em>visible</em> state of the specified controls with the * specified boolean. If the boolean is <code>null<code>, the controls' * <em>visible</em> states will be the specified default value. */ - public static void controlVisibleState(PropertyValueModel<Boolean> booleanModel, Iterable<? extends Control> controls, boolean defaultValue) { - controlVisibleState(booleanModel, new StaticCollectionValueModel<Control>(controls), defaultValue); + public static <C extends Control> void bindVisibleState(PropertyValueModel<Boolean> booleanModel, Iterable<C> controls, boolean defaultValue) { + BooleanControlStateModelBinding.Adapter<C> adapter = visibleAdapter(); + bindState(booleanModel, controls, defaultValue, adapter); } /** - * Control the <em>visible</em> state of the specified controls with the - * specified boolean. If the boolean is <code>null<code>, the controls' - * <em>visible</em> states will be <code>false<code>. + * Bind the <em>visible</em> state of the specified control with the + * specified boolean. If the boolean is <code>null<code>, the control's + * <em>visible</em> state will be the specified default value. */ - public static void controlVisibleState(PropertyValueModel<Boolean> booleanModel, CollectionValueModel<? extends Control> controlsModel) { - controlVisibleState(booleanModel, controlsModel, false); + public static void bindVisibleState(PropertyValueModel<Boolean> booleanModel, Control control, boolean defaultValue) { + bindState(booleanModel, control, defaultValue, visibleAdapter()); } - /** - * Control the <em>visible</em> state of the specified controls with the - * specified boolean. If the boolean is <code>null<code>, the controls' - * <em>visible</em> states will be the specified default value. - */ - public static void controlVisibleState(PropertyValueModel<Boolean> booleanModel, CollectionValueModel<? extends Control> controlsModel, boolean defaultValue) { - control(booleanModel, controlsModel, defaultValue, VISIBLE_ADAPTER); + @SuppressWarnings("unchecked") + private static <C extends Control> BooleanControlStateModelBinding.Adapter<C> visibleAdapter() { + return VISIBLE_ADAPTER; } - - /** - * Control the <em>visible</em> state of the specified control with the - * specified boolean. If the boolean is <code>null<code>, the control's - * <em>visible</em> state will be the specified default value. - */ - public static void controlVisibleState(PropertyValueModel<Boolean> booleanModel, Control control, boolean defaultValue) { - control(booleanModel, control, defaultValue, VISIBLE_ADAPTER); + @SuppressWarnings("rawtypes") + private static final BooleanControlStateModelBinding.Adapter VISIBLE_ADAPTER = new VisibleAdapter(); + /** CU private */ static class VisibleAdapter<C extends Control> + implements BooleanControlStateModelBinding.Adapter<C> + { + public void setState(C control, boolean b) { + control.setVisible(b); + } + @Override + public String toString() { + return ObjectTools.singletonToString(this); + } } - private static final BooleanStateController.Adapter VISIBLE_ADAPTER = - new BooleanStateController.Adapter() { - public void setState(Control control, boolean b) { - control.setVisible(b); - } - }; - - // ********** boolean state controller ********** + // ********** boolean state ********** @SuppressWarnings("unused") - private static void control(PropertyValueModel<Boolean> booleanModel, CollectionValueModel<? extends Control> controlsModel, boolean defaultValue, BooleanStateController.Adapter adapter) { - // the new controller will add itself as a listener to the value model and the controls - new MultiControlBooleanStateController(booleanModel, controlsModel, defaultValue, adapter); + private static <C extends Control> void bindState(PropertyValueModel<Boolean> booleanModel, Iterable<C> controls, boolean defaultValue, BooleanControlStateModelBinding.Adapter<C> adapter) { + // the new binding will add itself as a listener to the value model and the controls + new CompositeBooleanControlStateModelBinding<C>(booleanModel, controls, defaultValue, adapter); } @SuppressWarnings("unused") - private static void control(PropertyValueModel<Boolean> booleanModel, Control control, boolean defaultValue, BooleanStateController.Adapter adapter) { - // the new controller will add itself as a listener to the value model and the controls - new SimpleBooleanStateController(booleanModel, control, defaultValue, adapter); + private static <C extends Control> void bindState(PropertyValueModel<Boolean> booleanModel, C control, boolean defaultValue, BooleanControlStateModelBinding.Adapter<C> adapter) { + // the new binding will add itself as a listener to the value model and the controls + new SimpleBooleanControlStateModelBinding<C>(booleanModel, control, defaultValue, adapter); } // ********** 'expanded' state ********** /** - * Control the <em>expanded</em> state of the specified section with the + * Bind the <em>expanded</em> state of the specified section with the * specified boolean model. If the boolean is <code>null<code>, the section's - * <em>expanded</em> state will be false. + * <em>expanded</em> state will be <code>false</code>. */ - public static void controlExpandedState(PropertyValueModel<Boolean> booleanModel, Section section) { - controlExpandedState(booleanModel, section, false); + public static void bindExpandedState(PropertyValueModel<Boolean> booleanModel, Section section) { + bindExpandedState(booleanModel, section, false); } /** - * Control the <em>expanded</em> state of the specified section with the + * Bind the <em>expanded</em> state of the specified section with the * specified boolean model. If the boolean is <code>null<code>, the section's * <em>expanded</em> state will be the specified default value. */ - public static void controlExpandedState(PropertyValueModel<Boolean> booleanModel, Section section, boolean defaultValue) { - control(booleanModel, section, defaultValue, EXPANDED_ADAPTER); + public static void bindExpandedState(PropertyValueModel<Boolean> booleanModel, Section section, boolean defaultValue) { + bindState(booleanModel, section, defaultValue, EXPANDED_ADAPTER); } - private static final BooleanStateController.Adapter EXPANDED_ADAPTER = - new BooleanStateController.Adapter() { - public void setState(Control section, boolean b) { - ((Section) section).setExpanded(b); - } - }; - - @SuppressWarnings("unused") - private static void control(PropertyValueModel<Boolean> booleanModel, Section section, boolean defaultValue, BooleanStateController.Adapter adapter) { - // the new controller will add itself as a listener to the value model and the section - new SimpleBooleanStateController(booleanModel, section, defaultValue, adapter); + private static final BooleanControlStateModelBinding.Adapter<Section> EXPANDED_ADAPTER = new ExpandedAdapter(); + /** CU private */ static class ExpandedAdapter + implements BooleanControlStateModelBinding.Adapter<Section> + { + public void setState(Section section, boolean b) { + section.setExpanded(b); + } + @Override + public String toString() { + return ObjectTools.singletonToString(this); + } } + // ********** constructor ********** /** @@ -719,5 +707,4 @@ public final class SWTBindingTools { super(); throw new UnsupportedOperationException(); } - } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SWTComboAdapter.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SWTComboListWidgetAdapter.java index 4ba3a7956e..768b0593a3 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SWTComboAdapter.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SWTComboListWidgetAdapter.java @@ -9,23 +9,31 @@ ******************************************************************************/ package org.eclipse.jpt.common.ui.internal.swt.bindings; +import java.util.ArrayList; +import org.eclipse.jpt.common.ui.internal.swt.bindings.ListWidgetModelBinding.SelectionBinding; +import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Combo; /** - * Adapt an SWT {@link Combo} to the list widget expected by - * {@link ListWidgetModelBinding} and the - * drop-down list box expected by {@link DropDownListBoxSelectionBinding}. + * Adapt an SWT {@link Combo} to the {@link ListWidgetModelBinding.ListWidget + * list widget} expected by {@link ListWidgetModelBinding} and the + * {@link DropDownListBoxSelectionBinding.DropDownListBox drop-down list box} + * expected by {@link DropDownListBoxSelectionBinding}. */ -final class SWTComboAdapter - extends AbstractListWidgetAdapter<Combo> +final class SWTComboListWidgetAdapter<E> + extends AbstractListWidgetAdapter<E, Combo> implements DropDownListBoxSelectionBinding.DropDownListBox { - SWTComboAdapter(Combo combo) { + SWTComboListWidgetAdapter(Combo combo) { super(combo); } // ********** ListWidgetModelBinding.ListWidget implementation ********** + @SuppressWarnings("unchecked") + public SelectionBinding buildSelectionBinding(ArrayList<E> list, Object selectionModel) { + return new DropDownListBoxSelectionBinding<E>(list, (ModifiablePropertyValueModel<E>) selectionModel, new SWTComboListWidgetAdapter<E>(this.widget)); + } public String[] getItems() { return this.widget.getItems(); } @@ -45,7 +53,7 @@ final class SWTComboAdapter this.widget.removeAll(); } - // ********** ComboBoxSelectionBinding.ComboBox implementation ********** + // ********** DropDownListBoxSelectionBinding.DropDownListBox implementation ********** public void addSelectionListener(SelectionListener listener) { this.widget.addSelectionListener(listener); } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SWTListAdapter.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SWTListListWidgetAdapter.java index 121d1bed6c..50333b31b9 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SWTListAdapter.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SWTListListWidgetAdapter.java @@ -9,19 +9,26 @@ ******************************************************************************/ package org.eclipse.jpt.common.ui.internal.swt.bindings; +import java.util.ArrayList; +import org.eclipse.jpt.common.ui.internal.swt.bindings.ListWidgetModelBinding.SelectionBinding; +import org.eclipse.jpt.common.utility.model.value.ModifiableCollectionValueModel; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.List; /** - * Adapt an SWT {@link List} to the list widget expected by - * {@link ListWidgetModelBinding}. + * Adapt an SWT {@link List} to the {@link ListWidgetModelBinding.ListWidget + * list widget} expected by {@link ListWidgetModelBinding}. */ -final class SWTListAdapter - extends AbstractListWidgetAdapter<List> +final class SWTListListWidgetAdapter<E> + extends AbstractListWidgetAdapter<E, List> { - SWTListAdapter(List list) { + SWTListListWidgetAdapter(List list) { super(list); } + @SuppressWarnings("unchecked") + public SelectionBinding buildSelectionBinding(ArrayList<E> list, Object selectionModel) { + return new ListBoxSelectionBinding<E>(list, (ModifiableCollectionValueModel<E>) selectionModel, this.widget); + } public void addSelectionListener(SelectionListener listener) { this.widget.addSelectionListener(listener); } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SimpleBooleanStateController.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SimpleBooleanControlStateModelBinding.java index 5593086d9f..20cb21de61 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SimpleBooleanStateController.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/SimpleBooleanControlStateModelBinding.java @@ -13,9 +13,9 @@ import org.eclipse.jpt.common.utility.model.value.PropertyValueModel; import org.eclipse.swt.widgets.Control; /** - * This controller enables a boolean model to control either the + * This controller enables a <code>boolean</code> model to control either the * <em>enabled</em> or <em>visible</em> properties of an SWT control; i.e. the - * control's property is kept in synch with the boolean model, + * control's property is kept in sync with the <code>boolean</code> model, * but <em>not</em> vice-versa. * <p> * Once the control is disposed, this controller is kaput. @@ -24,22 +24,21 @@ import org.eclipse.swt.widgets.Control; * @see Control#setEnabled(boolean) * @see Control#setVisible(boolean) */ -final class SimpleBooleanStateController - extends BooleanStateController +final class SimpleBooleanControlStateModelBinding<C extends Control> + extends BooleanControlStateModelBinding<C> { - private final Control control; + private final C control; - // ********** constructor ********** - /** - * Constructor - the boolean model, the control, and the adapter are required. + * Constructor - the <code>boolean</code> model, the control, + * and the adapter are required. */ - SimpleBooleanStateController( + SimpleBooleanControlStateModelBinding( PropertyValueModel<Boolean> booleanModel, - Control control, + C control, boolean defaultValue, - Adapter adapter + Adapter<C> adapter ) { super(booleanModel, defaultValue, adapter); if (control == null) { @@ -48,20 +47,23 @@ final class SimpleBooleanStateController this.control = control; this.engageBooleanModel(); this.engageControl(control); - this.setControlState(control, this.getBooleanValue()); + this.setControlState(); } - // ********** controls ********** - @Override - void setControlState(boolean controlState) { - this.setControlState(this.control, controlState); + void setControlState() { + this.setControlState(this.control); } @Override - void controlDisposed(Control c) { + void controlDisposed(C c) { super.controlDisposed(c); this.disengageBooleanModel(); } + + @Override + boolean controlIsDisposed() { + return this.control.isDisposed(); + } } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/TextFieldModelBinding.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/TextFieldModelBinding.java index 021866880a..a2119b9363 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/TextFieldModelBinding.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/bindings/TextFieldModelBinding.java @@ -10,8 +10,11 @@ package org.eclipse.jpt.common.ui.internal.swt.bindings; import org.eclipse.jpt.common.ui.internal.listeners.SWTListenerWrapperTools; +import org.eclipse.jpt.common.ui.internal.swt.events.DisposeAdapter; +import org.eclipse.jpt.common.ui.internal.swt.events.ModifyAdapter; import org.eclipse.jpt.common.utility.internal.ObjectTools; 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.ModifiablePropertyValueModel; import org.eclipse.jpt.common.utility.model.value.PropertyValueModel; @@ -24,6 +27,8 @@ import org.eclipse.swt.widgets.Text; /** * This binding can be used to keep a text field * synchronized with a model text/string. + * <p> + * <strong>NB:</strong> This binding is bi-directional. * * @see ModifiablePropertyValueModel * @see Text @@ -40,7 +45,7 @@ class TextFieldModelBinding { * A listener that allows us to synchronize the text field's contents with * the text model. */ - private final PropertyChangeListener textModelChangeListener; + private final PropertyChangeListener textListener; /** * The text field we keep synchronized with the text model. @@ -59,11 +64,6 @@ class TextFieldModelBinding { */ private final DisposeListener textFieldDisposeListener; - /** - * Hmm... - */ - private boolean settingTextFieldText = false; - // ********** constructor ********** @@ -78,8 +78,8 @@ class TextFieldModelBinding { this.textModel = textModel; this.textField = textField; - this.textModelChangeListener = this.buildTextModelChangeListener(); - this.textModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.textModelChangeListener); + this.textListener = this.buildTextListener(); + this.textModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.textListener); this.textFieldModifyListener = this.buildTextFieldModifyListener(); this.textField.addModifyListener(this.textFieldModifyListener); @@ -93,51 +93,50 @@ class TextFieldModelBinding { // ********** initialization ********** - private PropertyChangeListener buildTextModelChangeListener() { - return SWTListenerWrapperTools.wrap(this.buildTextModelChangeListener_(), this.textField); + private PropertyChangeListener buildTextListener() { + return SWTListenerWrapperTools.wrap(new TextListener(), this.textField); } - private PropertyChangeListener buildTextModelChangeListener_() { - return new PropertyChangeListener() { - public void propertyChanged(PropertyChangeEvent event) { - TextFieldModelBinding.this.textModelChanged(event); - } - @Override - public String toString() { - return "text listener"; - } - }; + /* CU private */ class TextListener + extends PropertyChangeAdapter + { + @Override + public void propertyChanged(PropertyChangeEvent event) { + TextFieldModelBinding.this.textChanged(event); + } } private ModifyListener buildTextFieldModifyListener() { - return new ModifyListener() { - public void modifyText(ModifyEvent event) { - TextFieldModelBinding.this.textFieldModified(); - } - @Override - public String toString() { - return "text field modify listener"; - } - }; + return new TextFieldModifyListener(); + } + + /* CU private */ class TextFieldModifyListener + extends ModifyAdapter + { + @Override + public void modifyText(ModifyEvent event) { + TextFieldModelBinding.this.textFieldModified(); + } } private DisposeListener buildTextFieldDisposeListener() { - return new DisposeListener() { - public void widgetDisposed(DisposeEvent event) { - TextFieldModelBinding.this.textFieldDisposed(); - } - @Override - public String toString() { - return "text field dispose listener"; - } - }; + return new TextFieldDisposeListener(); + } + + /* CU private */ class TextFieldDisposeListener + extends DisposeAdapter + { + @Override + public void widgetDisposed(DisposeEvent event) { + TextFieldModelBinding.this.textFieldDisposed(); + } } // ********** text model events ********** - /* CU private */ void textModelChanged(PropertyChangeEvent event) { - if ( ! this.textField.isDisposed()) { // ??? + /* CU private */ void textChanged(PropertyChangeEvent event) { + if ( ! this.textField.isDisposed()) { this.setTextFieldText((String) event.getNewValue()); } } @@ -148,17 +147,8 @@ class TextFieldModelBinding { } private void setTextFieldText_(String text) { - if ( ! text.equals(this.textField.getText())) { // ??? - this.setTextFieldText__(text); - } - } - - private void setTextFieldText__(String text) { - this.settingTextFieldText = true; - try { + if ( ! text.equals(this.textField.getText())) { // text field does not short-circuit this.textField.setText(text); - } finally { - this.settingTextFieldText = false; } } @@ -166,15 +156,7 @@ class TextFieldModelBinding { // ********** text field events ********** /* CU private */ void textFieldModified() { - if ( ! this.settingTextFieldText) { - this.setTextModelText(this.textField.getText()); - } - } - - private void setTextModelText(String text) { - if ( ! text.equals(this.textModel.getValue())) { // ??? - this.textModel.setValue(text); - } + this.textModel.setValue(this.textField.getText()); } /* CU private */ void textFieldDisposed() { @@ -182,7 +164,7 @@ class TextFieldModelBinding { // so we can still remove our listeners this.textField.removeDisposeListener(this.textFieldDisposeListener); this.textField.removeModifyListener(this.textFieldModifyListener); - this.textModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.textModelChangeListener); + this.textModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.textListener); } diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/Pane.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/Pane.java index 213d9d821f..7f254d658a 100644 --- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/Pane.java +++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/Pane.java @@ -507,7 +507,7 @@ public abstract class Pane<T extends Model> { final Runnable buttonAction) { Button button = addUnmanagedButton(container, text, helpId, buttonAction); - this.controlEnabledState(button); + this.bindEnabledState(button); return button; } @@ -519,7 +519,7 @@ public abstract class Pane<T extends Model> { PropertyValueModel<Boolean> enabledModel) { Button button = addUnmanagedButton(container, text, helpId, buttonAction); - this.controlEnabledState(enabledModel, button); + this.bindEnabledState(enabledModel, button); return button; } @@ -611,7 +611,7 @@ public abstract class Pane<T extends Model> { PropertyValueModel<Boolean> enabledModel) { Button button = this.addUnmanagedToggleButton(parent, buttonText, booleanHolder, helpId, SWT.CHECK); - this.controlEnabledState(enabledModel, button); + this.bindEnabledState(enabledModel, button); return button; } @@ -625,7 +625,7 @@ public abstract class Pane<T extends Model> { */ protected final Combo addCombo(Composite container) { Combo combo = this.addUnmanagedCombo(container); - this.controlEnabledState(combo); + this.bindEnabledState(combo); return combo; } @@ -644,7 +644,7 @@ public abstract class Pane<T extends Model> { this.setHelp(combo, helpId); } - this.controlEnabledState(combo); + this.bindEnabledState(combo); return combo; } @@ -729,7 +729,7 @@ public abstract class Pane<T extends Model> { PropertyValueModel<Boolean> enabledModel) { Combo combo = this.addUnmanagedCombo(container, listHolder, selectedItemHolder, stringConverter); - this.controlEnabledState(enabledModel, combo); + this.bindEnabledState(enabledModel, combo); return combo; } @@ -804,7 +804,7 @@ public abstract class Pane<T extends Model> { String helpId) { Combo combo = this.addUnmanagedEditableCombo(container, listHolder, selectedItemHolder, stringConverter, helpId); - this.controlEnabledState(enabledModel, combo); + this.bindEnabledState(enabledModel, combo); return combo; } @@ -820,7 +820,7 @@ public abstract class Pane<T extends Model> { } combo.setLayoutData(getFieldGridData()); - this.controlEnabledState(combo); + this.bindEnabledState(combo); return combo; } @@ -902,7 +902,7 @@ public abstract class Pane<T extends Model> { final Runnable hyperLinkAction) { Hyperlink link = this.getWidgetFactory().createHyperlink(parent, text); - this.controlEnabledState(link); + this.bindEnabledState(link); link.addMouseListener(new MouseAdapter() { @Override @@ -923,7 +923,7 @@ public abstract class Pane<T extends Model> { String text) { Hyperlink link = this.getWidgetFactory().createHyperlink(parent, text); - this.controlEnabledState(link); + this.bindEnabledState(link); return link; } @@ -940,7 +940,7 @@ public abstract class Pane<T extends Model> { String labelText) { Label label = this.addUnmanagedLabel(container, labelText); - this.controlEnabledState(label); + this.bindEnabledState(label); return label; } @@ -950,7 +950,7 @@ public abstract class Pane<T extends Model> { PropertyValueModel<Boolean> enabledModel ) { Label label = this.addUnmanagedLabel(container, labelText); - this.controlEnabledState(enabledModel, label); + this.bindEnabledState(enabledModel, label); return label; } @@ -992,7 +992,7 @@ public abstract class Pane<T extends Model> { String helpId) { Spinner spinner = addUnmanagedSpinner(parent, numberHolder, defaultValue, minimumValue, maximumValue, helpId); - this.controlEnabledState(spinner); + this.bindEnabledState(spinner); return spinner; } @@ -1054,7 +1054,7 @@ public abstract class Pane<T extends Model> { String helpId) { DateTime dateTime = this.addUnmanagedDateTime(parent, hoursHolder, minutesHolder, secondsHolder, helpId); - this.controlEnabledState(dateTime); + this.bindEnabledState(dateTime); return dateTime; } @@ -1068,7 +1068,7 @@ public abstract class Pane<T extends Model> { PropertyValueModel<Boolean> enabledModel ) { DateTime dateTime = this.addUnmanagedDateTime(parent, hoursHolder, minutesHolder, secondsHolder, helpId); - this.controlEnabledState(enabledModel, dateTime); + this.bindEnabledState(enabledModel, dateTime); return dateTime; } @@ -1192,7 +1192,7 @@ public abstract class Pane<T extends Model> { String helpId) { List list = this.addUnmanagedList(container, selectionHolder, helpId); - this.controlEnabledState(list); + this.bindEnabledState(list); return list; } @@ -1241,7 +1241,7 @@ public abstract class Pane<T extends Model> { Text text = this.getWidgetFactory().createMultiLineText(container); text.setLayoutData(getFieldGridData()); - this.controlEnabledState(text); + this.bindEnabledState(text); return text; } @@ -1399,7 +1399,7 @@ public abstract class Pane<T extends Model> { Text text = this.getWidgetFactory().createPasswordText(container); text.setLayoutData(getFieldGridData()); - this.controlEnabledState(text); + this.bindEnabledState(text); return text; } @@ -1437,7 +1437,7 @@ public abstract class Pane<T extends Model> { final Runnable buttonAction) { Button button = this.getWidgetFactory().createPushButton(parent, buttonText); - controlEnabledState(button); + bindEnabledState(button); button.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { @@ -1672,7 +1672,7 @@ public abstract class Pane<T extends Model> { String helpId) { Table table = addUnmanagedTable(container, style, helpId); - this.controlEnabledState(table); + this.bindEnabledState(table); return table; } @@ -1758,7 +1758,7 @@ public abstract class Pane<T extends Model> { */ protected final Text addText(Composite container) { Text text = this.addUnmanagedText(container); - this.controlEnabledState(text); + this.bindEnabledState(text); return text; } @@ -1862,7 +1862,7 @@ public abstract class Pane<T extends Model> { PropertyValueModel<Boolean> enabledModel ) { Text text = this.addUnmanagedText(container, textHolder, helpId); - this.controlEnabledState(enabledModel, text); + this.bindEnabledState(enabledModel, text); return text; } @@ -2025,7 +2025,7 @@ public abstract class Pane<T extends Model> { booleanHolder, helpId, toggleButtonType); - this.controlEnabledState(button); + this.bindEnabledState(button); return button; } @@ -2049,7 +2049,7 @@ public abstract class Pane<T extends Model> { TriStateCheckBox checkBox = this.addUnmanagedTriStateCheckBox(parent, text, booleanHolder, helpId); - this.controlEnabledState(checkBox.getCheckBox()); + this.bindEnabledState(checkBox.getCheckBox()); return checkBox; } @@ -2119,7 +2119,7 @@ public abstract class Pane<T extends Model> { TriStateCheckBox checkBox = this.addUnmanagedTriStateCheckBox(parent, text, booleanHolder, helpId); - this.controlEnabledState(enabledModel, checkBox.getCheckBox()); + this.bindEnabledState(enabledModel, checkBox.getCheckBox()); SWTBindingTools.bindTextLabel(textModel, checkBox.getCheckBox()); @@ -2146,11 +2146,11 @@ public abstract class Pane<T extends Model> { * Control the <em>enabled</em> state of the specified controls with the * pane's {@link #enabledModel}. * <p> - * Use {@link #controlEnabledState(PropertyValueModel, Control...)} if the + * Use {@link #bindEnabledState(PropertyValueModel, Control...)} if the * controls might be disabled when the pane is enabled. */ - protected void controlEnabledState(Control... controls) { - SWTBindingTools.controlEnabledState(this.enabledModel, controls); + protected void bindEnabledState(Control... controls) { + SWTBindingTools.bindEnabledState(this.enabledModel, controls); } /** @@ -2159,11 +2159,11 @@ public abstract class Pane<T extends Model> { * If the specified boolean model returns <code>null</code> (which is * typical of aspect adapters), the controls will be disabled. * <p> - * Use {@link #controlEnabledState(Control...)} if the + * Use {@link #bindEnabledState(Control...)} if the * controls are only enabled when the pane is enabled. */ - protected void controlEnabledState(PropertyValueModel<Boolean> controlsEnabledModel, Control... controls) { - SWTBindingTools.controlEnabledState(this.andEnabledModel(controlsEnabledModel), controls); + protected void bindEnabledState(PropertyValueModel<Boolean> controlsEnabledModel, Control... controls) { + SWTBindingTools.bindEnabledState(this.andEnabledModel(controlsEnabledModel), controls); } /** |