--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+/*\r
+ * 7.6.2006\r
+ */\r
+package org.simantics.ui.workbench.dialogs;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.Collection;\r
+import java.util.Comparator;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import org.eclipse.jface.viewers.ILabelProvider;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.eclipse.ui.dialogs.AbstractElementListSelectionDialog;\r
+import org.eclipse.ui.dialogs.FilteredList;\r
+\r
+/**\r
+ * ElementListSelectionDialog. This dialog component automatically sorts\r
+ * previously selected objects to the top of the list. \r
+ * <p>\r
+ * The component uses title as key for distinguishing different dialog types.\r
+ * \r
+ * @author Toni Kalajainen\r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class ElementListSelectionDialog extends AbstractElementListSelectionDialog {\r
+\r
+ /** The number of previously selected objects to be remembered */\r
+ protected static final int REMEMBER_NUM = 128;\r
+\r
+ /** The number of previously selected objects to be prioritized in the list */\r
+ protected static final int PRIORITIZE_NUM = 5;\r
+ \r
+ protected String title = "";\r
+\r
+ protected List<Object> elementList = new ArrayList<Object>();\r
+\r
+ protected ILabelProvider labelProvider;\r
+\r
+ protected boolean usePreviousSelectionSort = true;\r
+\r
+ protected Label messageLabel;\r
+\r
+ protected Text filterText;\r
+\r
+\r
+ /**\r
+ * Creates a list selection dialog.\r
+ * \r
+ * @param parent the parent widget.\r
+ * @param labelProvider the label provider.\r
+ */\r
+ public ElementListSelectionDialog(Shell parent, ILabelProvider labelProvider) {\r
+ super(parent, labelProvider);\r
+ this.labelProvider = labelProvider;\r
+ this.setIgnoreCase(true);\r
+ }\r
+\r
+ /**\r
+ * Sets the elements of the list.\r
+ * @param elements the elements of the list.\r
+ */\r
+ public void setElements(Object... elements) {\r
+ elementList = null;\r
+ addElements(elements);\r
+ }\r
+\r
+ public void addElements(Object... elements) {\r
+ if (elementList==null)\r
+ elementList = new ArrayList<Object>();\r
+ for (Object e : elements)\r
+ elementList.add(e);\r
+ }\r
+\r
+ /**\r
+ * Sets the elements of the list.\r
+ * @param elements the elements of the list.\r
+ */\r
+ @SuppressWarnings("rawtypes")\r
+ public void setElements(Collection c) {\r
+ elementList = null;\r
+ addElements(c);\r
+ }\r
+\r
+ @SuppressWarnings("rawtypes")\r
+ public void addElements(Collection c) {\r
+ if (elementList==null)\r
+ elementList = new ArrayList<Object>();\r
+ for (Object e : c)\r
+ elementList.add(e);\r
+ }\r
+\r
+ public void updateList() {\r
+ // Make sure that the filtered list exists before trying to update it.\r
+ if (fFilteredList != null && elementList != null) {\r
+ Object[] objs = elementList.toArray(new Object[elementList.size()]);\r
+ final boolean isEmpty = objs.length == 0;\r
+ setListElements(objs);\r
+ Runnable r = new Runnable() {\r
+ public void run() {\r
+ handleListChange(isEmpty);\r
+ }\r
+ };\r
+ Display d = getShell().getDisplay();\r
+ if (Thread.currentThread() == d.getThread())\r
+ r.run();\r
+ else\r
+ d.asyncExec(r);\r
+ }\r
+ }\r
+\r
+ protected void handleListChange(boolean isEmpty) {\r
+ boolean wasEnabled = filterText.isEnabled();\r
+ boolean enable = !isEmpty;\r
+ messageLabel.setEnabled(enable);\r
+ filterText.setEnabled(enable);\r
+ fFilteredList.setEnabled(enable);\r
+ if (!wasEnabled)\r
+ filterText.setFocus();\r
+ updateOkState();\r
+ }\r
+\r
+ /**\r
+ * Do alphabetical sort for list elements\r
+ */\r
+ public void sortElements() {\r
+ if (elementList==null) return;\r
+ \r
+ Object[] objects = elementList.toArray(new Object[0]);\r
+ Arrays.sort(objects, new Comparator<Object>() {\r
+ public int compare(Object o1, Object o2) {\r
+ String n1 = labelProvider.getText(o1).toLowerCase();\r
+ String n2 = labelProvider.getText(o2).toLowerCase();\r
+ return n1.compareTo(n2);\r
+ }});\r
+ \r
+ elementList = new ArrayList<Object>(objects.length);\r
+ for (Object o : objects)\r
+ elementList.add(o);\r
+ }\r
+\r
+ /*\r
+ * @see SelectionStatusDialog#computeResult()\r
+ */\r
+ protected void computeResult() {\r
+ setResult(Arrays.asList(getSelectedElements()));\r
+ }\r
+\r
+ @Override\r
+ public void setTitle(String title) {\r
+ super.setTitle(title);\r
+ this.title = title;\r
+ }\r
+\r
+ public void setInitialSelection(Object selectedElement) {\r
+ this.setInitialSelections(new Object[] {selectedElement});\r
+ }\r
+\r
+ /**\r
+ * Overridden just to get a hold of the message area label.\r
+ * \r
+ * @see org.eclipse.ui.dialogs.AbstractElementListSelectionDialog#createMessageArea(org.eclipse.swt.widgets.Composite)\r
+ */\r
+ @Override\r
+ protected Label createMessageArea(Composite composite) {\r
+ messageLabel = super.createMessageArea(composite);\r
+ return messageLabel;\r
+ }\r
+\r
+ /**\r
+ * Overridden just to get a hold of the filter text.\r
+ *\r
+ * @see org.eclipse.ui.dialogs.AbstractElementListSelectionDialog#createFilterText(org.eclipse.swt.widgets.Composite)\r
+ */\r
+ @Override\r
+ protected Text createFilterText(Composite parent) {\r
+ filterText = super.createFilterText(parent);\r
+ return filterText;\r
+ }\r
+\r
+ @Override\r
+ protected FilteredList createFilteredList(Composite parent) {\r
+ FilteredList flist = super.createFilteredList(parent);\r
+\r
+ if (usePreviousSelectionSort) \r
+ {\r
+ List<Object> prioritizeList = new ArrayList<Object>();\r
+ int[] previousSelections = getPreviousSelections( title );\r
+ for (int i=0; i<previousSelections.length; i++)\r
+ for (int j=0; j<elementList.size(); j++)\r
+ if (elementList.get(j).hashCode()==previousSelections[i])\r
+ {\r
+ String name = labelProvider.getText(elementList.get(j));\r
+ if (name==null) continue;\r
+ prioritizeList.add(name);\r
+ if (prioritizeList.size()>PRIORITIZE_NUM)\r
+ break;\r
+ }\r
+ \r
+ flist.setComparator(new PrioritizeComparator(prioritizeList, isCaseIgnored()));\r
+ } else {\r
+ }\r
+ return flist;\r
+ }\r
+\r
+ protected void createControls(Composite contents) {\r
+ createMessageArea(contents);\r
+ createFilterText(contents);\r
+ createFilteredList(contents);\r
+ }\r
+ \r
+ /*\r
+ * @see Dialog#createDialogArea(Composite)\r
+ */\r
+ protected Control createDialogArea(Composite parent) {\r
+ Composite contents = (Composite) super.createDialogArea(parent);\r
+\r
+ createControls(contents);\r
+\r
+ setListElements(elementList.toArray(new Object[elementList.size()]));\r
+\r
+ // Select items\r
+ setSelection(getInitialElementSelections().toArray());\r
+\r
+ // If nothing is selected, select the first element\r
+ //if (getSelectionIndices()==null || getSelectionIndices().length==0)\r
+ // this.fFilteredList.setSelection(new int[] {0}); \r
+\r
+ return contents;\r
+ }\r
+ \r
+ @Override\r
+ protected void okPressed() {\r
+ super.okPressed();\r
+ for (Object o : getResult())\r
+ addSelection(title, o);\r
+ }\r
+ \r
+ protected static Map<String, List<Integer>> previousSelections =\r
+ new HashMap<String, List<Integer>>();\r
+ \r
+ protected static synchronized int[] getPreviousSelections(String key)\r
+ {\r
+ List<Integer> list = previousSelections.get(key);\r
+ if (list==null) return new int[0];\r
+ int result[] = new int[list.size()];\r
+ for (int i=0; i<list.size(); i++)\r
+ result[i] = list.get(i);\r
+ return result;\r
+ }\r
+ \r
+ protected static synchronized void addSelection(String key, Object o)\r
+ {\r
+ List<Integer> list = previousSelections.get(key);\r
+ if (list==null) {\r
+ list = new ArrayList<Integer>();\r
+ previousSelections.put(key, list);\r
+ }\r
+ int hash = o.hashCode();\r
+ // remove previous\r
+ for (int i=0; i<list.size(); i++)\r
+ if (list.get(i)==hash)\r
+ {\r
+ list.remove(i);\r
+ }\r
+ // Add as first\r
+ list.add(0, o.hashCode());\r
+ \r
+ // remove last\r
+ if (list.size()>REMEMBER_NUM)\r
+ list.remove(list.size()-1);\r
+ } \r
+ \r
+ public int[] getSelectionIndices() {\r
+ return super.getSelectionIndices();\r
+ }\r
+\r
+ public boolean isUsePreviousSelectionSort() {\r
+ return usePreviousSelectionSort;\r
+ }\r
+\r
+ /**\r
+ * Set usage for sorting of previous selections.\r
+ * When this sorting is enabled, the items that have been selected\r
+ * the items that have been selected previously in this same dialog\r
+ * are prioritized to appear first in the list\r
+ * \r
+ * (Dialogs are distinguished by their title :X)\r
+ * \r
+ * @param usePreviousSelectionSort\r
+ */\r
+ public void setUsePreviousSelectionSort(boolean usePreviousSelectionSort) {\r
+ this.usePreviousSelectionSort = usePreviousSelectionSort;\r
+ }\r
+ \r
+}\r
+\r
+class PrioritizeComparator implements Comparator<Object>\r
+{ \r
+ private final List<Object> prioritizeList;\r
+ private final boolean ignoreCase;\r
+ public PrioritizeComparator(List<Object> prioritizeList, boolean ignoreCase)\r
+ {\r
+ this.prioritizeList = prioritizeList;\r
+ this.ignoreCase = ignoreCase;\r
+ }\r
+ \r
+ public int getIndex(Object o)\r
+ {\r
+ for (int i=0; i<prioritizeList.size(); i++)\r
+ if (o==prioritizeList.get(i))\r
+ return i;\r
+ return Integer.MAX_VALUE/4;\r
+ }\r
+ \r
+ public int compare(Object o1, Object o2) {\r
+ int p1 = getIndex(o1);\r
+ int p2 = getIndex(o2);\r
+ if (p1==p2) \r
+ return (ignoreCase?o1.toString().compareToIgnoreCase(o2.toString()):o1.toString().compareTo(o2.toString())); \r
+ \r
+ return p1-p2;\r
+ }\r
+ \r
+}\r