1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
15 package org.simantics.ui.workbench.dialogs;
\r
17 import java.util.ArrayList;
\r
18 import java.util.Arrays;
\r
19 import java.util.Collection;
\r
20 import java.util.Comparator;
\r
21 import java.util.HashMap;
\r
22 import java.util.List;
\r
23 import java.util.Map;
\r
25 import org.eclipse.jface.viewers.ILabelProvider;
\r
26 import org.eclipse.swt.widgets.Composite;
\r
27 import org.eclipse.swt.widgets.Control;
\r
28 import org.eclipse.swt.widgets.Display;
\r
29 import org.eclipse.swt.widgets.Label;
\r
30 import org.eclipse.swt.widgets.Shell;
\r
31 import org.eclipse.swt.widgets.Text;
\r
32 import org.eclipse.ui.dialogs.AbstractElementListSelectionDialog;
\r
33 import org.eclipse.ui.dialogs.FilteredList;
\r
36 * ElementListSelectionDialog. This dialog component automatically sorts
\r
37 * previously selected objects to the top of the list.
\r
39 * The component uses title as key for distinguishing different dialog types.
\r
41 * @author Toni Kalajainen
\r
42 * @author Tuukka Lehtonen
\r
44 public class ElementListSelectionDialog extends AbstractElementListSelectionDialog {
\r
46 /** The number of previously selected objects to be remembered */
\r
47 protected static final int REMEMBER_NUM = 128;
\r
49 /** The number of previously selected objects to be prioritized in the list */
\r
50 protected static final int PRIORITIZE_NUM = 5;
\r
52 protected String title = "";
\r
54 protected List<Object> elementList = new ArrayList<Object>();
\r
56 protected ILabelProvider labelProvider;
\r
58 protected boolean usePreviousSelectionSort = true;
\r
60 protected Label messageLabel;
\r
62 protected Text filterText;
\r
66 * Creates a list selection dialog.
\r
68 * @param parent the parent widget.
\r
69 * @param labelProvider the label provider.
\r
71 public ElementListSelectionDialog(Shell parent, ILabelProvider labelProvider) {
\r
72 super(parent, labelProvider);
\r
73 this.labelProvider = labelProvider;
\r
74 this.setIgnoreCase(true);
\r
78 * Sets the elements of the list.
\r
79 * @param elements the elements of the list.
\r
81 public void setElements(Object... elements) {
\r
83 addElements(elements);
\r
86 public void addElements(Object... elements) {
\r
87 if (elementList==null)
\r
88 elementList = new ArrayList<Object>();
\r
89 for (Object e : elements)
\r
94 * Sets the elements of the list.
\r
95 * @param elements the elements of the list.
\r
97 @SuppressWarnings("rawtypes")
\r
98 public void setElements(Collection c) {
\r
103 @SuppressWarnings("rawtypes")
\r
104 public void addElements(Collection c) {
\r
105 if (elementList==null)
\r
106 elementList = new ArrayList<Object>();
\r
108 elementList.add(e);
\r
111 public void updateList() {
\r
112 // Make sure that the filtered list exists before trying to update it.
\r
113 if (fFilteredList != null && elementList != null) {
\r
114 Object[] objs = elementList.toArray(new Object[elementList.size()]);
\r
115 final boolean isEmpty = objs.length == 0;
\r
116 setListElements(objs);
\r
117 Runnable r = new Runnable() {
\r
118 public void run() {
\r
119 handleListChange(isEmpty);
\r
122 Display d = getShell().getDisplay();
\r
123 if (Thread.currentThread() == d.getThread())
\r
130 protected void handleListChange(boolean isEmpty) {
\r
131 boolean wasEnabled = filterText.isEnabled();
\r
132 boolean enable = !isEmpty;
\r
133 messageLabel.setEnabled(enable);
\r
134 filterText.setEnabled(enable);
\r
135 fFilteredList.setEnabled(enable);
\r
137 filterText.setFocus();
\r
142 * Do alphabetical sort for list elements
\r
144 public void sortElements() {
\r
145 if (elementList==null) return;
\r
147 Object[] objects = elementList.toArray(new Object[0]);
\r
148 Arrays.sort(objects, new Comparator<Object>() {
\r
149 public int compare(Object o1, Object o2) {
\r
150 String n1 = labelProvider.getText(o1).toLowerCase();
\r
151 String n2 = labelProvider.getText(o2).toLowerCase();
\r
152 return n1.compareTo(n2);
\r
155 elementList = new ArrayList<Object>(objects.length);
\r
156 for (Object o : objects)
\r
157 elementList.add(o);
\r
161 * @see SelectionStatusDialog#computeResult()
\r
163 protected void computeResult() {
\r
164 setResult(Arrays.asList(getSelectedElements()));
\r
168 public void setTitle(String title) {
\r
169 super.setTitle(title);
\r
170 this.title = title;
\r
173 public void setInitialSelection(Object selectedElement) {
\r
174 this.setInitialSelections(new Object[] {selectedElement});
\r
178 * Overridden just to get a hold of the message area label.
\r
180 * @see org.eclipse.ui.dialogs.AbstractElementListSelectionDialog#createMessageArea(org.eclipse.swt.widgets.Composite)
\r
183 protected Label createMessageArea(Composite composite) {
\r
184 messageLabel = super.createMessageArea(composite);
\r
185 return messageLabel;
\r
189 * Overridden just to get a hold of the filter text.
\r
191 * @see org.eclipse.ui.dialogs.AbstractElementListSelectionDialog#createFilterText(org.eclipse.swt.widgets.Composite)
\r
194 protected Text createFilterText(Composite parent) {
\r
195 filterText = super.createFilterText(parent);
\r
200 protected FilteredList createFilteredList(Composite parent) {
\r
201 FilteredList flist = super.createFilteredList(parent);
\r
203 if (usePreviousSelectionSort)
\r
205 List<Object> prioritizeList = new ArrayList<Object>();
\r
206 int[] previousSelections = getPreviousSelections( title );
\r
207 for (int i=0; i<previousSelections.length; i++)
\r
208 for (int j=0; j<elementList.size(); j++)
\r
209 if (elementList.get(j).hashCode()==previousSelections[i])
\r
211 String name = labelProvider.getText(elementList.get(j));
\r
212 if (name==null) continue;
\r
213 prioritizeList.add(name);
\r
214 if (prioritizeList.size()>PRIORITIZE_NUM)
\r
218 flist.setComparator(new PrioritizeComparator(prioritizeList, isCaseIgnored()));
\r
224 protected void createControls(Composite contents) {
\r
225 createMessageArea(contents);
\r
226 createFilterText(contents);
\r
227 createFilteredList(contents);
\r
231 * @see Dialog#createDialogArea(Composite)
\r
233 protected Control createDialogArea(Composite parent) {
\r
234 Composite contents = (Composite) super.createDialogArea(parent);
\r
236 createControls(contents);
\r
238 setListElements(elementList.toArray(new Object[elementList.size()]));
\r
241 setSelection(getInitialElementSelections().toArray());
\r
243 // If nothing is selected, select the first element
\r
244 //if (getSelectionIndices()==null || getSelectionIndices().length==0)
\r
245 // this.fFilteredList.setSelection(new int[] {0});
\r
251 protected void okPressed() {
\r
253 for (Object o : getResult())
\r
254 addSelection(title, o);
\r
257 protected static Map<String, List<Integer>> previousSelections =
\r
258 new HashMap<String, List<Integer>>();
\r
260 protected static synchronized int[] getPreviousSelections(String key)
\r
262 List<Integer> list = previousSelections.get(key);
\r
263 if (list==null) return new int[0];
\r
264 int result[] = new int[list.size()];
\r
265 for (int i=0; i<list.size(); i++)
\r
266 result[i] = list.get(i);
\r
270 protected static synchronized void addSelection(String key, Object o)
\r
272 List<Integer> list = previousSelections.get(key);
\r
274 list = new ArrayList<Integer>();
\r
275 previousSelections.put(key, list);
\r
277 int hash = o.hashCode();
\r
279 for (int i=0; i<list.size(); i++)
\r
280 if (list.get(i)==hash)
\r
285 list.add(0, o.hashCode());
\r
288 if (list.size()>REMEMBER_NUM)
\r
289 list.remove(list.size()-1);
\r
292 public int[] getSelectionIndices() {
\r
293 return super.getSelectionIndices();
\r
296 public boolean isUsePreviousSelectionSort() {
\r
297 return usePreviousSelectionSort;
\r
301 * Set usage for sorting of previous selections.
\r
302 * When this sorting is enabled, the items that have been selected
\r
303 * the items that have been selected previously in this same dialog
\r
304 * are prioritized to appear first in the list
\r
306 * (Dialogs are distinguished by their title :X)
\r
308 * @param usePreviousSelectionSort
\r
310 public void setUsePreviousSelectionSort(boolean usePreviousSelectionSort) {
\r
311 this.usePreviousSelectionSort = usePreviousSelectionSort;
\r
316 class PrioritizeComparator implements Comparator<Object>
\r
318 private final List<Object> prioritizeList;
\r
319 private final boolean ignoreCase;
\r
320 public PrioritizeComparator(List<Object> prioritizeList, boolean ignoreCase)
\r
322 this.prioritizeList = prioritizeList;
\r
323 this.ignoreCase = ignoreCase;
\r
326 public int getIndex(Object o)
\r
328 for (int i=0; i<prioritizeList.size(); i++)
\r
329 if (o==prioritizeList.get(i))
\r
331 return Integer.MAX_VALUE/4;
\r
334 public int compare(Object o1, Object o2) {
\r
335 int p1 = getIndex(o1);
\r
336 int p2 = getIndex(o2);
\r
338 return (ignoreCase?o1.toString().compareToIgnoreCase(o2.toString()):o1.toString().compareTo(o2.toString()));
\r