Skip to content

Commit

Permalink
Impl #106 - [Fill Handle] Add double click action
Browse files Browse the repository at this point in the history
  • Loading branch information
fipro78 committed Aug 6, 2024
1 parent 91cc8f0 commit 67d5fee
Show file tree
Hide file tree
Showing 8 changed files with 455 additions and 111 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*******************************************************************************
* Copyright (c) 2024 Dirk Fauth.
*
* 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.fillhandle.action;

import java.util.Date;
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.eclipse.nebula.widgets.nattable.Messages;
import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard;
import org.eclipse.nebula.widgets.nattable.fillhandle.command.FillHandlePasteCommand;
import org.eclipse.nebula.widgets.nattable.fillhandle.command.FillHandlePasteCommand.FillHandleOperation;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MenuAdapter;
import org.eclipse.swt.events.MenuEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;

/**
* Helper class for the fill handle actions.
*
* @since 2.5
*/
public final class FillHandleActionHelper {

private FillHandleActionHelper() {
// private default constructor for helper class
}

/**
* Check if the menu should be shown for selecting copy or series fill
* operation.
*
* @param natTable
* The NatTable instance on which the operation is performed.
* @param clipboard
* The internal clipboard that carries the cells for the copy
* &amp; paste operation triggered by using the fill handle.
* @return <code>true</code> if the menu should be shown, <code>false</code>
* if not.
*/
public static boolean showMenu(NatTable natTable, InternalCellClipboard clipboard) {
if (clipboard == null || clipboard.getCopiedCells() == null) {
return false;
}

Class<?> type = null;
for (ILayerCell[] cells : clipboard.getCopiedCells()) {
for (ILayerCell cell : cells) {
if (cell.getDataValue() == null) {
return false;
} else {
if (type == null) {
type = cell.getDataValue().getClass();
if (!Number.class.isAssignableFrom(type)
&& !Date.class.isAssignableFrom(type)) {
return false;
}
} else if (type != cell.getDataValue().getClass()) {
return false;
}
}
}
}
return true;
}

/**
* Create the menu that should be opened on a fill operation.
*
* @param natTable
* The NatTable instance on which the operation is performed and
* the menu should be connected to.
* @param directionProvider
* The {@link Supplier} that provides the The direction in which
* the fill handle was dragged.
* @param resetRunnable
* The {@link Runnable} that should be executed when the menu is
* hidden.
* @return The menu that should be opened on a fill operation.
*/
public static Menu createFillHandleMenu(NatTable natTable, Supplier<MoveDirectionEnum> directionProvider, Consumer<NatTable> resetRunnable) {
Menu menu = new Menu(natTable);
MenuItem copyItem = new MenuItem(menu, SWT.PUSH);
copyItem.setText(Messages.getLocalizedMessage("%FillHandleDragMode.menu.item.copy")); //$NON-NLS-1$
copyItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
natTable.doCommand(
new FillHandlePasteCommand(
FillHandleOperation.COPY,
directionProvider.get(),
natTable.getConfigRegistry()));
}
});
MenuItem seriesItem = new MenuItem(menu, SWT.PUSH);
seriesItem.setText(Messages.getLocalizedMessage("%FillHandleDragMode.menu.item.series")); //$NON-NLS-1$
seriesItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
natTable.doCommand(
new FillHandlePasteCommand(
FillHandleOperation.SERIES,
directionProvider.get(),
natTable.getConfigRegistry()));
}
});

// add a menu listener to reset the fill state when the menu is
// closed
menu.addMenuListener(new MenuAdapter() {
@Override
public void menuHidden(MenuEvent e) {
// perform the reset operation asynchronously because on
// several OS the hide event is processed BEFORE the
// selection event
Display.getDefault().asyncExec(() -> resetRunnable.accept(natTable));
}
});

// add the dispose listener for disposing the menu
natTable.addDisposeListener(e -> menu.dispose());

return menu;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*******************************************************************************
* Copyright (c) 2024 Dirk Fauth.
*
* 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.fillhandle.action;

