001    /*
002     * Copyright (c) 2005 Peter Palotas, Fredrik Johansson, Einar Pehrson,
003     * Sebastian Kekkonen, Lars Magnus Lång, Malin Johansson and Sofia Nilsson
004     *
005     * This file is part of
006     * CleanSheets Extension for Assertions
007     *
008     * CleanSheets Extension for Assertions is free software; you can
009     * redistribute it and/or modify it under the terms of the GNU General Public
010     * License as published by the Free Software Foundation; either version 2 of
011     * the License, or (at your option) any later version.
012     *
013     * CleanSheets Extension for Assertions is distributed in the hope that
014     * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
015     * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016     * See the GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with CleanSheets Extension for Assertions; if not, write to the
020     * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
021     * Boston, MA  02111-1307  USA
022     */
023    package csheets.ext.assertion;
024    
025    import java.io.IOException;
026    import java.util.ArrayList;
027    import java.util.List;
028    
029    import csheets.core.Cell;
030    import csheets.core.Value;
031    import csheets.ext.CellExtension;
032    
033    /**
034     * An extension of a cell in a spreadsheet, with support for assertions.
035     * @author Peter Palotas
036     * @author Fredrik Johansson
037     * @author Einar Pehrson
038     */
039    public class AssertableCell extends CellExtension {
040    
041            /** The unique version identifier used for serialization */
042            private static final long serialVersionUID = 4956240183977127091L;
043    
044            /** The cell's user-specified assertion */
045        private USAssertion usAssertion;
046    
047        /** The cell's system-generated assertion */
048        private SGAssertion sgAssertion;
049    
050            /** The listeners registered to receive events from the assertable cell */
051            private transient List<AssertableCellListener> listeners
052                    = new ArrayList<AssertableCellListener>();
053    
054            /**
055             * A flag that, when set, indicates that the system-generated assertion is
056             * <code>null</code> because of a mathematical error.
057             */
058            private boolean mathError;
059    
060            /**
061             * A short description of a possible existing math-error occuring when
062             * generating the system-generated assertion.
063             */
064            private String mathErrorMsg;
065    
066            /**
067             * Creates a assertable cell extension for the given cell.
068             * @param cell the cell to extend
069             */
070            AssertableCell(Cell cell) {
071                    super(cell, AssertionExtension.NAME);
072            }
073    
074    
075    /*
076     * DATA UPDATES
077     */
078    
079    
080            public void contentChanged(Cell cell) {
081                    if (getFormula() != null && !getFormula().getReferences().isEmpty())
082                            generateAssertion();
083                    else {
084                            sgAssertion = null;
085                            for (Cell depCell : getDependents())
086                                    ((AssertableCell)depCell).generateAssertion();
087                    }
088            }
089    
090    
091    /*
092     * ASSERTIONS ACCESSORS
093     */
094    
095    
096            /**
097             * Get the cell's user supplied assertion.
098             * @return The user supplied assertion for the cell or <code>null</code> if no user
099             supplied assertion exists.
100            */
101            public USAssertion getUSAssertion() {
102                    return usAssertion;
103            }
104    
105            /** Get the cell's system generated assertion.
106                    @return The system generated assertion for the cell or <code>null</code> if no
107                    system generated assertion exist. */
108            public SGAssertion getSGAssertion() {
109                    return sgAssertion;
110            }
111    
112            /** Get the most significant assertion of the cell. This is currently the
113                    System Generated Assertion if one exists, and the user supplied assertion otherwise.
114                    @return the most significant assertion if one exists, or <code>null</code> otherwise. */
115            public Assertion getPriorityAssertion() {
116                    if (isSGAsserted())
117                            return getSGAssertion();
118    
119                    if (isUSAsserted())
120                            return getUSAssertion();
121    
122                    return null;
123            }
124    
125            /**
126             * Returns whether the cell has an assertion.
127             * @return true if the cell has an assertion
128             */
129            public boolean isAsserted() {
130                    return isUSAsserted() || isSGAsserted();
131            }
132    
133            /** Checks if the cell has a user supplied assertion associated with it.
134                    @return <code>true</code> if the cell has a user supplied assertion associated with it, <code>false</code> otherwise. */
135            public boolean isUSAsserted() {
136                    return usAssertion != null;
137            }
138    
139            /** Checks if the cell has a system generated assertion associated with it.
140                    @return <code>true</code> if the cell has a system generated assertion associated with it, <code>false</code> otherwise. */
141            public boolean isSGAsserted() {
142                    return sgAssertion != null;
143            }
144    
145    
146    /*
147     * ASSERTION MODIFIERS
148     */
149    
150    
151            /**
152             * Sets the user-specified assertion for the cell.
153             * @param assertion the user-specified assertion
154             */
155            public void setUSAssertion(USAssertion assertion) {
156                    this.usAssertion = assertion;
157                    // Notifies listeners
158                    fireAssertionsChanged();
159    
160                    // Notifies all depending SGAssertions if this cell has no SGAssertion
161                    if (sgAssertion == null)
162                            for (Cell cell : getDependents())
163                                    ((AssertableCell)cell).generateAssertion();
164            }
165    
166            /**
167             * Invoked to indicate that the content of the cell in the spreadsheet was
168             * modified and that assertions that depend on that data must be updated.
169             */
170            public void generateAssertion() {
171                    if (getFormula() != null && !getFormula().hasCircularReference()) {
172                            // For debugging purposes only
173                            // System.out.println("Update SGA for cell: " + this);
174    
175                            try {
176                                    sgAssertion = new SGAssertion(this);
177                                    mathError = false;
178                                    mathErrorMsg = null;
179                            } catch (AssertionArithmeticException e) {
180                                    // For debugging purposes only
181                                    //e.printStackTrace();
182    
183                                    sgAssertion = null;
184                                    mathError = false;
185                                    mathErrorMsg = null;
186                            } catch (MathException e) {
187                                    // Division by zero error
188                                    mathErrorMsg = e.getMessage();
189                                    mathError = true;
190                                    sgAssertion = null;
191                            }
192    
193                            for (Cell cell : getDependents())
194                                    ((AssertableCell)cell).generateAssertion();
195    
196                            // Notifies listeners
197                            fireAssertionsChanged();
198                    }
199            }
200    
201    
202    /*
203     * ASSERTING
204     */
205    
206    
207            /** Asserts the current value of the cell using the user supplied assertion associated with the cell.
208                    @return the result of the assertion. If no assertion exists, <code>Assertion.Result.OK</code> is returned.
209                    @see USAssertion#validate(Value) */
210            public Assertion.Result assertUS() {
211                    return assertUS(getValue());
212            }
213    
214            /** Asserts the specified value using the user supplied assertion associated with the cell.
215                    @return the result of the assertion. If no assertion exists, <code>Assertion.Result.OK</code> is returned.
216                    @see USAssertion#validate(Value) */
217            public Assertion.Result assertUS(Value value) {
218                    if (usAssertion != null)
219                            return usAssertion.validate(value);
220    
221                    // If no assertion exist, the value is okay.
222                    return Assertion.Result.OK;
223            }
224    
225            /** Asserts the current value of the cell using the system generated assertion associated with the cell.
226                    @return the result of the assertion. If no assertion exists, <code>Assertion.Result.OK</code> is returned.
227                    @see SGAssertion#validate(Value) */
228            public Assertion.Result assertSG() {
229                    return assertSG(getValue());
230            }
231    
232            /** Asserts the specified value using the system generated assertion associated with the cell.
233                    @return the result of the assertion. If no assertion exists, <code>Assertion.Result.OK</code> is returned.
234                    @see SGAssertion#validate(Value) */
235            public Assertion.Result assertSG(Value value) {
236                    if (sgAssertion != null)
237                            return sgAssertion.validate(value);
238    
239                    // If no assertion exist, the value is okay.
240                    return Assertion.Result.OK;
241            }
242    
243            /** Asserts the specified value using any (or both) assertion(s) associated with the cell.
244                    The system generated assertion (if available) will be run first and upon error its return
245                    code will be returned. If the value was successfully asserted using the system generated
246                    assertion then the value will be asserted using the user supplied assertion, and its
247                    return code will be returned.  If no assertion is available in the cell <code>Assertion.Result.OK</code>
248                    will be returned.
249                    @return the success status of the assertion.
250                    @see USAssertion#validate(Value) */
251            public Assertion.Result assertAny(Value value) {
252                    Assertion.Result res = Assertion.Result.OK;
253    
254                    if (isSGAsserted()) {
255                            res = assertSG(value);
256                    }
257    
258                    if (res == Assertion.Result.OK && isUSAsserted()) {
259                            res = assertUS(value);
260                    }
261    
262                    return res;
263            }
264    
265            /** Asserts the current value of the cell using any (or both) assertion(s) associated with the cell.
266                    The system generated assertion (if available) will be run first and upon error its return
267                    code will be returned. If the value was successfully asserted using the system generated
268                    assertion then the value will be asserted using the user supplied assertion, and its
269                    return code will be returned.  If no assertion is available in the cell <code>Assertion.Result.OK</code>
270                    will be returned.
271                    @return the success status of the assertion.
272                    @see USAssertion#validate(Value) */
273            public Assertion.Result assertAny() {
274                    return assertAny(getValue());
275            }
276    
277            /** Checks wether the assertions associated with the cell agree with each other and
278                that no division by zero can occur using values within this assertion.
279                @return
280                            <ul>
281                            <li><code>Assertion.ComparisonResult.OK</code> if both the SGA and USA are specified for the cell and are equal <i>or</i>
282                            if none or only one of them is specified, AND the system generated assertion did not fail to
283                            generate because it would include a division by zero error.
284                            <li><code>Assertion.ComparisonResult.NON_EQUAL</code> if the SGA and USA are both specified and do not agree with each other.
285                            <li><code>Assertion.ComparisonResult.DIV_BY_ZERO</code> if the SGA failed to be generated because it would lead to
286                                    a division by zero error, either because of errenous assertions in precedents or an errenous
287                                    formula in the cell.
288                                    </ul>
289                             */
290            public Assertion.ComparisonResult assertAssertions() {
291    
292                    if (!isSGAsserted() && mathError) {
293                            Assertion.ComparisonResult errorResult = Assertion.ComparisonResult.ILLEGAL_INTERVAL;
294                            errorResult.setErrorMsg(mathErrorMsg);
295                            return errorResult;
296                    }
297    
298                    if (isSGAsserted() && isUSAsserted())
299                            return sgAssertion.equals(usAssertion) ? Assertion.ComparisonResult.OK : Assertion.ComparisonResult.NON_EQUAL;
300    
301                    return Assertion.ComparisonResult.OK;
302            }
303    
304            /** Checks wether there are any errors or inconsitencies in the cell related
305                    to assertions.
306                    @return <code>false</code> if there are no errors that can be found in the cell using
307                                    assertion related functions, <code>true</code> otherwise. */
308            public boolean hasAssertionError() {
309                    return !((assertAssertions() == Assertion.ComparisonResult.OK) && (assertAny() == Assertion.Result.OK));
310            }
311    
312    
313    /*
314     * EVENT LISTENING SUPPORT
315     */
316    
317    
318            /**
319             * Registers the given listener on the cell.
320             * @param listener the listener to be added
321             */
322            public void addAssertableCellListener(AssertableCellListener listener) {
323                    listeners.add(listener);
324            }
325    
326            /**
327             * Removes the given listener from the cell.
328             * @param listener the listener to be removed
329             */
330            public void removeAssertableCellListener(AssertableCellListener listener) {
331                    listeners.remove(listener);
332            }
333    
334            /**
335             * Notifies all registered listeners that the cell's assertions changed.
336             */
337            protected void fireAssertionsChanged() {
338                    for (AssertableCellListener listener : listeners)
339                            listener.assertionsChanged(this);
340            }
341    
342            /**
343             * Customizes serialization, by recreating the listener list.
344             * @param stream the object input stream from which the object is to be read
345             * @throws IOException If any of the usual Input/Output related exceptions occur
346             * @throws ClassNotFoundException If the class of a serialized object cannot be found.
347             */
348            private void readObject(java.io.ObjectInputStream stream)
349                            throws java.io.IOException, ClassNotFoundException {
350                stream.defaultReadObject();
351                    listeners = new ArrayList<AssertableCellListener>();
352            }
353    }