TableTreeViewer.java :  » IDE-Eclipse » jface » org » eclipse » jface » viewers » Java Open Source

Java Open Source » IDE Eclipse » jface 
jface » org » eclipse » jface » viewers » TableTreeViewer.java
/*******************************************************************************
 * Copyright (c) 2000, 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> - bug 153993
 *******************************************************************************/

package org.eclipse.jface.viewers;

import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableTree;
import org.eclipse.swt.custom.TableTreeEditor;
import org.eclipse.swt.custom.TableTreeItem;
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.TreeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Widget;

/**
 * A concrete viewer based on a SWT <code>TableTree</code> control.
 * <p>
 * This class is not intended to be subclassed outside the viewer framework. It
 * is designed to be instantiated with a pre-existing SWT table tree control and
 * configured with a domain-specific content provider, label provider, element
 * filter (optional), and element sorter (optional).
 * </p>
 * <p>
 * Content providers for table tree viewers must implement the
 * <code>ITreeContentProvider</code> interface.
 * </p>
 * <p>
 * Label providers for table tree viewers must implement either the
 * <code>ITableLabelProvider</code> or the <code>ILabelProvider</code>
 * interface (see <code>TableTreeViewer.setLabelProvider</code> for more
 * details).
 * </p>
 * 
 * @deprecated As of 3.1 use {@link TreeViewer} instead
 * @noextend This class is not intended to be subclassed by clients.
 */
public class TableTreeViewer extends AbstractTreeViewer {
  /**
   * Internal table viewer implementation.
   */
  private TableTreeEditorImpl tableEditorImpl;

  /**
   * This viewer's table tree control.
   */
  private TableTree tableTree;

  /**
   * This viewer's table tree editor.
   */
  private TableTreeEditor tableTreeEditor;

  /**
   * Copied from original TableEditorImpl and moved here since refactoring
   * completely wiped out the original implementation in 3.3
   * 
   * @since 3.1
   */
  class TableTreeEditorImpl {

    private CellEditor cellEditor;

    private CellEditor[] cellEditors;

    private ICellModifier cellModifier;

    private String[] columnProperties;

    private Item tableItem;

    private int columnNumber;

    private ICellEditorListener cellEditorListener;

    private FocusListener focusListener;

    private MouseListener mouseListener;

    private int doubleClickExpirationTime;

    private ColumnViewer viewer;

    private TableTreeEditorImpl(ColumnViewer viewer) {
      this.viewer = viewer;
      initCellEditorListener();
    }

    /**
     * Returns this <code>TableViewerImpl</code> viewer
     * 
     * @return the viewer
     */
    public ColumnViewer getViewer() {
      return viewer;
    }

