001 /*
002 * Copyright (c) 2005 Einar Pehrson <einar@pehrson.nu>.
003 *
004 * This file is part of
005 * CleanSheets - a spreadsheet application for the Java platform.
006 *
007 * CleanSheets is free software; you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as published by
009 * the Free Software Foundation; either version 2 of the License, or
010 * (at your option) any later version.
011 *
012 * CleanSheets is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with CleanSheets; if not, write to the Free Software
019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020 */
021 package csheets.core.formula.lang;
022
023 import csheets.core.Cell;
024 import csheets.core.Spreadsheet;
025 import csheets.core.Value;
026 import csheets.core.formula.BinaryOperator;
027 import csheets.core.formula.Expression;
028 import csheets.core.formula.Reference;
029
030 /**
031 * A reference to a range of cells in a spreadsheet.
032 * @author Einar Pehrson
033 */
034 public class RangeReference implements BinaryOperator {
035
036 /** The unique version identifier used for serialization */
037 private static final long serialVersionUID = 8527083457981256682L;
038
039 /**
040 * Creates a new range reference operator.
041 */
042 public RangeReference() {}
043
044 public Value applyTo(Expression leftOperand, Expression rightOperand) {
045 // Casts operands
046 if (!(leftOperand instanceof CellReference && rightOperand instanceof CellReference))
047 return new Value(new IllegalArgumentException("#OPERAND!"));
048 CellReference ref1 = (CellReference)leftOperand;
049 CellReference ref2 = (CellReference)rightOperand;
050
051 // Fetches the cells
052 Cell[][] cells;
053 try {
054 cells = getCells(ref1, ref2);
055 } catch (IllegalArgumentException e) {
056 return new Value(e);
057 }
058
059 // Fetches the values
060 Value[][] values = new Value[cells.length][cells[0].length];
061 for (int row = 0; row < cells.length; row++)
062 for (int column = 0; column < cells[row].length; column++)
063 values[row][column] = cells[row][column].getValue();
064 return new Value(values);
065 }
066
067 /**
068 * Returns the range of cells formed by the two cell references.
069 * @param reference1 the first reference
070 * @param reference2 the other reference
071 * @return an array of the cells that constitute the range
072 */
073 public Cell[][] getCells(Reference reference1, Reference reference2) {
074 // Casts operands
075 if (!(reference1 instanceof CellReference && reference2 instanceof CellReference))
076 throw new IllegalArgumentException("#OPERAND!");
077 CellReference ref1 = (CellReference)reference1;
078 CellReference ref2 = (CellReference)reference2;
079
080 // Checks that the references point to cells in the same spreadsheet
081 Spreadsheet spreadsheet = ref1.getCell().getSpreadsheet();
082 if (spreadsheet != ref2.getCell().getSpreadsheet())
083 throw new IllegalArgumentException("#3DREF!");
084
085 // Fetches coordinates
086 int column1 = ref1.getCell().getAddress().getColumn();
087 int column2 = ref2.getCell().getAddress().getColumn();
088 int row1 = ref1.getCell().getAddress().getRow();
089 int row2 = ref2.getCell().getAddress().getRow();
090 int startColumn = column1 <= column2 ? column1 : column2;
091 int endColumn = column1 <= column2 ? column2 : column1;
092 int startRow = row1 <= row2 ? row1 : row2;
093 int endRow = row1 <= row2 ? row2 : row1;
094
095 // Builds the matrix
096 Cell[][] matrix = new Cell
097 [endRow - startRow + 1]
098 [endColumn - startColumn + 1];
099 for (int row = 0; row < matrix.length; row++)
100 for (int column = 0; column < matrix[row].length; column++)
101 matrix[row][column] = spreadsheet.getCell
102 (column + startColumn, row + startRow);
103 return matrix;
104 }
105
106 public String getIdentifier() {
107 return ":";
108 }
109
110 public Value.Type getOperandValueType() {
111 return Value.Type.NUMERIC;
112 }
113
114 public String toString() {
115 return getIdentifier();
116 }
117 }