| /******************************************************************************* |
| * Copyright (c) 2004, 2005 IBM Corporation 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: |
| * IBM Corporation - Initial API and implementation |
| * Jens Lukowski/Innoopract - initial renaming/restructuring |
| *******************************************************************************/ |
| package org.eclipse.wst.common.ui.internal.viewers; |
| |
| import org.eclipse.swt.events.*; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.widgets.*; |
| |
| import org.eclipse.swt.custom.TableCursor; |
| import org.eclipse.swt.custom.TableTreeItem; |
| import org.eclipse.jface.viewers.*; |
| |
| |
| /** |
| * Adds a TableCursor to a StructuredViewer - for keyboard navigation of the table |
| * The intent of this class is to provide the standard listeners for using F2 to |
| * activate cell editors. |
| * |
| * Due to a current bug in the TableCursor, TableViewers using this class must make |
| * a call similar to the TableNavigator method moveCellEditorsAbove(cellEditors) |
| * whenever a setCellEditors call is made in the StructuredViewer. This is so that the |
| * cell editor control shows up above the table cursor control. |
| */ |
| |
| public class TableNavigator extends TableCursor |
| { |
| private static final String TABLETREEITEM_ID = "TableTreeItemID"; |
| |
| final Table table; |
| |
| public TableNavigator(Table table, StructuredViewer viewer) |
| { |
| super(table, SWT.NONE); |
| this.table = table; |
| final Table currentTable = table; |
| final StructuredViewer sViewer = viewer; |
| |
| // Linux index out of bounds fix. See defect 253429, 253433, and more |
| setVisible(false); |
| |
| addPaintListener(viewer); |
| addKeyListeners(viewer); |
| addMouseListeners(viewer); |
| addSelectionListener(new SelectionAdapter() |
| { |
| /** |
| * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(SelectionEvent) |
| */ |
| public void widgetSelected(SelectionEvent e) { |
| super.widgetSelected(e); |
| if (sViewer instanceof TableTreeViewer) |
| { |
| TableTreeItem tableTreeItem = (TableTreeItem)getRow().getData(TABLETREEITEM_ID); |
| StructuredSelection selection = new StructuredSelection(tableTreeItem.getData()); |
| sViewer.setSelection(selection, true); |
| } |
| } |
| |
| |
| }); |
| addFocusListener(new FocusAdapter(){ |
| public void focusGained(FocusEvent e) |
| { |
| // if e.source is not a child of the table then set selection - this is for tab into viewer |
| Object eventSource = e.getSource(); |
| if (eventSource instanceof Control) |
| { |
| if (!isChild(currentTable, (Control)eventSource)) |
| { |
| if (currentTable.getItemCount() > 0 && currentTable.getSelectionCount() <= 0) |
| { |
| if (sViewer instanceof TableTreeViewer) |
| { |
| TableTreeItem tableTreeItem = (TableTreeItem)getRow().getData(TABLETREEITEM_ID); |
| StructuredSelection selection = new StructuredSelection(tableTreeItem.getData()); |
| sViewer.setSelection(selection, true); |
| } |
| else |
| { |
| currentTable.setSelection(0); |
| setSelection(0,0); |
| } |
| } |
| } |
| else |
| { |
| if (currentTable.getItems().length > 0) |
| { |
| // cursor can end up on a non-existent table row |
| // currently no way to get the current table cursor row |
| // so for now just catch the exception since it doesn't |
| // cause any side effects. |
| try |
| { |
| setVisible(true); |
| } |
| catch (Exception ee) |
| { |
| currentTable.setSelection(0); |
| setSelection(0,0); |
| } |
| } |
| else // do not show table cursor if there are no elements in the table - avoid repaint |
| { |
| setVisible(false); |
| } |
| } |
| } |
| } |
| |
| protected boolean isChild(Control parent, Control child) |
| { |
| Control tempChild = child; |
| while (tempChild != null) |
| { |
| if (tempChild == parent) |
| { |
| return true; |
| } |
| tempChild = tempChild.getParent(); |
| } |
| return false; |
| } |
| |
| /** |
| * @see org.eclipse.swt.events.FocusAdapter#focusLost(FocusEvent) |
| */ |
| public void focusLost(FocusEvent e) |
| { |
| // Set the table navigator to be not visible if the the table |
| // is not in focus and a child of the table is not in focus |
| // note that we do this asynchronously so we don't mess up the |
| // current focus handling. |
| Display.getDefault().asyncExec(new Runnable() |
| { |
| /** |
| * @see java.lang.Runnable#run() |
| */ |
| public void run() |
| { |
| if (currentTable != null && !currentTable.isDisposed() && !currentTable.isFocusControl() && |
| !isChild(currentTable, Display.getDefault().getFocusControl())) |
| { |
| setVisible(false); |
| } |
| } |
| }); |
| } |
| |
| }); |
| |
| |
| |
| |
| table.addFocusListener(new FocusAdapter() |
| { |
| /** |
| * @see org.eclipse.swt.events.FocusListener#focusGained(FocusEvent) |
| */ |
| public void focusGained(FocusEvent e) |
| { |
| // only display navigator if there are items in the table |
| // and if the focus wasn't gained from our own table navigator |
| // (ie focus came from outside) |
| if (currentTable.getItemCount() > 0 && |
| (Display.getDefault().getFocusControl() != null) && |
| !Display.getDefault().getFocusControl().equals(TableNavigator.this)) |
| { |
| // note that we do this asynchronously so we don't mess up the |
| // current focus handling. |
| Display.getDefault().asyncExec(new Runnable() |
| { |
| /** |
| * @see java.lang.Runnable#run() |
| */ |
| public void run() |
| { |
| if (!isVisible()) |
| { |
| try |
| { |
| setVisible(true); |
| setFocus(); |
| } |
| catch (Exception e) |
| { |
| // catch IllegalArgumentExceptions here - index out of bounds on tableviewer |
| if (currentTable.getItemCount() > 0) |
| { |
| currentTable.setSelection(0); |
| setSelection(0,0); |
| } |
| else // do not show table cursor if there are no elements in the table - avoid repaint |
| { |
| setVisible(false); |
| } |
| } |
| } |
| } |
| }); |
| } |
| } |
| }); |
| } |
| |
| public Table getTable() |
| { |
| return table; |
| } |
| |
| public void addPaintListener(StructuredViewer viewer) |
| { |
| final StructuredViewer tableViewer = viewer; |
| |
| addPaintListener(new PaintListener() |
| { |
| public void paintControl(PaintEvent e) |
| { |
| TableItem[] selection = table.getSelection(); |
| final TableItem row = (selection.length == 0) ? table.getItem(table.getTopIndex()) : selection[0]; |
| final String cellText = row.getText(getColumn()); |
| final Image cellImage = row.getImage(getColumn()); |
| final int col = getColumn(); |
| |
| Display.getCurrent().asyncExec(new Runnable() |
| { |
| public void run() |
| { |
| if (!row.isDisposed()) |
| { |
| String newText = row.getText(getColumn()); |
| TableItem cursorRow = getRow(); |
| if (!newText.equals(cellText) || !(row.getImage(col) == cellImage)) |
| { |
| redraw(); |
| } |
| } |
| } |
| }); |
| } |
| }); |
| } |
| |
| |
| public SelectionKeyAdapter getKeyAdapter(StructuredViewer viewer) |
| { |
| if (keyAdapter == null) |
| { |
| return new SelectionKeyAdapter(viewer); |
| } |
| else return keyAdapter; |
| } |
| |
| public void setKeyAdapter(SelectionKeyAdapter kAdapter) |
| { |
| keyAdapter = kAdapter; |
| } |
| |
| protected SelectionKeyAdapter keyAdapter = null; |
| |
| public class SelectionKeyAdapter extends KeyAdapter |
| { |
| StructuredViewer structuredViewer; |
| |
| public SelectionKeyAdapter(StructuredViewer viewer) |
| { |
| super(); |
| this.structuredViewer = viewer; |
| } |
| |
| int lastKeyPressed = -1; // used to cache the last key for key combos |
| |
| public void keyPressed(KeyEvent e) |
| { |
| TableItem row = getRow(); |
| int column = getColumn(); |
| |
| // hack to emulate SHIFT+F10 popup menu - otherwise table cursor |
| // obscures the table popup mechanism and it doesn't work. |
| if (lastKeyPressed == SWT.SHIFT && e.keyCode == SWT.F10) |
| { |
| Menu popup = getTable().getMenu(); |
| popup.setVisible(true); |
| } |
| lastKeyPressed = e.keyCode; |
| |
| //jvh - look for + or - key |
| // column == 0 |
| if (row.getData(TABLETREEITEM_ID) instanceof TableTreeItem) |
| { |
| if (column == 0 && e.character == '+') |
| { |
| TableTreeItem tableTreeItem = (TableTreeItem)row.getData(TABLETREEITEM_ID); |
| ((TableTreeViewer)structuredViewer).setExpandedState(tableTreeItem.getData(), true); |
| refresh(); |
| } |
| else if (column == 0 && e.character == '-') |
| { |
| TableTreeItem tableTreeItem = (TableTreeItem)row.getData(TABLETREEITEM_ID); |
| ((TableTreeViewer)structuredViewer).setExpandedState(tableTreeItem.getData(), false); |
| refresh(); |
| } |
| } |
| // use F2 to invoke editing for a cell |
| if (e.keyCode == SWT.F2) |
| { |
| if (structuredViewer instanceof TableViewer) |
| { |
| ((TableViewer)structuredViewer).editElement(row.getData(), column); |
| } |
| else if (structuredViewer instanceof TableTreeViewer) |
| { |
| TableTreeItem tableTreeItem = (TableTreeItem)row.getData(TABLETREEITEM_ID); |
| ((TableTreeViewer)structuredViewer).editElement(tableTreeItem.getData(), column); |
| } |
| } |
| } |
| } |
| |
| public void addKeyListeners(StructuredViewer viewer) |
| { |
| final StructuredViewer structuredViewer = viewer; |
| |
| addKeyListener(getKeyAdapter(structuredViewer)); |
| } |
| |
| public void addMouseListeners(StructuredViewer viewer) |
| { |
| final StructuredViewer structuredViewer = viewer; |
| |
| addMouseListener(new MouseAdapter() |
| { |
| |
| public void mouseUp(MouseEvent e) |
| { |
| TableItem row = getRow(); |
| int column = getColumn(); |
| |
| // use mouse button 1 to invoke editing for a cell |
| if (e.button == 1) |
| { |
| if (structuredViewer instanceof TableViewer) |
| { |
| ((TableViewer)structuredViewer).editElement(row.getData(), column); |
| } |
| else if (structuredViewer instanceof TableTreeViewer && column == 1) |
| { |
| TableTreeItem tableTreeItem = (TableTreeItem)row.getData(TABLETREEITEM_ID); |
| ((TableTreeViewer)structuredViewer).editElement(tableTreeItem.getData(), column); |
| } |
| |
| if (structuredViewer instanceof TableTreeViewer && row.getData(TABLETREEITEM_ID) instanceof TableTreeItem) |
| { |
| if (column == 0) |
| { |
| TableTreeItem tableTreeItem = (TableTreeItem)row.getData(TABLETREEITEM_ID); |
| boolean expandState = tableTreeItem.getExpanded(); |
| ((TableTreeViewer)structuredViewer).setExpandedState(tableTreeItem.getData(), !expandState); |
| refresh(); |
| } |
| } |
| } |
| } |
| }); |
| } |
| |
| |
| /** |
| * Ensure that cell editor control shows up above the table cursor control. |
| * Should be called whenever the table viewer makes a new call to setCellEditors |
| * i.e. in constructor and in refreshCellEditors |
| * |
| * @param - array of cell editors for the StructuredViewer |
| */ |
| |
| public void moveCellEditorsAbove(CellEditor[] editorArray) |
| { |
| for (int i = 0; i < editorArray.length ; i++) |
| { |
| CellEditor cEd = editorArray[i]; |
| if (cEd != null && cEd.getControl() != null) |
| { |
| cEd.getControl().moveAbove(null); |
| } |
| } |
| } |
| |
| public void refresh() |
| { |
| Display.getCurrent().asyncExec(new Runnable() |
| { |
| public void run() |
| { |
| if (!isDisposed() && isVisible()) |
| redraw(); |
| } |
| }); |
| } |
| } |