Source for org.jfree.formula.lvalues.DefaultDataTable

   1: /**
   2:  * =========================================
   3:  * LibFormula : a free Java formula library
   4:  * =========================================
   5:  *
   6:  * Project Info:  http://reporting.pentaho.org/libformula/
   7:  *
   8:  * (C) Copyright 2006-2007, by Pentaho Corporation and Contributors.
   9:  *
  10:  * This library is free software; you can redistribute it and/or modify it under the terms
  11:  * of the GNU Lesser General Public License as published by the Free Software Foundation;
  12:  * either version 2.1 of the License, or (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  15:  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16:  * See the GNU Lesser General Public License for more details.
  17:  *
  18:  * You should have received a copy of the GNU Lesser General Public License along with this
  19:  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  20:  * Boston, MA 02111-1307, USA.
  21:  *
  22:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  23:  * in the United States and other countries.]
  24:  *
  25:  *
  26:  * ------------
  27:  * $Id: DefaultDataTable.java 3521 2007-10-16 10:55:14Z tmorgner $
  28:  * ------------
  29:  * (C) Copyright 2006-2007, by Pentaho Corporation.
  30:  */
  31: package org.jfree.formula.lvalues;
  32: 
  33: import org.jfree.formula.EvaluationException;
  34: import org.jfree.formula.FormulaContext;
  35: import org.jfree.formula.LibFormulaErrorValue;
  36: import org.jfree.formula.typing.Type;
  37: import org.jfree.formula.typing.ArrayCallback;
  38: import org.jfree.formula.typing.coretypes.AnyType;
  39: import org.jfree.util.ObjectTable;
  40: 
  41: /**
  42:  * Creation-Date: 05.11.2006, 13:34:01
  43:  *
  44:  * @author Thomas Morgner
  45:  * @author Cedric Pronzato
  46:  */
  47: public class DefaultDataTable extends ObjectTable implements DataTable
  48: {
  49: 
  50:   private static class DefaultArrayCallback implements ArrayCallback
  51:   {
  52:     private DefaultDataTable table;
  53:     private TypeValuePair[][] backend;
  54: 
  55:     private DefaultArrayCallback(final DefaultDataTable table)
  56:     {
  57:       this.table = table;
  58:       backend = new TypeValuePair[table.getRowCount()][table.getColumnCount()];
  59:     }
  60: 
  61:     public LValue getRaw(final int row, final int column)
  62:     {
  63:       return table.getValueAt(row, column);
  64:     }
  65: 
  66:     public Object getValue(final int row, final int column) throws EvaluationException
  67:     {
  68:       final TypeValuePair value = get(row, column);
  69:       return value.getValue();
  70:     }
  71: 
  72:     private TypeValuePair get(final int row, final int column)
  73:         throws EvaluationException
  74:     {
  75:       TypeValuePair value = backend[row][column];
  76:       if(value == null)
  77:       {
  78:         value = getRaw(row, column).evaluate();
  79:         backend[row][column] = value;
  80:       }
  81:       return value;
  82:     }
  83: 
  84:     public Type getType(final int row, final int column) throws EvaluationException
  85:     {
  86:       return get(row, column).getType();
  87:     }
  88: 
  89:     public int getColumnCount()
  90:     {
  91:       return table.getColumnCount();
  92:     }
  93: 
  94:     public int getRowCount()
  95:     {
  96:       return table.getRowCount();
  97:     }
  98:   }
  99: 
 100:   private transient Boolean constant;
 101:   private static final LValue[] EMPTY_LVALUES = new LValue[0];
 102: 
 103:   /**
 104:    * Creates a new table.
 105:    */
 106:   public DefaultDataTable()
 107:   {
 108:   }
 109: 
 110:   public DefaultDataTable(final LValue[][] array)
 111:   {
 112:     if(array != null && array.length > 0)
 113:     {
 114:       final int colCount = array[0].length;
 115:       //TODO: check if it is safe to do that
 116:       setData(array, colCount);
 117:     }
 118:   }
 119: 
 120:   public String getColumnName(int column)
 121:   {
 122:     final StringBuffer result = new StringBuffer();
 123:     for (; column >= 0; column = column / 26 - 1)
 124:     {
 125:       final int colChar = (char) (column % 26) + 'A';
 126:       result.append(colChar);
 127:     }
 128:     return result.toString();
 129:   }
 130: 
 131:   /**
 132:    * Sets the object for a cell in the table.  The table is expanded if
 133:    * necessary.
 134:    *
 135:    * @param row    the row index (zero-based).
 136:    * @param column the column index (zero-based).
 137:    * @param object the object.
 138:    */
 139:   public void setObject(final int row, final int column, final LValue object)
 140:   {
 141:     super.setObject(row, column, object);
 142:   }
 143: 
 144:   public LValue getValueAt(final int row, final int column)
 145:   {
 146:     return (LValue) getObject(row, column);
 147:   }
 148: 
 149:   public void initialize(final FormulaContext context) throws EvaluationException
 150:   {
 151:     final int rows = getRowCount();
 152:     final int cols = getColumnCount();
 153:     for (int row = 0; row < rows; row++)
 154:     {
 155:       for (int col = 0; col < cols; col++)
 156:       {
 157:         final LValue value = getValueAt(row, col);
 158:         if(value != null)
 159:         {
 160:           value.initialize(context);
 161:         }
 162:       }
 163:     }
 164:   }
 165: 
 166:   public TypeValuePair evaluate() throws EvaluationException
 167:   {
 168:     int colCount = -1;
 169:     final LValue[][] array = (LValue[][])getData();
 170:     for(int i=0; i<array.length; i++)
 171:     {
 172:       final LValue[] row = array[i];
 173:       if(colCount > 0 && row.length != colCount)
 174:       {
 175:         // error, different column count is not allowed
 176:         throw new EvaluationException(LibFormulaErrorValue.ERROR_ILLEGAL_ARRAY_VALUE);
 177:       }
 178:       else
 179:       {
 180:         colCount = row.length;
 181:       }
 182:     }
 183:     return new TypeValuePair(AnyType.ANY_ARRAY, new DefaultArrayCallback(this));
 184:   }
 185: 
 186:   public Object clone() throws CloneNotSupportedException
 187:   {
 188:     final DefaultDataTable table = (DefaultDataTable) super.clone();
 189:     final Object[][] data = getData();
 190:     final Object[][] targetData = (Object[][]) data.clone();
 191:     for (int i = 0; i < targetData.length; i++)
 192:     {
 193:       final Object[] objects = targetData[i];
 194:       if (objects == null)
 195:       {
 196:         continue;
 197:       }
 198: 
 199:       targetData[i] = (Object[]) objects.clone();
 200:       for (int j = 0; j < objects.length; j++)
 201:       {
 202:         final LValue object = (LValue) objects[j];
 203:         if (object == null)
 204:         {
 205:           continue;
 206:         }
 207:         objects[j] = object.clone();
 208:       }
 209:     }
 210: 
 211:     table.setData(targetData, getColumnCount());
 212:     return table;
 213:   }
 214: 
 215:   /**
 216:    * Querying the value type is only valid *after* the value has been
 217:    * evaluated.
 218:    *
 219:    * @return
 220:    */
 221:   public Type getValueType()
 222:   {
 223:     return AnyType.ANY_ARRAY;
 224:   }
 225: 
 226:   /**
 227:    * Returns any dependent lvalues (parameters and operands, mostly).
 228:    *
 229:    * @return
 230:    */
 231:   public LValue[] getChildValues()
 232:   {
 233:     // too expensive ...
 234:     return EMPTY_LVALUES;
 235:   }
 236: 
 237:   /**
 238:    * Checks, whether the LValue is constant. Constant lvalues always return the
 239:    * same value.
 240:    *
 241:    * @return
 242:    */
 243:   public boolean isConstant()
 244:   {
 245:     if (constant == null)
 246:     {
 247:       if (computeConstantValue())
 248:       {
 249:         constant = Boolean.TRUE;
 250:       }
 251:       else
 252:       {
 253:         constant = Boolean.FALSE;
 254:       }
 255:     }
 256: 
 257:     return Boolean.TRUE.equals(constant);
 258:   }
 259: 
 260:   private boolean computeConstantValue()
 261:   {
 262:     final int rows = getRowCount();
 263:     final int cols = getColumnCount();
 264:     for (int row = 0; row < rows; row++)
 265:     {
 266:       for (int col = 0; col < cols; col++)
 267:       {
 268:         final LValue value = getValueAt(row, col);
 269:         if (value.isConstant() == false)
 270:         {
 271:           return false;
 272:         }
 273:       }
 274:     }
 275:     return true;
 276:   }
 277: }