KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jxl > biff > formula > Attribute


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.biff.formula;
21
22 import java.util.Stack JavaDoc;
23
24 import common.Assert;
25 import common.Logger;
26
27 import jxl.WorkbookSettings;
28 import jxl.Sheet;
29 import jxl.biff.IntegerHelper;
30 /**
31  * A special attribute control token - typically either a SUM function
32  * or an IF function
33  */

34
35 class Attribute extends Operator implements ParsedThing
36 {
37   /**
38    * The logger
39    */

40   private static Logger logger = Logger.getLogger(Attribute.class);
41
42   /**
43    * The options used by the attribute
44    */

45   private int options;
46
47   /**
48    * The word contained in this attribute
49    */

50   private int word;
51
52   /**
53    * The workbook settings
54    */

55   private WorkbookSettings settings;
56
57   private final static int sumMask = 0x10;
58   private final static int ifMask = 0x02;
59   private final static int gotoMask = 0x08;
60
61   /**
62    * If this attribute is an IF functions, sets the associated if conditions
63    */

64   private VariableArgFunction ifConditions;
65
66   /**
67    * Constructor
68    */

69   public Attribute(WorkbookSettings ws)
70   {
71     settings = ws;
72   }
73
74   /**
75    * Constructor for use when this is called when parsing a string
76    *
77    * @param sf the built in function
78    * @param ws the workbook settings
79    */

80   public Attribute(StringFunction sf, WorkbookSettings ws)
81   {
82     settings = ws;
83
84     if (sf.getFunction(settings) == Function.SUM)
85     {
86       options |= sumMask;
87     }
88     else if (sf.getFunction(settings) == Function.IF)
89     {
90       options |= ifMask;
91     }
92   }
93
94   /**
95    * Sets the if conditions for this attribute, if it represents an IF function
96    *
97    * @param vaf a <code>VariableArgFunction</code> value
98    */

99   void setIfConditions(VariableArgFunction vaf)
100   {
101     ifConditions = vaf;
102
103     // Sometimes there is not Attribute token, so we need to create
104
// an attribute out of thin air. In that case, make sure the if mask
105
options |= ifMask;
106   }
107
108   /**
109    * Reads the ptg data from the array starting at the specified position
110    *
111    * @param data the RPN array
112    * @param pos the current position in the array, excluding the ptg identifier
113    * @return the number of bytes read
114    */

115   public int read(byte[] data, int pos)
116   {
117     options = data[pos];
118     word = IntegerHelper.getInt(data[pos+1], data[pos+2]);
119     return 3;
120   }
121
122   /**
123    * Queries whether this attribute is a function
124    *
125    * @return TRUE if this is a function, FALSE otherwise
126    */

127   public boolean isFunction()
128   {
129     return (options & (sumMask | ifMask) ) != 0;
130   }
131
132   /**
133    * Queries whether this attribute is a sum
134    *
135    * @return TRUE if this is SUM, FALSE otherwise
136    */

137   public boolean isSum()
138   {
139     return (options & sumMask) != 0;
140   }
141
142   /**
143    * Queries whether this attribute is an IF
144    *
145    * @return TRUE if this is an IF, FALSE otherwise
146    */

147   public boolean isIf()
148   {
149     return (options & ifMask) != 0;
150   }
151
152   /**
153    * Queries whether this attribute is a goto
154    *
155    * @return TRUE if this is a goto, FALSE otherwise
156    */

157   public boolean isGoto()
158   {
159     return (options & gotoMask) != 0;
160   }
161
162   /**
163    * Gets the operands for this operator from the stack
164    */

165   public void getOperands(Stack JavaDoc s)
166   {
167     if ((options & sumMask) != 0)
168     {
169       ParseItem o1 = (ParseItem) s.pop();
170       
171       add(o1);
172     }
173     else if ((options & ifMask) != 0)
174     {
175       ParseItem o1 = (ParseItem) s.pop();
176       add(o1);
177     }
178   }
179
180   public void getString(StringBuffer JavaDoc buf)
181   {
182     if ((options & sumMask) != 0)
183     {
184       ParseItem[] operands = getOperands();
185       buf.append(Function.SUM.getName(settings));
186       buf.append('(');
187       operands[0].getString(buf);
188       buf.append(')');
189     }
190     else if ((options & ifMask) != 0)
191     {
192       buf.append(Function.IF.getName(settings));
193       buf.append('(');
194
195       ParseItem[] operands = ifConditions.getOperands();
196
197       // Operands are in the correct order for IFs
198
for (int i = 0 ; i < operands.length-1 ; i++)
199       {
200         operands[i].getString(buf);
201         buf.append(',');
202       }
203       operands[operands.length-1].getString(buf);
204       buf.append(')');
205     }
206   }
207
208   /**
209    * Gets the token representation of this item in RPN. The Attribute
210    * token is a special case, which overrides anything useful we could do
211    * in the base class
212    *
213    * @return the bytes applicable to this formula
214    */

215   byte[] getBytes()
216   {
217     byte[] data = new byte[0];
218     if (isSum())
219     {
220       // Get the data for the operands
221
ParseItem[] operands = getOperands();
222
223       // Get the operands in reverse order to get the RPN
224
for (int i = operands.length - 1 ; i >= 0 ; i--)
225       {
226         byte[] opdata = operands[i].getBytes();
227         
228         // Grow the array
229
byte[] newdata = new byte[data.length + opdata.length];
230         System.arraycopy(data, 0, newdata, 0, data.length);
231         System.arraycopy(opdata, 0, newdata, data.length, opdata.length);
232         data = newdata;
233       }
234       
235       // Add on the operator byte
236
byte[] newdata = new byte[data.length + 4];
237       System.arraycopy(data, 0, newdata, 0, data.length);
238       newdata[data.length] = Token.ATTRIBUTE.getCode();
239       newdata[data.length+1] = sumMask;
240       data = newdata;
241     }
242     else if (isIf())
243     {
244       return getIf();
245     }
246
247     return data;
248   }
249
250   /**
251    * Gets the associated if conditions with this attribute
252    *
253    * @return the associated if conditions
254    */

255   private byte[] getIf()
256   {
257     ParseItem[] operands = ifConditions.getOperands();
258
259     // The position of the offset to the false portion of the expression
260
int falseOffsetPos = 0;
261     int gotoEndPos = 0;
262     int numArgs = operands.length;
263
264     // First, write out the conditions
265
byte[] data = operands[0].getBytes();
266     
267     // Grow the array by three and write out the optimized if attribute
268
int pos = data.length;
269     byte[] newdata = new byte[data.length+4];
270     System.arraycopy(data, 0, newdata, 0, data.length);
271     data = newdata;
272     data[pos] = Token.ATTRIBUTE.getCode();
273     data[pos+1] = 0x2;
274     falseOffsetPos = pos+2;
275
276     // Get the true portion of the expression and add it to the array
277
byte[] truedata = operands[1].getBytes();
278     newdata = new byte[data.length + truedata.length];
279     System.arraycopy(data, 0, newdata, 0, data.length);
280     System.arraycopy(truedata, 0, newdata, data.length, truedata.length);
281     data = newdata;
282
283     // Grow the array by three and write out the goto end attribute
284
pos = data.length;
285     newdata = new byte[data.length+4];
286     System.arraycopy(data, 0, newdata, 0, data.length);
287     data = newdata;
288     data[pos] = Token.ATTRIBUTE.getCode();
289     data[pos+1] = 0x8;
290     gotoEndPos = pos+2;
291
292     // If the false condition exists, then add that to the array
293
if (numArgs > 2)
294     {
295       // Set the offset to the false expression to be the current position
296
IntegerHelper.getTwoBytes(data.length - falseOffsetPos - 2,
297                                 data, falseOffsetPos);
298
299       // Copy in the false expression
300
byte[] falsedata = operands[numArgs-1].getBytes();
301       newdata = new byte[data.length + falsedata.length];
302       System.arraycopy(data, 0, newdata, 0, data.length);
303       System.arraycopy(falsedata, 0, newdata, data.length, falsedata.length);
304       data = newdata;
305
306       // Write the goto to skip over the varargs token
307
pos = data.length;
308       newdata = new byte[data.length+4];
309       System.arraycopy(data, 0, newdata, 0, data.length);
310       data = newdata;
311       data[pos] = Token.ATTRIBUTE.getCode();
312       data[pos+1] = 0x8;
313       data[pos+2] = 0x3;
314     }
315
316     // Grow the array and write out the varargs function
317
pos = data.length;
318     newdata = new byte[data.length+4];
319     System.arraycopy(data, 0, newdata, 0, data.length);
320     data = newdata;
321     data[pos] = Token.FUNCTIONVARARG.getCode();
322     data[pos+1] = (byte) numArgs;
323     data[pos+2] = 1;
324     data[pos+3] = 0; // indicates the end of the expression
325

326     // Position the final offsets
327
int endPos = data.length - 1;
328
329     if (numArgs < 3)
330     {
331       // Set the offset to the false expression to be the current position
332
IntegerHelper.getTwoBytes(endPos - falseOffsetPos - 5,
333                                 data, falseOffsetPos);
334     }
335
336     // Set the offset after the true expression
337
IntegerHelper.getTwoBytes(endPos - gotoEndPos - 2,
338                               data, gotoEndPos);
339
340     return data;
341   }
342
343   /**
344    * Gets the precedence for this operator. Operator precedents run from
345    * 1 to 5, one being the highest, 5 being the lowest
346    *
347    * @return the operator precedence
348    */

349   int getPrecedence()
350   {
351     return 3;
352   }
353
354   /**
355    * Default behaviour is to do nothing
356    *
357    * @param colAdjust the amount to add on to each relative cell reference
358    * @param rowAdjust the amount to add on to each relative row reference
359    */

360   public void adjustRelativeCellReferences(int colAdjust, int rowAdjust)
361   {
362     ParseItem[] operands = null;
363
364     if (isIf())
365     {
366       operands = ifConditions.getOperands();
367     }
368     else
369     {
370       operands = getOperands();
371     }
372
373     for (int i = 0 ; i < operands.length ; i++)
374     {
375       operands[i].adjustRelativeCellReferences(colAdjust, rowAdjust);
376     }
377   }
378
379   /**
380    * Called when a column is inserted on the specified sheet. Tells
381    * the formula parser to update all of its cell references beyond this
382    * column
383    *
384    * @param sheetIndex the sheet on which the column was inserted
385    * @param col the column number which was inserted
386    * @param currentSheet TRUE if this formula is on the sheet in which the
387    * column was inserted, FALSE otherwise
388    */

389   void columnInserted(int sheetIndex, int col, boolean currentSheet)
390   {
391     ParseItem[] operands = null;
392
393     if (isIf())
394     {
395       operands = ifConditions.getOperands();
396     }
397     else
398     {
399       operands = getOperands();
400     }
401
402     for (int i = 0 ; i < operands.length ; i++)
403     {
404       operands[i].columnInserted(sheetIndex, col, currentSheet);
405     }
406   }
407
408   /**
409    * Called when a column is inserted on the specified sheet. Tells
410    * the formula parser to update all of its cell references beyond this
411    * column
412    *
413    * @param sheetIndex the sheet on which the column was removed
414    * @param col the column number which was removed
415    * @param currentSheet TRUE if this formula is on the sheet in which the
416    * column was inserted, FALSE otherwise
417    */

418   void columnRemoved(int sheetIndex, int col, boolean currentSheet)
419   {
420     ParseItem[] operands = null;
421
422     if (isIf())
423     {
424       operands = ifConditions.getOperands();
425     }
426     else
427     {
428       operands = getOperands();
429     }
430
431     for (int i = 0 ; i < operands.length ; i++)
432     {
433       operands[i].columnRemoved(sheetIndex, col, currentSheet);
434     }
435   }
436
437   /**
438    * Called when a column is inserted on the specified sheet. Tells
439    * the formula parser to update all of its cell references beyond this
440    * column
441    *
442    * @param sheetIndex the sheet on which the row was inserted
443    * @param row the row number which was inserted1
444    * @param currentSheet TRUE if this formula is on the sheet in which the
445    * column was inserted, FALSE otherwise
446    */

447   void rowInserted(int sheetIndex, int row, boolean currentSheet)
448   {
449     ParseItem[] operands = null;
450
451     if (isIf())
452     {
453       operands = ifConditions.getOperands();
454     }
455     else
456     {
457       operands = getOperands();
458     }
459
460     for (int i = 0 ; i < operands.length ; i++)
461     {
462       operands[i].rowInserted(sheetIndex, row, currentSheet);
463     }
464   }
465
466   /**
467    * Called when a column is inserted on the specified sheet. Tells
468    * the formula parser to update all of its cell references beyond this
469    * column
470    *
471    * @param sheetIndex the sheet on which the row was removed
472    * @param row the row number which was removed
473    * @param currentSheet TRUE if this formula is on the sheet in which the
474    * column was inserted, FALSE otherwise
475    */

476   void rowRemoved(int sheetIndex, int row, boolean currentSheet)
477   {
478     ParseItem[] operands = null;
479
480     if (isIf())
481     {
482       operands = ifConditions.getOperands();
483     }
484     else
485     {
486       operands = getOperands();
487     }
488
489     for (int i = 0 ; i < operands.length ; i++)
490     {
491       operands[i].rowRemoved(sheetIndex, row, currentSheet);
492     }
493   }
494 }
495
496
497
498
499
Popular Tags