103f5e5afa4369b297ac280957b4f7fdd2cb538b
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / dialogs / AbstractElementListSelectionDialog.java
1 package net.sourceforge.phpdt.internal.ui.dialogs;
2
3 import net.sourceforge.phpdt.internal.ui.util.FilteredList;
4
5 import org.eclipse.core.runtime.IStatus;
6 import org.eclipse.jface.dialogs.IDialogConstants;
7 import org.eclipse.jface.util.Assert;
8 import org.eclipse.jface.viewers.ILabelProvider;
9 import org.eclipse.swt.SWT;
10 import org.eclipse.swt.custom.BusyIndicator;
11 import org.eclipse.swt.events.KeyEvent;
12 import org.eclipse.swt.events.KeyListener;
13 import org.eclipse.swt.events.SelectionEvent;
14 import org.eclipse.swt.events.SelectionListener;
15 import org.eclipse.swt.layout.GridData;
16 import org.eclipse.swt.widgets.Composite;
17 import org.eclipse.swt.widgets.Event;
18 import org.eclipse.swt.widgets.Label;
19 import org.eclipse.swt.widgets.Listener;
20 import org.eclipse.swt.widgets.Shell;
21 import org.eclipse.swt.widgets.Text;
22
23 /**
24  * An abstract class to select elements out of a list of elements.
25  */
26 public abstract class AbstractElementListSelectionDialog extends
27                 SelectionStatusDialog {
28
29         private ILabelProvider fRenderer;
30
31         private boolean fIgnoreCase = true;
32
33         private boolean fIsMultipleSelection = false;
34
35         private boolean fMatchEmptyString = true;
36
37         private boolean fAllowDuplicates = true;
38
39         private Label fMessage;
40
41         protected FilteredList fFilteredList;
42
43         private Text fFilterText;
44
45         private ISelectionValidator fValidator;
46
47         private String fFilter = null;
48
49         private String fEmptyListMessage = ""; //$NON-NLS-1$
50
51         private String fEmptySelectionMessage = ""; //$NON-NLS-1$
52
53         private int fWidth = 60;
54
55         private int fHeight = 18;
56
57         private Object[] fSelection = new Object[0];
58
59         /**
60          * Constructs a list selection dialog.
61          * 
62          * @param renderer
63          *            The label renderer used
64          * @param ignoreCase
65          *            Decides if the match string ignores lower/upppr case
66          * @param multipleSelection
67          *            Allow multiple selection
68          */
69         protected AbstractElementListSelectionDialog(Shell parent,
70                         ILabelProvider renderer) {
71                 super(parent);
72                 fRenderer = renderer;
73
74                 int shellStyle = getShellStyle();
75                 setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE);
76         }
77
78         /**
79          * Handles default selection (double click). By default, the OK button is
80          * pressed.
81          */
82         protected void handleDefaultSelected() {
83                 if (validateCurrentSelection())
84                         buttonPressed(IDialogConstants.OK_ID);
85         }
86
87         /**
88          * Specifies if sorting, filtering and folding is case sensitive.
89          */
90         public void setIgnoreCase(boolean ignoreCase) {
91                 fIgnoreCase = ignoreCase;
92         }
93
94         /**
95          * Returns if sorting, filtering and folding is case sensitive.
96          */
97         public boolean isCaseIgnored() {
98                 return fIgnoreCase;
99         }
100
101         /**
102          * Specifies whether everything or nothing should be filtered on empty
103          * filter string.
104          */
105         public void setMatchEmptyString(boolean matchEmptyString) {
106                 fMatchEmptyString = matchEmptyString;
107         }
108
109         /**
110          * Specifies if multiple selection is allowed.
111          */
112         public void setMultipleSelection(boolean multipleSelection) {
113                 fIsMultipleSelection = multipleSelection;
114         }
115
116         /**
117          * Specifies whether duplicate entries are displayed or not.
118          */
119         public void setAllowDuplicates(boolean allowDuplicates) {
120                 fAllowDuplicates = allowDuplicates;
121         }
122
123         /**
124          * Sets the list size in unit of characters.
125          * 
126          * @param width
127          *            the width of the list.
128          * @param height
129          *            the height of the list.
130          */
131         public void setSize(int width, int height) {
132                 fWidth = width;
133                 fHeight = height;
134         }
135
136         /**
137          * Sets the message to be displayed if the list is empty.
138          * 
139          * @param message
140          *            the message to be displayed.
141          */
142         public void setEmptyListMessage(String message) {
143                 fEmptyListMessage = message;
144         }
145
146         /**
147          * Sets the message to be displayed if the selection is empty.
148          * 
149          * @param message
150          *            the message to be displayed.
151          */
152         public void setEmptySelectionMessage(String message) {
153                 fEmptySelectionMessage = message;
154         }
155
156         /**
157          * Sets an optional validator to check if the selection is valid. The
158          * validator is invoked whenever the selection changes.
159          * 
160          * @param validator
161          *            the validator to validate the selection.
162          */
163         public void setValidator(ISelectionValidator validator) {
164                 fValidator = validator;
165         }
166
167         /**
168          * Sets the elements of the list (widget). To be called within open().
169          * 
170          * @param elements
171          *            the elements of the list.
172          */
173         protected void setListElements(Object[] elements) {
174                 Assert.isNotNull(fFilteredList);
175                 fFilteredList.setElements(elements);
176         }
177
178         /**
179          * Sets the filter pattern.
180          * 
181          * @param filter
182          *            the filter pattern.
183          */
184         public void setFilter(String filter) {
185                 if (fFilterText == null)
186                         fFilter = filter;
187                 else
188                         fFilterText.setText(filter);
189         }
190
191         /**
192          * Returns the current filter pattern.
193          * 
194          * @return returns the current filter pattern or
195          *         <code>null<code> if filter was not set.
196          */
197         public String getFilter() {
198                 if (fFilteredList == null)
199                         return fFilter;
200                 else
201                         return fFilteredList.getFilter();
202         }
203
204         /**
205          * Returns the indices referring the current selection. To be called within
206          * open().
207          * 
208          * @return returns the indices of the current selection.
209          */
210         protected int[] getSelectionIndices() {
211                 Assert.isNotNull(fFilteredList);
212                 return fFilteredList.getSelectionIndices();
213         }
214
215         /**
216          * Returns an index referring the first current selection. To be called
217          * within open().
218          * 
219          * @return returns the indices of the current selection.
220          */
221         protected int getSelectionIndex() {
222                 Assert.isNotNull(fFilteredList);
223                 return fFilteredList.getSelectionIndex();
224         }
225
226         /**
227          * Sets the selection referenced by an array of elements. To be called
228          * within open().
229          * 
230          * @param selection
231          *            the indices of the selection.
232          */
233         protected void setSelection(Object[] selection) {
234                 Assert.isNotNull(fFilteredList);
235                 fFilteredList.setSelection(selection);
236         }
237
238         /**
239          * Returns an array of the currently selected elements. To be called within
240          * or after open().
241          * 
242          * @return returns an array of the currently selected elements.
243          */
244         protected Object[] getSelectedElements() {
245                 Assert.isNotNull(fFilteredList);
246                 return fFilteredList.getSelection();
247         }
248
249         /**
250          * Returns all elements which are folded together to one entry in the list.
251          * 
252          * @param index
253          *            the index selecting the entry in the list.
254          * @return returns an array of elements folded together.
255          */
256         public Object[] getFoldedElements(int index) {
257                 Assert.isNotNull(fFilteredList);
258                 return fFilteredList.getFoldedElements(index);
259         }
260
261         /**
262          * Creates the message text widget and sets layout data.
263          * 
264          * @param composite
265          *            the parent composite of the message area.
266          */
267         protected Label createMessageArea(Composite composite) {
268                 Label label = super.createMessageArea(composite);
269
270                 GridData data = new GridData();
271                 data.grabExcessVerticalSpace = false;
272                 data.grabExcessHorizontalSpace = true;
273                 data.horizontalAlignment = GridData.FILL;
274                 data.verticalAlignment = GridData.BEGINNING;
275                 label.setLayoutData(data);
276
277                 fMessage = label;
278
279                 return label;
280         }
281
282         /**
283          * Handles a selection changed event. By default, the current selection is
284          * validated.
285          */
286         protected void handleSelectionChanged() {
287                 validateCurrentSelection();
288         }
289
290         /**
291          * Validates the current selection and updates the status line accordingly.
292          */
293         protected boolean validateCurrentSelection() {
294                 Assert.isNotNull(fFilteredList);
295
296                 IStatus status;
297                 Object[] elements = getSelectedElements();
298
299                 if (elements.length > 0) {
300                         if (fValidator != null) {
301                                 status = fValidator.validate(elements);
302                         } else {
303                                 status = new StatusInfo();
304                         }
305                 } else {
306                         if (fFilteredList.isEmpty()) {
307                                 status = new StatusInfo(IStatus.ERROR, fEmptyListMessage);
308                         } else {
309                                 status = new StatusInfo(IStatus.ERROR, fEmptySelectionMessage);
310                         }
311                 }
312
313                 updateStatus(status);
314
315                 return status.isOK();
316         }
317
318         /*
319          * @see Dialog#cancelPressed
320          */
321         protected void cancelPressed() {
322                 setResult(null);
323                 super.cancelPressed();
324         }
325
326         /**
327          * Creates a filtered list.
328          * 
329          * @param parent
330          *            the parent composite.
331          * @return returns the filtered list widget.
332          */
333         protected FilteredList createFilteredList(Composite parent) {
334                 int flags = SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL
335                                 | (fIsMultipleSelection ? SWT.MULTI : SWT.SINGLE);
336
337                 FilteredList list = new FilteredList(parent, flags, fRenderer,
338                                 fIgnoreCase, fAllowDuplicates, fMatchEmptyString);
339
340                 GridData data = new GridData();
341                 data.widthHint = convertWidthInCharsToPixels(fWidth);
342                 data.heightHint = convertHeightInCharsToPixels(fHeight);
343                 data.grabExcessVerticalSpace = true;
344                 data.grabExcessHorizontalSpace = true;
345                 data.horizontalAlignment = GridData.FILL;
346                 data.verticalAlignment = GridData.FILL;
347                 list.setLayoutData(data);
348
349                 list.setFilter((fFilter == null ? "" : fFilter)); //$NON-NLS-1$         
350
351                 list.addSelectionListener(new SelectionListener() {
352                         public void widgetDefaultSelected(SelectionEvent e) {
353                                 handleDefaultSelected();
354                         }
355
356                         public void widgetSelected(SelectionEvent e) {
357                                 handleWidgetSelected();
358                         }
359                 });
360
361                 fFilteredList = list;
362
363                 return list;
364         }
365
366         // 3515
367         private void handleWidgetSelected() {
368                 Object[] newSelection = fFilteredList.getSelection();
369
370                 if (newSelection.length != fSelection.length) {
371                         fSelection = newSelection;
372                         handleSelectionChanged();
373                 } else {
374                         for (int i = 0; i != newSelection.length; i++) {
375                                 if (!newSelection[i].equals(fSelection[i])) {
376                                         fSelection = newSelection;
377                                         handleSelectionChanged();
378                                         break;
379                                 }
380                         }
381                 }
382         }
383
384         protected Text createFilterText(Composite parent) {
385                 Text text = new Text(parent, SWT.BORDER);
386
387                 GridData data = new GridData();
388                 data.grabExcessVerticalSpace = false;
389                 data.grabExcessHorizontalSpace = true;
390                 data.horizontalAlignment = GridData.FILL;
391                 data.verticalAlignment = GridData.BEGINNING;
392                 text.setLayoutData(data);
393
394                 text.setText((fFilter == null ? "" : fFilter)); //$NON-NLS-1$
395
396                 Listener listener = new Listener() {
397                         public void handleEvent(Event e) {
398                                 fFilteredList.setFilter(fFilterText.getText());
399                         }
400                 };
401                 text.addListener(SWT.Modify, listener);
402
403                 text.addKeyListener(new KeyListener() {
404                         public void keyPressed(KeyEvent e) {
405                                 if (e.keyCode == SWT.ARROW_DOWN)
406                                         fFilteredList.setFocus();
407                         }
408
409                         public void keyReleased(KeyEvent e) {
410                         }
411                 });
412
413                 fFilterText = text;
414
415                 return text;
416         }
417
418         /*
419          * @see Window#open()
420          */
421         public int open() {
422                 BusyIndicator.showWhile(null, new Runnable() {
423                         public void run() {
424                                 access$superOpen();
425                         }
426                 });
427                 return getReturnCode();
428         }
429
430         private void access$superOpen() {
431                 super.open();
432         }
433
434         /*
435          * @see Window#create(Shell)
436          */
437         public void create() {
438                 super.create();
439
440                 Assert.isNotNull(fFilteredList);
441
442                 if (fFilteredList.isEmpty()) {
443                         handleEmptyList();
444                 } else {
445                         validateCurrentSelection();
446                         fFilterText.selectAll();
447                         fFilterText.setFocus();
448                 }
449         }
450
451         /**
452          * Handles empty list by disabling widgets.
453          */
454         protected void handleEmptyList() {
455                 fMessage.setEnabled(false);
456                 fFilterText.setEnabled(false);
457                 fFilteredList.setEnabled(false);
458         }
459
460 }