new version 1.0.4
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / dialog / CheckedTreeSelectionDialog.java
1 package net.sourceforge.phpdt.internal.ui.dialog;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.List;
6
7 import org.eclipse.core.runtime.IStatus;
8 import org.eclipse.jface.dialogs.IDialogConstants;
9 import org.eclipse.jface.viewers.CheckStateChangedEvent;
10 import org.eclipse.jface.viewers.CheckboxTreeViewer;
11 import org.eclipse.jface.viewers.ICheckStateListener;
12 import org.eclipse.jface.viewers.ILabelProvider;
13 import org.eclipse.jface.viewers.ITreeContentProvider;
14 import org.eclipse.jface.viewers.ViewerFilter;
15 import org.eclipse.jface.viewers.ViewerSorter;
16 import org.eclipse.swt.SWT;
17 import org.eclipse.swt.custom.BusyIndicator;
18 import org.eclipse.swt.events.SelectionAdapter;
19 import org.eclipse.swt.events.SelectionEvent;
20 import org.eclipse.swt.events.SelectionListener;
21 import org.eclipse.swt.layout.GridData;
22 import org.eclipse.swt.layout.GridLayout;
23 import org.eclipse.swt.widgets.Button;
24 import org.eclipse.swt.widgets.Composite;
25 import org.eclipse.swt.widgets.Control;
26 import org.eclipse.swt.widgets.Label;
27 import org.eclipse.swt.widgets.Shell;
28 import org.eclipse.swt.widgets.Tree;
29 import net.sourceforge.phpdt.internal.ui.viewsupport.ContainerCheckedTreeViewer;
30
31 /**
32  * A class to select elements out of a tree structure.
33  */
34 public class CheckedTreeSelectionDialog extends SelectionStatusDialog {
35
36         private CheckboxTreeViewer fViewer;
37
38         private ILabelProvider fLabelProvider;
39         private ITreeContentProvider fContentProvider;
40
41         private ISelectionValidator fValidator = null;
42         private ViewerSorter fSorter;
43         private String fEmptyListMessage = "No entries available";
44
45         private IStatus fCurrStatus = new StatusInfo();
46         private List fFilters;
47         private Object fInput;
48         private boolean fIsEmpty;
49
50         private int fWidth = 60;
51         private int fHeight = 18;
52
53         private boolean fContainerMode;
54         private Object[] fExpandedElements;
55
56         /**
57          * Constructs an instance of <code>ElementTreeSelectionDialog</code>.
58          * @param labelProvider   the label provider to render the entries
59          * @param contentProvider the content provider to evaluate the tree structure
60          */
61         public CheckedTreeSelectionDialog(Shell parent, ILabelProvider labelProvider, ITreeContentProvider contentProvider) {
62                 super(parent);
63
64                 fLabelProvider = labelProvider;
65                 fContentProvider = contentProvider;
66
67                 setResult(new ArrayList(0));
68                 setStatusLineAboveButtons(true);
69
70                 fContainerMode = false;
71                 fExpandedElements = null;
72
73                 int shellStyle = getShellStyle();
74                 setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE);
75         }
76
77         /**
78          * If set, the checked /gray state of containers (inner nodes) is derived from the checked state of its 
79          * leaf nodes.
80          * @param containerMode The containerMode to set
81          */
82         public void setContainerMode(boolean containerMode) {
83                 fContainerMode = containerMode;
84         }
85
86         /**
87          * Sets the initial selection.
88          * Convenience method.
89          * @param selection the initial selection.
90          */
91         public void setInitialSelection(Object selection) {
92                 setInitialSelections(new Object[] { selection });
93         }
94
95         /**
96          * Sets the message to be displayed if the list is empty.
97          * @param message the message to be displayed.
98          */
99         public void setEmptyListMessage(String message) {
100                 fEmptyListMessage = message;
101         }
102
103         /**
104          * Sets the sorter used by the tree viewer.
105          */
106         public void setSorter(ViewerSorter sorter) {
107                 fSorter = sorter;
108         }
109
110         /**
111          * Adds a filter to the tree viewer.
112          * @param filter a filter.
113          */
114         public void addFilter(ViewerFilter filter) {
115                 if (fFilters == null)
116                         fFilters = new ArrayList(4);
117
118                 fFilters.add(filter);
119         }
120
121         /**
122          * Sets an optional validator to check if the selection is valid.
123          * The validator is invoked whenever the selection changes.
124          * @param validator the validator to validate the selection.
125          */
126         public void setValidator(ISelectionValidator validator) {
127                 fValidator = validator;
128         }
129
130         /**
131          * Sets the tree input.
132          * @param input the tree input.
133          */
134         public void setInput(Object input) {
135                 fInput = input;
136         }
137
138         /**
139          * Expands the tree
140          */
141         public void setExpandedElements(Object[] elements) {
142                 fExpandedElements = elements;
143         }
144
145         /**
146          * Sets the size of the tree in unit of characters.
147          * @param width  the width of the tree.
148          * @param height the height of the tree.
149          */
150         public void setSize(int width, int height) {
151                 fWidth = width;
152                 fHeight = height;
153         }
154
155         protected void updateOKStatus() {
156                 if (!fIsEmpty) {
157                         if (fValidator != null) {
158                                 fCurrStatus = fValidator.validate(fViewer.getCheckedElements());
159                                 updateStatus(fCurrStatus);
160                         } else if (!fCurrStatus.isOK()) {
161                                 fCurrStatus = new StatusInfo();
162                         }
163                 } else {
164                         fCurrStatus = new StatusInfo(IStatus.ERROR, fEmptyListMessage);
165                 }
166                 updateStatus(fCurrStatus);
167         }
168
169         /*
170          * @see Window#open()
171          */
172         public int open() {
173                 fIsEmpty = evaluateIfTreeEmpty(fInput);
174                 BusyIndicator.showWhile(null, new Runnable() {
175                         public void run() {
176                                 access$superOpen();
177                         }
178                 });
179
180                 return getReturnCode();
181         }
182
183         private void access$superOpen() {
184                 super.open();
185         }
186
187         /**
188          * Handles cancel button pressed event.
189          */
190         protected void cancelPressed() {
191                 setResult(null);
192                 super.cancelPressed();
193         }
194
195         /*
196          * @see SelectionStatusDialog#computeResult()
197          */
198         protected void computeResult() {
199                 setResult(Arrays.asList(fViewer.getCheckedElements()));
200         }
201
202         /*
203          * @see Window#create()
204          */
205         public void create() {
206                 super.create();
207
208                 List initialSelections = getInitialSelections();
209                 if (initialSelections != null) {
210                         fViewer.setCheckedElements(initialSelections.toArray());
211                 }
212
213                 if (fExpandedElements != null) {
214                         fViewer.setExpandedElements(fExpandedElements);
215                 }
216
217                 updateOKStatus();
218         }
219
220         /*
221          * @see Dialog#createDialogArea(Composite)
222          */
223         protected Control createDialogArea(Composite parent) {
224                 Composite composite = (Composite) super.createDialogArea(parent);
225
226                 Label messageLabel = createMessageArea(composite);
227                 Control treeWidget = createTreeViewer(composite);
228                 Control buttonComposite = createSelectionButtons(composite);
229
230                 GridData data = new GridData(GridData.FILL_BOTH);
231                 data.widthHint = convertWidthInCharsToPixels(fWidth);
232                 data.heightHint = convertHeightInCharsToPixels(fHeight);
233                 treeWidget.setLayoutData(data);
234
235                 if (fIsEmpty) {
236                         messageLabel.setEnabled(false);
237                         treeWidget.setEnabled(false);
238                         buttonComposite.setEnabled(false);
239                 }
240
241                 return composite;
242         }
243
244         private Tree createTreeViewer(Composite parent) {
245                 if (fContainerMode) {
246                         fViewer = new ContainerCheckedTreeViewer(parent, SWT.BORDER);
247                 } else {
248                         fViewer = new CheckboxTreeViewer(parent, SWT.BORDER);
249                 }
250
251                 fViewer.setContentProvider(fContentProvider);
252                 fViewer.setLabelProvider(fLabelProvider);
253                 fViewer.addCheckStateListener(new ICheckStateListener() {
254                         public void checkStateChanged(CheckStateChangedEvent event) {
255                                 updateOKStatus();
256                         }
257                 });
258
259                 fViewer.setSorter(fSorter);
260                 if (fFilters != null) {
261                         for (int i = 0; i != fFilters.size(); i++)
262                                 fViewer.addFilter((ViewerFilter) fFilters.get(i));
263                 }
264
265                 fViewer.setInput(fInput);
266
267                 return fViewer.getTree();
268         }
269
270         /**
271          * Add the selection and deselection buttons to the dialog.
272          * @param composite org.eclipse.swt.widgets.Composite
273          */
274         private Composite createSelectionButtons(Composite composite) {
275
276                 Composite buttonComposite = new Composite(composite, SWT.RIGHT);
277                 GridLayout layout = new GridLayout();
278                 layout.numColumns = 2;
279                 buttonComposite.setLayout(layout);
280                 GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END | GridData.GRAB_HORIZONTAL);
281                 data.grabExcessHorizontalSpace = true;
282                 composite.setData(data);
283
284                 Button selectButton = createButton(buttonComposite, IDialogConstants.SELECT_ALL_ID, "Select &All", false);
285
286                 SelectionListener listener = new SelectionAdapter() {
287                         public void widgetSelected(SelectionEvent e) {
288                                 fViewer.setCheckedElements(fContentProvider.getElements(fInput));
289                                 updateOKStatus();
290                         }
291                 };
292                 selectButton.addSelectionListener(listener);
293
294                 Button deselectButton = createButton(buttonComposite, IDialogConstants.DESELECT_ALL_ID, "&Deselect All", false);
295
296                 listener = new SelectionAdapter() {
297                         public void widgetSelected(SelectionEvent e) {
298                                 fViewer.setCheckedElements(new Object[0]);
299                                 updateOKStatus();
300                         }
301                 };
302                 deselectButton.addSelectionListener(listener);
303                 return buttonComposite;
304         }
305
306         private boolean evaluateIfTreeEmpty(Object input) {
307                 Object[] elements = fContentProvider.getElements(input);
308                 if (elements.length > 0) {
309                         if (fFilters != null) {
310                                 for (int i = 0; i < fFilters.size(); i++) {
311                                         ViewerFilter curr = (ViewerFilter) fFilters.get(i);
312                                         elements = curr.filter(fViewer, input, elements);
313                                 }
314                         }
315                 }
316                 return elements.length == 0;
317         }
318
319 }