/******************************************************************************* * * 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.spi.impl.formula; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.netxilia.api.exception.EvaluationException; import org.netxilia.api.exception.NetxiliaBusinessException; import org.netxilia.api.exception.NetxiliaResourceException; import org.netxilia.api.exception.NotFoundException; import org.netxilia.api.exception.StorageException; import org.netxilia.api.formula.IFormulaContext; import org.netxilia.api.model.AbsoluteAlias; import org.netxilia.api.model.CellData; import org.netxilia.api.model.ISheet; import org.netxilia.api.model.SheetData; import org.netxilia.api.model.SheetDimensions; import org.netxilia.api.model.SheetFullName; import org.netxilia.api.reference.AreaReference; import org.netxilia.api.reference.CellReference; import org.netxilia.api.value.ErrorValue; import org.netxilia.api.value.ErrorValueType; import org.netxilia.api.value.IGenericValue; import org.springframework.util.Assert; public class FormulaContextImpl implements IFormulaContext { private final ISheet sheet; private final CellReference contextCell; private Map<SheetFullName, ISheet> openSheets = new HashMap<SheetFullName, ISheet>(); public FormulaContextImpl(ISheet sheet, CellReference contextCell) { Assert.notNull(sheet); this.sheet = sheet; this.contextCell = contextCell; } public CellReference getContextCell() { return contextCell; } protected ISheet getSheet(String sheetName) { SheetFullName sheetFullName = new SheetFullName(sheet.getFullName().getWorkbookId(), sheetName); ISheet retSheet = openSheets.get(sheetFullName); if (retSheet == null) { try { retSheet = sheet.getWorkbook().getSheet(sheetFullName.getSheetName()); } catch (StorageException e) { throw new EvaluationException(ErrorValueType.REF, e); } catch (NotFoundException e) { throw new EvaluationException(ErrorValueType.REF, e); } openSheets.put(sheetFullName, retSheet); } return retSheet; } @Override public Iterator<CellData> getCellIterator(AreaReference ref) { ISheet currentSheet; if (ref.getSheetName() == null) { currentSheet = sheet; } else { currentSheet = getSheet(ref.getSheetName()); } if (currentSheet == null) { return Collections.<CellData> emptyList().iterator(); } // TODO shift also areas!? // int r = getRowIndex(ref); // int c = getColumnIndex(ref); SheetDimensions dim; try { dim = currentSheet.getDimensions().getNonBlocking(); } catch (NetxiliaResourceException e) { throw new EvaluationException(ErrorValueType.REF, e); } catch (NetxiliaBusinessException e) { throw new EvaluationException(ErrorValueType.REF, e); } return new CellIterator(currentSheet, ref.iterator(dim.getRowCount(), dim.getColumnCount())); } @Override public IGenericValue getCellValue(CellReference ref) { ISheet currentSheet; if (ref.getSheetName() == null) { currentSheet = sheet; } else { currentSheet = getSheet(ref.getSheetName()); } if (currentSheet == null) { return new ErrorValue(ErrorValueType.REF); } int r = ref.getRowIndex(); int c = ref.getColumnIndex(); try { CellData cell = null; SheetDimensions dim = currentSheet.getDimensions().getNonBlocking(); if (r >= dim.getRowCount() || c >= dim.getColumnCount()) { return new ErrorValue(ErrorValueType.REF); } cell = currentSheet.receiveCell(new CellReference(r, c)).getNonBlocking(); // TODO - here we assume the value is already calculated if the cell is a formula. Should check this! return cell != null ? cell.getValue() : new ErrorValue(ErrorValueType.REF); } catch (NetxiliaResourceException e) { return new ErrorValue(ErrorValueType.REF); } catch (NetxiliaBusinessException e) { return new ErrorValue(ErrorValueType.REF); } } @Override public AreaReference resolveAlias(AbsoluteAlias alias) { ISheet currentSheet; if (alias.getSheetName() == null) { currentSheet = sheet; } else { currentSheet = getSheet(alias.getSheetName()); } if (currentSheet == null) { return null; } SheetData sheetData; try { sheetData = currentSheet.receiveSheet().getNonBlocking(); } catch (NetxiliaResourceException e) { throw new EvaluationException(ErrorValueType.REF, e); } catch (NetxiliaBusinessException e) { throw new EvaluationException(ErrorValueType.REF, e); } AreaReference ref = sheetData.resolveAlias(alias.getAlias()); if (ref == null) { return null; } // ref may not have the sheet name set. make sure the area reference is absolute return ref.withSheetName(alias.getSheetName()); } @Override public CellReference getCell() { return contextCell; } @Override public ISheet getSheet() { return sheet; } }