⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sheet.java

📁 类似于Windows上的Excel
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * MC2 -- j2me spreadsheet
 *
 * Copyright (c) 2004-2006 Michael Zemljanukha (mixaz@mail.ru)
 *
 * 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
 */

package com.wapindustrial.calc;

import java.util.*;
import java.io.*;
//#ifndef NOGUI
import javax.microedition.rms.*;
//#endif

public final class Sheet extends LispObject {
    
    static final int AXIS_X=0, AXIS_Y=1;
    
    public boolean isChanged = false;
    
    Hashtable cells;                /* of Cell type */
    Hashtable rows,columns;      	/* of RowColumn type */
    Hashtable changedCells;     	// of Cell type */
    Vector refTable;       			// of Dependency type
    // default row/column width/height, in font characters (not pixels!) / 64
    static final int fontDivider = 64;
    int defaultWidthHeight[]= { 6*fontDivider, 1*fontDivider };
    
    // visible range of sheet
    int visibleX, visibleY;
    
    public String name;			// sheet name
    
    public Sheet() {
        name = "untitled";
        visibleX = 8;
        visibleY = 32;
        clearSheet();
    }
    
    /* =========================
     * complex Atom interface
     */
    public int typeNumber() {
        return TYPE_SHEET;
    }
	/* (non-Javadoc)
	 * @see com.wapindustrial.calc.LispObject#listSize()
	 */
	public int listSize() {
		return 7;
	}
	/* (non-Javadoc)
	 * @see com.wapindustrial.calc.LispObject#getPart(int)
	 */
	LispObject getPart(int item) {
		switch(item) {
			case 0:
	            return Bfunc.BFUNC.table[Bfunc.INDEX_SHEET_CREATE];
			case 1:
                return new StringAtom( name );
			case 2:
				return new QuotedList( columns );
			case 3:
                return new QuotedList( rows );
			case 4:
                return  new QuotedList( cells );
			case 5:
                return new QuotedList( 
                        new LispObject[] {
                            new ShortAtom( defaultWidthHeight[AXIS_X] ),
                            new ShortAtom( defaultWidthHeight[AXIS_Y] )
                        }
                    );
			case 6:
                return new QuotedList( 
                        new LispObject[] {
                            new ShortAtom( visibleX ),
                            new ShortAtom( visibleY )
                        }
                    );
		}
		// will throw error
		return super.getPart(item);
	}
    
	/* (non-Javadoc)
	 * @see com.wapindustrial.calc.LispObject#setPart(int, com.wapindustrial.calc.LispObject)
	 */
//	LispObject setPart(int item, LispObject newvalue)
//			throws IllegalArgumentException {
//		switch(item) {
//			case 1:
//                name = ((StringAtomBase)newvalue).getValue();
//                break;
//			case 2:
//		        columns = ((QuotedList)newvalue).toHashtable();
//				break;
//			case 3:
//                return new QuotedList( rows );
//			case 4:
//                return  new QuotedList( cells );
//			case 5:
//                return new QuotedList( 
//                        new LispObject[] {
//                            new ShortAtom( defaultWidthHeight[AXIS_X] ),
//                            new ShortAtom( defaultWidthHeight[AXIS_Y] )
//                        }
//                    );
//			case 6:
//                return new QuotedList( 
//                        new LispObject[] {
//                            new ShortAtom( visibleX ),
//                            new ShortAtom( visibleY )
//                        }
//                    );
//		}
//		// will throw error
//		return super.getPart(item);
//	}
	
    public static Sheet sheetFromList( FunctorList fl ) throws EvaluateException {
        Sheet sheet = new Sheet();
        sheet.name = ((StringAtomBase)fl.getArgument1()).getValue();
        sheet.columns = ((QuotedList)fl.evaluateArg2()).toHashtable();
        sheet.rows = ((QuotedList)fl.evaluateArg3()).toHashtable();
        Hashtable cells = ((QuotedList)fl.evaluateArgN(4)).toHashtable();
        // append to cells and recalculate
        for (Enumeration e = cells.elements() ; e.hasMoreElements() ;) {
            Cell cl = (Cell) e.nextElement();
            sheet.putCell( cl );
        }
//        sheet.changedCells = ((QuotedList)fl.evaluateArgN(4)).toHashtable();; // duplicate [4]!
        int len = fl.listSize();
        if( len > 5 ) {
            QuotedList widthheight = fl.getQuotedList(5);
            sheet.defaultWidthHeight[AXIS_X] = widthheight.getShort(0);
            sheet.defaultWidthHeight[AXIS_Y] = widthheight.getShort(1);
        }
        if( len > 6 ) {
            QuotedList widthheight = fl.getQuotedList(6);
            sheet.visibleX = widthheight.getShort(0);
            sheet.visibleY = widthheight.getShort(1);
        }
//        try { // references can be recalculated only for active sheet :(
//            sheet.recalculateChangedCells( null );
//        }
//        catch( CircularReferenceException ee ) {
//            throw new EvaluateException(ee.getMessage());
//        }
        sheet.isChanged = false;
        return sheet;
    }
    
    
    public void clearSheet() {
        cells = new Hashtable();
        changedCells = new Hashtable();
        rows = new Hashtable();
        columns = new Hashtable();
        refTable = new Vector();
    }
    
