Skip to content

Commit

Permalink
Impl #125 - [Drag] Add support for key interactions in drag mode
Browse files Browse the repository at this point in the history
Signed-off-by: Dirk Fauth <[email protected]>
  • Loading branch information
fipro78 committed Oct 11, 2024
1 parent 243f00c commit b944310
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012, 2020 Original authors and others.
* Copyright (c) 2012, 2024 Original authors and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand All @@ -16,9 +16,10 @@
import java.util.LinkedHashSet;

import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseEvent;

public class AggregateDragMode implements IDragMode {
public class AggregateDragMode implements IDragMode, IDragModeWithKeySupport {

private MouseEvent initialEvent;
private MouseEvent currentEvent;
Expand Down Expand Up @@ -78,4 +79,20 @@ protected MouseEvent getCurrentEvent() {
return this.currentEvent;
}

@Override
public void keyPressed(NatTable natTable, KeyEvent event) {
for (IDragMode dragMode : this.dragModes) {
if (dragMode instanceof IDragModeWithKeySupport)
((IDragModeWithKeySupport) dragMode).keyPressed(natTable, event);
}
}

@Override
public void keyReleased(NatTable natTable, KeyEvent event) {
for (IDragMode dragMode : this.dragModes) {
if (dragMode instanceof IDragModeWithKeySupport)
((IDragModeWithKeySupport) dragMode).keyReleased(natTable, event);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,17 @@ public void focusLost(FocusEvent event) {
@Override
public void keyPressed(KeyEvent event) {
if (event.keyCode == SWT.ESC) {
// pressing ESC will always cancel the drag mode
mouseUp(this.mouseDownEvent);
} else if (this.dragMode instanceof IDragModeWithKeySupport) {
((IDragModeWithKeySupport) this.dragMode).keyPressed(this.natTable, event);
}
}

@Override
public void keyReleased(KeyEvent event) {
if (this.dragMode instanceof IDragModeWithKeySupport) {
((IDragModeWithKeySupport) this.dragMode).keyReleased(this.natTable, event);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*******************************************************************************
* Copyright (c) 2024 Dirk Fauth and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Dirk Fauth <[email protected]> - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.ui.action;

import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.swt.events.KeyEvent;

/**
* Extension of the {@link IDragMode} interface that adds support to react on
* key interactions while the drag mode is active.
*
* @since 2.5
*/
public interface IDragModeWithKeySupport extends IDragMode {

void keyPressed(NatTable natTable, KeyEvent event);

void keyReleased(NatTable natTable, KeyEvent event);

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.eclipse.nebula.widgets.nattable.data.IRowDataProvider;
import org.eclipse.nebula.widgets.nattable.data.IRowIdAccessor;
import org.eclipse.nebula.widgets.nattable.data.ListDataProvider;
import org.eclipse.nebula.widgets.nattable.data.command.RowInsertCommand;
import org.eclipse.nebula.widgets.nattable.data.command.RowInsertCommandHandler;
import org.eclipse.nebula.widgets.nattable.dataset.person.Person;
import org.eclipse.nebula.widgets.nattable.dataset.person.PersonService;
import org.eclipse.nebula.widgets.nattable.examples.AbstractNatExample;
Expand All @@ -44,6 +46,7 @@
import org.eclipse.nebula.widgets.nattable.layer.LayerUtil;
import org.eclipse.nebula.widgets.nattable.layer.cell.ColumnLabelAccumulator;
import org.eclipse.nebula.widgets.nattable.layer.event.StructuralRefreshEvent;
import org.eclipse.nebula.widgets.nattable.painter.IOverlayPainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.ICellPainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.ImagePainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.TextPainter;
Expand All @@ -57,6 +60,7 @@
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.nebula.widgets.nattable.ui.action.AggregateDragMode;
import org.eclipse.nebula.widgets.nattable.ui.action.ClearCursorAction;
import org.eclipse.nebula.widgets.nattable.ui.action.IDragModeWithKeySupport;
import org.eclipse.nebula.widgets.nattable.ui.action.IMouseAction;
import org.eclipse.nebula.widgets.nattable.ui.action.NoOpMouseAction;
import org.eclipse.nebula.widgets.nattable.ui.action.RowDragMode;
Expand All @@ -67,8 +71,11 @@
import org.eclipse.nebula.widgets.nattable.util.GUIHelper;
import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
Expand Down Expand Up @@ -122,6 +129,10 @@ public Control createExampleControl(Composite parent) {
DataLayer bodyDataLayer =
new DataLayer(bodyDataProvider);

// add the RowInsertCommandHandler to be able to copy a row
bodyDataLayer.registerCommandHandler(
new RowInsertCommandHandler<>(contents));

// add a config label accumulator, so we can change the rendering per
// column
bodyDataLayer.setConfigLabelAccumulator(new ColumnLabelAccumulator());
Expand Down Expand Up @@ -161,7 +172,7 @@ public Serializable getRowId(Person rowObject) {
new ColumnHeaderLayer(columnHeaderDataLayer, viewportLayer, selectionLayer);

// add the custom configuration to enable the structural row reordering
bodyDataLayer.addConfiguration(new StructuralRowReorderConfiguration(columnHeaderLayer, selectionLayer));
bodyDataLayer.addConfiguration(new StructuralRowReorderConfiguration(columnHeaderLayer, selectionLayer, bodyDataProvider));

// set the region labels to make default configurations work, e.g.
// selection
Expand All @@ -188,10 +199,12 @@ class StructuralRowReorderConfiguration extends AbstractLayerConfiguration<DataL

private final ILayer columnHeaderLayerStack;
private final SelectionLayer selectionLayer;
private final IRowDataProvider<Person> dataProvider;

public StructuralRowReorderConfiguration(ILayer columnHeaderLayerStack, SelectionLayer selectionLayer) {
public StructuralRowReorderConfiguration(ILayer columnHeaderLayerStack, SelectionLayer selectionLayer, IRowDataProvider<Person> dataProvider) {
this.columnHeaderLayerStack = columnHeaderLayerStack;
this.selectionLayer = selectionLayer;
this.dataProvider = dataProvider;
}

@Override
Expand Down Expand Up @@ -249,12 +262,16 @@ public boolean matches(NatTable natTable, MouseEvent event, LabelStack regionLab
GridRegion.BODY,
MouseEventMatcher.LEFT_BUTTON,
this.dragHandlePainter),
new AggregateDragMode(new RowDragMode(), new MultiRowReorderDragMode(this.columnHeaderLayerStack, this.selectionLayer)));
new AggregateDragMode(
new RowDragMode(),
new MultiRowReorderDragMode(this.columnHeaderLayerStack, this.selectionLayer, this.dataProvider)));

// register drag mode binding on right click in any cell of the body
uiBindingRegistry.registerMouseDragMode(
MouseEventMatcher.bodyRightClick(SWT.NONE),
new AggregateDragMode(new RowDragMode(), new MultiRowReorderDragMode(this.columnHeaderLayerStack, this.selectionLayer)));
new AggregateDragMode(
new RowDragMode(),
new MultiRowReorderDragMode(this.columnHeaderLayerStack, this.selectionLayer, this.dataProvider)));

// register binding to select a row on right mouse down
// simply to select the row so it is highlighted for the reorder
Expand Down Expand Up @@ -326,16 +343,26 @@ public void run(NatTable natTable, MouseEvent event) {
/**
* Extended {@link RowReorderDragMode} that supports multi row reordering.
*/
class MultiRowReorderDragMode extends RowReorderDragMode {
class MultiRowReorderDragMode extends RowReorderDragMode implements IDragModeWithKeySupport {

private ILayer columnHeaderLayerStack;
private SelectionLayer selectionLayer;
private int[] selectedRowPositions;

public MultiRowReorderDragMode(ILayer columnHeaderLayerStack, SelectionLayer selectionLayer) {
private IRowDataProvider<Person> dataProvider;
private Image infoImage;
protected InfoOverlayPainter infoImageOverlayPainter = new InfoOverlayPainter();
private boolean copy = false;

public MultiRowReorderDragMode(
ILayer columnHeaderLayerStack,
SelectionLayer selectionLayer,
IRowDataProvider<Person> dataProvider) {

super();
this.columnHeaderLayerStack = columnHeaderLayerStack;
this.selectionLayer = selectionLayer;
this.dataProvider = dataProvider;
}

@Override
Expand All @@ -348,10 +375,56 @@ public void mouseDown(NatTable natTable, MouseEvent event) {
this.selectedRowPositions = PositionUtil.getPositions(this.selectionLayer.getSelectedRowPositions());

natTable.addOverlayPainter(this.targetOverlayPainter);
natTable.addOverlayPainter(this.infoImageOverlayPainter);

// natTable.doCommand(new ClearAllSelectionsCommand());
}

@Override
public void mouseUp(NatTable natTable, MouseEvent event) {
natTable.removeOverlayPainter(this.infoImageOverlayPainter);

if (this.infoImage != null) {
this.infoImage.dispose();
}

if (this.copy) {
// Cancel any active viewport drag
// we call super with the initial event, which actually skips
// the reorder
super.mouseUp(natTable, this.initialEvent);

this.copy = false;

// remove the overlaypainter of the RowReorderDragMode
natTable.removeOverlayPainter(this.targetOverlayPainter);

List<Person> copiedPersons = new ArrayList<>();
int augment = 1;
for (int rowPos : this.selectedRowPositions) {
int rowIndex = this.selectionLayer.getRowIndexByPosition(rowPos);
Person selected = this.dataProvider.getRowObject(rowIndex);
Person copyPerson = new Person(
this.dataProvider.getRowCount() + augment++,
selected.getFirstName(),
selected.getLastName(),
selected.getGender(),
selected.isMarried(),
selected.getBirthday());

copiedPersons.add(copyPerson);
}

int dragToGridRowPosition = getDragToGridRowPosition(
getMoveDirection(event.y),
natTable.getRowPositionByY(event.y));
int toRowIndex = natTable.getRowIndexByPosition(dragToGridRowPosition);
natTable.doCommand(new RowInsertCommand<>(toRowIndex + 1, copiedPersons));
} else {
super.mouseUp(natTable, event);
}
}

@Override
protected int getDragFromGridRowPosition() {
int rowPosition = super.getDragFromGridRowPosition();
Expand Down Expand Up @@ -410,6 +483,57 @@ protected boolean isValidTargetRowPosition(ILayer natLayer, int dragFromGridRowP
protected void fireMoveEndCommand(NatTable natTable, int dragToGridRowPosition) {
natTable.doCommand(new MultiRowReorderCommand(this.selectionLayer, this.selectedRowPositions, dragToGridRowPosition));
}

@Override
public void keyPressed(NatTable natTable, KeyEvent event) {
if (event.keyCode == SWT.MOD1) {
this.copy = true;

GC gc = null;
try {
this.infoImage = new Image(natTable.getDisplay(), 160, 30);
gc = new GC(this.infoImage);

gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLUE));

gc.fillRectangle(0, 0, 160, 30);
gc.drawText("+ Create a copy", 10, 0);

natTable.redraw(0, 0, natTable.getWidth(), natTable.getHeight(), false);
} finally {
if (gc != null) {
gc.dispose();
}
}
}
}

@Override
public void keyReleased(NatTable natTable, KeyEvent event) {
if (event.keyCode == SWT.MOD1) {
this.copy = false;

this.infoImage.dispose();
this.infoImage = null;

natTable.redraw(0, 0, natTable.getWidth(), natTable.getHeight(), false);
}
}

private class InfoOverlayPainter implements IOverlayPainter {

@Override
public void paintOverlay(GC gc, ILayer layer) {
if (MultiRowReorderDragMode.this.infoImage != null && !MultiRowReorderDragMode.this.infoImage.isDisposed()) {
gc.drawImage(
MultiRowReorderDragMode.this.infoImage,
20,
MultiRowReorderDragMode.this.currentEvent.y + 20);
}
}
}

}

/**
Expand Down

0 comments on commit b944310

Please sign in to comment.