Package org.eclipse.jface.viewers

Source Code of org.eclipse.jface.viewers.ColumnViewerEditor

/*******************************************************************************
* 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
*******************************************************************************/

package org.eclipse.jface.viewers;

import org.eclipse.core.runtime.ListenerList;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Item;

/**
* 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 final int DEFAULT = 1;

  /**
   * Should if the end of the row is reach started from the start/end of the
   * row below/above
   */
  public static final 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 final int TABBING_CYCLE_IN_ROW = 1 << 2;

  /**
   * Support tabbing to Cell above/below the current cell
   */
  public static final int TABBING_VERTICAL = 1 << 3;

  /**
   * Should tabbing from column to column with in one row be supported
   */
  public static final int TABBING_HORIZONTAL = 1 << 4;

  /**
   * Style mask used to enable keyboard activation
   */
  public static final 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 ColumnViewerEditor(ColumnViewer viewer,
      ColumnViewerEditorActivationStrategy editorActivationStrategy,
      int feature) {
    this.viewer = viewer;
    this.editorActivationStrategy = editorActivationStrategy;
    if ((feature & KEYBOARD_ACTIVATION) == KEYBOARD_ACTIVATION) {
      this.editorActivationStrategy
          .setEnableEditorActivationWithKeyboard(true);
    }
    this.feature = feature;
    initCellEditorListener();
  }

  private void initCellEditorListener() {
    cellEditorListener = new ICellEditorListener() {
      public void editorValueChanged(boolean oldValidState,
          boolean newValidState) {
        // Ignore.
      }

      public void cancelEditor() {
        ColumnViewerEditor.this.cancelEditing();
      }

      public void applyEditorValue() {
        ColumnViewerEditor.this.applyEditorValue();
      }
    };
  }

  void activateCellEditor() {

    ViewerColumn part = viewer.getViewerColumn(cell.getColumnIndex());
    Object element = cell.getElement();

    if (part != null && part.getEditingSupport() != null
        && part.getEditingSupport().canEdit(element)) {

      cellEditor = part.getEditingSupport().getCellEditor(element);
      if (cellEditor != null) {
        if (editorActivationListener != null
            && !editorActivationListener.isEmpty()) {
          Object[] ls = editorActivationListener.getListeners();
          for (int i = 0; i < ls.length; i++) {

            if (activationEvent.cancel) {
              // Avoid leaking
              this.cell = null;
              return;
            }

            ((ColumnViewerEditorActivationListener) ls[i])
                .beforeEditorActivated(activationEvent);
          }
        }

        updateFocusCell(cell, activationEvent);

        cellEditor.addListener(cellEditorListener);
        part.getEditingSupport().initializeCellEditorValue(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.
        final Control control = cellEditor.getControl();
        cellEditor.activate(activationEvent);
        if (control == null) {
          return;
        }
        setLayoutData(cellEditor.getLayoutData());
        setEditor(control, (Item) cell.getItem(), cell.getColumnIndex());
        cellEditor.setFocus();

        if( cellEditor.dependsOnExternalFocusListener() ) {
          if (focusListener == null) {
            focusListener = new FocusAdapter() {
              public void focusLost(FocusEvent e) {
                applyEditorValue();
              }
            };
          }
          control.addFocusListener(focusListener);
        }

        mouseListener = new MouseAdapter() {
          public void mouseDown(MouseEvent e) {
            // time wrap?
            // check for expiration of doubleClickTime
            if (e.time <= activationTime) {
              control.removeMouseListener(mouseListener);
              cancelEditing();
              handleDoubleClickEvent();
            } else if (mouseListener != null) {
              control.removeMouseListener(mouseListener);
            }
          }
        };
        control.addMouseListener(mouseListener);

        if (tabeditingListener == null) {
          tabeditingListener = new TraverseListener() {

            public void keyTraversed(TraverseEvent e) {
              if ((feature & DEFAULT) != DEFAULT) {
                processTraverseEvent(cell.getColumnIndex(),
                    viewer.getViewerRowFromItem(cell
                        .getItem()), e);
              }
            }
          };
        }

        control.addTraverseListener(tabeditingListener);

        if (editorActivationListener != null
            && !editorActivationListener.isEmpty()) {
          Object[] ls = editorActivationListener.getListeners();
          for (int i = 0; i < ls.length; i++) {
            ((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 != null && this.cell != 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 != null
          && !editorActivationListener.isEmpty()) {
        Object[] ls = editorActivationListener.getListeners();
        for (int i = 0; i < ls.length; i++) {

          ((ColumnViewerEditorActivationListener) ls[i])
              .beforeEditorDeactivated(tmp);
        }
      }

      this.cellEditor = null;
      this.activationEvent = null;
      Item t = (Item) this.cell.getItem();

      // don't null out table item -- same item is still selected
      if (t != null && !t.isDisposed()) {
        saveEditorValue(c);
      }

      setEditor(null, null, 0);
      c.removeListener(cellEditorListener);
      Control control = c.getControl();
      if (control != null) {
        if (mouseListener != null) {
          control.removeMouseListener(mouseListener);
          // Clear the instance not needed any more
          mouseListener = null;
        }
        if (focusListener != null) {
          control.removeFocusListener(focusListener);
        }

        if (tabeditingListener != null) {
          control.removeTraverseListener(tabeditingListener);
        }
      }
      c.deactivate();

      if (editorActivationListener != null
          && !editorActivationListener.isEmpty()) {
        Object[] ls = editorActivationListener.getListeners();
        for (int i = 0; i < ls.length; i++) {
          ((ColumnViewerEditorActivationListener) ls[i])
              .afterEditorDeactivated(tmp);
        }
      }

      this.cell = null;
    }
  }

  /**
   * Cancel editing
   */
  void cancelEditing() {
    if (cellEditor != null) {
      ColumnViewerEditorDeactivationEvent tmp = new ColumnViewerEditorDeactivationEvent(
          cell);
      if (editorActivationListener != null
          && !editorActivationListener.isEmpty()) {
        Object[] ls = editorActivationListener.getListeners();
        for (int i = 0; i < ls.length; i++) {

          ((ColumnViewerEditorActivationListener) ls[i])
              .beforeEditorDeactivated(tmp);
        }
      }

      setEditor(null, null, 0);
      cellEditor.removeListener(cellEditorListener);

      Control control = cellEditor.getControl();
      if (control != null) {
        if (mouseListener != null) {
          control.removeMouseListener(mouseListener);
          // Clear the instance not needed any more
          mouseListener = null;
        }
        if (focusListener != null) {
          control.removeFocusListener(focusListener);
        }

        if (tabeditingListener != null) {
          control.removeTraverseListener(tabeditingListener);
        }
      }

      CellEditor oldEditor = cellEditor;
      oldEditor.deactivate();

      if (editorActivationListener != null
          && !editorActivationListener.isEmpty()) {
        Object[] ls = editorActivationListener.getListeners();
        for (int i = 0; i < ls.length; i++) {
          ((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(event)) {
      if (cellEditor != null) {
        applyEditorValue();
      }

      this.cell = (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 != null && part.getEditingSupport() != null) {
      part.getEditingSupport().saveCellEditorValue(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.
   */
  boolean isCellEditorActive() {
    return cellEditor != null;
  }

  void handleDoubleClickEvent() {
    viewer.fireDoubleClick(new DoubleClickEvent(viewer, viewer
        .getSelection()));
    viewer.fireOpen(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 == null) {
      editorActivationListener = new ListenerList();
    }
    editorActivationListener.add(listener);
  }

  /**
   * Removes the given listener.
   *
   * @param listener
   *            the listener to remove
   */
  public void removeEditorActivationListener(
      ColumnViewerEditorActivationListener listener) {
    if (editorActivationListener != 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 == SWT.TRAVERSE_TAB_PREVIOUS) {
      event.doit = false;

      if ((event.stateMask & SWT.CTRL) == SWT.CTRL
          && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) {
        cell2edit = searchCellAboveBelow(row, viewer, columnIndex, true);
      } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) {
        cell2edit = searchPreviousCell(row, viewer, columnIndex,
            columnIndex);
      }
    } else if (event.detail == SWT.TRAVERSE_TAB_NEXT) {
      event.doit = false;

      if ((event.stateMask & SWT.CTRL) == SWT.CTRL
          && (feature & TABBING_VERTICAL) == TABBING_VERTICAL) {
        cell2edit = searchCellAboveBelow(row, viewer, columnIndex,
            false);
      } else if ((feature & TABBING_HORIZONTAL) == TABBING_HORIZONTAL) {
        cell2edit = searchNextCell(row, viewer, columnIndex,
            columnIndex);
      }
    }

    if (cell2edit != null) {

      viewer.getControl().setRedraw(false);
      ColumnViewerEditorActivationEvent acEvent = new ColumnViewerEditorActivationEvent(
          cell2edit, event);
      viewer.triggerEditorActivationEvent(acEvent);
      viewer.getControl().setRedraw(true);
    }
  }

  private ViewerCell searchCellAboveBelow(ViewerRow row, ColumnViewer viewer,
      int columnIndex, boolean above) {
    ViewerCell rv = null;

    ViewerRow newRow = null;

    if (above) {
      newRow = row.getNeighbor(ViewerRow.ABOVE, false);
    } else {
      newRow = row.getNeighbor(ViewerRow.BELOW, false);
    }

    if (newRow != null) {
      ViewerColumn column = viewer.getViewerColumn(columnIndex);
      if (column != null
          && column.getEditingSupport() != null
          && column.getEditingSupport().canEdit(
              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 != null
          && column.getEditingSupport() != null
          && column.getEditingSupport().canEdit(
              row.getItem().getData())) {
        rv = row.getCell(columnIndex - 1);
      } else {
        rv = searchPreviousCell(row, viewer, columnIndex - 1,
            startIndex);
      }
    } else {
      if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) {
        // Check that we don't get into endless loop
        if (columnIndex - 1 != 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) == TABBING_MOVE_TO_ROW_NEIGHBOR) {
        ViewerRow rowAbove = row.getNeighbor(ViewerRow.ABOVE, false);
        if (rowAbove != 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 != null
          && column.getEditingSupport() != null
          && column.getEditingSupport().canEdit(
              row.getItem().getData())) {
        rv = row.getCell(columnIndex + 1);
      } else {
        rv = searchNextCell(row, viewer, columnIndex + 1, startIndex);
      }
    } else {
      if ((feature & TABBING_CYCLE_IN_ROW) == TABBING_CYCLE_IN_ROW) {
        // Check that we don't get into endless loop
        if (columnIndex + 1 != 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) == TABBING_MOVE_TO_ROW_NEIGHBOR) {
        ViewerRow rowBelow = row.getNeighbor(ViewerRow.BELOW, false);
        if (rowBelow != 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;
  }
}
TOP

Related Classes of org.eclipse.jface.viewers.ColumnViewerEditor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.