File: JeksExpression.java

package info (click to toggle)
sweethome3d 6.1.2+dfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 31,752 kB
  • sloc: java: 112,703; xml: 6,800; makefile: 43; sh: 38; php: 26
file content (180 lines) | stat: -rw-r--r-- 6,536 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
 * @(#)JeksExpression.java   05/02/99
 *
 * Copyright (c) 1998-2001 Emmanuel PUYBARET / eTeks <info@eteks.com>. All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Visit eTeks web site for up-to-date versions of this file and other
 * Java tools and tutorials : http://www.eteks.com/
 */
package com.eteks.jeks;

import com.eteks.parser.CompiledExpression;
import com.eteks.parser.Interpreter;

import javax.swing.table.TableModel;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;

/**
 * Cell values for computed expressions in a table.
 *
 * @version 1.0
 * @author  Emmanuel Puybaret
 * @since   Jeks 1.0
 */
public class JeksExpression extends CompiledExpression
{
  private transient Object value;

  public JeksExpression (CompiledExpression expression)
  {
    super (expression.getDefinition (), expression.getParameters (),
           expression.getExpressionParameter (), expression.getExpressionTree ());
  }

  /**
   * Returns the value of this expression computed with the <code>computeExpression ()</code>
   * method. This value is computed only at the first call of this method and each time
   * after a call to <code>invalidateValue ()</code>.
   * @exception CircularityException if this expression can't be computed because
   *            it belongs to a reference circularity.
   * @exception IllegalCellException if this expression uses an invalid expression reference (#REF!).
   * @exception IllegalArgumentException if some parameters used by this expression were forbidden.
   * @exception ArithmeticException if a integer division by 0 occured.
   * @exception StackOverflowError if the computation of this expression produced a stack overflow.
   */
  public Object getValue (Interpreter  interpreter)
  {
    if (value instanceof RuntimeException)
      throw (RuntimeException)value;
    else if (value instanceof Error)
      throw (Error)value;
    else
      try
      {
        if (value == null)
          synchronized (this)
          {
            value = computeExpression (interpreter);
          }
        // Return computed value only if it's correct
        return value;
      }
      catch (RuntimeException ex)
      {
        // Keep track of the exception and throw it again
        value = ex;
        throw ex;
      }
      catch (StackOverflowError ex)
      {
        // Keep track of the exception and throw it again
        value = ex;
        throw ex;
      }
  }

  /**
   * Invalidates the value stored by this expression to force the computation of the
   * expression next time <code>getValue ()</code> will be called.
   */
  public void invalidateValue ()
  {
    value = null;
  }

  /**
   * Invalidates the value stored by this expression with with the circularity
   * exception <code>ex</code>. This exception will be thrown when the <code>getValue ()</code>
   * method will be called next time.
   * @param ex a cicrularity exception. Generally it's the exception thrown by the
   *           <code>checkCircularity ()</code> method.
   */
  public void invalidateValue (CircularityException ex)
  {
    value = ex;
  }

  private boolean isCircular ()
  {
    return value instanceof CircularityException;
  }

  /**
   * Parses recursely all the parameters of this expression to
   * check if computing the formula of the referenced cells won't produce
   * a circularity.
   * @param     startCell  the coordinates of the cell storing this expression.
   * @exception CircularityException  if a circurlarity was detected.
   */
  public void checkCircularity (TableModel model, JeksCell startCell) throws CircularityException
  {
    if (getParameterCount () > 0)
      checkCircularity (model, startCell, new Vector ());
  }

  private void checkCircularity (TableModel model, JeksCell startCell, Vector checkedCells) throws CircularityException
  {
    for (Enumeration enumb = getParameters ().elements (); enumb.hasMoreElements (); )
    {
      Object cellOrSet = enumb.nextElement ();
      if (!cellOrSet.equals (IllegalCellException.class))
        if (cellOrSet instanceof JeksCell)
          checkCircularity (model, startCell, (JeksCell)cellOrSet, checkedCells);
        else // JeksCellSet
          checkCircularity (model, startCell, (JeksCellSet)cellOrSet, checkedCells);
    }
  }

  private void checkCircularity (TableModel model, JeksCell startCell, JeksCellSet cellParameterSet, Vector checkedCells) throws CircularityException
  {
    for (int row = cellParameterSet.getFirstRow (); row <= cellParameterSet.getLastRow (); row++)
      for (int column = cellParameterSet.getFirstColumn (); column <= cellParameterSet.getLastColumn (); column++)
        checkCircularity (model, startCell, new JeksCell (row, column), checkedCells);
  }

  private void checkCircularity (TableModel model, JeksCell startCell, JeksCell cellParameter, Vector checkedCells) throws CircularityException
  {
    if (!checkedCells.contains (cellParameter))
      try
      {
        if (startCell.equals (cellParameter))
          throw new CircularityException ();

        checkedCells.addElement (cellParameter);

        Object value = model.getValueAt (cellParameter.getRow (), cellParameter.getColumn ());
        if (value instanceof JeksExpression)
        {
          JeksExpression expression = (JeksExpression)value;
          if (expression.isCircular ())
            throw (CircularityException)expression.value;
          else
            expression.checkCircularity (model, startCell, checkedCells);
        }
      }
      catch (CircularityException ex)
      {
        // Record the cell in the exception and throw it again
        ex.addCell (cellParameter);
        throw ex;
      }
      catch (IndexOutOfBoundsException ex)
      { } // If cellParameter is out of bounds, it will be detected during computing
  }
}