com.netxforge.screens.editing.base.tables.SWTFocusBlockManager.java Source code

Java tutorial

Introduction

Here is the source code for com.netxforge.screens.editing.base.tables.SWTFocusBlockManager.java

Source

/*******************************************************************************
 * Copyright (c) 6 dec. 2012 NetXForge.
 * 
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details. You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>
 * 
 * Contributors: Christophe Bouhier - initial API and implementation and/or
 * initial documentation
 *******************************************************************************/
package com.netxforge.screens.editing.base.tables;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.core.runtime.Assert;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.viewers.ViewerRow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.ACC;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;

/**
 * This class is responsible to provide cell management base features for the
 * SWT-Controls {@link org.eclipse.swt.widgets.Table} and
 * {@link org.eclipse.swt.widgets.Tree}. </p>An adaption of
 * {@link SWTFocusCellManager}.</p> It supports drag-copying of cell content
 * from top to bottom. (Other dragging directions are not supported.</p>
 * 
 * </p> {@link #setFocusBlockActionHandler(IFocusBlockActionHandler)}.
 * 
 * While dragging an EMF Command command is created and updated with the
 * elements for the {@link ViewerCell}
 * 
 * @since 3.3
 * @author Christophe Bouhier
 */
abstract class SWTFocusBlockManager {

    private CellNavigationStrategyExposed navigationStrategy;

    private ColumnViewer viewer;

    // Consider putting this in the block.
    private ViewerCell focusCell;

    // The cells which are below the selection.
    private List<ViewerCell> focusBlock = new ArrayList<ViewerCell>();

    // Our focus block highlighter.
    private FocusBlockHighlighter cellHighlighter;

    // Our Action Handler
    private IFocusBlockActionHandler focusBlockActionHandler;

    private DisposeListener itemDeletionListener = new DisposeListener() {
        public void widgetDisposed(DisposeEvent e) {
            setFocusCell(null);
        }
    };

    /*
     * dragging state.
     */
    private boolean cellDragging;

    /**
     * @param viewer
     * @param focusDrawingDelegate
     * @param navigationDelegate
     */
    public SWTFocusBlockManager(ColumnViewer viewer, FocusBlockHighlighter focusDrawingDelegate,
            CellNavigationStrategyExposed navigationDelegate) {
        this.viewer = viewer;
        this.cellHighlighter = focusDrawingDelegate;
        if (this.cellHighlighter != null) {
            this.cellHighlighter.setMgr(this);
        }

        this.navigationStrategy = navigationDelegate;
        hookListener(viewer);
    }

    /**
     * This method is called by the framework to initialize this cell manager.
     */
    void init() {
        this.cellHighlighter.init();
        this.navigationStrategy.init();
    }

    /**
     * Handle mouse down event. The {@link #getFocusCell() focus cell} because
     * the {@link ViewerCell cell} at the {@link Event} coordinates. </p>The
     * state is set to 'dragging'.
     * 
     * @param event
     */
    private void handleMouseDown(Event event) {

        ViewerCell cell = viewer.getCell(new Point(event.x, event.y));

        if (cell != null) {
            if (!cell.equals(focusCell)) {
                setFocusCell(cell, event);
            }
        }
        cleanFocusBlock(focusCell, event);
        cellDragging = true;

        setCursorAccelerator(isAccelarating(event));
        // System.out
        // .println(" moving down, activate cell dragging, block size = "
        // + focusBlock.size());
    }

    private boolean isAccelarating(Event event) {
        return (event.stateMask & focusBlockActionHandler.getDragAccelerator()) != 0;
    }

    private void setCursorAccelerator(boolean accelerating) {

        @SuppressWarnings("unused")
        Cursor previousCursor = viewer.getControl().getCursor();

        if (accelerating) {
            viewer.getControl().setCursor(Display.getDefault().getSystemCursor(SWT.CURSOR_UPARROW));
        } else {
            viewer.getControl().setCursor(Display.getDefault().getSystemCursor(SWT.CURSOR_ARROW));
        }
    }

    /**
     * Handle mouse dragging event if the state is dragging.
     * 
     * @param event
     */
    private void handleMouseMove(Event event) {

        if (cellDragging) {
            //          System.out.println(" dragging mouse" + event.x + "," + event.y);
            handleCellDragging(event);
        } else {
            // we are not dragging, do nothing.
            // System.out.println(" moving mouse" + event.x + "," + event.y);
        }
    }

    /**
     * Handle mouse dragging.
     * 
     * @param event
     */
    private void handleCellDragging(Event event) {

        // in the new position, look if we are the focus cell,
        // if not, add to our cell blow only if we are the below neighbour...
        ViewerCell cell = viewer.getCell(new Point(event.x, event.y));

        if (cell != null) {

            if (!lastInFocusBlock(cell)) {
                // if we are not the last cell, but we are in the block, we
                // should get the position
                // to remove other cells..
                if (inFocusBlock(cell)) {
                    cleanFocusBlock(cell, event);
                    // System.out.println("Dragging....removing cell in column:"
                    // + cell.getVisualIndex() + " size of block = "
                    // + focusBlock.size());
                } else {

                    // we can add it now.
                    // do this for the last cell, not last focus cell.
                    ViewerCell belowNeighborCell = lastCellInBlock().getNeighbor(ViewerCell.BELOW, false);
                    if (cell.equals(belowNeighborCell)) {
                        addCellToBlock(cell, event);
                        // System.out.println("Dragging....Adding cell in column:"
                        // + cell.getVisualIndex() + " size of block = "
                        // + focusBlock.size());
                    }
                }
            } else {
                // last cell in the block do nothing...
            }
        }
    }

