/******************************************************************************* * * Copyright 2010 Alexandru Craciun, and individual contributors as indicated * by the @authors tag. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 3 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. ******************************************************************************/ package org.netxilia.api.model; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.netxilia.api.reference.AreaReference; import org.netxilia.api.reference.CellReference; /** * Used to manipulate the row and column spans present in {@link SheetData#getSpans()}. It returns the column and the * row spans for a given cell. It can also be used to add a new merge area. * * @author <a href='mailto:ax.craciun@gmail.com'>Alexandru Craciun</a> * */ public class SpanTable { // private static final Pair<Integer, Integer> INVISIBLE = new Pair<Integer, Integer>(-1, -1); /** * contains the value of the spans for the top left corners and -1 for the "invisible cells" */ private final Map<CellReference, SheetDimensions> spans = new HashMap<CellReference, SheetDimensions>(); public SpanTable(List<AreaReference> spanList) { for (AreaReference area : spanList) { addAreaDirectly(area); } } private void addAreaDirectly(AreaReference area) { for (int r = area.getFirstRowIndex(); r <= area.getLastRowIndex(); ++r) { for (int c = area.getFirstColumnIndex(); c <= area.getLastColumnIndex(); ++c) { spans.put(new CellReference(r, c), new SheetDimensions(area.getFirstRowIndex() - r, area.getFirstColumnIndex() - c)); } } spans.put(area.getTopLeft(), new SheetDimensions(area.getRowCount(), area.getColumnCount())); } private void removeArea(AreaReference area) { for (CellReference cell : area) { spans.remove(cell); } } private SheetDimensions getSpan(CellReference ref) { CellReference searchRef = ref; if (searchRef.getSheetName() != null) { // refs are relative (no sheet name) searchRef = searchRef.withSheetName(null); } return spans.get(searchRef); } public int getRowSpan(CellReference ref) { SheetDimensions span = getSpan(ref); if (span == null) { return 1; } return span.getRowCount() <= 0 ? -1 : span.getRowCount(); } public int getColSpan(CellReference ref) { SheetDimensions span = getSpan(ref); if (span == null) { return 1; } return span.getColumnCount() <= 0 ? -1 : span.getColumnCount(); } private AreaReference getArea(CellReference currentPos, SheetDimensions currentDim) { if (currentDim.getRowCount() >= 1 && currentDim.getColumnCount() >= 1) { // the currentPos is the top left corner return new AreaReference(currentPos, new CellReference(currentPos.getRowIndex() + currentDim.getRowCount() - 1, currentPos.getColumnIndex() + currentDim.getColumnCount() - 1)); } CellReference topLeftCorner = new CellReference(currentPos.getRowIndex() + currentDim.getRowCount(), currentPos.getColumnIndex() + currentDim.getColumnCount()); SheetDimensions topLeftDim = spans.get(topLeftCorner); if (topLeftDim == null) { throw new IllegalStateException("Could not find dimension for corner:" + topLeftCorner); } return getArea(topLeftCorner, topLeftDim); } /** * if this area goes completely inside an existing area, then remove this span.<br> * if this area is outside any other area, use as is.<br> * if this area intersects existing areas, a new region containing all the cells will replace all * * @param area */ public void toggleSpan(AreaReference area) { int firstRow = area.getFirstRowIndex(); int lastRow = area.getLastRowIndex(); int firstCol = area.getFirstColumnIndex(); int lastCol = area.getLastColumnIndex(); for (CellReference cell : area) { SheetDimensions dim = spans.get(cell); if (dim != null) { AreaReference foundArea = getArea(cell, dim); firstRow = Math.min(foundArea.getFirstRowIndex(), firstRow); lastRow = Math.max(foundArea.getLastRowIndex(), lastRow); firstCol = Math.min(foundArea.getFirstColumnIndex(), firstCol); lastCol = Math.max(foundArea.getLastColumnIndex(), lastCol); removeArea(foundArea); if (foundArea.contains(area)) { return; } } } addAreaDirectly(new AreaReference(null, firstRow, firstCol, lastRow, lastCol)); } public List<AreaReference> getSpans() { List<AreaReference> spanList = new ArrayList<AreaReference>(); for (Map.Entry<CellReference, SheetDimensions> entry : spans.entrySet()) { if (entry.getValue().getRowCount() >= 1 && entry.getValue().getColumnCount() >= 1) { spanList.add(getArea(entry.getKey(), entry.getValue())); } } return spanList; } }