]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.ui/src/org/simantics/ui/workbench/dialogs/ElementListSelectionDialog.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.ui / src / org / simantics / ui / workbench / dialogs / ElementListSelectionDialog.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 /*
13  * 7.6.2006
14  */
15 package org.simantics.ui.workbench.dialogs;
16
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.Collection;
20 import java.util.Comparator;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24
25 import org.eclipse.jface.viewers.ILabelProvider;
26 import org.eclipse.swt.widgets.Composite;
27 import org.eclipse.swt.widgets.Control;
28 import org.eclipse.swt.widgets.Display;
29 import org.eclipse.swt.widgets.Label;
30 import org.eclipse.swt.widgets.Shell;
31 import org.eclipse.swt.widgets.Text;
32 import org.eclipse.ui.dialogs.AbstractElementListSelectionDialog;
33 import org.eclipse.ui.dialogs.FilteredList;
34
35 /**
36  * ElementListSelectionDialog. This dialog component automatically sorts
37  * previously selected objects to the top of the list. 
38  * <p>
39  * The component uses title as key for distinguishing different dialog types.
40  * 
41  * @author Toni Kalajainen
42  * @author Tuukka Lehtonen
43  */
44 public class ElementListSelectionDialog extends AbstractElementListSelectionDialog {
45
46     /** The number of previously selected objects to be remembered */
47     protected static final int REMEMBER_NUM             = 128;
48
49     /** The number of previously selected objects to be prioritized in the list */
50     protected static final int PRIORITIZE_NUM           = 5;
51     
52     protected String           title                    = "";
53
54     protected List<Object>     elementList              = new ArrayList<Object>();
55
56     protected ILabelProvider   labelProvider;
57
58     protected boolean          usePreviousSelectionSort = true;
59
60     protected Label            messageLabel;
61
62     protected Text             filterText;
63
64
65     /**
66      * Creates a list selection dialog.
67      * 
68      * @param parent the parent widget.
69      * @param labelProvider the label provider.
70      */
71     public ElementListSelectionDialog(Shell parent, ILabelProvider labelProvider) {
72         super(parent, labelProvider);
73         this.labelProvider = labelProvider;
74         this.setIgnoreCase(true);
75     }
76
77     /**
78      * Sets the elements of the list.
79      * @param elements the elements of the list.
80      */
81     public void setElements(Object... elements) {
82         elementList = null;
83         addElements(elements);
84     }
85
86     public void addElements(Object... elements) {
87         if (elementList==null)
88             elementList = new ArrayList<Object>();
89         for (Object e : elements)
90             elementList.add(e);
91     }
92
93     /**
94      * Sets the elements of the list.
95      * @param elements the elements of the list.
96      */
97     @SuppressWarnings("rawtypes")
98     public void setElements(Collection c) {
99         elementList = null;
100         addElements(c);
101     }
102
103     @SuppressWarnings("rawtypes")
104     public void addElements(Collection c) {
105         if (elementList==null)
106             elementList = new ArrayList<Object>();
107         for (Object e : c)
108             elementList.add(e);
109     }
110
111     public void updateList() {
112         // Make sure that the filtered list exists before trying to update it.
113         if (fFilteredList != null && elementList != null) {
114             Object[] objs = elementList.toArray(new Object[elementList.size()]);
115             final boolean isEmpty = objs.length == 0;
116             setListElements(objs);
117             Runnable r = new Runnable() {
118                 public void run() {
119                     handleListChange(isEmpty);
120                 }
121             };
122             Display d = getShell().getDisplay();
123             if (Thread.currentThread() == d.getThread())
124                 r.run();
125             else
126                 d.asyncExec(r);
127         }
128     }
129
130     protected void handleListChange(boolean isEmpty) {
131         boolean wasEnabled = filterText.isEnabled();
132         boolean enable = !isEmpty;
133         messageLabel.setEnabled(enable);
134         filterText.setEnabled(enable);
135         fFilteredList.setEnabled(enable);
136         if (!wasEnabled)
137             filterText.setFocus();
138         updateOkState();
139     }
140
141     /**
142      * Do alphabetical sort for list elements
143      */
144     public void sortElements() {
145         if (elementList==null) return;
146         
147         Object[] objects = elementList.toArray(new Object[0]);
148         Arrays.sort(objects, new Comparator<Object>() {
149             public int compare(Object o1, Object o2) {
150                 String n1 = labelProvider.getText(o1).toLowerCase();
151                 String n2 = labelProvider.getText(o2).toLowerCase();
152                 return n1.compareTo(n2);
153             }});
154         
155         elementList = new ArrayList<Object>(objects.length);
156         for (Object o : objects)
157             elementList.add(o);
158     }
159
160     /*
161      * @see SelectionStatusDialog#computeResult()
162      */
163     protected void computeResult() {
164         setResult(Arrays.asList(getSelectedElements()));
165     }
166
167     @Override
168     public void setTitle(String title) {
169         super.setTitle(title);
170         this.title = title;
171     }
172
173     public void setInitialSelection(Object selectedElement) {
174         this.setInitialSelections(new Object[] {selectedElement});
175     }
176
177     /**
178      * Overridden just to get a hold of the message area label.
179      * 
180      * @see org.eclipse.ui.dialogs.AbstractElementListSelectionDialog#createMessageArea(org.eclipse.swt.widgets.Composite)
181      */
182     @Override
183     protected Label createMessageArea(Composite composite) {
184         messageLabel = super.createMessageArea(composite);
185         return messageLabel;
186     }
187
188     /**
189      * Overridden just to get a hold of the filter text.
190      *
191      * @see org.eclipse.ui.dialogs.AbstractElementListSelectionDialog#createFilterText(org.eclipse.swt.widgets.Composite)
192      */
193     @Override
194     protected Text createFilterText(Composite parent) {
195         filterText = super.createFilterText(parent);
196         return filterText;
197     }
198
199     @Override
200     protected FilteredList createFilteredList(Composite parent) {
201         FilteredList flist = super.createFilteredList(parent);
202
203         if (usePreviousSelectionSort) 
204         {
205             List<Object> prioritizeList = new ArrayList<Object>();
206             int[] previousSelections = getPreviousSelections( title );
207             for (int i=0; i<previousSelections.length; i++)
208                 for (int j=0; j<elementList.size(); j++)
209                     if (elementList.get(j).hashCode()==previousSelections[i])
210                     {
211                         String name = labelProvider.getText(elementList.get(j));
212                         if (name==null) continue;
213                         prioritizeList.add(name);
214                         if (prioritizeList.size()>PRIORITIZE_NUM)
215                             break;
216                     }
217         
218             flist.setComparator(new PrioritizeComparator(prioritizeList, isCaseIgnored()));
219         } else {
220         }
221         return flist;
222     }
223
224     protected void createControls(Composite contents) {
225         createMessageArea(contents);
226         createFilterText(contents);
227         createFilteredList(contents);
228     }
229     
230     /*
231      * @see Dialog#createDialogArea(Composite)
232      */
233     protected Control createDialogArea(Composite parent) {
234         Composite contents = (Composite) super.createDialogArea(parent);
235
236         createControls(contents);
237
238         setListElements(elementList.toArray(new Object[elementList.size()]));
239
240         // Select items
241         setSelection(getInitialElementSelections().toArray());
242
243         // If nothing is selected, select the first element
244         //if (getSelectionIndices()==null || getSelectionIndices().length==0)
245         //    this.fFilteredList.setSelection(new int[] {0});        
246
247         return contents;
248     }
249     
250     @Override
251     protected void okPressed() {
252         super.okPressed();
253         for (Object o : getResult())
254             addSelection(title, o);
255     }
256     
257     protected static Map<String, List<Integer>> previousSelections =
258          new HashMap<String, List<Integer>>();
259     
260     protected static synchronized int[] getPreviousSelections(String key)
261     {
262         List<Integer> list = previousSelections.get(key);
263         if (list==null) return new int[0];
264         int result[] = new int[list.size()];
265         for (int i=0; i<list.size(); i++)
266             result[i] = list.get(i);
267         return result;
268     }
269     
270     protected static synchronized void addSelection(String key, Object o)
271     {
272         List<Integer> list = previousSelections.get(key);
273         if (list==null) {
274             list = new ArrayList<Integer>();
275             previousSelections.put(key, list);
276         }
277         int hash = o.hashCode();
278         // remove previous
279         for (int i=0; i<list.size(); i++)
280             if (list.get(i)==hash)
281             {
282                 list.remove(i);
283             }
284         // Add as first
285         list.add(0, o.hashCode());
286         
287         // remove last
288         if (list.size()>REMEMBER_NUM)
289             list.remove(list.size()-1);
290     }    
291     
292     public int[] getSelectionIndices() {
293         return super.getSelectionIndices();
294     }
295
296     public boolean isUsePreviousSelectionSort() {
297         return usePreviousSelectionSort;
298     }
299
300     /**
301      * Set usage for sorting of previous selections.
302      * When this sorting is enabled, the items that have been selected
303      * the items that have been selected previously in this same dialog
304      * are prioritized to appear first in the list
305      * 
306      * (Dialogs are distinguished by their title :X)
307      * 
308      * @param usePreviousSelectionSort
309      */
310     public void setUsePreviousSelectionSort(boolean usePreviousSelectionSort) {
311         this.usePreviousSelectionSort = usePreviousSelectionSort;
312     }
313     
314 }
315
316 class PrioritizeComparator implements Comparator<Object>
317 {    
318     private final List<Object> prioritizeList;
319     private final boolean ignoreCase;
320     public PrioritizeComparator(List<Object> prioritizeList, boolean ignoreCase)
321     {
322         this.prioritizeList = prioritizeList;
323         this.ignoreCase = ignoreCase;
324     }
325     
326     public int getIndex(Object o)
327     {
328         for (int i=0; i<prioritizeList.size(); i++)
329             if (o==prioritizeList.get(i))
330                 return i;
331         return Integer.MAX_VALUE/4;
332     }
333     
334     public int compare(Object o1, Object o2) {
335         int p1 = getIndex(o1);
336         int p2 = getIndex(o2);
337         if (p1==p2)            
338             return (ignoreCase?o1.toString().compareToIgnoreCase(o2.toString()):o1.toString().compareTo(o2.toString()));     
339         
340         return p1-p2;
341     }
342     
343 }