1 /*
2 * GeoVISTA Center (Penn State, Dept. of Geography)
3 * Copyright (c), 1999 - 2002, GeoVISTA Center
4 * All Rights Researved.
5 *
6 * Description:
7 * This is a wrapper class for all objects in the table.
8 * A cell has a value which is either text or a number.
9 *
10 * Date: Apr 2, 2003
11 * Time: 10:42:12 PM
12 * @author Jin Chen
13 */
14
15 package edu.psu.geovista.app.spreadsheet.formula;
16
17
18 import edu.psu.geovista.app.spreadsheet.util.Debug;
19
20 import javax.swing.table.TableModel;
21 import javax.swing.table.DefaultTableModel;
22 import javax.swing.table.TableColumnModel;
23 import javax.swing.table.TableColumn;
24 import javax.swing.*;
25 import java.util.*;
26 import java.awt.*;
27
28 import edu.psu.geovista.app.spreadsheet.exception.ParserException;
29 import edu.psu.geovista.app.spreadsheet.exception.NoReferenceException;
30 import edu.psu.geovista.app.spreadsheet.table.SSTableModel;
31 import edu.psu.geovista.app.spreadsheet.SpreadSheetBean;
32 import edu.psu.geovista.app.spreadsheet.table.SSTable;
33
34
35
36 public class Cell {
37
38 /*** Value Type ***/
39 public static final int NULL = 0;
40
41 /*** The integer code that denotes the cell holds text. */
42 public static final int TEXT = 1;
43
44 /*** The integer code that denotes the cell holds numbers. */
45 public static final int NUMBER = 2;
46
47 /*** The integer code that denotes the cell holds a edu.psu.geovista.app.spreadsheet.formula. */
48 // public static final int FORMULA = 2;
49
50 public static final int UNKNOWN = 3;
51
52 private int valueType=0;
53
54 /*** Value of the cell. In a edu.psu.geovista.app.spreadsheet.formula, value holds the evaluated value. */
55 private Object value;
56
57 /***
58 * This expression contains the string and internal representation
59 * of the edu.psu.geovista.app.spreadsheet.formula if it exists.
60 */
61 private Formula expression;
62
63 /***
64 * The list of cells that reference this cell. When a cell is changes,
65 * all cells on this list should notified.
66 */
67 private TreeSet refs;
68
69 //Jin
70 private boolean isformula=false;//
71 private boolean deleted=false;//if the cell has been deleted
72 private SSTableModel dataModel;
73 private Vector container;// the row vector that contain the cell object
74
75
76 /***
77 * This constructor constructs a cell that will not have cells
78 * referencing it and are not formulas. Basically only used for creating
79 * the row and column labels.
80 * <P>
81 * <b>Warning:</b> Do not use this with Formulas
82 * @param datum the value of the "label" cell (not a edu.psu.geovista.app.spreadsheet.formula.Formula)
83 */
84 public Cell(Vector _container,SSTableModel tm) {
85 this.container =_container;
86 this.dataModel=tm;
87 expression = null;
88 refs = null;
89 }
90 /***
91 * protect against loop reference
92 */
93 public boolean addOwner(Cell cell) {
94 Debug.println("this address:"+this.getViewAddress() );
95 Debug.println("cell address:"+cell.getViewAddress() );
96 return this.getFormula().addOwner(cell);
97 }
98
99 public void evaluate(){
100 if (this.isFormula() ){
101
102 Object value=null;
103 try {
104 Formula form=this.getFormula() ;
105 if (form.isBad() ){ //invalid edu.psu.geovista.app.spreadsheet.formula
106 this.setValue("#NAME?");
107 }
108 else{
109 //SSTableModel.getInstance().get
110
111 //Debug.println(" A1:"+SpreadSheetBean4.getTableInstance().getValueAtIndex(1,1));
112 value = form.evaluate();
113 /*Debug.println("edu.psu.geovista.app.spreadsheet.formula.Cell.evaluate():"+value);
114 Debug.println("Cell.getViewAddress()"+this.getViewAddress() );
115 Thread.dumpStack() ; */
116 this.setValue(value);
117 }
118 } catch (ParserException e) {
119
120 this.setValue(e.toString() );
121 //SpreadSheetBean.getTableInstance().revaluate() ;//remove the loop dialog box
122 this.getDataModel().getTable().revaluate() ;
123 //e.printStackTrace() ;
124 } catch(NoReferenceException e){
125 //e.printStackTrace() ;//only for debug
126 this.setValue("#REF!");
127 }
128
129 } //if
130 }
131
132 /***
133 * This method returns the edu.psu.geovista.app.spreadsheet.formula associated with the cell or null if it
134 * does not exist.
135 *
136 * @return the edu.psu.geovista.app.spreadsheet.formula (string and internal object) or null if does not
137 * exist
138 */
139 public Formula getFormula() {
140 if (this.deleted ) return null;
141 else return expression;
142 }
143 public void setFormula(Formula form) {
144 expression = form;
145 //this.setAsFormula(true);
146
147 }
148
149
150
151
152
153
154
155 /***
156 * If it is a data cell, it returns the data of the cell. If it is a
157 * edu.psu.geovista.app.spreadsheet.formula, it returns the previously evaluated value of the edu.psu.geovista.app.spreadsheet.formula.
158 *
159 * @return the value (data or evaluated) of the cell
160 */
161 public Object getValue() {
162 //Debug.println("Cell.getValue:"+value+" at"+this.getViewAddress() );
163 /*if (this.isFormula() ){
164 this.evaluate() ;
165 } */
166
167 if (this.isDeleted() ) {
168 return "#REF!";
169 }
170 else return value;
171 }
172
173
174 /***
175 * Sets the value field of the cell.
176 *
177 * @param datum the object to set the value of cell to
178 */
179 public void setValue(Object datum) {
180 /*Point p=this.getViewAddress() ;
181 if (p.getX() ==1&&p.getY() ==0){
182 Debug.println("view(1,0)="+this.getValue() );
183 } */
184
185 if (datum==null){
186 this.setValueType(Cell.NULL );
187 }
188 else if(datum!=null){
189 if (datum instanceof String ){
190 String s=(String)datum;
191 this.setValueType(Cell.TEXT);
192 if (s.trim().equals("")){
193 datum=null;
194 this.setValueType(Cell.NULL );
195 }
196 }
197 else if (datum instanceof Number){
198 this.setValueType(Cell.NUMBER );
199 }
200 else{
201 this.setValueType(Cell.UNKNOWN );
202 }
203 }
204
205 value = datum;
206 //this.setAsFormula(false);
207
208 }
209
210
211
212 /***
213 * This method sets the cell to be a edu.psu.geovista.app.spreadsheet.formula cell. It puts the edu.psu.geovista.app.spreadsheet.formula
214 * object into the expression field. The Table of Cells is responsible
215 * for recalculating and setting the appropriate value in the value
216 * field of this cell.
217 *
218 * @param form the internal representation of edu.psu.geovista.app.spreadsheet.formula to set this cell to
219 */
220 public void setAsFormula(boolean isf) {
221
222 this.isformula =isf;
223 }
224
225
226
227 /***
228 * This method is useful for determining what information a cell holds. To
229 * check if a cell holds a certain type just see if
230 * getType() == edu.psu.geovista.app.spreadsheet.formula.Cell.CODE where CODE is any of the cell constants.
231 *
232 * @return the integer code of the type of data this cell holds
233 */
234 public int getValueType() {
235 if (value==null) valueType= Cell.NULL ;
236 ///if (expression != null) return edu.psu.geovista.app.spreadsheet.formula.Cell.FORMULA; //jin: no use
237 else if (value instanceof Number) valueType= Cell.NUMBER;
238 else if(value instanceof String)valueType= Cell.TEXT;
239 else valueType= Cell.UNKNOWN ;
240
241 return valueType;
242 }
243
244 public void setValueType(int t){
245 this.valueType =t;
246 }
247
248 /***
249 * This method returns true IFF it is a edu.psu.geovista.app.spreadsheet.formula cell
250 *
251 * @return true iff a edu.psu.geovista.app.spreadsheet.formula cell
252 */
253 public boolean isFormula() {
254 return this.isformula ;
255 }
256
257 /***
258 * If the column or row contain the cell is deleted, the cell is set "deleted"
259 *
260 */
261 public boolean isDeleted(){
262 return this.deleted ;
263 }
264
265 public void setDeleted(boolean d){
266 this.deleted =d;
267 }
268
269 public SSTableModel getDataModel() {
270 return dataModel;
271 }
272
273 /***
274 * This method determines a cell is a edu.psu.geovista.app.spreadsheet.formula cell that has a error.
275 *
276 * @return true if cell is an error cell
277
278 public boolean isErrorCell() {
279 return ((isFormula()) && (value instanceof ParserException));
280 } */
281
282
283
284 public Vector getContainer() {
285 return container;
286 }
287 /***
288 * toString() method return same data as getValue(), but in different format
289 * toString() return String format for table.getValue() to paintCell()
290 * getValue() return Number for evaluate edu.psu.geovista.app.spreadsheet.formula
291 * called when paint cell
292 */
293 public String toString() {
294 /*if (this.isFormula() )
295 return "="+expression.toString();
296 else*/
297 /* Because all values stored in TableModel is in form of edu.psu.geovista.app.spreadsheet.formula.Cell object,
298 * TableModel.getValueAt() will call object.toString() to get actual value
299 *, so toString() only return the evaluted value, not edu.psu.geovista.app.spreadsheet.formula expression*/
300 if (this.isDeleted() ){
301 return "#REF!";
302 }
303 if (this.isFormula()&&!this.getFormula().isBad() ){
304 this.evaluate() ;
305 }
306 if(value !=null)
307 return value.toString();
308 else
309 return null; //means empty value""
310 }
311 /***
312 * not finish yet, just for treeset
313 * String: if can't convert to number, alway on the top ."" is set to null in cell
314 * null<"": alway at the bottom
315 * number: always in middle
316 * @return a negative integer, zero, or a positive integer as
317 * this object is less than, equal to, or greater than
318 * the specified object.
319 */
320 public int compareTo( Cell x, boolean ascend){
321 final int over=2000000; //doesnot matter if ascend or descend, this cell always over the given cell
322 final int under=-2000000; //doesnot matter if ascend or descend, this cell always under the given cell
323 //Note:??? Use big number cause compareToIgnoreCase() will return some small number(like 2,11,20...), which may cause bug
324
325 int r;//return
326 //if this is blank which is lowest value
327 assert (x!=null);
328 int xt=x.getValueType();//x's value type
329 int tt=this.getValueType() ;//this value type
330
331 Object tvalue=this.value;
332 Object xvalue=x.getValue() ;
333 if (tt==Cell.NULL ){
334 //r= under;
335 return 1;
336 }
337 if (xt==Cell.NULL ){
338 //r= over;
339 return -1;
340 }
341
342 if (tt==Cell.TEXT ){
343 String tvs=(String)tvalue;
344 if (xt==Cell.TEXT ){
345 String xvs=(String)xvalue;
346 r= tvs.compareToIgnoreCase(xvs);
347 if (tvs!=null&&xvs!=null)
348 Debug.println( tvs +" compareToIgnoreCase "+xvs+ " = "+r);
349 }
350 else if(xt==Cell.NUMBER ){
351
352 try {
353 Number xvn=(Number)xvalue;
354 double xvd=xvn.doubleValue() ;
355 double tvd=Double.parseDouble(tvs); //??throw NumberFormatException
356 if(tvd>xvd) r= 1;
357 else if (tvd<xvd)r= -1;
358 else r= 0;
359 } catch (NumberFormatException e) {//String can't convert to number
360 r= over;
361 }
362 }
363 else if (xt==Cell.UNKNOWN ){
364 Comparable tvc=(Comparable)tvs;
365 Comparable xvc=(Comparable)xvalue;
366 r= tvc.compareTo(xvc); //??? throw ClassCastException
367
368 }
369 else{ //xt=edu.psu.geovista.app.spreadsheet.formula.Cell.Null, should never reach, just for compile purpose
370 assert false;
371 r= over;
372 }
373
374 }
375 else if(tt==Cell.NUMBER){
376 Number tvn=(Number)tvalue;
377 if (xt==Cell.TEXT ){
378 try {
379 String xvs=(String)xvalue;
380 double xvd=Double.parseDouble(xvs); //??throw NumberFormatException
381 double tvd=tvn.doubleValue() ;
382 if(tvd>xvd) r= 1;
383 else if (tvd<xvd)r= -1;
384 else r= 0;
385 } catch (NumberFormatException e) {
386 r=under;
387 }
388 }
389 else if(xt==Cell.NUMBER ){
390
391 Number xvn=(Number)xvalue;
392 double tvd=tvn.doubleValue() ;
393 double xvd=xvn.doubleValue() ;
394 if(tvd>xvd) r= 1;
395 else if (tvd<xvd)r= -1;
396 else r= 0;
397 }
398 else if (xt==Cell.UNKNOWN ){
399 r= 0 ;
400
401 //throw new ClassCastException();
402 }
403 else{ //xt =edu.psu.geovista.app.spreadsheet.formula.Cell.Null, should never reach, just for compile purpose
404 assert false;
405 r= over;
406 }
407
408 }
409 else { //unknow type
410 Debug.println("this cell value type:"+tt);
411 Comparable tvc=(Comparable)tvalue;
412 Comparable xvc=(Comparable)xvalue;
413 r= tvc.compareTo(xvc); //??? throw ClassCastException
414
415 }
416
417 if (r==over){
418 return -1;
419 }
420 else if (r==under){
421 return 1;
422 }
423 else{
424 if (ascend){
425 return r;
426 }
427 else{
428 return -r;
429 }
430 }
431
432
433 }
434
435 /*********************************************************************
436 * Address *
437 ********************************************************************/
438
439 /***
440 * return the address of the cell in Table in form of (x,y)
441 * Need translate. e.g. Row1 in Table is Row0 in TableModel
442 */
443 public Point getViewAddress(){
444 //Point address=this.getModelAddress() ;
445 //SSTableModel tm=SSTableModel.getInstance() ;
446 Point address=this.getDataModel().getCellAddress(this) ; //address in TableModel
447 if (address==null) return null;
448 int x=(int)address.getX() ; //edu.psu.geovista.app.spreadsheet.model index (sort edu.psu.geovista.app.spreadsheet.model if sort)
449 int y=(int)address.getY(); //edu.psu.geovista.app.spreadsheet.model index (sort edu.psu.geovista.app.spreadsheet.model if sort)
450
451
452
453
454 //For now Model row is same as table row. May not the case if implement Sort on row
455 int row=SSTable.transRowTableToView(x);
456 //int col=Cell.transColModelToView(y);
457 int col=this.getDataModel().getTable().transColModelToView(y);
458 //String col=edu.psu.geovista.app.spreadsheet.formula.Node.translateColumn(y );
459 return new Point(row,col);
460
461
462 }
463 public String getViewAddressText(){
464 String addrs=null;
465 Point address=getViewAddress() ; //address in Table
466 if (address!=null){
467 int x=(int)address.getX() ;
468 int y=(int)address.getY();
469 //String row=edu.psu.geovista.app.spreadsheet.formula.Node.translateRow(x );
470 String row=Integer.toString(x);
471 String col=SSTable.translateVVColumn(y);//translate to String. e.g. 1=>A
472 addrs=col+row;
473
474 }
475 return addrs;
476 }
477 /***
478 * return the address of the cell in TableModel in form of (x,y)
479 *
480 */
481 private Point getModelAddress(){
482 //SSTableModel tmd=SSTableModel.getInstance() ;
483 int row=this.getDataModel().getDataVector().indexOf(this.container );
484 int col=this.container.indexOf(this);
485 if (row>=0&&col>=0){
486 return new Point(row,col);
487 }
488 else{//happen when you delete a column which is referenced by other columns
489 return null;
490 }
491 }
492
493
494
495 /***
496 * Given a cell's address in View(table) return relative address in String format
497 */
498 public static String getRelCellAddress(Point p){
499 StringBuffer address = new StringBuffer();
500 String addr = null;
501 int x = (int) p.getX();
502 int y = (int) p.getY();
503 addr = SSTable.translateVVColumn(y);
504 address.append(addr);
505 addr = String.valueOf(x);
506 address.append(addr);//e.g.: A1
507 String a=address.toString();
508 Debug.println("Cell address :" + a);
509 return a;
510
511 }
512 /***
513 * Given a cell's address in View(table) return absolute address in String format
514 */
515 public static String getAbsCellAddress(Point p){
516 StringBuffer address = new StringBuffer();
517 String addr = null;
518 int x = (int) p.getX();
519 int y = (int) p.getY();
520 addr = SSTable.translateVVColumn(y);
521 address.append("$");
522 address.append(addr);
523 addr = String.valueOf(x);
524 address.append("$");
525 address.append(addr);//e.g.: A1
526 String a=address.toString();
527 Debug.println("Cell address :" + a);
528 return a;
529
530 }
531
532 }
533
This page was automatically generated by Maven