/******************************************************************************* * Copyright (c) 2011, 2012 Wind River Systems, Inc. and others. 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: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.tcf.te.ui.tables.properties; import java.util.LinkedHashMap; import java.util.Map; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableLayout; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.tcf.te.ui.WorkbenchPartControl; import org.eclipse.tcf.te.ui.forms.CustomFormToolkit; import org.eclipse.tcf.te.ui.interfaces.IUIConstants; import org.eclipse.tcf.te.ui.nls.Messages; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.forms.widgets.Section; /** * Abstract node properties table control implementation. */ public abstract class NodePropertiesTableControl extends WorkbenchPartControl { // Reference to the table viewer private TableViewer viewer; // Reference to the selection changed listener private ISelectionChangedListener editorSelectionChangedListener; // We remember the sorting order (ascending vs. descending) for each // column separately. That way we can come up with the sort order switching // correctly if the user changes from one column to the next. If set // to Boolean.FALSE, the sort order for the column is descending (default) private final Map<TableColumn, Boolean> columnSortOrder = new LinkedHashMap<TableColumn, Boolean>(); /** * Default node properties table control selection changed listener implementation. * The selection changed listener is registered to the editor tree control. */ protected class NodePropertiesTableControlSelectionChangedListener implements ISelectionChangedListener { /* (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent) */ @Override public void selectionChanged(SelectionChangedEvent event) { if (getViewer() != null) { getViewer().setInput(event.getSelection()); } } } /** * Constructor. * * @param parentPart The parent workbench part this control is embedded in or <code>null</code>. */ public NodePropertiesTableControl(IWorkbenchPart parentPart) { super(parentPart); } /* (non-Javadoc) * @see org.eclipse.tcf.te.ui.WorkbenchPartControl#dispose() */ @Override public void dispose() { // Dispose the editor tree control selection changed listener if (editorSelectionChangedListener != null) { ISelectionProvider selectionProvider = (ISelectionProvider)getParentPart().getAdapter(ISelectionProvider.class); if (selectionProvider != null) { selectionProvider.removeSelectionChangedListener(editorSelectionChangedListener); editorSelectionChangedListener = null; } } super.dispose(); } /* (non-Javadoc) * @see org.eclipse.tcf.te.ui.WorkbenchPartControl#setupFormPanel(org.eclipse.swt.widgets.Composite, org.eclipse.tcf.te.ui.forms.CustomFormToolkit) */ @Override public void setupFormPanel(Composite parent, CustomFormToolkit toolkit) { super.setupFormPanel(parent, toolkit); // Create the table viewer viewer = doCreateTableViewer(parent); // Configure the table viewer configureTableViewer(viewer); // Configure the table configureTable(viewer.getTable(), viewer.getComparator() != null); // Register the control as selection listener to the editor control ISelectionProvider selectionProvider = getParentPart() != null ? (ISelectionProvider)getParentPart().getAdapter(ISelectionProvider.class) : null; if (selectionProvider != null) { // Create the selection changed listener instance editorSelectionChangedListener = doCreateEditorSelectionChangedListener(); selectionProvider.addSelectionChangedListener(editorSelectionChangedListener); } // Prepare popup menu and toolbar createContributionItems(viewer); // Set the current selection as input viewer.setInput(selectionProvider != null ? selectionProvider.getSelection() : null); } /** * Creates a new editor tree control selection changed listener instance. * * @return The editor tree control selection changed listener instance. */ protected ISelectionChangedListener doCreateEditorSelectionChangedListener() { return new NodePropertiesTableControlSelectionChangedListener(); } /** * Creates the table viewer instance. * * @param parent The parent composite. Must not be <code>null</code>. * @return The table viewer. */ protected TableViewer doCreateTableViewer(Composite parent) { Assert.isNotNull(parent); TableViewer tableViewer = new TableViewer(parent, SWT.FULL_SELECTION | SWT.MULTI | SWT.BORDER); return tableViewer; } /** * Configure the table Viewer. * * @param tableViewer The table viewer. Must not be <code>null</code>. */ protected void configureTableViewer(TableViewer tableViewer) { Assert.isNotNull(tableViewer); tableViewer.setLabelProvider(doCreateTableViewerLabelProvider(tableViewer)); tableViewer.setContentProvider(doCreateTableViewerContentProvider(tableViewer)); tableViewer.setComparator(doCreateTableViewerComparator(tableViewer)); } /** * Creates the table viewer label provider instance. * * @param viewer The table viewer. Must not be <code>null</code>. * @return The table viewer label provider instance. */ protected abstract ITableLabelProvider doCreateTableViewerLabelProvider(TableViewer viewer); /** * Creates the table viewer content provider instance. * * @param viewer The table viewer. Must not be <code>null</code>. * @return The table viewer content provider instance. */ protected abstract IStructuredContentProvider doCreateTableViewerContentProvider(TableViewer viewer); /** * Creates the table viewer comparator instance. * * @param viewer The table viewer. Must not be <code>null</code>. * @return The table viewer comparator instance or <code>null</code> to turn of sorting. */ protected ViewerComparator doCreateTableViewerComparator(TableViewer viewer) { return null; } /** * Configure the table. * * @param table The table. Must not be <code>null</code>. * @param sorted Specify <code>true</code> if the table shall support sorting, <code>false</code> otherwise. */ protected void configureTable(Table table, boolean sorted) { Assert.isNotNull(table); // Create and configure the table columns createTableColumns(table, sorted); table.setHeaderVisible(true); table.setLinesVisible(true); } /** * Create the table columns. * * @param table The table. Must not be <code>null</code>. * @param sorted Specify <code>true</code> if the table shall support sorting, <code>false</code> otherwise. */ protected void createTableColumns(final Table table, boolean sorted) { Assert.isNotNull(table); TableColumn sortColumn = null; TableColumn column = new TableColumn(table, SWT.LEFT); column.setText(Messages.NodePropertiesTableControl_column_name_label); columnSortOrder.put(column, Boolean.TRUE); if (sorted) column.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (e.widget instanceof TableColumn) { switchSortColumn(table, (TableColumn)e.widget); } } }); // The property name is the default sorting column sortColumn = column; column = new TableColumn(table, SWT.LEFT); column.setText(Messages.NodePropertiesTableControl_column_value_label); columnSortOrder.put(column, Boolean.FALSE); if (sorted) column.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (e.widget instanceof TableColumn) { switchSortColumn(table, (TableColumn)e.widget); } } }); TableLayout tableLayout = new TableLayout(); tableLayout.addColumnData(new ColumnWeightData(30)); tableLayout.addColumnData(new ColumnWeightData(70)); table.setLayout(tableLayout); GridData layoutData = new GridData(GridData.FILL_BOTH | GridData.VERTICAL_ALIGN_BEGINNING); table.setLayoutData(layoutData); if (sorted) { // set the default sort column table.setSortColumn(sortColumn); table.setSortDirection(columnSortOrder.get(sortColumn).booleanValue() ? SWT.UP : SWT.DOWN); } } /** * Switches the sort order for the given column and set the * new sort order and sort column to the given table. * * @param table The table. * @param column The table column */ protected final void switchSortColumn(Table table, TableColumn column) { if (table == null || table.isDisposed() || column == null || column.isDisposed()) { return; } // Get the current sorting order for the given column boolean newSortOrder = !columnSortOrder.get(column).booleanValue(); // Set sort column and sort direction table.setSortColumn(column); table.setSortDirection(newSortOrder ? SWT.UP : SWT.DOWN); // And update the remembered sort order in the map columnSortOrder.put(column, Boolean.valueOf(newSortOrder)); getViewer().refresh(); } /** * Create the context menu and toolbar groups. * * @param viewer The table viewer. Must not be <code>null</code>. */ protected void createContributionItems(TableViewer viewer) { Assert.isNotNull(viewer); // Create the menu manager MenuManager manager = new MenuManager("#PopupMenu"); //$NON-NLS-1$ // Attach the menu listener manager.addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager manager) { manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); } }); // All items are removed when menu is closing manager.setRemoveAllWhenShown(true); // Associated with the tree viewer.getTable().setMenu(manager.createContextMenu(viewer.getTable())); // Register the context menu at the parent workbench part site. if (getParentPart() != null && getParentPart().getSite() != null && getContextMenuId() != null) { IWorkbenchPartSite site = getParentPart().getSite(); site.registerContextMenu(getContextMenuId(), manager, viewer); } // The toolbar is a bit more complicated as we want to have the // toolbar placed within the section title. createToolbarContributionItem(viewer); } /** * Returns the controls context menu id. * * @return The context menu id or <code>null</code>. */ protected String getContextMenuId() { return IUIConstants.ID_CONTROL_MENUS_BASE + ".menu.propertiesTable"; //$NON-NLS-1$ } /** * Creates the toolbar within the section parent of the given filtered tree. * * @param viewer The table viewer. Must not be <code>null</code>. */ protected void createToolbarContributionItem(TableViewer viewer) { Assert.isNotNull(viewer); // Determine the section parent from the filtered tree Composite parent = viewer.getTable().getParent(); while (parent != null && !(parent instanceof Section)) { parent = parent.getParent(); } // We are done here if we cannot find a section parent or the parent is disposed if (parent == null || parent.isDisposed()) { return; } // Create the toolbar control ToolBar toolbar = new ToolBar(parent, SWT.FLAT | SWT.HORIZONTAL | SWT.RIGHT); // The cursor within the toolbar shall change to an hand final Cursor handCursor = new Cursor(parent.getDisplay(), SWT.CURSOR_HAND); toolbar.setCursor(handCursor); // Cursor needs to be explicitly disposed toolbar.addDisposeListener(new DisposeListener() { @Override public void widgetDisposed(DisposeEvent e) { if (handCursor.isDisposed() == false) { handCursor.dispose(); } } }); // Set the toolbar as text client to the section header ((Section)parent).setTextClient(toolbar); // create the toolbar items createToolBarItems(toolbar); } /** * Create the toolbar items to be added to the toolbar. Override * to add the wanted toolbar items. * <p> * <b>Note:</b> The toolbar items are added from left to right. * * @param toolbar The toolbar to add the toolbar items too. Must not be <code>null</code>. */ protected void createToolBarItems(ToolBar toolbar) { Assert.isNotNull(toolbar); } /** * Returns the viewer instance. * * @return The viewer instance or <code>null</code>. */ public Viewer getViewer() { return viewer; } /* (non-Javadoc) * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) */ @Override public Object getAdapter(Class adapter) { if (Viewer.class.isAssignableFrom(adapter)) { // We have to double check if our real viewer is assignable to // the requested Viewer class. Viewer viewer = getViewer(); if (!adapter.isAssignableFrom(viewer.getClass())) { viewer = null; } return viewer; } else if (ISelectionListener.class.isAssignableFrom(adapter)) { return editorSelectionChangedListener; } return super.getAdapter(adapter); } }