    private void activateCellEditor() {
      if( cellEditors != null ) {
        if( cellEditors[columnNumber] != null && cellModifier != null ) {
          Object element = tableItem.getData();
          String property = columnProperties[columnNumber];
          
          if( cellModifier.canModify(element, property) ) {
            cellEditor = cellEditors[columnNumber];
            
            cellEditor.addListener(cellEditorListener);
            
            Object value = cellModifier.getValue(element, property);
            cellEditor.setValue(value);
            // 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();
            if (control == null) {
              return;
            }
            setLayoutData(cellEditor.getLayoutData());
            setEditor(control, tableItem, columnNumber);
            cellEditor.setFocus();
            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 <= doubleClickExpirationTime) {
                  control.removeMouseListener(mouseListener);
                  cancelEditing();
                  handleDoubleClickEvent();
                } else if (mouseListener != null) {
                  control.removeMouseListener(mouseListener);
                }
              }
            };
            control.addMouseListener(mouseListener);
          }
        }
      }
    }

    /**
     * Activate a cell editor for the given mouse position.
     */
    private void activateCellEditor(MouseEvent event) {
      if (tableItem == null || tableItem.isDisposed()) {
        // item no longer exists
        return;
      }
      int columnToEdit;
      int columns = getColumnCount();
      if (columns == 0) {
        // If no TableColumn, Table acts as if it has a single column
        // which takes the whole width.
        columnToEdit = 0;
      } else {
        columnToEdit = -1;
        for (int i = 0; i < columns; i++) {
          Rectangle bounds = getBounds(tableItem, i);
          if (bounds.contains(event.x, event.y)) {
            columnToEdit = i;
            break;
          }
        }
        if (columnToEdit == -1) {
          return;
        }
      }

      columnNumber = columnToEdit;
      activateCellEditor();
    }

    /**
     * Deactivates the currently active cell editor.
     */
    public void applyEditorValue() {
      CellEditor c = this.cellEditor;
      if (c != 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 ?
        this.cellEditor = null;
        Item t = this.tableItem;
        // don't null out table item -- same item is still selected
        if (t != null && !t.isDisposed()) {
          saveEditorValue(c, t);
        }
        setEditor(null, null, 0);
        c.removeListener(cellEditorListener);
        Control control = c.getControl();
        if (control != null) {
          if (mouseListener != null) {
            control.removeMouseListener(mouseListener);
          }
          if (focusListener != null) {
            control.removeFocusListener(focusListener);
          }
        }
        c.deactivate();
      }
    }

    /**
     * Cancels the active cell editor, without saving the value back to the
     * domain model.
     */
    public void cancelEditing() {
      if (cellEditor != null) {
        setEditor(null, null, 0);
        cellEditor.removeListener(cellEditorListener);
        CellEditor oldEditor = cellEditor;
        cellEditor = null;
        oldEditor.deactivate();
      }
    }

    /**
     * Start editing the given element.
     * 
     * @param element
     * @param column
     */
    public void editElement(Object element, int column) {
      if (cellEditor != null) {
        applyEditorValue();
      }

      setSelection(new StructuredSelection(element), true);
      Item[] selection = getSelection();
      if (selection.length != 1) {
        return;
      }

      tableItem = selection[0];

      // Make sure selection is visible
      showSelection();
      columnNumber = column;
      activateCellEditor();

    }

    /**
     * Return the array of CellEditors used in the viewer
     * 
     * @return the cell editors
     */
    public CellEditor[] getCellEditors() {
      return cellEditors;
    }

    /**
     * Get the cell modifier
     * 
     * @return the cell modifier
     */
    public ICellModifier getCellModifier() {
      return cellModifier;
    }

    /**
     * Return the properties for the column
     * 
     * @return the array of column properties
     */
    public Object[] getColumnProperties() {
      return columnProperties;
    }

    /**
     * Handles the mouse down event; activates the cell editor.
     * 
     * @param event
     *            the mouse event that should be handled
     */
    public void handleMouseDown(MouseEvent event) {
      if (event.button != 1) {
        return;
      }

      if (cellEditor != null) {
        applyEditorValue();
      }

      // activate the cell editor immediately. If a second mouseDown
      // is received prior to the expiration of the doubleClick time then
      // the cell editor will be deactivated and a doubleClick event will
      // be processed.
      //
      doubleClickExpirationTime = event.time
          + Display.getCurrent().getDoubleClickTime();

      Item[] items = getSelection();
      // Do not edit if more than one row is selected.
      if (items.length != 1) {
        tableItem = null;
        return;
      }
      tableItem = items[0];
      
      activateCellEditor(event);
    }

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

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

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

    /**
     * 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.
     */
    public boolean isCellEditorActive() {
      return cellEditor != null;
    }

    /**
     * Saves the value of the currently active cell editor, by delegating to
     * the cell modifier.
     */
    private void saveEditorValue(CellEditor cellEditor, Item tableItem) {
      if( cellModifier != null ) {
        if( ! cellEditor.isValueValid() ) {
          // Do what????
        }
      }
      String property = null;
      
      if( columnProperties != null && columnNumber < columnProperties.length ) {
        property = columnProperties[columnNumber];
      }
      cellModifier.modify(tableItem, property, cellEditor.getValue());
    }

    /**
     * Set the cell editors
     * 
     * @param editors
     */
    public void setCellEditors(CellEditor[] editors) {
      this.cellEditors = editors;
    }

    /**
     * Set the cell modifier
     * 
     * @param modifier
     */
    public void setCellModifier(ICellModifier modifier) {
      this.cellModifier = modifier;
    }

    /**
     * Set the column properties
     * 
     * @param columnProperties
     */
    public void setColumnProperties(String[] columnProperties) {
      this.columnProperties = columnProperties;
    }

    Rectangle getBounds(Item item, int columnNumber) {
      return ((TableTreeItem) item).getBounds(columnNumber);
    }

    int getColumnCount() {
      // getColumnCount() should be a API in TableTree.
      return getTableTree().getTable().getColumnCount();
    }

    Item[] getSelection() {
      return getTableTree().getSelection();
    }

    void setEditor(Control w, Item item, int columnNumber) {
      tableTreeEditor.setEditor(w, (TableTreeItem) item, columnNumber);
    }

    void setSelection(StructuredSelection selection, boolean b) {
      TableTreeViewer.this.setSelection(selection, b);
    }

    void showSelection() {
      getTableTree().showSelection();
    }

    void setLayoutData(CellEditor.LayoutData layoutData) {
      tableTreeEditor.horizontalAlignment = layoutData.horizontalAlignment;
      tableTreeEditor.grabHorizontal = layoutData.grabHorizontal;
      tableTreeEditor.minimumWidth = layoutData.minimumWidth;
    }

    void handleDoubleClickEvent() {
      Viewer viewer = getViewer();
      fireDoubleClick(new DoubleClickEvent(viewer, viewer.getSelection()));
      fireOpen(new OpenEvent(viewer, viewer.getSelection()));
    }
  }

  /**
   * Creates a table tree viewer on the given table tree control. The viewer
   * has no input, no content provider, a default label provider, no sorter,
   * and no filters.
   * 
   * @param tree
   *            the table tree control
   */
  public TableTreeViewer(TableTree tree) {
    super();
    tableTree = tree;
    hookControl(tree);
    tableTreeEditor = new TableTreeEditor(tableTree);
    tableEditorImpl = new TableTreeEditorImpl(this);
  }

  /**
   * Creates a table tree viewer on a newly-created table tree control under
   * the given parent. The table tree control is created using the SWT style
   * bits <code>MULTI, H_SCROLL, V_SCROLL, and BORDER</code>. The viewer
   * has no input, no content provider, a default label provider, no sorter,
   * and no filters.
   * 
   * @param parent
   *            the parent control
   */
  public TableTreeViewer(Composite parent) {
    this(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
  }

  /**
   * Creates a table tree viewer on a newly-created table tree control under
   * the given parent. The table tree control is created using the given SWT
   * style bits. The viewer has no input, no content provider, a default label
   * provider, no sorter, and no filters.
   * 
   * @param parent
   *            the parent control
   * @param style
   *            the SWT style bits
   */
  public TableTreeViewer(Composite parent, int style) {
    this(new TableTree(parent, style));
  }

  /*
   * (non-Javadoc) Method declared on AbstractTreeViewer.
   */
  protected void addTreeListener(Control c, TreeListener listener) {
    ((TableTree) c).addTreeListener(listener);
  }

  /**
   * Cancels a currently active cell editor. All changes already done in the
   * cell editor are lost.
   */
  public void cancelEditing() {
    tableEditorImpl.cancelEditing();
  }

  /*
   * (non-Javadoc) Method declared on AbstractTreeViewer.
   */
  protected void doUpdateItem(Item item, Object element) {
    // update icon and label
    // Similar code in TableTreeViewer.doUpdateItem()
    IBaseLabelProvider prov = getLabelProvider();
    ITableLabelProvider tprov = null;

    if (prov instanceof ITableLabelProvider) {
      tprov = (ITableLabelProvider) prov;
    }

    int columnCount = tableTree.getTable().getColumnCount();
    TableTreeItem ti = (TableTreeItem) item;
    // Also enter loop if no columns added. See 1G9WWGZ: JFUIF:WINNT -
    // TableViewer with 0 columns does not work
    for (int column = 0; column < columnCount || column == 0; column++) {
      String text = "";//$NON-NLS-1$
      Image image = null;
      if (tprov != null) {
        text = tprov.getColumnText(element, column);
        image = tprov.getColumnImage(element, column);
      } else {
        if (column == 0) {
          ViewerLabel updateLabel = new ViewerLabel(item.getText(),
              item.getImage());
          buildLabel(updateLabel, element);

          // As it is possible for user code to run the event
          // loop check here.
          if (item.isDisposed()) {
            unmapElement(element, item);
            return;
          }

          text = updateLabel.getText();
          image = updateLabel.getImage();
        }
      }

      // Avoid setting text to null
      if (text == null) {
        text = ""; //$NON-NLS-1$
      }

      ti.setText(column, text);
      // Apparently a problem to setImage to null if already null
      if (ti.getImage(column) != image) {
        ti.setImage(column, image);
      }

      getColorAndFontCollector().setFontsAndColors(element);
      getColorAndFontCollector().applyFontsAndColors(ti);
    }

  }

  /**
   * Starts editing the given element.
   * 
   * @param element
   *            the element
   * @param column
   *            the column number
   */
  public void editElement(Object element, int column) {
    tableEditorImpl.editElement(element, column);
  }

  /**
   * Returns the cell editors of this viewer.
   * 
   * @return the list of cell editors
   */
  public CellEditor[] getCellEditors() {
    return tableEditorImpl.getCellEditors();
  }

  /**
   * Returns the cell modifier of this viewer.
   * 
   * @return the cell modifier
   */
  public ICellModifier getCellModifier() {
    return tableEditorImpl.getCellModifier();
  }

  /*
   * (non-Javadoc) Method declared on AbstractTreeViewer.
   */
  protected Item[] getChildren(Widget o) {
    if (o instanceof TableTreeItem) {
      return ((TableTreeItem) o).getItems();
    }
    if (o instanceof TableTree) {
      return ((TableTree) o).getItems();
    }
    return null;
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.eclipse.jface.viewers.AbstractTreeViewer#getChild(org.eclipse.swt.widgets.Widget,
   *      int)
   */
  protected Item getChild(Widget widget, int index) {
    if (widget instanceof TableTreeItem) {
      return ((TableTreeItem) widget).getItem(index);
    }
    if (widget instanceof TableTree) {
      return ((TableTree) widget).getItem(index);
    }
    return null;
  }

  /**
   * Returns the column properties of this viewer. The properties must
   * correspond with the columns of the table control. They are used to
   * identify the column in a cell modifier.
   * 
   * @return the list of column properties
   */
  public Object[] getColumnProperties() {
    return tableEditorImpl.getColumnProperties();
  }

  /*
   * (non-Javadoc) Method declared on Viewer.
   */
  public Control getControl() {
    return tableTree;
  }

  /**
   * Returns the element with the given index from this viewer. Returns
   * <code>null</code> if the index is out of range.
   * <p>
   * This method is internal to the framework.
   * </p>
   * 
   * @param index
   *            the zero-based index
   * @return the element at the given index, or <code>null</code> if the
   *         index is out of range
   */
  public Object getElementAt(int index) {
    // XXX: Workaround for 1GBCSB1: SWT:WIN2000 - TableTree should have
    // getItem(int index)
    TableTreeItem i = tableTree.getItems()[index];
    if (i != null) {
      return i.getData();
    }
    return null;
  }

  /*
   * (non-Javadoc) Method declared on AbstractTreeViewer.
   */
  protected boolean getExpanded(Item item) {
    return ((TableTreeItem) item).getExpanded();
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.eclipse.jface.viewers.ColumnViewer#getItemAt(org.eclipse.swt.graphics.Point)
   */
  protected Item getItemAt(Point p) {
    return getTableTree().getTable().getItem(p);
  }

  /*
   * (non-Javadoc) Method declared on AbstractTreeViewer.
   */
  protected int getItemCount(Control widget) {
    return ((TableTree) widget).getItemCount();
  }

  /*
   * (non-Javadoc) Method declared on AbstractTreeViewer.
   */
  protected int getItemCount(Item item) {
    return ((TableTreeItem) item).getItemCount();
  }

  /*
   * (non-Javadoc) Method declared on AbstractTreeViewer.
   */
  protected org.eclipse.swt.widgets.Item[] getItems(
      org.eclipse.swt.widgets.Item item) {
    return ((TableTreeItem) item).getItems();
  }

  /**
   * The table tree viewer implementation of this <code>Viewer</code>
   * framework method returns the label provider, which in the case of table
   * tree viewers will be an instance of either
   * <code>ITableLabelProvider</code> or <code>ILabelProvider</code>. If
   * it is an <code>ITableLabelProvider</code>, then it provides a separate
   * label text and image for each column. If it is an
   * <code>ILabelProvider</code>, then it provides only the label text and
   * image for the first column, and any remaining columns are blank.
   */
  public IBaseLabelProvider getLabelProvider() {
    return super.getLabelProvider();
  }

  /*
   * (non-Javadoc) Method declared on AbstractTreeViewer.
   */
  protected Item getParentItem(Item item) {
    return ((TableTreeItem) item).getParentItem();
  }

  /*
   * (non-Javadoc) Method declared on AbstractTreeViewer.
   */
  protected Item[] getSelection(Control widget) {
    return ((TableTree) widget).getSelection();
  }

  /**
   * Returns this table tree viewer's table tree control.
   * 
   * @return the table tree control
   */
  public TableTree getTableTree() {
    return tableTree;
  }

  /*
   * (non-Javadoc) Method declared on AbstractTreeViewer.
   */
  protected void hookControl(Control control) {
    super.hookControl(control);
    tableTree.getTable().addMouseListener(new MouseAdapter() {
      public void mouseDown(MouseEvent e) {
        /*
         * If user clicked on the [+] or [-], do not activate
         * CellEditor.
         */
        // XXX: This code should not be here. SWT should either have
        // support to see
        // if the user clicked on the [+]/[-] or manage the table editor
        // activation
        org.eclipse.swt.widgets.TableItem[] items = tableTree
            .getTable().getItems();
        for (int i = 0; i < items.length; i++) {
          Rectangle rect = items[i].getImageBounds(0);
          if (rect.contains(e.x, e.y)) {
            return;
          }
        }

        tableEditorImpl.handleMouseDown(e);
      }
    });
  }

  /**
   * Returns whether there is an active cell editor.
   * 
   * @return <code>true</code> if there is an active cell editor, and
   *         <code>false</code> otherwise
   */
  public boolean isCellEditorActive() {
    return tableEditorImpl.isCellEditorActive();
  }

  /*
   * (non-Javadoc) Method declared in AbstractTreeViewer.
   */
  protected Item newItem(Widget parent, int flags, int ix) {
    TableTreeItem item;
    if (ix >= 0) {
      if (parent instanceof TableTreeItem) {
        item = new TableTreeItem((TableTreeItem) parent, flags, ix);
      } else {
        item = new TableTreeItem((TableTree) parent, flags, ix);
      }
    } else {
      if (parent instanceof TableTreeItem) {
        item = new TableTreeItem((TableTreeItem) parent, flags);
      } else {
        item = new TableTreeItem((TableTree) parent, flags);
      }
    }
    return item;
  }

  /*
   * (non-Javadoc) Method declared in AbstractTreeViewer.
   */
  protected void removeAll(Control widget) {
    ((TableTree) widget).removeAll();
  }

  /**
   * Sets the cell editors of this table viewer.
   * 
   * @param editors
   *            the list of cell editors
   */
  public void setCellEditors(CellEditor[] editors) {
    tableEditorImpl.setCellEditors(editors);
  }

  /**
   * Sets the cell modifier of this table viewer.
   * 
   * @param modifier
   *            the cell modifier
   */
  public void setCellModifier(ICellModifier modifier) {
    tableEditorImpl.setCellModifier(modifier);
  }

  /**
   * Sets the column properties of this table viewer. The properties must
   * correspond with the columns of the table control. They are used to
   * identify the column in a cell modifier.
   * 
   * @param columnProperties
   *            the list of column properties
   */
  public void setColumnProperties(String[] columnProperties) {
    tableEditorImpl.setColumnProperties(columnProperties);
  }

  /*
   * (non-Javadoc) Method declared in AbstractTreeViewer.
   */
  protected void setExpanded(Item node, boolean expand) {
    ((TableTreeItem) node).setExpanded(expand);
  }

  /*
   * (non-Javadoc) Method declared in AbstractTreeViewer.
   */
  protected void setSelection(List items) {
    TableTreeItem[] newItems = new TableTreeItem[items.size()];
    items.toArray(newItems);
    getTableTree().setSelection(newItems);
  }

  /*
   * (non-Javadoc) Method declared in AbstractTreeViewer.
   */
  protected void showItem(Item item) {
    getTableTree().showItem((TableTreeItem) item);
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.