| /******************************************************************************* |
| * 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.tests.internal.utility.swt; |
| |
| import java.text.Collator; |
| import java.util.ArrayList; |
| import java.util.Comparator; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.ListIterator; |
| |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.ActionContributionItem; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.window.ApplicationWindow; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.jpt.ui.internal.utility.swt.SWTTools; |
| import org.eclipse.jpt.utility.internal.model.AbstractModel; |
| import org.eclipse.jpt.utility.internal.model.value.ListAspectAdapter; |
| import org.eclipse.jpt.utility.internal.model.value.PropertyAspectAdapter; |
| import org.eclipse.jpt.utility.internal.model.value.SimplePropertyValueModel; |
| import org.eclipse.jpt.utility.internal.model.value.SortedListValueModelWrapper; |
| import org.eclipse.jpt.utility.model.Model; |
| import org.eclipse.jpt.utility.model.value.ListValueModel; |
| import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.CCombo; |
| import org.eclipse.swt.layout.FillLayout; |
| import org.eclipse.swt.layout.FormAttachment; |
| import org.eclipse.swt.layout.FormData; |
| import org.eclipse.swt.layout.FormLayout; |
| import org.eclipse.swt.widgets.Combo; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Text; |
| |
| /** |
| * Play around with a set of read-only combo-boxes. |
| */ |
| @SuppressWarnings("nls") |
| public class DropDownListBoxModelBindingUITest |
| extends ApplicationWindow |
| { |
| final TaskList taskList; |
| private final WritablePropertyValueModel<TaskList> taskListHolder; |
| private Text taskTextField; |
| |
| public static void main(String[] args) throws Exception { |
| Window window = new DropDownListBoxModelBindingUITest(args); |
| window.setBlockOnOpen(true); |
| window.open(); |
| Display.getCurrent().dispose(); |
| System.exit(0); |
| } |
| |
| private DropDownListBoxModelBindingUITest(@SuppressWarnings("unused") String[] args) { |
| super(null); |
| this.taskList = new TaskList(); |
| this.taskListHolder = new SimplePropertyValueModel<TaskList>(this.taskList); |
| this.taskList.addTask("swim"); |
| this.taskList.addTask("bike"); |
| this.taskList.addTask("run"); |
| Task rest = this.taskList.addTask("rest"); |
| this.taskList.addTask("repeat"); |
| this.taskList.setPriorityTask(rest); |
| } |
| |
| @Override |
| protected Control createContents(Composite parent) { |
| ((Shell) parent).setText(this.getClass().getSimpleName()); |
| parent.setSize(800, 300); |
| Composite mainPanel = new Composite(parent, SWT.NONE); |
| mainPanel.setLayout(new FormLayout()); |
| Control taskListPanel = this.buildTaskListPanel(mainPanel); |
| this.buildControlPanel(mainPanel, taskListPanel); |
| return mainPanel; |
| } |
| |
| private Control buildTaskListPanel(Composite parent) { |
| Composite panel = new Composite(parent, SWT.NONE); |
| |
| FormData fd = new FormData(); |
| fd.top = new FormAttachment(0); |
| fd.bottom = new FormAttachment(100, -30); |
| fd.left = new FormAttachment(0); |
| fd.right = new FormAttachment(100); |
| panel.setLayoutData(fd); |
| |
| panel.setLayout(new FormLayout()); |
| this.buildTaskListPanel(panel, false); // false = native (Combo) |
| this.buildTaskListPanel(panel, true); // true = custom (CCombo) |
| |
| return panel; |
| } |
| |
| private Control buildTaskListPanel(Composite parent, boolean custom) { |
| Composite panel = new Composite(parent, SWT.NONE); |
| |
| FormData fd = new FormData(); |
| fd.top = new FormAttachment(custom ? 50 : 0); |
| fd.bottom = new FormAttachment(custom ? 100 : 50); |
| fd.left = new FormAttachment(0); |
| fd.right = new FormAttachment(100); |
| panel.setLayoutData(fd); |
| |
| panel.setLayout(new FormLayout()); |
| this.buildPrimitiveTaskListPanel(panel, custom); |
| this.buildObjectTaskListPanel(panel, custom); |
| |
| return panel; |
| } |
| |
| private void buildPrimitiveTaskListPanel(Composite parent, boolean custom) { |
| Composite panel = new Composite(parent, SWT.NONE); |
| |
| FormData fd = new FormData(); |
| fd.top = new FormAttachment(0); |
| fd.bottom = new FormAttachment(50); |
| fd.left = new FormAttachment(0); |
| fd.right = new FormAttachment(100); |
| panel.setLayoutData(fd); |
| |
| panel.setLayout(new FillLayout()); |
| this.buildUnsortedPrimitiveListPanel(panel, custom); |
| this.buildStandardSortedPrimitiveListPanel(panel, custom); |
| this.buildCustomSortedPrimitiveListPanel(panel, custom); |
| } |
| |
| private void buildObjectTaskListPanel(Composite parent, boolean custom) { |
| Composite panel = new Composite(parent, SWT.NONE); |
| |
| FormData fd = new FormData(); |
| fd.top = new FormAttachment(50); |
| fd.bottom = new FormAttachment(100); |
| fd.left = new FormAttachment(0); |
| fd.right = new FormAttachment(100); |
| panel.setLayoutData(fd); |
| |
| panel.setLayout(new FillLayout()); |
| this.buildUnsortedObjectListPanel(panel, custom); |
| this.buildStandardSortedObjectListPanel(panel, custom); |
| this.buildCustomSortedObjectListPanel(panel, custom); |
| } |
| |
| private void buildUnsortedPrimitiveListPanel(Composite parent, boolean custom) { |
| String label = "primitive unsorted"; |
| if (custom) label += " (custom)"; |
| this.buildComboBoxPanel(parent, label, this.buildUnsortedPrimitiveListModel(), this.buildPriorityTaskNameAdapter(), custom); |
| } |
| |
| private void buildStandardSortedPrimitiveListPanel(Composite parent, boolean custom) { |
| String label = "primitive sorted"; |
| if (custom) label += " (custom)"; |
| this.buildComboBoxPanel(parent, label, this.buildStandardSortedPrimitiveListModel(), this.buildPriorityTaskNameAdapter(), custom); |
| } |
| |
| private void buildCustomSortedPrimitiveListPanel(Composite parent, boolean custom) { |
| String label = "primitive reverse sorted"; |
| if (custom) label += " (custom)"; |
| this.buildComboBoxPanel(parent, label, this.buildCustomSortedPrimitiveListModel(), this.buildPriorityTaskNameAdapter(), custom); |
| } |
| |
| private void buildUnsortedObjectListPanel(Composite parent, boolean custom) { |
| String label = "object unsorted"; |
| if (custom) label += " (custom)"; |
| this.buildComboBoxPanel(parent, label, this.buildUnsortedObjectListModel(), this.buildPriorityTaskAdapter(), custom); |
| } |
| |
| private void buildStandardSortedObjectListPanel(Composite parent, boolean custom) { |
| String label = "object sorted"; |
| if (custom) label += " (custom)"; |
| this.buildComboBoxPanel(parent, label, this.buildStandardSortedObjectListModel(), this.buildPriorityTaskAdapter(), custom); |
| } |
| |
| private void buildCustomSortedObjectListPanel(Composite parent, boolean custom) { |
| String label = "object reverse sorted"; |
| if (custom) label += " (custom)"; |
| this.buildComboBoxPanel(parent, label, this.buildCustomSortedObjectListModel(), this.buildPriorityTaskAdapter(), custom); |
| } |
| |
| private ListValueModel<String> buildUnsortedPrimitiveListModel() { |
| return this.buildPrimitiveTaskListAdapter(); |
| } |
| |
| private ListValueModel<String> buildStandardSortedPrimitiveListModel() { |
| return new SortedListValueModelWrapper<String>(this.buildPrimitiveTaskListAdapter()); |
| } |
| |
| private ListValueModel<String> buildCustomSortedPrimitiveListModel() { |
| return new SortedListValueModelWrapper<String>(this.buildPrimitiveTaskListAdapter(), this.buildCustomStringComparator()); |
| } |
| |
| private ListValueModel<Task> buildUnsortedObjectListModel() { |
| return this.buildObjectTaskListAdapter(); |
| } |
| |
| private ListValueModel<Task> buildStandardSortedObjectListModel() { |
| return new SortedListValueModelWrapper<Task>(this.buildObjectTaskListAdapter()); |
| } |
| |
| private ListValueModel<Task> buildCustomSortedObjectListModel() { |
| return new SortedListValueModelWrapper<Task>(this.buildObjectTaskListAdapter(), this.buildCustomTaskComparator()); |
| } |
| |
| private <E> void buildComboBoxPanel(Composite parent, String label, ListValueModel<E> model, WritablePropertyValueModel<E> selectedItemModel, boolean custom) { |
| Composite panel = new Composite(parent, SWT.NONE); |
| panel.setLayout(new FormLayout()); |
| |
| Label comboBoxLabel = new Label(panel, SWT.LEFT | SWT.VERTICAL); |
| comboBoxLabel.setText(label); |
| FormData fd = new FormData(); |
| fd.top = new FormAttachment(0, 3); |
| fd.bottom = new FormAttachment(0, 20); |
| fd.left = new FormAttachment(0, 5); |
| fd.right = new FormAttachment(100); |
| comboBoxLabel.setLayoutData(fd); |
| |
| Control comboBox = this.buildComboBox(panel, custom); |
| fd = new FormData(); |
| fd.top = new FormAttachment(comboBoxLabel); |
| fd.bottom = new FormAttachment(100); |
| fd.left = new FormAttachment(0); |
| fd.right = new FormAttachment(100); |
| comboBox.setLayoutData(fd); |
| if (custom) { |
| SWTTools.bind(model, selectedItemModel, (CCombo) comboBox); // use #toString() |
| } else { |
| SWTTools.bind(model, selectedItemModel, (Combo) comboBox); // use #toString() |
| } |
| } |
| |
| private Control buildComboBox(Composite parent, boolean custom) { |
| int style = SWT.READ_ONLY; |
| return custom ? new CCombo(parent, style) : new Combo(parent, style); |
| } |
| |
| private Comparator<String> buildCustomStringComparator() { |
| return new Comparator<String>() { |
| public int compare(String s1, String s2) { |
| return s2.compareTo(s1); |
| } |
| }; |
| } |
| |
| private Comparator<Task> buildCustomTaskComparator() { |
| return new Comparator<Task>() { |
| public int compare(Task to1, Task to2) { |
| return to2.compareTo(to1); |
| } |
| }; |
| } |
| |
| private ListValueModel<String> buildPrimitiveTaskListAdapter() { |
| return new ListAspectAdapter<TaskList, String>(this.taskListHolder, TaskList.TASK_NAMES_LIST) { |
| @Override |
| protected ListIterator<String> listIterator_() { |
| return this.subject.taskNames(); |
| } |
| }; |
| } |
| |
| private ListValueModel<Task> buildObjectTaskListAdapter() { |
| return new ListAspectAdapter<TaskList, Task>(this.taskListHolder, TaskList.TASKS_LIST) { |
| @Override |
| protected ListIterator<Task> listIterator_() { |
| return this.subject.tasks(); |
| } |
| }; |
| } |
| |
| private WritablePropertyValueModel<Task> buildPriorityTaskAdapter() { |
| return new PriorityTaskAdapter(this.taskListHolder); |
| } |
| |
| static class PriorityTaskAdapter |
| extends PropertyAspectAdapter<TaskList, Task> |
| { |
| PriorityTaskAdapter(WritablePropertyValueModel<TaskList> taskListHolder) { |
| super(taskListHolder, TaskList.PRIORITY_TASK_PROPERTY); |
| } |
| @Override |
| protected Task buildValue_() { |
| return this.subject.getPriorityTask(); |
| } |
| @Override |
| protected void setValue_(Task value) { |
| this.subject.setPriorityTask(value); |
| } |
| } |
| |
| private WritablePropertyValueModel<String> buildPriorityTaskNameAdapter() { |
| return new PriorityTaskNameAdapter(this.taskListHolder); |
| } |
| |
| static class PriorityTaskNameAdapter |
| extends PropertyAspectAdapter<TaskList, String> |
| { |
| PriorityTaskNameAdapter(WritablePropertyValueModel<TaskList> taskListHolder) { |
| super(taskListHolder, TaskList.PRIORITY_TASK_NAME_PROPERTY); |
| } |
| @Override |
| protected String buildValue_() { |
| return this.subject.getPriorityTaskName(); |
| } |
| @Override |
| protected void setValue_(String value) { |
| // ignore |
| } |
| } |
| |
| private void buildControlPanel(Composite parent, Control taskListPanel) { |
| Composite panel = new Composite(parent, SWT.NONE); |
| FormData fd = new FormData(); |
| fd.top = new FormAttachment(taskListPanel); |
| fd.bottom = new FormAttachment(100); |
| fd.left = new FormAttachment(0); |
| fd.right = new FormAttachment(100); |
| panel.setLayoutData(fd); |
| |
| panel.setLayout(new FormLayout()); |
| Control misc = this.buildMiscTaskPanel(panel); |
| this.buildAddRemoveTaskPanel(panel, misc); |
| } |
| |
| // is there a better way to associate an ACI with form data? |
| private Control buildMiscTaskPanel(Composite parent) { |
| Composite panel = new Composite(parent, SWT.NONE); |
| FormData fd = new FormData(); |
| fd.top = new FormAttachment(0); |
| fd.bottom = new FormAttachment(100); |
| fd.left = new FormAttachment(100, -400); |
| fd.right = new FormAttachment(100); |
| panel.setLayoutData(fd); |
| |
| panel.setLayout(new FillLayout()); |
| this.buildClearListACI().fill(panel); |
| this.buildClearModelACI().fill(panel); |
| this.buildRestoreModelACI().fill(panel); |
| this.buildChangePriorityTaskACI().fill(panel); |
| this.buildClearPriorityTaskACI().fill(panel); |
| return panel; |
| } |
| |
| private ActionContributionItem buildClearListACI() { |
| Action action = new Action("clear list", IAction.AS_PUSH_BUTTON) { |
| @Override |
| public void run() { |
| DropDownListBoxModelBindingUITest.this.clearTasks(); |
| } |
| }; |
| action.setToolTipText("clear all the tasks"); |
| return new ActionContributionItem(action); |
| } |
| |
| private ActionContributionItem buildClearModelACI() { |
| Action action = new Action("clear model", IAction.AS_PUSH_BUTTON) { |
| @Override |
| public void run() { |
| DropDownListBoxModelBindingUITest.this.clearModel(); |
| } |
| }; |
| action.setToolTipText("clear the task list model"); |
| return new ActionContributionItem(action); |
| } |
| |
| private ActionContributionItem buildRestoreModelACI() { |
| Action action = new Action("restore model", IAction.AS_PUSH_BUTTON) { |
| @Override |
| public void run() { |
| DropDownListBoxModelBindingUITest.this.restoreModel(); |
| } |
| }; |
| action.setToolTipText("restore the task list model"); |
| return new ActionContributionItem(action); |
| } |
| |
| private ActionContributionItem buildChangePriorityTaskACI() { |
| Action action = new Action("change priority", IAction.AS_PUSH_BUTTON) { |
| @Override |
| public void run() { |
| DropDownListBoxModelBindingUITest.this.changePriorityTask(); |
| } |
| }; |
| action.setToolTipText("change the priority task"); |
| return new ActionContributionItem(action); |
| } |
| |
| private ActionContributionItem buildClearPriorityTaskACI() { |
| Action action = new Action("clear priority", IAction.AS_PUSH_BUTTON) { |
| @Override |
| public void run() { |
| DropDownListBoxModelBindingUITest.this.clearPriorityTask(); |
| } |
| }; |
| action.setToolTipText("clear the priority task"); |
| return new ActionContributionItem(action); |
| } |
| |
| private void buildAddRemoveTaskPanel(Composite parent, Control clearButton) { |
| Composite panel = new Composite(parent, SWT.NONE); |
| FormData fd = new FormData(); |
| fd.top = new FormAttachment(0); |
| fd.bottom = new FormAttachment(100); |
| fd.left = new FormAttachment(0); |
| fd.right = new FormAttachment(clearButton); |
| panel.setLayoutData(fd); |
| |
| panel.setLayout(new FormLayout()); |
| Control addButton = this.buildAddButton(panel); |
| Control removeButton = this.buildRemoveButton(panel); |
| this.buildTaskTextField(panel, addButton, removeButton); |
| } |
| |
| // is there a better way to associate an ACI with form data? |
| private Control buildAddButton(Composite parent) { |
| Composite panel = new Composite(parent, SWT.NONE); |
| FormData fd = new FormData(); |
| fd.top = new FormAttachment(0); |
| fd.bottom = new FormAttachment(100); |
| fd.left = new FormAttachment(0); |
| fd.right = new FormAttachment(0, 50); |
| panel.setLayoutData(fd); |
| |
| panel.setLayout(new FillLayout()); |
| this.buildAddACI().fill(panel); |
| return panel; |
| } |
| |
| private ActionContributionItem buildAddACI() { |
| Action action = new Action("add", IAction.AS_PUSH_BUTTON) { |
| @Override |
| public void run() { |
| DropDownListBoxModelBindingUITest.this.addTask(); |
| } |
| }; |
| action.setToolTipText("add a task with the name in the entry field"); |
| return new ActionContributionItem(action); |
| } |
| |
| // is there a better way to associate an ACI with form data? |
| private Control buildRemoveButton(Composite parent) { |
| Composite panel = new Composite(parent, SWT.NONE); |
| FormData fd = new FormData(); |
| fd.top = new FormAttachment(0); |
| fd.bottom = new FormAttachment(100); |
| fd.left = new FormAttachment(100, -50); |
| fd.right = new FormAttachment(100); |
| panel.setLayoutData(fd); |
| |
| panel.setLayout(new FillLayout()); |
| this.buildRemoveACI().fill(panel); |
| return panel; |
| } |
| |
| private ActionContributionItem buildRemoveACI() { |
| Action action = new Action("remove", IAction.AS_PUSH_BUTTON) { |
| @Override |
| public void run() { |
| DropDownListBoxModelBindingUITest.this.removeTask(); |
| } |
| }; |
| action.setToolTipText("remove the task with the name in the entry field"); |
| return new ActionContributionItem(action); |
| } |
| |
| private void buildTaskTextField(Composite parent, Control addButton, Control removeButton) { |
| this.taskTextField = new Text(parent, SWT.SINGLE | SWT.BORDER); |
| FormData fd = new FormData(); |
| fd.top = new FormAttachment(0); |
| fd.bottom = new FormAttachment(100); |
| fd.left = new FormAttachment(addButton); |
| fd.right = new FormAttachment(removeButton); |
| this.taskTextField.setLayoutData(fd); |
| } |
| |
| private String taskTextFieldText() { |
| return this.taskTextField.getText(); |
| } |
| |
| void addTask() { |
| String taskText = this.taskTextFieldText(); |
| if (taskText.length() != 0) { |
| this.taskList.addTask(taskText); |
| } |
| } |
| |
| void removeTask() { |
| String task = this.taskTextFieldText(); |
| if (task.length() != 0) { |
| this.taskList.removeTask(task); |
| } |
| } |
| |
| void clearTasks() { |
| this.taskList.clearTasks(); |
| } |
| |
| void clearModel() { |
| this.taskListHolder.setValue(null); |
| } |
| |
| void restoreModel() { |
| this.taskListHolder.setValue(this.taskList); |
| } |
| |
| void changePriorityTask() { |
| boolean found = false; |
| for (Task task : this.taskList.getTasks()) { |
| if (this.taskList.getPriorityTask() == task) { |
| found = true; |
| } else { |
| if (found) { |
| this.taskList.setPriorityTask(task); |
| return; |
| } |
| } |
| } |
| Iterator<Task> tasks = this.taskList.tasks(); |
| if (tasks.hasNext()) { |
| this.taskList.setPriorityTask(tasks.next()); |
| } |
| } |
| |
| void clearPriorityTask() { |
| this.taskList.setPriorityTask(null); |
| } |
| |
| |
| // ********** TaskList ********** |
| |
| // note absence of validation... |
| public static class TaskList extends AbstractModel { |
| private final List<String> taskNames = new ArrayList<String>(); |
| public static final String TASK_NAMES_LIST = "taskNames"; |
| private final List<Task> tasks = new ArrayList<Task>(); |
| public static final String TASKS_LIST = "tasks"; |
| private String priorityTaskName = null; |
| public static final String PRIORITY_TASK_NAME_PROPERTY = "priorityTaskName"; |
| private Task priorityTask = null; |
| public static final String PRIORITY_TASK_PROPERTY = "priorityTask"; |
| public TaskList() { |
| super(); |
| } |
| public ListIterator<String> taskNames() { |
| return this.taskNames.listIterator(); |
| } |
| public Iterable<Task> getTasks() { |
| return this.tasks; |
| } |
| public ListIterator<Task> tasks() { |
| return this.tasks.listIterator(); |
| } |
| public String getPriorityTaskName() { |
| return this.priorityTaskName; |
| } |
| public Task getPriorityTask() { |
| return this.priorityTask; |
| } |
| public Task addTask(String taskName) { |
| this.addItemToList(taskName, this.taskNames, TASK_NAMES_LIST); |
| Task task = new Task(taskName); |
| this.addItemToList(task, this.tasks, TASKS_LIST); |
| return task; |
| } |
| public void removeTask(String taskName) { |
| int index = this.taskNames.indexOf(taskName); |
| if (index != -1) { |
| Task task = this.tasks.get(index); |
| if (task == this.priorityTask) { |
| this.setPriorityTask(null); |
| } |
| // assume the indexes match... |
| this.removeItemFromList(index, this.taskNames, TASK_NAMES_LIST); |
| this.removeItemFromList(index, this.tasks, TASKS_LIST); |
| } |
| } |
| public void clearTasks() { |
| this.setPriorityTask(null); |
| this.clearList(this.taskNames, TASK_NAMES_LIST); |
| this.clearList(this.tasks, TASKS_LIST); |
| } |
| private void setPriorityTaskName(String priorityTaskName) { |
| String old = this.priorityTaskName; |
| this.priorityTaskName = priorityTaskName; |
| this.firePropertyChanged(PRIORITY_TASK_NAME_PROPERTY, old, priorityTaskName); |
| } |
| public void setPriorityTask(Task priorityTask) { |
| Task old = this.priorityTask; |
| this.priorityTask = priorityTask; |
| this.firePropertyChanged(PRIORITY_TASK_PROPERTY, old, priorityTask); |
| this.setPriorityTaskName((priorityTask == null) ? null : priorityTask.getName()); |
| } |
| } |
| |
| |
| // ********** Task ********** |
| |
| public static class Task extends AbstractModel implements Displayable { |
| private String name; |
| private int instanceCount; |
| private static int INSTANCE_COUNT = 1; |
| public Task(String name) { |
| this.name = name; |
| this.instanceCount = INSTANCE_COUNT++; |
| } |
| public String displayString() { |
| return this.name + ": " + this.instanceCount; |
| } |
| public int compareTo(Displayable o) { |
| return DEFAULT_COMPARATOR.compare(this, o); |
| } |
| public String getName() { |
| return this.name; |
| } |
| public void setName(String name) { |
| Object old = this.name; |
| this.name = name; |
| this.firePropertyChanged(DISPLAY_STRING_PROPERTY, old, name); |
| } |
| @Override |
| public String toString() { |
| return this.displayString(); |
| } |
| } |
| |
| public interface Displayable extends Model, Comparable<Displayable> { |
| |
| String displayString(); |
| String DISPLAY_STRING_PROPERTY = "displayString"; |
| |
| |
| // ********** helper implementations ********** |
| |
| Collator DEFAULT_COLLATOR = Collator.getInstance(); |
| |
| Comparator<Displayable> DEFAULT_COMPARATOR = |
| new Comparator<Displayable>() { |
| public int compare(Displayable d1, Displayable d2) { |
| // disallow duplicates based on object identity |
| if (d1 == d2) { |
| return 0; |
| } |
| |
| // first compare display strings using the default collator |
| int result = DEFAULT_COLLATOR.compare(d1.displayString(), d2.displayString()); |
| if (result != 0) { |
| return result; |
| } |
| |
| // then compare using object-id |
| result = System.identityHashCode(d1) - System.identityHashCode(d2); |
| if (result != 0) { |
| return result; |
| } |
| |
| // It's unlikely that we get to this point; but, just in case, we will return -1. |
| // Unfortunately, this introduces some mild unpredictability to the sort order |
| // (unless the objects are always passed into this method in the same order). |
| return -1; // if all else fails, indicate that o1 < o2 |
| } |
| @Override |
| public String toString() { |
| return "Displayable.DEFAULT_COMPARATOR"; |
| } |
| }; |
| |
| } |
| } |