    /**
     * Remove the {@link ViewerCell cell} from the selection of cells in the
     * block when dragging upwards.
     * 
     * @param cell
     * @param event
     */
    private void cleanFocusBlock(ViewerCell cell, Event event) {

        if (focusBlock.isEmpty()) {
            // do nothing, we always have the focus cell.
        } else {
            // remember the old block for the highlighter to repaint.
            ViewerCell[] oldBlock = block();
            // When we are the focus cell, we should clean the block.
            if (focusCell.equals(cell)) {
                // System.out.println("Dragging....Clearing cells:"
                // + cell.getVisualIndex());
                focusBlock.clear();
                cellHighlighter.focusBlockChanged(block(), oldBlock);
                focusBlockActionHandler.updateCommand(focusCell, getTargets(), event);

            } else if (focusBlock.contains(cell)) {
                int indexOf = focusBlock.indexOf(cell);
                Collection<ViewerCell> retain = new ArrayList<ViewerCell>();
                // Note pre-increment, to get the first item from the list index
                // 0.
                for (int i = -1; i < indexOf; i++) {
                    retain.add(focusBlock.get(i + 1));
                }
                focusBlock.retainAll(retain);
                // System.out.println("Dragging....Clearing cells:"
                // + cell.getVisualIndex());
                cellHighlighter.focusBlockChanged(block(), oldBlock);
                focusBlockActionHandler.updateCommand(focusCell, getTargets(), event);
            }
        }
    }

    /**
     * get all the targets for the focus block.
     */
    private Collection<EObject> getTargets() {

        // Do a transformation.
        Collection<EObject> targets = new ArrayList<EObject>();
        for (ViewerCell cell : focusBlock) {
            Object element = cell.getElement();
            if (element instanceof EObject) {
                targets.add((EObject) element);
            }
        }
        return targets;
    }

    private ViewerCell[] block() {
        ViewerCell[] block = null;
        block = new ViewerCell[focusBlock.size() + 1];
        focusBlock.toArray(block);
        block[focusBlock.size()] = focusCell;

        return block;
    }

    /**
     * Are we the last cell in the focus block.
     * 
     * @param cell
     * @return
     */
    private boolean lastInFocusBlock(ViewerCell cell) {
        // return the focus cell equality or the the last cell in the focus
        // block equality.
        return lastCellInBlock().equals(cell);
    }

    private boolean inFocusBlock(ViewerCell cell) {
        return focusCell.equals(cell) || focusBlock.contains(cell);
    }

    private ViewerCell lastCellInBlock() {
        if (focusBlock.isEmpty()) {
            return focusCell;
        } else {
            return focusBlock.get(focusBlock.size() == 1 ? 0 : focusBlock.size() - 1);
        }
    }

    private void addCellToBlock(ViewerCell cell, Event event) {

        if (!focusBlock.contains(cell)) {

            ViewerCell[] oldBlock = block();
            focusBlock.add(cell);
            ViewerCell[] newBlock = block();
            cellHighlighter.focusBlockChanged(newBlock, oldBlock);
            focusBlockActionHandler.updateCommand(focusCell, getTargets(), event);
        }
    }

    private void handleMouseUp(Event event) {

        // System.out.println(" mouse up, disable dragging");
        if (cellDragging) {
            focusBlockActionHandler.executeCommand();
            // System.out.println("SWTFocusBlockManager: Executing copy command");
        }
        this.cellDragging = false;
        setCursorAccelerator(isAccelarating(event));
    }

    private void handleKeyDown(Event event) {
        ViewerCell tmp = null;

        if (navigationStrategy.isCollapseEvent(viewer, focusCell, event)) {
            navigationStrategy.collapse(viewer, focusCell, event);
        } else if (navigationStrategy.isExpandEvent(viewer, focusCell, event)) {
            navigationStrategy.expand(viewer, focusCell, event);
        } else if (navigationStrategy.isNavigationEvent(viewer, event)) {
            tmp = navigationStrategy.findSelectedCell(viewer, focusCell, event);

            if (tmp != null) {
                if (!tmp.equals(focusCell)) {
                    setFocusCell(tmp, event);
                }
            }
        }

        if (navigationStrategy.shouldCancelEvent(viewer, event)) {
            event.doit = false;
        }
    }

