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