? CVS_REL_2_BRANCH.jpx ? CVS_REL_2_BRANCH.jpx.local ? DragosPatch.patch ? JBuilder_lib ? POI_libs.library ? Servlet.library ? bak ? classes ? jsp.war ? workbook.xls ? workbook_2.xls ? src/contrib/src/org/apache/poi/hssf/usermodel/TestDataValidationAndHideRows.java ? src/contrib/src/org/apache/poi/hssf/usermodel/TestHSSFSheet_Hide_Clone.java ? src/contrib/src/org/apache/poi/hssf/usermodel/TestOutliningGrouping.java ? src/examples/jsp/WEB-INF ? src/java/org/apache/poi/hssf/record/DVALRecord.java ? src/java/org/apache/poi/hssf/record/DVRecord.java ? src/java/org/apache/poi/hssf/util/HSSFCellRangeAddress.java ? src/java/org/apache/poi/hssf/util/HSSFDataValidation.java ? src/testcases/org/apache/poi/hssf/data/templateExcelWithAutofilter.xls Index: src/examples/jsp/HSSFExample.jsp =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/examples/jsp/HSSFExample.jsp,v retrieving revision 1.1 diff -u -r1.1 HSSFExample.jsp --- src/examples/jsp/HSSFExample.jsp 26 Jan 2003 20:43:02 -0000 1.1 +++ src/examples/jsp/HSSFExample.jsp 8 Mar 2004 08:47:32 -0000 @@ -1,26 +1,23 @@ -<%@page contentType="text/html" -import="java.io.*,org.apache.poi.poifs.filesystem.POIFSFileSystem,org.apache.poi -.hssf.record.*,org.apache.poi.hssf.model.*,org.apache.poi.hssf.usermodel.*,org.a -pache.poi.hssf.util.*" %> +<%@page contentType="text/html" import="java.io.*,org.apache.poi.poifs.filesystem.POIFSFileSystem,org.apache.poi.hssf.record.*,org.apache.poi.hssf.model.*,org.apache.poi.hssf.usermodel.*,org.apache.poi.hssf.util.*" %> Read Excel file -An example of using Jakarta POI's HSSF package to read an excel spreadsheet: +An example of using Jakarta POI's HSSF package to read an excel spreadsheet:
-Select an Excel file to read. +Select an Excel file to read.
<% - String filename = request.getParameter("xls_filename"); + String filename = request.getParameter("xls_filename"); if (filename != null && !filename.equals("")) { -%> -
You chose the file <%= filename %>. -

It's contents are: -<% +%> +
You chose the file <%= filename %>. +

It's contents are: +<% try { @@ -31,26 +28,26 @@ for (int k = 0; k < wb.getNumberOfSheets(); k++) { -%> +%>

Sheet <%= k %>
-<% - +<% + HSSFSheet sheet = wb.getSheetAt(k); int rows = sheet.getPhysicalNumberOfRows(); for (int r = 0; r < rows; r++) { HSSFRow row = sheet.getRow(r); - if (row != null) { + if (row != null) { int cells = row.getPhysicalNumberOfCells(); %> -
ROW <%= +
ROW <%= row.getRowNum() %> <% - for (short c = 0; c < cells; c++) - { + for (short c = 0; c < cells; c++) + { HSSFCell cell = row.getCell(c); - if (cell != null) { + if (cell != null) { String value = null; switch (cell.getCellType()) @@ -73,13 +70,13 @@ default : } -%> - <%= "CELL col=" - +%> + <%= "CELL col=" + + cell.getCellNum() + " VALUE=" + value %> <% - } + } } } } @@ -89,12 +86,12 @@ { %> Error occurred: <%= e.getMessage() %> -<% +<% e.printStackTrace(); } - } -%> + } +%> Index: src/examples/src/org/apache/poi/hssf/usermodel/examples/OfficeDrawing.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/examples/src/org/apache/poi/hssf/usermodel/examples/Attic/OfficeDrawing.java,v retrieving revision 1.1.2.2 diff -u -r1.1.2.2 OfficeDrawing.java --- src/examples/src/org/apache/poi/hssf/usermodel/examples/OfficeDrawing.java 28 Feb 2004 12:55:57 -0000 1.1.2.2 +++ src/examples/src/org/apache/poi/hssf/usermodel/examples/OfficeDrawing.java 8 Mar 2004 08:47:33 -0000 @@ -14,13 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - + package org.apache.poi.hssf.usermodel.examples; import org.apache.poi.hssf.usermodel.*; import java.io.IOException; import java.io.FileOutputStream; +import java.io.FileInputStream; import java.io.FileNotFoundException; /** @@ -50,6 +51,12 @@ FileOutputStream fileOut = new FileOutputStream("workbook.xls"); wb.write(fileOut); fileOut.close(); + +// wb = new HSSFWorkbook(new FileInputStream("workbook.xls")); +// fileOut = new FileOutputStream("workbook_2.xls"); +// wb.write(fileOut); +// fileOut.close(); + } private static void drawSheet1( HSSFSheet sheet1 ) Index: src/java/org/apache/poi/hssf/eventmodel/EventRecordFactory.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/eventmodel/EventRecordFactory.java,v retrieving revision 1.5.2.1 diff -u -r1.5.2.1 EventRecordFactory.java --- src/java/org/apache/poi/hssf/eventmodel/EventRecordFactory.java 22 Feb 2004 11:54:46 -0000 1.5.2.1 +++ src/java/org/apache/poi/hssf/eventmodel/EventRecordFactory.java 8 Mar 2004 08:47:33 -0000 @@ -93,6 +93,7 @@ import org.apache.poi.hssf.record.SharedFormulaRecord; import org.apache.poi.hssf.record.StringRecord; import org.apache.poi.hssf.record.StyleRecord; +import org.apache.poi.hssf.record.SupBookRecord; import org.apache.poi.hssf.record.TabIdRecord; import org.apache.poi.hssf.record.TopMarginRecord; import org.apache.poi.hssf.record.UnknownRecord; @@ -111,15 +112,16 @@ * this refactored version throws record events as it comes * accross the records. I throws the "lazily" one record behind * to ensure that ContinueRecords are processed first. - * + * * @author Andrew C. Oliver (acoliver@apache.org) - probably to blame for the bugs (so yank his chain on the list) * @author Marc Johnson (mjohnson at apache dot org) - methods taken from RecordFactory * @author Glen Stampoultzis (glens at apache.org) - methods taken from RecordFactory * @author Csaba Nagy (ncsaba at yahoo dot com) + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) */ public class EventRecordFactory { - + /** * contains the classes for all the records we want to parse. */ @@ -138,7 +140,7 @@ PrecisionRecord.class, RefreshAllRecord.class, BookBoolRecord.class, FontRecord.class, FormatRecord.class, ExtendedFormatRecord.class, StyleRecord.class, UseSelFSRecord.class, BoundSheetRecord.class, - CountryRecord.class, SSTRecord.class, ExtSSTRecord.class, + CountryRecord.class, SupBookRecord.class, SSTRecord.class, ExtSSTRecord.class, EOFRecord.class, IndexRecord.class, CalcModeRecord.class, CalcCountRecord.class, RefModeRecord.class, IterationRecord.class, DeltaRecord.class, SaveRecalcRecord.class, PrintHeadersRecord.class, @@ -156,9 +158,9 @@ TopMarginRecord.class, BottomMarginRecord.class, PaletteRecord.class, StringRecord.class, SharedFormulaRecord.class }; - + } - + /** * cache of the recordsToMap(); */ @@ -172,54 +174,54 @@ /** * List of the listners that are registred. should all be ERFListener - */ + */ private List listeners; /** * instance is abortable or not */ private boolean abortable; - + /** - * Construct an abortable EventRecordFactory. + * Construct an abortable EventRecordFactory. * The same as calling new EventRecordFactory(true) * @see #EventRecordFactory(boolean) */ public EventRecordFactory() { - this(true); + this(true); } - + /** * Create an EventRecordFactory - * @param abortable specifies whether the return from the listener + * @param abortable specifies whether the return from the listener * handler functions are obeyed. False means they are ignored. True * means the event loop exits on error. */ public EventRecordFactory(boolean abortable) { this.abortable = abortable; - listeners = new ArrayList(recordsMap.size()); - + listeners = new ArrayList(recordsMap.size()); + if (sidscache == null) { - sidscache = getAllKnownRecordSIDs(); + sidscache = getAllKnownRecordSIDs(); } } - + /** - * Register a listener for records. These can be for all records + * Register a listener for records. These can be for all records * or just a subset. - * + * * @param sids an array of Record.sid values identifying the records - * the listener will work with. Alternatively if this is "null" then + * the listener will work with. Alternatively if this is "null" then * all records are passed. */ public void registerListener(ERFListener listener, short[] sids) { if (sids == null) sids = sidscache; - ERFListener wrapped = new ListenerWrapper(listener, sids, abortable); + ERFListener wrapped = new ListenerWrapper(listener, sids, abortable); listeners.add(wrapped); } - + /** * used for unit tests to test the registration of record listeners. * @return Iterator of ERFListeners @@ -238,11 +240,11 @@ { boolean result = true; Iterator i = listeners.iterator(); - + while (i.hasNext()) { - result = ((ERFListener) i.next()).processRecord(record); + result = ((ERFListener) i.next()).processRecord(record); if (abortable == true && result == false) { - break; + break; } } return result; @@ -285,7 +287,7 @@ if ( last_record != null ) { if (throwRecordEvent(last_record) == false && abortable == true) { last_record = null; - break; + break; } } // records.add( @@ -316,12 +318,12 @@ if (last_record != null) { if (throwRecordEvent(last_record) == false && abortable == true) { last_record = null; - break; + break; } } - + last_record = record; - + //records.add(record); } } @@ -329,9 +331,9 @@ } } while (rectype != 0); - + if (last_record != null) { - throwRecordEvent(last_record); + throwRecordEvent(last_record); } } catch (IOException e) @@ -341,7 +343,7 @@ // Record[] retval = new Record[ records.size() ]; // retval = ( Record [] ) records.toArray(retval); - + } /** @@ -496,10 +498,10 @@ ListenerWrapper(ERFListener listener, short[] sids, boolean abortable) { this.listener = listener; - this.sids = sids; + this.sids = sids; this.abortable = abortable; - } - + } + public boolean processRecord(Record rec) { @@ -507,12 +509,12 @@ for (int k = 0; k < sids.length; k++) { if (sids[k] == rec.getSid()) { result = listener.processRecord(rec); - + if (abortable == true && result == false) { - break; + break; } } } return result; - } + } } Index: src/java/org/apache/poi/hssf/model/FormulaParser.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/model/FormulaParser.java,v retrieving revision 1.13.2.3 diff -u -r1.13.2.3 FormulaParser.java --- src/java/org/apache/poi/hssf/model/FormulaParser.java 22 Feb 2004 11:54:46 -0000 1.13.2.3 +++ src/java/org/apache/poi/hssf/model/FormulaParser.java 8 Mar 2004 08:47:37 -0000 @@ -30,7 +30,7 @@ /** * This class parses a formula string into a List of tokens in RPN order. - * Inspired by + * Inspired by * Lets Build a Compiler, by Jack Crenshaw * BNF for the formula expression is : * ::= [ ]* @@ -43,39 +43,40 @@ * @author Eric Ladner (eladner at goldinc dot com) * @author Cameron Riley (criley at ekmail.com) * @author Peter M. Murray (pete at quantrix dot com) + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) */ public class FormulaParser { - + public static int FORMULA_TYPE_CELL = 0; public static int FORMULA_TYPE_SHARED = 1; public static int FORMULA_TYPE_ARRAY =2; public static int FORMULA_TYPE_CONDFOMRAT = 3; public static int FORMULA_TYPE_NAMEDRANGE = 4; - + private String formulaString; private int pointer=0; private int formulaLength; - + private List tokens = new java.util.Stack(); - + /** * Using an unsynchronized linkedlist to implement a stack since we're not multi-threaded. */ private List functionTokens = new LinkedList(); - + //private Stack tokens = new java.util.Stack(); private List result = new ArrayList(); private int numParen; - + private static char TAB = '\t'; private static char CR = '\n'; - + private char look; // Lookahead Character private boolean inFunction = false; - + private Workbook book; - - + + /** create the parser with the string that is to be parsed * later call the parse() method to return ptg list in rpn order * then call the getRPNPtg() to retrive the parse results @@ -87,12 +88,12 @@ this.book = book; formulaLength = formulaString.length(); } - + /** Read New Character From Input Stream */ private void GetChar() { // Check to see if we've walked off the end of the string. - // Just return if so and reset Look to smoething to keep + // Just return if so and reset Look to smoething to keep // SkipWhitespace from spinning if (pointer == formulaLength) { look = (char)0; @@ -101,64 +102,64 @@ look=formulaString.charAt(pointer++); //System.out.println("Got char: "+ look); } - + /** Report an Error */ private void Error(String s) { System.out.println("Error: "+s); } - - - + + + /** Report Error and Halt */ private void Abort(String s) { Error(s); //System.exit(1); //throw exception?? throw new RuntimeException("Cannot Parse, sorry : "+s); } - - + + /** Report What Was Expected */ private void Expected(String s) { Abort(s + " Expected"); } - - - + + + /** Recognize an Alpha Character */ private boolean IsAlpha(char c) { return Character.isLetter(c) || c == '$'; } - - - + + + /** Recognize a Decimal Digit */ private boolean IsDigit(char c) { //System.out.println("Checking digit for"+c); return Character.isDigit(c); } - - + + /** Recognize an Alphanumeric */ private boolean IsAlNum(char c) { return (IsAlpha(c) || IsDigit(c)); } - - + + /** Recognize an Addop */ private boolean IsAddop( char c) { return (c =='+' || c =='-'); } - + /** Recognize White Space */ private boolean IsWhite( char c) { return (c ==' ' || c== TAB); } - + /** * Determines special characters;primarily in use for definition of string literals * @param c @@ -167,7 +168,7 @@ private boolean IsSpecialChar(char c) { return (c == '>' || c== '<' || c== '=' || c=='&' || c=='[' || c==']'); } - + /** Skip Over Leading White Space */ private void SkipWhite() { @@ -175,8 +176,8 @@ GetChar(); } } - - + + /** Match a Specific Input Character */ private void Match(char x) { @@ -187,7 +188,7 @@ SkipWhite(); } } - + /** Get an Identifier */ private String GetName() { StringBuffer Token = new StringBuffer(); @@ -219,20 +220,20 @@ SkipWhite(); return Token.toString(); } - - /**Get an Identifier AS IS, without stripping white spaces or + + /**Get an Identifier AS IS, without stripping white spaces or converting to uppercase; used for literals */ private String GetNameAsIs() { StringBuffer Token = new StringBuffer(); - + while (IsAlNum(look) || IsWhite(look) || IsSpecialChar(look)) { Token = Token.append(look); GetChar(); } return Token.toString(); } - - + + /** Get a Number */ private String GetNum() { String Value =""; @@ -255,7 +256,7 @@ Emit(s); System.out.println();; } - + /** Parse and Translate a String Identifier */ private void Ident() { String name; @@ -276,14 +277,17 @@ if (look == ':') { Match(':'); String second=GetName(); - + tokens.add(new Area3DPtg(first+":"+second,externIdx)); } else { tokens.add(new Ref3DPtg(first,externIdx)); } } else { //this can be either a cell ref or a named range !! - boolean cellRef = true ; //we should probably do it with reg exp?? + //Dragos Buleandra : previous line leads to an error when using an explicit string + // formula in data validation + boolean cellRef = name.startsWith("$"); + //boolean cellRef = true ; //we should probably do it with reg exp?? boolean boolLit = (name.equals("TRUE") || name.equals("FALSE")); if (boolLit) { tokens.add(new BoolPtg(name)); @@ -291,10 +295,16 @@ tokens.add(new ReferencePtg(name)); }else { //handle after named range is integrated!! + //Dragos Buleandra + if ( formulaString.endsWith(";") ) + { + formulaString = formulaString.substring(0, formulaString.length()-1); + } + tokens.add(new StringPtg(formulaString)); } } } - + /** * Adds a pointer to the last token to the latest function argument list. * @param obj @@ -306,19 +316,19 @@ arguments.add(tokens.get(tokens.size()-1)); } } - + private void function(String name) { //average 2 args per function this.functionTokens.add(0, new ArrayList(2)); - + Match('('); int numArgs = Arguments(); Match(')'); - + AbstractFunctionPtg functionPtg = getFunction(name,(byte)numArgs); - + tokens.add(functionPtg); - + if (functionPtg.getName().equals("externalflag")) { tokens.add(new NamePtg(name, this.book)); } @@ -326,7 +336,7 @@ //remove what we just put in this.functionTokens.remove(0); } - + /** * Adds the size of all the ptgs after the provided index (inclusive). *

@@ -336,16 +346,16 @@ */ private int getPtgSize(int index) { int count = 0; - + Iterator ptgIterator = tokens.listIterator(index); while (ptgIterator.hasNext()) { Ptg ptg = (Ptg)ptgIterator.next(); count+=ptg.getSize(); } - + return count; } - + private int getPtgSize(int start, int end) { int count = 0; int index = start; @@ -355,91 +365,91 @@ count+=ptg.getSize(); index++; } - + return count; } /** * Generates the variable function ptg for the formula. *

- * For IF Formulas, additional PTGs are added to the tokens + * For IF Formulas, additional PTGs are added to the tokens * @param name * @param numArgs * @return Ptg a null is returned if we're in an IF formula, it needs extreme manipulation and is handled in this function */ private AbstractFunctionPtg getFunction(String name, byte numArgs) { AbstractFunctionPtg retval = null; - + if (name.equals("IF")) { retval = new FuncVarPtg(AbstractFunctionPtg.ATTR_NAME, numArgs); - + //simulated pop, no bounds checking because this list better be populated by function() List argumentPointers = (List)this.functionTokens.get(0); - - + + AttrPtg ifPtg = new AttrPtg(); ifPtg.setData((short)7); //mirroring excel output ifPtg.setOptimizedIf(true); - + if (argumentPointers.size() != 2 && argumentPointers.size() != 3) { throw new IllegalArgumentException("["+argumentPointers.size()+"] Arguments Found - An IF formula requires 2 or 3 arguments. IF(CONDITION, TRUE_VALUE, FALSE_VALUE [OPTIONAL]"); } - + //Biffview of an IF formula record indicates the attr ptg goes after the condition ptgs and are //tracked in the argument pointers //The beginning first argument pointer is the last ptg of the condition int ifIndex = tokens.indexOf(argumentPointers.get(0))+1; tokens.add(ifIndex, ifPtg); - + //we now need a goto ptgAttr to skip to the end of the formula after a true condition //the true condition is should be inserted after the last ptg in the first argument - + int gotoIndex = tokens.indexOf(argumentPointers.get(1))+1; - + AttrPtg goto1Ptg = new AttrPtg(); goto1Ptg.setGoto(true); - - + + tokens.add(gotoIndex, goto1Ptg); - - + + if (numArgs > 2) { //only add false jump if there is a false condition - + //second goto to skip past the function ptg AttrPtg goto2Ptg = new AttrPtg(); goto2Ptg.setGoto(true); goto2Ptg.setData((short)(retval.getSize()-1)); //Page 472 of the Microsoft Excel Developer's kit states that: //The b(or w) field specifies the number byes (or words to skip, minus 1 - + tokens.add(goto2Ptg); //this goes after all the arguments are defined } - + //data portion of the if ptg points to the false subexpression (Page 472 of MS Excel Developer's kit) //count the number of bytes after the ifPtg to the False Subexpression //doesn't specify -1 in the documentation ifPtg.setData((short)(getPtgSize(ifIndex+1, gotoIndex))); - + //count all the additional (goto) ptgs but dont count itself int ptgCount = this.getPtgSize(gotoIndex)-goto1Ptg.getSize()+retval.getSize(); if (ptgCount > (int)Short.MAX_VALUE) { throw new RuntimeException("Ptg Size exceeds short when being specified for a goto ptg in an if"); } - + goto1Ptg.setData((short)(ptgCount-1)); - + } else { - + retval = new FuncVarPtg(name,numArgs); } - + return retval; } - + /** get arguments to a function */ private int Arguments() { int numArgs = 0; if (look != ')') { - numArgs++; + numArgs++; Expression(); addArgumentPointer(); } @@ -475,7 +485,7 @@ } else if(look == '"') { StringLiteral(); } else { - + String number = GetNum(); if (look=='.') { Match('.'); @@ -487,8 +497,8 @@ } } } - - private void StringLiteral() + + private void StringLiteral() { // Can't use match here 'cuz it consumes whitespace // which we need to preserve inside the string. @@ -524,16 +534,16 @@ tokens.add(new StringPtg(Token.toString())); } } - + /** Recognize and Translate a Multiply */ private void Multiply(){ Match('*'); Factor(); tokens.add(new MultiplyPtg()); - + } - - + + /** Recognize and Translate a Divide */ private void Divide() { Match('/'); @@ -541,13 +551,13 @@ tokens.add(new DividePtg()); } - - + + /** Parse and Translate a Math Term */ private void Term(){ Factor(); while (look == '*' || look == '/' || look == '^' || look == '&') { - + ///TODO do we need to do anything here?? if (look == '*') Multiply(); else if (look == '/') Divide(); @@ -555,42 +565,42 @@ else if (look == '&') Concat(); } } - + /** Recognize and Translate an Add */ private void Add() { Match('+'); Term(); tokens.add(new AddPtg()); } - + /** Recognize and Translate a Concatination */ private void Concat() { Match('&'); Term(); tokens.add(new ConcatPtg()); } - + /** Recognize and Translate a test for Equality */ private void Equal() { Match('='); Expression(); tokens.add(new EqualPtg()); } - + /** Recognize and Translate a Subtract */ private void Subtract() { Match('-'); Term(); tokens.add(new SubtractPtg()); - } + } private void Power() { Match('^'); Term(); tokens.add(new PowerPtg()); } - - + + /** Parse and Translate an Expression */ private void Expression() { Term(); @@ -598,21 +608,21 @@ if (look == '+' ) Add(); else if (look == '-') Subtract(); } - + /* * This isn't quite right since it would allow multiple comparison operators. */ - + if(look == '=' || look == '>' || look == '<') { if (look == '=') Equal(); else if (look == '>') GreaterThan(); else if (look == '<') LessThan(); return; - } - - + } + + } - + /** Recognize and Translate a Greater Than */ private void GreaterThan() { Match('>'); @@ -623,7 +633,7 @@ tokens.add(new GreaterThanPtg()); } } - + /** Recognize and Translate a Less Than */ private void LessThan() { Match('<'); @@ -636,40 +646,40 @@ tokens.add(new LessThanPtg()); } - } - + } + /** * Recognize and translate Greater than or Equal * - */ + */ private void GreaterEqual() { Match('='); Expression(); tokens.add(new GreaterEqualPtg()); - } + } /** * Recognize and translate Less than or Equal * - */ + */ private void LessEqual() { Match('='); Expression(); tokens.add(new LessEqualPtg()); } - + /** * Recognize and not Equal * - */ + */ private void NotEqual() { Match('>'); Expression(); tokens.add(new NotEqualPtg()); - } - + } + //{--------------------------------------------------------------} //{ Parse and Translate an Assignment Statement } /** @@ -682,15 +692,15 @@ end; **/ - - + + /** Initialize */ - + private void init() { GetChar(); SkipWhite(); } - + /** API call to execute the parsing of the formula * */ @@ -700,27 +710,27 @@ Expression(); } } - - + + /********************************* * PARSER IMPLEMENTATION ENDS HERE * EXCEL SPECIFIC METHODS BELOW *******************************/ - - /** API call to retrive the array of Ptgs created as + + /** API call to retrive the array of Ptgs created as * a result of the parsing */ public Ptg[] getRPNPtg() { return getRPNPtg(FORMULA_TYPE_CELL); } - + public Ptg[] getRPNPtg(int formulaType) { Node node = createTree(); setRootLevelRVA(node, formulaType); setParameterRVA(node,formulaType); return (Ptg[]) tokens.toArray(new Ptg[0]); } - + private void setRootLevelRVA(Node n, int formulaType) { //Pg 16, excelfileformat.pdf @ openoffice.org Ptg p = (Ptg) n.getValue(); @@ -733,9 +743,9 @@ } else { setClass(n,Ptg.CLASS_VALUE); } - + } - + private void setParameterRVA(Node n, int formulaType) { Ptg p = (Ptg) n.getValue(); if (p instanceof AbstractFunctionPtg) { @@ -745,16 +755,16 @@ if (n.getChild(i).getValue() instanceof AbstractFunctionPtg) { setParameterRVA(n.getChild(i),formulaType); } - } + } } else { for (int i =0;i 0; j--) { //TODO: catch stack underflow and throw parse exception. operands[j - 1] = (String) stack.pop(); - } + } stack.push(o.toFormulaString(operands)); if (!(o instanceof AbstractFunctionPtg)) continue; @@ -887,12 +897,12 @@ Node[] operands; for (int i=0;iRecord object does not implement cloneable. + * can be added to a sheet. The Record object does not implement cloneable. * When adding a new record, implement a public clone method if and only if the record - * belongs to a sheet. + * belongs to a sheet. */ public Sheet cloneSheet() { @@ -385,9 +386,9 @@ records.add(retval.rowBreaks); retval.colBreaks = new PageBreakRecord(PageBreakRecord.VERTICAL_SID); records.add(retval.colBreaks); - + retval.header = (HeaderRecord) retval.createHeader(); - records.add( retval.header ); + records.add( retval.header ); retval.footer = (FooterRecord) retval.createFooter(); records.add( retval.footer ); records.add( retval.createHCenter() ); @@ -397,18 +398,18 @@ retval.defaultcolwidth = (DefaultColWidthRecord) retval.createDefaultColWidth(); records.add( retval.defaultcolwidth); - retval.dims = ( DimensionsRecord ) retval.createDimensions(); + retval.dims = ( DimensionsRecord ) retval.createDimensions(); records.add(retval.dims); retval.dimsloc = records.size()-1; records.add(retval.windowTwo = retval.createWindowTwo()); retval.setLoc(records.size() - 1); - retval.selection = + retval.selection = (SelectionRecord) retval.createSelection(); records.add(retval.selection); retval.protect = (ProtectRecord) retval.createProtect(); records.add(retval.protect); records.add(retval.createEOF()); - + retval.records = records; log.log(POILogger.DEBUG, "Sheet createsheet from scratch exit"); return retval; @@ -439,11 +440,11 @@ if (merged == null || merged.getNumAreas() == 1027) { merged = ( MergeCellsRecord ) createMergedCells(); - mergedRecords.add(merged); + mergedRecords.add(merged); records.add(records.size() - 1, merged); } merged.addArea(rowFrom, colFrom, rowTo, colTo); - return numMergedRegions++; + return numMergedRegions++; } public void removeMergedRegion(int index) @@ -451,15 +452,15 @@ //safety checks if (index >= numMergedRegions || mergedRecords.size() == 0) return; - + int pos = 0; int startNumRegions = 0; - + //optimisation for current record if (numMergedRegions - index < merged.getNumAreas()) { pos = mergedRecords.size() - 1; - startNumRegions = numMergedRegions - merged.getNumAreas(); + startNumRegions = numMergedRegions - merged.getNumAreas(); } else { @@ -471,7 +472,7 @@ pos = n; break; } - startNumRegions += record.getNumAreas(); + startNumRegions += record.getNumAreas(); } } @@ -482,7 +483,7 @@ { mergedRecords.remove(pos); //get rid of the record from the sheet - records.remove(merged); + records.remove(merged); if (merged == rec) { //pull up the LAST record for operations when we finally //support continue records for mergedRegions @@ -500,10 +501,10 @@ //safety checks if (index >= numMergedRegions || mergedRecords.size() == 0) return null; - + int pos = 0; int startNumRegions = 0; - + //optimisation for current record if (numMergedRegions - index < merged.getNumAreas()) { @@ -520,7 +521,7 @@ pos = n; break; } - startNumRegions += record.getNumAreas(); + startNumRegions += record.getNumAreas(); } } return ((MergeCellsRecord) mergedRecords.get(pos)).getAreaAt(index - startNumRegions); @@ -1780,19 +1781,33 @@ } /** + * @author Dragos Buleandra - I modified the calculation of ColumnInfo's width field * creates the ColumnInfo Record and sets it to a default column/width * @see org.apache.poi.hssf.record.ColumnInfoRecord * @return record containing a ColumnInfoRecord */ - protected Record createColInfo() { - ColumnInfoRecord retval = new ColumnInfoRecord(); - - retval.setColumnWidth(( short ) 0x8); - retval.setOptions(( short ) 6); - retval.setXFIndex(( short ) 0x0f); - return retval; + ColumnInfoRecord retval = new ColumnInfoRecord(); + //retval.setColumnWidth(( short ) 0x8); + //Dragos Buleandra -> + //the width field of ColumnInfo record represents the width of the columns + //in 1/256s of a character width . Here was a confusion with DEFCOLWIDTH record , + //where column width is measured as number of characters . + //So , the correct formula for this field is given by following the steps : + //The default column width in user units is 8.43 . + double defValue = 8.43; + + //Excel rounds the column width to the nearest pixel. + //Therefore we first convert to pixels and then to the internal units. + //The pixel to users-units relationship is different for values less than 1 , but this isn't our case . + int pixels = (int)((defValue *7 ) +5); + short finalValue = (short)(pixels*256/7); + retval.setColumnWidth(finalValue); + //<- end : Dragos Buleandra + retval.setOptions(( short ) 6); + retval.setXFIndex(( short ) 0x0f); + return retval; } /** @@ -1998,6 +2013,233 @@ } } + + /** + * @author : Dragos Buleandra + * @param column The column number ( zero based ) + * @param level The outlining level ( max. level is 7 ) + * @param collapsed True if column should be collapsed , false otherwise + */ + public void createOutlineColumn(short column, short level, boolean collapsed ) + { + /** @todo I copied the logic of creating ColumnInfo records from + * sheet.setColumnWidth method ; + * This logic can be optimized in order to minimize the number + * of created ColumnInfo records + */ + ColumnInfoRecord ci = null; + int k = 0; + + if (columnSizes == null) + { + columnSizes = new ArrayList(); + } + + for (k = 0; k < columnSizes.size(); k++) + { + ci = ( ColumnInfoRecord ) columnSizes.get(k); + if ((ci.getFirstColumn() <= column) && (column <= ci.getLastColumn())) + { + break; + } + ci = null; + } + if (ci != null) + { + if (ci.getOutlineLevel() == level) + { + // do nothing...the cell's outline level is equal to what we're setting it to. + } + else if ((ci.getFirstColumn() == column) && (ci.getLastColumn() == column)) + { + // if its only for this cell then just change the level + ci.setOutlineLevel(level); + } + else if ((ci.getFirstColumn() == column) || (ci.getLastColumn() == column)) + { + // okay so the outline level is different but the first or last column == the column we'return setting + // we'll just divide the info and create a new one + if (ci.getFirstColumn() == column) + { + ci.setFirstColumn(( short ) (column + 1)); + } + else + { + ci.setLastColumn(( short ) (column - 1)); + } + ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo(); + + nci.setFirstColumn(column); + nci.setLastColumn(column); + nci.setOptions(ci.getOptions()); + nci.setXFIndex(ci.getXFIndex()); + nci.setOutlineLevel(level); + columnSizes.add(k, nci); + records.add((1 + getDimsLoc() - columnSizes.size()) + k, nci); + dimsloc++; + } + else + { + //split to 3 records + short lastcolumn = ci.getLastColumn(); + ci.setLastColumn(( short ) (column - 1)); + + ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo(); + nci.setFirstColumn(column); + nci.setLastColumn(column); + nci.setOptions(ci.getOptions()); + nci.setXFIndex(ci.getXFIndex()); + nci.setOutlineLevel(level); + columnSizes.add(k, nci); + records.add((1 + getDimsLoc() - columnSizes.size()) + k, nci); + dimsloc++; + + nci = ( ColumnInfoRecord ) createColInfo(); + nci.setFirstColumn((short)(column+1)); + nci.setLastColumn(lastcolumn); + nci.setOptions(ci.getOptions()); + nci.setXFIndex(ci.getXFIndex()); + nci.setColumnWidth(ci.getColumnWidth()); + columnSizes.add(k, nci); + records.add((1 + getDimsLoc() - columnSizes.size()) + k, nci); + dimsloc++; + } + } + else + { + //okay so there ISN'T a column info record that cover's this column so lets create one! + ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo(); + nci.setFirstColumn((short)column); + nci.setLastColumn((short)column); + nci.setOutlineLevel(level); + + columnSizes.add(k, nci); + records.add((1 + getDimsLoc() - columnSizes.size()) + k, nci); + dimsloc++; + } + this.collapseColumnLevel(level, column, collapsed); + } + + /** + * @author Dragos Buleandra + * Collapsing/expanding columns is more complex than grouping & outlining rows . + * This is a very strange Excel mechanism : + * The general rule used by Excel to collapse a column , is : + * 1) first it sets the column's hidden flag to true + * 2) if this ColumnInfo record is followed by another one , than Excel sets + * it's collapsed flag to true . If this ColumnInfo record isn't followed by + * another one , Excel creates a new ColumnInfo record and set its' collapsed + * flag to true . + * In other words , the collapsed flag of a ColumnInfo record isn't used to indicate + * that this column should be collapsed ; instead it is used to indicate that the previous + * column should be collapsed . + * @param level The level which should be collapsed ; there can be different columns ranges + * which belongs to the same level ( eg. columns A,B,C whith level 1 , + * columns G,H to same level 1 ) . To collapse only the desired range , the second + * parameter is needed + * @param column The column that should be collapsed ( if there are many columns which belongs + * to the same group , all of them will suffer the same modification ) + * @param collapsed True if this level should be collapsed , false otherwise + */ + protected void collapseColumnLevel( short level, short column, boolean collapsed ) + { + if ( (columnSizes == null) || (columnSizes.size() == 0) ) + { + return; + } + /** Here we should loop through all ColInfo records to find all ColInfo records which belongs + * to desired level and , of course , which contains the desired column ; + * The second solution is a for in for : in main loop we'll search for level + * and if a ColInfo with the same level is founded , begin the second loop to search + * for the column ; this second lopp will end when the column is founded or when a + * different level is founded ( we ignore upper non-zero levels , though ) or , + * of course, when we reach the end of the collection + * ( this second solution seems to be more optimized ) + */ + int start_pos = -1 ; + int end_pos = -1 ; + boolean founded = false; + for (int k = 0; k < columnSizes.size(); k++) + { + ColumnInfoRecord currCInfo_1 = ( ColumnInfoRecord ) columnSizes.get(k); + if ( currCInfo_1.getOutlineLevel() == level ) + { + start_pos = k; + //we start from the founded index , 'cause we should check + //it's range of columns + for ( int j = k; j level ) ) + { + break; + } + } + if ( founded ) + { + break; + } + } + if ( !founded ) + { + return; + } + //ok , now we have the range of ColInfo records + int iter = 0; + for ( int k=start_pos; k<=end_pos; k++ ) + { + ColumnInfoRecord currCInfo_1 = ( ColumnInfoRecord )columnSizes.get(k); + currCInfo_1.setHidden(collapsed); + if ( iter/2 != 0 ) + { + //this ColInfo should be modified + currCInfo_1.setCollapsed( collapsed ); + } + iter++; + } + if ( columnSizes.size()-1 == end_pos ) + { + if ( collapsed ) + { + ColumnInfoRecord nci = (ColumnInfoRecord) createColInfo(); + short col = (short) ( ( (ColumnInfoRecord) columnSizes.get(end_pos)).getLastColumn() + 1); + nci.setFirstColumn(col); + nci.setLastColumn(col); + nci.setCollapsed( collapsed ); + columnSizes.add(nci); + records.add( (1 + getDimsLoc() - columnSizes.size()) + end_pos, nci); + dimsloc++; + } + } + else + { + ColumnInfoRecord nci = ( ColumnInfoRecord )columnSizes.get(end_pos); + nci.setCollapsed( collapsed ); + } + } + + /** * creates the Dimensions Record and sets it to bogus values (you should set this yourself * or let the high level API do it for you) @@ -2061,7 +2303,7 @@ retval.setNumRefs(( short ) 0x0); return retval; } - + /** * Returns the active row * @@ -2076,7 +2318,7 @@ } return selection.getActiveCellRow(); } - + /** * Sets the active row * @@ -2091,7 +2333,7 @@ selection.setActiveCellRow(row); } } - + /** * Returns the active column * @@ -2106,7 +2348,7 @@ } return selection.getActiveCellCol(); } - + /** * Sets the active column * @@ -2652,15 +2894,15 @@ * @param breaks The page record to be shifted * @param start Starting "main" value to shift breaks * @param stop Ending "main" value to shift breaks - * @param count number of units (rows/columns) to shift by + * @param count number of units (rows/columns) to shift by */ public void shiftBreaks(PageBreakRecord breaks, short start, short stop, int count) { - + if(rowBreaks == null) return; Iterator iterator = breaks.getBreaksIterator(); List shiftedBreak = new ArrayList(); - while(iterator.hasNext()) + while(iterator.hasNext()) { PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); short breakLocation = breakItem.main; @@ -2669,20 +2911,20 @@ if(inStart && inEnd) shiftedBreak.add(breakItem); } - + iterator = shiftedBreak.iterator(); - while (iterator.hasNext()) { + while (iterator.hasNext()) { PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); breaks.removeBreak(breakItem.main); breaks.addBreak((short)(breakItem.main+count), breakItem.subFrom, breakItem.subTo); } } - + /** * Sets a page break at the indicated row * @param row */ - public void setRowBreak(int row, short fromCol, short toCol) { + public void setRowBreak(int row, short fromCol, short toCol) { rowBreaks.addBreak((short)row, fromCol, toCol); } @@ -2707,7 +2949,7 @@ * Sets a page break at the indicated column * @param row */ - public void setColumnBreak(short column, short fromRow, short toRow) { + public void setColumnBreak(short column, short fromRow, short toRow) { colBreaks.addBreak(column, fromRow, toRow); } @@ -2727,7 +2969,7 @@ public boolean isColumnBroken(short column) { return colBreaks.getBreak(column) != null; } - + /** * Shifts the horizontal page breaks for the indicated count * @param startingRow @@ -2747,7 +2989,7 @@ public void shiftColumnBreaks(short startingCol, short endingCol, short count) { shiftBreaks(colBreaks, startingCol, endingCol, count); } - + /** * Returns all the row page breaks * @return @@ -2755,7 +2997,7 @@ public Iterator getRowBreaks() { return rowBreaks.getBreaksIterator(); } - + /** * Returns the number of row page breaks * @return @@ -2763,7 +3005,7 @@ public int getNumRowBreaks(){ return (int)rowBreaks.getNumBreaks(); } - + /** * Returns all the column page breaks * @return @@ -2771,7 +3013,7 @@ public Iterator getColumnBreaks(){ return colBreaks.getBreaksIterator(); } - + /** * Returns the number of column page breaks * @return Index: src/java/org/apache/poi/hssf/model/Workbook.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/model/Workbook.java,v retrieving revision 1.29.2.8 diff -u -r1.29.2.8 Workbook.java --- src/java/org/apache/poi/hssf/model/Workbook.java 22 Feb 2004 11:54:46 -0000 1.29.2.8 +++ src/java/org/apache/poi/hssf/model/Workbook.java 8 Mar 2004 08:47:45 -0000 @@ -51,6 +51,9 @@ * @author Luc Girardin (luc dot girardin at macrofocus dot com) * @author Dan Sherman (dsherman at isisph.com) * @author Brian Sanders (bsanders at risklabs dot com) - custom palette + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) Fixed some bugs when cloning/removing sheets ; + * Methods for updating ExternSheet and SupBook records when adding/removing sheets + * Methods for hidding sheets ( normal hide and strong hide ) * @see org.apache.poi.hssf.usermodel.HSSFWorkbook * @version 1.0-pre */ @@ -85,6 +88,12 @@ protected ExternSheetRecord externSheet= null; /** + * @Author : Dragos Buleandra + * Holds the Supbook record ( needed when cloning sheets ) + */ + protected SupBookRecord supBook= null; + + /** * holds the "boundsheet" records (aka bundlesheet) so that they can have their * reference to their "BOF" marker */ @@ -125,13 +134,13 @@ log.log(DEBUG, "Workbook (readfile) created with reclen=", new Integer(recs.size())); Workbook retval = new Workbook(); - ArrayList records = new ArrayList(recs.size() / 3); + //ArrayList records = new ArrayList(recs.size() / 3); for (int k = 0; k < recs.size(); k++) { Record rec = ( Record ) recs.get(k); if (rec.getSid() == EOFRecord.sid) { - records.add(rec); + retval.records.add(rec); log.log(DEBUG, "found workbook eof record at " + k); break; } @@ -177,6 +186,9 @@ case ExternSheetRecord.sid : log.log(DEBUG, "found extern sheet record at " + k); retval.externSheet = ( ExternSheetRecord ) rec; + //Dragos Buleandra + retval.records.setExternsheetPos(k); + //<-Dragos Buleandra break; case NameRecord.sid : log.log(DEBUG, "found name record at " + k); @@ -184,13 +196,16 @@ // retval.records.namepos = k; break; case SupBookRecord.sid : + // Dragos Buleandra -> log.log(DEBUG, "found SupBook record at " + k); -// retval.records.supbookpos = k; + retval.supBook = (SupBookRecord) rec; + retval.records.setSupbookpos(k); + //<- Dragos Buleandra break; case FormatRecord.sid : - log.log(DEBUG, "found format record at " + k); - retval.formats.add(rec); - retval.maxformatid = retval.maxformatid >= ((FormatRecord)rec).getIndexCode() ? retval.maxformatid : ((FormatRecord)rec).getIndexCode(); + log.log(DEBUG, "found format record at " + k); + retval.formats.add(rec); + retval.maxformatid = retval.maxformatid >= ((FormatRecord)rec).getIndexCode() ? retval.maxformatid : ((FormatRecord)rec).getIndexCode(); break; case DateWindow1904Record.sid : log.log(DEBUG, "found datewindow1904 record at " + k); @@ -201,7 +216,7 @@ retval.records.setPalettepos( k ); default : } - records.add(rec); + retval.records.add(rec); } //What if we dont have any ranges and supbooks // if (retval.records.supbookpos == 0) { @@ -209,7 +224,7 @@ // retval.records.namepos = retval.records.supbookpos + 1; // } - retval.records.setRecords(records); + //retval.records.setRecords(records); log.log(DEBUG, "exit create workbook from existing file function"); return retval; } @@ -222,38 +237,38 @@ { log.log( DEBUG, "creating new workbook from scratch" ); Workbook retval = new Workbook(); - ArrayList records = new ArrayList( 30 ); + //ArrayList records = new ArrayList( 30 ); ArrayList formats = new ArrayList( 8 ); - records.add( retval.createBOF() ); - records.add( retval.createInterfaceHdr() ); - records.add( retval.createMMS() ); - records.add( retval.createInterfaceEnd() ); - records.add( retval.createWriteAccess() ); - records.add( retval.createCodepage() ); - records.add( retval.createDSF() ); - records.add( retval.createTabId() ); - retval.records.setTabpos( records.size() - 1 ); - records.add( retval.createFnGroupCount() ); - records.add( retval.createWindowProtect() ); - records.add( retval.createProtect() ); - retval.records.setProtpos( records.size() - 1 ); - records.add( retval.createPassword() ); - records.add( retval.createProtectionRev4() ); - records.add( retval.createPasswordRev4() ); - records.add( retval.createWindowOne() ); - records.add( retval.createBackup() ); - retval.records.setBackuppos( records.size() - 1 ); - records.add( retval.createHideObj() ); - records.add( retval.createDateWindow1904() ); - records.add( retval.createPrecision() ); - records.add( retval.createRefreshAll() ); - records.add( retval.createBookBool() ); - records.add( retval.createFont() ); - records.add( retval.createFont() ); - records.add( retval.createFont() ); - records.add( retval.createFont() ); - retval.records.setFontpos( records.size() - 1 ); // last font record postion + retval.records.add( retval.createBOF() ); + retval.records.add( retval.createInterfaceHdr() ); + retval.records.add( retval.createMMS() ); + retval.records.add( retval.createInterfaceEnd() ); + retval.records.add( retval.createWriteAccess() ); + retval.records.add( retval.createCodepage() ); + retval.records.add( retval.createDSF() ); + retval.records.add( retval.createTabId() ); + retval.records.setTabpos( retval.records.size() - 1 ); + retval.records.add( retval.createFnGroupCount() ); + retval.records.add( retval.createWindowProtect() ); + retval.records.add( retval.createProtect() ); + retval.records.setProtpos( retval.records.size() - 1 ); + retval.records.add( retval.createPassword() ); + retval.records.add( retval.createProtectionRev4() ); + retval.records.add( retval.createPasswordRev4() ); + retval.records.add( retval.createWindowOne() ); + retval.records.add( retval.createBackup() ); + retval.records.setBackuppos( retval.records.size() - 1 ); + retval.records.add( retval.createHideObj() ); + retval.records.add( retval.createDateWindow1904() ); + retval.records.add( retval.createPrecision() ); + retval.records.add( retval.createRefreshAll() ); + retval.records.add( retval.createBookBool() ); + retval.records.add( retval.createFont() ); + retval.records.add( retval.createFont() ); + retval.records.add( retval.createFont() ); + retval.records.add( retval.createFont() ); + retval.records.setFontpos( retval.records.size() - 1 ); // last font record postion retval.numfonts = 4; // set up format records @@ -263,39 +278,44 @@ rec = retval.createFormat( i ); retval.maxformatid = retval.maxformatid >= ( (FormatRecord) rec ).getIndexCode() ? retval.maxformatid : ( (FormatRecord) rec ).getIndexCode(); formats.add( rec ); - records.add( rec ); + retval.records.add( rec ); } retval.formats = formats; for ( int k = 0; k < 21; k++ ) { - records.add( retval.createExtendedFormat( k ) ); + retval.records.add( retval.createExtendedFormat( k ) ); retval.numxfs++; } - retval.records.setXfpos( records.size() - 1 ); + retval.records.setXfpos( retval.records.size() - 1 ); for ( int k = 0; k < 6; k++ ) { - records.add( retval.createStyle( k ) ); + retval.records.add( retval.createStyle( k ) ); } - records.add( retval.createUseSelFS() ); + retval.records.add( retval.createUseSelFS() ); for ( int k = 0; k < 1; k++ ) { // now just do 1 - BoundSheetRecord bsr = - (BoundSheetRecord) retval.createBoundSheet( k ); + BoundSheetRecord bsr = (BoundSheetRecord) retval.createBoundSheet( k ); - records.add( bsr ); + retval.records.add( bsr ); retval.boundsheets.add( bsr ); - retval.records.setBspos( records.size() - 1 ); + retval.records.setBspos( retval.records.size() - 1 ); } // retval.records.supbookpos = retval.records.bspos + 1; // retval.records.namepos = retval.records.supbookpos + 2; - records.add( retval.createCountry() ); + retval.records.add( retval.createCountry() ); + + //Dragos Buleandra + retval.supBook = retval.createSupBookRecord(); + retval.externSheet = retval.createExternSheet(); + //<-Dragos Buleandra + retval.sst = (SSTRecord) retval.createSST(); - records.add( retval.sst ); - records.add( retval.createExtendedSST() ); + retval.records.add( retval.sst ); + retval.records.add( retval.createExtendedSST() ); - records.add( retval.createEOF() ); - retval.records.setRecords(records); + retval.records.add( retval.createEOF() ); + //retval.records.setRecords(records); log.log( DEBUG, "exit create new workbook from scratch" ); return retval; } @@ -312,15 +332,15 @@ Iterator iterator = names.iterator(); while (iterator.hasNext()) { NameRecord record = ( NameRecord ) iterator.next(); - + //print areas are one based if (record.getBuiltInName() == name && record.getIndexToSheet() == sheetIndex) { return record; } } - + return null; - + } /** @@ -335,7 +355,7 @@ if (record != null) { names.remove(record); } - + } public int getNumRecords() { @@ -440,18 +460,18 @@ sheet.setSheetnameLength( (byte)sheetname.length() ); sheet.setCompressedUnicodeFlag( (byte)encoding ); } - + /** * sets the order of appearance for a given sheet. * * @param sheetname the name of the sheet to reorder * @param pos the position that we want to insert the sheet into (0 based) */ - + public void setSheetOrder(String sheetname, int pos ) { int sheetNumber = getSheetIndex(sheetname); //remove the sheet that needs to be reordered and place it in the spot we want - boundsheets.add(pos, boundsheets.remove(sheetNumber)); + boundsheets.add(pos, boundsheets.remove(sheetNumber)); } /** @@ -487,6 +507,46 @@ } /** + * @author Dragos Buleandra + * Hide/Unhide a sheet + * @param sheetnum Sheet's index + * @param hide True to hide the sheet , false to make it visible + * @param strong_hide True if the sheet should be string hidden ( can't be unhidden form Excel user interface ) + */ + public void hideSheet(int sheetnum, boolean hide, boolean strong_hide ) + { + BoundSheetRecord boundSheetRec = ( BoundSheetRecord )boundsheets.get(sheetnum); + + if ( ! hide ) //make it visible + { + boundSheetRec.setHidden(false); + } + else + { + if ( strong_hide ) // make it strong hidden + { + boundSheetRec.setStrongHidden(true); + } + else //make it hidden , only + { + boundSheetRec.setHidden(true); + } + } + } + + /** + * @author Dragos Buleandra + * Hide/Unhide a sheet + * @param sheetname Sheet's name + * @param hide True to hide the sheet , false to make it visible + * @param strong_hide True if the sheet should be string hidden ( can't be unhidden form Excel user interface ) + */ + public void hideSheet(String sheetname, boolean hide, boolean strong_hide ) + { + this.hideSheet( this.getSheetIndex(sheetname), hide, strong_hide ); + } + + /** * if we're trying to address one more sheet than we have, go ahead and add it! if we're * trying to address >1 more than we have throw an exception! */ @@ -502,6 +562,10 @@ records.setBspos( records.getBspos() + 1 ); boundsheets.add(bsr); fixTabIdRecord(); + //Dragos Buleandra : refresh supbook and externSheet records + fixSupBookRecord(); + checkExternSheet(sheetnum); + //<- Dragos Buleandra } } @@ -511,19 +575,40 @@ // records.bspos--; boundsheets.remove(sheetnum); fixTabIdRecord(); + //Dragos Buleandra : refresh supbook and externSheet records + fixSupBookRecord(); + checkExternSheet(sheetnum); + //we also should check if a name record should also be deleted + if ( this.getNameRecordForSheet((short)sheetnum) != null ) + { + this.removeName(sheetnum); + } + //<- Dragos Buleandra } } /** + * @author Dragos Buleandra + * make SupBook record look like the current situation. + */ + private void fixSupBookRecord() + { + SupBookRecord supbook = (SupBookRecord) records.get(records.getSupbookpos()); + supbook.setNumberOfSheets((short)boundsheets.size()); + } + + /** * make the tabid record look like the current situation. - * + * Dragos Buleandra - fixed sheet's index bug in TabIdRecord - this field is one-based , not zero-based */ private void fixTabIdRecord() { TabIdRecord tir = ( TabIdRecord ) records.get(records.getTabpos()); short[] tia = new short[ boundsheets.size() ]; for (short k = 0; k < tia.length; k++) { - tia[ k ] = k; + // Dragos Buleandra : fix -> in TABID record sheet's index are one-based , not zero-based + //tia[ k ] = k; + tia[ k ] = (short)(k+(short)1); } tir.setTabIdArray(tia); } @@ -1574,7 +1659,7 @@ { return new PaletteRecord(PaletteRecord.sid); } - + /** * Creates the UseSelFS object with the use natural language flag set to 0 (false) * @return record containing a UseSelFSRecord @@ -1695,13 +1780,13 @@ public SheetReferences getSheetReferences() { SheetReferences refs = new SheetReferences(); - + if (externSheet != null) { for (int k = 0; k < externSheet.getNumOfREFStructures(); k++) { - + String sheetName = findSheetNameFromExternSheet((short)k); refs.addSheetReference(sheetName, k); - + } } return refs; @@ -1767,10 +1852,29 @@ if (!flag) { result = addSheetIndexToExternSheet((short) sheetNumber); } - + else + { + //Dragos Buleandra + //check if this sheet reference should be removed + removeSheetIndexFromExternSheet((short) sheetNumber); + } return result; } + /** + * @author Dragos Buleandra + * @param sheetNumber + */ + private void removeSheetIndexFromExternSheet( short sheetNumber ) + { + short sheetsNo = (short) boundsheets.size(); + if ( sheetsNo <= sheetNumber+1) + { + externSheet.setNumOfREFStructures((short)(externSheet.getNumOfREFStructures() - 1)); + externSheet.removeREFRecord(); + } + } + private short addSheetIndexToExternSheet(short sheetNumber){ short result; @@ -1784,6 +1888,31 @@ return result; } + /** + * @author Dragos Buleandra + * Check if a sheet is involved in a Name record + * @param sheetNumber Zero-based sheet number + * @return + */ + public NameRecord getNameRecordForSheet( short sheetNumber ) + { + NameRecord nameRecord = null; + short oneBased_sheetNumber = (short)(sheetNumber+1); + if ( this.names == null || this.names.size() == 0 ) + { + return null; + } + for ( int i=0; i (int)Short.MAX_VALUE) + if (index == -1 || index+1 > (int)Short.MAX_VALUE) throw new IllegalArgumentException("Index is not valid ["+index+"]"); - + NameRecord name = new NameRecord(builtInName, (short)(index)); - + addName(name); - + return name; } @@ -1864,31 +1993,82 @@ int idx = findFirstRecordLocBySid(NameRecord.sid); records.remove(idx + namenum); names.remove(namenum); + //Dragos Buleandra - we should update sheetIndex field for remaining name records + for ( int i=namenum; i= pos) setExternsheetPos(getExternsheetPos() + 1); } + /** + * @author Dragos Buleandra + * @param r + */ + public void add ( Record r ) + { + records.add(r); + } + public List getRecords() { return records; @@ -164,7 +173,7 @@ this.palettepos = palettepos; } - + /** * Returns the namepos. * @return int Index: src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/Attic/AbstractEscherHolderRecord.java,v retrieving revision 1.1.2.2 diff -u -r1.1.2.2 AbstractEscherHolderRecord.java --- src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java 22 Feb 2004 11:54:47 -0000 1.1.2.2 +++ src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java 8 Mar 2004 08:47:45 -0000 @@ -32,6 +32,7 @@ * must be subclassed for maximum benefit. * * @author Glen Stampoultzis (glens at apache.org) + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) Fixed bug when this record isn't deserialized */ public abstract class AbstractEscherHolderRecord extends Record @@ -59,7 +60,7 @@ public AbstractEscherHolderRecord(short id, short size, byte [] data) { super(id, size, data); - + } /** @@ -75,7 +76,7 @@ public AbstractEscherHolderRecord(short id, short size, byte [] data, int offset) { super(id, size, data, offset); - + } /** @@ -135,8 +136,13 @@ { if (escherRecords.size() == 0 && rawData != null) { - System.arraycopy( rawData, 0, data, offset, rawData.length); - return rawData.length; + //Dragos Buleandra - ok , it isn't deserialized , but sid and length field should + // be added in output data array + LittleEndian.putShort(data, 0 + offset, getSid()); + LittleEndian.putShort(data, 2 + offset, (short)(rawData.length)); + //System.arraycopy( rawData, 0, data, offset, rawData.length); + System.arraycopy( rawData, 0, data, 4 + offset, rawData.length); + return getRecordSize(); } else { @@ -163,7 +169,9 @@ { if (escherRecords.size() == 0 && rawData != null) { - return rawData.length; + //Dragos Buleandra - what about sid and length field ?! + //return rawData.length; + return rawData.length+4; } else { Index: src/java/org/apache/poi/hssf/record/BoundSheetRecord.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/BoundSheetRecord.java,v retrieving revision 1.8.2.2 diff -u -r1.8.2.2 BoundSheetRecord.java --- src/java/org/apache/poi/hssf/record/BoundSheetRecord.java 22 Feb 2004 11:54:47 -0000 1.8.2.2 +++ src/java/org/apache/poi/hssf/record/BoundSheetRecord.java 8 Mar 2004 08:47:46 -0000 @@ -14,13 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - + package org.apache.poi.hssf.record; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.StringUtil; +import org.apache.poi.util.BitField; + /** * Title: Bound Sheet Record (aka BundleSheet)

* Description: Defines a sheet within a workbook. Basically stores the sheetname @@ -29,6 +31,7 @@ * REFERENCE: PG 291 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) * @author Sergei Kozello (sergeikozello at mail.ru) + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) Added support for modifying sheet's visibility and type * @version 2.0-pre */ @@ -42,6 +45,27 @@ private byte field_4_compressed_unicode_flag; // not documented private String field_5_sheetname; + /** + * Dragos Buleandra + * Description : added support for modifying sheet's visibility and type + * field_2_option_flags - compund from following optioon flags : + * - ---------------------------------------------- + * | Bits Mask Contents + * - ---------------------------------------------- + * 0-1 0003 Visibility - 00 = Visible + * 01 = Hidden , but the sheet can be unhidden + * via Excel user interface + * ( Format->Sheet->Unhide... menu) + * 02 = Strong hidden , but it's not possible anymore + * to make visible such a sheet via + * Excel user interface , only via a VBA macro + * 15-8 FF00 Sheet type - 00 = Worksheet + * 02 = Chart + * 06 = VBA module + */ + private BitField _sheet_visibility = new BitField(0x0003); + private BitField _sheet_type = new BitField(0xFF00); + public BoundSheetRecord() { } @@ -133,6 +157,30 @@ } /** + * Dragos Buleandra + * set the option flag for making a sheet visible/hidden + * @param hidden + */ + public void setHidden( boolean hidden ) + { + short value = (hidden) ? (short)0x0001 : (short)0x0000 ; + this.field_2_option_flags = this._sheet_visibility.setShortValue(this.field_2_option_flags, value); + } + + /** + * Dragos Buleandra + * set the option flag for making a sheet strong hidden + * @param hidden + */ + public void setStrongHidden( boolean strong_hidden ) + { + if ( strong_hidden ) + { + this.field_2_option_flags = this._sheet_visibility.setShortValue(this.field_2_option_flags, (short)0x0002); + } + } + + /** * Set the length of the sheetname in characters * * @param len number of characters in the sheet name @@ -158,12 +206,12 @@ /** * Set the sheetname for this sheet. (this appears in the tabs at the bottom) * @param sheetname the name of the sheet - * @thows IllegalArgumentException if sheet name will cause excel to crash. + * @thows IllegalArgumentException if sheet name will cause excel to crash. */ public void setSheetname( String sheetname ) { - + if ((sheetname == null) || (sheetname.length()==0) || (sheetname.length()>31) || (sheetname.indexOf("/") > -1) Index: src/java/org/apache/poi/hssf/record/DrawingRecord.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/Attic/DrawingRecord.java,v retrieving revision 1.1.2.2 diff -u -r1.1.2.2 DrawingRecord.java --- src/java/org/apache/poi/hssf/record/DrawingRecord.java 22 Feb 2004 11:54:47 -0000 1.1.2.2 +++ src/java/org/apache/poi/hssf/record/DrawingRecord.java 8 Mar 2004 08:47:46 -0000 @@ -109,4 +109,15 @@ this.recordData = thedata; } + /** + * @author Dragos Buleandra + * @return + */ + public Object clone() + { + DrawingRecord rec = new DrawingRecord(); + rec.recordData = recordData; + return rec; + } + } Index: src/java/org/apache/poi/hssf/record/ExternSheetRecord.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java,v retrieving revision 1.4.2.2 diff -u -r1.4.2.2 ExternSheetRecord.java --- src/java/org/apache/poi/hssf/record/ExternSheetRecord.java 22 Feb 2004 11:54:47 -0000 1.4.2.2 +++ src/java/org/apache/poi/hssf/record/ExternSheetRecord.java 8 Mar 2004 08:47:46 -0000 @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - + package org.apache.poi.hssf.record; @@ -27,6 +27,7 @@ * Description: A List of Inndexes to SupBook