    /* =========================================
     * Misc
     */
    public final boolean isEmpty( int i, int j ) {
        return getCell( i,j ).isEmpty();      // don't compare with CELL_EMPTY since there may be an expression
    }
//    public final boolean isFormula( int i, int j ) {
//        return getCell( i,j ).isFormula();
//    }

    public int coord( int axis, int I ) {
        int Y = 0;
        Hashtable tb = axis == AXIS_Y ? rows : columns;
        int default_size = defaultWidthHeight[axis];
        for( int i=0; i<I; i++ ) {
            RowColumn rc = (RowColumn) tb.get( new Integer(i) );
            if( rc != null )
                Y += rc.width_height;
            else
                Y += default_size;
        }
        return Y;
    }
    
    /* =================================================================
     * references
     */
    // point p2 depends on range r1
    private void addReference( int i1, int j1, int i2, int j2, int i3, int j3 ) {
        
        // test if it's already in the list
        for( int i=refTable.size()-1; i>=0; i-- ) {
            Dependency dep = (Dependency) refTable.elementAt( i );
            if( 
                dep.i1 == i1 && dep.j1 == j1 &&
                dep.i2 == i2 && dep.j2 == j2 &&
                dep.i3 == i3 && dep.j3 == j3
            )
                return;
        }
        
        refTable.addElement( new Dependency( i1,j1,i2,j2,i3,j3 ) );
    }
    
    public Cell clearCell( int I, int J ) {
        // remove references from this cell
        for( int i=refTable.size()-1; i>=0; i-- ) {
            Dependency dep = (Dependency) refTable.elementAt( i );
            if( dep.i3 == I && dep.j3 == J )
                refTable.removeElementAt( i );
        }
        Cell cl = getCell( I,J );
        cells.remove( cl );
        changedCells.put( cl, cl );
        return cl;
    }
    
    // returns true if value has been changed
    // does not recalculate dependencies!
    public void setFormula( int I, int J, String ss ) throws ParseException, EvaluateException {
        
        // evaluate the expression
        LispObject rr = LispObject.parseSExp( ss );
        // calculate references
        rr = evaluateRef( rr, I, J );
//        LispObject rrr = rr.evaluateSExp();
        // no exception occured
        Cell oldcell = getCell( I, J );
        Cell cl = new Cell( I, J, rr, oldcell.format );
        putCell( cl ); 
    }
    
    // do not forget to evaluateRef() and to calculate value
    void putCell( Cell cl ) {
        // remove old value from dependencies and sheets
        clearCell( cl.i, cl.j );
        if( cl.formula != NIL ) {
            addRef( cl.formula, cl.i, cl.j );
            cells.put( cl, cl );
            changedCells.put( cl, cl );
        }
        isChanged = true;
    }

    // does not recalculate dependencies!
    public void setWSFormula( int I, int J, String ss ) throws FormulaParseException, EvaluateException {
        
        // evaluate the expression
        LispObject rr;
        if( ss.length() == 0 )
            rr = NIL;
        else {
            rr = Operator.OPERATOR.parseFormula( ss );
            rr = evaluateRef( rr, I, J );        // no ref evaluating required - they already are atoms
        }
//        LispObject rrr = rr.evaluateSExp();
        // no exception occured

        // remove old value from dependencies and sheets
        Cell oldcell = getCell( I, J );
//        Cell cl = new Cell( I,J, rr, rrr, oldcell.format );
        Cell cl = new Cell( I,J, rr, oldcell.format );
        putCell( cl );
    }

