| /******************************************************************************* |
| * Copyright (c) 2005, 2018 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Brad Reynolds - bugs 116920, 160000 |
| * Matthew Hall - bugs 260329, 260337 |
| *******************************************************************************/ |
| package org.eclipse.jface.tests.databinding.scenarios; |
| |
| import static org.junit.Assert.assertEquals; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Locale; |
| |
| import org.eclipse.core.databinding.beans.BeanProperties; |
| import org.eclipse.core.databinding.beans.BeansObservables; |
| import org.eclipse.core.databinding.observable.Realm; |
| import org.eclipse.core.databinding.observable.list.IObservableList; |
| import org.eclipse.core.databinding.observable.list.WritableList; |
| import org.eclipse.core.databinding.observable.value.IObservableValue; |
| import org.eclipse.jface.databinding.swt.SWTObservables; |
| import org.eclipse.jface.databinding.viewers.ViewerSupport; |
| import org.eclipse.jface.databinding.viewers.ViewersObservables; |
| import org.eclipse.jface.examples.databinding.model.Account; |
| import org.eclipse.jface.examples.databinding.model.Adventure; |
| import org.eclipse.jface.examples.databinding.model.Catalog; |
| import org.eclipse.jface.examples.databinding.model.Lodging; |
| import org.eclipse.jface.examples.databinding.model.SampleData; |
| import org.eclipse.jface.viewers.ComboViewer; |
| import org.eclipse.jface.viewers.ILabelProvider; |
| import org.eclipse.jface.viewers.IStructuredContentProvider; |
| import org.eclipse.jface.viewers.LabelProvider; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.CCombo; |
| import org.eclipse.swt.layout.FillLayout; |
| import org.eclipse.swt.widgets.Combo; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| public class ComboScenarios extends ScenariosTestCase { |
| |
| protected ComboViewer cviewer = null; |
| |
| protected Combo combo = null; |
| |
| protected Catalog catalog = null; |
| |
| ILabelProvider lodgingLabelProvider = new LabelProvider() { |
| @Override |
| public String getText(Object element) { |
| return ((Lodging) element).getName(); |
| } |
| }; |
| |
| ILabelProvider accountLabelProvider = new LabelProvider() { |
| @Override |
| public String getText(Object element) { |
| return ((Account) element).getCountry(); |
| } |
| }; |
| |
| @Override |
| @Before |
| public void setUp() throws Exception { |
| super.setUp(); |
| getComposite().setLayout(new FillLayout()); |
| |
| combo = new Combo(getComposite(), SWT.READ_ONLY | SWT.DROP_DOWN); |
| cviewer = new ComboViewer(combo); |
| |
| catalog = SampleData.CATALOG_2005; // Lodging source |
| } |
| |
| @Override |
| @After |
| public void tearDown() throws Exception { |
| combo.dispose(); |
| combo = null; |
| cviewer = null; |
| super.tearDown(); |
| } |
| |
| protected Object getViewerSelection() { |
| return cviewer.getStructuredSelection().getFirstElement(); |
| } |
| |
| /** |
| * @return the ComboViewer's domain object list |
| */ |
| protected List getViewerContent(ComboViewer cviewer) { |
| Object[] elements = ((IStructuredContentProvider) cviewer |
| .getContentProvider()).getElements(null); |
| if (elements != null) |
| return Arrays.asList(elements); |
| return null; |
| } |
| |
| /** |
| * |
| * @return the combo's items (String[]), which is the same thing as the |
| * Viewer's labels |
| * |
| */ |
| protected List getComboContent() { |
| String[] elements = combo.getItems(); |
| if (elements != null) |
| return Arrays.asList(elements); |
| return null; |
| } |
| |
| protected List getColumn(Object[] list, String feature) { |
| List result = new ArrayList(); |
| if (list == null || list.length == 0) |
| return result; |
| String getterName = "get" |
| + feature.substring(0, 1).toUpperCase(Locale.ENGLISH) |
| + feature.substring(1); |
| try { |
| Method getter = list[0].getClass().getMethod(getterName); |
| try { |
| for (int i = 0; i < list.length; i++) { |
| result.add(getter.invoke(list[i])); |
| } |
| } catch (IllegalArgumentException e) { |
| } catch (IllegalAccessException e) { |
| } catch (InvocationTargetException e) { |
| } |
| } catch (SecurityException e) { |
| } catch (NoSuchMethodException e) { |
| } |
| return result; |
| } |
| |
| /** |
| * This test case deal with the 3rd scenario, using vanilla bindings: Ensure |
| * a valid content and selection are bounded correctly Bind a collection of |
| * Lodgings to a ComboViewer Bind the ComboViewer's selection to the |
| * defaultLodging of an Adventure |
| * |
| * This test does not deal with null values, empty content, changed content, |
| * property change of content elements, etc. |
| * |
| */ |
| @Test |
| public void test_ROCombo_Scenario03_vanilla() { |
| IObservableList lodgings = BeansObservables.observeList(Realm |
| .getDefault(), catalog, "lodgings"); |
| ViewerSupport.bind(cviewer, lodgings, BeanProperties.value( |
| Lodging.class, "name")); |
| |
| Adventure skiAdventure = SampleData.WINTER_HOLIDAY; // selection will |
| |
| // Ensure that cv's content now has the catalog's lodgings |
| assertArrayEquals(catalog.getLodgings(), getViewerContent(cviewer) |
| .toArray()); |
| |
| // Ensure that the cv's labels are the same as the lodging descriptions |
| assertEquals(getColumn(catalog.getLodgings(), "name"), |
| getComboContent()); |
| |
| getDbc().bindValue(ViewersObservables.observeSingleSelection(cviewer), |
| BeansObservables.observeValue(skiAdventure, "defaultLodging")); |
| |
| // Check to see that the initial selection is the currentDefault Lodging |
| assertEquals(getViewerSelection(), skiAdventure.getDefaultLodging()); |
| |
| // Change the selection of the ComboViewer to all possible lodgings, and |
| // verify that skiAdventure's default lodging was changed accordingly |
| for (int i = 0; i < catalog.getLodgings().length; i++) { |
| Object selection = catalog.getLodgings()[i]; |
| cviewer.setSelection(new StructuredSelection(selection)); |
| assertEquals(selection, skiAdventure.getDefaultLodging()); |
| assertEquals(getViewerSelection(), skiAdventure.getDefaultLodging()); |
| } |
| |
| } |
| |
| /** |
| * This test case deal with the 3rd scenario, and focuses on the collection |
| * binding to the combo. It will bind a collection, add/remove/change |
| * elements in the collection, and change element's properties to ensure |
| * that the combo's labels were updated appropriatly. |
| * |
| * it also induce null values in properties, and elments. |
| * |
| * This test does not deal with the combo's selection. |
| */ |
| @Test |
| public void test_ROCombo_Scenario03_collectionBindings() { |
| // column binding |
| // Bind the ComboViewer's content to the available lodging |
| IObservableList lodgings = BeansObservables.observeList(Realm |
| .getDefault(), catalog, "lodgings"); |
| ViewerSupport.bind(cviewer, lodgings, BeanProperties.value( |
| Lodging.class, "name")); |
| |
| // Ensure that cv's content now has the catalog's lodgings |
| assertArrayEquals(catalog.getLodgings(), getViewerContent(cviewer) |
| .toArray()); |
| |
| // Ensure that the cv's labels are the same as the lodging descriptions |
| assertEquals(getColumn(catalog.getLodgings(), "name"), |
| getComboContent()); |
| |
| // Add a lodging in the middle (not supported by the model right now) |
| // Lodging lodging = SampleData.FACTORY.createLodging(); |
| // lodging.setName("Middle Lodging"); |
| // catalog.addLodging(lodging); |
| // assertEquals(getViewerContent(cviewer).get(2), lodging); |
| |
| // Add a lodging at the end |
| Lodging lodging = SampleData.FACTORY.createLodging(); |
| lodging.setName("End Lodging"); |
| catalog.addLodging(lodging); |
| int index = getComboContent().size() - 1; |
| assertEquals(getViewerContent(cviewer).get(index), lodging); |
| |
| // Delete the first Lodging |
| catalog.removeLodging(catalog.getLodgings()[0]); |
| // Ensure that the cv's labels are the same as the lodging descriptions |
| assertEquals(getColumn(catalog.getLodgings(), "name"), |
| getComboContent()); |
| |
| // Delete middle Lodging |
| catalog.removeLodging(catalog.getLodgings()[2]); |
| // Ensure that the cv's labels are the same as the lodging descriptions |
| assertEquals(getColumn(catalog.getLodgings(), "name"), |
| getComboContent()); |
| |
| // Change the names of all Lodging |
| for (int i = 0; i < catalog.getLodgings().length; i++) { |
| Lodging l = catalog.getLodgings()[i]; |
| l.setName("Changed: " + l.getName()); |
| } |
| spinEventLoop(0); // force Async. efforts |
| assertEquals(getColumn(catalog.getLodgings(), "name"), |
| getComboContent()); |
| |
| // Set to null value |
| Lodging l = catalog.getLodgings()[0]; |
| assertEquals(combo.getItem(0), l.getName()); |
| l.setName(null); |
| assertEquals("", combo.getItem(0)); |
| |
| // set to empty list |
| while (catalog.getLodgings().length > 0) { |
| catalog.removeLodging(catalog.getLodgings()[0]); |
| assertEquals(getColumn(catalog.getLodgings(), "name"), |
| getComboContent()); |
| } |
| } |
| |
| /** |
| * This scenario tests a simple SWT combo with a set item list where the |
| * selection is bouded to a String property |
| */ |
| // @Test |
| // public void test_ROCombo_Scenario01() { |
| // |
| // // Read-Only Combo will not change its text property on a call to |
| // // setText() |
| // |
| // String[] items = new String[] { "FairyLand", "TuneLand", "NoWereLand", |
| // "TinkerLand", "DreamLand" }; |
| // combo.setItems(items); |
| // Account account = catalog.getAccounts()[0]; |
| // |
| // // simple Combo's selection bound to the Account's country property |
| // getDbc().bind(new Property(combo, SWTProperties.SELECTION), |
| // new Property(account, "country"), null); |
| // |
| // // Drive the combo selection |
| // int index = 3; |
| // combo.setText(items[index]); // this should drive the selection |
| // assertEquals(account.getCountry(), items[index]); |
| // |
| // // Set the country, and ensure selection is set property |
| // index = 1; |
| // account.setCountry(items[index]); |
| // assertEquals(index, combo.getSelectionIndex()); |
| // assertEquals(combo.getText(), items[index]); |
| // |
| // index = combo.getSelectionIndex(); |
| // String txt = combo.getText(); |
| // // Set the country to something that is not in the Combo's list |
| // account.setCountry("FooBar"); |
| // // Combo's selection will not Change |
| // assertEquals(combo.getSelectionIndex(), index); |
| // assertEquals(combo.getText(), txt); |
| // |
| // } |
| /** |
| * This scenario tests a simple SWT combo that is bound to a list of Country |
| * objects. The Country object's name property is listed in the Combo. |
| * |
| * The Combo's selection is bounded to the Country property of an Account. |
| */ |
| // @Test |
| // public void test_ROCombo_Scenario02_SWTCombo() { |
| // |
| // // Create a list of Strings for the countries |
| // IObservableList list = new WritableList(); |
| // for (int i = 0; i < catalog.getAccounts().length; i++) |
| // list.add(catalog.getAccounts()[i].getCountry()); |
| // |
| // // Bind the combo's content to that of the String based list |
| // getDbc().bind(combo, list, null); |
| // assertEquals(Arrays.asList(combo.getItems()), list); |
| // |
| // Account account = catalog.getAccounts()[0]; |
| // |
| // // simple Combo's selection bound to the Account's country property |
| // getDbc().bind(new Property(combo, SWTProperties.SELECTION), |
| // new Property(account, "country"), null); |
| // |
| // // Drive the combo selection |
| // String selection = (String) list.get(2); |
| // combo.setText(selection); // this should drive the selection |
| // assertEquals(account.getCountry(), selection); |
| // |
| // } |
| /** |
| * This scenario tests a simple SWT combo that is bound to a list of Country |
| * objects. The Country object's name property is listed in the Combo. |
| * |
| * The Combo's selection is bounded to the Country property of an Account. |
| */ |
| // @Test |
| // public void test_ROCombo_Scenario02_ComboViewer() { |
| // |
| // // Account label provider will fill the combo with the country |
| // cviewer.setLabelProvider(accountLabelProvider); |
| // // Bind the ComboViewer's content to the available accounts |
| // getDbc().bind( |
| // cviewer, |
| // new ListModelDescription(new Property(catalog, "accounts"), |
| // "country"), null); |
| // |
| // // Ensure that cv's content now has the catalog's accounts |
| // assertArrayEquals(catalog.getAccounts(), getViewerContent(cviewer) |
| // .toArray()); |
| // // Ensure that the cv's labels are the same as the account countries |
| // assertEquals(getColumn(catalog.getAccounts(), "country"), |
| // getComboContent()); |
| // |
| // Account account = SampleData.FACTORY.createAccount(); |
| // |
| // // Use the Viewers visual Combo (Strings) to set the account's country |
| // getDbc().bind(new Property(combo, SWTProperties.SELECTION), |
| // new Property(account, "country"), null); |
| // |
| // // Change the selection of the ComboViewer to all possible accounts, and |
| // // verify that the account's Country is being changed correctly. |
| // for (int i = 0; i < catalog.getAccounts().length; i++) { |
| // Account selection = catalog.getAccounts()[i]; |
| // cviewer.setSelection(new StructuredSelection(selection)); |
| // assertEquals(selection.getCountry(), account.getCountry()); |
| // } |
| // |
| // } |
| /** |
| * This test ensure that multiple combos can be bound to the same deomain |
| * model |
| */ |
| @Test |
| public void test_ROCombo_multipleBindings() { |
| Adventure skiAdventure = SampleData.WINTER_HOLIDAY; // for selection |
| |
| // Bind the ComboViewer's content to the available lodging |
| IObservableList lodgings = BeansObservables.observeList(Realm |
| .getDefault(), catalog, "lodgings"); |
| ViewerSupport.bind(cviewer, lodgings, BeanProperties.value( |
| Lodging.class, "name")); |
| |
| // Ensure that cv's content now has the catalog's lodgings |
| assertArrayEquals(catalog.getLodgings(), getViewerContent(cviewer) |
| .toArray()); |
| |
| // Ensure that the cv's labels are the same as the lodging descriptions |
| assertEquals(getColumn(catalog.getLodgings(), "name"), |
| getComboContent()); |
| |
| ComboViewer otherViewer = new ComboViewer(getComposite(), SWT.NONE); |
| ViewerSupport.bind(otherViewer, lodgings, BeanProperties.value( |
| Lodging.class, "name")); |
| |
| // Ensure that cv's content now has the catalog's lodgings |
| assertArrayEquals(catalog.getLodgings(), getViewerContent(otherViewer) |
| .toArray()); |
| |
| // Bind both selections to the same thing |
| IObservableValue selection = ViewersObservables |
| .observeSingleSelection(cviewer); |
| getDbc().bindValue(selection, |
| BeansObservables.observeValue(skiAdventure, "defaultLodging")); |
| |
| IObservableValue otherSelection = ViewersObservables |
| .observeSingleSelection(otherViewer); |
| getDbc().bindValue(otherSelection, |
| BeansObservables.observeValue(skiAdventure, "defaultLodging")); |
| |
| Lodging lodging = catalog.getLodgings()[0]; |
| |
| // Ensure that setting the selection is driven forward to the other |
| // combo |
| cviewer.setSelection(new StructuredSelection(lodging)); |
| assertEquals(cviewer.getStructuredSelection().getFirstElement(), |
| otherViewer.getStructuredSelection().getFirstElement()); |
| |
| // Change the list of one combo, and ensure it updates the other combo |
| catalog.removeLodging(lodging); |
| assertEquals(getViewerContent(cviewer), getViewerContent(otherViewer)); |
| |
| } |
| |
| /** |
| * This scenario tests a simple SWT CCombo that is bound to a list of |
| * Country objects. The Country object's name property is listed in the |
| * Combo. |
| * |
| * The Combo's selection is bounded to the Country property of an Account. |
| */ |
| @Test |
| public void test_ROCombo_SWTCCombo() { |
| |
| // Create a list of Strings for the countries |
| IObservableList list = new WritableList(); |
| for (int i = 0; i < catalog.getAccounts().length; i++) |
| list.add(catalog.getAccounts()[i].getCountry()); |
| |
| CCombo ccombo = new CCombo(getComposite(), SWT.READ_ONLY |
| | SWT.DROP_DOWN); |
| |
| // Bind the combo's content to that of the String based list |
| getDbc().bindList(SWTObservables.observeItems(ccombo), list); |
| assertEquals(Arrays.asList(ccombo.getItems()), list); |
| |
| Account account = catalog.getAccounts()[0]; |
| |
| // simple Combo's selection bound to the Account's country property |
| IObservableValue comboSelection = SWTObservables |
| .observeSelection(ccombo); |
| getDbc().bindValue(comboSelection, |
| BeansObservables.observeValue(account, "country")); |
| |
| // Drive the combo selection |
| String selection = (String) list.get(2); |
| ccombo.setText(selection); // this should drive the selection |
| assertEquals(account.getCountry(), selection); |
| |
| } |
| |
| /** |
| * This scenario tests a simple SWT CCombo that is bound to a list of |
| * Country objects. The Country object's name property is listed in the |
| * Combo. |
| * |
| * The Combo's selection is bounded to the Country property of an Account. |
| */ |
| @Test |
| public void test_WCombo_SWTCCombo() { |
| |
| // Create a list of Strings for the countries |
| IObservableList list = new WritableList(); |
| for (int i = 0; i < catalog.getAccounts().length; i++) |
| list.add(catalog.getAccounts()[i].getCountry()); |
| |
| CCombo ccombo = new CCombo(getComposite(), SWT.READ_ONLY |
| | SWT.DROP_DOWN); |
| |
| // Bind the combo's content to that of the String based list |
| getDbc().bindList(SWTObservables.observeItems(ccombo), list); |
| assertEquals(Arrays.asList(ccombo.getItems()), list); |
| |
| Account account = catalog.getAccounts()[0]; |
| |
| // simple Combo's selection bound to the Account's country property |
| IObservableValue comboSelection = SWTObservables |
| .observeSelection(ccombo); |
| getDbc().bindValue(comboSelection, |
| BeansObservables.observeValue(account, "country")); |
| |
| // Drive the combo selection |
| String selection = (String) list.get(2); |
| ccombo.setText(selection); // this should drive the selection |
| assertEquals(account.getCountry(), selection); |
| |
| selection = (String) list.get(1); |
| account.setCountry(selection); |
| assertEquals(selection, ccombo.getItem(ccombo.getSelectionIndex())); |
| assertEquals(selection, ccombo.getText()); |
| |
| selection = "country not in list"; |
| account.setCountry(selection); |
| assertEquals(-1, ccombo.getSelectionIndex()); |
| assertEquals(selection, ccombo.getText()); |
| } |
| |
| /** |
| * This scenario tests a simple SWT CCombo that is bound to a list of |
| * Country objects. The Country object's name property is listed in the |
| * Combo. |
| * |
| * The Combo's selection is bounded to the Country property of an Account. |
| */ |
| @Test |
| public void test_ROCombo_SWTList() { |
| |
| // Create a list of Strings for the countries |
| IObservableList list = new WritableList(); |
| for (int i = 0; i < catalog.getAccounts().length; i++) |
| list.add(catalog.getAccounts()[i].getCountry()); |
| |
| org.eclipse.swt.widgets.List swtlist = new org.eclipse.swt.widgets.List( |
| getComposite(), SWT.READ_ONLY | SWT.SINGLE); |
| |
| // Bind the combo's content to that of the String based list |
| getDbc().bindList(SWTObservables.observeItems(swtlist), list); |
| assertEquals(Arrays.asList(swtlist.getItems()), list); |
| |
| Account account = catalog.getAccounts()[0]; |
| |
| // simple Combo's selection bound to the Account's country property |
| IObservableValue listSelection = SWTObservables |
| .observeSelection(swtlist); |
| getDbc().bindValue(listSelection, |
| BeansObservables.observeValue(account, "country")); |
| |
| String selection = (String) list.get(2); |
| swtlist.select(2); // this should drive the selection |
| swtlist.notifyListeners(SWT.Selection, null); // Force notification |
| assertEquals(account.getCountry(), selection); |
| |
| } |
| |
| } |