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