KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jxl > write > biff > FormulaRecord


1 /*********************************************************************
2 *
3 * Copyright (C) 2002 Andrew Khan
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ***************************************************************************/

19
20 package jxl.write.biff;
21
22 import common.Assert;
23 import common.Logger;
24
25 import jxl.CellType;
26 import jxl.Sheet;
27 import jxl.FormulaCell;
28 import jxl.WorkbookSettings;
29 import jxl.CellReferenceHelper;
30 import jxl.write.WritableCell;
31 import jxl.format.CellFormat;
32 import jxl.biff.Type;
33 import jxl.biff.IntegerHelper;
34 import jxl.biff.FormattingRecords;
35 import jxl.biff.WorkbookMethods;
36 import jxl.biff.formula.FormulaException;
37 import jxl.biff.formula.ExternalSheet;
38 import jxl.biff.FormulaData;
39 import jxl.biff.FormattingRecords;
40 import jxl.biff.formula.FormulaParser;
41 import jxl.biff.formula.FormulaException;
42
43 /**
44  * A formula record. Parses the string passed in to deduce the set of
45  * formula records
46  */

47 public class FormulaRecord extends CellValue implements FormulaData
48 {
49   /**
50    * The logger
51    */

52   private static Logger logger = Logger.getLogger(FormulaRecord.class);
53
54   /**
55    * The formula to parse
56    */

57   private String JavaDoc formulaToParse;
58
59   /**
60    * The formula parser
61    */

62   private FormulaParser parser;
63
64   /**
65    * The parsed formula string
66    */

67   private String JavaDoc formulaString;
68
69   /**
70    * The parsed formula bytes
71    */

72   private byte[] formulaBytes;
73
74   /**
75    * The location where this formula was copied from. It is used subsequently
76    * to adjust relative cell references
77    */

78   private CellValue copiedFrom;
79
80   /**
81    * Constructor
82    *
83    * @param f the formula to copy
84    */

85   public FormulaRecord(int c, int r, String JavaDoc f)
86   {
87     super(Type.FORMULA2, c, r);
88     formulaToParse = f;
89     copiedFrom = null;
90   }
91
92   /**
93    * Constructor
94    *
95    * @param f the formula to copy
96    */

97   public FormulaRecord(int c, int r, String JavaDoc f, CellFormat st)
98   {
99     super(Type.FORMULA, c, r, st);
100     formulaToParse = f;
101     copiedFrom = null;
102   }
103
104   /**
105    * Copy constructor for writable formulas
106    *
107    * @param c the column
108    * @param r the row
109    * @param fr the record to copy
110    */

111   protected FormulaRecord(int c, int r, FormulaRecord fr)
112   {
113     super(Type.FORMULA, c, r, fr);
114     copiedFrom = fr;
115     formulaBytes = new byte[fr.formulaBytes.length];
116     System.arraycopy(fr.formulaBytes, 0, formulaBytes, 0, formulaBytes.length);
117   }
118
119   /**
120    * Copy constructor for formulas read in - invoked fromwritable formulas
121    *
122    * @param c the column
123    * @param r the row
124    * @param rfr the formula data to copy
125    */

126   protected FormulaRecord(int c, int r, ReadFormulaRecord rfr)
127   {
128     super(Type.FORMULA, c, r, rfr);
129     try
130     {
131       copiedFrom = rfr;
132       byte[] readFormulaData = rfr.getFormulaData();
133       formulaBytes = new byte[readFormulaData.length - 16];
134       System.arraycopy(readFormulaData, 16, formulaBytes, 0,
135                        formulaBytes.length);
136     }
137     catch (FormulaException e)
138     {
139       // Fail silently
140
logger.error("", e);
141     }
142   }
143
144   /**
145    * Initializes the string and the formula bytes. In order to get
146    * access to the workbook settings, the object is not initialized until
147    * it is added to the sheet
148    *
149    * @param ws the workbook settings
150    * @param es the external sheet
151    * @param nt the name table
152    */

153   private void initialize(WorkbookSettings ws, ExternalSheet es,
154                           WorkbookMethods nt)
155   {
156     if (copiedFrom != null)
157     {
158       initializeCopiedFormula(ws, es, nt);
159       return;
160     }
161
162     parser = new FormulaParser(formulaToParse, es, nt, ws);
163
164     try
165     {
166       parser.parse();
167       formulaString = parser.getFormula();
168       formulaBytes = parser.getBytes();
169     }
170     catch (FormulaException e)
171     {
172       logger.warn
173         (e.getMessage() +
174          " when parsing formula " + formulaToParse + " in cell " +
175          getSheet().getName() + "!" +
176            CellReferenceHelper.getCellReference(getColumn(), getRow()));
177
178       try
179       {
180         // try again, with an error formula
181
formulaToParse = "ERROR(1)";
182         parser = new FormulaParser(formulaToParse, es, nt, ws);
183         parser.parse();
184         formulaString = parser.getFormula();
185         formulaBytes = parser.getBytes();
186       }
187       catch (FormulaException e2)
188       {
189         // fail silently
190
logger.error("",e2);
191       }
192     }
193   }
194
195   /**
196    * This formula was copied from a formula already present in the writable
197    * workbook. Requires special handling to sort out the cell references
198
199    * @param ws the workbook settings
200    * @param es the external sheet
201    * @param nt the name table
202    */

203   private void initializeCopiedFormula(WorkbookSettings ws,
204                                        ExternalSheet es, WorkbookMethods nt)
205   {
206     try
207     {
208       parser = new FormulaParser(formulaBytes, this, es, nt, ws);
209       parser.parse();
210       parser.adjustRelativeCellReferences
211         (getColumn() - copiedFrom.getColumn(),
212          getRow() - copiedFrom.getRow());
213       formulaString = parser.getFormula();
214       formulaBytes = parser.getBytes();
215     }
216     catch (FormulaException e)
217     {
218       try
219       {
220         // try again, with an error formula
221
formulaToParse = "ERROR(1)";
222         parser = new FormulaParser(formulaToParse, es, nt, ws);
223         parser.parse();
224         formulaString = parser.getFormula();
225         formulaBytes = parser.getBytes();
226         
227       }
228       catch (FormulaException e2)
229       {
230         // fail silently
231
logger.error("", e2);
232       }
233     }
234   }
235
236   /**
237    * Called when the cell is added to the worksheet. Overrides the
238    * method in the base class in order to get a handle to the
239    * WorkbookSettings so that this formula may be initialized
240    *
241    * @param fr the formatting records
242    * @param ss the shared strings used within the workbook
243    * @param s the sheet this is being added to
244    */

245   void setCellDetails(FormattingRecords fr, SharedStrings ss,
246                       WritableSheetImpl s)
247   {
248     super.setCellDetails(fr, ss, s);
249     initialize(s.getWorkbookSettings(), s.getWorkbook(), s.getWorkbook());
250     s.getWorkbook().addRCIRCell(this);
251   }
252
253   /**
254    * Gets the binary data for output to file
255    *
256    * @return the binary data
257    */

258   public byte[] getData()
259   {
260     byte[] celldata = super.getData();
261     byte[] formulaData = getFormulaData();
262     byte[] data = new byte[formulaData.length + celldata.length];
263     System.arraycopy(celldata, 0, data, 0, celldata.length);
264     System.arraycopy(formulaData, 0, data, celldata.length,
265                      formulaData.length);
266     return data;
267   }
268
269   /**
270    * Returns the content type of this cell
271    *
272    * @return the content type for this cell
273    */

274   public CellType getType()
275   {
276     return CellType.ERROR;
277   }
278
279   /**
280    * Quick and dirty function to return the contents of this cell as a string.
281    * For more complex manipulation of the contents, it is necessary to cast
282    * this interface to correct subinterface
283    *
284    * @return the contents of this cell as a string
285    */

286   public String JavaDoc getContents()
287   {
288     return formulaString;
289   }
290
291   /**
292    * Gets the raw bytes for the formula. This will include the
293    * parsed tokens array
294    *
295    * @return the raw record data
296    */

297   public byte[] getFormulaData()
298   {
299     byte[] data = new byte[formulaBytes.length + 16];
300     System.arraycopy(formulaBytes, 0, data, 16, formulaBytes.length);
301     
302     data[6] = (byte) 0x10;
303     data[7] = (byte) 0x40;
304     data[12] = (byte) 0xe0;
305     data[13] = (byte) 0xfc;
306     // Set the recalculate on load bit
307
data[8] |= 0x02;
308
309     // Set the length of the rpn array
310
IntegerHelper.getTwoBytes(formulaBytes.length, data, 14);
311
312     return data;
313   }
314
315   /**
316    * A dummy implementation to keep the compiler quiet. This object needs
317    * to be instantiated from ReadFormulaRecord
318    *
319    * @param col the column which the new cell will occupy
320    * @param row the row which the new cell will occupy
321    * @return NOTHING
322    */

323   public WritableCell copyTo(int col, int row)
324   {
325     Assert.verify(false);
326     return null;
327   }
328
329   /**
330    * Called when a column is inserted on the specified sheet. Notifies all
331    * RCIR cells of this change. The default implementation here does nothing
332    *
333    * @param s the sheet on which the column was inserted
334    * @param sheetIndex the sheet index on which the column was inserted
335    * @param col the column number which was inserted
336    */

337   void columnInserted(Sheet s, int sheetIndex, int col)
338   {
339     parser.columnInserted(sheetIndex, col, s == getSheet());
340     formulaBytes = parser.getBytes();
341   }
342
343   /**
344    * Called when a column is removed on the specified sheet. Notifies all
345    * RCIR cells of this change. The default implementation here does nothing
346    *
347    * @param s the sheet on which the column was inserted
348    * @param sheetIndex the sheet index on which the column was inserted
349    * @param col the column number which was inserted
350    */

351   void columnRemoved(Sheet s, int sheetIndex, int col)
352   {
353     parser.columnRemoved(sheetIndex, col, s == getSheet());
354     formulaBytes = parser.getBytes();
355   }
356
357   /**
358    * Called when a row is inserted on the specified sheet. Notifies all
359    * RCIR cells of this change. The default implementation here does nothing
360    *
361    * @param s the sheet on which the column was inserted
362    * @param sheetIndex the sheet index on which the column was inserted
363    * @param row the column number which was inserted
364    */

365   void rowInserted(Sheet s, int sheetIndex, int row)
366   {
367     parser.rowInserted(sheetIndex, row, s == getSheet());
368     formulaBytes = parser.getBytes();
369   }
370
371   /**
372    * Called when a row is inserted on the specified sheet. Notifies all
373    * RCIR cells of this change. The default implementation here does nothing
374    *
375    * @param s the sheet on which the row was removed
376    * @param sheetIndex the sheet index on which the column was removed
377    * @param row the column number which was removed
378    */

379   void rowRemoved(Sheet s, int sheetIndex, int row)
380   {
381     parser.rowRemoved(sheetIndex, row, s == getSheet());
382     formulaBytes = parser.getBytes();
383   }
384 }
385
Popular Tags