diff options
Diffstat (limited to 'jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/widgets/AddRemoveListPane.java')
-rw-r--r-- | jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/widgets/AddRemoveListPane.java | 554 |
1 files changed, 554 insertions, 0 deletions
diff --git a/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/widgets/AddRemoveListPane.java b/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/widgets/AddRemoveListPane.java new file mode 100644 index 0000000000..89069c5d58 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/widgets/AddRemoveListPane.java @@ -0,0 +1,554 @@ +/******************************************************************************* + * Copyright (c) 2008, 2009 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.ui.internal.widgets; + +import org.eclipse.jface.viewers.IBaseLabelProvider; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jpt.ui.internal.listeners.SWTPropertyChangeListenerWrapper; +import org.eclipse.jpt.ui.internal.swt.ColumnAdapter; +import org.eclipse.jpt.ui.internal.swt.TableModelAdapter; +import org.eclipse.jpt.ui.internal.swt.TableModelAdapter.SelectionChangeEvent; +import org.eclipse.jpt.ui.internal.swt.TableModelAdapter.SelectionChangeListener; +import org.eclipse.jpt.ui.internal.util.SWTUtil; +import org.eclipse.jpt.utility.internal.model.value.SimplePropertyValueModel; +import org.eclipse.jpt.utility.internal.model.value.swing.ObjectListSelectionModel; +import org.eclipse.jpt.utility.model.Model; +import org.eclipse.jpt.utility.model.event.ListAddEvent; +import org.eclipse.jpt.utility.model.event.ListChangeEvent; +import org.eclipse.jpt.utility.model.event.ListClearEvent; +import org.eclipse.jpt.utility.model.event.ListMoveEvent; +import org.eclipse.jpt.utility.model.event.ListRemoveEvent; +import org.eclipse.jpt.utility.model.event.ListReplaceEvent; +import org.eclipse.jpt.utility.model.event.PropertyChangeEvent; +import org.eclipse.jpt.utility.model.listener.PropertyChangeListener; +import org.eclipse.jpt.utility.model.value.ListValueModel; +import org.eclipse.jpt.utility.model.value.PropertyValueModel; +import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Layout; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; + +/** + * This implementation of the <code>AddRemovePane</code> uses a <code>Table</code> + * as its main widget, a <code>List</code> can't be used because it doesn't + * support showing images. However, the table is displayed like a list. + * <p> + * Here the layot of this pane: + * <pre> + * ----------------------------------------------------------------------------- + * | ------------------------------------------------------------- ----------- | + * | | Item 1 | | Add... | | + * | | ... | ----------- | + * | | Item n | ----------- | + * | | | | Edit... | | + * | | | ----------- | + * | | | ----------- | + * | | | | Remove | | + * | | | ----------- | + * | ------------------------------------------------------------- | + * -----------------------------------------------------------------------------</pre> + * + * @version 2.0 + * @since 1.0 + */ +@SuppressWarnings("nls") +public class AddRemoveListPane<T extends Model> extends AddRemovePane<T> +{ + + /** + * The main widget of this add/remove pane. + */ + private Table table; + + /** + * Creates a new <code>AddRemoveListPane</code>. + * + * @param parentPane The parent container of this one + * @param parent The parent container + * @param adapter + * @param listHolder The <code>ListValueModel</code> containing the items + * @param selectedItemHolder The holder of the selected item, if more than + * one item or no items are selected, then <code>null</code> will be passed + * @param labelProvider The renderer used to format the table holder's items + */ + public AddRemoveListPane(Pane<? extends T> parentPane, + Composite parent, + Adapter adapter, + ListValueModel<?> listHolder, + WritablePropertyValueModel<?> selectedItemHolder, + ILabelProvider labelProvider) { + + super(parentPane, + parent, + adapter, + listHolder, + selectedItemHolder, + labelProvider); + } + + /** + * Creates a new <code>AddRemoveListPane</code>. + * + * @param parentPane The parent container of this one + * @param parent The parent container + * @param adapter + * @param listHolder The <code>ListValueModel</code> containing the items + * @param selectedItemHolder The holder of the selected item, if more than + * one item or no items are selected, then <code>null</code> will be passed + * @param labelProvider The renderer used to format the table holder's items + * @param helpId The topic help ID to be registered with this pane + */ + public AddRemoveListPane(Pane<? extends T> parentPane, + Composite parent, + Adapter adapter, + ListValueModel<?> listHolder, + WritablePropertyValueModel<?> selectedItemHolder, + ILabelProvider labelProvider, + String helpId) { + + super(parentPane, + parent, + adapter, + listHolder, + selectedItemHolder, + labelProvider, + helpId); + } + + /** + * Creates a new <code>AddRemoveListPane</code>. + * + * @param parentPane The parent container of this one + * @param parent The parent container + * @param adapter + * @param listHolder The <code>ListValueModel</code> containing the items + * @param selectedItemHolder The holder of the selected item, if more than + * one item or no items are selected, then <code>null</code> will be passed + * @param labelProvider The renderer used to format the table holder's items + * @param helpId The topic help ID to be registered with this pane + * @param parentManagePane <code>true</code> to have the parent pane manage + * the enabled state of this pane + */ + public AddRemoveListPane(Pane<? extends T> parentPane, + Composite parent, + Adapter adapter, + ListValueModel<?> listHolder, + WritablePropertyValueModel<?> selectedItemHolder, + ILabelProvider labelProvider, + String helpId, + boolean parentManagePane) { + + super(parentPane, + parent, + adapter, + listHolder, + selectedItemHolder, + labelProvider, + helpId, + parentManagePane); + } + + /** + * Creates a new <code>AddRemoveListPane</code>. + * + * @param parentPane The parent container of this one + * @param subjectHolder The holder of the subject + * @param adapter + * @param parent The parent container + * @param listHolder The <code>ListValueModel</code> containing the items + * @param selectedItemHolder The holder of the selected item, if more than + * one item or no items are selected, then <code>null</code> will be passed + * @param labelProvider The renderer used to format the table holder's items + */ + public AddRemoveListPane(Pane<?> parentPane, + PropertyValueModel<? extends T> subjectHolder, + Composite parent, + Adapter adapter, + ListValueModel<?> listHolder, + WritablePropertyValueModel<?> selectedItemHolder, + ILabelProvider labelProvider) { + + super(parentPane, + subjectHolder, + parent, + adapter, + listHolder, + selectedItemHolder, + labelProvider); + } + + /** + * Creates a new <code>AddRemoveListPane</code>. + * + * @param parentPane The parent container of this one + * @param subjectHolder The holder of the subject + * @param adapter + * @param parent The parent container + * @param listHolder The <code>ListValueModel</code> containing the items + * @param selectedItemHolder The holder of the selected item, if more than + * one item or no items are selected, then <code>null</code> will be passed + * @param labelProvider The renderer used to format the table holder's items + * @param helpId The topic help ID to be registered with this pane + */ + public AddRemoveListPane(Pane<?> parentPane, + PropertyValueModel<? extends T> subjectHolder, + Composite parent, + Adapter adapter, + ListValueModel<?> listHolder, + WritablePropertyValueModel<?> selectedItemHolder, + ILabelProvider labelProvider, + String helpId) { + + super(parentPane, + subjectHolder, + parent, + adapter, + listHolder, + selectedItemHolder, + labelProvider, + helpId); + } + + private ColumnAdapter<Object> buildColumnAdapter() { + return new ColumnAdapter<Object>() { + public WritablePropertyValueModel<?>[] cellModels(Object subject) { + WritablePropertyValueModel<?>[] valueHolders = new WritablePropertyValueModel<?>[1]; + valueHolders[0] = new SimplePropertyValueModel<Object>(subject); + return valueHolders; + } + + public int columnCount() { + return 1; + } + + public String columnName(int columnIndex) { + return ""; + } + }; + } + + @Override + protected void itemsAdded(ListAddEvent e) { + super.itemsAdded(e); + revalidateLayout(); + } + + @Override + protected void itemsMoved(ListMoveEvent e) { + super.itemsMoved(e); + revalidateLayout(); + } + + @Override + protected void itemsRemoved(ListRemoveEvent e) { + super.itemsRemoved(e); + revalidateLayout(); + } + + @Override + protected void itemsReplaced(ListReplaceEvent e) { + super.itemsReplaced(e); + revalidateLayout(); + } + + @Override + protected void listChanged(ListChangeEvent e) { + super.listChanged(e); + revalidateLayout(); + } + + @Override + protected void listCleared(ListClearEvent e) { + super.listCleared(e); + revalidateLayout(); + } + + /** + * Revalidates the table layout after the list of items has changed. The + * layout has to be done in a new UI thread because our listener might be + * notified before the table has been updated (table column added or removed). + */ + private void revalidateLayout() { + SWTUtil.asyncExec(new Runnable() { public void run() { + if (!table.isDisposed()) { + table.getParent().computeSize(SWT.DEFAULT, SWT.DEFAULT); + table.getParent().layout(); + } + }}); + } + + private PropertyChangeListener buildSelectedItemPropertyChangeListener() { + return new SWTPropertyChangeListenerWrapper( + buildSelectedItemPropertyChangeListener_() + ); + } + + private PropertyChangeListener buildSelectedItemPropertyChangeListener_() { + return new PropertyChangeListener() { + public void propertyChanged(PropertyChangeEvent e) { + if (table.isDisposed()) { + return; + } + getSelectionModel().setSelectedValue(e.getNewValue()); + updateButtons(); + } + }; + } + + private SelectionChangeListener<Object> buildSelectionListener() { + return new SelectionChangeListener<Object>() { + public void selectionChanged(SelectionChangeEvent<Object> e) { + AddRemoveListPane.this.selectionChanged(); + } + }; + } + + private Composite addTableContainer(Composite container) { + + container = addPane(container, buildTableContainerLayout()); + container.setLayoutData(new GridData(GridData.FILL_BOTH)); + return container; + } + + private Layout buildTableContainerLayout() { + return new Layout() { + @Override + protected Point computeSize(Composite composite, + int widthHint, + int heightHint, + boolean flushCache) { + + Table table = (Table) composite.getChildren()[0]; + TableColumn tableColumn = table.getColumn(0); + int columnWidth = tableColumn.getWidth(); + packColumn(table); + + // Calculate the table size and adjust it with the hints + Point size = table.computeSize(SWT.DEFAULT, SWT.DEFAULT); + + if (widthHint != SWT.DEFAULT) { + size.x = widthHint; + } + + if (heightHint != SWT.DEFAULT) { + size.y = heightHint; + } + + // Revert the column's width to its current value + table.setRedraw(false); + table.setLayoutDeferred(true); + tableColumn.setWidth(columnWidth); + table.setLayoutDeferred(false); + table.setRedraw(true); + + return size; + } + + private boolean isVerticalScrollbarBarVisible(Table table, + Rectangle clientArea) { + + // Get the height of all the rows + int height = table.getItemCount() * table.getItemHeight(); + + // Remove the border from the height + height += (table.getBorderWidth() * 2); + + return (clientArea.height < height); + } + + @Override + protected void layout(Composite composite, boolean flushCache) { + + Rectangle bounds = composite.getClientArea(); + + if (bounds.width > 0) { + + Table table = (Table) composite.getChildren()[0]; + table.setBounds(0, 0, bounds.width, bounds.height); + + updateTableColumnWidth( + table, + bounds.width, + isVerticalScrollbarBarVisible(table, bounds) + ); + } + } + + private void packColumn(Table table) { + + TableColumn tableColumn = table.getColumn(0); + + table.setRedraw(false); + table.setLayoutDeferred(true); + tableColumn.pack(); + table.setLayoutDeferred(false); + table.setRedraw(true); + + // Cache the column width so it can be used in + // updateTableColumnWidth() when determine which width to use + table.setData( + "column.width", + Integer.valueOf(tableColumn.getWidth()) + ); + } + + private void updateTableColumnWidth(Table table, + int width, + boolean verticalScrollbarBarVisible) { + + // Remove the border from the width + width -= (table.getBorderWidth() * 2); + + // Remove the scrollbar from the width if it is shown + if (verticalScrollbarBarVisible) { + width -= table.getVerticalBar().getSize().x; + } + + TableColumn tableColumn = table.getColumn(0); + + // Retrieve the cached column width, which is required for + // determining which width to use (the column width or the + // calculated width) + Integer columnWitdh = (Integer) table.getData("column.width"); + + // Use the calculated width if the column is smaller, otherwise + // use the column width and a horizontal scroll bar will show up + width = Math.max(width, columnWitdh); + + // Adjust the column width + tableColumn.setWidth(width); + } + }; + } + + private ITableLabelProvider buildTableLabelProvider(IBaseLabelProvider labelProvider) { + return new TableLabelProvider((ILabelProvider) labelProvider); + } + + /* + * (non-Javadoc) + */ + @Override + public Table getMainControl() { + return table; + } + + /* + * (non-Javadoc) + */ + @Override + @SuppressWarnings("unchecked") + protected void initializeMainComposite(Composite container, + Adapter adapter, + ListValueModel<?> listHolder, + WritablePropertyValueModel<?> selectedItemHolder, + IBaseLabelProvider labelProvider, + String helpId) { + + table = addUnmanagedTable( + addTableContainer(container), + SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.MULTI, + helpId + ); + + + TableModelAdapter model = TableModelAdapter.adapt( + (ListValueModel<Object>) listHolder, + getSelectedItemHolder(), + table, + buildColumnAdapter(), + buildTableLabelProvider(labelProvider) + ); + + model.addSelectionChangeListener(buildSelectionListener()); + + selectedItemHolder.addPropertyChangeListener( + PropertyValueModel.VALUE, + buildSelectedItemPropertyChangeListener() + ); + + initializeTable(table); + } + + /** + * Initializes the given table, which acts like a list in our case. + * + * @param table The main widget of this pane + */ + protected void initializeTable(Table table) { + + table.setData("column.width", new Integer(0)); + table.setHeaderVisible(false); + table.setLinesVisible(false); + } + + /** + * The selection has changed, update (1) the selected item holder, (2) the + * selection model and (3) the buttons. + */ + private void selectionChanged() { + WritablePropertyValueModel<Object> selectedItemHolder = getSelectedItemHolder(); + ObjectListSelectionModel selectionModel = getSelectionModel(); + int selectionCount = this.table.getSelectionCount(); + + if (selectionCount == 0) { + selectedItemHolder.setValue(null); + selectionModel.clearSelection(); + } + else if (selectionCount != 1) { + selectedItemHolder.setValue(null); + selectionModel.clearSelection(); + + for (int index : this.table.getSelectionIndices()) { + selectionModel.addSelectionInterval(index, index); + } + } + else { + int selectedIndex = this.table.getSelectionIndex(); + Object selectedItem = getListHolder().get(selectedIndex); + + selectedItemHolder.setValue(selectedItem); + selectionModel.setSelectedValue(selectedItem); + } + + updateButtons(); + } + + /** + * This label provider simply delegates the rendering to the provided + * <code>ILabelProvider</code>. + */ + private class TableLabelProvider extends LabelProvider + implements ITableLabelProvider { + + private ILabelProvider labelProvider; + + TableLabelProvider(ILabelProvider labelProvider) { + super(); + this.labelProvider = labelProvider; + } + + public Image getColumnImage(Object element, int columnIndex) { + return labelProvider.getImage(element); + } + + public String getColumnText(Object element, int columnIndex) { + return labelProvider.getText(element); + } + } +}
\ No newline at end of file |