/* * Copyright 2015 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.widget.grid.renderers.grids.impl; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; import org.uberfire.commons.validation.PortablePreconditions; 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.util.ColumnIndexUtilities; import org.uberfire.ext.wires.core.grids.client.widget.grid.renderers.grids.SelectionsTransformer; /** * Helper functions to convert SelectedCells into SelectedRanges. */ public class DefaultSelectionsTransformer implements SelectionsTransformer { protected final GridData model; protected final List<GridColumn<?>> columns; public DefaultSelectionsTransformer(final GridData model, final List<GridColumn<?>> columns) { this.model = PortablePreconditions.checkNotNull("model", model); this.columns = PortablePreconditions.checkNotNull("columns", columns); } @Override public List<SelectedRange> transformToSelectedRanges() { //Group into vertical ranges translating modelColumnIndexes to uiColumnIndexes int currentUiColumnIndex = -1; SelectedRange currentRange = null; final List<GridData.SelectedCell> orderedSelectedCells = sortSelectedCells(); final Map<Integer, List<SelectedRange>> orderedSelectedRanges = new TreeMap<Integer, List<SelectedRange>>(); for (GridData.SelectedCell selectedCell : orderedSelectedCells) { final int scRowIndex = selectedCell.getRowIndex(); final int scColumnIndex = selectedCell.getColumnIndex(); final int uiColumnIndex = ColumnIndexUtilities.findUiColumnIndex(getApplicableColumns(), scColumnIndex); if (uiColumnIndex != currentUiColumnIndex) { storeSelectedRange(orderedSelectedRanges, currentRange, currentUiColumnIndex); currentUiColumnIndex = uiColumnIndex; currentRange = new SelectedRange(scRowIndex, uiColumnIndex, 1, 1); } else if (scRowIndex == currentRange.getUiRowIndex() + currentRange.getHeight()) { currentRange.setHeight(currentRange.getHeight() + 1); } else { storeSelectedRange(orderedSelectedRanges, currentRange, uiColumnIndex); currentRange = new SelectedRange(scRowIndex, uiColumnIndex, 1, 1); } } storeSelectedRange(orderedSelectedRanges, currentRange, currentUiColumnIndex); //Group vertical ranges horizontally final int maxColumnIndex = getMaximumColumnIndex(orderedSelectedRanges); for (Map.Entry<Integer, List<SelectedRange>> e : orderedSelectedRanges.entrySet()) { for (SelectedRange selectedRange : e.getValue()) { for (int mergeColumnIndex = e.getKey() + 1; mergeColumnIndex <= maxColumnIndex; mergeColumnIndex++) { final List<SelectedRange> mergeRanges = orderedSelectedRanges.get(mergeColumnIndex); if (mergeRanges == null) { break; } final Iterator<SelectedRange> srIterator = mergeRanges.iterator(); while (srIterator.hasNext()) { final SelectedRange mergeRange = srIterator.next(); if (selectedRange.getUiRowIndex() == mergeRange.getUiRowIndex()) { if (selectedRange.getUiColumnIndex() + selectedRange.getWidth() == mergeRange.getUiColumnIndex()) { if (selectedRange.getHeight() == mergeRange.getHeight()) { selectedRange.setWidth(selectedRange.getWidth() + 1); srIterator.remove(); } } } } } } } //Dump into a single list final List<SelectedRange> selectedRanges = new ArrayList<SelectedRange>(); for (List<SelectedRange> ranges : orderedSelectedRanges.values()) { selectedRanges.addAll(ranges); } return selectedRanges; } private int getMaximumColumnIndex(final Map<Integer, List<SelectedRange>> selectedRanges) { int maxColumnIndex = 0; for (Integer idx : selectedRanges.keySet()) { maxColumnIndex = Math.max(maxColumnIndex, idx); } return maxColumnIndex; } private void storeSelectedRange(final Map<Integer, List<SelectedRange>> orderedSelectedRanges, final SelectedRange currentRange, final int uiColumnIndex) { if (currentRange != null) { List<SelectedRange> selectedRanges = orderedSelectedRanges.get(uiColumnIndex); if (selectedRanges == null) { selectedRanges = new ArrayList<SelectedRange>(); orderedSelectedRanges.put(uiColumnIndex, selectedRanges); } selectedRanges.add(currentRange); } } protected List<GridColumn<?>> getApplicableColumns() { return model.getColumns(); } //Sort arbitrary selections by column->row to simplify grouping private List<GridData.SelectedCell> sortSelectedCells() { final List<GridData.SelectedCell> selectedCells = new ArrayList<GridData.SelectedCell>(); for (GridData.SelectedCell sc : model.getSelectedCells()) { if (isSelectionInColumns(sc)) { selectedCells.add(sc); } } final int rowCount = model.getRowCount(); Collections.sort(selectedCells, new Comparator<GridData.SelectedCell>() { @Override public int compare(final GridData.SelectedCell o1, final GridData.SelectedCell o2) { //(0,0)->0, (1,0)->3, (2,0)->6 //(0,1)->1, (1,1)->4, (2,1)->7 //(0,2)->2, (1,2)->5, (2,2)->8 final int o1Index = o1.getRowIndex() + o1.getColumnIndex() * rowCount; final int o2Index = o2.getRowIndex() + o2.getColumnIndex() * rowCount; return o1Index - o2Index; } }); return selectedCells; } private boolean isSelectionInColumns(final GridData.SelectedCell sc) { final int scColumnIndex = sc.getColumnIndex(); for (GridColumn<?> column : columns) { final int columnIndex = column.getIndex(); if (scColumnIndex == columnIndex) { return true; } } return false; } }