diff options
Diffstat (limited to 'jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/utility/swt/ListBoxSelectionBinding.java')
-rw-r--r-- | jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/utility/swt/ListBoxSelectionBinding.java | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/utility/swt/ListBoxSelectionBinding.java b/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/utility/swt/ListBoxSelectionBinding.java new file mode 100644 index 0000000000..f0568663b8 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/utility/swt/ListBoxSelectionBinding.java @@ -0,0 +1,305 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 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.ui.internal.utility.swt; + +import java.util.ArrayList; +import java.util.Arrays; + +import org.eclipse.jpt.ui.internal.listeners.SWTCollectionChangeListenerWrapper; +import org.eclipse.jpt.utility.internal.ArrayTools; +import org.eclipse.jpt.utility.internal.StringTools; +import org.eclipse.jpt.utility.internal.Tools; +import org.eclipse.jpt.utility.model.event.CollectionAddEvent; +import org.eclipse.jpt.utility.model.event.CollectionChangeEvent; +import org.eclipse.jpt.utility.model.event.CollectionClearEvent; +import org.eclipse.jpt.utility.model.event.CollectionRemoveEvent; +import org.eclipse.jpt.utility.model.listener.CollectionChangeListener; +import org.eclipse.jpt.utility.model.value.CollectionValueModel; +import org.eclipse.jpt.utility.model.value.ListValueModel; +import org.eclipse.jpt.utility.model.value.WritableCollectionValueModel; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +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. + * + * @see ListValueModel + * @see WritableCollectionValueModel + * @see List + * @see SWTTools + */ +@SuppressWarnings("nls") +final class ListBoxSelectionBinding<E> + implements ListWidgetModelBinding.SelectionBinding +{ + // ***** model + /** + * The underlying list model. + */ + private final ListValueModel<E> listModel; + + /** + * A writable value model on the underlying model selections. + */ + private final WritableCollectionValueModel<E> selectedItemsModel; + + /** + * A listener that allows us to synchronize the list box's selection with + * the model selections. + */ + private final CollectionChangeListener selectedItemsChangeListener; + + // ***** UI + /** + * 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 + * with the list box's selection. + */ + private final SelectionListener listBoxSelectionListener; + + + // ********** constructor ********** + + /** + * Constructor - all parameters are required. + */ + ListBoxSelectionBinding( + ListValueModel<E> listModel, + WritableCollectionValueModel<E> selectedItemsModel, + List listBox + ) { + super(); + if ((listModel == null) || (selectedItemsModel == null) || (listBox == null)) { + throw new NullPointerException(); + } + this.listModel = listModel; + this.selectedItemsModel = selectedItemsModel; + this.listBox = listBox; + + this.selectedItemsChangeListener = this.buildSelectedItemsChangeListener(); + this.selectedItemsModel.addCollectionChangeListener(CollectionValueModel.VALUES, this.selectedItemsChangeListener); + + this.listBoxSelectionListener = this.buildListBoxSelectionListener(); + this.listBox.addSelectionListener(this.listBoxSelectionListener); + } + + + // ********** initialization ********** + + private CollectionChangeListener buildSelectedItemsChangeListener() { + return new SWTCollectionChangeListenerWrapper(this.buildSelectedItemsChangeListener_()); + } + + 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"; + } + }; + } + + 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"; + } + }; + } + + + // ********** ListWidgetModelBinding.SelectionBinding implementation ********** + + /** + * Modifying the list box's selected items programmatically does not + * trigger a SelectionEvent. + * + * 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 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[] old = ArrayTools.sort(this.listBox.getSelectionIndices()); + select = ArrayTools.sort(select); + if ( ! Arrays.equals(select, old)) { + this.listBox.deselect(deselect); + this.listBox.select(select); + } + } + + public void dispose() { + this.listBox.removeSelectionListener(this.listBoxSelectionListener); + this.selectedItemsModel.removeCollectionChangeListener(CollectionValueModel.VALUES, this.selectedItemsChangeListener); + } + + + // ********** selected items ********** + + void selectedItemsAdded(CollectionAddEvent event) { + if ( ! this.listBox.isDisposed()) { + this.selectedItemsAdded_(event); + } + } + + /** + * Modifying the list box's selected items programmatically does not + * trigger a SelectionEvent. + */ + private void selectedItemsAdded_(CollectionAddEvent event) { + int[] indices = new int[event.getItemsSize()]; + int i = 0; + for (E item : this.getItems(event)) { + 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) { + if ( ! this.listBox.isDisposed()) { + this.selectedItemsRemoved_(event); + } + } + + /** + * Modifying the list box's selected items programmatically does not + * trigger a SelectionEvent. + */ + private void selectedItemsRemoved_(CollectionRemoveEvent event) { + int[] indices = new int[event.getItemsSize()]; + int i = 0; + for (E item : this.getItems(event)) { + 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) { + if ( ! this.listBox.isDisposed()) { + this.selectedItemsCleared_(event); + } + } + + /** + * Modifying the list box's selected items programmatically does not + * trigger a SelectionEvent. + */ + private void selectedItemsCleared_(@SuppressWarnings("unused") CollectionClearEvent event) { + this.listBox.deselectAll(); + } + + void selectedItemsChanged(CollectionChangeEvent event) { + if ( ! this.listBox.isDisposed()) { + this.selectedItemsChanged_(event); + } + } + + private void selectedItemsChanged_(@SuppressWarnings("unused") CollectionChangeEvent event) { + this.synchronizeListWidgetSelection(); + } + + private int indexOf(E item) { + int len = this.listModel.size(); + for (int i = 0; i < len; i++) { + if (Tools.valuesAreEqual(this.listModel.get(i), item)) { + return 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); + } + } + + private void listBoxSelectionChanged_(@SuppressWarnings("unused") SelectionEvent event) { + this.selectedItemsModel.setValues(this.getListBoxSelectedItems()); + } + + private Iterable<E> getListBoxSelectedItems() { + ArrayList<E> selectedItems = new ArrayList<E>(this.listBox.getSelectionCount()); + for (int selectionIndex : this.listBox.getSelectionIndices()) { + selectedItems.add(this.listModel.get(selectionIndex)); + } + return selectedItems; + } + + + // ********** standard methods ********** + + @Override + public String toString() { + return StringTools.buildToStringFor(this, this.selectedItemsModel); + } + +} |