diff options
| author | Dirk Fauth | 2015-12-24 13:18:06 +0000 |
|---|---|---|
| committer | Dirk Fauth | 2015-12-24 13:18:06 +0000 |
| commit | 0d4c91b45b272f328ecbe075b2775b4b8eb92b39 (patch) | |
| tree | d1ded6d10ef5b96f16261bb1fe83a6e6ee5fa547 | |
| parent | 8955d78dbe8aa4618e15fa376a0eb658b1b38cea (diff) | |
| download | org.eclipse.nebula.widgets.nattable-0d4c91b45b272f328ecbe075b2775b4b8eb92b39.tar.gz org.eclipse.nebula.widgets.nattable-0d4c91b45b272f328ecbe075b2775b4b8eb92b39.tar.xz org.eclipse.nebula.widgets.nattable-0d4c91b45b272f328ecbe075b2775b4b8eb92b39.zip | |
Bug 484880 - Add fill drag handle to support autofill actions
Change-Id: I287df69733b9095d8927fb97f8f5c8a413c291a0
Signed-off-by: Dirk Fauth <dirk.fauth@googlemail.com>
36 files changed, 5709 insertions, 316 deletions
diff --git a/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/fillhandle/FillHandlePasteTest.java b/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/fillhandle/FillHandlePasteTest.java new file mode 100644 index 00000000..2df1069f --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/fillhandle/FillHandlePasteTest.java @@ -0,0 +1,905 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.fillhandle; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import org.eclipse.nebula.widgets.nattable.NatTable; +import org.eclipse.nebula.widgets.nattable.config.AbstractRegistryConfiguration; +import org.eclipse.nebula.widgets.nattable.config.EditableRule; +import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; +import org.eclipse.nebula.widgets.nattable.copy.command.CopyDataToClipboardCommand; +import org.eclipse.nebula.widgets.nattable.data.IDataProvider; +import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes; +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.fillhandle.config.FillHandleConfiguration; +import org.eclipse.nebula.widgets.nattable.formula.TwoDimensionalArrayDataProvider; +import org.eclipse.nebula.widgets.nattable.layer.DataLayer; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum; +import org.eclipse.nebula.widgets.nattable.test.fixture.NatTableFixture; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class FillHandlePasteTest { + + IDataProvider dataProvider = new TwoDimensionalArrayDataProvider(new Object[10][10]); + SelectionLayer selectionLayer = new SelectionLayer(new DataLayer(this.dataProvider)); + NatTable natTable = new NatTableFixture(this.selectionLayer, false); + + @Before + public void setup() { + this.natTable.addConfiguration(new FillHandleConfiguration(this.selectionLayer)); + this.natTable.addConfiguration(new AbstractRegistryConfiguration() { + + @Override + public void configureRegistry(IConfigRegistry configRegistry) { + configRegistry.registerConfigAttribute( + EditConfigAttributes.CELL_EDITABLE_RULE, + EditableRule.ALWAYS_EDITABLE); + } + }); + this.natTable.configure(); + } + + @After + public void tearDown() { + this.selectionLayer.clear(); + this.selectionLayer.setFillHandleRegion(null); + } + + @Test + public void testSingleCellDragOneDown() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 5)); + + testCellStates(new Point(4, 4), new Point(4, 5)); + } + + @Test + public void testSingleCellDragOneUp() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 3, 1, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.UP, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 3)); + + testCellStates(new Point(4, 4), new Point(4, 3)); + } + + @Test + public void testSingleCellDragOneRight() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 2, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(5, 4)); + + testCellStates(new Point(4, 4), new Point(5, 4)); + } + + @Test + public void testSingleCellDragOneLeft() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(3, 4, 2, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.LEFT, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(3, 4)); + + testCellStates(new Point(4, 4), new Point(3, 4)); + } + + @Test + public void testSingleCellDragMultipleDown() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 7)); + + testCellStates(new Point(4, 4), new Point(4, 5), new Point(4, 6), new Point(4, 7)); + } + + @Test + public void testSingleCellDragMultiUp() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 0, 1, 5)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.UP, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 0)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 1)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 2)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 3)); + + testCellStates(new Point(4, 4), new Point(4, 0), new Point(4, 1), new Point(4, 2), new Point(4, 3)); + } + + @Test + public void testSingleCellDragMultiRight() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 4, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(7, 4)); + + testCellStates(new Point(4, 4), new Point(5, 4), new Point(6, 4), new Point(7, 4)); + } + + @Test + public void testSingleCellDragMultiLeft() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(0, 4, 5, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.LEFT, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(0, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(1, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(2, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(3, 4)); + + testCellStates(new Point(4, 4), new Point(0, 4), new Point(1, 4), new Point(2, 4), new Point(3, 4)); + } + + @Test + public void testSingleCellDragDownRight() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 2, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(5, 5)); + + testCellStates(new Point(4, 4), new Point(4, 5), new Point(5, 4), new Point(5, 5)); + } + + @Test + public void testSingleCellDragOneUpRight() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 3, 2, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.UP, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 3)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(5, 3)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(5, 4)); + + testCellStates(new Point(4, 3), new Point(5, 3), new Point(4, 4), new Point(5, 4)); + } + + @Test + public void testSingleCellDragUpLeft() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(3, 3, 2, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.LEFT, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(3, 3)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 3)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + + testCellStates(new Point(3, 3), new Point(4, 3), new Point(3, 4), new Point(4, 4)); + } + + @Test + public void testSingleCellDragDownLeft() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(3, 4, 2, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.LEFT, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(3, 5)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 5)); + + testCellStates(new Point(3, 4), new Point(4, 4), new Point(3, 5), new Point(4, 5)); + } + + @Test + public void testMultiVerticalCellDragRight() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + this.dataProvider.setDataValue(4, 5, "Flanders"); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + testCellStates(new Point(4, 4), new Point(4, 5)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 3, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(5, 5)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(6, 5)); + + testCellStates(new Point(4, 4), new Point(4, 5), new Point(5, 4), new Point(5, 5), new Point(6, 4), new Point(6, 5)); + } + + @Test + public void testMultiVerticalCellDragLeft() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + this.dataProvider.setDataValue(4, 5, "Flanders"); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + testCellStates(new Point(4, 4), new Point(4, 5)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(2, 4, 3, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.LEFT, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(2, 4)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(2, 5)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(3, 5)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 5)); + + testCellStates(new Point(2, 4), new Point(2, 5), new Point(3, 4), new Point(3, 5), new Point(4, 4), new Point(4, 5)); + } + + @Test + public void testMultiVerticalCellDragDown() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + this.dataProvider.setDataValue(4, 5, "Flanders"); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + testCellStates(new Point(4, 4), new Point(4, 5)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 5)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 8)); + + testCellStates(new Point(4, 4), new Point(4, 5), new Point(4, 6), new Point(4, 7), new Point(4, 8)); + } + + @Test + public void testMultiVerticalCellDragUp() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + this.dataProvider.setDataValue(4, 5, "Flanders"); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + testCellStates(new Point(4, 4), new Point(4, 5)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 1, 1, 5)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.UP, this.natTable.getConfigRegistry())); + + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 1)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 2)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 3)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 5)); + + testCellStates(new Point(4, 1), new Point(4, 2), new Point(4, 3), new Point(4, 4), new Point(4, 5)); + } + + @Test + public void testMultiHorizontalCellDragRight() { + this.dataProvider.setDataValue(3, 4, "Homer"); + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.selectCell(3, 4, false, true); + this.selectionLayer.selectCell(4, 4, false, true); + + testCellStates(new Point(3, 4), new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(3, 4, 5, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(7, 4)); + + testCellStates(new Point(3, 4), new Point(4, 4), new Point(5, 4), new Point(6, 4), new Point(7, 4)); + } + + @Test + public void testMultiHorizontalCellDragLeft() { + this.dataProvider.setDataValue(3, 4, "Homer"); + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.selectCell(3, 4, false, true); + this.selectionLayer.selectCell(4, 4, false, true); + + testCellStates(new Point(3, 4), new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(0, 4, 5, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.LEFT, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(0, 4)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(1, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(2, 4)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + + testCellStates(new Point(0, 4), new Point(1, 4), new Point(2, 4), new Point(3, 4), new Point(4, 4)); + } + + @Test + public void testMultiHorizontalCellDragDown() { + this.dataProvider.setDataValue(3, 4, "Homer"); + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.selectCell(3, 4, false, true); + this.selectionLayer.selectCell(4, 4, false, true); + + testCellStates(new Point(3, 4), new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(3, 4, 2, 3)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 5)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 6)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 6)); + + testCellStates(new Point(3, 4), new Point(4, 4), new Point(3, 5), new Point(4, 5), new Point(3, 6), new Point(4, 6)); + } + + @Test + public void testMultiHorizontalCellDragUp() { + this.dataProvider.setDataValue(3, 4, "Homer"); + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.selectCell(3, 4, false, true); + this.selectionLayer.selectCell(4, 4, false, true); + + testCellStates(new Point(3, 4), new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(3, 2, 2, 3)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.UP, this.natTable.getConfigRegistry())); + + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 2)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 2)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 3)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 3)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + + testCellStates(new Point(3, 2), new Point(4, 2), new Point(3, 3), new Point(4, 3), new Point(3, 4), new Point(4, 4)); + } + + @Test + public void testMultiCellDragOneDown() { + this.dataProvider.setDataValue(3, 4, "Homer"); + this.dataProvider.setDataValue(4, 4, "Simpson"); + this.dataProvider.setDataValue(3, 5, "Ned"); + this.dataProvider.setDataValue(4, 5, "Flanders"); + + this.selectionLayer.selectCell(3, 4, false, true); + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(3, 5, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + testCellStates(new Point(3, 4), new Point(4, 4), new Point(3, 5), new Point(4, 5)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(3, 4, 2, 3)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(3, 5)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 6)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 6)); + + testCellStates( + new Point(3, 4), new Point(4, 4), + new Point(3, 5), new Point(4, 5), + new Point(3, 6), new Point(4, 6)); + } + + @Test + public void testMultiCellDragThreeDown() { + this.dataProvider.setDataValue(3, 4, "Homer"); + this.dataProvider.setDataValue(4, 4, "Simpson"); + this.dataProvider.setDataValue(3, 5, "Ned"); + this.dataProvider.setDataValue(4, 5, "Flanders"); + + this.selectionLayer.selectCell(3, 4, false, true); + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(3, 5, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + testCellStates(new Point(3, 4), new Point(4, 4), new Point(3, 5), new Point(4, 5)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(3, 4, 2, 5)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(3, 5)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 6)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(3, 5)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 6)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 6)); + + testCellStates( + new Point(3, 4), new Point(4, 4), + new Point(3, 5), new Point(4, 5), + new Point(3, 6), new Point(4, 6), + new Point(3, 7), new Point(4, 7), + new Point(3, 8), new Point(4, 8)); + } + + @Test + public void testMultiCellDragOneUp() { + this.dataProvider.setDataValue(3, 4, "Homer"); + this.dataProvider.setDataValue(4, 4, "Simpson"); + this.dataProvider.setDataValue(3, 5, "Ned"); + this.dataProvider.setDataValue(4, 5, "Flanders"); + + this.selectionLayer.selectCell(3, 4, false, true); + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(3, 5, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + testCellStates(new Point(3, 4), new Point(4, 4), new Point(3, 5), new Point(4, 5)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(3, 3, 2, 3)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.UP, this.natTable.getConfigRegistry())); + + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(3, 3)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 3)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(3, 5)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 5)); + + testCellStates( + new Point(3, 3), new Point(4, 3), + new Point(3, 4), new Point(4, 4), + new Point(3, 5), new Point(4, 5)); + } + + @Test + public void testMultiCellDragThreeUp() { + this.dataProvider.setDataValue(3, 4, "Homer"); + this.dataProvider.setDataValue(4, 4, "Simpson"); + this.dataProvider.setDataValue(3, 5, "Ned"); + this.dataProvider.setDataValue(4, 5, "Flanders"); + + this.selectionLayer.selectCell(3, 4, false, true); + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(3, 5, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + testCellStates(new Point(3, 4), new Point(4, 4), new Point(3, 5), new Point(4, 5)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(3, 1, 2, 5)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.UP, this.natTable.getConfigRegistry())); + + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(3, 1)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 1)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 2)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 2)); + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(3, 3)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 3)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(3, 5)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 5)); + + testCellStates( + new Point(3, 1), new Point(4, 1), + new Point(3, 2), new Point(4, 2), + new Point(3, 3), new Point(4, 3), + new Point(3, 4), new Point(4, 4), + new Point(3, 5), new Point(4, 5)); + } + + @Test + public void testMultiCellDragOneRight() { + this.dataProvider.setDataValue(3, 4, "Homer"); + this.dataProvider.setDataValue(4, 4, "Simpson"); + this.dataProvider.setDataValue(3, 5, "Ned"); + this.dataProvider.setDataValue(4, 5, "Flanders"); + + this.selectionLayer.selectCell(3, 4, false, true); + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(3, 5, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + testCellStates(new Point(3, 4), new Point(4, 4), new Point(3, 5), new Point(4, 5)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(3, 4, 3, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(3, 5)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(5, 5)); + + testCellStates( + new Point(3, 4), new Point(4, 4), new Point(5, 4), + new Point(3, 5), new Point(4, 5), new Point(5, 5)); + } + + @Test + public void testMultiCellDragThreeRight() { + this.dataProvider.setDataValue(3, 4, "Homer"); + this.dataProvider.setDataValue(4, 4, "Simpson"); + this.dataProvider.setDataValue(3, 5, "Ned"); + this.dataProvider.setDataValue(4, 5, "Flanders"); + + this.selectionLayer.selectCell(3, 4, false, true); + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(3, 5, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + testCellStates(new Point(3, 4), new Point(4, 4), new Point(3, 5), new Point(4, 5)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(3, 4, 5, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(7, 4)); + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(3, 5)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(5, 5)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(6, 5)); + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(7, 5)); + + testCellStates( + new Point(3, 4), new Point(4, 4), new Point(5, 4), new Point(6, 4), new Point(7, 4), + new Point(3, 5), new Point(4, 5), new Point(5, 5), new Point(6, 5), new Point(7, 5)); + } + + @Test + public void testMultiCellDragOneLeft() { + this.dataProvider.setDataValue(3, 4, "Homer"); + this.dataProvider.setDataValue(4, 4, "Simpson"); + this.dataProvider.setDataValue(3, 5, "Ned"); + this.dataProvider.setDataValue(4, 5, "Flanders"); + + this.selectionLayer.selectCell(3, 4, false, true); + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(3, 5, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + testCellStates(new Point(3, 4), new Point(4, 4), new Point(3, 5), new Point(4, 5)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(2, 4, 3, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.LEFT, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(2, 4)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(2, 5)); + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(3, 5)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 5)); + + testCellStates( + new Point(2, 4), new Point(3, 4), new Point(4, 4), + new Point(2, 5), new Point(3, 5), new Point(4, 5)); + } + + @Test + public void testMultiCellDragThreeLeft() { + this.dataProvider.setDataValue(3, 4, "Homer"); + this.dataProvider.setDataValue(4, 4, "Simpson"); + this.dataProvider.setDataValue(3, 5, "Ned"); + this.dataProvider.setDataValue(4, 5, "Flanders"); + + this.selectionLayer.selectCell(3, 4, false, true); + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(3, 5, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + testCellStates(new Point(3, 4), new Point(4, 4), new Point(3, 5), new Point(4, 5)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(0, 4, 5, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.LEFT, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(0, 4)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(1, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(2, 4)); + assertEquals("Homer", this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(0, 5)); + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(1, 5)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(2, 5)); + assertEquals("Ned", this.selectionLayer.getDataValueByPosition(3, 5)); + assertEquals("Flanders", this.selectionLayer.getDataValueByPosition(4, 5)); + + testCellStates( + new Point(0, 4), new Point(1, 4), new Point(2, 4), new Point(3, 4), new Point(4, 4), + new Point(0, 5), new Point(1, 5), new Point(2, 5), new Point(3, 5), new Point(4, 5)); + } + + private void testCellStates(Point... nonNull) { + for (int i = 0; i < this.dataProvider.getColumnCount(); i++) { + for (int j = 0; j < this.dataProvider.getRowCount(); j++) { + + boolean check = true; + for (Point p : nonNull) { + if ((i == p.x) && (j == p.y)) { + check = false; + break; + } + } + if (check) { + assertNull("Position " + i + "/" + j + " is not null", this.selectionLayer.getDataValueByPosition(i, j)); + } else { + assertNotNull("Position " + i + "/" + j + " is null", this.selectionLayer.getDataValueByPosition(i, j)); + } + } + } + } + +} diff --git a/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/fillhandle/FillHandleSeriesTest.java b/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/fillhandle/FillHandleSeriesTest.java new file mode 100644 index 00000000..3c90b4f9 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/fillhandle/FillHandleSeriesTest.java @@ -0,0 +1,1320 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.fillhandle; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Calendar; +import java.util.Date; + +import org.eclipse.nebula.widgets.nattable.NatTable; +import org.eclipse.nebula.widgets.nattable.config.AbstractRegistryConfiguration; +import org.eclipse.nebula.widgets.nattable.config.EditableRule; +import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; +import org.eclipse.nebula.widgets.nattable.copy.command.CopyDataToClipboardCommand; +import org.eclipse.nebula.widgets.nattable.data.IDataProvider; +import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes; +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.fillhandle.config.FillHandleConfigAttributes; +import org.eclipse.nebula.widgets.nattable.fillhandle.config.FillHandleConfiguration; +import org.eclipse.nebula.widgets.nattable.formula.TwoDimensionalArrayDataProvider; +import org.eclipse.nebula.widgets.nattable.layer.DataLayer; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum; +import org.eclipse.nebula.widgets.nattable.test.fixture.NatTableFixture; +import org.eclipse.swt.graphics.Rectangle; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class FillHandleSeriesTest { + + IDataProvider dataProvider = new TwoDimensionalArrayDataProvider(new Object[10][10]); + SelectionLayer selectionLayer = new SelectionLayer(new DataLayer(this.dataProvider)); + NatTable natTable = new NatTableFixture(this.selectionLayer, false); + + @Before + public void setup() { + this.natTable.addConfiguration(new FillHandleConfiguration(this.selectionLayer)); + this.natTable.addConfiguration(new AbstractRegistryConfiguration() { + + @Override + public void configureRegistry(IConfigRegistry configRegistry) { + configRegistry.registerConfigAttribute( + EditConfigAttributes.CELL_EDITABLE_RULE, + EditableRule.ALWAYS_EDITABLE); + } + }); + this.natTable.configure(); + } + + @After + public void tearDown() { + this.selectionLayer.clear(); + this.selectionLayer.setFillHandleRegion(null); + } + + @Test + public void testSingleCellIntegerValueDragDown() { + this.dataProvider.setDataValue(4, 4, Integer.valueOf("1")); + + this.selectionLayer.setSelectedCell(4, 4); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Integer.valueOf("2"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Integer.valueOf("3"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Integer.valueOf("4"), this.selectionLayer.getDataValueByPosition(4, 7)); + } + + @Test + public void testSingleCellIntegerValueDragUp() { + this.dataProvider.setDataValue(4, 4, Integer.valueOf("1")); + + this.selectionLayer.setSelectedCell(4, 4); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 1, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.UP, this.natTable.getConfigRegistry())); + + assertEquals(Integer.valueOf("-2"), this.selectionLayer.getDataValueByPosition(4, 1)); + assertEquals(Integer.valueOf("-1"), this.selectionLayer.getDataValueByPosition(4, 2)); + assertEquals(Integer.valueOf("0"), this.selectionLayer.getDataValueByPosition(4, 3)); + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + } + + @Test + public void testSingleCellIntegerValueDragRight() { + this.dataProvider.setDataValue(4, 4, Integer.valueOf("1")); + + this.selectionLayer.setSelectedCell(4, 4); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 4, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Integer.valueOf("2"), this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(Integer.valueOf("3"), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals(Integer.valueOf("4"), this.selectionLayer.getDataValueByPosition(7, 4)); + } + + @Test + public void testSingleCellIntegerValueDragLeft() { + this.dataProvider.setDataValue(4, 4, Integer.valueOf("1")); + + this.selectionLayer.setSelectedCell(4, 4); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(1, 4, 4, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.LEFT, this.natTable.getConfigRegistry())); + + assertEquals(Integer.valueOf("-2"), this.selectionLayer.getDataValueByPosition(1, 4)); + assertEquals(Integer.valueOf("-1"), this.selectionLayer.getDataValueByPosition(2, 4)); + assertEquals(Integer.valueOf("0"), this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + } + + @Test + public void testSingleCellByteValueDragDown() { + this.dataProvider.setDataValue(4, 4, Byte.valueOf("1")); + + this.selectionLayer.setSelectedCell(4, 4); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Byte.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Byte.valueOf("2"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Byte.valueOf("3"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Byte.valueOf("4"), this.selectionLayer.getDataValueByPosition(4, 7)); + } + + @Test + public void testSingleCellShortValueDragDown() { + this.dataProvider.setDataValue(4, 4, Short.valueOf("1")); + + this.selectionLayer.setSelectedCell(4, 4); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Short.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Short.valueOf("2"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Short.valueOf("3"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Short.valueOf("4"), this.selectionLayer.getDataValueByPosition(4, 7)); + } + + @Test + public void testSingleCellLongValueDragDown() { + this.dataProvider.setDataValue(4, 4, Long.valueOf("1")); + + this.selectionLayer.setSelectedCell(4, 4); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Long.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Long.valueOf("2"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Long.valueOf("3"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Long.valueOf("4"), this.selectionLayer.getDataValueByPosition(4, 7)); + } + + @Test + public void testSingleCellFloatValueDragDown() { + this.dataProvider.setDataValue(4, 4, Float.valueOf("1.4")); + + this.selectionLayer.setSelectedCell(4, 4); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Float.valueOf("1.4"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Float.valueOf("2.4"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Float.valueOf("3.4"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Float.valueOf("4.4"), this.selectionLayer.getDataValueByPosition(4, 7)); + } + + @Test + public void testSingleCellDoubleValueDragDown() { + this.dataProvider.setDataValue(4, 4, Double.valueOf("1.6")); + + this.selectionLayer.setSelectedCell(4, 4); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Double.valueOf("1.6"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Double.valueOf("2.6"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Double.valueOf("3.6"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Double.valueOf("4.6"), this.selectionLayer.getDataValueByPosition(4, 7)); + } + + @Test + public void testSingleCellBigIntegerValueDragDown() { + this.dataProvider.setDataValue(4, 4, BigInteger.valueOf(100)); + + this.selectionLayer.setSelectedCell(4, 4); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(BigInteger.valueOf(100), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(BigInteger.valueOf(101), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(BigInteger.valueOf(102), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(BigInteger.valueOf(103), this.selectionLayer.getDataValueByPosition(4, 7)); + } + + @Test + public void testSingleCellBigDecimalValueDragDown() { + this.dataProvider.setDataValue(4, 4, BigDecimal.valueOf(13.8d)); + + this.selectionLayer.setSelectedCell(4, 4); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(BigDecimal.valueOf(13.8d), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(BigDecimal.valueOf(14.8d), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(BigDecimal.valueOf(15.8d), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(BigDecimal.valueOf(16.8d), this.selectionLayer.getDataValueByPosition(4, 7)); + } + + @SuppressWarnings("deprecation") + @Test + public void testSingleCellDateValueDragDown() { + this.dataProvider.setDataValue(4, 4, new Date(2015, 9, 29)); + + this.selectionLayer.setSelectedCell(4, 4); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(new Date(2015, 9, 29), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(new Date(2015, 9, 30), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(new Date(2015, 9, 31), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(new Date(2015, 10, 1), this.selectionLayer.getDataValueByPosition(4, 7)); + } + + @SuppressWarnings("deprecation") + @Test + public void testSingleCellDateValueDragUp() { + this.dataProvider.setDataValue(4, 4, new Date(2015, 9, 2)); + + this.selectionLayer.setSelectedCell(4, 4); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 1, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.UP, this.natTable.getConfigRegistry())); + + assertEquals(new Date(2015, 8, 29), this.selectionLayer.getDataValueByPosition(4, 1)); + assertEquals(new Date(2015, 8, 30), this.selectionLayer.getDataValueByPosition(4, 2)); + assertEquals(new Date(2015, 9, 1), this.selectionLayer.getDataValueByPosition(4, 3)); + assertEquals(new Date(2015, 9, 2), this.selectionLayer.getDataValueByPosition(4, 4)); + } + + @Test + public void testMultiCellSameDiffIntegerValueDragDown() { + this.dataProvider.setDataValue(4, 4, Integer.valueOf("1")); + this.dataProvider.setDataValue(4, 5, Integer.valueOf("3")); + this.dataProvider.setDataValue(4, 6, Integer.valueOf("5")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + this.selectionLayer.selectCell(4, 6, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Integer.valueOf("3"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Integer.valueOf("5"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Integer.valueOf("7"), this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(Integer.valueOf("9"), this.selectionLayer.getDataValueByPosition(4, 8)); + assertEquals(Integer.valueOf("11"), this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testMultiCellSameDiffIntegerValueDragRight() { + this.dataProvider.setDataValue(4, 4, Integer.valueOf("1")); + this.dataProvider.setDataValue(5, 4, Integer.valueOf("3")); + this.dataProvider.setDataValue(6, 4, Integer.valueOf("5")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(5, 4, false, true); + this.selectionLayer.selectCell(6, 4, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 6, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Integer.valueOf("3"), this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(Integer.valueOf("5"), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals(Integer.valueOf("7"), this.selectionLayer.getDataValueByPosition(7, 4)); + assertEquals(Integer.valueOf("9"), this.selectionLayer.getDataValueByPosition(8, 4)); + assertEquals(Integer.valueOf("11"), this.selectionLayer.getDataValueByPosition(9, 4)); + } + + @Test + public void testMultiCellSameDiffIntegerValueDragUp() { + this.dataProvider.setDataValue(4, 4, Integer.valueOf("1")); + this.dataProvider.setDataValue(4, 5, Integer.valueOf("3")); + this.dataProvider.setDataValue(4, 6, Integer.valueOf("5")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + this.selectionLayer.selectCell(4, 6, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 1, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.UP, this.natTable.getConfigRegistry())); + + assertEquals(Integer.valueOf("-5"), this.selectionLayer.getDataValueByPosition(4, 1)); + assertEquals(Integer.valueOf("-3"), this.selectionLayer.getDataValueByPosition(4, 2)); + assertEquals(Integer.valueOf("-1"), this.selectionLayer.getDataValueByPosition(4, 3)); + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Integer.valueOf("3"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Integer.valueOf("5"), this.selectionLayer.getDataValueByPosition(4, 6)); + } + + @Test + public void testMultiCellSameDiffIntegerValueDragLeft() { + this.dataProvider.setDataValue(4, 4, Integer.valueOf("1")); + this.dataProvider.setDataValue(5, 4, Integer.valueOf("3")); + this.dataProvider.setDataValue(6, 4, Integer.valueOf("5")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(5, 4, false, true); + this.selectionLayer.selectCell(6, 4, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(1, 4, 6, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.LEFT, this.natTable.getConfigRegistry())); + + assertEquals(Integer.valueOf("-5"), this.selectionLayer.getDataValueByPosition(1, 4)); + assertEquals(Integer.valueOf("-3"), this.selectionLayer.getDataValueByPosition(2, 4)); + assertEquals(Integer.valueOf("-1"), this.selectionLayer.getDataValueByPosition(3, 4)); + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Integer.valueOf("3"), this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(Integer.valueOf("5"), this.selectionLayer.getDataValueByPosition(6, 4)); + } + + @Test + public void testMultiCellSameDiffByteValueDragDown() { + this.dataProvider.setDataValue(4, 4, Byte.valueOf("1")); + this.dataProvider.setDataValue(4, 5, Byte.valueOf("3")); + this.dataProvider.setDataValue(4, 6, Byte.valueOf("5")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + this.selectionLayer.selectCell(4, 6, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Byte.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Byte.valueOf("3"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Byte.valueOf("5"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Byte.valueOf("7"), this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(Byte.valueOf("9"), this.selectionLayer.getDataValueByPosition(4, 8)); + assertEquals(Byte.valueOf("11"), this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testMultiCellSameDiffShortValueDragDown() { + this.dataProvider.setDataValue(4, 4, Short.valueOf("1")); + this.dataProvider.setDataValue(4, 5, Short.valueOf("3")); + this.dataProvider.setDataValue(4, 6, Short.valueOf("5")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + this.selectionLayer.selectCell(4, 6, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Short.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Short.valueOf("3"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Short.valueOf("5"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Short.valueOf("7"), this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(Short.valueOf("9"), this.selectionLayer.getDataValueByPosition(4, 8)); + assertEquals(Short.valueOf("11"), this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testMultiCellSameDiffLongValueDragDown() { + this.dataProvider.setDataValue(4, 4, Long.valueOf("1")); + this.dataProvider.setDataValue(4, 5, Long.valueOf("3")); + this.dataProvider.setDataValue(4, 6, Long.valueOf("5")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + this.selectionLayer.selectCell(4, 6, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Long.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Long.valueOf("3"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Long.valueOf("5"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Long.valueOf("7"), this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(Long.valueOf("9"), this.selectionLayer.getDataValueByPosition(4, 8)); + assertEquals(Long.valueOf("11"), this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testMultiCellSameDiffFloatValueDragDown() { + this.dataProvider.setDataValue(4, 4, Float.valueOf("1.3")); + this.dataProvider.setDataValue(4, 5, Float.valueOf("2.6")); + this.dataProvider.setDataValue(4, 6, Float.valueOf("3.9")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + this.selectionLayer.selectCell(4, 6, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Float.valueOf("1.3"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Float.valueOf("2.6"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Float.valueOf("3.9"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Float.valueOf("5.2"), this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(Float.valueOf("6.5"), this.selectionLayer.getDataValueByPosition(4, 8)); + assertEquals(Float.valueOf("7.8"), this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testMultiCellSameDiffDoubleValueDragDown() { + this.dataProvider.setDataValue(4, 4, Double.valueOf("1.3")); + this.dataProvider.setDataValue(4, 5, Double.valueOf("2.6")); + this.dataProvider.setDataValue(4, 6, Double.valueOf("3.9")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + this.selectionLayer.selectCell(4, 6, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Double.valueOf("1.3"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Double.valueOf("2.6"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Double.valueOf("3.9"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Double.valueOf("5.2"), this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(Double.valueOf("6.5"), this.selectionLayer.getDataValueByPosition(4, 8)); + assertEquals(Double.valueOf("7.8"), this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testMultiCellSameDiffBigIntegerValueDragDown() { + this.dataProvider.setDataValue(4, 4, BigInteger.valueOf(1)); + this.dataProvider.setDataValue(4, 5, BigInteger.valueOf(3)); + this.dataProvider.setDataValue(4, 6, BigInteger.valueOf(5)); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + this.selectionLayer.selectCell(4, 6, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(BigInteger.valueOf(1), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(BigInteger.valueOf(3), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(BigInteger.valueOf(5), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(BigInteger.valueOf(7), this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(BigInteger.valueOf(9), this.selectionLayer.getDataValueByPosition(4, 8)); + assertEquals(BigInteger.valueOf(11), this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testMultiCellSameDiffBigDecimalValueDragDown() { + this.dataProvider.setDataValue(4, 4, BigDecimal.valueOf(1.2d)); + this.dataProvider.setDataValue(4, 5, BigDecimal.valueOf(2.4d)); + this.dataProvider.setDataValue(4, 6, BigDecimal.valueOf(3.6d)); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + this.selectionLayer.selectCell(4, 6, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(BigDecimal.valueOf(1.2d), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(BigDecimal.valueOf(2.4d), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(BigDecimal.valueOf(3.6d), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(BigDecimal.valueOf(4.8d), this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(BigDecimal.valueOf(6d), this.selectionLayer.getDataValueByPosition(4, 8)); + assertEquals(BigDecimal.valueOf(7.2d), this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @SuppressWarnings("deprecation") + @Test + public void testMultiCellSameDiffDateValueDragDown() { + this.dataProvider.setDataValue(4, 4, new Date(2015, 9, 2)); + this.dataProvider.setDataValue(4, 5, new Date(2015, 9, 5)); + this.dataProvider.setDataValue(4, 6, new Date(2015, 9, 8)); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + this.selectionLayer.selectCell(4, 6, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(new Date(2015, 9, 2), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(new Date(2015, 9, 5), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(new Date(2015, 9, 8), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(new Date(2015, 9, 11), this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(new Date(2015, 9, 14), this.selectionLayer.getDataValueByPosition(4, 8)); + assertEquals(new Date(2015, 9, 17), this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @SuppressWarnings("deprecation") + @Test + public void testMultiCellSameDiffDateYearValueDragDown() { + this.dataProvider.setDataValue(4, 4, new Date(2002, 9, 2)); + this.dataProvider.setDataValue(4, 5, new Date(2004, 9, 5)); + this.dataProvider.setDataValue(4, 6, new Date(2006, 9, 8)); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + this.selectionLayer.selectCell(4, 6, false, true); + + this.natTable.getConfigRegistry().registerConfigAttribute( + FillHandleConfigAttributes.INCREMENT_DATE_FIELD, + Calendar.YEAR); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(new Date(2002, 9, 2), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(new Date(2004, 9, 5), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(new Date(2006, 9, 8), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(new Date(2008, 9, 2), this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(new Date(2010, 9, 5), this.selectionLayer.getDataValueByPosition(4, 8)); + assertEquals(new Date(2012, 9, 8), this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testMultiCellSameDiffByteValueDragRight() { + this.dataProvider.setDataValue(4, 4, Byte.valueOf("1")); + this.dataProvider.setDataValue(5, 4, Byte.valueOf("3")); + this.dataProvider.setDataValue(6, 4, Byte.valueOf("5")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(5, 4, false, true); + this.selectionLayer.selectCell(6, 4, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 6, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals(Byte.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Byte.valueOf("3"), this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(Byte.valueOf("5"), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals(Byte.valueOf("7"), this.selectionLayer.getDataValueByPosition(7, 4)); + assertEquals(Byte.valueOf("9"), this.selectionLayer.getDataValueByPosition(8, 4)); + assertEquals(Byte.valueOf("11"), this.selectionLayer.getDataValueByPosition(9, 4)); + } + + @Test + public void testMultiCellSameDiffShortValueDragRight() { + this.dataProvider.setDataValue(4, 4, Short.valueOf("1")); + this.dataProvider.setDataValue(5, 4, Short.valueOf("3")); + this.dataProvider.setDataValue(6, 4, Short.valueOf("5")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(5, 4, false, true); + this.selectionLayer.selectCell(6, 4, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 6, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals(Short.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Short.valueOf("3"), this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(Short.valueOf("5"), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals(Short.valueOf("7"), this.selectionLayer.getDataValueByPosition(7, 4)); + assertEquals(Short.valueOf("9"), this.selectionLayer.getDataValueByPosition(8, 4)); + assertEquals(Short.valueOf("11"), this.selectionLayer.getDataValueByPosition(9, 4)); + } + + @Test + public void testMultiCellSameDiffLongValueDragRight() { + this.dataProvider.setDataValue(4, 4, Long.valueOf("1")); + this.dataProvider.setDataValue(5, 4, Long.valueOf("3")); + this.dataProvider.setDataValue(6, 4, Long.valueOf("5")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(5, 4, false, true); + this.selectionLayer.selectCell(6, 4, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 6, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals(Long.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Long.valueOf("3"), this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(Long.valueOf("5"), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals(Long.valueOf("7"), this.selectionLayer.getDataValueByPosition(7, 4)); + assertEquals(Long.valueOf("9"), this.selectionLayer.getDataValueByPosition(8, 4)); + assertEquals(Long.valueOf("11"), this.selectionLayer.getDataValueByPosition(9, 4)); + } + + @Test + public void testMultiCellSameDiffFloatValueDragRight() { + this.dataProvider.setDataValue(4, 4, Float.valueOf("1.3")); + this.dataProvider.setDataValue(5, 4, Float.valueOf("2.6")); + this.dataProvider.setDataValue(6, 4, Float.valueOf("3.9")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(5, 4, false, true); + this.selectionLayer.selectCell(6, 4, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 6, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals(Float.valueOf("1.3"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Float.valueOf("2.6"), this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(Float.valueOf("3.9"), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals(Float.valueOf("5.2"), this.selectionLayer.getDataValueByPosition(7, 4)); + assertEquals(Float.valueOf("6.5"), this.selectionLayer.getDataValueByPosition(8, 4)); + assertEquals(Float.valueOf("7.8"), this.selectionLayer.getDataValueByPosition(9, 4)); + } + + @Test + public void testMultiCellSameDiffDoubleValueDragRight() { + this.dataProvider.setDataValue(4, 4, Double.valueOf("1.3")); + this.dataProvider.setDataValue(5, 4, Double.valueOf("2.6")); + this.dataProvider.setDataValue(6, 4, Double.valueOf("3.9")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(5, 4, false, true); + this.selectionLayer.selectCell(6, 4, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 6, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals(Double.valueOf("1.3"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Double.valueOf("2.6"), this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(Double.valueOf("3.9"), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals(Double.valueOf("5.2"), this.selectionLayer.getDataValueByPosition(7, 4)); + assertEquals(Double.valueOf("6.5"), this.selectionLayer.getDataValueByPosition(8, 4)); + assertEquals(Double.valueOf("7.8"), this.selectionLayer.getDataValueByPosition(9, 4)); + } + + @Test + public void testMultiCellSameDiffBigIntegerValueDragRight() { + this.dataProvider.setDataValue(4, 4, BigInteger.valueOf(1)); + this.dataProvider.setDataValue(5, 4, BigInteger.valueOf(3)); + this.dataProvider.setDataValue(6, 4, BigInteger.valueOf(5)); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(5, 4, false, true); + this.selectionLayer.selectCell(6, 4, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 6, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals(BigInteger.valueOf(1), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(BigInteger.valueOf(3), this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(BigInteger.valueOf(5), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals(BigInteger.valueOf(7), this.selectionLayer.getDataValueByPosition(7, 4)); + assertEquals(BigInteger.valueOf(9), this.selectionLayer.getDataValueByPosition(8, 4)); + assertEquals(BigInteger.valueOf(11), this.selectionLayer.getDataValueByPosition(9, 4)); + } + + @Test + public void testMultiCellSameDiffBigDecimalValueDragRight() { + this.dataProvider.setDataValue(4, 4, BigDecimal.valueOf(1.2d)); + this.dataProvider.setDataValue(5, 4, BigDecimal.valueOf(2.4d)); + this.dataProvider.setDataValue(6, 4, BigDecimal.valueOf(3.6d)); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(5, 4, false, true); + this.selectionLayer.selectCell(6, 4, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 6, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals(BigDecimal.valueOf(1.2d), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(BigDecimal.valueOf(2.4d), this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(BigDecimal.valueOf(3.6d), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals(BigDecimal.valueOf(4.8d), this.selectionLayer.getDataValueByPosition(7, 4)); + assertEquals(BigDecimal.valueOf(6d), this.selectionLayer.getDataValueByPosition(8, 4)); + assertEquals(BigDecimal.valueOf(7.2d), this.selectionLayer.getDataValueByPosition(9, 4)); + } + + @SuppressWarnings("deprecation") + @Test + public void testMultiCellSameDiffDateValueDragRight() { + this.dataProvider.setDataValue(4, 4, new Date(2002, 9, 2)); + this.dataProvider.setDataValue(5, 4, new Date(2002, 9, 5)); + this.dataProvider.setDataValue(6, 4, new Date(2002, 9, 8)); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(5, 4, false, true); + this.selectionLayer.selectCell(6, 4, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 6, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + assertEquals(new Date(2002, 9, 2), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(new Date(2002, 9, 5), this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(new Date(2002, 9, 8), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals(new Date(2002, 9, 11), this.selectionLayer.getDataValueByPosition(7, 4)); + assertEquals(new Date(2002, 9, 14), this.selectionLayer.getDataValueByPosition(8, 4)); + assertEquals(new Date(2002, 9, 17), this.selectionLayer.getDataValueByPosition(9, 4)); + } + + @Test + public void testMultiCellDifferentIntegerValueDragDown() { + this.dataProvider.setDataValue(4, 4, Integer.valueOf("1")); + this.dataProvider.setDataValue(4, 5, Integer.valueOf("2")); + this.dataProvider.setDataValue(4, 6, Integer.valueOf("4")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + this.selectionLayer.selectCell(4, 6, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + // as there is no common diff value in the cells we simply perform a + // copy operation + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Integer.valueOf("2"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Integer.valueOf("4"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(Integer.valueOf("2"), this.selectionLayer.getDataValueByPosition(4, 8)); + assertEquals(Integer.valueOf("4"), this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testMultiCellIntegerValueDragDown() { + // column 4 simple series + this.dataProvider.setDataValue(4, 4, Integer.valueOf("1")); + this.dataProvider.setDataValue(4, 5, Integer.valueOf("2")); + this.dataProvider.setDataValue(4, 6, Integer.valueOf("3")); + // column 5 calculated series + this.dataProvider.setDataValue(5, 4, Integer.valueOf("2")); + this.dataProvider.setDataValue(5, 5, Integer.valueOf("4")); + this.dataProvider.setDataValue(5, 6, Integer.valueOf("6")); + // column 6 incontiguous + this.dataProvider.setDataValue(6, 4, Integer.valueOf("1")); + this.dataProvider.setDataValue(6, 5, Integer.valueOf("2")); + this.dataProvider.setDataValue(6, 6, Integer.valueOf("4")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(6, 6, true, false); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 3, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + // simple series + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Integer.valueOf("2"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Integer.valueOf("3"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Integer.valueOf("4"), this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(Integer.valueOf("5"), this.selectionLayer.getDataValueByPosition(4, 8)); + assertEquals(Integer.valueOf("6"), this.selectionLayer.getDataValueByPosition(4, 9)); + + // series with 2 difference + assertEquals(Integer.valueOf("2"), this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(Integer.valueOf("4"), this.selectionLayer.getDataValueByPosition(5, 5)); + assertEquals(Integer.valueOf("6"), this.selectionLayer.getDataValueByPosition(5, 6)); + assertEquals(Integer.valueOf("8"), this.selectionLayer.getDataValueByPosition(5, 7)); + assertEquals(Integer.valueOf("10"), this.selectionLayer.getDataValueByPosition(5, 8)); + assertEquals(Integer.valueOf("12"), this.selectionLayer.getDataValueByPosition(5, 9)); + + // as there is no common diff value in the cells we simply perform a + // copy operation + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals(Integer.valueOf("2"), this.selectionLayer.getDataValueByPosition(6, 5)); + assertEquals(Integer.valueOf("4"), this.selectionLayer.getDataValueByPosition(6, 6)); + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(6, 7)); + assertEquals(Integer.valueOf("2"), this.selectionLayer.getDataValueByPosition(6, 8)); + assertEquals(Integer.valueOf("4"), this.selectionLayer.getDataValueByPosition(6, 9)); + } + + @Test + public void testMultiCellIntegerValueDragRight() { + // column 4 simple series + this.dataProvider.setDataValue(4, 4, Integer.valueOf("1")); + this.dataProvider.setDataValue(5, 4, Integer.valueOf("2")); + this.dataProvider.setDataValue(6, 4, Integer.valueOf("3")); + // column 5 calculated series + this.dataProvider.setDataValue(4, 5, Integer.valueOf("2")); + this.dataProvider.setDataValue(5, 5, Integer.valueOf("4")); + this.dataProvider.setDataValue(6, 5, Integer.valueOf("6")); + // column 6 incontiguous + this.dataProvider.setDataValue(4, 6, Integer.valueOf("1")); + this.dataProvider.setDataValue(5, 6, Integer.valueOf("2")); + this.dataProvider.setDataValue(6, 6, Integer.valueOf("4")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(6, 6, true, false); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 6, 3)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + // simple series + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Integer.valueOf("2"), this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(Integer.valueOf("3"), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals(Integer.valueOf("4"), this.selectionLayer.getDataValueByPosition(7, 4)); + assertEquals(Integer.valueOf("5"), this.selectionLayer.getDataValueByPosition(8, 4)); + assertEquals(Integer.valueOf("6"), this.selectionLayer.getDataValueByPosition(9, 4)); + + // series with 2 difference + assertEquals(Integer.valueOf("2"), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Integer.valueOf("4"), this.selectionLayer.getDataValueByPosition(5, 5)); + assertEquals(Integer.valueOf("6"), this.selectionLayer.getDataValueByPosition(6, 5)); + assertEquals(Integer.valueOf("8"), this.selectionLayer.getDataValueByPosition(7, 5)); + assertEquals(Integer.valueOf("10"), this.selectionLayer.getDataValueByPosition(8, 5)); + assertEquals(Integer.valueOf("12"), this.selectionLayer.getDataValueByPosition(9, 5)); + + // as there is no common diff value in the cells we simply perform a + // copy operation + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(Integer.valueOf("2"), this.selectionLayer.getDataValueByPosition(5, 6)); + assertEquals(Integer.valueOf("4"), this.selectionLayer.getDataValueByPosition(6, 6)); + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(7, 6)); + assertEquals(Integer.valueOf("2"), this.selectionLayer.getDataValueByPosition(8, 6)); + assertEquals(Integer.valueOf("4"), this.selectionLayer.getDataValueByPosition(9, 6)); + } + + @Test + public void testByteNullCellValueDragDown() { + this.dataProvider.setDataValue(4, 4, Byte.valueOf("1")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Byte.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Byte.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(Byte.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 8)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testShortNullCellValueDragDown() { + this.dataProvider.setDataValue(4, 4, Short.valueOf("1")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Short.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Short.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(Short.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 8)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testIntegerNullCellValueDragDown() { + this.dataProvider.setDataValue(4, 4, Integer.valueOf("1")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 8)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testLongNullCellValueDragDown() { + this.dataProvider.setDataValue(4, 4, Long.valueOf("1")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Long.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Long.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(Long.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 8)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testFloatNullCellValueDragDown() { + this.dataProvider.setDataValue(4, 4, Float.valueOf("1")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Float.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Float.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(Float.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 8)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testDoubleNullCellValueDragDown() { + this.dataProvider.setDataValue(4, 4, Double.valueOf("1")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(Double.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Double.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(Double.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 8)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testBigIntegerNullCellValueDragDown() { + this.dataProvider.setDataValue(4, 4, BigInteger.valueOf(1)); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(BigInteger.valueOf(1), this.selectionLayer.getDataValueByPosition(4, 4)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(BigInteger.valueOf(1), this.selectionLayer.getDataValueByPosition(4, 6)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(BigInteger.valueOf(1), this.selectionLayer.getDataValueByPosition(4, 8)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testBigDecimalNullCellValueDragDown() { + this.dataProvider.setDataValue(4, 4, BigDecimal.valueOf(1)); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(BigDecimal.valueOf(1), this.selectionLayer.getDataValueByPosition(4, 4)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(BigDecimal.valueOf(1), this.selectionLayer.getDataValueByPosition(4, 6)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(BigDecimal.valueOf(1), this.selectionLayer.getDataValueByPosition(4, 8)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @SuppressWarnings("deprecation") + @Test + public void testDateNullCellValueDragDown() { + this.dataProvider.setDataValue(4, 4, new Date(2015, 9, 13)); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 6)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals(new Date(2015, 9, 13), this.selectionLayer.getDataValueByPosition(4, 4)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(new Date(2015, 9, 13), this.selectionLayer.getDataValueByPosition(4, 6)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 7)); + assertEquals(new Date(2015, 9, 13), this.selectionLayer.getDataValueByPosition(4, 8)); + assertNull(this.selectionLayer.getDataValueByPosition(4, 9)); + } + + @Test + public void testMultiCellDifferentTypesDragDown() { + this.dataProvider.setDataValue(4, 4, Float.valueOf("3.5")); + this.dataProvider.setDataValue(4, 5, BigInteger.valueOf(1)); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + // result should be a copy because of different data types + assertEquals(Float.valueOf("3.5"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(BigInteger.valueOf(1), this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals(Float.valueOf("3.5"), this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals(BigInteger.valueOf(1), this.selectionLayer.getDataValueByPosition(4, 7)); + } + + @Test + public void testMultiCellDifferentTypesDragRight() { + this.dataProvider.setDataValue(4, 4, Integer.valueOf("1")); + this.dataProvider.setDataValue(5, 4, Float.valueOf("3.5")); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(5, 4, false, true); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 4, 1)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.RIGHT, this.natTable.getConfigRegistry())); + + // result should be a copy because of different data types + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals(Float.valueOf("3.5"), this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(Integer.valueOf("1"), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals(Float.valueOf("3.5"), this.selectionLayer.getDataValueByPosition(7, 4)); + } + +} diff --git a/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/formula/FormulaFillHandlePasteTest.java b/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/formula/FormulaFillHandlePasteTest.java new file mode 100644 index 00000000..2fcb7544 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/formula/FormulaFillHandlePasteTest.java @@ -0,0 +1,269 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.formula; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.math.BigDecimal; + +import org.eclipse.nebula.widgets.nattable.NatTable; +import org.eclipse.nebula.widgets.nattable.config.AbstractRegistryConfiguration; +import org.eclipse.nebula.widgets.nattable.config.EditableRule; +import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; +import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard; +import org.eclipse.nebula.widgets.nattable.copy.command.CopyDataToClipboardCommand; +import org.eclipse.nebula.widgets.nattable.copy.command.InternalCopyDataCommandHandler; +import org.eclipse.nebula.widgets.nattable.data.IDataProvider; +import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes; +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.formula.command.FormulaFillHandlePasteCommandHandler; +import org.eclipse.nebula.widgets.nattable.formula.config.DefaultFormulaConfiguration; +import org.eclipse.nebula.widgets.nattable.layer.DataLayer; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum; +import org.eclipse.nebula.widgets.nattable.test.fixture.NatTableFixture; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class FormulaFillHandlePasteTest { + + IDataProvider dataProvider = new TwoDimensionalArrayDataProvider(new String[10][10]); + FormulaDataProvider formulaDataProvider = new FormulaDataProvider(this.dataProvider); + SelectionLayer selectionLayer = new SelectionLayer(new DataLayer(this.formulaDataProvider)); + NatTable natTable = new NatTableFixture(this.selectionLayer, false); + + @Before + public void setup() { + InternalCellClipboard clipboard = new InternalCellClipboard(); + this.selectionLayer.registerCommandHandler( + new InternalCopyDataCommandHandler(this.selectionLayer, clipboard)); + this.selectionLayer.registerCommandHandler( + new FormulaFillHandlePasteCommandHandler(this.selectionLayer, clipboard, this.formulaDataProvider)); + + this.natTable.addConfiguration(new DefaultFormulaConfiguration( + this.formulaDataProvider, + this.selectionLayer, + clipboard)); + + this.natTable.addConfiguration(new AbstractRegistryConfiguration() { + + @Override + public void configureRegistry(IConfigRegistry configRegistry) { + configRegistry.registerConfigAttribute( + EditConfigAttributes.CELL_EDITABLE_RULE, + EditableRule.ALWAYS_EDITABLE); + } + }); + this.natTable.configure(); + } + + @After + public void tearDown() { + this.selectionLayer.clear(); + this.selectionLayer.setFillHandleRegion(null); + } + + @Test + public void testSingleCellDragOneDown() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.COPY, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 5)); + + testCellStates(new Point(4, 4), new Point(4, 5)); + } + + @Test + public void testSingleCellSeriesStringDragOneDown() { + this.dataProvider.setDataValue(4, 4, "Simpson"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals("Simpson", this.selectionLayer.getDataValueByPosition(4, 5)); + + testCellStates(new Point(4, 4), new Point(4, 5)); + } + + @Test + public void testSingleNumberCellDragDown() { + this.dataProvider.setDataValue(4, 4, "1"); + + this.selectionLayer.setSelectedCell(4, 4); + + testCellStates(new Point(4, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals("1", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("2", this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals("3", this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals("4", this.selectionLayer.getDataValueByPosition(4, 7)); + + testCellStates(new Point(4, 4), new Point(4, 5), new Point(4, 6), new Point(4, 7)); + } + + @Test + public void testMultiNumberCellDragDown() { + this.dataProvider.setDataValue(4, 4, "2"); + this.dataProvider.setDataValue(4, 5, "4"); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(4, 5, false, true); + + testCellStates(new Point(4, 4), new Point(4, 5)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 1, 4)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals("2", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("4", this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals("6", this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals("8", this.selectionLayer.getDataValueByPosition(4, 7)); + + testCellStates(new Point(4, 4), new Point(4, 5), new Point(4, 6), new Point(4, 7)); + } + + @Test + public void testFunctionCellDragDown() { + this.dataProvider.setDataValue(4, 4, "2"); + this.dataProvider.setDataValue(5, 4, "21"); + this.dataProvider.setDataValue(6, 4, "=E5*F5"); + this.dataProvider.setDataValue(4, 5, "3"); + this.dataProvider.setDataValue(5, 5, "22"); + + this.selectionLayer.selectCell(6, 4, false, true); + + testCellStates(new Point(4, 4), new Point(5, 4), new Point(6, 4), + new Point(4, 5), new Point(5, 5)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(6, 4, 1, 2)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals("2", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("21", this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(new BigDecimal("42"), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals("3", this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals("22", this.selectionLayer.getDataValueByPosition(5, 5)); + assertEquals(new BigDecimal("66"), this.selectionLayer.getDataValueByPosition(6, 5)); + + testCellStates(new Point(4, 4), new Point(5, 4), new Point(6, 4), + new Point(4, 5), new Point(5, 5), new Point(6, 5)); + } + + @Test + public void testFullFunctionCellDragDown() { + this.dataProvider.setDataValue(4, 4, "2"); + this.dataProvider.setDataValue(5, 4, "21"); + this.dataProvider.setDataValue(6, 4, "=E5*F5"); + + assertEquals(new BigDecimal("42"), this.formulaDataProvider.getDataValue(6, 4)); + + this.selectionLayer.selectCell(4, 4, false, true); + this.selectionLayer.selectCell(5, 4, false, true); + this.selectionLayer.selectCell(6, 4, false, true); + + testCellStates(new Point(4, 4), new Point(5, 4), new Point(6, 4)); + + this.natTable.doCommand(new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + this.natTable.getConfigRegistry())); + + this.selectionLayer.setFillHandleRegion(new Rectangle(4, 4, 3, 3)); + this.natTable.doCommand( + new FillHandlePasteCommand(FillHandleOperation.SERIES, MoveDirectionEnum.DOWN, this.natTable.getConfigRegistry())); + + assertEquals("2", this.selectionLayer.getDataValueByPosition(4, 4)); + assertEquals("21", this.selectionLayer.getDataValueByPosition(5, 4)); + assertEquals(new BigDecimal("42"), this.selectionLayer.getDataValueByPosition(6, 4)); + assertEquals("3", this.selectionLayer.getDataValueByPosition(4, 5)); + assertEquals("22", this.selectionLayer.getDataValueByPosition(5, 5)); + assertEquals(new BigDecimal("66"), this.selectionLayer.getDataValueByPosition(6, 5)); + assertEquals("4", this.selectionLayer.getDataValueByPosition(4, 6)); + assertEquals("23", this.selectionLayer.getDataValueByPosition(5, 6)); + assertEquals(new BigDecimal("92"), this.selectionLayer.getDataValueByPosition(6, 6)); + + testCellStates(new Point(4, 4), new Point(5, 4), new Point(6, 4), + new Point(4, 5), new Point(5, 5), new Point(6, 5), + new Point(4, 6), new Point(5, 6), new Point(6, 6)); + } + + private void testCellStates(Point... nonNull) { + for (int i = 0; i < this.dataProvider.getColumnCount(); i++) { + for (int j = 0; j < this.dataProvider.getRowCount(); j++) { + + boolean check = true; + for (Point p : nonNull) { + if ((i == p.x) && (j == p.y)) { + check = false; + break; + } + } + if (check) { + assertNull("Position " + i + "/" + j + " is not null", this.selectionLayer.getDataValueByPosition(i, j)); + } else { + assertNotNull("Position " + i + "/" + j + " is null", this.selectionLayer.getDataValueByPosition(i, j)); + } + } + } + } + +} diff --git a/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/selection/SelectionUtilsTest.java b/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/selection/SelectionUtilsTest.java new file mode 100644 index 00000000..e759d47e --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/selection/SelectionUtilsTest.java @@ -0,0 +1,180 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.selection; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.eclipse.nebula.widgets.nattable.layer.DataLayer; +import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; +import org.eclipse.nebula.widgets.nattable.test.fixture.data.DataProviderFixture; +import org.junit.Test; + +public class SelectionUtilsTest { + + @Test + public void testConsecutivePositions() { + int[] test = new int[] { 1, 2, 3, 4, 5 }; + assertTrue(SelectionUtils.isConsecutive(test)); + } + + @Test + public void testDuplicateConsecutivePositions() { + int[] test = new int[] { 1, 1, 2, 3, 4, 5 }; + assertFalse(SelectionUtils.isConsecutive(test)); + } + + @Test + public void testGapConsecutivePositions() { + int[] test = new int[] { 1, 3, 4, 5 }; + assertFalse(SelectionUtils.isConsecutive(test)); + } + + @Test + public void testEmptyArray() { + int[] test = new int[] {}; + assertTrue(SelectionUtils.isConsecutive(test)); + } + + @Test + public void testOneEntryArray() { + int[] test = new int[] { 42 }; + assertTrue(SelectionUtils.isConsecutive(test)); + } + + @Test + public void testGetBottomRightSelectAll() { + DataLayer dataLayer = new DataLayer(new DataProviderFixture(10, 10)); + SelectionLayer selectionLayer = new SelectionLayer(dataLayer); + + // select all cells + selectionLayer.selectAll(); + + ILayerCell bottomRight = SelectionUtils.getBottomRightCellInSelection(selectionLayer); + assertEquals(9, bottomRight.getColumnPosition()); + assertEquals(9, bottomRight.getRowPosition()); + } + + @Test + public void testGetBottomRightSelectOne() { + DataLayer dataLayer = new DataLayer(new DataProviderFixture(10, 10)); + SelectionLayer selectionLayer = new SelectionLayer(dataLayer); + + // select one cell + selectionLayer.selectCell(5, 5, false, false); + + ILayerCell bottomRight = SelectionUtils.getBottomRightCellInSelection(selectionLayer); + assertEquals(5, bottomRight.getColumnPosition()); + assertEquals(5, bottomRight.getRowPosition()); + } + + @Test + public void testGetBottomRightSelectNothing() { + DataLayer dataLayer = new DataLayer(new DataProviderFixture(10, 10)); + SelectionLayer selectionLayer = new SelectionLayer(dataLayer); + + ILayerCell bottomRight = SelectionUtils.getBottomRightCellInSelection(selectionLayer); + assertNull(bottomRight); + } + + @Test + public void testGetBottomRightSelectRegion() { + DataLayer dataLayer = new DataLayer(new DataProviderFixture(10, 10)); + SelectionLayer selectionLayer = new SelectionLayer(dataLayer); + + // select region + selectionLayer.selectRegion(2, 2, 3, 3); + + ILayerCell bottomRight = SelectionUtils.getBottomRightCellInSelection(selectionLayer); + assertEquals(4, bottomRight.getColumnPosition()); + assertEquals(4, bottomRight.getRowPosition()); + } + + @Test + public void testGetBottomRightSelectRegionDeselectMiddle() { + DataLayer dataLayer = new DataLayer(new DataProviderFixture(10, 10)); + SelectionLayer selectionLayer = new SelectionLayer(dataLayer); + + // select region + selectionLayer.selectRegion(2, 2, 3, 3); + + // deselect a cell + selectionLayer.clearSelection(3, 3); + + ILayerCell bottomRight = SelectionUtils.getBottomRightCellInSelection(selectionLayer); + assertNull(bottomRight); + } + + @Test + public void testGetBottomRightSelectRegionDeselectTopEdge() { + DataLayer dataLayer = new DataLayer(new DataProviderFixture(10, 10)); + SelectionLayer selectionLayer = new SelectionLayer(dataLayer); + + // select region + selectionLayer.selectRegion(2, 2, 3, 3); + + // deselect a cell + selectionLayer.clearSelection(2, 2); + + ILayerCell bottomRight = SelectionUtils.getBottomRightCellInSelection(selectionLayer); + assertNull(bottomRight); + } + + @Test + public void testGetBottomRightSelectRegionDeselectMiddleBottomEdge() { + DataLayer dataLayer = new DataLayer(new DataProviderFixture(10, 10)); + SelectionLayer selectionLayer = new SelectionLayer(dataLayer); + + // select region + selectionLayer.selectRegion(2, 2, 3, 3); + + // deselect a cell + selectionLayer.clearSelection(4, 4); + + ILayerCell bottomRight = SelectionUtils.getBottomRightCellInSelection(selectionLayer); + assertNull(bottomRight); + } + + @Test + public void testGetBottomRightSelectDifferentRows() { + DataLayer dataLayer = new DataLayer(new DataProviderFixture(10, 10)); + SelectionLayer selectionLayer = new SelectionLayer(dataLayer); + + // select cells for same columns in non consecutive rows + selectionLayer.selectRegion(2, 2, 3, 1); + selectionLayer.selectRegion(4, 4, 3, 1); + + assertEquals(6, selectionLayer.getSelectedCells().size()); + + ILayerCell bottomRight = SelectionUtils.getBottomRightCellInSelection(selectionLayer); + assertNull(bottomRight); + } + + @Test + public void testGetBottomRightSelectDifferentColumns() { + DataLayer dataLayer = new DataLayer(new DataProviderFixture(10, 10)); + SelectionLayer selectionLayer = new SelectionLayer(dataLayer); + + // select cells for same columns in non consecutive rows + selectionLayer.selectRegion(2, 2, 1, 3); + selectionLayer.selectRegion(4, 4, 1, 3); + + assertEquals(6, selectionLayer.getSelectedCells().size()); + + ILayerCell bottomRight = SelectionUtils.getBottomRightCellInSelection(selectionLayer); + assertNull(bottomRight); + } + +} diff --git a/org.eclipse.nebula.widgets.nattable.core/META-INF/MANIFEST.MF b/org.eclipse.nebula.widgets.nattable.core/META-INF/MANIFEST.MF index fb4cf376..9787b58e 100644 --- a/org.eclipse.nebula.widgets.nattable.core/META-INF/MANIFEST.MF +++ b/org.eclipse.nebula.widgets.nattable.core/META-INF/MANIFEST.MF @@ -39,6 +39,11 @@ Export-Package: org.eclipse.nebula.widgets.nattable;version="1.4.0", org.eclipse.nebula.widgets.nattable.export.command;version="1.4.0", org.eclipse.nebula.widgets.nattable.export.config;version="1.4.0", org.eclipse.nebula.widgets.nattable.export.excel;version="1.4.0", + org.eclipse.nebula.widgets.nattable.fillhandle;version="1.4.0", + org.eclipse.nebula.widgets.nattable.fillhandle.action;version="1.4.0", + org.eclipse.nebula.widgets.nattable.fillhandle.command;version="1.4.0", + org.eclipse.nebula.widgets.nattable.fillhandle.config;version="1.4.0", + org.eclipse.nebula.widgets.nattable.fillhandle.event;version="1.4.0", org.eclipse.nebula.widgets.nattable.filterrow;version="1.4.0", org.eclipse.nebula.widgets.nattable.filterrow.action;version="1.4.0", org.eclipse.nebula.widgets.nattable.filterrow.combobox;version="1.4.0", diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/NatTable.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/NatTable.java index eda241bf..ca7855c0 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/NatTable.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/NatTable.java @@ -32,6 +32,7 @@ import org.eclipse.nebula.widgets.nattable.conflation.EventConflaterChain; import org.eclipse.nebula.widgets.nattable.conflation.IEventConflater; import org.eclipse.nebula.widgets.nattable.conflation.VisualChangeEventConflater; import org.eclipse.nebula.widgets.nattable.coordinate.Range; +import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard; import org.eclipse.nebula.widgets.nattable.edit.ActiveCellEditorRegistry; import org.eclipse.nebula.widgets.nattable.edit.CellEditorCreatedEvent; import org.eclipse.nebula.widgets.nattable.edit.editor.ICellEditor; @@ -168,6 +169,12 @@ public class NatTable extends Canvas implements ILayer, PaintListener, IClientAr private ThemeManager themeManager; /** + * The {@link InternalCellClipboard} that is used for internal copy & + * paste functionality. + */ + private InternalCellClipboard clipboard = new InternalCellClipboard(); + + /** * The active cell editor or {@code null} if there is no one. */ private ICellEditor activeCellEditor; @@ -1122,6 +1129,16 @@ public class NatTable extends Canvas implements ILayer, PaintListener, IClientAr doCommand(new VisualRefreshCommand()); } + /** + * + * @return The {@link InternalCellClipboard} that is used for internal copy + * & paste functionality. + * @since 1.4 + */ + public InternalCellClipboard getInternalCellClipboard() { + return this.clipboard; + } + // Editor /** * Returns the active cell editor that is currently open or {@code null} if diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/action/FormulaPasteDataAction.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/copy/action/PasteDataAction.java index 4f15bae5..c248306d 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/action/FormulaPasteDataAction.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/copy/action/PasteDataAction.java @@ -10,23 +10,23 @@ * Dirk Fauth <dirk.fauth@googlemail.com> - Initial API and implementation * *****************************************************************************/ -package org.eclipse.nebula.widgets.nattable.formula.action; +package org.eclipse.nebula.widgets.nattable.copy.action; import org.eclipse.nebula.widgets.nattable.NatTable; -import org.eclipse.nebula.widgets.nattable.formula.command.FormulaPasteDataCommand; +import org.eclipse.nebula.widgets.nattable.copy.command.PasteDataCommand; import org.eclipse.nebula.widgets.nattable.ui.action.IKeyAction; import org.eclipse.swt.events.KeyEvent; /** - * {@link IKeyAction} that triggers the {@link FormulaPasteDataCommand}. + * {@link IKeyAction} that triggers the {@link PasteDataCommand}. * * @since 1.4 */ -public class FormulaPasteDataAction implements IKeyAction { +public class PasteDataAction implements IKeyAction { @Override public void run(NatTable natTable, KeyEvent event) { - natTable.doCommand(new FormulaPasteDataCommand(natTable.getConfigRegistry())); + natTable.doCommand(new PasteDataCommand(natTable.getConfigRegistry())); } } diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/action/PasteOrMoveSelectionAction.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/copy/action/PasteOrMoveSelectionAction.java index 4bd09b67..51522447 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/action/PasteOrMoveSelectionAction.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/copy/action/PasteOrMoveSelectionAction.java @@ -10,19 +10,19 @@ * Dirk Fauth <dirk.fauth@googlemail.com> - Initial API and implementation * *****************************************************************************/ -package org.eclipse.nebula.widgets.nattable.formula.action; +package org.eclipse.nebula.widgets.nattable.copy.action; import org.eclipse.nebula.widgets.nattable.NatTable; import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard; -import org.eclipse.nebula.widgets.nattable.formula.command.FormulaPasteDataCommand; +import org.eclipse.nebula.widgets.nattable.copy.command.PasteDataCommand; import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum; import org.eclipse.nebula.widgets.nattable.selection.action.MoveSelectionAction; import org.eclipse.swt.events.KeyEvent; /** - * Action implementation that performs a {@link FormulaPasteDataCommand} if - * there are values in the {@link InternalCellClipboard}, otherwise it performs - * a selection movement. + * Action implementation that performs a {@link PasteDataCommand} if there are + * values in the {@link InternalCellClipboard}, otherwise it performs a + * selection movement. * * @since 1.4 */ @@ -59,11 +59,10 @@ public class PasteOrMoveSelectionAction extends MoveSelectionAction { public void run(NatTable natTable, KeyEvent event) { if (this.clipboard.getCopiedCells() != null) { - natTable.doCommand(new FormulaPasteDataCommand(natTable.getConfigRegistry())); + natTable.doCommand(new PasteDataCommand(natTable.getConfigRegistry())); this.clipboard.clear(); - } - else { + } else { super.run(natTable, event); } } diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/copy/command/InternalCopyDataCommandHandler.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/copy/command/InternalCopyDataCommandHandler.java new file mode 100644 index 00000000..26873924 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/copy/command/InternalCopyDataCommandHandler.java @@ -0,0 +1,75 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.copy.command; + +import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; +import org.eclipse.nebula.widgets.nattable.selection.SelectionUtils; + +/** + * Specialized {@link CopyDataCommandHandler} that stores the copied cells in + * the {@link InternalCellClipboard} so it can be pasted within NatTable. + * + * @since 1.4 + */ +public class InternalCopyDataCommandHandler extends CopyDataCommandHandler { + + protected InternalCellClipboard clipboard; + + /** + * Creates an instance that only checks the {@link SelectionLayer} for the + * data to add to the system clipboard and the given + * {@link InternalCellClipboard}. + * + * @param selectionLayer + * The {@link SelectionLayer} within the NatTable. Can not be + * <code>null</code>. + * @param clipboard + * The {@link InternalCellClipboard} that should be used for + * copy/paste operations within a NatTable instance. + */ + public InternalCopyDataCommandHandler(SelectionLayer selectionLayer, InternalCellClipboard clipboard) { + super(selectionLayer); + this.clipboard = clipboard; + } + + @Override + public boolean doCommand(CopyDataToClipboardCommand command) { + // copy to clipboard + super.doCommand(command); + + // only copy if contiguous cells + if (SelectionUtils.hasConsecutiveSelection(this.selectionLayer)) { + preInternalCopy(); + + // remember cells to copy to support paste + this.clipboard.setCopiedCells(assembleCopiedDataStructure()); + + postInternalCopy(); + } + + return true; + } + + /** + * Perform actions prior copying values to the internal clipboard. E.g. + * disabling formula evaluation. + */ + protected void preInternalCopy() {} + + /** + * Perform actions after copying values to the internal clipboard. E.g. + * enabling formula evaluation. + */ + protected void postInternalCopy() {} +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/copy/command/InternalPasteDataCommandHandler.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/copy/command/InternalPasteDataCommandHandler.java new file mode 100644 index 00000000..e11d8dc5 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/copy/command/InternalPasteDataCommandHandler.java @@ -0,0 +1,125 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.copy.command; + +import org.eclipse.nebula.widgets.nattable.command.AbstractLayerCommandHandler; +import org.eclipse.nebula.widgets.nattable.command.ILayerCommandHandler; +import org.eclipse.nebula.widgets.nattable.coordinate.PositionCoordinate; +import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard; +import org.eclipse.nebula.widgets.nattable.edit.command.EditUtils; +import org.eclipse.nebula.widgets.nattable.edit.command.UpdateDataCommand; +import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; + +/** + * {@link ILayerCommandHandler} for handling {@link PasteDataCommand}s using the + * {@link InternalCellClipboard}. + * + * @since 1.4 + */ +public class InternalPasteDataCommandHandler extends AbstractLayerCommandHandler<PasteDataCommand> { + + protected SelectionLayer selectionLayer; + protected InternalCellClipboard clipboard; + + /** + * + * @param selectionLayer + * {@link SelectionLayer} that is needed to determine the + * position to paste the values to. + * @param clipboard + * The {@link InternalCellClipboard} that contains the values + * that should be pasted. + */ + public InternalPasteDataCommandHandler( + SelectionLayer selectionLayer, + InternalCellClipboard clipboard) { + + this.selectionLayer = selectionLayer; + this.clipboard = clipboard; + } + + @Override + protected boolean doCommand(PasteDataCommand command) { + if (this.clipboard.getCopiedCells() != null) { + + preInternalPaste(); + + PositionCoordinate coord = this.selectionLayer.getSelectionAnchor(); + int pasteColumn = coord.getColumnPosition(); + int pasteRow = coord.getRowPosition(); + + for (ILayerCell[] cells : this.clipboard.getCopiedCells()) { + for (ILayerCell cell : cells) { + if (EditUtils.isCellEditable( + this.selectionLayer, + command.configRegistry, + new PositionCoordinate(this.selectionLayer, pasteColumn, pasteRow))) { + + this.selectionLayer.doCommand( + new UpdateDataCommand( + this.selectionLayer, + pasteColumn, + pasteRow, + getPasteValue(cell, pasteColumn, pasteRow))); + } + + pasteColumn++; + + if (pasteColumn >= this.selectionLayer.getColumnCount()) { + break; + } + } + pasteRow++; + pasteColumn = coord.getColumnPosition(); + } + + postInternalPaste(); + } + return true; + } + + /** + * Returns the value that should be pasted. + * + * @param cell + * The {@link ILayerCell} from which to retrieve the value to + * paste from. + * @param pasteColumn + * The column position of the cell to paste to. + * @param pasteRow + * The row position of the cell to paste to. + * @return The value that should be pasted. + */ + protected Object getPasteValue(ILayerCell cell, int pasteColumn, int pasteRow) { + return cell.getDataValue(); + } + + /** + * Perform actions prior pasting values from the internal clipboard. E.g. + * disabling formula evaluation. + */ + protected void preInternalPaste() {} + + /** + * Perform actions after pasting values from the internal clipboard. E.g. + * enabling formula evaluation. + */ + protected void postInternalPaste() {} + + @Override + public Class<PasteDataCommand> getCommandClass() { + return PasteDataCommand.class; + } + +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/command/FormulaPasteDataCommand.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/copy/command/PasteDataCommand.java index 92ffc28f..444d800e 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/command/FormulaPasteDataCommand.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/copy/command/PasteDataCommand.java @@ -10,7 +10,7 @@ * Dirk Fauth <dirk.fauth@googlemail.com> - Initial API and implementation * *****************************************************************************/ -package org.eclipse.nebula.widgets.nattable.formula.command; +package org.eclipse.nebula.widgets.nattable.copy.command; import org.eclipse.nebula.widgets.nattable.command.AbstractContextFreeCommand; import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; @@ -20,17 +20,13 @@ import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; * * @since 1.4 * - * @see FormulaPasteDataCommandHandler + * @see InternalPasteDataCommandHandler */ -public class FormulaPasteDataCommand extends AbstractContextFreeCommand { +public class PasteDataCommand extends AbstractContextFreeCommand { - private final IConfigRegistry configRegistry; + public final IConfigRegistry configRegistry; - public FormulaPasteDataCommand(IConfigRegistry configRegistry) { + public PasteDataCommand(IConfigRegistry configRegistry) { this.configRegistry = configRegistry; } - - public IConfigRegistry getConfigRegistry() { - return this.configRegistry; - } } diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/FillHandleLayerPainter.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/FillHandleLayerPainter.java new file mode 100644 index 00000000..4d731b85 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/FillHandleLayerPainter.java @@ -0,0 +1,669 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.fillhandle; + +import org.eclipse.nebula.widgets.nattable.NatTable; +import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes; +import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; +import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard; +import org.eclipse.nebula.widgets.nattable.fillhandle.config.FillHandleConfigAttributes; +import org.eclipse.nebula.widgets.nattable.layer.ILayer; +import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; +import org.eclipse.nebula.widgets.nattable.painter.layer.ILayerPainter; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayerPainter; +import org.eclipse.nebula.widgets.nattable.style.BorderStyle; +import org.eclipse.nebula.widgets.nattable.style.BorderStyle.LineStyleEnum; +import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes; +import org.eclipse.nebula.widgets.nattable.style.DisplayMode; +import org.eclipse.nebula.widgets.nattable.style.IStyle; +import org.eclipse.nebula.widgets.nattable.style.SelectionStyleLabels; +import org.eclipse.nebula.widgets.nattable.util.GUIHelper; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Rectangle; + +/** + * Extended {@link SelectionLayerPainter} that renders an additional border + * around cells that are selected via fill handle. By default the additional + * fill handle border style is a green solid 2 pixel sized line. This + * {@link BorderStyle} can be configured via IConfigRegistry using the config + * label {@link FillHandleConfigAttributes#FILL_HANDLE_REGION_BORDER_STYLE}. + * <p> + * You can also register a different cell style for cells in the fill handle + * region by configuring a style for the label + * {@link SelectionStyleLabels#FILL_HANDLE_REGION} + * </p> + * <p> + * This {@link ILayerPainter} also renders a border around cells that are + * currently copied to the {@link InternalCellClipboard}. For this an + * {@link InternalCellClipboard} needs to be set to this painter. Note that a + * global instance of {@link InternalCellClipboard} can be retrieved via + * {@link NatTable#getInternalCellClipboard()}. + * </p> + * + * @see FillHandleConfigAttributes#FILL_HANDLE_REGION_BORDER_STYLE + * @see SelectionStyleLabels#FILL_HANDLE_REGION + * + * @since 1.4 + */ +public class FillHandleLayerPainter extends SelectionLayerPainter { + + /** + * The bounds of the current visible selection handle or <code>null</code> + * if no fill handle is currently rendered. + */ + protected Rectangle handleBounds; + + /** + * The {@link InternalCellClipboard} that is used to identify whether a cell + * is currently copied. Can be <code>null</code> to disable special + * rendering of copied cells. + */ + protected InternalCellClipboard clipboard; + + /** + * Create a SelectionLayerPainter that renders gray grid lines and uses the + * default clipping behavior. + */ + public FillHandleLayerPainter() { + super(); + } + + /** + * Create an {@link FillHandleLayerPainter} that renders grid lines in the + * specified color and uses the default clipping behavior. + * + * @param gridColor + * The color that should be used to render the grid lines. + */ + public FillHandleLayerPainter(final Color gridColor) { + super(gridColor); + } + + /** + * Create an {@link FillHandleLayerPainter} that renders gray grid lines and + * uses the specified clipping behavior. + * + * @param clipLeft + * Configure the rendering behavior when cells overlap. If set to + * <code>true</code> the left cell will be clipped, if set to + * <code>false</code> the right cell will be clipped. The default + * value is <code>false</code>. + * @param clipTop + * Configure the rendering behavior when cells overlap. If set to + * <code>true</code> the top cell will be clipped, if set to + * <code>false</code> the bottom cell will be clipped. The + * default value is <code>false</code>. + */ + public FillHandleLayerPainter(boolean clipLeft, boolean clipTop) { + this(GUIHelper.COLOR_GRAY, clipLeft, clipTop); + } + + /** + * Create an {@link FillHandleLayerPainter} that renders grid lines in the + * specified color and uses the specified clipping behavior. + * + * @param gridColor + * The color that should be used to render the grid lines. + * @param clipLeft + * Configure the rendering behavior when cells overlap. If set to + * <code>true</code> the left cell will be clipped, if set to + * <code>false</code> the right cell will be clipped. The default + * value is <code>false</code>. + * @param clipTop + * Configure the rendering behavior when cells overlap. If set to + * <code>true</code> the top cell will be clipped, if set to + * <code>false</code> the bottom cell will be clipped. The + * default value is <code>false</code>. + */ + public FillHandleLayerPainter(final Color gridColor, boolean clipLeft, boolean clipTop) { + super(gridColor, clipLeft, clipTop); + } + + /** + * Create an {@link FillHandleLayerPainter} that renders gray grid lines and + * uses the default clipping behavior. It also renders a border around + * internally copied cells. + * + * @param clipboard + * The {@link InternalCellClipboard} that stores the cells that + * are currently copied. + */ + public FillHandleLayerPainter(InternalCellClipboard clipboard) { + this.clipboard = clipboard; + } + + /** + * Create an {@link FillHandleLayerPainter} that renders grid lines in the + * specified color and uses the default clipping behavior. + * + * @param clipboard + * The {@link InternalCellClipboard} that stores the cells that + * are currently copied. + * @param gridColor + * The color that should be used to render the grid lines. + */ + public FillHandleLayerPainter(InternalCellClipboard clipboard, final Color gridColor) { + super(gridColor); + } + + /** + * Create an {@link FillHandleLayerPainter} that renders gray grid lines and + * uses the specified clipping behavior. + * + * @param clipboard + * The {@link InternalCellClipboard} that stores the cells that + * are currently copied. + * @param clipLeft + * Configure the rendering behavior when cells overlap. If set to + * <code>true</code> the left cell will be clipped, if set to + * <code>false</code> the right cell will be clipped. The default + * value is <code>false</code>. + * @param clipTop + * Configure the rendering behavior when cells overlap. If set to + * <code>true</code> the top cell will be clipped, if set to + * <code>false</code> the bottom cell will be clipped. The + * default value is <code>false</code>. + */ + public FillHandleLayerPainter(InternalCellClipboard clipboard, + boolean clipLeft, boolean clipTop) { + this(clipboard, GUIHelper.COLOR_GRAY, clipLeft, clipTop); + } + + /** + * Create an {@link FillHandleLayerPainter} that renders grid lines in the + * specified color and uses the specified clipping behavior. + * + * @param clipboard + * The {@link InternalCellClipboard} that stores the cells that + * are currently copied. + * @param gridColor + * The color that should be used to render the grid lines. + * @param clipLeft + * Configure the rendering behavior when cells overlap. If set to + * <code>true</code> the left cell will be clipped, if set to + * <code>false</code> the right cell will be clipped. The default + * value is <code>false</code>. + * @param clipTop + * Configure the rendering behavior when cells overlap. If set to + * <code>true</code> the top cell will be clipped, if set to + * <code>false</code> the bottom cell will be clipped. The + * default value is <code>false</code>. + */ + public FillHandleLayerPainter(InternalCellClipboard clipboard, final Color gridColor, + boolean clipLeft, boolean clipTop) { + super(gridColor, clipLeft, clipTop); + this.clipboard = clipboard; + } + + @Override + public void paintLayer( + ILayer natLayer, GC gc, + int xOffset, int yOffset, Rectangle pixelRectangle, + IConfigRegistry configRegistry) { + + Rectangle positionRectangle = getPositionRectangleFromPixelRectangle(natLayer, pixelRectangle); + int columnPositionOffset = positionRectangle.x; + int rowPositionOffset = positionRectangle.y; + + super.paintLayer(natLayer, gc, xOffset, yOffset, pixelRectangle, configRegistry); + + // Save gc settings + int originalLineStyle = gc.getLineStyle(); + int originalLineWidth = gc.getLineWidth(); + Color originalForeground = gc.getForeground(); + + // Apply border settings + applyHandleBorderStyle(gc, configRegistry); + + int handleBorderWidth = gc.getLineWidth(); + int startAdjustment = (handleBorderWidth == 1) ? 1 : 0; + int endAdjustment = (handleBorderWidth == 1) ? 1 : handleBorderWidth - 1; + + ILayerCell fillHandleCell = null; + + // Draw horizontal borders + for (int columnPosition = columnPositionOffset; columnPosition < columnPositionOffset + positionRectangle.width; columnPosition++) { + + ILayerCell previousCell = null; + ILayerCell currentCell = null; + ILayerCell afterCell = null; + for (int rowPosition = rowPositionOffset; rowPosition < rowPositionOffset + positionRectangle.height; rowPosition++) { + + currentCell = natLayer.getCellByPosition(columnPosition, rowPosition); + afterCell = natLayer.getCellByPosition(columnPosition, rowPosition + 1); + + if (currentCell != null) { + Rectangle currentCellBounds = currentCell.getBounds(); + + if (isFillHandleRegion(currentCell)) { + int x0 = currentCellBounds.x; + int x1 = currentCellBounds.x + currentCellBounds.width; + + int y = currentCellBounds.y - startAdjustment; + + if (previousCell != null) { + Rectangle previousCellBounds = previousCell.getBounds(); + x0 = Math.max(x0, previousCellBounds.x); + x1 = Math.min(x1, previousCellBounds.x + previousCellBounds.width); + } + + if (previousCell == null || !isFillHandleRegion(previousCell)) { + gc.drawLine( + x0 - startAdjustment - (handleBorderWidth == 1 ? 0 : 1), + y, + x1 - startAdjustment, + y); + } + + // check after + if (afterCell == null || (!isFillHandleRegion(afterCell))) { + Rectangle cellBounds = afterCell != null ? afterCell.getBounds() : currentCell.getBounds(); + + y = currentCellBounds.y + currentCellBounds.height - endAdjustment; + + x0 = Math.max(x0, cellBounds.x); + x1 = Math.min(x1, cellBounds.x + cellBounds.width); + + gc.drawLine( + x0 - startAdjustment, + y, + x1 - startAdjustment, + y); + } + } else { + // check if previous was selected to not override the + // border again + // this is necessary because of single cell updates + if (positionRectangle.width == 2 || positionRectangle.height == 2) { + if (afterCell != null && (isFillHandleRegion(afterCell))) { + Rectangle afterCellBounds = afterCell.getBounds(); + + int x0 = Math.max( + afterCellBounds.x, + currentCellBounds.x); + int x1 = Math.min( + afterCellBounds.x + afterCellBounds.width, + currentCellBounds.x + currentCellBounds.width); + + int y = currentCellBounds.y + currentCellBounds.height - startAdjustment; + + if (isFillHandleRegion(afterCell)) { + gc.drawLine( + x0 - startAdjustment, + y, + x1 - startAdjustment, + y); + } + + } + } + } + } + previousCell = currentCell; + + if (fillHandleCell == null && isFillHandleCell(currentCell)) { + fillHandleCell = currentCell; + } + } + } + + // Draw vertical borders + for (int rowPosition = rowPositionOffset; rowPosition < rowPositionOffset + positionRectangle.height; rowPosition++) { + + ILayerCell previousCell = null; + ILayerCell currentCell = null; + ILayerCell afterCell = null; + for (int columnPosition = columnPositionOffset; columnPosition < columnPositionOffset + positionRectangle.width; columnPosition++) { + + currentCell = natLayer.getCellByPosition(columnPosition, rowPosition); + afterCell = natLayer.getCellByPosition(columnPosition + 1, rowPosition); + + if (currentCell != null) { + Rectangle currentCellBounds = currentCell.getBounds(); + + if (isFillHandleRegion(currentCell)) { + int y0 = currentCellBounds.y; + int y1 = currentCellBounds.y + currentCellBounds.height; + + int x = currentCellBounds.x - startAdjustment; + + if (previousCell != null) { + Rectangle previousCellBounds = previousCell.getBounds(); + y0 = Math.max(y0, previousCellBounds.y); + y1 = Math.min(y1, previousCellBounds.y + previousCellBounds.height); + } + + if (previousCell == null || !isFillHandleRegion(previousCell)) { + gc.drawLine( + x, + y0 - startAdjustment, + x, + y1 - startAdjustment); + } + + // check after + if (afterCell == null || !isFillHandleRegion(afterCell)) { + Rectangle cellBounds = afterCell != null ? afterCell.getBounds() : currentCell.getBounds(); + + x = currentCellBounds.x + currentCellBounds.width - endAdjustment; + + y0 = Math.max(y0, cellBounds.y); + y1 = Math.min(y1, cellBounds.y + cellBounds.height); + + gc.drawLine( + x, + y0 - startAdjustment, + x, + y1 - startAdjustment); + } + } else { + // check if previous was selected to not override the + // border again + // this is necessary because of single cell updates + if (positionRectangle.width == 2 + || positionRectangle.height == 2) { + if (afterCell != null && isFillHandleRegion(afterCell)) { + Rectangle afterCellBounds = afterCell.getBounds(); + + int y0 = Math.max(afterCellBounds.y, currentCellBounds.y); + int y1 = Math.min( + afterCellBounds.y + afterCellBounds.height, + currentCellBounds.y + currentCellBounds.height); + + int x = currentCellBounds.x + currentCellBounds.width - startAdjustment; + + gc.drawLine( + x, + y0 - startAdjustment, + x, + y1 - startAdjustment); + } + } + } + } + previousCell = currentCell; + } + } + + // Restore original gc settings + gc.setLineStyle(originalLineStyle); + gc.setLineWidth(originalLineWidth); + gc.setForeground(originalForeground); + + // paint the border around the copied cells if a clipboard is set + if (this.clipboard != null && this.clipboard.getCopiedCells() != null) { + paintCopyBorder(natLayer, gc, xOffset, yOffset, pixelRectangle, configRegistry); + } + + if (fillHandleCell != null) { + paintFillHandle(fillHandleCell, gc, xOffset, yOffset, configRegistry); + } else { + // set the local stored bounds to null as no handle is rendered and + // therefore event matchers shouldn't react anymore + this.handleBounds = null; + } + } + + protected void paintFillHandle( + ILayerCell bottomRight, GC gc, + int xOffset, int yOffset, + IConfigRegistry configRegistry) { + + // Save gc settings + int originalLineStyle = gc.getLineStyle(); + int originalLineWidth = gc.getLineWidth(); + Color originalForeground = gc.getForeground(); + Color originalBackground = gc.getBackground(); + + Rectangle bounds = bottomRight.getBounds(); + + applyHandleStyle(gc, configRegistry); + + this.handleBounds = new Rectangle( + bounds.x + bounds.width - GUIHelper.convertHorizontalPixelToDpi(4), + bounds.y + bounds.height - GUIHelper.convertHorizontalPixelToDpi(4), + GUIHelper.convertHorizontalPixelToDpi(6), + GUIHelper.convertVerticalPixelToDpi(6)); + + gc.fillRectangle(this.handleBounds); + gc.drawRectangle(this.handleBounds); + + // Restore original gc settings + gc.setLineStyle(originalLineStyle); + gc.setLineWidth(originalLineWidth); + gc.setForeground(originalForeground); + gc.setBackground(originalBackground); + } + + protected void paintCopyBorder( + ILayer natLayer, GC gc, + int xOffset, int yOffset, Rectangle pixelRectangle, + IConfigRegistry configRegistry) { + + Rectangle positionRectangle = getPositionRectangleFromPixelRectangle(natLayer, pixelRectangle); + int columnPositionOffset = positionRectangle.x; + int rowPositionOffset = positionRectangle.y; + + // Save gc settings + int originalLineStyle = gc.getLineStyle(); + Color originalForeground = gc.getForeground(); + + applyCopyBorderStyle(gc, configRegistry); + + int x0 = 0; + int x1 = 0; + int y0 = 0; + int y1 = 0; + boolean isFirst = true; + for (ILayerCell[] cells : this.clipboard.getCopiedCells()) { + for (ILayerCell cell : cells) { + if (isFirst) { + x0 = cell.getBounds().x; + x1 = cell.getBounds().x + cell.getBounds().width; + y0 = cell.getBounds().y; + y1 = cell.getBounds().y + cell.getBounds().height; + isFirst = false; + } else { + x0 = Math.min(x0, cell.getBounds().x); + x1 = Math.max(x1, cell.getBounds().x + cell.getBounds().width); + y0 = Math.min(y0, cell.getBounds().y); + y1 = Math.max(y1, cell.getBounds().y + cell.getBounds().height); + } + } + } + + x0 += xOffset - columnPositionOffset; + x1 += xOffset - columnPositionOffset; + y0 += yOffset - rowPositionOffset; + y1 += yOffset - rowPositionOffset; + + gc.drawLine(x0, y0, x0, y1); + gc.drawLine(x0, y0, x1, y0); + gc.drawLine(x0, y1, x1, y1); + gc.drawLine(x1, y0, x1, y1); + + // Restore original gc settings + gc.setLineStyle(originalLineStyle); + gc.setForeground(originalForeground); + } + + /** + * + * @param cell + * The {@link ILayerCell} to check. + * @return <code>true</code> if the cell is part of the fill handle region, + * <code>false</code> if not. + */ + protected boolean isFillHandleRegion(ILayerCell cell) { + return cell.getConfigLabels().hasLabel(SelectionStyleLabels.FILL_HANDLE_REGION); + } + + /** + * + * @param cell + * The {@link ILayerCell} to check. + * @return <code>true</code> if the cell is the bottom right cell in a fill + * region, <code>false</code> if not. + */ + protected boolean isFillHandleCell(ILayerCell cell) { + return cell.getConfigLabels().hasLabel(SelectionStyleLabels.FILL_HANDLE_CELL); + } + + /** + * Apply the border style that should be used to render the border for cells + * that are currently part of the fill handle region. Checks the + * {@link IConfigRegistry} for a registered {@link IStyle} for the + * {@link FillHandleConfigAttributes#FILL_HANDLE_REGION_BORDER_STYLE} label. + * If none is registered, a default line style will be used to render the + * border. + * + * @param gc + * The current {@link GC} that is used for rendering. + * @param configRegistry + * The {@link IConfigRegistry} to retrieve the style information + * from. + */ + protected void applyHandleBorderStyle(GC gc, IConfigRegistry configRegistry) { + BorderStyle borderStyle = configRegistry.getConfigAttribute( + FillHandleConfigAttributes.FILL_HANDLE_REGION_BORDER_STYLE, + DisplayMode.NORMAL); + + // if there is no border style configured, use the default + if (borderStyle == null) { + gc.setLineStyle(SWT.LINE_SOLID); + gc.setLineWidth(2); + gc.setForeground(GUIHelper.getColor(0, 125, 10)); + } else { + gc.setLineStyle(LineStyleEnum.toSWT(borderStyle.getLineStyle())); + gc.setLineWidth(borderStyle.getThickness()); + gc.setForeground(borderStyle.getColor()); + } + } + + /** + * Apply the style for rendering the fill handle. If the + * {@link IConfigRegistry} is <code>null</code> or does not contain + * configurations for styling the fill handle, the default style is used. + * The default is a dark green square with a white solid one pixel width + * line. + * + * @param gc + * The {@link GC} to set the styles to. + * @param configRegistry + * The {@link IConfigRegistry} needed to determine the configured + * fill handle style. Can be <code>null</code> which results in + * using the default style of a green square with white 1 pixel + * solid line border. + */ + protected void applyHandleStyle(GC gc, IConfigRegistry configRegistry) { + if (configRegistry != null) { + BorderStyle borderStyle = configRegistry.getConfigAttribute( + FillHandleConfigAttributes.FILL_HANDLE_BORDER_STYLE, + DisplayMode.NORMAL); + + Color color = configRegistry.getConfigAttribute( + FillHandleConfigAttributes.FILL_HANDLE_COLOR, + DisplayMode.NORMAL); + + if (color != null) { + gc.setBackground(color); + } else { + // set default color + gc.setBackground(GUIHelper.getColor(0, 125, 10)); + } + + if (borderStyle != null) { + gc.setLineStyle(LineStyleEnum.toSWT(borderStyle.getLineStyle())); + gc.setLineWidth(borderStyle.getThickness()); + gc.setForeground(borderStyle.getColor()); + } else { + gc.setLineStyle(SWT.LINE_SOLID); + gc.setLineWidth(1); + gc.setForeground(GUIHelper.COLOR_WHITE); + } + } else { + // set default border style + gc.setLineStyle(SWT.LINE_SOLID); + gc.setLineWidth(1); + gc.setForeground(GUIHelper.COLOR_WHITE); + // set default color + gc.setBackground(GUIHelper.getColor(0, 125, 10)); + } + } + + /** + * Apply the border style that should be used to render the border for cells + * that are currently copied to the {@link InternalCellClipboard}. Checks + * the {@link IConfigRegistry} for a registered {@link IStyle} for the + * {@link SelectionStyleLabels#COPY_BORDER_STYLE} label. If none is + * registered, a default line style will be used to render the border. + * + * @param gc + * The current {@link GC} that is used for rendering. + * @param configRegistry + * The {@link IConfigRegistry} to retrieve the style information + * from. + */ + protected void applyCopyBorderStyle(GC gc, IConfigRegistry configRegistry) { + IStyle cellStyle = configRegistry.getConfigAttribute( + CellConfigAttributes.CELL_STYLE, + DisplayMode.NORMAL, + SelectionStyleLabels.COPY_BORDER_STYLE); + BorderStyle borderStyle = cellStyle != null ? cellStyle.getAttributeValue(CellStyleAttributes.BORDER_STYLE) : null; + + // if there is no border style configured, use the default + if (borderStyle == null) { + gc.setLineStyle(SWT.LINE_DASH); + gc.setLineDash(new int[] { 2, 2 }); + gc.setForeground(GUIHelper.COLOR_BLACK); + } else { + gc.setLineStyle(LineStyleEnum.toSWT(borderStyle.getLineStyle())); + gc.setLineWidth(borderStyle.getThickness()); + gc.setForeground(borderStyle.getColor()); + } + } + + /** + * + * @return The bounds of the current visible selection handle or + * <code>null</code> if no fill handle is currently rendered. + */ + public Rectangle getSelectionHandleBounds() { + return this.handleBounds; + } + + /** + * + * @return The {@link InternalCellClipboard} that is used to identify + * whether a cell is currently copied or <code>null</code> if + * special rendering of copied cells is disabled. + */ + public InternalCellClipboard getClipboard() { + return this.clipboard; + } + + /** + * + * @param clipboard + * The {@link InternalCellClipboard} that should be used to + * identify whether a cell is currently copied or + * <code>null</code> to disable special rendering of copied + * cells. + */ + public void setClipboard(InternalCellClipboard clipboard) { + this.clipboard = clipboard; + } + +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/action/FillHandleCursorAction.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/action/FillHandleCursorAction.java new file mode 100644 index 00000000..c2ad0ef1 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/action/FillHandleCursorAction.java @@ -0,0 +1,104 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.fillhandle.action; + +import org.eclipse.nebula.widgets.nattable.NatTable; +import org.eclipse.nebula.widgets.nattable.fillhandle.config.FillHandleConfiguration; +import org.eclipse.nebula.widgets.nattable.ui.action.IMouseAction; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.PaletteData; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Display; + +/** + * Action to enable a custom cursor (small cross) on NatTable. Used when moving + * over the fill handle of a current selection. + * + * @see FillHandleConfiguration + * + * @since 1.4 + */ +public class FillHandleCursorAction implements IMouseAction { + + private Cursor fillHandleCursor; + + @Override + public void run(NatTable natTable, MouseEvent event) { + if (this.fillHandleCursor == null) { + PaletteData paletteData = new PaletteData(new RGB[] { + new RGB(0, 0, 0), new RGB(255, 255, 255) + }); + ImageData sourceData = new ImageData(16, 16, 1, paletteData); + ImageData maskData = new ImageData(16, 16, 1, paletteData); + + byte[] cursorSource = new byte[] { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + + byte[] cursorMask = new byte[] { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + sourceData.setPixels(0, 0, 255, cursorSource, 0); + maskData.setPixels(0, 0, 255, cursorMask, 0); + + this.fillHandleCursor = new Cursor(Display.getDefault(), sourceData, maskData, 7, 7); + + natTable.addDisposeListener(new DisposeListener() { + + @Override + public void widgetDisposed(DisposeEvent e) { + FillHandleCursorAction.this.fillHandleCursor.dispose(); + } + + }); + } + + natTable.setCursor(this.fillHandleCursor); + } + +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/action/FillHandleDragMode.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/action/FillHandleDragMode.java new file mode 100644 index 00000000..d6d2b131 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/action/FillHandleDragMode.java @@ -0,0 +1,324 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.fillhandle.action; + +import java.util.Date; + +import org.eclipse.nebula.widgets.nattable.Messages; +import org.eclipse.nebula.widgets.nattable.NatTable; +import org.eclipse.nebula.widgets.nattable.coordinate.PositionCoordinate; +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.fillhandle.config.FillDirection; +import org.eclipse.nebula.widgets.nattable.fillhandle.config.FillHandleConfigAttributes; +import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum; +import org.eclipse.nebula.widgets.nattable.style.DisplayMode; +import org.eclipse.nebula.widgets.nattable.ui.action.IDragMode; +import org.eclipse.nebula.widgets.nattable.viewport.command.ViewportDragCommand; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; + +/** + * The {@link IDragMode} that is registered to get triggered for dragging the + * fill drag handle. + * + * @since 1.4 + */ +public class FillHandleDragMode implements IDragMode { + + protected MouseEvent startEvent; + protected Point startIndex; + protected MoveDirectionEnum direction; + + protected SelectionLayer selectionLayer; + + protected ILayerCell selectionCell; + + 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 & + * paste operation triggered by using the fill handle. + */ + public FillHandleDragMode(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 mouseDown(NatTable natTable, MouseEvent event) { + PositionCoordinate[] selectedCellPositions = this.selectionLayer.getSelectedCellPositions(); + if (selectedCellPositions.length > 0) { + this.startEvent = event; + + this.selectionCell = this.selectionLayer.getCellByPosition( + selectedCellPositions[0].columnPosition, + selectedCellPositions[0].rowPosition); + + this.startIndex = new Point( + this.selectionCell.getColumnIndex(), + this.selectionCell.getRowIndex()); + } + } + + @Override + public void mouseMove(NatTable natTable, MouseEvent event) { + Rectangle clientArea = natTable.getClientAreaProvider().getClientArea(); + + int x = event.x; + int y = event.y; + + MoveDirectionEnum horizontal = MoveDirectionEnum.NONE; + if (event.x < 0) { + horizontal = MoveDirectionEnum.LEFT; + x = 0; + } else if (event.x > clientArea.width) { + horizontal = MoveDirectionEnum.RIGHT; + x = clientArea.width; + } + + MoveDirectionEnum vertical = MoveDirectionEnum.NONE; + if (event.y < 0) { + vertical = MoveDirectionEnum.UP; + y = 0; + } else if (event.y > clientArea.height) { + vertical = MoveDirectionEnum.DOWN; + y = clientArea.height; + } + + if (natTable.doCommand(new ViewportDragCommand(horizontal, vertical))) { + + int selectedColumnPosition = natTable.getColumnPositionByX(x); + int selectedRowPosition = natTable.getRowPositionByY(y); + + int selectedColumnIndex = natTable.getColumnIndexByPosition(selectedColumnPosition); + int selectedRowIndex = natTable.getRowIndexByPosition(selectedRowPosition); + + if (selectedColumnPosition > -1 && selectedRowPosition > -1) { + Rectangle actionBounds = null; + + int xStart = this.startIndex.x; + int yStart = this.startIndex.y; + + // only increase range in one direction + int xDiff = selectedColumnIndex - this.startIndex.x; + if (xDiff < 0) { + xDiff *= -1; + } + xDiff++; + + int yDiff = selectedRowIndex - this.startIndex.y; + if (yDiff < 0) { + yDiff *= -1; + } + yDiff++; + + int width = -1; + int height = -1; + + // check if only drag operations in one direction are supported + FillDirection direction = natTable.getConfigRegistry().getConfigAttribute( + FillHandleConfigAttributes.ALLOWED_FILL_DIRECTION, + DisplayMode.NORMAL, + this.selectionCell.getConfigLabels().getLabels()); + + if (direction == null) { + direction = FillDirection.BOTH; + } + + if (direction == FillDirection.VERTICAL + || (direction == FillDirection.BOTH && yDiff >= xDiff)) { + height = Math.max(yDiff, this.selectionLayer.getSelectedRowCount()); + width = this.selectionLayer.getSelectedColumnPositions().length; + this.direction = MoveDirectionEnum.DOWN; + if ((selectedRowIndex - this.startIndex.y) < 0) { + yStart = selectedRowIndex; + height = yDiff + this.selectionLayer.getSelectedRowCount() - 1; + this.direction = MoveDirectionEnum.UP; + } + } else { + height = this.selectionLayer.getSelectedRowCount(); + width = Math.max(xDiff, this.selectionLayer.getSelectedColumnPositions().length); + this.direction = MoveDirectionEnum.RIGHT; + if ((selectedColumnIndex - this.startIndex.x) < 0) { + xStart = selectedColumnIndex; + width = xDiff + this.selectionLayer.getSelectedColumnPositions().length - 1; + this.direction = MoveDirectionEnum.LEFT; + } + } + + actionBounds = new Rectangle( + xStart, + yStart, + width, + height); + + this.selectionLayer.setFillHandleRegion(actionBounds); + natTable.redraw(); + } + } + } + + @Override + public void mouseUp(final NatTable natTable, MouseEvent event) { + if (natTable.doCommand( + new CopyDataToClipboardCommand( + "\t", //$NON-NLS-1$ + System.getProperty("line.separator"), //$NON-NLS-1$ + natTable.getConfigRegistry()))) { + + if (this.clipboard != null) { + if (showMenu(natTable)) { + openMenu(natTable); + } else { + natTable.doCommand( + new FillHandlePasteCommand( + FillHandleOperation.COPY, + this.direction, + natTable.getConfigRegistry())); + reset(natTable); + } + } else { + natTable.doCommand( + new FillHandlePasteCommand( + FillHandleOperation.COPY, + this.direction, + 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) { + Class<?> type = null; + for (ILayerCell[] cells : this.clipboard.getCopiedCells()) { + for (ILayerCell cell : cells) { + if (cell.getDataValue() == null) { + return false; + } else { + if (type == null) { + type = cell.getDataValue().getClass(); + if (!type.isAssignableFrom(Number.class) + && !type.isAssignableFrom(Date.class)) { + return false; + } + } else if (type != cell.getDataValue().getClass()) { + return false; + } + } + } + } + return true; + } + + /** + * 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 = new Menu(natTable); + MenuItem copyItem = new MenuItem(this.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, + FillHandleDragMode.this.direction, + natTable.getConfigRegistry())); + reset(natTable); + } + }); + MenuItem seriesItem = new MenuItem(this.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, + FillHandleDragMode.this.direction, + natTable.getConfigRegistry())); + reset(natTable); + } + }); + + // add the dispose listener for disposing the menu + natTable.addDisposeListener(new DisposeListener() { + + @Override + public void widgetDisposed(DisposeEvent e) { + FillHandleDragMode.this.menu.dispose(); + } + }); + } + + this.menu.setVisible(true); + } + + /** + * Reset the {@link FillHandleDragMode} states, the fill handle region in + * the {@link SelectionLayer} and redraw the given NatTable. + * + * @param natTable + * The NatTable instance on which the operation is performed. + */ + protected void reset(NatTable natTable) { + this.selectionCell = null; + this.startEvent = null; + this.startIndex = null; + this.direction = null; + this.selectionLayer.setFillHandleRegion(null); + this.clipboard.clear(); + natTable.redraw(); + } +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/command/FillHandlePasteCommand.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/command/FillHandlePasteCommand.java new file mode 100644 index 00000000..6a4de56d --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/command/FillHandlePasteCommand.java @@ -0,0 +1,86 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.fillhandle.command; + +import org.eclipse.nebula.widgets.nattable.command.AbstractContextFreeCommand; +import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum; + +/** + * Command to trigger pasting data via fill handle drag operation. + * + * @since 1.4 + */ +public class FillHandlePasteCommand extends AbstractContextFreeCommand { + + /** + * The operation that should be triggered to fill the cells. + */ + public enum FillHandleOperation { + /** + * Copy the current selected values to the cells in the fill handle + * area. + */ + COPY, + /** + * Fill the cells in the fill handle area by creating a series based on + * the current selected values. + */ + SERIES + } + + /** + * The {@link FillHandleOperation} that should be triggered. + */ + public final FillHandleOperation operation; + /** + * The direction in which the fill handle was dragged. Necessary for the + * series operation to calculate the values. + */ + public final MoveDirectionEnum direction; + /** + * The {@link IConfigRegistry} needed to dynamically read configurations on + * command handling, e.g. editable state. + */ + public final IConfigRegistry configRegistry; + + /** + * Create a FillHandlePasteCommand that triggers a copy operation. + * + * @param configRegistry + * The {@link IConfigRegistry} needed to dynamically read + * configurations on command handling, e.g. editable state. + */ + public FillHandlePasteCommand(IConfigRegistry configRegistry) { + this(FillHandleOperation.COPY, null, configRegistry); + } + + /** + * Create a FillHandlePasteCommand. + * + * @param operation + * The {@link FillHandleOperation} that should be triggered. + * @param direction + * The direction in which the fill handle was dragged. Necessary + * for the series operation to calculate the values. + * @param configRegistry + * The {@link IConfigRegistry} needed to dynamically read + * configurations on command handling, e.g. editable state. + */ + public FillHandlePasteCommand( + FillHandleOperation operation, MoveDirectionEnum direction, IConfigRegistry configRegistry) { + this.operation = operation; + this.direction = direction; + this.configRegistry = configRegistry; + } +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/command/FillHandlePasteCommandHandler.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/command/FillHandlePasteCommandHandler.java new file mode 100644 index 00000000..a8b637e0 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/command/FillHandlePasteCommandHandler.java @@ -0,0 +1,577 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.fillhandle.command; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Calendar; +import java.util.Date; + +import org.eclipse.nebula.widgets.nattable.command.ILayerCommandHandler; +import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; +import org.eclipse.nebula.widgets.nattable.coordinate.PositionCoordinate; +import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard; +import org.eclipse.nebula.widgets.nattable.edit.command.EditUtils; +import org.eclipse.nebula.widgets.nattable.edit.command.UpdateDataCommand; +import org.eclipse.nebula.widgets.nattable.fillhandle.config.FillHandleConfigAttributes; +import org.eclipse.nebula.widgets.nattable.layer.ILayer; +import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum; +import org.eclipse.nebula.widgets.nattable.style.DisplayMode; +import org.eclipse.swt.graphics.Rectangle; + +/** + * Command handler for the {@link FillHandlePasteCommand}. + * + * @see FillHandlePasteCommand + * + * @since 1.4 + */ +public class FillHandlePasteCommandHandler implements ILayerCommandHandler<FillHandlePasteCommand> { + + protected SelectionLayer selectionLayer; + protected InternalCellClipboard clipboard; + + /** + * Creates a {@link FillHandlePasteCommandHandler} + * + * @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 & + * paste operation triggered by using the fill handle. + */ + public FillHandlePasteCommandHandler( + SelectionLayer selectionLayer, + InternalCellClipboard clipboard) { + + this.selectionLayer = selectionLayer; + this.clipboard = clipboard; + } + + @Override + public boolean doCommand(ILayer targetLayer, FillHandlePasteCommand command) { + if (this.clipboard.getCopiedCells() != null) { + int pasteColumn = -1; + int pasteRow = -1; + int pasteWidth = this.clipboard.getCopiedCells().length; + int pasteHeight = this.clipboard.getCopiedCells()[0].length; + Rectangle handleRegion = this.selectionLayer.getFillHandleRegion(); + if (handleRegion != null) { + pasteColumn = handleRegion.x; + pasteRow = handleRegion.y; + pasteWidth = handleRegion.width; + pasteHeight = handleRegion.height; + } else { + PositionCoordinate coord = this.selectionLayer.getSelectionAnchor(); + pasteColumn = coord.getColumnPosition(); + pasteRow = coord.getRowPosition(); + } + + int pasteStartColumn = pasteColumn; + + int rowStartAdjustment = 0; + if (command.direction == MoveDirectionEnum.UP) { + rowStartAdjustment = pasteHeight % this.clipboard.getCopiedCells().length; + } + + int columnStartAdjustment = 0; + if (command.direction == MoveDirectionEnum.LEFT) { + columnStartAdjustment = pasteWidth % this.clipboard.getCopiedCells()[0].length; + } + + for (int i = 0; i < pasteHeight; i++) { + ILayerCell[] cells = this.clipboard.getCopiedCells()[(i + rowStartAdjustment) % this.clipboard.getCopiedCells().length]; + for (int j = 0; j < pasteWidth; j++) { + ILayerCell cell = cells[(j + columnStartAdjustment) % this.clipboard.getCopiedCells()[0].length]; + + Object cellValue = getPasteValue(cell, command, pasteColumn, pasteRow); + + if (EditUtils.isCellEditable( + this.selectionLayer, + command.configRegistry, + new PositionCoordinate(this.selectionLayer, + pasteColumn, + pasteRow))) { + this.selectionLayer.doCommand(new UpdateDataCommand(this.selectionLayer, pasteColumn, pasteRow, cellValue)); + } + + pasteColumn++; + + if (pasteColumn >= this.selectionLayer.getColumnCount()) { + break; + } + } + + pasteRow++; + pasteColumn = pasteStartColumn; + } + } + return true; + } + + /** + * Returns the value from the given cell that should be pasted to the given + * position. + * + * @param cell + * The cell that is copied. + * @param command + * The command that contains the necessary information for the + * paste operation. + * @param toColumn + * The column position of the cell to which the value should be + * pasted. + * @param toRow + * The row position of the cell to which the value should be + * pasted. + * @return The value that should be set to the given position. + */ + protected Object getPasteValue(ILayerCell cell, FillHandlePasteCommand command, int toColumn, int toRow) { + switch (command.operation) { + case COPY: + return cell.getDataValue(); + case SERIES: + Object diff = 0; + if (command.direction == MoveDirectionEnum.LEFT || command.direction == MoveDirectionEnum.RIGHT) { + diff = calculateVerticalDiff(cell, toColumn, command.configRegistry); + } else if (command.direction == MoveDirectionEnum.UP || command.direction == MoveDirectionEnum.DOWN) { + diff = calculateHorizontalDiff(cell, toRow, command.configRegistry); + } + Object value = cell.getDataValue(); + // if we can not determine a common diff value we perform a copy + if (diff != null) { + if (value instanceof Byte) { + byte result = (byte) (((Byte) value).byteValue() + (Byte) diff); + return result; + } else if (value instanceof Short) { + short result = (short) (((Short) value).shortValue() + (Short) diff); + return result; + } else if (value instanceof Integer) { + return (Integer) value + (Integer) diff; + } else if (value instanceof Long) { + return (Long) value + (Long) diff; + } else if (value instanceof Float) { + return (Float) value + (Float) diff; + } else if (value instanceof Double) { + return (Double) value + (Double) diff; + } else if (value instanceof BigInteger) { + return ((BigInteger) value).add((BigInteger) diff); + } else if (value instanceof BigDecimal) { + return ((BigDecimal) value).add((BigDecimal) diff); + } else if (value instanceof Date) { + Calendar cal = Calendar.getInstance(); + cal.setTime((Date) value); + cal.add(getIncrementDateField(cell, command.configRegistry), (Integer) diff); + return cal.getTime(); + } + } + // if the value is neither a number nor a date simply return the + // value as we can't calculate a series for other data types + return value; + default: + return cell.getDataValue(); + } + } + + protected Number calculateHorizontalDiff(ILayerCell cell, int toRow, IConfigRegistry configRegistry) { + Class<?> type = cell.getDataValue() != null ? cell.getDataValue().getClass() : null; + + ILayerCell[][] cells = this.clipboard.getCopiedCells(); + int rowDiff = toRow - cell.getRowIndex(); + if (cells.length == 1) { + return getCastValue(rowDiff, type); + } else if (type != null) { + int columnArrayIndex = cell.getColumnIndex() - this.clipboard.getCopiedCells()[0][0].getColumnIndex(); + if (type.isAssignableFrom(Byte.class)) { + Byte diff = calculateByteDiff(cells[1][columnArrayIndex], cells[0][columnArrayIndex]); + if (diff == null) { + return null; + } + Byte temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateByteDiff(cells[i][columnArrayIndex], cells[i - 1][columnArrayIndex]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + byte result = (byte) (diff * rowDiff); + return result; + } else if (type.isAssignableFrom(Short.class)) { + Short diff = calculateShortDiff(cells[1][columnArrayIndex], cells[0][columnArrayIndex]); + if (diff == null) { + return null; + } + Short temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateShortDiff(cells[i][columnArrayIndex], cells[i - 1][columnArrayIndex]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + short result = (short) (diff * rowDiff); + return result; + } else if (type.isAssignableFrom(Integer.class)) { + Integer diff = calculateIntDiff(cells[1][columnArrayIndex], cells[0][columnArrayIndex]); + if (diff == null) { + return null; + } + Integer temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateIntDiff(cells[i][columnArrayIndex], cells[i - 1][columnArrayIndex]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + return diff * rowDiff; + } else if (type.isAssignableFrom(Long.class)) { + Long diff = calculateLongDiff(cells[1][columnArrayIndex], cells[0][columnArrayIndex]); + if (diff == null) { + return null; + } + Long temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateLongDiff(cells[i][columnArrayIndex], cells[i - 1][columnArrayIndex]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + return diff * rowDiff; + } else if (type.isAssignableFrom(Float.class)) { + Float diff = calculateFloatDiff(cells[1][columnArrayIndex], cells[0][columnArrayIndex]); + if (diff == null) { + return null; + } + Float temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateFloatDiff(cells[i][columnArrayIndex], cells[i - 1][columnArrayIndex]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + return BigDecimal.valueOf(diff).multiply(BigDecimal.valueOf(rowDiff)).floatValue(); + } else if (type.isAssignableFrom(Double.class)) { + Double diff = calculateDoubleDiff(cells[1][columnArrayIndex], cells[0][columnArrayIndex]); + if (diff == null) { + return null; + } + Double temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateDoubleDiff(cells[i][columnArrayIndex], cells[i - 1][columnArrayIndex]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + return BigDecimal.valueOf(diff).multiply(BigDecimal.valueOf(rowDiff)).doubleValue(); + } else if (type.isAssignableFrom(BigInteger.class)) { + BigInteger diff = calculateBigIntegerDiff(cells[1][columnArrayIndex], cells[0][columnArrayIndex]); + if (diff == null) { + return null; + } + BigInteger temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateBigIntegerDiff(cells[i][columnArrayIndex], cells[i - 1][columnArrayIndex]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + return diff.multiply(BigInteger.valueOf(rowDiff)); + } else if (type.isAssignableFrom(BigDecimal.class)) { + BigDecimal diff = calculateBigDecimalDiff(cells[1][columnArrayIndex], cells[0][columnArrayIndex]); + if (diff == null) { + return null; + } + BigDecimal temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateBigDecimalDiff(cells[i][columnArrayIndex], cells[i - 1][columnArrayIndex]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + return diff.multiply(BigDecimal.valueOf(rowDiff)); + } else if (type.isAssignableFrom(Date.class)) { + Integer diff = calculateDateDiff(cells[1][columnArrayIndex], cells[0][columnArrayIndex], configRegistry); + if (diff == null) { + return null; + } + Integer temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateDateDiff(cells[i][columnArrayIndex], cells[i - 1][columnArrayIndex], configRegistry); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + return diff * rowDiff; + } + } + return null; + } + + protected Number calculateVerticalDiff(ILayerCell cell, int toColumn, IConfigRegistry configRegistry) { + Class<?> type = cell.getDataValue() != null ? cell.getDataValue().getClass() : null; + + ILayerCell[][] cells = this.clipboard.getCopiedCells(); + int columnDiff = toColumn - cell.getColumnIndex(); + int rowArrayIndex = cell.getRowIndex() - this.clipboard.getCopiedCells()[0][0].getRowIndex(); + if (cells[rowArrayIndex].length == 1) { + return getCastValue(columnDiff, type); + } else if (type != null) { + if (type.isAssignableFrom(Byte.class)) { + Byte diff = calculateByteDiff(cells[rowArrayIndex][1], cells[rowArrayIndex][0]); + if (diff == null) { + return null; + } + Byte temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateByteDiff(cells[rowArrayIndex][i], cells[rowArrayIndex][i - 1]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + byte result = (byte) (diff * columnDiff); + return result; + } else if (type.isAssignableFrom(Short.class)) { + Short diff = calculateShortDiff(cells[rowArrayIndex][1], cells[rowArrayIndex][0]); + if (diff == null) { + return null; + } + Short temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateShortDiff(cells[rowArrayIndex][i], cells[rowArrayIndex][i - 1]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + short result = (short) (diff * columnDiff); + return result; + } else if (type.isAssignableFrom(Integer.class)) { + Integer diff = calculateIntDiff(cells[rowArrayIndex][1], cells[rowArrayIndex][0]); + if (diff == null) { + return null; + } + Integer temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateIntDiff(cells[rowArrayIndex][i], cells[rowArrayIndex][i - 1]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + return diff * columnDiff; + } else if (type.isAssignableFrom(Long.class)) { + Long diff = calculateLongDiff(cells[rowArrayIndex][1], cells[rowArrayIndex][0]); + if (diff == null) { + return null; + } + Long temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateLongDiff(cells[rowArrayIndex][i], cells[rowArrayIndex][i - 1]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + return diff * columnDiff; + } else if (type.isAssignableFrom(Float.class)) { + Float diff = calculateFloatDiff(cells[rowArrayIndex][1], cells[rowArrayIndex][0]); + if (diff == null) { + return null; + } + Float temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateFloatDiff(cells[rowArrayIndex][i], cells[rowArrayIndex][i - 1]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + return BigDecimal.valueOf(diff).multiply(BigDecimal.valueOf(columnDiff)).floatValue(); + } else if (type.isAssignableFrom(Double.class)) { + Double diff = calculateDoubleDiff(cells[rowArrayIndex][1], cells[rowArrayIndex][0]); + if (diff == null) { + return null; + } + Double temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateDoubleDiff(cells[rowArrayIndex][i], cells[rowArrayIndex][i - 1]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + return BigDecimal.valueOf(diff).multiply(BigDecimal.valueOf(columnDiff)).doubleValue(); + } else if (type.isAssignableFrom(BigInteger.class)) { + BigInteger diff = calculateBigIntegerDiff(cells[rowArrayIndex][1], cells[rowArrayIndex][0]); + if (diff == null) { + return null; + } + BigInteger temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateBigIntegerDiff(cells[rowArrayIndex][i], cells[rowArrayIndex][i - 1]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + return diff.multiply(BigInteger.valueOf(columnDiff)); + } else if (type.isAssignableFrom(BigDecimal.class)) { + BigDecimal diff = calculateBigDecimalDiff(cells[rowArrayIndex][1], cells[rowArrayIndex][0]); + if (diff == null) { + return null; + } + BigDecimal temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateBigDecimalDiff(cells[rowArrayIndex][i], cells[rowArrayIndex][i - 1]); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + return diff.multiply(BigDecimal.valueOf(columnDiff)); + } else if (type.isAssignableFrom(Date.class)) { + Integer diff = calculateDateDiff(cells[rowArrayIndex][1], cells[rowArrayIndex][0], configRegistry); + if (diff == null) { + return null; + } + Integer temp = diff; + for (int i = 1; i < cells.length; i++) { + temp = calculateDateDiff(cells[rowArrayIndex][i], cells[rowArrayIndex][i - 1], configRegistry); + if (temp == null || !temp.equals(diff)) { + return null; + } + } + return diff * columnDiff; + } + } + return null; + } + + protected Number getCastValue(int diff, Class<?> type) { + if (type != null) { + if (type.isAssignableFrom(Byte.class)) { + return (byte) diff; + } else if (type.isAssignableFrom(Short.class)) { + return (short) diff; + } else if (type.isAssignableFrom(Long.class)) { + return (long) diff; + } else if (type.isAssignableFrom(Float.class)) { + return (float) diff; + } else if (type.isAssignableFrom(Double.class)) { + return (double) diff; + } else if (type.isAssignableFrom(BigInteger.class)) { + return BigInteger.valueOf(diff); + } else if (type.isAssignableFrom(BigDecimal.class)) { + return BigDecimal.valueOf(diff); + } + } + return diff; + } + + protected Byte calculateByteDiff(ILayerCell c1, ILayerCell c2) { + return (c1.getDataValue() == null || c2.getDataValue() == null + || !(c1.getDataValue() instanceof Byte) || !(c2.getDataValue() instanceof Byte)) + ? null : (byte) (((Byte) c1.getDataValue()) - ((Byte) c2.getDataValue())); + } + + protected Short calculateShortDiff(ILayerCell c1, ILayerCell c2) { + return (c1.getDataValue() == null || c2.getDataValue() == null + || !(c1.getDataValue() instanceof Short) || !(c2.getDataValue() instanceof Short)) + ? null : (short) (((Short) c1.getDataValue()) - ((Short) c2.getDataValue())); + } + + protected Integer calculateIntDiff(ILayerCell c1, ILayerCell c2) { + return (c1.getDataValue() == null || c2.getDataValue() == null + || !(c1.getDataValue() instanceof Integer) || !(c2.getDataValue() instanceof Integer)) + ? null : (Integer) (c1.getDataValue()) - (Integer) (c2.getDataValue()); + } + + protected Long calculateLongDiff(ILayerCell c1, ILayerCell c2) { + return (c1.getDataValue() == null || c2.getDataValue() == null + || !(c1.getDataValue() instanceof Long) || !(c2.getDataValue() instanceof Long)) + ? null : ((Long) c1.getDataValue()) - ((Long) c2.getDataValue()); + } + + protected Float calculateFloatDiff(ILayerCell c1, ILayerCell c2) { + if (c1.getDataValue() == null || c2.getDataValue() == null + || !(c1.getDataValue() instanceof Float) || !(c2.getDataValue() instanceof Float)) { + return null; + } + + // Use BigDecimal for exact calculations because of floating point + // arithmetic issues. Because of that we also use the String constructor + // of BigDecimal. + BigDecimal v1 = new BigDecimal(c1.getDataValue().toString()); + BigDecimal v2 = new BigDecimal(c2.getDataValue().toString()); + return v1.subtract(v2).floatValue(); + } + + protected Double calculateDoubleDiff(ILayerCell c1, ILayerCell c2) { + if (c1.getDataValue() == null || c2.getDataValue() == null + || !(c1.getDataValue() instanceof Double) || !(c2.getDataValue() instanceof Double)) { + return null; + } + + // Use BigDecimal for exact calculations because of floating point + // arithmetic issues. Because of that we also use the String constructor + // of BigDecimal. + BigDecimal v1 = new BigDecimal(c1.getDataValue().toString()); + BigDecimal v2 = new BigDecimal(c2.getDataValue().toString()); + return v1.subtract(v2).doubleValue(); + } + + protected BigInteger calculateBigIntegerDiff(ILayerCell c1, ILayerCell c2) { + return (c1.getDataValue() == null || c2.getDataValue() == null + || !(c1.getDataValue() instanceof BigInteger) || !(c2.getDataValue() instanceof BigInteger)) + ? null : ((BigInteger) c1.getDataValue()).subtract((BigInteger) c2.getDataValue()); + } + + protected BigDecimal calculateBigDecimalDiff(ILayerCell c1, ILayerCell c2) { + return (c1.getDataValue() == null || c2.getDataValue() == null + || !(c1.getDataValue() instanceof BigDecimal) || !(c2.getDataValue() instanceof BigDecimal)) + ? null : ((BigDecimal) c1.getDataValue()).subtract((BigDecimal) c2.getDataValue()); + } + + protected Integer calculateDateDiff(ILayerCell c1, ILayerCell c2, IConfigRegistry configRegistry) { + if (c1.getDataValue() == null || c2.getDataValue() == null + || !(c1.getDataValue() instanceof Date) || !(c2.getDataValue() instanceof Date)) { + return null; + } + + int dateField = getIncrementDateField(c1, configRegistry); + + Calendar cal1 = Calendar.getInstance(); + cal1.setTime((Date) c1.getDataValue()); + int fieldValue1 = cal1.get(dateField); + + Calendar cal2 = Calendar.getInstance(); + cal2.setTime((Date) c2.getDataValue()); + int fieldValue2 = cal2.get(dateField); + + return fieldValue1 - fieldValue2; + } + + protected int getIncrementDateField(ILayerCell cell, IConfigRegistry configRegistry) { + Integer dateField = configRegistry.getConfigAttribute( + FillHandleConfigAttributes.INCREMENT_DATE_FIELD, + DisplayMode.NORMAL, + cell.getConfigLabels().getLabels()); + + if (dateField == null) { + dateField = Calendar.DATE; + } + + return dateField; + } + + @Override + public Class<FillHandlePasteCommand> getCommandClass() { + return FillHandlePasteCommand.class; + } + +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/config/FillDirection.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/config/FillDirection.java new file mode 100644 index 00000000..0ac287bf --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/config/FillDirection.java @@ -0,0 +1,23 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.fillhandle.config; + +/** + * Enumeration that is used to configure which directions are allowed for using + * the fill drag handle. + * + * @since 1.4 + */ +public enum FillDirection { + HORIZONTAL, VERTICAL, BOTH +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/config/FillHandleConfigAttributes.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/config/FillHandleConfigAttributes.java new file mode 100644 index 00000000..c623ac8b --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/config/FillHandleConfigAttributes.java @@ -0,0 +1,61 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.fillhandle.config; + +import java.util.Calendar; + +import org.eclipse.nebula.widgets.nattable.style.BorderStyle; +import org.eclipse.nebula.widgets.nattable.style.ConfigAttribute; +import org.eclipse.swt.graphics.Color; + +/** + * This interface contains {@link ConfigAttribute}s that can be used to + * configure the fill handle behavior. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + * + * @since 1.4 + */ +public interface FillHandleConfigAttributes { + + /** + * ConfigAttribute to configure the line style used to render a special + * border on dragging the fill handle. + */ + ConfigAttribute<BorderStyle> FILL_HANDLE_REGION_BORDER_STYLE = new ConfigAttribute<BorderStyle>(); + + /** + * ConfigAttribute to configure the border style of the fill handle itself. + */ + ConfigAttribute<BorderStyle> FILL_HANDLE_BORDER_STYLE = new ConfigAttribute<BorderStyle>(); + + /** + * ConfigAttribute to configure the color of the fill handle. + */ + ConfigAttribute<Color> FILL_HANDLE_COLOR = new ConfigAttribute<Color>(); + + /** + * ConfigAttribute to configure the date field that should be incremented + * when inserting a series via fill handle. Fields from the {@link Calendar} + * class should be used for configuration. + */ + ConfigAttribute<Integer> INCREMENT_DATE_FIELD = new ConfigAttribute<Integer>(); + + /** + * ConfigAttribute to configure the directions that are allowed for the fill + * handle. If nothing is specified {@link FillDirection#BOTH} will be used + * implicitly. + */ + ConfigAttribute<FillDirection> ALLOWED_FILL_DIRECTION = new ConfigAttribute<FillDirection>(); +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/config/FillHandleConfiguration.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/config/FillHandleConfiguration.java new file mode 100644 index 00000000..95707d4f --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/config/FillHandleConfiguration.java @@ -0,0 +1,103 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.fillhandle.config; + +import org.eclipse.nebula.widgets.nattable.NatTable; +import org.eclipse.nebula.widgets.nattable.config.AbstractLayerConfiguration; +import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard; +import org.eclipse.nebula.widgets.nattable.copy.command.InternalCopyDataCommandHandler; +import org.eclipse.nebula.widgets.nattable.fillhandle.FillHandleLayerPainter; +import org.eclipse.nebula.widgets.nattable.fillhandle.action.FillHandleCursorAction; +import org.eclipse.nebula.widgets.nattable.fillhandle.action.FillHandleDragMode; +import org.eclipse.nebula.widgets.nattable.fillhandle.command.FillHandlePasteCommandHandler; +import org.eclipse.nebula.widgets.nattable.fillhandle.event.FillHandleEventMatcher; +import org.eclipse.nebula.widgets.nattable.fillhandle.event.FillHandleMarkupListener; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; +import org.eclipse.nebula.widgets.nattable.ui.action.ClearCursorAction; +import org.eclipse.nebula.widgets.nattable.ui.action.NoOpMouseAction; +import org.eclipse.nebula.widgets.nattable.ui.binding.UiBindingRegistry; +import org.eclipse.nebula.widgets.nattable.ui.matcher.MouseEventMatcher; + +/** + * Default configuration for fill handle functionality. Registers the + * corresponding painter, command handler and ui bindings. + * + * @since 1.4 + */ +public class FillHandleConfiguration extends AbstractLayerConfiguration<NatTable> { + + protected SelectionLayer selectionLayer; + + protected FillHandleLayerPainter painter; + + protected InternalCellClipboard clipboard; + + /** + * Create the FillHandleConfiguration for a NatTable. + * + * @param selectionLayer + * The {@link SelectionLayer} needed to determine the current + * selection on which the fill handle will be rendered. Can not + * be <code>null</code>. + */ + public FillHandleConfiguration(SelectionLayer selectionLayer) { + if (selectionLayer == null) { + throw new IllegalArgumentException("SelectionLayer can not be null"); //$NON-NLS-1$ + } + this.selectionLayer = selectionLayer; + } + + @Override + public void configureTypedLayer(NatTable natTable) { + // initialization works here because configureLayer() is executed before + // configureUiBindings() + this.clipboard = natTable.getInternalCellClipboard(); + + this.painter = new FillHandleLayerPainter(); + this.selectionLayer.setLayerPainter(this.painter); + + this.selectionLayer.addLayerListener(new FillHandleMarkupListener(this.selectionLayer)); + + this.selectionLayer.registerCommandHandler( + new InternalCopyDataCommandHandler(this.selectionLayer, this.clipboard)); + this.selectionLayer.registerCommandHandler( + new FillHandlePasteCommandHandler(this.selectionLayer, this.clipboard)); + } + + @Override + public void configureUiBindings(UiBindingRegistry uiBindingRegistry) { + FillHandleEventMatcher matcher = new FillHandleEventMatcher(this.painter); + + // Mouse move + // Show fill handle cursor + uiBindingRegistry.registerFirstMouseMoveBinding( + matcher, + new FillHandleCursorAction()); + uiBindingRegistry.registerMouseMoveBinding( + new MouseEventMatcher(), + new ClearCursorAction()); + + // Mouse drag + // trigger the handle drag operations + uiBindingRegistry.registerFirstMouseDragMode( + matcher, + new FillHandleDragMode(this.selectionLayer, this.clipboard)); + + // Mouse click + // ensure no selection is triggered on mouse down on the handle + uiBindingRegistry.registerFirstMouseDownBinding( + matcher, + new NoOpMouseAction()); + } + +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/event/FillHandleEventMatcher.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/event/FillHandleEventMatcher.java new file mode 100644 index 00000000..03ee943e --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/event/FillHandleEventMatcher.java @@ -0,0 +1,56 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.fillhandle.event; + +import org.eclipse.nebula.widgets.nattable.NatTable; +import org.eclipse.nebula.widgets.nattable.fillhandle.FillHandleLayerPainter; +import org.eclipse.nebula.widgets.nattable.layer.LabelStack; +import org.eclipse.nebula.widgets.nattable.ui.matcher.MouseEventMatcher; +import org.eclipse.swt.events.MouseEvent; + +/** + * Matcher that returns <code>true</code> in case the mouse moves over the fill + * handle rendered by the {@link FillHandleLayerPainter}. + * + * @since 1.4 + */ +public class FillHandleEventMatcher extends MouseEventMatcher { + + protected FillHandleLayerPainter fillHandlePainter; + + /** + * Create a {@link FillHandleEventMatcher} that reacts when the mouse is + * moved over the fill handle rendered by the given + * {@link FillHandleLayerPainter}. + * + * @param fillHandlePainter + * The {@link FillHandleLayerPainter} that should be used to + * determine the bounds of the fill handle. Can not be + * <code>null</code>. + */ + public FillHandleEventMatcher(FillHandleLayerPainter fillHandlePainter) { + if (fillHandlePainter == null) { + throw new IllegalArgumentException("FillHandleLayerPainter can not be null"); //$NON-NLS-1$ + } + this.fillHandlePainter = fillHandlePainter; + } + + @Override + public boolean matches(NatTable natTable, MouseEvent event, LabelStack regionLabels) { + if (this.fillHandlePainter.getSelectionHandleBounds() != null) { + return this.fillHandlePainter.getSelectionHandleBounds().contains(event.x, event.y); + } + return false; + } + +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/event/FillHandleMarkupListener.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/event/FillHandleMarkupListener.java new file mode 100644 index 00000000..84e4d569 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/fillhandle/event/FillHandleMarkupListener.java @@ -0,0 +1,41 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.fillhandle.event; + +import org.eclipse.nebula.widgets.nattable.layer.ILayerListener; +import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; +import org.eclipse.nebula.widgets.nattable.selection.event.ISelectionEvent; + +/** + * {@link ILayerListener} that will trigger the markup in the + * {@link SelectionLayer} of the cell that will hold the fill handle. + * + * @since 1.4 + */ +public class FillHandleMarkupListener implements ILayerListener { + + private final SelectionLayer selectionLayer; + + public FillHandleMarkupListener(SelectionLayer selectionLayer) { + this.selectionLayer = selectionLayer; + } + + @Override + public void handleLayerEvent(ILayerEvent event) { + if (event instanceof ISelectionEvent) { + FillHandleMarkupListener.this.selectionLayer.markFillHandleCell(); + } + } + +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/FormulaLayerPainter.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/CopySelectionLayerPainter.java index 1a09fe0c..88bc8a97 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/FormulaLayerPainter.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/CopySelectionLayerPainter.java @@ -16,7 +16,6 @@ import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes; import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry; import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard; -import org.eclipse.nebula.widgets.nattable.formula.config.FormulaStyleLabels; import org.eclipse.nebula.widgets.nattable.layer.ILayer; import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; @@ -26,6 +25,7 @@ import org.eclipse.nebula.widgets.nattable.style.BorderStyle.LineStyleEnum; import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes; import org.eclipse.nebula.widgets.nattable.style.DisplayMode; import org.eclipse.nebula.widgets.nattable.style.IStyle; +import org.eclipse.nebula.widgets.nattable.style.SelectionStyleLabels; import org.eclipse.nebula.widgets.nattable.util.GUIHelper; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; @@ -42,25 +42,39 @@ import org.eclipse.swt.graphics.Rectangle; * * @since 1.4 */ -public class FormulaLayerPainter extends SelectionLayerPainter { +public class CopySelectionLayerPainter extends SelectionLayerPainter { protected InternalCellClipboard clipboard; /** - * Create a FormulaLayerPainter that renders gray grid lines and uses the - * default clipping behavior. + * Create a {@link CopySelectionLayerPainter} that renders gray grid lines + * and uses the default clipping behavior. * * @param clipboard * The {@link InternalCellClipboard} that stores the cells that * are currently copied. */ - public FormulaLayerPainter(InternalCellClipboard clipboard) { + public CopySelectionLayerPainter(InternalCellClipboard clipboard) { this.clipboard = clipboard; } /** - * Create a FormulaLayerPainter that renders grid lines in the specified - * color and uses the specified clipping behavior. + * Create a {@link CopySelectionLayerPainter} that renders gray grid lines + * and uses the default clipping behavior. + * + * @param clipboard + * The {@link InternalCellClipboard} that stores the cells that + * are currently copied. + * @param gridColor + * The color that should be used to render the grid lines. + */ + public CopySelectionLayerPainter(InternalCellClipboard clipboard, final Color gridColor) { + this.clipboard = clipboard; + } + + /** + * Create a {@link CopySelectionLayerPainter} that renders grid lines in the + * specified color and uses the specified clipping behavior. * * @param clipboard * The {@link InternalCellClipboard} that stores the cells that @@ -78,14 +92,14 @@ public class FormulaLayerPainter extends SelectionLayerPainter { * <code>false</code> the bottom cell will be clipped. The * default value is <code>false</code>. */ - public FormulaLayerPainter(InternalCellClipboard clipboard, final Color gridColor, boolean clipLeft, boolean clipTop) { + public CopySelectionLayerPainter(InternalCellClipboard clipboard, final Color gridColor, boolean clipLeft, boolean clipTop) { super(gridColor, clipLeft, clipTop); this.clipboard = clipboard; } /** - * Create a FormulaLayerPainter that renders gray grid lines and uses the - * specified clipping behavior. + * Create a {@link CopySelectionLayerPainter} that renders gray grid lines + * and uses the specified clipping behavior. * * @param clipboard * The {@link InternalCellClipboard} that stores the cells that @@ -101,7 +115,7 @@ public class FormulaLayerPainter extends SelectionLayerPainter { * <code>false</code> the bottom cell will be clipped. The * default value is <code>false</code>. */ - public FormulaLayerPainter(InternalCellClipboard clipboard, boolean clipLeft, boolean clipTop) { + public CopySelectionLayerPainter(InternalCellClipboard clipboard, boolean clipLeft, boolean clipTop) { this(clipboard, GUIHelper.COLOR_GRAY, clipLeft, clipTop); } @@ -135,8 +149,7 @@ public class FormulaLayerPainter extends SelectionLayerPainter { y0 = cell.getBounds().y; y1 = cell.getBounds().y + cell.getBounds().height; isFirst = false; - } - else { + } else { x0 = Math.min(x0, cell.getBounds().x); x1 = Math.max(x1, cell.getBounds().x + cell.getBounds().width); y0 = Math.min(y0, cell.getBounds().y); @@ -165,7 +178,7 @@ public class FormulaLayerPainter extends SelectionLayerPainter { * Apply the border style that should be used to render the border for cells * that are currently copied to the {@link InternalCellClipboard}. Checks * the {@link ConfigRegistry} for a registered {@link IStyle} for the - * {@link FormulaStyleLabels#COPY_BORDER_STYLE} label. If none is + * {@link SelectionStyleLabels#COPY_BORDER_STYLE} label. If none is * registered, a default line style will be used to render the border. * * @param gc @@ -178,7 +191,7 @@ public class FormulaLayerPainter extends SelectionLayerPainter { IStyle cellStyle = configRegistry.getConfigAttribute( CellConfigAttributes.CELL_STYLE, DisplayMode.NORMAL, - FormulaStyleLabels.COPY_BORDER_STYLE); + SelectionStyleLabels.COPY_BORDER_STYLE); BorderStyle borderStyle = cellStyle != null ? cellStyle.getAttributeValue(CellStyleAttributes.BORDER_STYLE) : null; // if there is no border style configured, use the default diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/action/FormulaFillHandleDragMode.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/action/FormulaFillHandleDragMode.java new file mode 100644 index 00000000..fda7295d --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/action/FormulaFillHandleDragMode.java @@ -0,0 +1,87 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.formula.action; + +import java.math.BigDecimal; +import java.util.Date; + +import org.eclipse.nebula.widgets.nattable.NatTable; +import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard; +import org.eclipse.nebula.widgets.nattable.fillhandle.action.FillHandleDragMode; +import org.eclipse.nebula.widgets.nattable.formula.FormulaDataProvider; +import org.eclipse.nebula.widgets.nattable.formula.command.DisableFormulaEvaluationCommand; +import org.eclipse.nebula.widgets.nattable.formula.command.EnableFormulaEvaluationCommand; +import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; + +/** + * Specialized {@link FillHandleDragMode} that also opens the dialog in case of + * String values that can be converted to {@link BigDecimal} values using the + * {@link FormulaDataProvider}. + * + * @since 1.4 + */ +public class FormulaFillHandleDragMode extends FillHandleDragMode { + + protected FormulaDataProvider dataProvider; + + /** + * + * @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 & + * paste operation triggered by using the fill handle. + * @param dataProvider + * The {@link FormulaDataProvider} that is needed to determine + * whether a value is a number value. + */ + public FormulaFillHandleDragMode(SelectionLayer selectionLayer, InternalCellClipboard clipboard, + FormulaDataProvider dataProvider) { + super(selectionLayer, clipboard); + this.dataProvider = dataProvider; + } + + @Override + protected boolean showMenu(final NatTable natTable) { + natTable.doCommand(new DisableFormulaEvaluationCommand()); + + try { + Class<?> type = null; + for (ILayerCell[] cells : this.clipboard.getCopiedCells()) { + for (ILayerCell cell : cells) { + if (cell.getDataValue() == null) { + return false; + } else { + if (type == null) { + type = cell.getDataValue().getClass(); + if (!type.isAssignableFrom(Number.class) + && !type.isAssignableFrom(Date.class) + && (type.isAssignableFrom(String.class) + && !this.dataProvider.getFormulaParser().isNumber((String) cell.getDataValue()))) { + return false; + } + } else if (type != cell.getDataValue().getClass()) { + return false; + } + } + } + } + } finally { + natTable.doCommand(new EnableFormulaEvaluationCommand()); + } + + return true; + } +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/command/FormulaCopyDataCommandHandler.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/command/FormulaCopyDataCommandHandler.java index 2493aea8..d6a1503a 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/command/FormulaCopyDataCommandHandler.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/command/FormulaCopyDataCommandHandler.java @@ -14,8 +14,7 @@ package org.eclipse.nebula.widgets.nattable.formula.command; import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard; import org.eclipse.nebula.widgets.nattable.copy.command.CopyDataCommandHandler; -import org.eclipse.nebula.widgets.nattable.copy.command.CopyDataToClipboardCommand; -import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; +import org.eclipse.nebula.widgets.nattable.copy.command.InternalCopyDataCommandHandler; import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; /** @@ -24,9 +23,7 @@ import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; * * @since 1.4 */ -public class FormulaCopyDataCommandHandler extends CopyDataCommandHandler { - - private InternalCellClipboard clipboard; +public class FormulaCopyDataCommandHandler extends InternalCopyDataCommandHandler { /** * Creates an instance that only checks the {@link SelectionLayer} for the @@ -41,65 +38,16 @@ public class FormulaCopyDataCommandHandler extends CopyDataCommandHandler { * copy/paste operations within a NatTable instance. */ public FormulaCopyDataCommandHandler(SelectionLayer selectionLayer, InternalCellClipboard clipboard) { - super(selectionLayer); - this.clipboard = clipboard; + super(selectionLayer, clipboard); } @Override - public boolean doCommand(CopyDataToClipboardCommand command) { - // copy to clipboard - super.doCommand(command); - - // only copy if contiguous cells - ILayerCell[][] cells = assembleCopiedDataStructure(); - if (!isDiscontiguousSelection(cells)) { - this.selectionLayer.doCommand(new DisableFormulaEvaluationCommand()); - - // remember cells to copy to support paste of formulas - this.clipboard.setCopiedCells(assembleCopiedDataStructure()); - - this.selectionLayer.doCommand(new EnableFormulaEvaluationCommand()); - } - - return true; + protected void preInternalCopy() { + this.selectionLayer.doCommand(new DisableFormulaEvaluationCommand()); } - /** - * Performs a check whether the selection contains discontinuous cells. In - * such a case copy/paste operations are not possible. - * - * @param selectedCells - * The selection to check. - * @return <code>true</code> if the selection contains discontinuous cells, - * therefore copy/paste operations are not possible, - * <code>false</code> if a valid selection with continuous cells is - * checked - */ - protected boolean isDiscontiguousSelection(ILayerCell[][] selectedCells) { - int previousColumnIndex = -1; - int previousRowIndex = -1; - for (ILayerCell[] cells : selectedCells) { - for (ILayerCell cell : cells) { - if (cell != null) { - if (previousColumnIndex >= 0) { - int diff = cell.getColumnIndex() - previousColumnIndex; - if (diff > 1) { - return true; - } - } - previousColumnIndex = cell.getColumnIndex(); - } - } - - if (previousRowIndex >= 0) { - int diff = cells[0].getRowIndex() - previousRowIndex; - if (diff > 1) { - return true; - } - } - previousRowIndex = cells[0].getRowIndex(); - } - return false; + @Override + protected void postInternalCopy() { + this.selectionLayer.doCommand(new EnableFormulaEvaluationCommand()); } - } diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/command/FormulaFillHandlePasteCommandHandler.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/command/FormulaFillHandlePasteCommandHandler.java new file mode 100644 index 00000000..2914e6f9 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/command/FormulaFillHandlePasteCommandHandler.java @@ -0,0 +1,134 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.formula.command; + +import java.math.BigDecimal; + +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.FillHandlePasteCommandHandler; +import org.eclipse.nebula.widgets.nattable.formula.FormulaDataProvider; +import org.eclipse.nebula.widgets.nattable.formula.function.FunctionException; +import org.eclipse.nebula.widgets.nattable.layer.ILayer; +import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; +import org.eclipse.nebula.widgets.nattable.layer.cell.LayerCell; +import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; + +/** + * Specialized command handler for {@link FillHandlePasteCommand}s that is able + * to deal with formulas. + * + * @since 1.4 + */ +public class FormulaFillHandlePasteCommandHandler extends FillHandlePasteCommandHandler { + + protected FormulaDataProvider dataProvider; + + /** + * + * @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 & + * paste operation triggered by using the fill handle. + * @param dataProvider + * The {@link FormulaDataProvider} that is needed to copy & paste + * formulas. + */ + public FormulaFillHandlePasteCommandHandler( + SelectionLayer selectionLayer, + InternalCellClipboard clipboard, + FormulaDataProvider dataProvider) { + + super(selectionLayer, clipboard); + this.dataProvider = dataProvider; + } + + @Override + public boolean doCommand(ILayer targetLayer, FillHandlePasteCommand command) { + if (this.clipboard.getCopiedCells() != null) { + // in case there are no cached data information held in the copied + // cells, ensure that formulas are not evaluated on paste + this.selectionLayer.doCommand(new DisableFormulaEvaluationCommand()); + + super.doCommand(targetLayer, command); + + this.selectionLayer.doCommand(new EnableFormulaEvaluationCommand()); + } + return true; + } + + @Override + protected Object getPasteValue(ILayerCell cell, FillHandlePasteCommand command, int toColumn, int toRow) { + Object cellValue = cell.getDataValue(); + if (cellValue != null && this.dataProvider.getFormulaParser().isFunction(cellValue.toString())) { + try { + cellValue = this.dataProvider.getFormulaParser().updateReferences( + cellValue.toString(), cell.getColumnPosition(), cell.getRowPosition(), toColumn, toRow); + } catch (FunctionException e) { + if (this.dataProvider.getErrorReporter() != null) { + this.dataProvider.getErrorReporter().addFormulaError(toColumn, toRow, e.getLocalizedMessage()); + } + cellValue = e.getErrorMarkup(); + } + } else if (cellValue != null + && cellValue instanceof String + && this.dataProvider.getFormulaParser().isNumber((String) cellValue)) { + final BigDecimal converted = this.dataProvider.getFormulaParser().convertToBigDecimal((String) cellValue); + ILayerCell temp = new LayerCell(cell.getLayer(), + cell.getOriginColumnPosition(), cell.getOriginRowPosition(), + cell.getColumnPosition(), cell.getRowPosition(), + cell.getColumnSpan(), cell.getRowSpan()) { + + @Override + public Object getDataValue() { + return converted; + } + }; + Object calculated = super.getPasteValue(temp, command, toColumn, toRow); + cellValue = (calculated != null) ? calculated.toString() : calculated; + } else { + cellValue = super.getPasteValue(cell, command, toColumn, toRow); + } + return cellValue; + } + + @Override + protected BigDecimal calculateBigDecimalDiff(ILayerCell c1, ILayerCell c2) { + BigDecimal result = null; + if (c1.getDataValue() != null && c2.getDataValue() != null) { + BigDecimal v1 = null; + if (c1.getDataValue() instanceof BigDecimal) { + v1 = (BigDecimal) c1.getDataValue(); + } else if (c1.getDataValue() instanceof String + && this.dataProvider.getFormulaParser().isNumber((String) c1.getDataValue())) { + v1 = this.dataProvider.getFormulaParser().convertToBigDecimal((String) c1.getDataValue()); + } + + BigDecimal v2 = null; + if (c2.getDataValue() instanceof BigDecimal) { + v2 = (BigDecimal) c2.getDataValue(); + } else if (c2.getDataValue() instanceof String + && this.dataProvider.getFormulaParser().isNumber((String) c2.getDataValue())) { + v2 = this.dataProvider.getFormulaParser().convertToBigDecimal((String) c2.getDataValue()); + } + + if (v1 != null && v2 != null) { + result = v1.subtract(v2); + } + } + return result; + } + +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/command/FormulaPasteDataCommandHandler.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/command/FormulaPasteDataCommandHandler.java index 0c38e518..455bc1a2 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/command/FormulaPasteDataCommandHandler.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/command/FormulaPasteDataCommandHandler.java @@ -12,92 +12,72 @@ *****************************************************************************/ package org.eclipse.nebula.widgets.nattable.formula.command; -import org.eclipse.nebula.widgets.nattable.command.AbstractLayerCommandHandler; import org.eclipse.nebula.widgets.nattable.command.ILayerCommandHandler; -import org.eclipse.nebula.widgets.nattable.coordinate.PositionCoordinate; import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard; -import org.eclipse.nebula.widgets.nattable.edit.command.EditUtils; -import org.eclipse.nebula.widgets.nattable.edit.command.UpdateDataCommand; +import org.eclipse.nebula.widgets.nattable.copy.command.InternalPasteDataCommandHandler; +import org.eclipse.nebula.widgets.nattable.copy.command.PasteDataCommand; import org.eclipse.nebula.widgets.nattable.formula.FormulaDataProvider; import org.eclipse.nebula.widgets.nattable.formula.function.FunctionException; import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer; /** - * {@link ILayerCommandHandler} for handling {@link FormulaPasteDataCommand}s. - * Uses the {@link InternalCellClipboard} and transforms formulas to match the - * new position. + * {@link ILayerCommandHandler} for handling {@link PasteDataCommand}s. Uses the + * {@link InternalCellClipboard} and transforms formulas to match the new + * position. * * @since 1.4 */ -public class FormulaPasteDataCommandHandler extends AbstractLayerCommandHandler<FormulaPasteDataCommand> { +public class FormulaPasteDataCommandHandler extends InternalPasteDataCommandHandler { - protected SelectionLayer selectionLayer; protected FormulaDataProvider dataProvider; - protected InternalCellClipboard clipboard; + /** + * + * @param selectionLayer + * {@link SelectionLayer} that is needed to determine the + * position to paste the values to. + * @param dataProvider + * the {@link FormulaDataProvider} that is needed to perform + * formula related functions on pasting data. + * @param clipboard + * The {@link InternalCellClipboard} that contains the values + * that should be pasted. + */ public FormulaPasteDataCommandHandler( SelectionLayer selectionLayer, - FormulaDataProvider dataProvider, - InternalCellClipboard clipboard) { + InternalCellClipboard clipboard, + FormulaDataProvider dataProvider) { - this.selectionLayer = selectionLayer; + super(selectionLayer, clipboard); this.dataProvider = dataProvider; - this.clipboard = clipboard; } @Override - protected boolean doCommand(FormulaPasteDataCommand command) { - if (this.clipboard.getCopiedCells() != null) { - // in case there are no cached data information held in the copied - // cells, ensure that formulas are not evaluated on paste - this.selectionLayer.doCommand(new DisableFormulaEvaluationCommand()); - - PositionCoordinate coord = this.selectionLayer.getSelectionAnchor(); - int pasteColumn = coord.getColumnPosition(); - int pasteRow = coord.getRowPosition(); - - for (ILayerCell[] cells : this.clipboard.getCopiedCells()) { - for (ILayerCell cell : cells) { - Object cellValue = cell.getDataValue(); - if (cellValue != null && this.dataProvider.getFormulaParser().isFunction(cellValue.toString())) { - try { - cellValue = this.dataProvider.getFormulaParser().updateReferences( - cellValue.toString(), cell.getColumnPosition(), cell.getRowPosition(), pasteColumn, pasteRow); - } catch (FunctionException e) { - if (this.dataProvider.getErrorReporter() != null) { - this.dataProvider.getErrorReporter().addFormulaError(pasteColumn, pasteRow, e.getLocalizedMessage()); - } - cellValue = e.getErrorMarkup(); - } - } - - if (EditUtils.isCellEditable( - this.selectionLayer, - command.getConfigRegistry(), - new PositionCoordinate(this.selectionLayer, pasteColumn, pasteRow))) { - - this.selectionLayer.doCommand(new UpdateDataCommand(this.selectionLayer, pasteColumn, pasteRow, cellValue)); - } - - pasteColumn++; - - if (pasteColumn >= this.selectionLayer.getColumnCount()) { - break; - } + protected Object getPasteValue(ILayerCell cell, int pasteColumn, int pasteRow) { + Object cellValue = cell.getDataValue(); + if (cellValue != null && this.dataProvider.getFormulaParser().isFunction(cellValue.toString())) { + try { + cellValue = this.dataProvider.getFormulaParser().updateReferences( + cellValue.toString(), cell.getColumnPosition(), cell.getRowPosition(), pasteColumn, pasteRow); + } catch (FunctionException e) { + if (this.dataProvider.getErrorReporter() != null) { + this.dataProvider.getErrorReporter().addFormulaError(pasteColumn, pasteRow, e.getLocalizedMessage()); } - pasteRow++; - pasteColumn = coord.getColumnPosition(); + cellValue = e.getErrorMarkup(); } - - this.selectionLayer.doCommand(new EnableFormulaEvaluationCommand()); } - return true; + return cellValue; + } + + @Override + protected void preInternalPaste() { + this.selectionLayer.doCommand(new DisableFormulaEvaluationCommand()); } @Override - public Class<FormulaPasteDataCommand> getCommandClass() { - return FormulaPasteDataCommand.class; + protected void postInternalPaste() { + this.selectionLayer.doCommand(new EnableFormulaEvaluationCommand()); } } diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/config/DefaultFormulaConfiguration.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/config/DefaultFormulaConfiguration.java index 183d1f65..7bda0015 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/config/DefaultFormulaConfiguration.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/config/DefaultFormulaConfiguration.java @@ -19,19 +19,23 @@ import org.eclipse.nebula.widgets.nattable.config.IEditableRule; import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard; import org.eclipse.nebula.widgets.nattable.copy.InternalClipboardStructuralChangeListener; import org.eclipse.nebula.widgets.nattable.copy.action.ClearClipboardAction; +import org.eclipse.nebula.widgets.nattable.copy.action.PasteDataAction; +import org.eclipse.nebula.widgets.nattable.copy.action.PasteOrMoveSelectionAction; import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes; import org.eclipse.nebula.widgets.nattable.edit.action.DeleteSelectionAction; import org.eclipse.nebula.widgets.nattable.edit.command.DeleteSelectionCommandHandler; import org.eclipse.nebula.widgets.nattable.edit.editor.TextCellEditor; import org.eclipse.nebula.widgets.nattable.export.command.ExportCommandHandler; +import org.eclipse.nebula.widgets.nattable.fillhandle.FillHandleLayerPainter; +import org.eclipse.nebula.widgets.nattable.fillhandle.event.FillHandleEventMatcher; import org.eclipse.nebula.widgets.nattable.formula.FormulaDataProvider; import org.eclipse.nebula.widgets.nattable.formula.FormulaEditDisplayConverter; import org.eclipse.nebula.widgets.nattable.formula.FormulaResultDisplayConverter; -import org.eclipse.nebula.widgets.nattable.formula.action.FormulaPasteDataAction; -import org.eclipse.nebula.widgets.nattable.formula.action.PasteOrMoveSelectionAction; +import org.eclipse.nebula.widgets.nattable.formula.action.FormulaFillHandleDragMode; import org.eclipse.nebula.widgets.nattable.formula.command.DisableFormulaEvaluationCommandHandler; import org.eclipse.nebula.widgets.nattable.formula.command.EnableFormulaEvaluationCommandHandler; import org.eclipse.nebula.widgets.nattable.formula.command.FormulaCopyDataCommandHandler; +import org.eclipse.nebula.widgets.nattable.formula.command.FormulaFillHandlePasteCommandHandler; import org.eclipse.nebula.widgets.nattable.formula.command.FormulaPasteDataCommandHandler; import org.eclipse.nebula.widgets.nattable.grid.GridRegion; import org.eclipse.nebula.widgets.nattable.layer.ILayer; @@ -41,6 +45,7 @@ import org.eclipse.nebula.widgets.nattable.style.BorderStyle.LineStyleEnum; import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes; import org.eclipse.nebula.widgets.nattable.style.DisplayMode; import org.eclipse.nebula.widgets.nattable.style.IStyle; +import org.eclipse.nebula.widgets.nattable.style.SelectionStyleLabels; import org.eclipse.nebula.widgets.nattable.style.Style; import org.eclipse.nebula.widgets.nattable.ui.binding.UiBindingRegistry; import org.eclipse.nebula.widgets.nattable.ui.matcher.KeyEventMatcher; @@ -98,7 +103,7 @@ public class DefaultFormulaConfiguration implements IConfiguration { CellConfigAttributes.CELL_STYLE, copyBorderStyle, DisplayMode.NORMAL, - FormulaStyleLabels.COPY_BORDER_STYLE); + SelectionStyleLabels.COPY_BORDER_STYLE); } @Override @@ -111,7 +116,7 @@ public class DefaultFormulaConfiguration implements IConfiguration { // ui binding to perform a paste action on pressing CTRL+V uiBindingRegistry.registerFirstKeyBinding( new KeyEventMatcher(SWT.MOD1, 'v'), - new FormulaPasteDataAction()); + new PasteDataAction()); // ui binding to perform paste or selection movement on ENTER uiBindingRegistry.registerFirstKeyBinding( @@ -122,6 +127,14 @@ public class DefaultFormulaConfiguration implements IConfiguration { uiBindingRegistry.registerFirstKeyBinding( new KeyEventMatcher(SWT.NONE, SWT.ESC), new ClearClipboardAction(this.clipboard)); + + // Mouse drag + // trigger the handle drag operations + // Note: we ensure a FillHandleLayerPainter is set in configureLayer + uiBindingRegistry.registerFirstMouseDragMode( + new FillHandleEventMatcher((FillHandleLayerPainter) this.selectionLayer.getLayerPainter()), + new FormulaFillHandleDragMode(this.selectionLayer, this.clipboard, this.dataProvider)); + } @Override @@ -145,8 +158,20 @@ public class DefaultFormulaConfiguration implements IConfiguration { // changes this.selectionLayer.addLayerListener(new InternalClipboardStructuralChangeListener(this.clipboard)); + // add the layer painter that renders a border around copied cells + if (!(this.selectionLayer.getLayerPainter() instanceof FillHandleLayerPainter)) { + this.selectionLayer.setLayerPainter(new FillHandleLayerPainter(this.clipboard)); + } else { + // ensure the clipboard is set + ((FillHandleLayerPainter) this.selectionLayer.getLayerPainter()).setClipboard(this.clipboard); + } + // register special copy+paste command handlers - layer.registerCommandHandler(new FormulaCopyDataCommandHandler(this.selectionLayer, this.clipboard)); - layer.registerCommandHandler(new FormulaPasteDataCommandHandler(this.selectionLayer, this.dataProvider, this.clipboard)); + layer.registerCommandHandler( + new FormulaCopyDataCommandHandler(this.selectionLayer, this.clipboard)); + layer.registerCommandHandler( + new FormulaPasteDataCommandHandler(this.selectionLayer, this.clipboard, this.dataProvider)); + layer.registerCommandHandler( + new FormulaFillHandlePasteCommandHandler(this.selectionLayer, this.clipboard, this.dataProvider)); } }
\ No newline at end of file diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/config/FormulaStyleLabels.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/config/FormulaStyleLabels.java deleted file mode 100644 index a3bdbf44..00000000 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/formula/config/FormulaStyleLabels.java +++ /dev/null @@ -1,33 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2015 CEA LIST. - * - * 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.formula.config; - -import org.eclipse.nebula.widgets.nattable.formula.FormulaLayerPainter; -import org.eclipse.nebula.widgets.nattable.formula.command.FormulaCopyDataCommandHandler; -import org.eclipse.nebula.widgets.nattable.formula.command.FormulaPasteDataCommandHandler; - -/** - * @since 1.4 - */ -public class FormulaStyleLabels { - - /** - * Style label for configuring the copy border. - * - * @see FormulaLayerPainter - * @see FormulaCopyDataCommandHandler - * @see FormulaPasteDataCommandHandler - */ - public static final String COPY_BORDER_STYLE = "copyBorderStyle"; //$NON-NLS-1$ - -} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/messages.properties b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/messages.properties index 41a7d8f7..0285d9a0 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/messages.properties +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/messages.properties @@ -176,3 +176,6 @@ FormulaParser.error.parenthesisNotClosed=Parenthesis not closed FormulaParser.error.functionParameterNotOpened=Parameter list not opened FormulaParser.error.functionParameterNotClosed=Parameter list not closed FormulaParser.error.instantiation=Could not instantiate FunctionValue: {0} + +FillHandleDragMode.menu.item.copy=Copy +FillHandleDragMode.menu.item.series=Series
\ No newline at end of file diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/messages_de.properties b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/messages_de.properties index e2f7dbd2..cd6ce1fa 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/messages_de.properties +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/messages_de.properties @@ -175,3 +175,6 @@ FormulaParser.error.parenthesisNotOpened=Klammer nicht ge\u00F6ffnet FormulaParser.error.parenthesisNotClosed=Klammer nicht geschlossen FormulaParser.error.functionParameterNotOpened=Parameterliste nicht ge\u00F6ffnet FormulaParser.error.functionParameterNotClosed=Parameterliste nicht geschlossen + +FillHandleDragMode.menu.item.copy=Kopieren +FillHandleDragMode.menu.item.series=Datenreihe auff\u00FCllen
\ No newline at end of file diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionConfigAttributes.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionConfigAttributes.java new file mode 100644 index 00000000..2f060075 --- /dev/null +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionConfigAttributes.java @@ -0,0 +1,35 @@ +/***************************************************************************** + * Copyright (c) 2015 CEA LIST. + * + * 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.selection; + +import org.eclipse.nebula.widgets.nattable.style.BorderStyle; +import org.eclipse.nebula.widgets.nattable.style.ConfigAttribute; + +/** + * This interface contains {@link ConfigAttribute}s that can be used to + * configure selection rendering, like the border style of the active selection. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + * + * @since 1.4 + */ +public interface SelectionConfigAttributes { + + /** + * ConfigAttribute to configure the line style used to render the selection + * border around selected cells. This is the line that surrounds an active + * selection. By default this is the black dotted one pixel line. + */ + ConfigAttribute<BorderStyle> SELECTION_GRID_LINE_STYLE = new ConfigAttribute<BorderStyle>(); +} diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionLayer.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionLayer.java index d1bf62c3..2fb6b311 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionLayer.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionLayer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2013, 2014 Original authors and others. + * Copyright (c) 2012, 2015 Original authors 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 @@ -27,6 +27,8 @@ import org.eclipse.nebula.widgets.nattable.coordinate.PositionCoordinate; import org.eclipse.nebula.widgets.nattable.coordinate.Range; import org.eclipse.nebula.widgets.nattable.copy.command.CopyDataCommandHandler; import org.eclipse.nebula.widgets.nattable.edit.command.EditSelectionCommandHandler; +import org.eclipse.nebula.widgets.nattable.fillhandle.FillHandleLayerPainter; +import org.eclipse.nebula.widgets.nattable.fillhandle.action.FillHandleDragMode; import org.eclipse.nebula.widgets.nattable.grid.command.InitializeAutoResizeColumnsCommandHandler; import org.eclipse.nebula.widgets.nattable.grid.command.InitializeAutoResizeRowsCommandHandler; import org.eclipse.nebula.widgets.nattable.hideshow.command.ColumnHideCommand; @@ -75,6 +77,23 @@ public class SelectionLayer extends AbstractIndexLayerTransform { protected final PositionCoordinate selectionAnchor; protected Rectangle lastSelectedRegion; + /** + * The region <i>selected</i> via fill handle to extend the current + * selection for triggering a fill action. Can be <code>null</code>. + * + * @since 1.4 + */ + protected Rectangle fillHandleRegion; + + /** + * The bottom right cell in a contiguous selection or <code>null</code> if + * there is no selection or the selection is not contiguous. Needed to + * identify the cell on which the fill handle should be rendered. + * + * @since 1.4 + */ + protected PositionCoordinate bottomRightInSelection; + protected SelectRowCommandHandler selectRowCommandHandler; protected SelectCellCommandHandler selectCellCommandHandler; protected SelectColumnCommandHandler selectColumnCommandHandler; @@ -302,8 +321,7 @@ public class SelectionLayer extends AbstractIndexLayerTransform { // null, simply set the reference if (region == null || this.lastSelectedRegion == null) { this.lastSelectedRegion = region; - } - else { + } else { // we are modifying the values of the current lastSelectedRegion // instead of setting a new reference because of reference // issues in other places @@ -496,8 +514,19 @@ public class SelectionLayer extends AbstractIndexLayerTransform { if (cellRectangle.contains(getSelectionAnchor().columnPosition, getSelectionAnchor().rowPosition)) { labelStack.addLabel(SelectionStyleLabels.SELECTION_ANCHOR_STYLE); } + + if (this.bottomRightInSelection != null + && cellRectangle.contains( + this.bottomRightInSelection.columnPosition, + this.bottomRightInSelection.rowPosition)) { + labelStack.addLabel(SelectionStyleLabels.FILL_HANDLE_CELL); + } } + if (this.fillHandleRegion != null + && this.fillHandleRegion.contains(cell.getColumnIndex(), cell.getRowIndex())) { + labelStack.addLabel(SelectionStyleLabels.FILL_HANDLE_REGION); + } return labelStack; } @@ -570,7 +599,8 @@ public class SelectionLayer extends AbstractIndexLayerTransform { * least one fully selected column position, the {@link ColumnHideCommand} * will be consumed and a {@link MultiColumnHideCommand} will be created and * executed further down the layer stack, that contains all fully selected - * column positions. Otherwise the given command will be executed further.<br> + * column positions. Otherwise the given command will be executed further. + * <br> * * This is necessary because neither the ColumnHideShowLayer nor the action * that caused the execution of the {@link ColumnHideCommand} is aware of @@ -725,4 +755,52 @@ public class SelectionLayer extends AbstractIndexLayerTransform { return super.doCommand(command); } } + + /** + * Set the region that is currently <i>selected</i> via fill handle to + * extend the current active selection for triggering a fill action. + * + * @param region + * The region <i>selected</i> via fill handle. + * + * @see FillHandleDragMode + * @see FillHandleLayerPainter + * + * @since 1.4 + */ + public void setFillHandleRegion(Rectangle region) { + this.fillHandleRegion = region; + } + + /** + * Returns the region that is currently <i>selected</i> via fill handle to + * extend the current active selection. Used to perform actions on drag + * & drop of the fill handle. + * + * @return The region <i>selected</i> via fill handle or <code>null</code>. + * + * @since 1.4 + */ + public Rectangle getFillHandleRegion() { + return this.fillHandleRegion; + } + + /** + * Marks the bottom right cell in a contiguous selection within the + * {@link SelectionLayer}. Also removes the markup in case there is no + * selection or the selection is not contiguous. + * + * @since 1.4 + */ + public void markFillHandleCell() { + ILayerCell bottomRight = SelectionUtils.getBottomRightCellInSelection(this); + if (bottomRight != null) { + this.bottomRightInSelection = new PositionCoordinate( + this, + bottomRight.getColumnPosition(), + bottomRight.getRowPosition()); + } else { + this.bottomRightInSelection = null; + } + } } diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionLayerPainter.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionLayerPainter.java index f40e0ddf..49915fa1 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionLayerPainter.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionLayerPainter.java @@ -74,8 +74,7 @@ public class SelectionLayerPainter extends GridLineCellLayerPainter { * <code>false</code> the bottom cell will be clipped. The * default value is <code>false</code>. */ - public SelectionLayerPainter(final Color gridColor, boolean clipLeft, - boolean clipTop) { + public SelectionLayerPainter(final Color gridColor, boolean clipLeft, boolean clipTop) { super(gridColor, clipLeft, clipTop); } @@ -99,68 +98,63 @@ public class SelectionLayerPainter extends GridLineCellLayerPainter { } @Override - public void paintLayer(ILayer natLayer, GC gc, int xOffset, int yOffset, - Rectangle pixelRectangle, IConfigRegistry configRegistry) { - Rectangle positionRectangle = getPositionRectangleFromPixelRectangle( - natLayer, pixelRectangle); + public void paintLayer( + ILayer natLayer, GC gc, + int xOffset, int yOffset, Rectangle pixelRectangle, + IConfigRegistry configRegistry) { + + Rectangle positionRectangle = getPositionRectangleFromPixelRectangle(natLayer, pixelRectangle); int columnPositionOffset = positionRectangle.x; int rowPositionOffset = positionRectangle.y; - super.paintLayer(natLayer, gc, xOffset, yOffset, pixelRectangle, - configRegistry); + super.paintLayer(natLayer, gc, xOffset, yOffset, pixelRectangle, configRegistry); // Save gc settings int originalLineStyle = gc.getLineStyle(); + int originalLineWidth = gc.getLineWidth(); Color originalForeground = gc.getForeground(); // Apply border settings applyBorderStyle(gc, configRegistry); // Draw horizontal borders - for (int columnPosition = columnPositionOffset; columnPosition < columnPositionOffset - + positionRectangle.width; columnPosition++) { + for (int columnPosition = columnPositionOffset; columnPosition < columnPositionOffset + positionRectangle.width; columnPosition++) { + ILayerCell previousCell = null; ILayerCell currentCell = null; ILayerCell afterCell = null; - for (int rowPosition = rowPositionOffset; rowPosition < rowPositionOffset - + positionRectangle.height; rowPosition++) { - currentCell = natLayer.getCellByPosition(columnPosition, - rowPosition); - afterCell = natLayer.getCellByPosition(columnPosition, - rowPosition + 1); + for (int rowPosition = rowPositionOffset; rowPosition < rowPositionOffset + positionRectangle.height; rowPosition++) { + + currentCell = natLayer.getCellByPosition(columnPosition, rowPosition); + afterCell = natLayer.getCellByPosition(columnPosition, rowPosition + 1); if (currentCell != null) { Rectangle currentCellBounds = currentCell.getBounds(); if (isSelected(currentCell)) { int x0 = currentCellBounds.x - 1; - int x1 = currentCellBounds.x + currentCellBounds.width - - 1; + int x1 = currentCellBounds.x + currentCellBounds.width - 1; int y = currentCellBounds.y - 1; if (previousCell != null) { - Rectangle previousCellBounds = previousCell - .getBounds(); + Rectangle previousCellBounds = previousCell.getBounds(); x0 = Math.max(x0, previousCellBounds.x - 1); - x1 = Math.min(x1, previousCellBounds.x - + previousCellBounds.width - 1); + x1 = Math.min(x1, previousCellBounds.x + previousCellBounds.width - 1); } - if (previousCell == null || !isSelected(previousCell)) + if (previousCell == null || !isSelected(previousCell)) { gc.drawLine(x0, y, x1, y); + } // check after if (afterCell == null || !isSelected(afterCell)) { - Rectangle cellBounds = afterCell != null ? afterCell - .getBounds() : currentCell.getBounds(); + Rectangle cellBounds = afterCell != null ? afterCell.getBounds() : currentCell.getBounds(); - y = currentCellBounds.y + currentCellBounds.height - - 1; + y = currentCellBounds.y + currentCellBounds.height - 1; x0 = Math.max(x0, cellBounds.x - 1); - x1 = Math.min(x1, cellBounds.x + cellBounds.width - - 1); + x1 = Math.min(x1, cellBounds.x + cellBounds.width - 1); gc.drawLine(x0, y, x1, y); } @@ -171,18 +165,16 @@ public class SelectionLayerPainter extends GridLineCellLayerPainter { if (positionRectangle.width == 2 || positionRectangle.height == 2) { if (afterCell != null && isSelected(afterCell)) { - Rectangle afterCellBounds = afterCell - .getBounds(); + Rectangle afterCellBounds = afterCell.getBounds(); - int x0 = Math.max(afterCellBounds.x - 1, + int x0 = Math.max( + afterCellBounds.x - 1, currentCellBounds.x - 1); - int x1 = Math.min(afterCellBounds.x - + afterCellBounds.width - 1, - currentCellBounds.x - + currentCellBounds.width - 1); + int x1 = Math.min( + afterCellBounds.x + afterCellBounds.width - 1, + currentCellBounds.x + currentCellBounds.width - 1); - int y = currentCellBounds.y - + currentCellBounds.height - 1; + int y = currentCellBounds.y + currentCellBounds.height - 1; gc.drawLine(x0, y, x1, y); } } @@ -193,50 +185,43 @@ public class SelectionLayerPainter extends GridLineCellLayerPainter { } // Draw vertical borders - for (int rowPosition = rowPositionOffset; rowPosition < rowPositionOffset - + positionRectangle.height; rowPosition++) { + for (int rowPosition = rowPositionOffset; rowPosition < rowPositionOffset + positionRectangle.height; rowPosition++) { + ILayerCell previousCell = null; ILayerCell currentCell = null; ILayerCell afterCell = null; - for (int columnPosition = columnPositionOffset; columnPosition < columnPositionOffset - + positionRectangle.width; columnPosition++) { - currentCell = natLayer.getCellByPosition(columnPosition, - rowPosition); - afterCell = natLayer.getCellByPosition(columnPosition + 1, - rowPosition); + for (int columnPosition = columnPositionOffset; columnPosition < columnPositionOffset + positionRectangle.width; columnPosition++) { + + currentCell = natLayer.getCellByPosition(columnPosition, rowPosition); + afterCell = natLayer.getCellByPosition(columnPosition + 1, rowPosition); if (currentCell != null) { Rectangle currentCellBounds = currentCell.getBounds(); if (isSelected(currentCell)) { int y0 = currentCellBounds.y - 1; - int y1 = currentCellBounds.y + currentCellBounds.height - - 1; + int y1 = currentCellBounds.y + currentCellBounds.height - 1; int x = currentCellBounds.x - 1; if (previousCell != null) { - Rectangle previousCellBounds = previousCell - .getBounds(); + Rectangle previousCellBounds = previousCell.getBounds(); y0 = Math.max(y0, previousCellBounds.y - 1); - y1 = Math.min(y1, previousCellBounds.y - + previousCellBounds.height - 1); + y1 = Math.min(y1, previousCellBounds.y + previousCellBounds.height - 1); } - if (previousCell == null || !isSelected(previousCell)) + if (previousCell == null || !isSelected(previousCell)) { gc.drawLine(x, y0, x, y1); + } // check after if (afterCell == null || !isSelected(afterCell)) { - Rectangle cellBounds = afterCell != null ? afterCell - .getBounds() : currentCell.getBounds(); + Rectangle cellBounds = afterCell != null ? afterCell.getBounds() : currentCell.getBounds(); - x = currentCellBounds.x + currentCellBounds.width - - 1; + x = currentCellBounds.x + currentCellBounds.width - 1; y0 = Math.max(y0, cellBounds.y - 1); - y1 = Math.min(y1, cellBounds.y + cellBounds.height - - 1); + y1 = Math.min(y1, cellBounds.y + cellBounds.height - 1); gc.drawLine(x, y0, x, y1); } @@ -244,24 +229,19 @@ public class SelectionLayerPainter extends GridLineCellLayerPainter { // check if previous was selected to not override the // border again // this is necessary because of single cell updates - // check if previous was selected to not override the - // border again - // this is necessary because of single cell updates if (positionRectangle.width == 2 || positionRectangle.height == 2) { if (afterCell != null && isSelected(afterCell)) { - Rectangle afterCellBounds = afterCell - .getBounds(); + Rectangle afterCellBounds = afterCell.getBounds(); - int y0 = Math.max(afterCellBounds.y - 1, + int y0 = Math.max( + afterCellBounds.y - 1, currentCellBounds.y - 1); - int y1 = Math.min(afterCellBounds.y - + afterCellBounds.height - 1, - currentCellBounds.y - + currentCellBounds.height - 1); + int y1 = Math.min( + afterCellBounds.y + afterCellBounds.height - 1, + currentCellBounds.y + currentCellBounds.height - 1); - int x = currentCellBounds.x - + currentCellBounds.width - 1; + int x = currentCellBounds.x + currentCellBounds.width - 1; gc.drawLine(x, y0, x, y1); } } @@ -273,31 +253,38 @@ public class SelectionLayerPainter extends GridLineCellLayerPainter { // Restore original gc settings gc.setLineStyle(originalLineStyle); + gc.setLineWidth(originalLineWidth); gc.setForeground(originalForeground); } private boolean isSelected(ILayerCell cell) { - return (cell.getDisplayMode() == DisplayMode.SELECT || cell - .getDisplayMode() == DisplayMode.SELECT_HOVER); + return (cell.getDisplayMode() == DisplayMode.SELECT + || cell.getDisplayMode() == DisplayMode.SELECT_HOVER); } protected void applyBorderStyle(GC gc, IConfigRegistry configRegistry) { - // Note: If there is no style configured for the - // SelectionStyleLabels.SELECTION_ANCHOR_GRID_LINE_STYLE - // label, the style configured for DisplayMode.SELECT will be retrieved - // by this call. - // Ensure that the selection style configuration does not contain a - // border style configuration - // to avoid strange rendering behaviour. By default there is no border - // configuration added, - // so there shouldn't be issues with backwards compatibility. And if - // there are some, they can - // be solved easily by adding the necessary border style configuration. - IStyle cellStyle = configRegistry.getConfigAttribute( - CellConfigAttributes.CELL_STYLE, DisplayMode.SELECT, - SelectionStyleLabels.SELECTION_ANCHOR_GRID_LINE_STYLE); - BorderStyle borderStyle = cellStyle != null ? cellStyle - .getAttributeValue(CellStyleAttributes.BORDER_STYLE) : null; + BorderStyle borderStyle = configRegistry.getConfigAttribute( + SelectionConfigAttributes.SELECTION_GRID_LINE_STYLE, + DisplayMode.SELECT); + + // check for backwards compatibility style configuration + if (borderStyle == null) { + // Note: If there is no style configured for the + // SelectionStyleLabels.SELECTION_ANCHOR_GRID_LINE_STYLE + // label, the style configured for DisplayMode.SELECT will be + // retrieved by this call. + // Ensure that the selection style configuration does not contain a + // border style configuration to avoid strange rendering behavior. + // By default there is no border configuration added, so there + // shouldn't be issues with backwards compatibility. And if there + // are some, they can be solved easily by adding the necessary + // border style configuration. + IStyle cellStyle = configRegistry.getConfigAttribute( + CellConfigAttributes.CELL_STYLE, + DisplayMode.SELECT, + SelectionStyleLabels.SELECTION_ANCHOR_GRID_LINE_STYLE); + borderStyle = cellStyle != null ? cellStyle.getAttributeValue(CellStyleAttributes.BORDER_STYLE) : null; + } // if there is no border style configured, use the default one for // backwards compatibility diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionUtils.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionUtils.java index 5172cad0..f9b0527a 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionUtils.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/selection/SelectionUtils.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012 Original authors and others. + * Copyright (c) 2012, 2015 Original authors 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 @@ -10,25 +10,169 @@ ******************************************************************************/ package org.eclipse.nebula.widgets.nattable.selection; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import org.eclipse.nebula.widgets.nattable.coordinate.PositionCoordinate; +import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; + +/** + * Helper class to operate with selections. + */ public class SelectionUtils { - public static boolean noShiftOrControl(boolean withShiftMask, - boolean withControlMask) { + /** + * + * @param withShiftMask + * flag to indicate whether the shift masked is active + * @param withControlMask + * flag to indicate whether the control masked is active + * @return <code>true</code> if both, shift and control mask, are not active + */ + public static boolean noShiftOrControl(boolean withShiftMask, boolean withControlMask) { return !withShiftMask && !withControlMask; } - public static boolean bothShiftAndControl(boolean withShiftMask, - boolean withControlMask) { + /** + * + * @param withShiftMask + * flag to indicate whether the shift masked is active + * @param withControlMask + * flag to indicate whether the control masked is active + * @return <code>true</code> if both, shift and control mask are active + */ + public static boolean bothShiftAndControl(boolean withShiftMask, boolean withControlMask) { return withShiftMask && withControlMask; } - public static boolean isControlOnly(boolean withShiftMask, - boolean withControlMask) { + /** + * + * @param withShiftMask + * flag to indicate whether the shift masked is active + * @param withControlMask + * flag to indicate whether the control masked is active + * @return <code>true</code> if only the control mask is active + */ + public static boolean isControlOnly(boolean withShiftMask, boolean withControlMask) { return !withShiftMask && withControlMask; } - public static boolean isShiftOnly(boolean withShiftMask, - boolean withControlMask) { + /** + * + * @param withShiftMask + * flag to indicate whether the shift masked is active + * @param withControlMask + * flag to indicate whether the control masked is active + * @return <code>true</code> if only the shift mask is active + */ + public static boolean isShiftOnly(boolean withShiftMask, boolean withControlMask) { return withShiftMask && !withControlMask; } + + /** + * Test if the numbers in the given array are consecutive. If there are + * duplicates or gaps in the array, <code>false</code> will be returned. + * + * @param pos + * the array of numbers to check + * @return <code>true</code> if the numbers are consecutive, + * <code>false</code> if there are duplicates or gaps. + * + * @since 1.4 + */ + public static boolean isConsecutive(int[] pos) { + for (int i = 1; i < pos.length; i++) { + if (pos[i - 1] + 1 != pos[i]) { + return false; + } + } + return true; + } + + /** + * Checks whether the selected region tracked by the given + * {@link SelectionLayer} is consecutive or not. + * + * @param selectionLayer + * The {@link SelectionLayer} that tracks the selection. + * @return <code>true</code> if the current selection is consecutive, + * <code>false</code> if not. + * + * @since 1.4 + */ + public static boolean hasConsecutiveSelection(SelectionLayer selectionLayer) { + if (selectionLayer != null + && SelectionUtils.isConsecutive(selectionLayer.getSelectedColumnPositions())) { + + Map<Integer, Set<Integer>> positions = new HashMap<Integer, Set<Integer>>(); + int column = -1; + int row = -1; + + // collect the selection information + for (PositionCoordinate coord : selectionLayer.getSelectedCellPositions()) { + Set<Integer> rows = positions.get(coord.columnPosition); + if (rows == null) { + rows = new LinkedHashSet<Integer>(); + positions.put(coord.columnPosition, rows); + } + rows.add(coord.rowPosition); + + column = Math.max(column, coord.columnPosition); + row = Math.max(row, coord.rowPosition); + } + + // check if the selected region is a rectangle + // every row collection for each column needs to have the same size + // and the same content + Set<Integer> previous = null; + for (Set<Integer> rows : positions.values()) { + if (previous != null && !previous.equals(rows)) { + return false; + } + previous = rows; + } + + // test if rows are consecutive + if (previous != null) { + int[] rowPositions = new int[previous.size()]; + int i = 0; + for (Integer rowPos : previous) { + rowPositions[i++] = rowPos; + } + if (SelectionUtils.isConsecutive(rowPositions)) { + return true; + } + } + } + return false; + } + + /** + * Returns the bottom right cell of a selected region. Will only return an + * ILayerCell if the selected region is consecutive. Otherwise + * <code>null</code> will be returned. + * + * @param selectionLayer + * The {@link SelectionLayer} needed to determine the selection. + * + * @return The bottom right cell of a selected region or <code>null</code> + * if the selected region is not consecutive. + * + * @since 1.4 + */ + public static ILayerCell getBottomRightCellInSelection(SelectionLayer selectionLayer) { + if (hasConsecutiveSelection(selectionLayer)) { + int column = -1; + int row = -1; + for (PositionCoordinate coord : selectionLayer.getSelectedCellPositions()) { + column = Math.max(column, coord.columnPosition); + row = Math.max(row, coord.rowPosition); + } + return selectionLayer.getCellByPosition(column, row); + } + return null; + } + } diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/style/SelectionStyleLabels.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/style/SelectionStyleLabels.java index 3146d9d0..cd6e8fac 100644 --- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/style/SelectionStyleLabels.java +++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/style/SelectionStyleLabels.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012 Original authors and others. + * Copyright (c) 2012, 2015 Original authors 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 @@ -10,18 +10,72 @@ ******************************************************************************/ package org.eclipse.nebula.widgets.nattable.style; +import org.eclipse.nebula.widgets.nattable.copy.command.InternalCopyDataCommandHandler; +import org.eclipse.nebula.widgets.nattable.copy.command.InternalPasteDataCommandHandler; +import org.eclipse.nebula.widgets.nattable.fillhandle.FillHandleLayerPainter; +import org.eclipse.nebula.widgets.nattable.formula.CopySelectionLayerPainter; import org.eclipse.nebula.widgets.nattable.grid.GridRegion; +/** + * Interface that contains labels that are used to style selection related + * components. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ public interface SelectionStyleLabels { - public static final String SELECTION_ANCHOR_STYLE = "selectionAnchor"; //$NON-NLS-1$ + /** + * Label that is applied to the cell which is currently holding the + * selection anchor. + */ + String SELECTION_ANCHOR_STYLE = "selectionAnchor"; //$NON-NLS-1$ + + /** + * Label that is used to configure the line style of the selection grid + * line. This is the line that surrounds an active selection. By default + * this is the black dotted one pixel line. + */ + String SELECTION_ANCHOR_GRID_LINE_STYLE = "selectionAnchorGridLine"; //$NON-NLS-1$ + + /** + * Label that is applied to the column header cell of the column that is + * fully selected. + */ + String COLUMN_FULLY_SELECTED_STYLE = GridRegion.COLUMN_HEADER + "_FULL"; //$NON-NLS-1$ - public static final String SELECTION_ANCHOR_GRID_LINE_STYLE = "selectionAnchorGridLine"; //$NON-NLS-1$ + /** + * Label that is applied to the row header cell of the row that is fully + * selected. + */ + String ROW_FULLY_SELECTED_STYLE = GridRegion.ROW_HEADER + "_FULL"; //$NON-NLS-1$ - public static final String COLUMN_FULLY_SELECTED_STYLE = GridRegion.COLUMN_HEADER - + "_FULL"; //$NON-NLS-1$ + /** + * Label that is used to mark cells as part of the fill handle region. This + * is the region that is <i>selected</i> via fill handle to trigger a fill + * action (copy/series) by dragging a current selection. + * + * @since 1.4 + */ + String FILL_HANDLE_REGION = "FILL_HANDLE_REGION"; //$NON-NLS-1$ - public static final String ROW_FULLY_SELECTED_STYLE = GridRegion.ROW_HEADER - + "_FULL"; //$NON-NLS-1$ + /** + * Label that is added to the bottom right cell of a contiguous selection. + * Used to mark the cell for rendering the fill handle. + * + * @since 1.4 + */ + String FILL_HANDLE_CELL = "selectionHandleCell"; //$NON-NLS-1$ + /** + * Style label for configuring the copy border. + * + * @see CopySelectionLayerPainter + * @see FillHandleLayerPainter + * @see InternalCopyDataCommandHandler + * @see InternalPasteDataCommandHandler + * + * @since 1.4 + */ + String COPY_BORDER_STYLE = "copyBorderStyle"; //$NON-NLS-1$ } diff --git a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_300_Data/_305_FormulaDataExample.java b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_300_Data/_305_FormulaDataExample.java index 78a6a1da..ecdfb323 100644 --- a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_300_Data/_305_FormulaDataExample.java +++ b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_300_Data/_305_FormulaDataExample.java @@ -18,15 +18,14 @@ import org.eclipse.nebula.widgets.nattable.config.AbstractRegistryConfiguration; import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry; import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration; import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; -import org.eclipse.nebula.widgets.nattable.copy.InternalCellClipboard; import org.eclipse.nebula.widgets.nattable.data.IDataProvider; import org.eclipse.nebula.widgets.nattable.examples.AbstractNatExample; import org.eclipse.nebula.widgets.nattable.examples.runner.StandaloneNatExampleRunner; import org.eclipse.nebula.widgets.nattable.export.ExportConfigAttributes; import org.eclipse.nebula.widgets.nattable.extension.poi.HSSFExcelExporter; import org.eclipse.nebula.widgets.nattable.extension.poi.PoiExcelExporter; +import org.eclipse.nebula.widgets.nattable.fillhandle.config.FillHandleConfiguration; import org.eclipse.nebula.widgets.nattable.formula.FormulaDataProvider; -import org.eclipse.nebula.widgets.nattable.formula.FormulaLayerPainter; import org.eclipse.nebula.widgets.nattable.formula.FormulaTooltipErrorReporter; import org.eclipse.nebula.widgets.nattable.formula.command.DisableFormulaEvaluationCommand; import org.eclipse.nebula.widgets.nattable.formula.command.EnableFormulaEvaluationCommand; @@ -100,15 +99,16 @@ public class _305_FormulaDataExample extends AbstractNatExample { final FormulaBodyLayerStack bodyLayer = gridLayer.getBodyLayer(); - // This is the formula specific configuration - InternalCellClipboard clipboard = new InternalCellClipboard(); + natTable.addConfiguration(new FillHandleConfiguration(bodyLayer.getSelectionLayer())); + // This is the formula specific configuration natTable.addConfiguration( - new DefaultFormulaConfiguration(bodyLayer.getFormulaDataProvider(), bodyLayer.getSelectionLayer(), clipboard)); + new DefaultFormulaConfiguration( + bodyLayer.getFormulaDataProvider(), + bodyLayer.getSelectionLayer(), + natTable.getInternalCellClipboard())); bodyLayer.getFormulaDataProvider().setErrorReporter(new FormulaTooltipErrorReporter(natTable, bodyLayer.getDataLayer())); - bodyLayer.getSelectionLayer().setLayerPainter(new FormulaLayerPainter(clipboard)); - natTable.addConfiguration(new AbstractRegistryConfiguration() { @Override @@ -134,8 +134,7 @@ public class _305_FormulaDataExample extends AbstractNatExample { if (_305_FormulaDataExample.this.evaluationEnabled) { natTable.doCommand(new EnableFormulaEvaluationCommand()); toggleFormulaButton.setText("Disable Formula Evaluation"); - } - else { + } else { natTable.doCommand(new DisableFormulaEvaluationCommand()); toggleFormulaButton.setText("Enable Formula Evaluation"); } @@ -226,9 +225,10 @@ public class _305_FormulaDataExample extends AbstractNatExample { bodyLayer, selectionLayer); // Corner - ILayer cornerLayer = new CornerLayer(new DataLayer( - new DefaultCornerDataProvider(columnHeaderDataProvider, - rowHeaderDataProvider)), rowHeaderLayer, + ILayer cornerLayer = new CornerLayer( + new DataLayer( + new DefaultCornerDataProvider(columnHeaderDataProvider, rowHeaderDataProvider)), + rowHeaderLayer, columnHeaderLayer); setBodyLayer(bodyLayer); |
