8bed2adc005c5235a4fb8c3bf1254021a90e546d
[phpeclipse.git] /
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.wizards.dialogfields;
12
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
16
17 import net.sourceforge.phpdt.internal.ui.util.PixelConverter;
18 import net.sourceforge.phpdt.internal.ui.util.SWTUtil;
19
20 import org.eclipse.jface.util.Assert;
21 import org.eclipse.jface.viewers.DoubleClickEvent;
22 import org.eclipse.jface.viewers.IDoubleClickListener;
23 import org.eclipse.jface.viewers.ILabelProvider;
24 import org.eclipse.jface.viewers.ISelection;
25 import org.eclipse.jface.viewers.ISelectionChangedListener;
26 import org.eclipse.jface.viewers.IStructuredSelection;
27 import org.eclipse.jface.viewers.ITreeContentProvider;
28 import org.eclipse.jface.viewers.SelectionChangedEvent;
29 import org.eclipse.jface.viewers.StructuredSelection;
30 import org.eclipse.jface.viewers.TreeViewer;
31 import org.eclipse.jface.viewers.Viewer;
32 import org.eclipse.jface.viewers.ViewerSorter;
33 import org.eclipse.swt.SWT;
34 import org.eclipse.swt.events.KeyAdapter;
35 import org.eclipse.swt.events.KeyEvent;
36 import org.eclipse.swt.events.SelectionEvent;
37 import org.eclipse.swt.events.SelectionListener;
38 import org.eclipse.swt.layout.GridData;
39 import org.eclipse.swt.layout.GridLayout;
40 import org.eclipse.swt.widgets.Button;
41 import org.eclipse.swt.widgets.Composite;
42 import org.eclipse.swt.widgets.Control;
43 import org.eclipse.swt.widgets.Display;
44 import org.eclipse.swt.widgets.Label;
45 import org.eclipse.swt.widgets.Tree;
46
47 /**
48  * A list with a button bar. Typical buttons are 'Add', 'Remove', 'Up' and
49  * 'Down'. List model is independend of widget creation. DialogFields controls
50  * are: Label, List and Composite containing buttons.
51  */
52 public class TreeListDialogField extends DialogField {
53
54         protected TreeViewer fTree;
55
56         protected ILabelProvider fLabelProvider;
57
58         protected TreeViewerAdapter fTreeViewerAdapter;
59
60         protected List fElements;
61
62         protected ViewerSorter fViewerSorter;
63
64         protected String[] fButtonLabels;
65
66         private Button[] fButtonControls;
67
68         private boolean[] fButtonsEnabled;
69
70         private int fRemoveButtonIndex;
71
72         private int fUpButtonIndex;
73
74         private int fDownButtonIndex;
75
76         private Label fLastSeparator;
77
78         private Tree fTreeControl;
79
80         private Composite fButtonsControl;
81
82         private ISelection fSelectionWhenEnabled;
83
84         private ITreeListAdapter fTreeAdapter;
85
86         private Object fParentElement;
87
88         private int fTreeExpandLevel;
89
90         /**
91          * @param adapter
92          *            Can be <code>null</code>.
93          */
94         public TreeListDialogField(ITreeListAdapter adapter, String[] buttonLabels,
95                         ILabelProvider lprovider) {
96                 super();
97                 fTreeAdapter = adapter;
98
99                 fLabelProvider = lprovider;
100                 fTreeViewerAdapter = new TreeViewerAdapter();
101                 fParentElement = this;
102
103                 fElements = new ArrayList(10);
104
105                 fButtonLabels = buttonLabels;
106                 if (fButtonLabels != null) {
107                         int nButtons = fButtonLabels.length;
108                         fButtonsEnabled = new boolean[nButtons];
109                         for (int i = 0; i < nButtons; i++) {
110                                 fButtonsEnabled[i] = true;
111                         }
112                 }
113
114                 fTree = null;
115                 fTreeControl = null;
116                 fButtonsControl = null;
117
118                 fRemoveButtonIndex = -1;
119                 fUpButtonIndex = -1;
120                 fDownButtonIndex = -1;
121
122                 fTreeExpandLevel = 0;
123         }
124
125         /**
126          * Sets the index of the 'remove' button in the button label array passed in
127          * the constructor. The behaviour of the button marked as the 'remove'
128          * button will then behandled internally. (enable state, button invocation
129          * behaviour)
130          */
131         public void setRemoveButtonIndex(int removeButtonIndex) {
132                 Assert.isTrue(removeButtonIndex < fButtonLabels.length);
133                 fRemoveButtonIndex = removeButtonIndex;
134         }
135
136         /**
137          * Sets the index of the 'up' button in the button label array passed in the
138          * constructor. The behaviour of the button marked as the 'up' button will
139          * then behandled internally. (enable state, button invocation behaviour)
140          */
141         public void setUpButtonIndex(int upButtonIndex) {
142                 Assert.isTrue(upButtonIndex < fButtonLabels.length);
143                 fUpButtonIndex = upButtonIndex;
144         }
145
146         /**
147          * Sets the index of the 'down' button in the button label array passed in
148          * the constructor. The behaviour of the button marked as the 'down' button
149          * will then be handled internally. (enable state, button invocation
150          * behaviour)
151          */
152         public void setDownButtonIndex(int downButtonIndex) {
153                 Assert.isTrue(downButtonIndex < fButtonLabels.length);
154                 fDownButtonIndex = downButtonIndex;
155         }
156
157         /**
158          * Sets the viewerSorter.
159          * 
160          * @param viewerSorter
161          *            The viewerSorter to set
162          */
163         public void setViewerSorter(ViewerSorter viewerSorter) {
164                 fViewerSorter = viewerSorter;
165         }
166
167         /**
168          * Sets the viewerSorter.
169          * 
170          * @param viewerSorter
171          *            The viewerSorter to set
172          */
173         public void setTreeExpansionLevel(int level) {
174                 fTreeExpandLevel = level;
175                 if (fTree != null) {
176                         fTree.expandToLevel(level);
177                 }
178         }
179
180         // ------ adapter communication
181
182         private void buttonPressed(int index) {
183                 if (!managedButtonPressed(index) && fTreeAdapter != null) {
184                         fTreeAdapter.customButtonPressed(this, index);
185                 }
186         }
187
188         /**
189          * Checks if the button pressed is handled internally
190          * 
191          * @return Returns true if button has been handled.
192          */
193         protected boolean managedButtonPressed(int index) {
194                 if (index == fRemoveButtonIndex) {
195                         remove();
196                 } else if (index == fUpButtonIndex) {
197                         up();
198                 } else if (index == fDownButtonIndex) {
199                         down();
200                 } else {
201                         return false;
202                 }
203                 return true;
204         }
205
206         // ------ layout helpers
207
208         /*
209          * @see DialogField#doFillIntoGrid
210          */
211         public Control[] doFillIntoGrid(Composite parent, int nColumns) {
212                 PixelConverter converter = new PixelConverter(parent);
213
214                 assertEnoughColumns(nColumns);
215
216                 Label label = getLabelControl(parent);
217                 GridData gd = gridDataForLabel(1);
218                 gd.verticalAlignment = GridData.BEGINNING;
219                 label.setLayoutData(gd);
220
221                 Control list = getTreeControl(parent);
222                 gd = new GridData();
223                 gd.horizontalAlignment = GridData.FILL;
224                 gd.grabExcessHorizontalSpace = false;
225                 gd.verticalAlignment = GridData.FILL;
226                 gd.grabExcessVerticalSpace = true;
227                 gd.horizontalSpan = nColumns - 2;
228                 gd.widthHint = converter.convertWidthInCharsToPixels(50);
229                 gd.heightHint = converter.convertHeightInCharsToPixels(6);
230
231                 list.setLayoutData(gd);
232
233                 Composite buttons = getButtonBox(parent);
234                 gd = new GridData();
235                 gd.horizontalAlignment = GridData.FILL;
236                 gd.grabExcessHorizontalSpace = false;
237                 gd.verticalAlignment = GridData.FILL;
238                 gd.grabExcessVerticalSpace = true;
239                 gd.horizontalSpan = 1;
240                 buttons.setLayoutData(gd);
241
242                 return new Control[] { label, list, buttons };
243         }
244
245         /*
246          * @see DialogField#getNumberOfControls
247          */
248         public int getNumberOfControls() {
249                 return 3;
250         }
251
252         /**
253          * Sets the minimal width of the buttons. Must be called after widget
254          * creation.
255          */
256         public void setButtonsMinWidth(int minWidth) {
257                 if (fLastSeparator != null) {
258                         ((GridData) fLastSeparator.getLayoutData()).widthHint = minWidth;
259                 }
260         }
261
262         // ------ ui creation
263
264         /**
265          * Returns the tree control. When called the first time, the control will be
266          * created.
267          * 
268          * @param The
269          *            parent composite when called the first time, or
270          *            <code>null</code> after.
271          */
272         public Control getTreeControl(Composite parent) {
273                 if (fTreeControl == null) {
274                         assertCompositeNotNull(parent);
275
276                         fTree = createTreeViewer(parent);
277
278                         fTreeControl = (Tree) fTree.getControl();
279                         fTreeControl.addKeyListener(new KeyAdapter() {
280                                 public void keyPressed(KeyEvent e) {
281                                         handleKeyPressed(e);
282                                 }
283                         });
284                         fTree.setAutoExpandLevel(99);
285                         fTree.setContentProvider(fTreeViewerAdapter);
286                         fTree.setLabelProvider(fLabelProvider);
287                         fTree.addSelectionChangedListener(fTreeViewerAdapter);
288                         fTree.addDoubleClickListener(fTreeViewerAdapter);
289
290                         fTree.setInput(fParentElement);
291                         fTree.expandToLevel(fTreeExpandLevel);
292
293                         if (fViewerSorter != null) {
294                                 fTree.setSorter(fViewerSorter);
295                         }
296
297                         fTreeControl.setEnabled(isEnabled());
298                         if (fSelectionWhenEnabled != null) {
299                                 postSetSelection(fSelectionWhenEnabled);
300                         }
301                 }
302                 return fTreeControl;
303         }
304
305         /**
306          * Returns the internally used table viewer.
307          */
308         public TreeViewer getTreeViewer() {
309                 return fTree;
310         }
311
312         /*
313          * Subclasses may override to specify a different style.
314          */
315         protected int getTreeStyle() {
316                 int style = SWT.BORDER | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL;
317                 return style;
318         }
319
320         protected TreeViewer createTreeViewer(Composite parent) {
321                 Tree tree = new Tree(parent, getTreeStyle());
322                 return new TreeViewer(tree);
323         }
324
325         protected Button createButton(Composite parent, String label,
326                         SelectionListener listener) {
327                 Button button = new Button(parent, SWT.PUSH);
328                 button.setText(label);
329                 button.addSelectionListener(listener);
330                 GridData gd = new GridData();
331                 gd.horizontalAlignment = GridData.FILL;
332                 gd.grabExcessHorizontalSpace = true;
333                 gd.verticalAlignment = GridData.BEGINNING;
334                 gd.heightHint = SWTUtil.getButtonHeightHint(button);
335                 gd.widthHint = SWTUtil.getButtonWidthHint(button);
336
337                 button.setLayoutData(gd);
338                 return button;
339         }
340
341         private Label createSeparator(Composite parent) {
342                 Label separator = new Label(parent, SWT.NONE);
343                 separator.setVisible(false);
344                 GridData gd = new GridData();
345                 gd.horizontalAlignment = GridData.FILL;
346                 gd.verticalAlignment = GridData.BEGINNING;
347                 gd.heightHint = 4;
348                 separator.setLayoutData(gd);
349                 return separator;
350         }
351
352         /**
353          * Returns the composite containing the buttons. When called the first time,
354          * the control will be created.
355          * 
356          * @param The
357          *            parent composite when called the first time, or
358          *            <code>null</code> after.
359          */
360         public Composite getButtonBox(Composite parent) {
361                 if (fButtonsControl == null) {
362                         assertCompositeNotNull(parent);
363
364                         SelectionListener listener = new SelectionListener() {
365                                 public void widgetDefaultSelected(SelectionEvent e) {
366                                         doButtonSelected(e);
367                                 }
368
369                                 public void widgetSelected(SelectionEvent e) {
370                                         doButtonSelected(e);
371                                 }
372                         };
373
374                         Composite contents = new Composite(parent, SWT.NULL);
375                         GridLayout layout = new GridLayout();
376                         layout.marginWidth = 0;
377                         layout.marginHeight = 0;
378                         contents.setLayout(layout);
379
380                         if (fButtonLabels != null) {
381                                 fButtonControls = new Button[fButtonLabels.length];
382                                 for (int i = 0; i < fButtonLabels.length; i++) {
383                                         String currLabel = fButtonLabels[i];
384                                         if (currLabel != null) {
385                                                 fButtonControls[i] = createButton(contents, currLabel,
386                                                                 listener);
387                                                 fButtonControls[i].setEnabled(isEnabled()
388                                                                 && fButtonsEnabled[i]);
389                                         } else {
390                                                 fButtonControls[i] = null;
391                                                 createSeparator(contents);
392                                         }
393                                 }
394                         }
395
396                         fLastSeparator = createSeparator(contents);
397
398                         updateButtonState();
399                         fButtonsControl = contents;
400                 }
401
402                 return fButtonsControl;
403         }
404
405         private void doButtonSelected(SelectionEvent e) {
406                 if (fButtonControls != null) {
407                         for (int i = 0; i < fButtonControls.length; i++) {
408                                 if (e.widget == fButtonControls[i]) {
409                                         buttonPressed(i);
410                                         return;
411                                 }
412                         }
413                 }
414         }
415
416         /**
417          * Handles key events in the table viewer. Specifically when the delete key
418          * is pressed.
419          */
420         protected void handleKeyPressed(KeyEvent event) {
421                 if (event.character == SWT.DEL && event.stateMask == 0) {
422                         if (fRemoveButtonIndex != -1
423                                         && isButtonEnabled(fTree.getSelection(), fRemoveButtonIndex)) {
424                                 managedButtonPressed(fRemoveButtonIndex);
425                                 return;
426                         }
427                 }
428                 fTreeAdapter.keyPressed(this, event);
429         }
430
431         // ------ enable / disable management
432
433         /*
434          * @see DialogField#dialogFieldChanged
435          */
436         public void dialogFieldChanged() {
437                 super.dialogFieldChanged();
438                 updateButtonState();
439         }
440
441         /*
442          * Updates the enable state of the all buttons
443          */
444         protected void updateButtonState() {
445                 if (fButtonControls != null) {
446                         ISelection sel = fTree.getSelection();
447                         for (int i = 0; i < fButtonControls.length; i++) {
448                                 Button button = fButtonControls[i];
449                                 if (isOkToUse(button)) {
450                                         button.setEnabled(isButtonEnabled(sel, i));
451                                 }
452                         }
453                 }
454         }
455
456         protected boolean containsAttributes(List selected) {
457                 for (int i = 0; i < selected.size(); i++) {
458                         if (!fElements.contains(selected.get(i))) {
459                                 return true;
460                         }
461                 }
462                 return false;
463         }
464
465         protected boolean getManagedButtonState(ISelection sel, int index) {
466                 List selected = getSelectedElements();
467                 boolean hasAttributes = containsAttributes(selected);
468                 if (index == fRemoveButtonIndex) {
469                         return !selected.isEmpty() && !hasAttributes;
470                 } else if (index == fUpButtonIndex) {
471                         return !sel.isEmpty() && !hasAttributes && canMoveUp(selected);
472                 } else if (index == fDownButtonIndex) {
473                         return !sel.isEmpty() && !hasAttributes && canMoveDown(selected);
474                 }
475                 return true;
476         }
477
478         /*
479          * @see DialogField#updateEnableState
480          */
481         protected void updateEnableState() {
482                 super.updateEnableState();
483
484                 boolean enabled = isEnabled();
485                 if (isOkToUse(fTreeControl)) {
486                         if (!enabled) {
487                                 fSelectionWhenEnabled = fTree.getSelection();
488                                 selectElements(null);
489                         } else {
490                                 selectElements(fSelectionWhenEnabled);
491                                 fSelectionWhenEnabled = null;
492                         }
493                         fTreeControl.setEnabled(enabled);
494                 }
495                 updateButtonState();
496         }
497
498         /**
499          * Sets a button enabled or disabled.
500          */
501         public void enableButton(int index, boolean enable) {
502                 if (fButtonsEnabled != null && index < fButtonsEnabled.length) {
503                         fButtonsEnabled[index] = enable;
504                         updateButtonState();
505                 }
506         }
507
508         private boolean isButtonEnabled(ISelection sel, int index) {
509                 boolean extraState = getManagedButtonState(sel, index);
510                 return isEnabled() && extraState && fButtonsEnabled[index];
511         }
512
513         // ------ model access
514
515         /**
516          * Sets the elements shown in the list.
517          */
518         public void setElements(List elements) {
519                 fElements = new ArrayList(elements);
520                 refresh();
521                 if (fTree != null) {
522                         fTree.expandToLevel(fTreeExpandLevel);
523                 }
524                 dialogFieldChanged();
525         }
526
527         /**
528          * Gets the elements shown in the list. The list returned is a copy, so it
529          * can be modified by the user.
530          */
531         public List getElements() {
532                 return new ArrayList(fElements);
533         }
534
535         /**
536          * Gets the element shown at the given index.
537          */
538         public Object getElement(int index) {
539                 return fElements.get(index);
540         }
541
542         /**
543          * Gets the index of an element in the list or -1 if element is not in list.
544          */
545         public int getIndexOfElement(Object elem) {
546                 return fElements.indexOf(elem);
547         }
548
549         /**
550          * Replace an element.
551          */
552         public void replaceElement(Object oldElement, Object newElement)
553                         throws IllegalArgumentException {
554                 int idx = fElements.indexOf(oldElement);
555                 if (idx != -1) {
556                         fElements.set(idx, newElement);
557                         if (fTree != null) {
558                                 List selected = getSelectedElements();
559                                 if (selected.remove(oldElement)) {
560                                         selected.add(newElement);
561                                 }
562                                 boolean isExpanded = fTree.getExpandedState(oldElement);
563                                 fTree.remove(oldElement);
564                                 fTree.add(fParentElement, newElement);
565                                 if (isExpanded) {
566                                         fTree.expandToLevel(newElement, fTreeExpandLevel);
567                                 }
568                                 selectElements(new StructuredSelection(selected));
569                         }
570                         dialogFieldChanged();
571                 } else {
572                         throw new IllegalArgumentException();
573                 }
574         }
575
576         /**
577          * Adds an element at the end of the tree list.
578          */
579         public void addElement(Object element) {
580                 if (fElements.contains(element)) {
581                         return;
582                 }
583                 fElements.add(element);
584                 if (fTree != null) {
585                         fTree.add(fParentElement, element);
586                         fTree.expandToLevel(element, fTreeExpandLevel);
587                 }
588                 dialogFieldChanged();
589         }
590
591         /**
592          * Adds elements at the end of the tree list.
593          */
594         public void addElements(List elements) {
595                 int nElements = elements.size();
596
597                 if (nElements > 0) {
598                         // filter duplicated
599                         ArrayList elementsToAdd = new ArrayList(nElements);
600
601                         for (int i = 0; i < nElements; i++) {
602                                 Object elem = elements.get(i);
603                                 if (!fElements.contains(elem)) {
604                                         elementsToAdd.add(elem);
605                                 }
606                         }
607                         fElements.addAll(elementsToAdd);
608                         if (fTree != null) {
609                                 fTree.add(fParentElement, elementsToAdd.toArray());
610                                 for (int i = 0; i < elementsToAdd.size(); i++) {
611                                         fTree.expandToLevel(elementsToAdd.get(i), fTreeExpandLevel);
612                                 }
613                         }
614                         dialogFieldChanged();
615                 }
616         }
617
618         /**
619          * Adds an element at a position.
620          */
621         public void insertElementAt(Object element, int index) {
622                 if (fElements.contains(element)) {
623                         return;
624                 }
625                 fElements.add(index, element);
626                 if (fTree != null) {
627                         fTree.add(fParentElement, element);
628                         if (fTreeExpandLevel != -1) {
629                                 fTree.expandToLevel(element, fTreeExpandLevel);
630                         }
631                 }
632
633                 dialogFieldChanged();
634         }
635
636         /**
637          * Adds an element at a position.
638          */
639         public void removeAllElements() {
640                 if (fElements.size() > 0) {
641                         fElements.clear();
642                         refresh();
643                         dialogFieldChanged();
644                 }
645         }
646
647         /**
648          * Removes an element from the list.
649          */
650         public void removeElement(Object element) throws IllegalArgumentException {
651                 if (fElements.remove(element)) {
652                         if (fTree != null) {
653                                 fTree.remove(element);
654                         }
655                         dialogFieldChanged();
656                 } else {
657                         throw new IllegalArgumentException();
658                 }
659         }
660
661         /**
662          * Removes elements from the list.
663          */
664         public void removeElements(List elements) {
665                 if (elements.size() > 0) {
666                         fElements.removeAll(elements);
667                         if (fTree != null) {
668                                 fTree.remove(elements.toArray());
669                         }
670                         dialogFieldChanged();
671                 }
672         }
673
674         /**
675          * Gets the number of elements
676          */
677         public int getSize() {
678                 return fElements.size();
679         }
680
681         public void selectElements(ISelection selection) {
682                 fSelectionWhenEnabled = selection;
683                 if (fTree != null) {
684                         fTree.setSelection(selection, true);
685                 }
686         }
687
688         public void selectFirstElement() {
689                 Object element = null;
690                 if (fViewerSorter != null) {
691                         Object[] arr = fElements.toArray();
692                         fViewerSorter.sort(fTree, arr);
693                         if (arr.length > 0) {
694                                 element = arr[0];
695                         }
696                 } else {
697                         if (fElements.size() > 0) {
698                                 element = fElements.get(0);
699                         }
700                 }
701                 if (element != null) {
702                         selectElements(new StructuredSelection(element));
703                 }
704         }
705
706         public void postSetSelection(final ISelection selection) {
707                 if (isOkToUse(fTreeControl)) {
708                         Display d = fTreeControl.getDisplay();
709                         d.asyncExec(new Runnable() {
710                                 public void run() {
711                                         if (isOkToUse(fTreeControl)) {
712                                                 selectElements(selection);
713                                         }
714                                 }
715                         });
716                 }
717         }
718
719         /**
720          * Refreshes the tree.
721          */
722         public void refresh() {
723                 if (fTree != null) {
724                         fTree.refresh();
725                 }
726         }
727
728         /**
729          * Refreshes the tree.
730          */
731         public void refresh(Object element) {
732                 if (fTree != null) {
733                         fTree.refresh(element);
734                 }
735         }
736
737         // ------- list maintenance
738
739         private List moveUp(List elements, List move) {
740                 int nElements = elements.size();
741                 List res = new ArrayList(nElements);
742                 Object floating = null;
743                 for (int i = 0; i < nElements; i++) {
744                         Object curr = elements.get(i);
745                         if (move.contains(curr)) {
746                                 res.add(curr);
747                         } else {
748                                 if (floating != null) {
749                                         res.add(floating);
750                                 }
751                                 floating = curr;
752                         }
753                 }
754                 if (floating != null) {
755                         res.add(floating);
756                 }
757                 return res;
758         }
759
760         private void moveUp(List toMoveUp) {
761                 if (toMoveUp.size() > 0) {
762                         setElements(moveUp(fElements, toMoveUp));
763                         fTree.reveal(toMoveUp.get(0));
764                 }
765         }
766
767         private void moveDown(List toMoveDown) {
768                 if (toMoveDown.size() > 0) {
769                         setElements(reverse(moveUp(reverse(fElements), toMoveDown)));
770                         fTree.reveal(toMoveDown.get(toMoveDown.size() - 1));
771                 }
772         }
773
774         private List reverse(List p) {
775                 List reverse = new ArrayList(p.size());
776                 for (int i = p.size() - 1; i >= 0; i--) {
777                         reverse.add(p.get(i));
778                 }
779                 return reverse;
780         }
781
782         private void remove() {
783                 removeElements(getSelectedElements());
784         }
785
786         private void up() {
787                 moveUp(getSelectedElements());
788         }
789
790         private void down() {
791                 moveDown(getSelectedElements());
792         }
793
794         private boolean canMoveUp(List selectedElements) {
795                 if (isOkToUse(fTreeControl)) {
796                         int nSelected = selectedElements.size();
797                         int nElements = fElements.size();
798                         for (int i = 0; i < nElements && nSelected > 0; i++) {
799                                 if (!selectedElements.contains(fElements.get(i))) {
800                                         return true;
801                                 }
802                                 nSelected--;
803                         }
804                 }
805                 return false;
806         }
807
808         private boolean canMoveDown(List selectedElements) {
809                 if (isOkToUse(fTreeControl)) {
810                         int nSelected = selectedElements.size();
811                         for (int i = fElements.size() - 1; i >= 0 && nSelected > 0; i--) {
812                                 if (!selectedElements.contains(fElements.get(i))) {
813                                         return true;
814                                 }
815                                 nSelected--;
816                         }
817                 }
818                 return false;
819         }
820
821         /**
822          * Returns the selected elements.
823          */
824         public List getSelectedElements() {
825                 ArrayList result = new ArrayList();
826                 if (fTree != null) {
827                         ISelection selection = fTree.getSelection();
828                         if (selection instanceof IStructuredSelection) {
829                                 Iterator iter = ((IStructuredSelection) selection).iterator();
830                                 while (iter.hasNext()) {
831                                         result.add(iter.next());
832                                 }
833                         }
834                 }
835                 return result;
836         }
837
838         public void expandElement(Object element, int level) {
839                 if (fTree != null) {
840                         fTree.expandToLevel(element, level);
841                 }
842         }
843
844         // ------- TreeViewerAdapter
845
846         private class TreeViewerAdapter implements ITreeContentProvider,
847                         ISelectionChangedListener, IDoubleClickListener {
848
849                 private final Object[] NO_ELEMENTS = new Object[0];
850
851                 // ------- ITreeContentProvider Interface ------------
852
853                 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
854                         // will never happen
855                 }
856
857                 public boolean isDeleted(Object element) {
858                         return false;
859                 }
860
861                 public void dispose() {
862                 }
863
864                 public Object[] getElements(Object obj) {
865                         return fElements.toArray();
866                 }
867
868                 public Object[] getChildren(Object element) {
869                         if (fTreeAdapter != null) {
870                                 return fTreeAdapter.getChildren(TreeListDialogField.this,
871                                                 element);
872                         }
873                         return NO_ELEMENTS;
874                 }
875
876                 public Object getParent(Object element) {
877                         if (!fElements.contains(element) && fTreeAdapter != null) {
878                                 return fTreeAdapter
879                                                 .getParent(TreeListDialogField.this, element);
880                         }
881                         return fParentElement;
882                 }
883
884                 public boolean hasChildren(Object element) {
885                         if (fTreeAdapter != null) {
886                                 return fTreeAdapter.hasChildren(TreeListDialogField.this,
887                                                 element);
888                         }
889                         return false;
890                 }
891
892                 // ------- ISelectionChangedListener Interface ------------
893
894                 public void selectionChanged(SelectionChangedEvent event) {
895                         doListSelected(event);
896                 }
897
898                 /*
899                  * (non-Javadoc)
900                  * 
901                  * @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(org.eclipse.jface.viewers.DoubleClickEvent)
902                  */
903                 public void doubleClick(DoubleClickEvent event) {
904                         doDoubleClick(event);
905                 }
906
907         }
908
909         protected void doListSelected(SelectionChangedEvent event) {
910                 updateButtonState();
911                 if (fTreeAdapter != null) {
912                         fTreeAdapter.selectionChanged(this);
913                 }
914         }
915
916         protected void doDoubleClick(DoubleClickEvent event) {
917                 if (fTreeAdapter != null) {
918                         fTreeAdapter.doubleClicked(this);
919                 }
920         }
921
922 }