/******************************************************************************* * Copyright (c) 2013, 2017 Dirk Fauth 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: * Dirk Fauth <dirk.fauth@googlemail.com> - initial API and implementation *******************************************************************************/ package org.eclipse.nebula.widgets.nattable.reorder.action; import org.eclipse.nebula.widgets.nattable.NatTable; import org.eclipse.nebula.widgets.nattable.layer.ILayer; import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; import org.eclipse.nebula.widgets.nattable.painter.IOverlayPainter; import org.eclipse.nebula.widgets.nattable.reorder.command.RowReorderEndCommand; import org.eclipse.nebula.widgets.nattable.reorder.command.RowReorderStartCommand; import org.eclipse.nebula.widgets.nattable.selection.command.ClearAllSelectionsCommand; import org.eclipse.nebula.widgets.nattable.ui.action.IDragMode; import org.eclipse.nebula.widgets.nattable.ui.util.CellEdgeDetectUtil; import org.eclipse.nebula.widgets.nattable.ui.util.CellEdgeEnum; import org.eclipse.nebula.widgets.nattable.util.GUIHelper; import org.eclipse.nebula.widgets.nattable.viewport.action.AutoScrollDragMode; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; /** * Default {@link IDragMode} invoked for 'left click + drag' on the row header. * It does the following when invoked: * <ol> * <li>Fires a row reorder command, to move columns</li> * <li>Overlays a black line indicating the new row position</li> * </ol> */ public class RowReorderDragMode extends AutoScrollDragMode { protected NatTable natTable; protected MouseEvent initialEvent; protected MouseEvent currentEvent; protected int dragFromGridRowPosition; protected RowReorderOverlayPainter targetOverlayPainter = new RowReorderOverlayPainter(); public RowReorderDragMode() { super(false, true); } @Override public void mouseDown(NatTable natTable, MouseEvent event) { this.natTable = natTable; this.initialEvent = event; this.currentEvent = this.initialEvent; this.dragFromGridRowPosition = getDragFromGridRowPosition(); natTable.addOverlayPainter(this.targetOverlayPainter); natTable.doCommand(new ClearAllSelectionsCommand()); fireMoveStartCommand(natTable, this.dragFromGridRowPosition); } @Override public void mouseMove(NatTable natTable, MouseEvent event) { super.mouseMove(natTable, event); this.currentEvent = event; natTable.redraw(); } @Override public void mouseUp(NatTable natTable, MouseEvent event) { // Cancel any active viewport drag super.mouseUp(natTable, event); natTable.removeOverlayPainter(this.targetOverlayPainter); int dragToGridRowPosition = getDragToGridRowPosition( getMoveDirection(event.y), natTable.getRowPositionByY(event.y)); if (!isValidTargetRowPosition(natTable, this.dragFromGridRowPosition, dragToGridRowPosition)) { dragToGridRowPosition = -1; } fireMoveEndCommand(natTable, dragToGridRowPosition); natTable.redraw(); } /** * @return The row position of the row that is dragged */ protected int getDragFromGridRowPosition() { return this.natTable.getRowPositionByY(this.initialEvent.y); } /** * @param moveDirection * The direction to indicate whether the drop was before or after * the given row position * @param gridRowPosition * The row position at which the drop was performed * @return The row position where the dragged row should be dropped */ protected int getDragToGridRowPosition(CellEdgeEnum moveDirection, int gridRowPosition) { int dragToGridRowPosition = -1; if (moveDirection != null) { switch (moveDirection) { case TOP: dragToGridRowPosition = gridRowPosition; break; case BOTTOM: dragToGridRowPosition = gridRowPosition + 1; break; } } return dragToGridRowPosition; } /** * @param y * The y coordinate of the drop location * @return The direction whether the drop should be performed before the the * cell at drop position or after */ protected CellEdgeEnum getMoveDirection(int y) { ILayerCell cell = getRowCell(y); if (cell != null) { Rectangle selectedRowHeaderRect = cell.getBounds(); return CellEdgeDetectUtil.getVerticalCellEdge(selectedRowHeaderRect, new Point(this.initialEvent.x, y)); } return null; } /** * @param y * The y coordinate of the drop location * @return The {@link ILayerCell} at the drop location */ private ILayerCell getRowCell(int y) { int gridColumnPosition = this.natTable.getColumnPositionByX(this.initialEvent.x); int gridRowPosition = this.natTable.getRowPositionByY(y); return this.natTable.getCellByPosition(gridColumnPosition, gridRowPosition); } /** * * @param natLayer * The layer the positions are related to * @param dragFromGridRowPosition * The row position of the row that is dragged * @param dragToGridRowPosition * The row position where the row is dropped * @return <code>true</code> if the drop position is valid, * <code>false</code> if not */ protected boolean isValidTargetRowPosition(ILayer natLayer, int dragFromGridRowPosition, int dragToGridRowPosition) { return dragFromGridRowPosition >= 0 && dragToGridRowPosition >= 0; } /** * Executes the command to indicate row reorder starting. * * @param natTable * The NatTable instance on which the command should be executed * @param dragFromGridRowPosition * The row position of the row that is dragged */ protected void fireMoveStartCommand(NatTable natTable, int dragFromGridRowPosition) { natTable.doCommand(new RowReorderStartCommand(natTable, dragFromGridRowPosition)); } /** * Executes the command to indicate row reorder ending. * * @param natTable * The NatTable instance on which the command should be executed * @param dragToGridRowPosition * The position of the row to which the dragged row should be * dropped */ protected void fireMoveEndCommand(NatTable natTable, int dragToGridRowPosition) { natTable.doCommand(new RowReorderEndCommand(natTable, dragToGridRowPosition)); } /** * The overlay painter for showing the drag operation. */ private class RowReorderOverlayPainter implements IOverlayPainter { @Override public void paintOverlay(GC gc, ILayer layer) { int dragFromGridRowPosition = getDragFromGridRowPosition(); if (RowReorderDragMode.this.currentEvent.y > RowReorderDragMode.this.natTable.getHeight()) { return; } CellEdgeEnum moveDirection = getMoveDirection(RowReorderDragMode.this.currentEvent.y); int dragToGridRowPosition = getDragToGridRowPosition( moveDirection, RowReorderDragMode.this.natTable.getRowPositionByY(RowReorderDragMode.this.currentEvent.y)); if (isValidTargetRowPosition( RowReorderDragMode.this.natTable, dragFromGridRowPosition, dragToGridRowPosition)) { int dragToRowHandleY = -1; if (moveDirection != null) { Rectangle selectedRowHeaderRect = getRowCell(RowReorderDragMode.this.currentEvent.y).getBounds(); switch (moveDirection) { case TOP: dragToRowHandleY = selectedRowHeaderRect.y; break; case BOTTOM: dragToRowHandleY = selectedRowHeaderRect.y + selectedRowHeaderRect.height; break; } } if (dragToRowHandleY > 0) { Color orgBgColor = gc.getBackground(); gc.setBackground(GUIHelper.COLOR_DARK_GRAY); gc.fillRectangle(0, dragToRowHandleY - 1, layer.getWidth(), 2); gc.setBackground(orgBgColor); } } } } }