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