123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- /* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You 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.apache.poi.ss.usermodel.helpers;
-
- import java.util.ArrayList;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Set;
-
- import org.apache.poi.ss.usermodel.Row;
- import org.apache.poi.ss.usermodel.Sheet;
- import org.apache.poi.ss.util.CellRangeAddress;
- import org.apache.poi.util.Beta;
-
- /**
- * Helper for shifting columns up or down
- *
- * @since POI 4.0.0
- */
- // non-Javadoc: This abstract class exists to consolidate duplicated code between XSSFColumnShifter and HSSFColumnShifter
- // (currently methods sprinkled throughout HSSFSheet)
- @Beta
- public abstract class ColumnShifter extends BaseRowColShifter {
- protected final Sheet sheet;
-
- public ColumnShifter(Sheet sh) {
- sheet = sh;
- }
-
- /**
- * Shifts, grows, or shrinks the merged regions due to a column shift.
- * Merged regions that are completely overlaid by shifting will be deleted.
- *
- * @param startColumn the column to start shifting
- * @param endColumn the column to end shifting
- * @param n the number of columns to shift
- * @return an array of affected merged regions, doesn't contain deleted ones
- * @since POI 4.0.0
- */
- // Keep this code in sync with {@link RowShifter#shiftMergedRegions}
- @Override
- public List<CellRangeAddress> shiftMergedRegions(int startColumn, int endColumn, int n) {
- List<CellRangeAddress> shiftedRegions = new ArrayList<>();
- Set<Integer> removedIndices = new HashSet<>();
- //move merged regions completely if they fall within the new region boundaries when they are shifted
- int size = sheet.getNumMergedRegions();
- for (int i = 0; i < size; i++) {
- CellRangeAddress merged = sheet.getMergedRegion(i);
-
- // remove merged region that are replaced by the shifting,
- // i.e. where the area includes something in the overwritten area
- if(removalNeeded(merged, startColumn, endColumn, n)) {
- removedIndices.add(i);
- continue;
- }
-
- boolean inStart = (merged.getFirstColumn() >= startColumn || merged.getLastColumn() >= startColumn);
- boolean inEnd = (merged.getFirstColumn() <= endColumn || merged.getLastColumn() <= endColumn);
-
- //don't check if it's not within the shifted area
- if (!inStart || !inEnd) {
- continue;
- }
-
- //only shift if the region outside the shifted columns is not merged too
- if (!merged.containsColumn(startColumn - 1) && !merged.containsColumn(endColumn + 1)) {
- merged.setFirstColumn(merged.getFirstColumn() + n);
- merged.setLastColumn(merged.getLastColumn() + n);
- //have to remove/add it back
- shiftedRegions.add(merged);
- removedIndices.add(i);
- }
- }
-
- if(!removedIndices.isEmpty()) {
- sheet.removeMergedRegions(removedIndices);
- }
-
- //read so it doesn't get shifted again
- for (CellRangeAddress region : shiftedRegions) {
- sheet.addMergedRegion(region);
- }
- return shiftedRegions;
- }
-
- // Keep in sync with {@link RowShifter#removalNeeded}
- private boolean removalNeeded(CellRangeAddress merged, int startColumn, int endColumn, int n) {
- final int movedColumns = endColumn - startColumn + 1;
-
- // build a range of the columns that are overwritten, i.e. the target-area, but without
- // columns that are moved along
- final CellRangeAddress overwrite;
- if(n > 0) {
- // area is moved down => overwritten area is [endColumn + n - movedColumns, endColumn + n]
- final int firstCol = Math.max(endColumn + 1, endColumn + n - movedColumns);
- final int lastCol = endColumn + n;
- overwrite = new CellRangeAddress(0, 0, firstCol, lastCol);
- } else {
- // area is moved up => overwritten area is [startColumn + n, startColumn + n + movedColumns]
- final int firstCol = startColumn + n;
- final int lastCol = Math.min(startColumn - 1, startColumn + n + movedColumns);
- overwrite = new CellRangeAddress(0, 0, firstCol, lastCol);
- }
-
- // if the merged-region and the overwritten area intersect, we need to remove it
- return merged.intersects(overwrite);
- }
-
- public void shiftColumns(int firstShiftColumnIndex, int lastShiftColumnIndex, int step){
- if(step > 0){
- for (Row row : sheet)
- if(row != null)
- row.shiftCellsRight(firstShiftColumnIndex, lastShiftColumnIndex, step);
- }
- else if(step < 0){
- for (Row row : sheet)
- if(row != null)
- row.shiftCellsLeft(firstShiftColumnIndex, lastShiftColumnIndex, -step);
- }
- //else step == 0 => nothing to shift
- }
- }
|