/* * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.uberfire.ext.wires.core.grids.client.model.impl; import java.util.ArrayList; import java.util.List; import org.uberfire.ext.wires.core.grids.client.model.GridCell; import org.uberfire.ext.wires.core.grids.client.model.GridColumn; import org.uberfire.ext.wires.core.grids.client.model.GridData; import org.uberfire.ext.wires.core.grids.client.model.GridRow; import org.uberfire.ext.wires.core.grids.client.util.ColumnIndexUtilities; /** * Helper class that manages "selected cell" meta-data following different mutations to {@link GridData} */ public class BaseGridDataSelectionsManager { private final GridData gridData; public BaseGridDataSelectionsManager(final GridData gridData) { this.gridData = gridData; } public void onMerge(final boolean isMerged) { if (isMerged) { final List<GridData.SelectedCell> selectedCells = gridData.getSelectedCells(); final List<GridData.SelectedCell> cloneSelectedCells = new ArrayList<GridData.SelectedCell>(selectedCells); gridData.clearSelections(); for (GridData.SelectedCell cell : cloneSelectedCells) { gridData.selectCells(cell.getRowIndex(), ColumnIndexUtilities.findUiColumnIndex(gridData.getColumns(), cell.getColumnIndex()), 1, 1); } } } public void onDeleteColumn(final int index) { final List<GridData.SelectedCell> selectedCells = gridData.getSelectedCells(); final List<GridData.SelectedCell> selectedCellsToRemove = new ArrayList<GridData.SelectedCell>(); final List<GridData.SelectedCell> selectedCellsToUpdate = new ArrayList<GridData.SelectedCell>(); for (GridData.SelectedCell sc : selectedCells) { if (sc.getColumnIndex() == index) { selectedCellsToRemove.add(sc); } else if (sc.getColumnIndex() > index) { selectedCellsToUpdate.add(sc); } } selectedCells.removeAll(selectedCellsToRemove); selectedCells.removeAll(selectedCellsToUpdate); for (GridData.SelectedCell sc : selectedCellsToUpdate) { selectedCells.add(new GridData.SelectedCell(sc.getRowIndex(), sc.getColumnIndex() - 1)); } } public void onInsertRow(final int rowIndex) { final List<GridData.SelectedCell> selectedCells = gridData.getSelectedCells(); final List<GridData.SelectedCell> selectedCellsToUpdate = new ArrayList<GridData.SelectedCell>(); for (GridData.SelectedCell sc : selectedCells) { if (sc.getRowIndex() >= rowIndex) { selectedCellsToUpdate.add(sc); } } selectedCells.removeAll(selectedCellsToUpdate); for (GridData.SelectedCell sc : selectedCellsToUpdate) { selectedCells.add(new GridData.SelectedCell(sc.getRowIndex() + 1, sc.getColumnIndex())); } } public void onDeleteRow(final GridData.Range range) { final int minRowIndex = range.getMinRowIndex(); final int maxRowIndex = range.getMaxRowIndex(); final List<GridData.SelectedCell> selectedCells = gridData.getSelectedCells(); final List<GridData.SelectedCell> selectedCellsToRemove = new ArrayList<GridData.SelectedCell>(); final List<GridData.SelectedCell> selectedCellsToUpdate = new ArrayList<GridData.SelectedCell>(); for (GridData.SelectedCell sc : selectedCells) { if (sc.getRowIndex() >= minRowIndex && sc.getRowIndex() <= maxRowIndex) { selectedCellsToRemove.add(sc); } else if (sc.getRowIndex() > maxRowIndex) { selectedCellsToUpdate.add(sc); } } selectedCells.removeAll(selectedCellsToRemove); selectedCells.removeAll(selectedCellsToUpdate); for (GridData.SelectedCell sc : selectedCellsToUpdate) { selectedCells.add(new GridData.SelectedCell(sc.getRowIndex() - 1, sc.getColumnIndex())); } } public GridData.Range onSelectCell(final int rowIndex, final int columnIndex) { if (gridData.isMerged()) { return selectCellMerged(rowIndex, columnIndex); } else { selectCellNotMerged(rowIndex, columnIndex); return new GridData.Range(rowIndex); } } public GridData.Range onSelectCells(final int rowIndex, final int columnIndex, final int width, final int height) { //If we're not merged just set the value of a single cell if (!gridData.isMerged()) { selectCellsNotMerged(rowIndex, columnIndex, width, height); return new GridData.Range(rowIndex); } //Find affected rows for merged data int _columnIndex; int minRowIndex = rowIndex; int maxRowIndex = rowIndex + height - 1; final List<GridColumn<?>> columns = gridData.getColumns(); for (int ci = columnIndex; ci < columnIndex + width; ci++) { _columnIndex = columns.get(ci).getIndex(); minRowIndex = Math.min(minRowIndex, findMinRowIndex(minRowIndex, _columnIndex)); maxRowIndex = Math.max(maxRowIndex, findMaxRowIndex(maxRowIndex, _columnIndex)); } //Select all applicable rows' cells selectCellsNotMerged(minRowIndex, columnIndex, width, maxRowIndex - minRowIndex + 1); return new GridData.Range(minRowIndex, maxRowIndex); } private GridData.Range selectCellMerged(final int rowIndex, final int columnIndex) { //Find affected rows for merged data final List<GridColumn<?>> columns = gridData.getColumns(); final int _columnIndex = columns.get(columnIndex).getIndex(); final int minRowIndex = findMinRowIndex(rowIndex, _columnIndex); final int maxRowIndex = findMaxRowIndex(rowIndex, _columnIndex); //Select all applicable rows' cells selectCellsNotMerged(minRowIndex, columnIndex, 1, maxRowIndex - minRowIndex + 1); return new GridData.Range(minRowIndex, maxRowIndex); } private GridData.Range selectCellNotMerged(final int rowIndex, final int columnIndex) { final List<GridRow> rows = gridData.getRows(); final List<GridColumn<?>> columns = gridData.getColumns(); final List<GridData.SelectedCell> selectedCells = gridData.getSelectedCells(); final GridData.Range range = new GridData.Range(rowIndex); if (rowIndex < 0 || rowIndex > rows.size() - 1) { return range; } if (columnIndex < 0 || columnIndex > columns.size() - 1) { return range; } final int _columnIndex = columns.get(columnIndex).getIndex(); final GridData.SelectedCell selectedCell = new GridData.SelectedCell(rowIndex, _columnIndex); if (!selectedCells.contains(selectedCell)) { selectedCells.add(selectedCell); } return range; } private GridData.Range selectCellsNotMerged(final int rowIndex, final int columnIndex, final int width, final int height) { final List<GridRow> rows = gridData.getRows(); final List<GridColumn<?>> columns = gridData.getColumns(); final List<GridData.SelectedCell> selectedCells = gridData.getSelectedCells(); final GridData.Range range = new GridData.Range(rowIndex); if (rowIndex < 0 || rowIndex > rows.size() - 1) { return range; } if (columnIndex < 0 || columnIndex > columns.size() - 1) { return range; } if (width < 1) { return range; } if (height < 1) { return range; } for (int ri = rowIndex; ri < rowIndex + height; ri++) { for (int ci = columnIndex; ci < columnIndex + width; ci++) { final int _columnIndex = columns.get(ci).getIndex(); final GridData.SelectedCell selectedCell = new GridData.SelectedCell(ri, _columnIndex); if (!selectedCells.contains(selectedCell)) { selectedCells.add(selectedCell); } } } return new GridData.Range(rowIndex, rowIndex + height - 1); } private int findMinRowIndex(final int rowIndex, final int columnIndex) { int minRowIndex = rowIndex; final GridRow currentRow = gridData.getRow(rowIndex); final GridCell<?> currentRowCell = currentRow.getCells().get(columnIndex); //Find minimum row with a cell containing the same value as that being updated boolean foundTopSplitMarker = currentRowCell != null && currentRowCell.getMergedCellCount() > 0; while (minRowIndex > 0) { final GridRow previousRow = gridData.getRow(minRowIndex - 1); final GridCell<?> previousRowCell = previousRow.getCells().get(columnIndex); if (!(previousRow.isCollapsed() && currentRow.isCollapsed())) { if (previousRowCell == null) { break; } if (previousRowCell.isCollapsed() && foundTopSplitMarker) { break; } if (!previousRowCell.equals(currentRowCell)) { break; } if (previousRowCell.getMergedCellCount() > 0) { foundTopSplitMarker = true; } } minRowIndex--; } return minRowIndex; } private int findMaxRowIndex(final int rowIndex, final int columnIndex) { int maxRowIndex = rowIndex + 1; final GridRow currentRow = gridData.getRow(rowIndex); final GridCell<?> currentRowCell = currentRow.getCells().get(columnIndex); //Find maximum row with a cell containing the same value as that being updated boolean foundBottomSplitMarker = false; while (maxRowIndex < gridData.getRowCount()) { final GridRow nextRow = gridData.getRow(maxRowIndex); final GridCell<?> nextRowCell = nextRow.getCells().get(columnIndex); if (!nextRow.isCollapsed()) { if (nextRowCell == null) { break; } if (nextRowCell.isCollapsed() && foundBottomSplitMarker) { maxRowIndex--; break; } if (!nextRowCell.equals(currentRowCell)) { break; } if (nextRowCell.getMergedCellCount() > 0) { foundBottomSplitMarker = true; } } maxRowIndex++; } return maxRowIndex - 1; } public void onMoveRows(final List<GridRow> rowsMoved, final GridData.Range oldBlockExtent) { final List<GridRow> rows = gridData.getRows(); final int oldBlockStart = oldBlockExtent.getMinRowIndex(); final int oldBlockEnd = oldBlockExtent.getMaxRowIndex(); final int newBlockStart = rows.indexOf(rowsMoved.get(0)); final int newBlockEnd = rows.indexOf(rowsMoved.get(rowsMoved.size() - 1)); final List<GridData.SelectedCell> selectedCells = gridData.getSelectedCells(); final List<GridData.SelectedCell> selectedCellsToMoveUp = new ArrayList<GridData.SelectedCell>(); final List<GridData.SelectedCell> selectedCellsToMoveDown = new ArrayList<GridData.SelectedCell>(); final List<GridData.SelectedCell> selectedCellsToUpdate = new ArrayList<GridData.SelectedCell>(); if (newBlockStart < oldBlockStart) { //Moving row(s) up for (GridData.SelectedCell sc : selectedCells) { if (sc.getRowIndex() >= oldBlockStart && sc.getRowIndex() <= oldBlockEnd) { selectedCellsToMoveUp.add(sc); } else if (sc.getRowIndex() >= newBlockStart && sc.getRowIndex() <= newBlockEnd) { selectedCellsToMoveDown.add(sc); } else if (sc.getRowIndex() > newBlockEnd && sc.getRowIndex() < oldBlockStart) { selectedCellsToUpdate.add(sc); } } selectedCells.removeAll(selectedCellsToMoveUp); selectedCells.removeAll(selectedCellsToMoveDown); selectedCells.removeAll(selectedCellsToUpdate); for (GridData.SelectedCell sc : selectedCellsToMoveUp) { selectedCells.add(new GridData.SelectedCell(sc.getRowIndex() - (oldBlockStart - newBlockStart), sc.getColumnIndex())); } for (GridData.SelectedCell sc : selectedCellsToMoveDown) { selectedCells.add(new GridData.SelectedCell(sc.getRowIndex() + (oldBlockEnd - oldBlockStart) + 1, sc.getColumnIndex())); } for (GridData.SelectedCell sc : selectedCellsToUpdate) { selectedCells.add(new GridData.SelectedCell(sc.getRowIndex() + (oldBlockEnd - oldBlockStart) + 1, sc.getColumnIndex())); } } else if (newBlockStart > oldBlockStart) { //Moving row(s) down for (GridData.SelectedCell sc : selectedCells) { if (sc.getRowIndex() >= oldBlockStart && sc.getRowIndex() <= oldBlockEnd) { selectedCellsToMoveDown.add(sc); } else if (sc.getRowIndex() >= newBlockStart && sc.getRowIndex() <= newBlockEnd) { selectedCellsToMoveUp.add(sc); } else if (sc.getRowIndex() > oldBlockEnd && sc.getRowIndex() < newBlockStart) { selectedCellsToUpdate.add(sc); } } selectedCells.removeAll(selectedCellsToMoveUp); selectedCells.removeAll(selectedCellsToMoveDown); selectedCells.removeAll(selectedCellsToUpdate); for (GridData.SelectedCell sc : selectedCellsToMoveUp) { selectedCells.add(new GridData.SelectedCell(sc.getRowIndex() - (oldBlockEnd - oldBlockStart) - 1, sc.getColumnIndex())); } for (GridData.SelectedCell sc : selectedCellsToMoveDown) { selectedCells.add(new GridData.SelectedCell(sc.getRowIndex() + (newBlockStart - oldBlockStart), sc.getColumnIndex())); } for (GridData.SelectedCell sc : selectedCellsToUpdate) { selectedCells.add(new GridData.SelectedCell(sc.getRowIndex() - (newBlockEnd - newBlockStart) - 1, sc.getColumnIndex())); } } } }