blob: 6798bb69288d06889db181b85564f3769e131339 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2020 Original authors and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Original authors and others - initial API and implementation
* Dirk Fauth <dirk.fauth@googlemail.com> - Bug 458537
* Thorsten Schlathölter <tschlat@gmx.de> - Bug 467047
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.search.strategy;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.coordinate.PositionCoordinate;
import org.eclipse.nebula.widgets.nattable.coordinate.Range;
import org.eclipse.nebula.widgets.nattable.layer.ILayer;
import org.eclipse.nebula.widgets.nattable.search.ISearchDirection;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
public class GridSearchStrategy extends AbstractSearchStrategy {
private final IConfigRegistry configRegistry;
public GridSearchStrategy(IConfigRegistry configRegistry, boolean wrapSearch, boolean columnFirst) {
this(configRegistry, wrapSearch, ISearchDirection.SEARCH_FORWARD, columnFirst);
}
public GridSearchStrategy(IConfigRegistry configRegistry, boolean wrapSearch, String searchDirection, boolean columnFirst) {
this.configRegistry = configRegistry;
this.wrapSearch = wrapSearch;
this.searchDirection = searchDirection;
this.columnFirst = columnFirst;
}
public static class GridRectangle {
Range firstDim;
Range secondDim;
}
@Override
public PositionCoordinate executeSearch(Object valueToMatch) {
ILayer contextLayer = getContextLayer();
if (!(contextLayer instanceof SelectionLayer)) {
throw new IllegalStateException("For the GridSearchStrategy to work it needs the selectionLayer to be passed as the contextLayer."); //$NON-NLS-1$
}
SelectionLayer selectionLayer = (SelectionLayer) contextLayer;
PositionCoordinate selectionAnchor = selectionLayer.getSelectionAnchor();
// Pick start and end values depending on the direction of the search.
int direction = this.searchDirection.equals(ISearchDirection.SEARCH_FORWARD) ? 1 : -1;
boolean hadSelectionAnchor = selectionAnchor.columnPosition >= 0 && selectionAnchor.rowPosition >= 0;
if (!hadSelectionAnchor) {
selectionAnchor.columnPosition = 0;
selectionAnchor.rowPosition = 0;
}
// Pick a first and second dimension based on whether it's a column or
// row-first search.
int firstDimPosition;
int firstDimCount;
int secondDimPosition;
int secondDimCount;
if (this.columnFirst) {
firstDimPosition = selectionAnchor.columnPosition;
firstDimCount = selectionLayer.getColumnCount();
secondDimPosition = selectionAnchor.rowPosition;
secondDimCount = selectionLayer.getRowCount();
} else {
firstDimPosition = selectionAnchor.rowPosition;
firstDimCount = selectionLayer.getRowCount();
secondDimPosition = selectionAnchor.columnPosition;
secondDimCount = selectionLayer.getColumnCount();
}
int firstDimStart;
int firstDimEnd;
int secondDimStart;
int secondDimEnd;
if (direction == 1) {
firstDimStart = 0;
firstDimEnd = firstDimCount;
secondDimStart = 0;
secondDimEnd = secondDimCount;
} else {
firstDimStart = firstDimCount - 1;
firstDimEnd = -1;
secondDimStart = secondDimCount - 1;
secondDimEnd = -1;
}
// Move to the next cell if a selection was active and it's not
// an incremental search.
final boolean startWithNextCell = hadSelectionAnchor && !isIncremental();
if (startWithNextCell) {
if (secondDimPosition + direction != secondDimEnd) {
// Increment the second dimension
secondDimPosition += direction;
} else {
// Wrap the second dimension
secondDimPosition = secondDimStart;
if (firstDimPosition + direction != firstDimEnd) {
// Increment the first dimension
firstDimPosition += direction;
} else if (this.wrapSearch) {
// Wrap the first dimension
firstDimPosition = firstDimStart;
} else {
// Fail outright because there's nothing to search
return null;
}
}
}
// Get a sequence of ranges for searching.
List<GridRectangle> gridRanges = getRanges(
firstDimPosition,
secondDimPosition,
direction,
firstDimStart,
firstDimEnd,
secondDimStart,
secondDimEnd);
// Perform the search.
@SuppressWarnings("unchecked")
Comparator<String> comparator = (Comparator<String>) getComparator();
return CellDisplayValueSearchUtil.findCell(
getContextLayer(),
this.configRegistry,
gridRanges,
valueToMatch,
comparator,
isCaseSensitive(),
isWholeWord(),
isRegex(),
isColumnFirst(),
isIncludeCollapsed());
}
/**
* Divides the grid search into multiple, sequential ranges, with single
* slices at the starting point and multiple slices elsewhere.
*
* @param firstDimPosition
* @param secondDimPosition
* @param direction
* @param firstDimStart
* @param firstDimEnd
* @param secondDimStart
* @param secondDimEnd
* @return
*/
private List<GridRectangle> getRanges(
int firstDimPosition, int secondDimPosition, int direction,
int firstDimStart, int firstDimEnd, int secondDimStart, int secondDimEnd) {
List<GridRectangle> gridRanges = new ArrayList<>();
GridRectangle gridRange;
// One first-dimension slice starting at the second
// dimension selection.
gridRange = new GridRectangle();
gridRange.firstDim = new Range(firstDimPosition, firstDimPosition + direction);
gridRange.secondDim = new Range(secondDimPosition, secondDimEnd);
gridRanges.add(gridRange);
if (firstDimStart == 0 && firstDimEnd == 0) {
// Bug 458537 - this might happen for a grid without content rows
return gridRanges;
}
// One or more first-dimension slices to the wrapping boundary.
gridRange = new GridRectangle();
gridRange.firstDim = new Range(firstDimPosition + direction, firstDimEnd);
gridRange.secondDim = new Range(secondDimStart, secondDimEnd);
gridRanges.add(gridRange);
// We're done if wrapping is not enabled or if we've already covered the
// whole table.
if (!this.wrapSearch
|| firstDimPosition == firstDimStart && secondDimPosition == secondDimStart) {
return gridRanges;
}
// One or more first-dimension slices after wrapping, up to the
// first-dimension slice with the starting point.
gridRange = new GridRectangle();
gridRange.firstDim = new Range(firstDimStart, firstDimPosition);
gridRange.secondDim = new Range(secondDimStart, secondDimEnd);
gridRanges.add(gridRange);
// One first-dimension slice ending at the second-dimension selection.
gridRange = new GridRectangle();
gridRange.firstDim = new Range(firstDimPosition, firstDimPosition + direction);
gridRange.secondDim = new Range(secondDimStart, secondDimPosition);
gridRanges.add(gridRange);
return gridRanges;
}
}