Mercurial > projects > dwt-addons
view dwtx/jface/viewers/ColumnViewerEditor.d @ 39:644f1334b451
fix anon classes
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Tue, 08 Apr 2008 22:05:42 +0200 |
parents | b6c35faf97c8 |
children | 07b9d96fd764 |
line wrap: on
line source
/******************************************************************************* * Copyright (c) 2006, 2008 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 * Tom Schindl <tom.schindl@bestsolution.at> - refactoring (bug 153993) * fix in bug 151295,166500,200337 * Port to the D programming language: * Frank Benoit <benoit@tionex.de> *******************************************************************************/ module dwtx.jface.viewers.ColumnViewerEditor; import dwtx.jface.viewers.CellEditor; import dwtx.jface.viewers.ICellEditorListener; import dwtx.jface.viewers.ColumnViewer; import dwtx.jface.viewers.ColumnViewerEditorActivationStrategy; import dwtx.jface.viewers.ViewerCell; import dwtx.jface.viewers.ViewerColumn; import dwtx.jface.viewers.ColumnViewerEditorActivationEvent; import dwtx.jface.viewers.ColumnViewerEditorActivationListener; import dwtx.jface.viewers.ColumnViewerEditorDeactivationEvent; import dwtx.jface.viewers.ViewerRow; import dwtx.jface.viewers.DoubleClickEvent; import dwtx.jface.viewers.OpenEvent; import dwt.DWT; import dwt.events.FocusAdapter; import dwt.events.FocusEvent; import dwt.events.FocusListener; import dwt.events.MouseAdapter; import dwt.events.MouseEvent; import dwt.events.MouseListener; import dwt.events.TraverseEvent; import dwt.events.TraverseListener; import dwt.widgets.Control; import dwt.widgets.Display; import dwt.widgets.Item; import dwtx.core.runtime.ListenerList; import dwt.dwthelper.utils; /** * This is the base for all editor implementations of Viewers. ColumnViewer * implementators have to subclass this class and implement the missing methods * * @since 3.3 * @see TableViewerEditor * @see TreeViewerEditor */ public abstract class ColumnViewerEditor { private CellEditor cellEditor; private ICellEditorListener cellEditorListener; private FocusListener focusListener; private MouseListener mouseListener; private ColumnViewer viewer; private TraverseListener tabeditingListener; private int activationTime; private ViewerCell cell; private ColumnViewerEditorActivationEvent activationEvent; private ListenerList editorActivationListener; private ColumnViewerEditorActivationStrategy editorActivationStrategy; /** * Tabbing from cell to cell is turned off */ public static const int DEFAULT = 1; /** * Should if the end of the row is reach started from the start/end of the * row below/above */ public static const int TABBING_MOVE_TO_ROW_NEIGHBOR = 1 << 1; /** * Should if the end of the row is reach started from the beginning in the * same row */ public static const int TABBING_CYCLE_IN_ROW = 1 << 2; /** * Support tabbing to Cell above/below the current cell */ public static const int TABBING_VERTICAL = 1 << 3; /** * Should tabbing from column to column with in one row be supported */ public static const int TABBING_HORIZONTAL = 1 << 4; /** * Style mask used to enable keyboard activation */ public static const int KEYBOARD_ACTIVATION = 1 << 5; private int feature; /** * @param viewer * the viewer this editor is attached to * @param editorActivationStrategy * the strategy used to decide about editor activation * @param feature * bit mask controlling the editor * <ul> * <li>{@link ColumnViewerEditor#DEFAULT}</li> * <li>{@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}</li> * <li>{@link ColumnViewerEditor#TABBING_HORIZONTAL}</li> * <li>{@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}</li> * <li>{@link ColumnViewerEditor#TABBING_VERTICAL}</li> * </ul> */ protected this(ColumnViewer viewer, ColumnViewerEditorActivationStrategy editorActivationStrategy, int feature) { this.viewer = viewer; this.editorActivationStrategy = editorActivationStrategy; if ((feature & KEYBOARD_ACTIVATION) is KEYBOARD_ACTIVATION) { this.editorActivationStrategy .setEnableEditorActivationWithKeyboard(true); } this.feature = feature; initCellEditorListener(); } private void initCellEditorListener() { cellEditorListener = new class ICellEditorListener { public void editorValueChanged(bool oldValidState, bool newValidState) { // Ignore. } public void cancelEditor() { this.outer.cancelEditing(); } public void applyEditorValue() { this.outer.applyEditorValue(); } }; } void activateCellEditor() { ViewerColumn part = viewer.getViewerColumn(cell.getColumnIndex()); Object element = cell.getElement(); if (part !is null && part.getEditingSupport() !is null && part.getEditingSupport().canEdit_package(element)) { cellEditor = part.getEditingSupport().getCellEditor_package(element); if (cellEditor !is null) { if (editorActivationListener !is null && !editorActivationListener.isEmpty()) { Object[] ls = editorActivationListener.getListeners(); for (int i = 0; i < ls.length; i++) { if (activationEvent.cancel) { // Avoid leaking this.cell = null; return; } (cast(ColumnViewerEditorActivationListener) ls[i]) .beforeEditorActivated(activationEvent); } } updateFocusCell(cell, activationEvent); cellEditor.addListener(cellEditorListener); part.getEditingSupport().initializeCellEditorValue_package(cellEditor, cell); // Tricky flow of control here: // activate() can trigger callback to cellEditorListener which // will clear cellEditor // so must get control first, but must still call activate() // even if there is no control. Control control = cellEditor.getControl(); cellEditor.activate(activationEvent); if (control is null) { return; } setLayoutData(cellEditor.getLayoutData()); setEditor(control, cast(Item) cell.getItem(), cell.getColumnIndex()); cellEditor.setFocus(); if( cellEditor.dependsOnExternalFocusListener() ) { if (focusListener is null) { focusListener = new class FocusAdapter { public void focusLost(FocusEvent e) { applyEditorValue(); } }; } control.addFocusListener(focusListener); } mouseListener = new class(control) MouseAdapter { Control control_; this(Control a){ control_=a; } public void mouseDown(MouseEvent e) { // time wrap? // check for expiration of doubleClickTime if (e.time <= activationTime) { control_.removeMouseListener(mouseListener); cancelEditing(); handleDoubleClickEvent(); } else if (mouseListener !is null) { control_.removeMouseListener(mouseListener); } } }; control.addMouseListener(mouseListener); if (tabeditingListener is null) { tabeditingListener = new class TraverseListener { public void keyTraversed(TraverseEvent e) { if ((feature & DEFAULT) !is DEFAULT) { processTraverseEvent(cell.getColumnIndex(), viewer.getViewerRowFromItem_package(cell .getItem()), e); } } }; } control.addTraverseListener(tabeditingListener); if (editorActivationListener !is null && !editorActivationListener.isEmpty()) { Object[] ls = editorActivationListener.getListeners(); for (int i = 0; i < ls.length; i++) { (cast(ColumnViewerEditorActivationListener) ls[i]) .afterEditorActivated(activationEvent); } } } } else { // Avoid leaking this.cell = null; } } /** * Applies the current value and deactivates the currently active cell * editor. */ void applyEditorValue() { CellEditor c = this.cellEditor; if (c !is null && this.cell !is null) { // null out cell editor before calling save // in case save results in applyEditorValue being re-entered // see 1GAHI8Z: ITPUI:ALL - How to code event notification when // using cell editor ? ColumnViewerEditorDeactivationEvent tmp = new ColumnViewerEditorDeactivationEvent( cell); if (editorActivationListener !is null && !editorActivationListener.isEmpty()) { Object[] ls = editorActivationListener.getListeners(); for (int i = 0; i < ls.length; i++) { (cast(ColumnViewerEditorActivationListener) ls[i]) .beforeEditorDeactivated(tmp); } } this.cellEditor = null; this.activationEvent = null; Item t = cast(Item) this.cell.getItem(); // don't null out table item -- same item is still selected if (t !is null && !t.isDisposed()) { saveEditorValue(c); } setEditor(null, null, 0); c.removeListener(cellEditorListener); Control control = c.getControl(); if (control !is null) { if (mouseListener !is null) { control.removeMouseListener(mouseListener); // Clear the instance not needed any more mouseListener = null; } if (focusListener !is null) { control.removeFocusListener(focusListener); } if (tabeditingListener !is null) { control.removeTraverseListener(tabeditingListener); } } c.deactivate(); if (editorActivationListener !is null && !editorActivationListener.isEmpty()) { Object[] ls = editorActivationListener.getListeners(); for (int i = 0; i < ls.length; i++) { (cast(ColumnViewerEditorActivationListener) ls[i]) .afterEditorDeactivated(tmp); } } this.cell = null; } } /** * Cancel editing */ void cancelEditing() { if (cellEditor !is null) { ColumnViewerEditorDeactivationEvent tmp = new ColumnViewerEditorDeactivationEvent( cell); if (editorActivationListener !is null && !editorActivationListener.isEmpty()) { Object[] ls = editorActivationListener.getListeners(); for (int i = 0; i < ls.length; i++) { (cast(ColumnViewerEditorActivationListener) ls[i]) .beforeEditorDeactivated(tmp); } } setEditor(null, null, 0); cellEditor.removeListener(cellEditorListener); Control control = cellEditor.getControl(); if (control !is null) { if (mouseListener !is null) { control.removeMouseListener(mouseListener); // Clear the instance not needed any more mouseListener = null; } if (focusListener !is null) { control.removeFocusListener(focusListener); } if (tabeditingListener !is null) { control.removeTraverseListener(tabeditingListener); } } CellEditor oldEditor = cellEditor; oldEditor.deactivate(); if (editorActivationListener !is null && !editorActivationListener.isEmpty()) { Object[] ls = editorActivationListener.getListeners(); for (int i = 0; i < ls.length; i++) { (cast(ColumnViewerEditorActivationListener) ls[i]) .afterEditorDeactivated(tmp); } } this.cellEditor = null; this.activationEvent = null; this.cell = null; } } /** * Enable the editor by mouse down * * @param event */ void handleEditorActivationEvent(ColumnViewerEditorActivationEvent event) { if (editorActivationStrategy.isEditorActivationEvent_package(event)) { if (cellEditor !is null) { applyEditorValue(); } this.cell = cast(ViewerCell) event.getSource(); activationEvent = event; activationTime = event.time + Display.getCurrent().getDoubleClickTime(); activateCellEditor(); } } private void saveEditorValue(CellEditor cellEditor) { ViewerColumn part = viewer.getViewerColumn(cell.getColumnIndex()); if (part !is null && part.getEditingSupport() !is null) { part.getEditingSupport().saveCellEditorValue_package(cellEditor, cell); } } /** * Return whether there is an active cell editor. * * @return <code>true</code> if there is an active cell editor; otherwise * <code>false</code> is returned. */ bool isCellEditorActive() { return cellEditor !is null; } void handleDoubleClickEvent() { viewer.fireDoubleClick_package(new DoubleClickEvent(viewer, viewer .getSelection())); viewer.fireOpen_package(new OpenEvent(viewer, viewer.getSelection())); } /** * Adds the given listener, it is to be notified when the cell editor is * activated or deactivated. * * @param listener * the listener to add */ public void addEditorActivationListener( ColumnViewerEditorActivationListener listener) { if (editorActivationListener is null) { editorActivationListener = new ListenerList(); } editorActivationListener.add(listener); } /** * Removes the given listener. * * @param listener * the listener to remove */ public void removeEditorActivationListener( ColumnViewerEditorActivationListener listener) { if (editorActivationListener !is null) { editorActivationListener.remove(listener); } } /** * Process the traverse event and opens the next available editor depending * of the implemented strategy. The default implementation uses the style * constants * <ul> * <li>{@link ColumnViewerEditor#TABBING_MOVE_TO_ROW_NEIGHBOR}</li> * <li>{@link ColumnViewerEditor#TABBING_CYCLE_IN_ROW}</li> * <li>{@link ColumnViewerEditor#TABBING_VERTICAL}</li> * <li>{@link ColumnViewerEditor#TABBING_HORIZONTAL}</li> * </ul> * * <p> * Subclasses may overwrite to implement their custom logic to edit the next * cell * </p> * * @param columnIndex * the index of the current column * @param row * the current row - may only be used for the duration of this * method call * @param event * the traverse event */ protected void processTraverseEvent(int columnIndex, ViewerRow row, TraverseEvent event) { ViewerCell cell2edit = null; if (event.detail is DWT.TRAVERSE_TAB_PREVIOUS) { event.doit = false; if ((event.stateMask & DWT.CTRL) is DWT.CTRL && (feature & TABBING_VERTICAL) is TABBING_VERTICAL) { cell2edit = searchCellAboveBelow(row, viewer, columnIndex, true); } else if ((feature & TABBING_HORIZONTAL) is TABBING_HORIZONTAL) { cell2edit = searchPreviousCell(row, viewer, columnIndex, columnIndex); } } else if (event.detail is DWT.TRAVERSE_TAB_NEXT) { event.doit = false; if ((event.stateMask & DWT.CTRL) is DWT.CTRL && (feature & TABBING_VERTICAL) is TABBING_VERTICAL) { cell2edit = searchCellAboveBelow(row, viewer, columnIndex, false); } else if ((feature & TABBING_HORIZONTAL) is TABBING_HORIZONTAL) { cell2edit = searchNextCell(row, viewer, columnIndex, columnIndex); } } if (cell2edit !is null) { viewer.getControl().setRedraw(false); ColumnViewerEditorActivationEvent acEvent = new ColumnViewerEditorActivationEvent( cell2edit, event); viewer.triggerEditorActivationEvent_package(acEvent); viewer.getControl().setRedraw(true); } } private ViewerCell searchCellAboveBelow(ViewerRow row, ColumnViewer viewer, int columnIndex, bool above) { ViewerCell rv = null; ViewerRow newRow = null; if (above) { newRow = row.getNeighbor(ViewerRow.ABOVE, false); } else { newRow = row.getNeighbor(ViewerRow.BELOW, false); } if (newRow !is null) { ViewerColumn column = viewer.getViewerColumn(columnIndex); if (column !is null && column.getEditingSupport() !is null && column.getEditingSupport().canEdit_package( newRow.getItem().getData())) { rv = newRow.getCell(columnIndex); } else { rv = searchCellAboveBelow(newRow, viewer, columnIndex, above); } } return rv; } private ViewerCell searchPreviousCell(ViewerRow row, ColumnViewer viewer, int columnIndex, int startIndex) { ViewerCell rv = null; if (columnIndex - 1 >= 0) { ViewerColumn column = viewer.getViewerColumn(columnIndex - 1); if (column !is null && column.getEditingSupport() !is null && column.getEditingSupport().canEdit_package( row.getItem().getData())) { rv = row.getCell(columnIndex - 1); } else { rv = searchPreviousCell(row, viewer, columnIndex - 1, startIndex); } } else { if ((feature & TABBING_CYCLE_IN_ROW) is TABBING_CYCLE_IN_ROW) { // Check that we don't get into endless loop if (columnIndex - 1 !is startIndex) { // Don't subtract -1 from getColumnCount() we need to // start in the virtual column // next to it rv = searchPreviousCell(row, viewer, row.getColumnCount(), startIndex); } } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) is TABBING_MOVE_TO_ROW_NEIGHBOR) { ViewerRow rowAbove = row.getNeighbor(ViewerRow.ABOVE, false); if (rowAbove !is null) { rv = searchPreviousCell(rowAbove, viewer, rowAbove .getColumnCount(), startIndex); } } } return rv; } private ViewerCell searchNextCell(ViewerRow row, ColumnViewer viewer, int columnIndex, int startIndex) { ViewerCell rv = null; if (columnIndex + 1 < row.getColumnCount()) { ViewerColumn column = viewer.getViewerColumn(columnIndex + 1); if (column !is null && column.getEditingSupport() !is null && column.getEditingSupport().canEdit_package( row.getItem().getData())) { rv = row.getCell(columnIndex + 1); } else { rv = searchNextCell(row, viewer, columnIndex + 1, startIndex); } } else { if ((feature & TABBING_CYCLE_IN_ROW) is TABBING_CYCLE_IN_ROW) { // Check that we don't get into endless loop if (columnIndex + 1 !is startIndex) { // Start from -1 from the virtual column before the // first one rv = searchNextCell(row, viewer, -1, startIndex); } } else if ((feature & TABBING_MOVE_TO_ROW_NEIGHBOR) is TABBING_MOVE_TO_ROW_NEIGHBOR) { ViewerRow rowBelow = row.getNeighbor(ViewerRow.BELOW, false); if (rowBelow !is null) { rv = searchNextCell(rowBelow, viewer, -1, startIndex); } } } return rv; } /** * Position the editor inside the control * * @param w * the editor control * @param item * the item (row) in which the editor is drawn in * @param fColumnNumber * the column number in which the editor is shown */ protected abstract void setEditor(Control w, Item item, int fColumnNumber); /** * set the layout data for the editor * * @param layoutData * the layout data used when editor is displayed */ protected abstract void setLayoutData(CellEditor.LayoutData layoutData); /** * @param focusCell * updates the cell with the current input focus * @param event * the event requesting to update the focusCell */ protected abstract void updateFocusCell(ViewerCell focusCell, ColumnViewerEditorActivationEvent event); /** * @return the cell currently holding the focus if no cell has the focus or * the viewer implementation doesn't support <code>null</code> is * returned * */ public ViewerCell getFocusCell() { return null; } /** * @return the viewer working for */ protected ColumnViewer getViewer() { return viewer; } }