/******************************************************************************* * Copyright (c) 2005, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Brad Reynolds - bugs 116920, 160000 * Matthew Hall - bugs 260329, 260337 *******************************************************************************/ package org.eclipse.jface.tests.databinding.scenarios; 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; 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 protected 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 protected 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, new Class[0]); try { for (int i = 0; i < list.length; i++) { result.add(getter.invoke(list[i], new Object[0])); } } 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. * */ 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. */ 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 */ // 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. */ // 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. */ // 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 */ 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. */ 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. */ 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. */ 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); } }