* REFERENCE:

* @author Libin Roman (Vista Portal LDT. Developer) + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) * @version 1.0-pre */ @@ -34,11 +35,11 @@ public final static short sid = 0x17; private short field_1_number_of_REF_sturcutres; private ArrayList field_2_REF_structures; - + public ExternSheetRecord() { field_2_REF_structures = new ArrayList(); } - + /** * Constructs a Extern Sheet record and sets its fields appropriately. * @@ -46,11 +47,11 @@ * @param size the size of the data area of the record * @param data data of the record (should not contain sid/len) */ - + public ExternSheetRecord(short id, short size, byte[] data) { super(id, size, data); } - + /** * Constructs a Extern Sheet record and sets its fields appropriately. * @@ -62,7 +63,7 @@ public ExternSheetRecord(short id, short size, byte[] data, int offset) { super(id, size, data, offset); } - + /** * called by constructor, should throw runtime exception in the event of a * record passed with a differing ID. @@ -74,7 +75,7 @@ throw new RecordFormatException("NOT An ExternSheet RECORD"); } } - + /** * called by the constructor, should set class level fields. Should throw * runtime exception for bad/icomplete data. @@ -85,63 +86,71 @@ */ protected void fillFields(byte [] data, short size, int offset) { field_2_REF_structures = new ArrayList(); - + field_1_number_of_REF_sturcutres = LittleEndian.getShort(data, 0 + offset); - + int pos = 2 + offset; for (int i = 0 ; i < field_1_number_of_REF_sturcutres ; ++i) { ExternSheetSubRecord rec = new ExternSheetSubRecord((short)0, (short)6 , data , pos); - + pos += 6; - + field_2_REF_structures.add( rec); } } - - /** + + /** * sets the number of the REF structors , that is in Excel file * @param numStruct number of REF structs */ public void setNumOfREFStructures(short numStruct) { field_1_number_of_REF_sturcutres = numStruct; } - - /** + + /** * return the number of the REF structors , that is in Excel file * @return number of REF structs */ public short getNumOfREFStructures() { return field_1_number_of_REF_sturcutres; } - - /** + + /** * adds REF struct (ExternSheetSubRecord) * @param rec REF struct */ public void addREFRecord(ExternSheetSubRecord rec) { field_2_REF_structures.add(rec); } - + + /** + * @author Dragos Buleandra + */ + public void removeREFRecord() + { + field_2_REF_structures.remove(field_2_REF_structures.size()-1); + } + /** returns the number of REF Records, which is in model * @return number of REF records */ public int getNumOfREFRecords() { return field_2_REF_structures.size(); } - + /** returns the REF record (ExternSheetSubRecord) * @param elem index to place * @return REF record */ public ExternSheetSubRecord getREFRecordAt(int elem) { ExternSheetSubRecord result = ( ExternSheetSubRecord ) field_2_REF_structures.get(elem); - + return result; } - + public String toString() { StringBuffer buffer = new StringBuffer(); - + buffer.append("[EXTERNSHEET]\n"); buffer.append(" numOfRefs = ").append(getNumOfREFStructures()).append("\n"); for (int k=0; k < this.getNumOfREFRecords(); k++) { @@ -150,11 +159,11 @@ buffer.append("----refrec #").append(k).append('\n'); } buffer.append("[/EXTERNSHEET]\n"); - - + + return buffer.toString(); } - + /** * called by the class that is responsible for writing this sucker. * Subclasses should implement this so that their data is passed back in a @@ -167,24 +176,24 @@ public int serialize(int offset, byte [] data) { LittleEndian.putShort(data, 0 + offset, sid); LittleEndian.putShort(data, 2 + offset,(short)(2 + (getNumOfREFRecords() *6))); - + LittleEndian.putShort(data, 4 + offset, getNumOfREFStructures()); - + int pos = 6 ; - + for (int k = 0; k < getNumOfREFRecords(); k++) { ExternSheetSubRecord record = getREFRecordAt(k); System.arraycopy(record.serialize(), 0, data, pos + offset, 6); - + pos +=6; } return getRecordSize(); } - + public int getRecordSize() { return 4 + 2 + getNumOfREFRecords() * 6; } - + /** * return the non static version of the id for this record. */ Index: src/java/org/apache/poi/hssf/record/NameRecord.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/NameRecord.java,v retrieving revision 1.12.2.3 diff -u -r1.12.2.3 NameRecord.java --- src/java/org/apache/poi/hssf/record/NameRecord.java 22 Feb 2004 11:54:47 -0000 1.12.2.3 +++ src/java/org/apache/poi/hssf/record/NameRecord.java 8 Mar 2004 08:47:47 -0000 @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - + package org.apache.poi.hssf.record; @@ -37,6 +37,7 @@ * @author Libin Roman (Vista Portal LDT. Developer) * @author Sergei Kozello (sergeikozello at mail.ru) * @author Glen Stampoultzis (glens at apache.org) + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) Added support for Autofiltering * @version 1.0-pre */ @@ -44,11 +45,11 @@ /** */ public final static short sid = 0x18; //Docs says that it is 0x218 - + /**Included for completeness sake, not implemented */ public final static byte BUILTIN_CONSOLIDATE_AREA = (byte)1; - + /**Included for completeness sake, not implemented */ public final static byte BUILTIN_AUTO_OPEN = (byte)2; @@ -64,32 +65,35 @@ /**Included for completeness sake, not implemented */ public final static byte BUILTIN_CRITERIA = (byte)5; - + public final static byte BUILTIN_PRINT_AREA = (byte)6; public final static byte BUILTIN_PRINT_TITLE = (byte)7; - + /**Included for completeness sake, not implemented */ public final static byte BUILTIN_RECORDER = (byte)8; - + /**Included for completeness sake, not implemented */ public final static byte BUILTIN_DATA_FORM = (byte)9; - + /**Included for completeness sake, not implemented */ public final static byte BUILTIN_AUTO_ACTIVATE = (byte)10; - + /**Included for completeness sake, not implemented */ public final static byte BUILTIN_AUTO_DEACTIVATE = (byte)11; - + /**Included for completeness sake, not implemented */ public final static byte BUILTIN_SHEET_TITLE = (byte)12; - + + //Dragos Buleandra + public final static byte BUILTIN_AUTOFILTER = (byte)13; + public static final short OPT_HIDDEN_NAME = (short) 0x0001; public static final short OPT_FUNCTION_NAME = (short) 0x0002; public static final short OPT_COMMAND_NAME = (short) 0x0004; @@ -98,7 +102,7 @@ public static final short OPT_BUILTIN = (short) 0x0020; public static final short OPT_BINDATA = (short) 0x1000; - + private short field_1_option_flag; private byte field_2_keyboard_shortcut; private byte field_3_length_name_text; @@ -157,23 +161,23 @@ /** * Constructor to create a built-in named region * @param builtin Built-in byte representation for the name record, use the public constants - * @param index + * @param index */ public NameRecord(byte builtin, short index) { - this(); + this(); this.field_12_builtIn_name = builtin; this.setOptionFlag((short)(this.getOptionFlag() | OPT_BUILTIN)); this.setNameTextLength((byte)1); this.setEqualsToIndexToSheet(index); //the extern sheets are set through references - + //clearing these because they are not used with builtin records this.setCustomMenuLength((byte)0); this.setDescriptionTextLength((byte)0); this.setHelpTopicLength((byte)0); this.setStatusBarLength((byte)0); - + } /** sets the option flag for the named range @@ -539,7 +543,7 @@ else { */ LittleEndian.putShort( data, 2 + offset, (short) ( 15 + getTextsLength() ) ); - + int start_of_name_definition = 19 + field_3_length_name_text; if (this.isBuiltInName()) { @@ -547,7 +551,7 @@ data [19 + offset] = this.getBuiltInName(); } else { StringUtil.putCompressedUnicode( getNameText(), data, 19 + offset ); - + } @@ -559,7 +563,7 @@ { System.arraycopy( field_13_raw_name_definition, 0, data , start_of_name_definition + offset, field_13_raw_name_definition.length ); - } + } int start_of_custom_menu_text = start_of_name_definition + field_4_length_name_definition; @@ -678,6 +682,34 @@ return result; } + /** + * @author Dragos Buleandra + * Return the Ptg token from this NameRecord's field_13_name_definition field + */ + public Ptg getRPN_Token() + { + if (field_13_name_definition == null) return null; + Ptg ptg = (Ptg) field_13_name_definition.peek(); + return ptg; + } + + /** + * @author Dragos Buleandra + * Set sheet index reference ( zero-based ) + * NOTE ! This method is implemented only for Area3D RPN token + * + * @param zeroBasedSheetNo + */ + public void setPTGTokenExternSheetIndex( short zeroBasedSheetNo ) + { + /** @todo Extend implementation for others RPN tokens */ + Ptg RPNToken = getRPN_Token(); + if (RPNToken.getClass() == Area3DPtg.class) + { + ((Area3DPtg)RPNToken).setExternSheetIndex(zeroBasedSheetNo); + } + } + /** sets the reference , the area only (range) * @param ref area reference */ @@ -739,7 +771,7 @@ field_8_length_description_text = data [11 + offset]; field_9_length_help_topic_text = data [12 + offset]; field_10_length_status_bar_text = data [13 + offset]; - + /* temp: gjs @@ -764,34 +796,34 @@ } } else { */ - + field_11_compressed_unicode_flag= data [14 + offset]; - - + + //store the name in byte form if it's a builtin name if (this.isBuiltInName()) { field_12_builtIn_name = data[ 15 + offset ]; } - + field_12_name_text = StringUtil.getFromCompressedUnicode(data, 15 + offset, LittleEndian.ubyteToInt(field_3_length_name_text)); - + int start_of_name_definition = 15 + field_3_length_name_text; field_13_name_definition = getParsedExpressionTokens(data, field_4_length_name_definition, offset, start_of_name_definition); - + int start_of_custom_menu_text = start_of_name_definition + field_4_length_name_definition; field_14_custom_menu_text = StringUtil.getFromCompressedUnicode(data, start_of_custom_menu_text + offset, LittleEndian.ubyteToInt(field_7_length_custom_menu)); - + int start_of_description_text = start_of_custom_menu_text + field_7_length_custom_menu;; field_15_description_text = StringUtil.getFromCompressedUnicode(data, start_of_description_text + offset, LittleEndian.ubyteToInt(field_8_length_description_text)); - + int start_of_help_topic_text = start_of_description_text + field_8_length_description_text; field_16_help_topic_text = StringUtil.getFromCompressedUnicode(data, start_of_help_topic_text + offset, LittleEndian.ubyteToInt(field_9_length_help_topic_text)); - + int start_of_status_bar_text = start_of_help_topic_text + field_9_length_help_topic_text; field_17_status_bar_text = StringUtil.getFromCompressedUnicode(data, start_of_status_bar_text + offset, LittleEndian.ubyteToInt(field_10_length_status_bar_text)); @@ -831,54 +863,54 @@ return this.sid; } /* - 20 00 - 00 - 01 + 20 00 + 00 + 01 1A 00 // sz = 0x1A = 26 - 00 00 - 01 00 - 00 - 00 - 00 - 00 + 00 00 + 01 00 + 00 + 00 + 00 + 00 00 // unicode flag 07 // name - + 29 17 00 3B 00 00 00 00 FF FF 00 00 02 00 3B 00 //{ 26 00 07 00 07 00 00 00 FF 00 10 // } - - - - 20 00 - 00 - 01 + + + + 20 00 + 00 + 01 0B 00 // sz = 0xB = 11 - 00 00 - 01 00 - 00 - 00 - 00 - 00 + 00 00 + 01 00 + 00 + 00 + 00 + 00 00 // unicode flag 07 // name - + 3B 00 00 07 00 07 00 00 00 FF 00 // { 11 } */ /* - 18, 00, - 1B, 00, - - 20, 00, - 00, - 01, - 0B, 00, - 00, - 00, - 00, - 00, - 00, - 07, - 3B 00 00 07 00 07 00 00 00 FF 00 ] + 18, 00, + 1B, 00, + + 20, 00, + 00, + 01, + 0B, 00, + 00, + 00, + 00, + 00, + 00, + 07, + 3B 00 00 07 00 07 00 00 00 FF 00 ] */ /** @@ -912,10 +944,10 @@ .append("\n"); buffer.append(" .Name (Unicode text) = ").append( getNameText() ) .append("\n"); - buffer.append(" .Formula data (RPN token array without size field) = ").append( HexDump.toHex( + buffer.append(" .Formula data (RPN token array without size field) = ").append( HexDump.toHex( ((field_13_raw_name_definition != null) ? field_13_raw_name_definition : new byte[0] ) ) ) .append("\n"); - + buffer.append(" .Menu text (Unicode string without length field) = ").append( field_14_custom_menu_text ) .append("\n"); buffer.append(" .Description text (Unicode string without length field) = ").append( field_15_description_text ) @@ -926,7 +958,7 @@ .append("\n"); buffer.append(org.apache.poi.util.HexDump.dump(this.field_13_raw_name_definition,0,0)); buffer.append("[/NAME]\n"); - + return buffer.toString(); } @@ -944,16 +976,27 @@ case NameRecord.BUILTIN_CONSOLIDATE_AREA : return "Consolidate_Area"; case NameRecord.BUILTIN_CRITERIA : return "Criteria"; case NameRecord.BUILTIN_DATABASE : return "Database"; - case NameRecord.BUILTIN_DATA_FORM : return "Data_Form"; + case NameRecord.BUILTIN_DATA_FORM : return "Data_Form"; case NameRecord.BUILTIN_PRINT_AREA : return "Print_Area"; case NameRecord.BUILTIN_PRINT_TITLE : return "Print_Titles"; case NameRecord.BUILTIN_RECORDER : return "Recorder"; case NameRecord.BUILTIN_SHEET_TITLE : return "Sheet_Title"; - + case NameRecord.BUILTIN_AUTOFILTER : return "Auto_Filter"; //added by Dragos Buleandra } - + return "Unknown"; } - + /** + * @author Dragos Buleandra + * @return A clone object + */ + public Object clone() + { + byte[] sdata = this.serialize(); + byte[] data = new byte[sdata.length-4]; + System.arraycopy(sdata, 4, data, 0, data.length); + NameRecord rec = new NameRecord(NameRecord.sid, (short)(data.length), data); + return rec; + } } Index: src/java/org/apache/poi/hssf/record/ObjRecord.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/Attic/ObjRecord.java,v retrieving revision 1.1.2.2 diff -u -r1.1.2.2 ObjRecord.java --- src/java/org/apache/poi/hssf/record/ObjRecord.java 22 Feb 2004 11:54:47 -0000 1.1.2.2 +++ src/java/org/apache/poi/hssf/record/ObjRecord.java 8 Mar 2004 08:47:47 -0000 @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - + package org.apache.poi.hssf.record; @@ -31,6 +31,7 @@ * The obj record is used to hold various graphic objects and controls. * * @author Glen Stampoultzis (glens at apache.org) + * @author Dragos Buleandra ( dragos.buleandra@trade2b.ro ) */ public class ObjRecord extends Record @@ -96,7 +97,26 @@ { short subRecordSid = LittleEndian.getShort(data, pos); short subRecordSize = LittleEndian.getShort(data, pos + 2); - Record subRecord = SubRecord.createSubRecord(subRecordSid, subRecordSize, data, pos + 4); + //Draqos Buleandra + //here's a strange behaviour which I encountered on an Obj record + //involved in autofiltering : + //A subrecord with sid = 0x13 (List box data) has a strange length field ( huge value , + //greater than Obj record's length !?!?!?! ) which should be , theoretically , impossible + //since it's a subrecord af the Obj record , but for Excel XP ( at least ) , this isn't a problem ; + //it renders the autofilter without any problems + //So , to avoid such situations , when we encounter a record with such a greater length field, + //we'll read the rest of the Obj record as an UnknownRecord ( without EndSubRecord , of course, which + //always should be the last subrecord of an OBJ record ) + Record subRecord = null; + if ( (subRecordSize > size-4-(pos+4)) && (subRecordSid != EndSubRecord.sid) ) + { + subRecordSize = (short)(size-4-(pos+4)); + subRecord = new UnknownRecord(subRecordSid, subRecordSize, data, pos + 4); + } + else + { + subRecord = SubRecord.createSubRecord(subRecordSid, subRecordSize, data, pos + 4); + } subrecords.add(subRecord); pos += 4 + subRecordSize; } @@ -179,7 +199,14 @@ rec.subrecords = new ArrayList(); for ( Iterator iterator = subrecords.iterator(); iterator.hasNext(); ) - subrecords.add(( (Record) iterator.next() ).clone()); + { + //Dragos Buleandra - the following statement throws an java.util.ConcurrentModificationException + // because "subrecords" coleection of this Obj record is modified and iterated + // at the same time ; here we should clone this object , not modify it + // - just joking , I know that it's a rush mistaken -:) + //subrecords.add( ( (Record) iterator.next()).clone()); + rec.subrecords.add( ( (Record) iterator.next()).clone()); + } return rec; } Index: src/java/org/apache/poi/hssf/record/RecordFactory.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/RecordFactory.java,v retrieving revision 1.16.2.3 diff -u -r1.16.2.3 RecordFactory.java --- src/java/org/apache/poi/hssf/record/RecordFactory.java 22 Feb 2004 11:54:47 -0000 1.16.2.3 +++ src/java/org/apache/poi/hssf/record/RecordFactory.java 8 Mar 2004 08:47:48 -0000 @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - + package org.apache.poi.hssf.record; @@ -35,6 +35,7 @@ * @author Marc Johnson (mjohnson at apache dot org) * @author Glen Stampoultzis (glens at apache.org) * @author Csaba Nagy (ncsaba at yahoo dot com) + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) * @version 1.0-pre */ @@ -57,7 +58,7 @@ PrecisionRecord.class, RefreshAllRecord.class, BookBoolRecord.class, FontRecord.class, FormatRecord.class, ExtendedFormatRecord.class, StyleRecord.class, UseSelFSRecord.class, BoundSheetRecord.class, - CountryRecord.class, SSTRecord.class, ExtSSTRecord.class, + CountryRecord.class, SupBookRecord.class, SSTRecord.class, ExtSSTRecord.class, EOFRecord.class, IndexRecord.class, CalcModeRecord.class, CalcCountRecord.class, RefModeRecord.class, IterationRecord.class, DeltaRecord.class, SaveRecalcRecord.class, PrintHeadersRecord.class, @@ -91,7 +92,7 @@ PrecisionRecord.class, RefreshAllRecord.class, BookBoolRecord.class, FontRecord.class, FormatRecord.class, ExtendedFormatRecord.class, StyleRecord.class, UseSelFSRecord.class, BoundSheetRecord.class, - CountryRecord.class, SSTRecord.class, ExtSSTRecord.class, + CountryRecord.class, SupBookRecord.class, SSTRecord.class, ExtSSTRecord.class, EOFRecord.class, IndexRecord.class, CalcModeRecord.class, CalcCountRecord.class, RefModeRecord.class, IterationRecord.class, DeltaRecord.class, SaveRecalcRecord.class, PrintHeadersRecord.class, Index: src/java/org/apache/poi/hssf/record/RowRecord.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/RowRecord.java,v retrieving revision 1.7.2.1 diff -u -r1.7.2.1 RowRecord.java --- src/java/org/apache/poi/hssf/record/RowRecord.java 22 Feb 2004 11:54:47 -0000 1.7.2.1 +++ src/java/org/apache/poi/hssf/record/RowRecord.java 8 Mar 2004 08:47:49 -0000 @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - + package org.apache.poi.hssf.record; @@ -27,6 +27,7 @@ * REFERENCE: PG 379 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) * @author Jason Height (jheight at chariot dot net dot au) + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) * @version 2.0-pre */ @@ -36,7 +37,7 @@ { public final static short sid = 0x208; //private short field_1_row_number; - private int field_1_row_number; + private int field_1_row_number; private short field_2_first_col; private short field_3_last_col; // plus 1 private short field_4_height; @@ -302,7 +303,9 @@ public short getOptionFlags() { - return field_7_option_flags; + //Dragos Buleandra + //return field_7_option_flags; + return (short)(field_7_option_flags | (short)0x0100); } // option bitfields Index: src/java/org/apache/poi/hssf/record/WSBoolRecord.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/WSBoolRecord.java,v retrieving revision 1.5.2.1 diff -u -r1.5.2.1 WSBoolRecord.java --- src/java/org/apache/poi/hssf/record/WSBoolRecord.java 22 Feb 2004 11:54:47 -0000 1.5.2.1 +++ src/java/org/apache/poi/hssf/record/WSBoolRecord.java 8 Mar 2004 08:47:49 -0000 @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - + package org.apache.poi.hssf.record; @@ -29,6 +29,8 @@ * @author Andrew C. Oliver (acoliver at apache dot org) * @author Glen Stampoultzis (gstamp@iprimus.com.au) * @author Jason Height (jheight at chariot dot net dot au) + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) Fixed bug : field_1_wsbool and field_2_wsbool were wrong + * filled/serialized ( in a reversed order ) * @version 2.0-pre */ @@ -105,10 +107,13 @@ protected void fillFields(byte [] data, short size, int offset) { - field_1_wsbool = - data[ 1 + offset ]; // backwards because theoretically this is one short field - field_2_wsbool = - data[ 0 + offset ]; // but it was easier to implement it this way to avoid confusion + //Dragos Buleandra - these 2 fields were filled in a reversed order +// field_1_wsbool = +// data[ 1 + offset ]; // backwards because theoretically this is one short field +// field_2_wsbool = +// data[ 0 + offset ]; // but it was easier to implement it this way to avoid confusion + field_1_wsbool = data[ 0 + offset ]; + field_2_wsbool = data[ 1 + offset ]; } // because the dev kit shows the masks for it as 2 byte fields // why? Why ask why? But don't drink bud dry as its a really @@ -365,8 +370,11 @@ { LittleEndian.putShort(data, 0 + offset, sid); LittleEndian.putShort(data, 2 + offset, ( short ) 0x2); - data[ 5 + offset ] = getWSBool1(); - data[ 4 + offset ] = getWSBool2(); + //Dragos Buleandra - like filled the serialization of these 2 fields was made in a reversed order +// data[ 5 + offset ] = getWSBool1(); +// data[ 4 + offset ] = getWSBool2(); + data[ 4 + offset ] = getWSBool1(); + data[ 5 + offset ] = getWSBool2(); return getRecordSize(); } Index: src/java/org/apache/poi/hssf/record/formula/IntPtg.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/IntPtg.java,v retrieving revision 1.10.2.2 diff -u -r1.10.2.2 IntPtg.java --- src/java/org/apache/poi/hssf/record/formula/IntPtg.java 22 Feb 2004 11:54:52 -0000 1.10.2.2 +++ src/java/org/apache/poi/hssf/record/formula/IntPtg.java 8 Mar 2004 08:47:49 -0000 @@ -38,11 +38,12 @@ { public final static int SIZE = 3; public final static byte sid = 0x1e; - private short field_1_value; + // private short field_1_value; + private int field_1_value; private String val; private int strlen = 0; - + private IntPtg() { //Required for clone methods } @@ -51,19 +52,20 @@ { setValue(LittleEndian.getShort(data, offset + 1)); } - - + + // IntPtg should be able to create itself, shouldnt have to call setValue public IntPtg(String formulaToken) { - setValue(Short.parseShort(formulaToken)); + //setValue(Short.parseShort(formulaToken)); + setValue( Integer.parseInt(formulaToken)); } - public void setValue(short value) + public void setValue(int value) { field_1_value = value; } - public short getValue() + public int getValue() { return field_1_value; } @@ -71,7 +73,7 @@ public void writeBytes(byte [] array, int offset) { array[ offset + 0 ] = sid; - LittleEndian.putShort(array, offset + 1, getValue()); + LittleEndian.putInt(array, offset + 1, getValue()); //.putShort(array, offset + 1, getValue()); } public int getSize() @@ -83,7 +85,7 @@ { return "" + getValue(); } - public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} + public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} public Object clone() { IntPtg ptg = new IntPtg(); Index: src/java/org/apache/poi/hssf/usermodel/HSSFRow.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java,v retrieving revision 1.12.2.1 diff -u -r1.12.2.1 HSSFRow.java --- src/java/org/apache/poi/hssf/usermodel/HSSFRow.java 22 Feb 2004 11:54:53 -0000 1.12.2.1 +++ src/java/org/apache/poi/hssf/usermodel/HSSFRow.java 8 Mar 2004 08:47:50 -0000 @@ -36,6 +36,7 @@ * @version 1.0-pre * @author Andrew C. Oliver (acoliver at apache dot org) * @author Glen Stampoultzis (glens at apache.org) + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) Added method for hiding rows */ public class HSSFRow @@ -345,6 +346,16 @@ row.setBadFontHeight(true); row.setHeight((short) (height * 20)); } + + /** + * @author Dragos Buleandra + * Hide a row + * @param hide True to hide the row , false otherwise + */ + public void hide( boolean hide ) + { + sheet.getRow(rowNum).setZeroHeight( hide ); + } /** * get the row's height or ff (-1) for undefined/default-height in twips (1/20th of a point) Index: src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java,v retrieving revision 1.21.2.6 diff -u -r1.21.2.6 HSSFSheet.java --- src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java 22 Feb 2004 11:54:53 -0000 1.21.2.6 +++ src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java 8 Mar 2004 08:47:52 -0000 @@ -28,12 +28,21 @@ import org.apache.poi.hssf.util.Region; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; +import org.apache.poi.hssf.model.FormulaParser; +import org.apache.poi.hssf.record.formula.Ptg; +import org.apache.poi.hssf.util.HSSFDataValidation; +import org.apache.poi.hssf.util.HSSFCellRangeAddress; +import org.apache.poi.hssf.record.DVALRecord; +import org.apache.poi.hssf.record.DVRecord; +import org.apache.poi.hssf.record.EOFRecord; +import org.apache.poi.hssf.record.GutsRecord; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.TreeMap; +import java.util.Stack; /** * High level representation of a worksheet. @@ -41,6 +50,8 @@ * @author Glen Stampoultzis (glens at apache.org) * @author Libin Roman (romal at vistaportal.com) * @author Shawn Laubach (slaubach at apache dot org) (Just a little) + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) Added support for grouping/outlining rows and columns + * Method for full implementation of Data validation Excel's mechanism */ public class HSSFSheet @@ -964,7 +975,7 @@ shiftMerged(startRow, endRow, n, true); sheet.shiftRowBreaks(startRow, endRow, n); - + for ( int rowNum = s; rowNum >= startRow && rowNum <= endRow && rowNum >= 0 && rowNum < 65536; rowNum += inc ) { HSSFRow row = getRow( rowNum ); @@ -1018,6 +1029,238 @@ } /** + * @author : Dragos Buleandra + * Creates a data validation object + * @param obj_validation The Data validation object settings + */ + public void addValidationData( HSSFDataValidation obj_validation ) + { + if ( obj_validation == null ) + { + return; + } + DVALRecord dvalRec = (DVALRecord)sheet.findFirstRecordBySid( DVALRecord.sid ); + int eofLoc = sheet.findFirstRecordLocBySid( EOFRecord.sid ); + if ( dvalRec == null ) + { + dvalRec = new DVALRecord(); + sheet.getRecords().add( eofLoc, dvalRec ); + } + int curr_dvRecNo = dvalRec.getDVRecNo(); + dvalRec.setDVRecNo(curr_dvRecNo+1); + + //create dv record + DVRecord dvRecord = new DVRecord(); + + //dv record's option flags + dvRecord.setDataType( obj_validation.getDataValidationType() ); + dvRecord.setErrorStyle(obj_validation.getErrorStyle()); + dvRecord.setEmptyCellAllowed(obj_validation.getEmptyCellAllowed()); + dvRecord.setSurppresDropdownArrow(obj_validation.getSurppressDropDownArrow()); + dvRecord.setShowPromptOnCellSelected(obj_validation.getShowPromptBox()); + dvRecord.setShowErrorOnInvalidValue(obj_validation.getShowErrorBox()); + dvRecord.setConditionOperator(obj_validation.getOperator()); + + //string fields + dvRecord.setStringField( DVRecord.STRING_PROMPT_TITLE,obj_validation.getPromptBoxTitle()); + dvRecord.setStringField( DVRecord.STRING_PROMPT_TEXT, obj_validation.getPromptBoxText()); + dvRecord.setStringField( DVRecord.STRING_ERROR_TITLE, obj_validation.getErrorBoxTitle()); + dvRecord.setStringField( DVRecord.STRING_ERROR_TEXT, obj_validation.getErrorBoxText()); + + //formula fields ( size and data ) + String str_formula = obj_validation.getFirstFormula(); + FormulaParser fp = new FormulaParser(str_formula+";",book); + fp.parse(); + Stack ptg_arr = new Stack(); + Ptg[] ptg = fp.getRPNPtg(); + int size = 0; + for (int k = 0; k < ptg.length; k++) + { + if ( ptg[k] instanceof org.apache.poi.hssf.record.formula.AreaPtg ) + { + //we should set ptgClass to Ptg.CLASS_REF and explicit formula string to false + ptg[k].setClass(Ptg.CLASS_REF); + obj_validation.setExplicitListFormula(false); + } + size += ptg[k].getSize(); + ptg_arr.push(ptg[k]); + } + dvRecord.setFirstFormulaRPN(ptg_arr); + dvRecord.setFirstFormulaSize((short)size); + + dvRecord.setListExplicitFormula(obj_validation.getExplicitListFormula()); + + if ( obj_validation.getSecondFormula() != null ) + { + str_formula = obj_validation.getSecondFormula(); + fp = new FormulaParser(str_formula+";",book); + fp.parse(); + ptg_arr = new Stack(); + ptg = fp.getRPNPtg(); + size = 0; + for (int k = 0; k < ptg.length; k++) + { + size += ptg[k].getSize(); + ptg_arr.push(ptg[k]); + } + dvRecord.setSecFormulaRPN(ptg_arr); + dvRecord.setSecFormulaSize((short)size); + } + + //dv records cell range field + HSSFCellRangeAddress cell_range = new HSSFCellRangeAddress(); + cell_range.addADDRStructure(obj_validation.getFirstRow(), obj_validation.getFirstColumn(), obj_validation.getLastRow(), obj_validation.getLastColumn()); + dvRecord.setCellRangeAddress(cell_range); + + //add dv record + eofLoc = sheet.findFirstRecordLocBySid( EOFRecord.sid ); + sheet.getRecords().add( eofLoc, dvRecord ); + } + + /** + * @author : Dragos Buleandra + * @param rowno The row number ( zero based ) + * @param level The outlining level ( 1<= level <=7 ) + * @param collapsed True if row should be collapsed , false otherwise + * @param rowSumBellow True if summary rows should be placed bellow detail , false otherwise + * In other words , where to place the '+' sign . + */ + public void createOutlineRow(int rowno, short level, boolean collapsed, boolean rowSumBellow ) + { + HSSFRow row = this.getRow(rowno); + + GutsRecord gutsRec = (GutsRecord)sheet.findFirstRecordBySid( GutsRecord.sid ); + + short currLevelMax = gutsRec.getRowLevelMax(); + if ( level < 0 ) level = 0; + if ( level > 7 ) level = 7; + + short level_diff = (short)(currLevelMax - level); + + if ( level_diff < (short)0 ) + { + if ( Math.abs(level_diff) > 1 ) + { + level = ( currLevelMax == 0 ) ? 1 : currLevelMax ; + } + gutsRec.setRowLevelMax( (short)(level+1) ); + } + else + { + if (level_diff == (short)0 ) + { + gutsRec.setRowLevelMax( (short)(level+1) ); + } + } + + if ( row == null ) + { + row = this.createRow( rowno ); + } + + if ( gutsRec.getLeftRowGutter() == 0) + { + gutsRec.setLeftRowGutter((short)41); + } + + WSBoolRecord wsBoolRec = (WSBoolRecord)sheet.findFirstRecordBySid( WSBoolRecord.sid ); + wsBoolRec.setRowSumsBelow(rowSumBellow); + + RowRecord undRow = row.getRowRecord(); + undRow.setOutlineLevel(level); + undRow.setBadFontHeight(false); + undRow.setColapsed(collapsed); + undRow.setZeroHeight(collapsed); + } + + /** + * @author : Dragos Buleandra + * @param rowno The row number ( zero based ) + * @param level The outlining level ( 1<= level <=7 ) + * @param collapsed True if row should be collapsed , false otherwise + */ + public void createOutlineRow(int rowno, short level, boolean collapsed ) + { + this.createOutlineRow( rowno, level, collapsed, true ); + } + + /** + * @author : Dragos Buleandra + * @param rowno The row number ( zero based ) + * @param level The outlining level ( 1<= level <=7 ) + */ + public void createOutlineRow(int rowno, short level) + { + this.createOutlineRow( rowno, level, false, true ); + } + + /** + * @author : Dragos Buleandra + * @param colno The column number ( zero based ) + * @param level The outlining level ( max. level is 7 ) + * @param collapsed True if this outline level should be collapsed , false otherwise + * @param colSumRight True if summary cols should be placed on the right of detail , false otherwise + * In other words , where to place the '+' sign . + */ + public void createOutlineColumn( short colno, short level, boolean collapsed, boolean colSumRight ) + { + GutsRecord gutsRec = (GutsRecord)sheet.findFirstRecordBySid( GutsRecord.sid ); + + short currLevelMax = gutsRec.getColLevelMax(); + if ( level < 0 ) level = 0; + if ( level > 7 ) level = 7; + + short level_diff = (short)(currLevelMax - level); + + if ( level_diff < (short)0 ) + { + if ( Math.abs(level_diff) > 1 ) + { + level = ( currLevelMax == 0 ) ? 1 : currLevelMax ; + } + gutsRec.setColLevelMax( (short)(level+1) ); + } + else + { + if (level_diff == (short)0 ) + { + gutsRec.setColLevelMax( (short)(level+1) ); + } + } + + if ( gutsRec.getTopColGutter() == 0) + { + gutsRec.setTopColGutter((short)41); + } + + WSBoolRecord wsBoolRec = (WSBoolRecord)sheet.findFirstRecordBySid( WSBoolRecord.sid ); + wsBoolRec.setRowSumsRight(colSumRight); + + this.sheet.createOutlineColumn( colno, level, collapsed ); + } + + /** + * @author : Dragos Buleandra + * @param colno The column number ( zero based ) + * @param level The outlining level ( max. level is 7 ) + * @param collapsed True if this outline level should be collapsed , false otherwise + */ + public void createOutlineColumn( short colno, short level, boolean collapsed ) + { + this.createOutlineColumn( colno, level, collapsed, true ); + } + + /** + * @author : Dragos Buleandra + * @param colno The column number ( zero based ) + * @param level The outlining level ( max. level is 7 ) + */ + public void createOutlineColumn( short colno, short level ) + { + this.createOutlineColumn( colno, level, false, true ); + } + + /** * Creates a split (freezepane). * @param colSplit Horizonatal position of split. * @param rowSplit Vertical position of split. @@ -1108,7 +1351,7 @@ public boolean isDisplayRowColHeadings() { return sheet.isDisplayRowColHeadings(); } - + /** * Sets a page break at the indicated row * @param row @@ -1126,7 +1369,7 @@ public boolean isRowBroken(int row) { return sheet.isRowBroken(row); } - + /** * Removes the page break at the indicated row * @param row @@ -1134,13 +1377,13 @@ public void removeRowBreak(int row) { sheet.removeRowBreak(row); } - + /** * Retrieves all the horizontal page breaks * @return */ public int[] getRowBreaks(){ - //we can probably cache this information, but this should be a sparsely used function + //we can probably cache this information, but this should be a sparsely used function int[] returnValue = new int[sheet.getNumRowBreaks()]; Iterator iterator = sheet.getRowBreaks(); int i = 0; @@ -1156,7 +1399,7 @@ * @return */ public short[] getColumnBreaks(){ - //we can probably cache this information, but this should be a sparsely used function + //we can probably cache this information, but this should be a sparsely used function short[] returnValue = new short[sheet.getNumColumnBreaks()]; Iterator iterator = sheet.getColumnBreaks(); int i = 0; @@ -1166,8 +1409,8 @@ } return returnValue; } - - + + /** * Sets a page break at the indicated column * @param column @@ -1185,7 +1428,7 @@ public boolean isColumnBroken(short column) { return sheet.isColumnBroken(column); } - + /** * Removes a page break at the indicated column * @param column @@ -1193,7 +1436,7 @@ public void removeColumnBreak(short column) { sheet.removeColumnBreak(column); } - + /** * Runs a bounds check for row numbers * @param row @@ -1202,7 +1445,7 @@ if (row > 65535) throw new IllegalArgumentException("Maximum row number is 65535"); if (row < 0) throw new IllegalArgumentException("Minumum row number is 0"); } - + /** * Runs a bounds check for column numbers * @param column Index: src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java,v retrieving revision 1.24.2.6 diff -u -r1.24.2.6 HSSFWorkbook.java --- src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java 22 Feb 2004 11:54:53 -0000 1.24.2.6 +++ src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java 8 Mar 2004 08:47:53 -0000 @@ -59,6 +59,8 @@ * @author Andrew C. Oliver (acoliver at apache dot org) * @author Glen Stampoultzis (glens at apache.org) * @author Shawn Laubach (slaubach at apache dot org) + * @author Dragos Buleandra (dragos.buleandra@trade2b.ro) Fixed bugs when cloning sheets . + * Methods for hidding ( normal hide and strong hide ) sheets * @version 2.0-pre */ @@ -160,8 +162,6 @@ EventRecordFactory factory = new EventRecordFactory(); - - List records = RecordFactory.createRecords(stream); workbook = Workbook.createWorkbook(records); @@ -239,7 +239,7 @@ /** - * set the sheet name. + * set the sheet name. * Will throw IllegalArgumentException if the name is greater than 31 chars * or contains /\?*[] * @param sheet number (0 based) @@ -328,7 +328,8 @@ /** * create an HSSFSheet from an existing sheet in the HSSFWorkbook. - * + * Modified : Dragos Buleandra -> we should also check if cloned sheet is involved in a Name record , in which case + * we should create a Name record for the new sheet also * @return HSSFSheet representing the cloned sheet. */ @@ -347,6 +348,17 @@ }else { workbook.setSheetName(sheets.size()-1,srcName.substring(0,28)+"(2)"); } + //Dragos Buleandra + NameRecord nameRecord = workbook.getNameRecordForSheet( (short)sheetNum ); + if ( nameRecord != null ) + { + short cloneSheetNo = (short)sheets.size(); + //we should create a name record for this new sheet also + NameRecord newNameRecord = (NameRecord) nameRecord.clone(); + newNameRecord.setEqualsToIndexToSheet(cloneSheetNo); + newNameRecord.setPTGTokenExternSheetIndex( (short)(cloneSheetNo-1) ); + workbook.addName(newNameRecord); + } return clonedSheet; } return null; @@ -427,6 +439,30 @@ { sheets.remove(index); workbook.removeSheet(index); + } + + /** + * @author Dragos Buleandra + * Hide/Unhide a sheet + * @param sheetnum Sheet's index + * @param hide True to hide the sheet , false to make it visible + * @param strong_hide True if the sheet should be string hidden ( can't be unhidden form Excel user interface ) + */ + public void hideSheet(int sheetnum, boolean hide, boolean strong_hide ) + { + workbook.hideSheet( sheetnum, hide, strong_hide); + } + + /** + * @author Dragos Buleandra + * Hide/Unhide a sheet + * @param sheetname Sheet's name + * @param hide True to hide the sheet , false to make it visible + * @param strong_hide True if the sheet should be string hidden ( can't be unhidden form Excel user interface ) + */ + public void hideSheet(String sheetname, boolean hide, boolean strong_hide ) + { + workbook.hideSheet( sheetname, hide, strong_hide); } /** Index: src/java/org/apache/poi/util/LittleEndian.java =================================================================== RCS file: /home/cvspublic/jakarta-poi/src/java/org/apache/poi/util/LittleEndian.java,v retrieving revision 1.12.2.2 diff -u -r1.12.2.2 LittleEndian.java --- src/java/org/apache/poi/util/LittleEndian.java 22 Feb 2004 11:50:12 -0000 1.12.2.2 +++ src/java/org/apache/poi/util/LittleEndian.java 8 Mar 2004 08:47:54 -0000 @@ -98,7 +98,7 @@ *@return The shortArray value */ public static short[] getShortArray(final byte[] data, final int offset) { - int size = (short) getNumber(data, offset, SHORT_SIZE); + int size = (int) getNumber(data, offset, SHORT_SIZE); short[] results = getSimpleShortArray(data, offset, size); return results; }