    /**
     * And selection movements for a {@link ViewerCell}
     * 
     * @param event
     */
    private void handleSelection(Event event) {
        // ignore while dragging.
        if (cellDragging) {
            return;
        }

        if ((event.detail & SWT.CHECK) == 0 && focusCell != null && focusCell.getItem() != event.item
                && event.item != null && !event.item.isDisposed()) {
            if (viewer instanceof OpenTreeViewer) {
                OpenTreeViewer atrViewer = (OpenTreeViewer) viewer;
                ViewerRow row = atrViewer.getViewerRowFromItemExposed(event.item);
                Assert.isNotNull(row, "Internal Structure invalid. Row item has no row ViewerRow assigned"); //$NON-NLS-1$

                // CB TODO, update to sync our focus block.
                ViewerCell tmp = row.getCell(focusCell.getColumnIndex());
                if (!focusCell.equals(tmp)) {
                    setFocusCell(tmp, event);
                }
            }
        }
    }

    /**
     * Handles the {@link SWT#FocusIn} event.
     * 
     * @param event
     *            the event
     */
    private void handleFocusIn(Event event) {
        if (focusCell == null) {
            setFocusCell(getInitialFocusCell(), event);
        }
    }

    abstract ViewerCell getInitialFocusCell();

    /**
     * Hook ourself to a events on the {@link ColumnViewer}.
     * 
     * @param viewer
     */
    private void hookListener(final ColumnViewer viewer) {
        Listener listener = new Listener() {

            public void handleEvent(Event event) {
                switch (event.type) {
                case SWT.MouseDown:
                    handleMouseDown(event);
                    break;
                case SWT.MouseMove:
                    handleMouseMove(event);
                    break;
                case SWT.MouseUp:
                    handleMouseUp(event);
                    break;
                case SWT.KeyDown:
                    handleKeyDown(event);
                    break;
                case SWT.Selection:
                    handleSelection(event);
                    break;
                case SWT.FocusIn:
                    handleFocusIn(event);
                    break;
                }
            }

        };

        viewer.getControl().addListener(SWT.MouseDown, listener);
        viewer.getControl().addListener(SWT.MouseUp, listener);
        viewer.getControl().addListener(SWT.MouseMove, listener);
        viewer.getControl().addListener(SWT.KeyDown, listener);
        viewer.getControl().addListener(SWT.Selection, listener);

        // When disposing a selection, we reset the focus cell.
        viewer.addSelectionChangedListener(new ISelectionChangedListener() {

            public void selectionChanged(SelectionChangedEvent event) {
                if (event.getSelection().isEmpty()) {
                    setFocusCell(null);
                }
            }

        });
        viewer.getControl().addListener(SWT.FocusIn, listener);

        // Disable accessibility as we do not have access to the viewer column.
        // viewer.getControl().getAccessible()
        // .addAccessibleListener(new AccessibleAdapter() {
        // public void getName(AccessibleEvent event) {
        // ViewerCell cell = getFocusCell();
        // if (cell == null)
        // return;
        //
        // ViewerRow row = cell.getViewerRow();
        // if (row == null)
        // return;
        //
        // ViewerColumn viewPart = viewer.getViewerColumn(cell
        // .getColumnIndex());
        //
        // if (viewPart == null)
        // return;
        //
        // CellLabelProvider labelProvider = viewPart
        // .getLabelProvider();
        //
        // if (labelProvider == null)
        // return;
        // labelProvider.update(cell);
        // event.result = cell.getText();
        // }
        // });

    }

    /**
     * @return the cell with the focus
     * 
     */
    public ViewerCell getFocusCell() {
        return focusCell;
    }

    final ViewerCell _getFocusCell() {
        return focusCell;
    }

    // Get the focus block, excluding the focus cell itself.
    final ViewerCell[] _getFocusBlock() {
        ViewerCell[] focusBlockArray = new ViewerCell[focusBlock.size()];
        return focusBlock.toArray(focusBlockArray);
    }

    protected void setFocusCell(ViewerCell newFocusCell) {
        setFocusCell(newFocusCell, null);
    }

    void setFocusCell(ViewerCell focusCell, Event event) {
        ViewerCell oldCell = this.focusCell;

        if (this.focusCell != null && !this.focusCell.getItem().isDisposed()) {
            this.focusCell.getItem().removeDisposeListener(itemDeletionListener);
        }

        this.focusCell = focusCell;

        if (this.focusCell != null && !this.focusCell.getItem().isDisposed()) {
            this.focusCell.getItem().addDisposeListener(itemDeletionListener);
        }

        if (focusCell != null) {
            focusCell.scrollIntoView();
        }
        this.cellHighlighter.focusCellChanged(focusCell, oldCell);
        focusBlockActionHandler.updateCommand(focusCell, getTargets(), event);
        getViewer().getControl().getAccessible().setFocus(ACC.CHILDID_SELF);
    }

    ColumnViewer getViewer() {
        return viewer;
    }

    public IFocusBlockActionHandler getFocusBlockActionHandler() {
        return focusBlockActionHandler;
    }

    public void setFocusBlockActionHandler(IFocusBlockActionHandler focusBlockActionHandler) {
        this.focusBlockActionHandler = focusBlockActionHandler;
    }
}