import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard;
import org.eclipse.nebula.widgets.nattable.copy.command.CopyDataToClipboardCommand;
import org.eclipse.nebula.widgets.nattable.fillhandle.command.FillHandlePasteCommand;
import org.eclipse.nebula.widgets.nattable.fillhandle.command.FillHandlePasteCommand.FillHandleOperation;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum;
import org.eclipse.nebula.widgets.nattable.ui.action.IMouseAction;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Menu;

/**
* {@link IMouseAction} that can be registered on double clicks on the fill
* handle to trigger an automatic fill operation for the whole column.
*
* @since 2.5
*/
public class FillHandleColumnAction implements IMouseAction {

protected SelectionLayer selectionLayer;
protected InternalCellClipboard clipboard;

protected Menu menu;

/**
*
* @param selectionLayer
* The {@link SelectionLayer} needed to determine the fill handle
* region and perform the update command.
* @param clipboard
* The internal clipboard that carries the cells for the copy
* &amp; paste operation triggered by using the fill handle.
*/
public FillHandleColumnAction(SelectionLayer selectionLayer, InternalCellClipboard clipboard) {
if (selectionLayer == null) {
throw new IllegalArgumentException("SelectionLayer can not be null"); //$NON-NLS-1$
}
this.selectionLayer = selectionLayer;
this.clipboard = clipboard;
}

@Override
public void run(NatTable natTable, MouseEvent event) {
if (this.selectionLayer.hasColumnSelection()) {

if (natTable.doCommand(
new CopyDataToClipboardCommand(
"\t", //$NON-NLS-1$
System.getProperty("line.separator"), //$NON-NLS-1$
natTable.getConfigRegistry()))) {

// set the fill handle region to be the whole column
int startRow = this.selectionLayer.getSelectedRowPositions().iterator().next().start;
Rectangle region = new Rectangle(
this.selectionLayer.getSelectedColumnPositions()[0],
startRow,
this.selectionLayer.getSelectedColumnPositions().length,
this.selectionLayer.getRowCount() - startRow);
this.selectionLayer.setFillHandleRegion(region);

if (this.clipboard != null) {
if (showMenu(natTable)) {
openMenu(natTable);
} else {
natTable.doCommand(
new FillHandlePasteCommand(
FillHandleOperation.COPY,
MoveDirectionEnum.DOWN,
natTable.getConfigRegistry()));
reset(natTable);
}
} else {
natTable.doCommand(
new FillHandlePasteCommand(
FillHandleOperation.COPY,
MoveDirectionEnum.DOWN,
natTable.getConfigRegistry()));
reset(natTable);
}
} else {
reset(natTable);
}
}
}

/**
* Check if the menu should be shown for selecting copy or series fill
* operation.
*
* @param natTable
* The NatTable instance on which the operation is performed.
* @return <code>true</code> if the menu should be shown, <code>false</code>
* if not.
*/
protected boolean showMenu(final NatTable natTable) {
return FillHandleActionHelper.showMenu(natTable, this.clipboard);
}

/**
* Opens a menu that enables a user to select whether values should simply
* be copied or if a series should be filled.
*
* @param natTable
* The NatTable instance on which the operation is performed.
*/
protected void openMenu(final NatTable natTable) {
// lazily create the menu
if (this.menu == null || this.menu.isDisposed()) {
this.menu = FillHandleActionHelper.createFillHandleMenu(
natTable,
() -> MoveDirectionEnum.DOWN,
(n) -> reset(n));
}

this.menu.setVisible(true);
}

/**
* Reset the fill handle region in the {@link SelectionLayer}, clear the
* clipboard and redraw the given NatTable.
*
* @param natTable
* The NatTable instance on which the operation is performed.
*/
protected void reset(NatTable natTable) {
this.selectionLayer.setFillHandleRegion(null);
this.clipboard.clear();
if (!natTable.isDisposed()) {
natTable.redraw();
}
}

}
Loading

0 comments on commit 67d5fee

Please sign in to comment.