X-Git-Url: http://secure.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/wizards/dialogfields/ListDialogField.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/wizards/dialogfields/ListDialogField.java new file mode 100644 index 0000000..3c85696 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/wizards/dialogfields/ListDialogField.java @@ -0,0 +1,920 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package net.sourceforge.phpdt.internal.ui.wizards.dialogfields; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import net.sourceforge.phpdt.internal.ui.util.PixelConverter; +import net.sourceforge.phpdt.internal.ui.util.SWTUtil; +import net.sourceforge.phpdt.internal.ui.util.TableLayoutComposite; + +//incastrix +//import org.eclipse.jface.text.Assert; +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.viewers.ColumnLayoutData; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TableLayout; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerSorter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; + +/** + * A list with a button bar. Typical buttons are 'Add', 'Remove', 'Up' and + * 'Down'. List model is independend of widget creation. DialogFields controls + * are: Label, List and Composite containing buttons. + */ +public class ListDialogField extends DialogField { + + public static class ColumnsDescription { + private ColumnLayoutData[] columns; + + private String[] headers; + + private boolean drawLines; + + public ColumnsDescription(ColumnLayoutData[] columns, String[] headers, + boolean drawLines) { + this.columns = columns; + this.headers = headers; + this.drawLines = drawLines; + } + + public ColumnsDescription(String[] headers, boolean drawLines) { + this(createColumnWeightData(headers.length), headers, drawLines); + } + + public ColumnsDescription(int nColumns, boolean drawLines) { + this(createColumnWeightData(nColumns), null, drawLines); + } + + private static ColumnLayoutData[] createColumnWeightData(int nColumns) { + ColumnLayoutData[] data = new ColumnLayoutData[nColumns]; + for (int i = 0; i < nColumns; i++) { + data[i] = new ColumnWeightData(1); + } + return data; + } + } + + protected TableViewer fTable; + + protected ILabelProvider fLabelProvider; + + protected ListViewerAdapter fListViewerAdapter; + + protected List fElements; + + protected ViewerSorter fViewerSorter; + + protected String[] fButtonLabels; + + private Button[] fButtonControls; + + private boolean[] fButtonsEnabled; + + private int fRemoveButtonIndex; + + private int fUpButtonIndex; + + private int fDownButtonIndex; + + //private Label fLastSeparator; + + private Control fTableControl; + + private Composite fButtonsControl; + + private ISelection fSelectionWhenEnabled; + + private IListAdapter fListAdapter; + + private Object fParentElement; + + private ColumnsDescription fTableColumns; + + /** + * Creates the ListDialogField. + * + * @param adapter + * A listener for button invocation, selection changes. Can be + * null. + * @param buttonLabels + * The labels of all buttons: null is a valid + * array entry and marks a separator. + * @param lprovider + * The label provider to render the table entries + */ + public ListDialogField(IListAdapter adapter, String[] buttonLabels, + ILabelProvider lprovider) { + super(); + fListAdapter = adapter; + + fLabelProvider = lprovider; + fListViewerAdapter = new ListViewerAdapter(); + fParentElement = this; + + fElements = new ArrayList(10); + + fButtonLabels = buttonLabels; + if (fButtonLabels != null) { + int nButtons = fButtonLabels.length; + fButtonsEnabled = new boolean[nButtons]; + for (int i = 0; i < nButtons; i++) { + fButtonsEnabled[i] = true; + } + } + + fTable = null; + fTableControl = null; + fButtonsControl = null; + fTableColumns = null; + + fRemoveButtonIndex = -1; + fUpButtonIndex = -1; + fDownButtonIndex = -1; + } + + /** + * Sets the index of the 'remove' button in the button label array passed in + * the constructor. The behaviour of the button marked as the 'remove' + * button will then be handled internally. (enable state, button invocation + * behaviour) + */ + public void setRemoveButtonIndex(int removeButtonIndex) { + Assert.isTrue(removeButtonIndex < fButtonLabels.length); + fRemoveButtonIndex = removeButtonIndex; + } + + /** + * Sets the index of the 'up' button in the button label array passed in the + * constructor. The behaviour of the button marked as the 'up' button will + * then be handled internally. (enable state, button invocation behaviour) + */ + public void setUpButtonIndex(int upButtonIndex) { + Assert.isTrue(upButtonIndex < fButtonLabels.length); + fUpButtonIndex = upButtonIndex; + } + + /** + * Sets the index of the 'down' button in the button label array passed in + * the constructor. The behaviour of the button marked as the 'down' button + * will then be handled internally. (enable state, button invocation + * behaviour) + */ + public void setDownButtonIndex(int downButtonIndex) { + Assert.isTrue(downButtonIndex < fButtonLabels.length); + fDownButtonIndex = downButtonIndex; + } + + /** + * Sets the viewerSorter. + * + * @param viewerSorter + * The viewerSorter to set + */ +// public void setViewerSorter(ViewerSorter viewerSorter) { +// fViewerSorter = viewerSorter; +// } + + public void setTableColumns(ColumnsDescription column) { + fTableColumns = column; + } + + // ------ adapter communication + + private void buttonPressed(int index) { + if (!managedButtonPressed(index) && fListAdapter != null) { + fListAdapter.customButtonPressed(this, index); + } + } + + /** + * Checks if the button pressed is handled internally + * + * @return Returns true if button has been handled. + */ + protected boolean managedButtonPressed(int index) { + if (index == fRemoveButtonIndex) { + remove(); + } else if (index == fUpButtonIndex) { + up(); + } else if (index == fDownButtonIndex) { + down(); + } else { + return false; + } + return true; + } + + // ------ layout helpers + + /* + * @see DialogField#doFillIntoGrid + */ + public Control[] doFillIntoGrid(Composite parent, int nColumns) { + PixelConverter converter = new PixelConverter(parent); + + assertEnoughColumns(nColumns); + + Label label = getLabelControl(parent); + GridData gd = gridDataForLabel(1); + gd.verticalAlignment = GridData.BEGINNING; + label.setLayoutData(gd); + + Control list = getListControl(parent); + gd = new GridData(); + gd.horizontalAlignment = GridData.FILL; + gd.grabExcessHorizontalSpace = false; + gd.verticalAlignment = GridData.FILL; + gd.grabExcessVerticalSpace = true; + gd.horizontalSpan = nColumns - 2; + gd.widthHint = converter.convertWidthInCharsToPixels(50); + gd.heightHint = converter.convertHeightInCharsToPixels(6); + + list.setLayoutData(gd); + + Composite buttons = getButtonBox(parent); + gd = new GridData(); + gd.horizontalAlignment = GridData.FILL; + gd.grabExcessHorizontalSpace = false; + gd.verticalAlignment = GridData.FILL; + gd.grabExcessVerticalSpace = true; + gd.horizontalSpan = 1; + buttons.setLayoutData(gd); + + return new Control[] { label, list, buttons }; + } + + /* + * @see DialogField#getNumberOfControls + */ + public int getNumberOfControls() { + return 3; + } + + /** + * Sets the minimal width of the buttons. Must be called after widget + * creation. + */ +// public void setButtonsMinWidth(int minWidth) { +// if (fLastSeparator != null) { +// ((GridData) fLastSeparator.getLayoutData()).widthHint = minWidth; +// } +// } + + // ------ ui creation + + /** + * Returns the list control. When called the first time, the control will be + * created. + * + * @param The + * parent composite when called the first time, or + * null after. + */ + public Control getListControl(Composite parent) { + if (fTableControl == null) { + assertCompositeNotNull(parent); + + if (fTableColumns == null) { + fTable = createTableViewer(parent); + Table tableControl = fTable.getTable(); + + fTableControl = tableControl; + tableControl.setLayout(new TableLayout()); + } else { + TableLayoutComposite composite = new TableLayoutComposite( + parent, SWT.NONE); + fTableControl = composite; + + fTable = createTableViewer(composite); + Table tableControl = fTable.getTable(); + + tableControl.setHeaderVisible(fTableColumns.headers != null); + tableControl.setLinesVisible(fTableColumns.drawLines); + ColumnLayoutData[] columns = fTableColumns.columns; + for (int i = 0; i < columns.length; i++) { + composite.addColumnData(columns[i]); + TableColumn column = new TableColumn(tableControl, SWT.NONE); + // tableLayout.addColumnData(columns[i]); + if (fTableColumns.headers != null) { + column.setText(fTableColumns.headers[i]); + } + } + } + + fTable.getTable().addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent e) { + handleKeyPressed(e); + } + }); + + // fTableControl.setLayout(tableLayout); + + fTable.setContentProvider(fListViewerAdapter); + fTable.setLabelProvider(fLabelProvider); + fTable.addSelectionChangedListener(fListViewerAdapter); + fTable.addDoubleClickListener(fListViewerAdapter); + + fTable.setInput(fParentElement); + + if (fViewerSorter != null) { + fTable.setSorter(fViewerSorter); + } + + fTableControl.setEnabled(isEnabled()); + if (fSelectionWhenEnabled != null) { + postSetSelection(fSelectionWhenEnabled); + } + } + return fTableControl; + } + + /** + * Returns the internally used table viewer. + */ + public TableViewer getTableViewer() { + return fTable; + } + + /* + * Subclasses may override to specify a different style. + */ + protected int getListStyle() { + int style = SWT.BORDER | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL; + if (fTableColumns != null) { + style |= SWT.FULL_SELECTION; + } + return style; + } + + protected TableViewer createTableViewer(Composite parent) { + Table table = new Table(parent, getListStyle()); + return new TableViewer(table); + } + + protected Button createButton(Composite parent, String label, + SelectionListener listener) { + Button button = new Button(parent, SWT.PUSH); + button.setText(label); + button.addSelectionListener(listener); + GridData gd = new GridData(); + gd.horizontalAlignment = GridData.FILL; + gd.grabExcessHorizontalSpace = true; + gd.verticalAlignment = GridData.BEGINNING; + gd.heightHint = SWTUtil.getButtonHeightHint(button); + gd.widthHint = SWTUtil.getButtonWidthHint(button); + + button.setLayoutData(gd); + return button; + } + + private Label createSeparator(Composite parent) { + Label separator = new Label(parent, SWT.NONE); + separator.setVisible(false); + GridData gd = new GridData(); + gd.horizontalAlignment = GridData.FILL; + gd.verticalAlignment = GridData.BEGINNING; + gd.heightHint = 4; + separator.setLayoutData(gd); + return separator; + } + + /** + * Returns the composite containing the buttons. When called the first time, + * the control will be created. + * + * @param The + * parent composite when called the first time, or + * null after. + */ + public Composite getButtonBox(Composite parent) { + if (fButtonsControl == null) { + assertCompositeNotNull(parent); + + SelectionListener listener = new SelectionListener() { + public void widgetDefaultSelected(SelectionEvent e) { + doButtonSelected(e); + } + + public void widgetSelected(SelectionEvent e) { + doButtonSelected(e); + } + }; + + Composite contents = new Composite(parent, SWT.NULL); + GridLayout layout = new GridLayout(); + layout.marginWidth = 0; + layout.marginHeight = 0; + contents.setLayout(layout); + + if (fButtonLabels != null) { + fButtonControls = new Button[fButtonLabels.length]; + for (int i = 0; i < fButtonLabels.length; i++) { + String currLabel = fButtonLabels[i]; + if (currLabel != null) { + fButtonControls[i] = createButton(contents, currLabel, + listener); + fButtonControls[i].setEnabled(isEnabled() + && fButtonsEnabled[i]); + } else { + fButtonControls[i] = null; + createSeparator(contents); + } + } + } + + //fLastSeparator = createSeparator(contents); + + updateButtonState(); + fButtonsControl = contents; + } + + return fButtonsControl; + } + + private void doButtonSelected(SelectionEvent e) { + if (fButtonControls != null) { + for (int i = 0; i < fButtonControls.length; i++) { + if (e.widget == fButtonControls[i]) { + buttonPressed(i); + return; + } + } + } + } + + /** + * Handles key events in the table viewer. Specifically when the delete key + * is pressed. + */ + protected void handleKeyPressed(KeyEvent event) { + if (event.character == SWT.DEL && event.stateMask == 0) { + if (fRemoveButtonIndex != -1 + && isButtonEnabled(fTable.getSelection(), + fRemoveButtonIndex)) { + managedButtonPressed(fRemoveButtonIndex); + } + } + } + + // ------ enable / disable management + + /* + * @see DialogField#dialogFieldChanged + */ + public void dialogFieldChanged() { + super.dialogFieldChanged(); + updateButtonState(); + } + + /* + * Updates the enable state of the all buttons + */ + protected void updateButtonState() { + if (fButtonControls != null) { + ISelection sel = fTable.getSelection(); + for (int i = 0; i < fButtonControls.length; i++) { + Button button = fButtonControls[i]; + if (isOkToUse(button)) { + button.setEnabled(isButtonEnabled(sel, i)); + } + } + } + } + + protected boolean getManagedButtonState(ISelection sel, int index) { + if (index == fRemoveButtonIndex) { + return !sel.isEmpty(); + } else if (index == fUpButtonIndex) { + return !sel.isEmpty() && canMoveUp(); + } else if (index == fDownButtonIndex) { + return !sel.isEmpty() && canMoveDown(); + } + return true; + } + + /* + * @see DialogField#updateEnableState + */ + protected void updateEnableState() { + super.updateEnableState(); + + boolean enabled = isEnabled(); + if (isOkToUse(fTableControl)) { + if (!enabled) { + fSelectionWhenEnabled = fTable.getSelection(); + selectElements(null); + } else { + selectElements(fSelectionWhenEnabled); + fSelectionWhenEnabled = null; + } + fTableControl.setEnabled(enabled); + } + updateButtonState(); + } + + /** + * Sets a button enabled or disabled. + */ + public void enableButton(int index, boolean enable) { + if (fButtonsEnabled != null && index < fButtonsEnabled.length) { + fButtonsEnabled[index] = enable; + updateButtonState(); + } + } + + private boolean isButtonEnabled(ISelection sel, int index) { + boolean extraState = getManagedButtonState(sel, index); + return isEnabled() && extraState && fButtonsEnabled[index]; + } + + // ------ model access + + /** + * Sets the elements shown in the list. + */ + public void setElements(List elements) { + fElements = new ArrayList(elements); + if (fTable != null) { + fTable.refresh(); + } + dialogFieldChanged(); + } + + /** + * Gets the elements shown in the list. The list returned is a copy, so it + * can be modified by the user. + */ + public List getElements() { + return new ArrayList(fElements); + } + + /** + * Gets the elements shown at the given index. + */ + public Object getElement(int index) { + return fElements.get(index); + } + + /** + * Gets the index of an element in the list or -1 if element is not in list. + */ +// public int getIndexOfElement(Object elem) { +// return fElements.indexOf(elem); +// } + + /** + * Replace an element. + */ + public void replaceElement(Object oldElement, Object newElement) + throws IllegalArgumentException { + int idx = fElements.indexOf(oldElement); + if (idx != -1) { + fElements.set(idx, newElement); + if (fTable != null) { + List selected = getSelectedElements(); + if (selected.remove(oldElement)) { + selected.add(newElement); + } + fTable.refresh(); + selectElements(new StructuredSelection(selected)); + } + dialogFieldChanged(); + } else { + throw new IllegalArgumentException(); + } + } + + /** + * Adds an element at the end of the list. + */ + public void addElement(Object element) { + if (fElements.contains(element)) { + return; + } + fElements.add(element); + if (fTable != null) { + fTable.add(element); + } + dialogFieldChanged(); + } + + /** + * Adds elements at the end of the list. + */ +// public void addElements(List elements) { +// int nElements = elements.size(); +// +// if (nElements > 0) { +// // filter duplicated +// ArrayList elementsToAdd = new ArrayList(nElements); +// +// for (int i = 0; i < nElements; i++) { +// Object elem = elements.get(i); +// if (!fElements.contains(elem)) { +// elementsToAdd.add(elem); +// } +// } +// fElements.addAll(elementsToAdd); +// if (fTable != null) { +// fTable.add(elementsToAdd.toArray()); +// } +// dialogFieldChanged(); +// } +// } + + /** + * Adds an element at a position. + */ + public void insertElementAt(Object element, int index) { + if (fElements.contains(element)) { + return; + } + fElements.add(index, element); + if (fTable != null) { + fTable.add(element); + } + + dialogFieldChanged(); + } + + /** + * Adds an element at a position. + */ +// public void removeAllElements() { +// if (fElements.size() > 0) { +// fElements.clear(); +// if (fTable != null) { +// fTable.refresh(); +// } +// dialogFieldChanged(); +// } +// } + + /** + * Removes an element from the list. + */ +// public void removeElement(Object element) throws IllegalArgumentException { +// if (fElements.remove(element)) { +// if (fTable != null) { +// fTable.remove(element); +// } +// dialogFieldChanged(); +// } else { +// throw new IllegalArgumentException(); +// } +// } + + /** + * Removes elements from the list. + */ + public void removeElements(List elements) { + if (elements.size() > 0) { + fElements.removeAll(elements); + if (fTable != null) { + fTable.remove(elements.toArray()); + } + dialogFieldChanged(); + } + } + + /** + * Gets the number of elements + */ + public int getSize() { + return fElements.size(); + } + + public void selectElements(ISelection selection) { + fSelectionWhenEnabled = selection; + if (fTable != null) { + fTable.setSelection(selection, true); + } + } + + public void selectFirstElement() { + Object element = null; + if (fViewerSorter != null) { + Object[] arr = fElements.toArray(); + fViewerSorter.sort(fTable, arr); + if (arr.length > 0) { + element = arr[0]; + } + } else { + if (fElements.size() > 0) { + element = fElements.get(0); + } + } + if (element != null) { + selectElements(new StructuredSelection(element)); + } + } + + public void postSetSelection(final ISelection selection) { + if (isOkToUse(fTableControl)) { + Display d = fTableControl.getDisplay(); + d.asyncExec(new Runnable() { + public void run() { + if (isOkToUse(fTableControl)) { + selectElements(selection); + } + } + }); + } + } + + /** + * Refreshes the table. + */ + public void refresh() { + if (fTable != null) { + fTable.refresh(); + } + } + + // ------- list maintenance + + private List moveUp(List elements, List move) { + int nElements = elements.size(); + List res = new ArrayList(nElements); + Object floating = null; + for (int i = 0; i < nElements; i++) { + Object curr = elements.get(i); + if (move.contains(curr)) { + res.add(curr); + } else { + if (floating != null) { + res.add(floating); + } + floating = curr; + } + } + if (floating != null) { + res.add(floating); + } + return res; + } + + private void moveUp(List toMoveUp) { + if (toMoveUp.size() > 0) { + setElements(moveUp(fElements, toMoveUp)); + fTable.reveal(toMoveUp.get(0)); + } + } + + private void moveDown(List toMoveDown) { + if (toMoveDown.size() > 0) { + setElements(reverse(moveUp(reverse(fElements), toMoveDown))); + fTable.reveal(toMoveDown.get(toMoveDown.size() - 1)); + } + } + + private List reverse(List p) { + List reverse = new ArrayList(p.size()); + for (int i = p.size() - 1; i >= 0; i--) { + reverse.add(p.get(i)); + } + return reverse; + } + + private void remove() { + removeElements(getSelectedElements()); + } + + private void up() { + moveUp(getSelectedElements()); + } + + private void down() { + moveDown(getSelectedElements()); + } + + private boolean canMoveUp() { + if (isOkToUse(fTableControl)) { + int[] indc = fTable.getTable().getSelectionIndices(); + for (int i = 0; i < indc.length; i++) { + if (indc[i] != i) { + return true; + } + } + } + return false; + } + + private boolean canMoveDown() { + if (isOkToUse(fTableControl)) { + int[] indc = fTable.getTable().getSelectionIndices(); + int k = fElements.size() - 1; + for (int i = indc.length - 1; i >= 0; i--, k--) { + if (indc[i] != k) { + return true; + } + } + } + return false; + } + + /** + * Returns the selected elements. + */ + public List getSelectedElements() { + List result = new ArrayList(); + if (fTable != null) { + ISelection selection = fTable.getSelection(); + if (selection instanceof IStructuredSelection) { + Iterator iter = ((IStructuredSelection) selection).iterator(); + while (iter.hasNext()) { + result.add(iter.next()); + } + } + } + return result; + } + + // ------- ListViewerAdapter + + private class ListViewerAdapter implements IStructuredContentProvider, + ISelectionChangedListener, IDoubleClickListener { + + // ------- ITableContentProvider Interface ------------ + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + // will never happen + } + + public boolean isDeleted(Object element) { + return false; + } + + public void dispose() { + } + + public Object[] getElements(Object obj) { + return fElements.toArray(); + } + + // ------- ISelectionChangedListener Interface ------------ + + public void selectionChanged(SelectionChangedEvent event) { + doListSelected(event); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(org.eclipse.jface.viewers.DoubleClickEvent) + */ + public void doubleClick(DoubleClickEvent event) { + doDoubleClick(event); + } + + } + + protected void doListSelected(SelectionChangedEvent event) { + updateButtonState(); + if (fListAdapter != null) { + fListAdapter.selectionChanged(this); + } + } + + protected void doDoubleClick(DoubleClickEvent event) { + if (fListAdapter != null) { + fListAdapter.doubleClicked(this); + } + } + +}