1d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardpackage autotest.common.ui; 2d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 3d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardimport com.google.gwt.event.dom.client.ChangeEvent; 4d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardimport com.google.gwt.event.dom.client.ChangeHandler; 5d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardimport com.google.gwt.event.dom.client.ClickEvent; 6d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardimport com.google.gwt.event.dom.client.ClickHandler; 7d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardimport com.google.gwt.event.dom.client.DoubleClickEvent; 8d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardimport com.google.gwt.event.dom.client.DoubleClickHandler; 9d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardimport com.google.gwt.event.dom.client.HasClickHandlers; 10d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardimport com.google.gwt.event.shared.GwtEvent; 11d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardimport com.google.gwt.event.shared.HandlerRegistration; 12d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 13d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardimport java.util.ArrayList; 14d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardimport java.util.Collections; 15d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardimport java.util.HashSet; 16d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardimport java.util.List; 17d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardimport java.util.Set; 18d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 19d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 20d9e04c1a7950691cc348e70fa2470f8c414ae94fshowardpublic class MultiListSelectPresenter implements ClickHandler, DoubleClickHandler, ChangeHandler { 21d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward /* Simple display showing two list boxes, one of available items and one of selected items */ 22d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public interface DoubleListDisplay { 23d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public HasClickHandlers getAddAllButton(); 24d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public HasClickHandlers getAddButton(); 25d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public HasClickHandlers getRemoveButton(); 26d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public HasClickHandlers getRemoveAllButton(); 27d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public HasClickHandlers getMoveUpButton(); 28d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public HasClickHandlers getMoveDownButton(); 29d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public SimplifiedList getAvailableList(); 30d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public SimplifiedList getSelectedList(); 31d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward // ListBoxes don't support DoubleClickEvents themselves, so the display needs to handle them 32d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public HandlerRegistration addDoubleClickHandler(DoubleClickHandler handler); 33d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 34d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 356f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li /* Optional additional display allowing toggle between a simple ListBox and a 366f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li * DoubleListSelector 37d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward */ 38d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public interface ToggleDisplay { 39d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public SimplifiedList getSingleSelector(); 40d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public ToggleControl getToggleMultipleLink(); 41d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void setDoubleListVisible(boolean doubleListVisible); 42d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 43d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 44d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public interface GeneratorHandler { 45d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward /** 46d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward * The given generated Item was just deselected; handle any necessary cleanup. 47d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward */ 48d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void onRemoveGeneratedItem(Item generatedItem); 49d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 50d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 51d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public static class Item implements Comparable<Item> { 52d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public String name; 53d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public String value; 54d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward // a generated item is destroyed when deselected. 55d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public boolean isGeneratedItem; 56d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 57d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private boolean selected; 58d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 59d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private Item(String name, String value) { 60d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward this.name = name; 61d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward this.value = value; 62d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 63d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 64d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public static Item createItem(String name, String value) { 65d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return new Item(name, value); 66d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 67d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 68d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public static Item createGeneratedItem(String name, String value) { 69d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward Item item = new Item(name, value); 70d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward item.isGeneratedItem = true; 71d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return item; 72d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 73d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 74d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public int compareTo(Item item) { 75d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return name.compareTo(item.name); 76d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 77d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 78d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 79d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public boolean equals(Object obj) { 80d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (!(obj instanceof Item)) { 81d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return false; 82d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 83d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward Item other = (Item) obj; 84d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return name.equals(other.name); 85d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 86d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 87d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 88d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public int hashCode() { 89d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return name.hashCode(); 90d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 91d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 92d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 93d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public String toString() { 94d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return "Item<" + name + ", " + value + ">"; 95d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 966f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li 978b0ea2285c1327a686ff0b6ab245915e7fd20094showard private boolean isSelected() { 98d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (isGeneratedItem) { 99d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return true; 100d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 101d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return selected; 102d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 1036f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li 1048b0ea2285c1327a686ff0b6ab245915e7fd20094showard private void setSelected(boolean selected) { 1058b0ea2285c1327a686ff0b6ab245915e7fd20094showard assert !isGeneratedItem; 106d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward this.selected = selected; 107d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 108d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 109d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 1108b0ea2285c1327a686ff0b6ab245915e7fd20094showard /** 1118b0ea2285c1327a686ff0b6ab245915e7fd20094showard * Null object to support displays that don't do toggling. 1128b0ea2285c1327a686ff0b6ab245915e7fd20094showard */ 113d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private static class NullToggleDisplay implements ToggleDisplay { 114d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 115d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public SimplifiedList getSingleSelector() { 116d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return new SimplifiedList() { 117d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 118d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void addItem(String name, String value) { 119d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return; 120d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 121d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 122d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 123d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void clear() { 124d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return; 125d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 126d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 127d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 128d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public String getSelectedName() { 129d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return ""; 130d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 131d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 132d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 133d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void selectByName(String name) { 134d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return; 135d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 136d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 137d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 138d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public HandlerRegistration addChangeHandler(ChangeHandler handler) { 139d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward throw new UnsupportedOperationException(); 140d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 1416f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li 1426f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li @Override 1436f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li public void setEnabled(boolean enabled) { 1446f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li throw new UnsupportedOperationException(); 1456f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li } 146d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward }; 147d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 148d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 149d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 150d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public ToggleControl getToggleMultipleLink() { 151d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return new ToggleControl() { 152d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 153d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public HandlerRegistration addClickHandler(ClickHandler handler) { 154d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward throw new UnsupportedOperationException(); 155d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 156d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 157d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 158d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void fireEvent(GwtEvent<?> event) { 159d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward throw new UnsupportedOperationException(); 160d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 161d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 162d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 163d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public boolean isActive() { 164d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return true; 165d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 166d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 167d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 168d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void setActive(boolean active) { 169d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return; 170d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 171d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward }; 172d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 173d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 174d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 175d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void setDoubleListVisible(boolean doubleListVisible) { 176d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return; 177d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 178d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 179d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 180d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private List<Item> items = new ArrayList<Item>(); 181d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward // need a second list to track ordering 182d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private List<Item> selectedItems = new ArrayList<Item>(); 183d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private DoubleListDisplay display; 184d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private ToggleDisplay toggleDisplay = new NullToggleDisplay(); 185d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private GeneratorHandler generatorHandler; 186d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 187d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void setGeneratorHandler(GeneratorHandler handler) { 188d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward this.generatorHandler = handler; 189d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 190d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 191d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void bindDisplay(DoubleListDisplay display) { 192d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward this.display = display; 193d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward display.getAddAllButton().addClickHandler(this); 194d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward display.getAddButton().addClickHandler(this); 195d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward display.getRemoveButton().addClickHandler(this); 196d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward display.getRemoveAllButton().addClickHandler(this); 197d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward display.getMoveUpButton().addClickHandler(this); 198d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward display.getMoveDownButton().addClickHandler(this); 199d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward display.addDoubleClickHandler(this); 200d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 201d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 202d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void bindToggleDisplay(ToggleDisplay toggleDisplay) { 203d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward this.toggleDisplay = toggleDisplay; 204d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward toggleDisplay.getSingleSelector().addChangeHandler(this); 205d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward toggleDisplay.getToggleMultipleLink().addClickHandler(this); 206d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward toggleDisplay.getToggleMultipleLink().setActive(false); 207d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 208d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 209d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private boolean verifyConsistency() { 210d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward // check consistency of selectedItems 211d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward for (Item item : items) { 212d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (item.isSelected() && !selectedItems.contains(item)) { 2136f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li throw new RuntimeException("selectedItems is inconsistent, missing: " 214d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward + item.toString()); 215d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 216d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 217d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return true; 218d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 219d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 220d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void addItem(Item item) { 2218b0ea2285c1327a686ff0b6ab245915e7fd20094showard if (item.isGeneratedItem && isItemPresent(item)) { 22216ab5250da1e2e5fb1549774063a8099ce4fdbb8showard return; 223d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 224d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward items.add(item); 225d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward Collections.sort(items); 226d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (item.isSelected()) { 227d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward selectedItems.add(item); 228d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 229d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward assert verifyConsistency(); 230d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward refresh(); 231d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 23216ab5250da1e2e5fb1549774063a8099ce4fdbb8showard 23316ab5250da1e2e5fb1549774063a8099ce4fdbb8showard private boolean isItemPresent(Item item) { 23416ab5250da1e2e5fb1549774063a8099ce4fdbb8showard return Collections.binarySearch(items, item) >= 0; 23516ab5250da1e2e5fb1549774063a8099ce4fdbb8showard } 2366f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li 237d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private void removeItem(Item item) { 238d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward items.remove(item); 239d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (item.isSelected()) { 240d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward selectedItems.remove(item); 241d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 242d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward assert verifyConsistency(); 243d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward refresh(); 244d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 245d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 2468b0ea2285c1327a686ff0b6ab245915e7fd20094showard public void clearItems() { 2478b0ea2285c1327a686ff0b6ab245915e7fd20094showard for (Item item : new ArrayList<Item>(items)) { 2488b0ea2285c1327a686ff0b6ab245915e7fd20094showard removeItem(item); 2498b0ea2285c1327a686ff0b6ab245915e7fd20094showard } 250d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 251d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 252d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private void refreshSingleSelector() { 253d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward SimplifiedList selector = toggleDisplay.getSingleSelector(); 254d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 255d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (!selectedItems.isEmpty()) { 256d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward assert selectedItems.size() == 1; 257d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 258d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 259d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward selector.clear(); 260d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward for (Item item : items) { 261d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward selector.addItem(item.name, item.value); 262d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (item.isSelected()) { 263d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward selector.selectByName(item.name); 264d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 265d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 266d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 267d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 268d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private void refreshMultipleSelector() { 269d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward display.getAvailableList().clear(); 270d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward for (Item item : items) { 271d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (!item.isSelected()) { 272d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward display.getAvailableList().addItem(item.name, item.value); 273d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 274d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 275d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 276d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward display.getSelectedList().clear(); 277d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward for (Item item : selectedItems) { 278d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward display.getSelectedList().addItem(item.name, item.value); 279d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 280d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 281d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 282d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private void refresh() { 283d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (selectedItems.size() > 1) { 284d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward switchToMultiple(); 285d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 286d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (isMultipleSelectActive()) { 287d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward refreshMultipleSelector(); 288d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } else { 289d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward // single selector always needs something selected 2908b0ea2285c1327a686ff0b6ab245915e7fd20094showard if (selectedItems.size() == 0 && !items.isEmpty()) { 2918b0ea2285c1327a686ff0b6ab245915e7fd20094showard selectItem(items.get(0)); 292d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 293d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward refreshSingleSelector(); 294a29e963afc9de0ab086b5b2bea2e43ff68d81038showard } 295d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 296d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 297d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private void selectItem(Item item) { 2988b0ea2285c1327a686ff0b6ab245915e7fd20094showard item.setSelected(true); 2998b0ea2285c1327a686ff0b6ab245915e7fd20094showard selectedItems.add(item); 300d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward assert verifyConsistency(); 301d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 3026f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li 303d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void selectItemByName(String name) { 304d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward selectItem(getItemByName(name)); 305d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward refresh(); 306d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 3078b0ea2285c1327a686ff0b6ab245915e7fd20094showard 3088b0ea2285c1327a686ff0b6ab245915e7fd20094showard /** 3098b0ea2285c1327a686ff0b6ab245915e7fd20094showard * Set the set of selected items by specifying item names. All names must exist in the set of 3108b0ea2285c1327a686ff0b6ab245915e7fd20094showard * header fields. 3118b0ea2285c1327a686ff0b6ab245915e7fd20094showard */ 312d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void setSelectedItemsByName(List<String> names) { 313d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward for (String itemName : names) { 314d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward Item item = getItemByName(itemName); 315d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (!item.isSelected()) { 316d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward selectItem(item); 317d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 318d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 319a29e963afc9de0ab086b5b2bea2e43ff68d81038showard 320d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward Set<String> selectedNames = new HashSet<String>(names); 321a29e963afc9de0ab086b5b2bea2e43ff68d81038showard for (Item item : getItemsCopy()) { 322d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (item.isSelected() && !selectedNames.contains(item.name)) { 323d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward deselectItem(item); 324d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 325d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 326d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 327d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (selectedItems.size() < 2) { 328d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward switchToSingle(); 329d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 330d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward refresh(); 331d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 332d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 3338b0ea2285c1327a686ff0b6ab245915e7fd20094showard /** 3346f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li * Set the set of selected items, silently dropping any that don't exist in the header field 3358b0ea2285c1327a686ff0b6ab245915e7fd20094showard * list. 3368b0ea2285c1327a686ff0b6ab245915e7fd20094showard */ 3378b0ea2285c1327a686ff0b6ab245915e7fd20094showard public void restoreSelectedItems(List<Item> items) { 3388b0ea2285c1327a686ff0b6ab245915e7fd20094showard List<String> currentItems = new ArrayList<String>(); 3398b0ea2285c1327a686ff0b6ab245915e7fd20094showard for (Item item : items) { 3408b0ea2285c1327a686ff0b6ab245915e7fd20094showard if (hasItemName(item.name)) { 3418b0ea2285c1327a686ff0b6ab245915e7fd20094showard currentItems.add(item.name); 3428b0ea2285c1327a686ff0b6ab245915e7fd20094showard } 3438b0ea2285c1327a686ff0b6ab245915e7fd20094showard } 3448b0ea2285c1327a686ff0b6ab245915e7fd20094showard setSelectedItemsByName(currentItems); 3458b0ea2285c1327a686ff0b6ab245915e7fd20094showard } 3468b0ea2285c1327a686ff0b6ab245915e7fd20094showard 347d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private void deselectItem(Item item) { 348d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (item.isGeneratedItem) { 349d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward removeItem(item); 3508b0ea2285c1327a686ff0b6ab245915e7fd20094showard generatorHandler.onRemoveGeneratedItem(item); 351d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } else { 352d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward item.setSelected(false); 353d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward selectedItems.remove(item); 354d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 355d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward assert verifyConsistency(); 356d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 357d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 358d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public List<Item> getSelectedItems() { 3598b0ea2285c1327a686ff0b6ab245915e7fd20094showard return new ArrayList<Item>(selectedItems); 360d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 361d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 362d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private boolean isMultipleSelectActive() { 363d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return toggleDisplay.getToggleMultipleLink().isActive(); 364d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 365d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 366d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private void switchToSingle() { 367d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward // reduce selection to the first selected item 368d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward while (selectedItems.size() > 1) { 369d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward deselectItem(selectedItems.get(1)); 370d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 371d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 372d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward toggleDisplay.setDoubleListVisible(false); 373d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward toggleDisplay.getToggleMultipleLink().setActive(false); 374d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 375d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 376d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private void switchToMultiple() { 377d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward toggleDisplay.setDoubleListVisible(true); 378d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward toggleDisplay.getToggleMultipleLink().setActive(true); 379d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 380d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 381d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private Item getItemByName(String name) { 3828b0ea2285c1327a686ff0b6ab245915e7fd20094showard Item item = findItem(name); 3838b0ea2285c1327a686ff0b6ab245915e7fd20094showard if (item != null) { 3848b0ea2285c1327a686ff0b6ab245915e7fd20094showard return item; 3858b0ea2285c1327a686ff0b6ab245915e7fd20094showard } 3868b0ea2285c1327a686ff0b6ab245915e7fd20094showard throw new IllegalArgumentException("Item '" + name + "' does not exist in " + items); 3878b0ea2285c1327a686ff0b6ab245915e7fd20094showard } 3888b0ea2285c1327a686ff0b6ab245915e7fd20094showard 3898b0ea2285c1327a686ff0b6ab245915e7fd20094showard private Item findItem(String name) { 390d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward for (Item item : items) { 391d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (item.name.equals(name)) { 392d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return item; 393d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 394d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 3958b0ea2285c1327a686ff0b6ab245915e7fd20094showard return null; 3968b0ea2285c1327a686ff0b6ab245915e7fd20094showard } 3976f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li 3988b0ea2285c1327a686ff0b6ab245915e7fd20094showard public boolean hasItemName(String name) { 3998b0ea2285c1327a686ff0b6ab245915e7fd20094showard return findItem(name) != null; 400d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 401d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 402d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 403d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void onClick(ClickEvent event) { 4046f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li boolean isItemSelectedOnLeft = display.getAvailableList().getSelectedName() != null; 4056f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li boolean isItemSelectedOnRight = display.getSelectedList().getSelectedName() != null; 406d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward Object source = event.getSource(); 407d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (source == display.getAddAllButton()) { 408d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward addAll(); 409d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } else if (source == display.getAddButton() && isItemSelectedOnLeft) { 410d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward doSelect(); 411d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } else if (source == display.getRemoveButton() && isItemSelectedOnRight) { 412d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward doDeselect(); 413d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } else if (source == display.getRemoveAllButton()) { 414227a7a1d0484dcfa4c6d996a1c10e95437d059efshoward deselectAll(); 415d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } else if ((source == display.getMoveUpButton() || source == display.getMoveDownButton()) 416d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward && isItemSelectedOnRight) { 417d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward reorderItem(source == display.getMoveUpButton()); 418d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return; // don't refresh again or we'll mess up the user's selection 419d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } else if (source == toggleDisplay.getToggleMultipleLink()) { 420d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (toggleDisplay.getToggleMultipleLink().isActive()) { 421d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward switchToMultiple(); 422d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } else { 423d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward switchToSingle(); 424d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 425d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } else { 426d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward throw new RuntimeException("Unexpected ClickEvent from " + event.getSource()); 427d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 4286f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li 429d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward refresh(); 430d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 431d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 432d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 433d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void onDoubleClick(DoubleClickEvent event) { 434d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward Object source = event.getSource(); 435d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (source == display.getAvailableList()) { 436d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward doSelect(); 437d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } else if (source == display.getSelectedList()) { 438d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward doDeselect(); 439d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } else { 440d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward // ignore double-clicks on other widgets 441d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return; 442d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 4436f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li 444d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward refresh(); 445d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 446d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 447d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward @Override 448d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward public void onChange(ChangeEvent event) { 449d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward assert toggleDisplay != null; 450d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward SimplifiedList selector = toggleDisplay.getSingleSelector(); 451d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward assert event.getSource() == selector; 452d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward // events should only come from the single selector when it's active 453d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward assert !toggleDisplay.getToggleMultipleLink().isActive(); 454a29e963afc9de0ab086b5b2bea2e43ff68d81038showard 455d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward for (Item item : getItemsCopy()) { 456d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (item.isSelected()) { 457d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward deselectItem(item); 458d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } else if (item.name.equals(selector.getSelectedName())) { 459d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward selectItem(item); 460d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 461d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 4626f27d4f22a1ba5063968b8c322fa0845f3279adeEric Li 463d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward refresh(); 464d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 465d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 466d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward /** 467d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward * Selecting or deselecting items can add or remove items (due to generators), so sometimes we 468d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward * need to iterate over a copy. 469d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward */ 470d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private Iterable<Item> getItemsCopy() { 471d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward return new ArrayList<Item>(items); 472d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 473d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 474d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private void doSelect() { 475d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward selectItem(getItemByName(display.getAvailableList().getSelectedName())); 476d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 477d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 478d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private void doDeselect() { 479d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward deselectItem(getItemByName(display.getSelectedList().getSelectedName())); 480d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 481d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 482d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private void addAll() { 483d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward for (Item item : items) { 4848b0ea2285c1327a686ff0b6ab245915e7fd20094showard if (!item.isSelected()) { 485d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward selectItem(item); 486d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 487d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 488d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 489d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 490227a7a1d0484dcfa4c6d996a1c10e95437d059efshoward public void deselectAll() { 491d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward for (Item item : getItemsCopy()) { 492d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward if (item.isSelected()) { 493d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward deselectItem(item); 494d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 495d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 496d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 497d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward 498d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward private void reorderItem(boolean moveUp) { 499d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward Item item = getItemByName(display.getSelectedList().getSelectedName()); 500d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward int positionDelta = moveUp ? -1 : 1; 501d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward int newPosition = selectedItems.indexOf(item) + positionDelta; 502d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward newPosition = Math.max(0, Math.min(selectedItems.size() - 1, newPosition)); 503d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward selectedItems.remove(item); 504d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward selectedItems.add(newPosition, item); 505d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward refresh(); 506d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward display.getSelectedList().selectByName(item.name); 507d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward } 508d9e04c1a7950691cc348e70fa2470f8c414ae94fshoward} 509