    // does not recalculate dependencies!
    public void setFormula1( int i, int j, String ss ) {
        try {
            setFormula( i, j, ss );
        }
        catch( Exception e ) { }
//        catch( BadFormulaException e ) {
//            System.out.println("system error - exception <" + e.getMessage() + "> wasn't expected here");
//        }
    }
    
    // evaluates all Refs in the tree
    // throws EvaluateException if broken arguments of Reference are specified
    static LispObject evaluateRef( LispObject lo, int I, int J ) throws EvaluateException {
        if( lo.typeNumber() == TYPE_FUNCTORLIST ) {
            FunctorList fl = (FunctorList) lo;
            if( fl.functor == Bfunc.BFUNC.table[Bfunc.INDEX_REF] || 
                fl.functor == Bfunc.BFUNC.table[Bfunc.INDEX_DATE]    ) {
                // found, will replace
                // argumenst must be constants, so no argument evaluation required
                return fromList( fl );
            }
            final int size = fl.listSize();
            if( fl.functor == Bfunc.BFUNC.table[Bfunc.INDEX_QLIST] ) {
                final LispObject newargs[] = new LispObject[size-1];
                for( int i=1; i<size; i++ ) {
                    LispObject oldarg = fl.getArgumentN(i);
                    newargs[i-1] = evaluateRef( oldarg, I, J );
                }
                return new QuotedList(newargs);
            }
            final LispObject newargs[] = new LispObject[size];
            boolean replace = false;
            newargs[0] = fl.functor;
            for( int i=1; i<size; i++ ) {
                LispObject oldarg = fl.getArgumentN(i);
                LispObject newarg = newargs[i] = evaluateRef( oldarg, I, J );
                if(oldarg!=newarg)
                    replace = true;
            }
            if(replace)
                return createFunctorList(newargs);
        }
        return lo;
    }

    // and ads it to references
    void addRef( LispObject lo, int I, int J ) {
    	int type = lo.typeNumber();
        if( lo instanceof Reference ) {
            // found, will replace
            Reference ref = (Reference) lo;
            // don't add broken refs
            if( (ref.absFlags&Reference.BAD_REF) == 0 )
                addReference( ref.i1,ref.j1, ref.i2,ref.j2, I,J );
            return;
        }
        if( lo instanceof FunctorList ) {
            FunctorList fl = (FunctorList) lo;
            final int size = fl.listSize();
            for( int i=1; i<size; i++ )
                addRef( fl.getArgumentN(i), I, J );
        }
        if( lo instanceof QuotedList ) {
            QuotedList fl = (QuotedList) lo;
            for( int i=0; i<fl.value.length; i++ )
                addRef( fl.value[i], I, J );
        }
    }

    /*
     * Algorithm:
     * From every changed cell claculate waves recursevelly with setting step (wave number).
     * If come to an already changed cell, increase its step if it's below current one, 
     * also recursevelly to all depended cells.
     * No change if encountered step is above the current one.
     * Then calculate cells in order of step (wave number), for whole wave.
     */
    Hashtable waveCells; // of WaveCell
    Hashtable pathCells; // cell in the path from root change, to control circular references
    // canvas is used to notify the caller about repainted cells
    
    void recalculateChangedCells(
//#ifndef NOGUI
            CanvasHandler1 canvas
//#endif            
            ) throws CircularReferenceException {
        waveCells = createHashtable( changedCells.size() );
        pathCells = new Hashtable( 10 );
        
        Enumeration en;
        // scann all changed cells which haven't been processed yet
        while( (en=changedCells.elements()).hasMoreElements() ) {
            Cell cell = (Cell) en.nextElement();
            en = null;      // we are going to remove cells from changedCells, so enumeration may be broken then
                            // have to recreate Enumeration
            // mark all depended cells 
            markDepended( cell, 0 );
        }

        pathCells = null;
        
        // now recalculate cells wave by wave
        int level = 0;
        while( waveCells.size() > 0 ) {
            for( en=waveCells.elements(); en.hasMoreElements(); ) {
                WaveCell wc = (WaveCell) en.nextElement();
                if( wc.level == level ) {
                	LispObject rr = FormulaError.ERROR;
            		debug( "recalculating cell: " + wc.cell.toString() );
                	try {
                		rr = wc.cell.formula.evaluateSExp();
                	}
                	catch( EvaluateException ee ) {
                		debug( "error while recalculating cells: " + ee.getMessage() );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -