From: Nick Burch Date: Fri, 16 May 2008 17:08:40 +0000 (+0000) Subject: Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-63924... X-Git-Tag: REL_3_5_BETA2~86 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=8f9f5b0065db47207d4541091bd197ec96f49890;p=poi.git Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646404,646406-646665,646667-646853,646855-646869,646871-647151,647153-647185,647187-647277,647279-647566,647568-647573,647575,647578-647711,647714-647737,647739-647823,647825-648155,648157-648202,648204-648273,648275,648277-648302,648304-648333,648335-648588,648590-648622,648625-648673,648675-649141,649144,649146-649556,649558-649795,649799,649801-649910,649912-649913,649915-650128,650131-650132,650134-650137,650140-650914,650916-651991,651993-652284,652286-652287,652289,652291,652293-652297,652299-652328,652330-652425,652427-652445,652447-652560,652562-652933,652935,652937-652993,652995-653116,653118-653124,653126-653483,653487-653519,653522-653550,653552-653607,653609-653667,653669-653674,653676-653814,653817-653830,653832-657131 via svnmerge from https://svn.apache.org:443/repos/asf/poi/trunk ........ r653892 | josh | 2008-05-06 20:48:55 +0100 (Tue, 06 May 2008) | 1 line Another attempt to fix unicode problems in functionMetadata.txt. Made that file pure ascii. ........ r653945 | nick | 2008-05-06 23:51:28 +0100 (Tue, 06 May 2008) | 1 line Add disabled test for bug #44898, and slightly improve a few poifs related error messages ........ r654056 | nick | 2008-05-07 10:41:03 +0100 (Wed, 07 May 2008) | 1 line Update a test to match the new warning on short files ........ r654356 | josh | 2008-05-08 01:52:05 +0100 (Thu, 08 May 2008) | 1 line 44950 - fixed HSSFFormulaEvaluator.evaluateInCell() and Area3DEval.getValue() also added validation for number of elements in AreaEvals ........ r654366 | josh | 2008-05-08 02:06:56 +0100 (Thu, 08 May 2008) | 1 line tiny clean-up after r654356 (bug 44950) ........ r654649 | josh | 2008-05-09 00:02:43 +0100 (Fri, 09 May 2008) | 1 line fixed mistake in FuncPtg.clone(), added test case, cleaned up outdated (since bug 13292) test method. ........ r654650 | josh | 2008-05-09 00:06:30 +0100 (Fri, 09 May 2008) | 1 line removed unused constructor and old comment after r654649 ........ r655216 | josh | 2008-05-11 02:30:56 +0100 (Sun, 11 May 2008) | 1 line bug 23630 - fixed spelling mistake in constant name ........ r655278 | josh | 2008-05-11 09:15:39 +0100 (Sun, 11 May 2008) | 1 line 41187 - fixed HSSFSheet to properly read xls files without ROW records ........ r655282 | yegor | 2008-05-11 10:03:24 +0100 (Sun, 11 May 2008) | 1 line Added boolean flag to turn on use of merged columns in autosize ........ r655912 | josh | 2008-05-13 16:25:51 +0100 (Tue, 13 May 2008) | 1 line added test case for reported bug 44987 ........ r656213 | yegor | 2008-05-14 11:15:00 +0100 (Wed, 14 May 2008) | 1 line properly update TextSpecInfoAtom when parent text is changed ........ r656215 | yegor | 2008-05-14 11:18:00 +0100 (Wed, 14 May 2008) | 1 line Support for embedded ActiveX objects: PowerPoint references them similar to embedded documents but in a different container: ExControl instead of ExEmbed ........ r656252 | yegor | 2008-05-14 13:42:30 +0100 (Wed, 14 May 2008) | 1 line convert line breaks into internal ppt represenatation when changing text ........ r656699 | yegor | 2008-05-15 16:23:38 +0100 (Thu, 15 May 2008) | 1 line added a set accessor for embedded ole data ........ r656757 | josh | 2008-05-15 18:49:23 +0100 (Thu, 15 May 2008) | 1 line bug 45000 - Fixed NPE in ListLevel when numberText is null ........ r656893 | josh | 2008-05-16 00:30:08 +0100 (Fri, 16 May 2008) | 1 line 44523 - fixed workbook sheet selection and focus ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@657135 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 3eb198142a..b2dea5c407 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -44,6 +44,11 @@ Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx + 44523 - fixed workbook sheet selection and focus + 45000 - Fixed NPE in ListLevel when numberText is null + 44985 - Properly update TextSpecInfoAtom when the parent text is changed + 41187 - fixed HSSFSheet to properly read xls files without ROW records + 44950 - fixed HSSFFormulaEvaluator.evaluateInCell() and Area3DEval.getValue() also added validation for number of elements in AreaEvals 42570 - fixed LabelRecord to use empty string instead of null when the length is zero. 42564 - fixed ArrayPtg to use ConstantValueParser. Fixed a few other ArrayPtg encoding issues. Follow-on from 28754 - StringPtg.toFormulaString() should escape double quotes diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 5732cd9339..75117754bd 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -41,6 +41,11 @@ Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx + 44523 - fixed workbook sheet selection and focus + 45000 - Fixed NPE in ListLevel when numberText is null + 44985 - Properly update TextSpecInfoAtom when the parent text is changed + 41187 - fixed HSSFSheet to properly read xls files without ROW records + 44950 - fixed HSSFFormulaEvaluator.evaluateInCell() and Area3DEval.getValue() also added validation for number of elements in AreaEvals 42570 - fixed LabelRecord to use empty string instead of null when the length is zero. 42564 - fixed ArrayPtg to use ConstantValueParser. Fixed a few other ArrayPtg encoding issues. Follow-on from 28754 - StringPtg.toFormulaString() should escape double quotes diff --git a/src/documentation/release-guide.txt b/src/documentation/release-guide.txt index 56ebf3fa1d..e1fbc94e6f 100755 --- a/src/documentation/release-guide.txt +++ b/src/documentation/release-guide.txt @@ -37,14 +37,14 @@ where $TAG is the release tag, for example, REL_3_1_BETA1 3. Checkout the tagged version {code} cd tags -svn checkout https://svn.apache.org/repos/asf/poi/tags/TAG +svn checkout https://svn.apache.org/repos/asf/poi/tags/$TAG {code} 4. Merge (if required) {code} cd $TAG -$ svn merge https://svn.apache.org/repos/asf/poi/tags/TAG \ +$ svn merge https://svn.apache.org/repos/asf/poi/tags/$TAG \ https://svn.apache.org/repos/asf/poi/trunk {code} diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java index 2af25e7481..45090e85cf 100644 --- a/src/java/org/apache/poi/hssf/model/Sheet.java +++ b/src/java/org/apache/poi/hssf/model/Sheet.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -16,7 +15,6 @@ limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.model; import org.apache.poi.hssf.record.*; @@ -57,9 +55,7 @@ import java.util.List; // normally I don't do this, buy we literally mean ALL * @see org.apache.poi.hssf.usermodel.HSSFSheet * @version 1.0-pre */ - -public class Sheet implements Model -{ +public final class Sheet implements Model { public static final short LeftMargin = 0; public static final short RightMargin = 1; public static final short TopMargin = 2; @@ -97,9 +93,9 @@ public class Sheet implements Model protected ObjectProtectRecord objprotect = null; protected ScenarioProtectRecord scenprotect = null; protected PasswordRecord password = null; - protected List condFormatting = new ArrayList();; + protected List condFormatting = new ArrayList(); - /** Add an UncalcedRecord if not true indicating formulas have not been calculated */ + /** Add an UncalcedRecord if not true indicating formulas have not been calculated */ protected boolean uncalced = false; public static final byte PANE_LOWER_RIGHT = (byte)0; @@ -108,7 +104,7 @@ public class Sheet implements Model public static final byte PANE_UPPER_LEFT = (byte)3; /** - * Creates new Sheet with no intialization --useless at this point + * Creates new Sheet with no initialization --useless at this point * @see #createSheet(List,int,int) */ public Sheet() @@ -166,7 +162,7 @@ public class Sheet implements Model } } else if (rec.getSid() == UncalcedRecord.sid) { - retval.uncalced = true; + retval.uncalced = true; } else if (rec.getSid() == DimensionsRecord.sid) { @@ -188,14 +184,14 @@ public class Sheet implements Model } else if ( rec.getSid() == CFHeaderRecord.sid ) { - CFRecordsAggregate cfAgg = CFRecordsAggregate.createCFAggregate(recs, k); - retval.condFormatting.add(cfAgg); - rec = cfAgg; + CFRecordsAggregate cfAgg = CFRecordsAggregate.createCFAggregate(recs, k); + retval.condFormatting.add(cfAgg); + rec = cfAgg; } else if ( rec.getSid() == CFRuleRecord.sid ) { - // Skip it since it is processed by CFRecordsAggregate - rec = null; + // Skip it since it is processed by CFRecordsAggregate + rec = null; } else if (rec.getSid() == ColumnInfoRecord.sid) { @@ -244,7 +240,7 @@ public class Sheet implements Model if ( isfirstrow ) { retval.rows = new RowRecordsAggregate(); - rec = retval.rows; + rec = retval.rows; isfirstrow = false; } retval.rows.insertRow(row); @@ -256,7 +252,7 @@ public class Sheet implements Model else if ( rec.getSid() == GridsetRecord.sid ) { retval.gridset = (GridsetRecord) rec; - } + } else if ( rec.getSid() == HeaderRecord.sid && bofEofNestingLevel == 1) { retval.header = (HeaderRecord) rec; @@ -301,32 +297,32 @@ public class Sheet implements Model { rec = null; } - - else if ( rec.getSid() == ProtectRecord.sid ) - { - retval.protect = (ProtectRecord) rec; - } - else if ( rec.getSid() == ObjectProtectRecord.sid ) - { - retval.objprotect = (ObjectProtectRecord) rec; - } - else if ( rec.getSid() == ScenarioProtectRecord.sid ) - { - retval.scenprotect = (ScenarioProtectRecord) rec; - } - else if ( rec.getSid() == PasswordRecord.sid ) - { - retval.password = (PasswordRecord) rec; - } - else if (rec.getSid() == PageBreakRecord.HORIZONTAL_SID) - { - retval.rowBreaks = (PageBreakRecord)rec; - } - else if (rec.getSid() == PageBreakRecord.VERTICAL_SID) - { - retval.colBreaks = (PageBreakRecord)rec; - } - + + else if ( rec.getSid() == ProtectRecord.sid ) + { + retval.protect = (ProtectRecord) rec; + } + else if ( rec.getSid() == ObjectProtectRecord.sid ) + { + retval.objprotect = (ObjectProtectRecord) rec; + } + else if ( rec.getSid() == ScenarioProtectRecord.sid ) + { + retval.scenprotect = (ScenarioProtectRecord) rec; + } + else if ( rec.getSid() == PasswordRecord.sid ) + { + retval.password = (PasswordRecord) rec; + } + else if (rec.getSid() == PageBreakRecord.HORIZONTAL_SID) + { + retval.rowBreaks = (PageBreakRecord)rec; + } + else if (rec.getSid() == PageBreakRecord.VERTICAL_SID) + { + retval.colBreaks = (PageBreakRecord)rec; + } + if (rec != null) { records.add(rec); @@ -351,9 +347,9 @@ public class Sheet implements Model /** * Clones the low level records of this sheet and returns the new sheet instance. * This method is implemented by adding methods for deep cloning to all records that - * can be added to a sheet. The Record 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() { @@ -374,7 +370,7 @@ public class Sheet implements Model ValueRecordsAggregate vrAgg = (ValueRecordsAggregate)rec; for (Iterator cellIter = vrAgg.getIterator();cellIter.hasNext();) { Record valRec = (Record)cellIter.next(); - + if (valRec instanceof FormulaRecordAggregate) { FormulaRecordAggregate fmAgg = (FormulaRecordAggregate)valRec; Record fmAggRec = fmAgg.getFormulaRecord(); @@ -459,9 +455,9 @@ public class Sheet implements Model 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() ); @@ -479,11 +475,11 @@ public class Sheet implements Model 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); + retval.protect = (ProtectRecord) retval.createProtect(); + records.add(retval.protect); records.add(retval.createEOF()); @@ -511,26 +507,25 @@ public class Sheet implements Model } } - //public int addMergedRegion(short rowFrom, short colFrom, short rowTo, - public int addMergedRegion(int rowFrom, short colFrom, int rowTo, - short colTo) - { - // Validate input - if(rowTo < rowFrom) { - throw new IllegalArgumentException("The row to ("+rowTo+") must be >= the row from ("+rowFrom+")"); - } - if(colTo < colFrom) { - throw new IllegalArgumentException("The col to ("+colTo+") must be >= the col from ("+colFrom+")"); - } - + public int addMergedRegion(int rowFrom, short colFrom, int rowTo, short colTo) { + // Validate input + if (rowTo < rowFrom) { + throw new IllegalArgumentException("The 'to' row (" + rowTo + + ") must not be less than the 'from' row (" + rowFrom + ")"); + } + if (colTo < colFrom) { + throw new IllegalArgumentException("The 'to' col (" + colTo + + ") must not be less than the 'from' col (" + colFrom + ")"); + } + 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) @@ -538,15 +533,15 @@ public class Sheet implements Model //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 { @@ -558,7 +553,7 @@ public class Sheet implements Model pos = n; break; } - startNumRegions += record.getNumAreas(); + startNumRegions += record.getNumAreas(); } } @@ -567,17 +562,17 @@ public class Sheet implements Model numMergedRegions--; if (rec.getNumAreas() == 0) { - mergedRecords.remove(pos); - //get rid of the record from the sheet - records.remove(merged); + mergedRecords.remove(pos); + //get rid of the record from the sheet + records.remove(merged); if (merged == rec) { - //pull up the LAST record for operations when we finally - //support continue records for mergedRegions - if (mergedRecords.size() > 0) { - merged = (MergeCellsRecord) mergedRecords.get(mergedRecords.size() - 1); - } else { - merged = null; - } + //pull up the LAST record for operations when we finally + //support continue records for mergedRegions + if (mergedRecords.size() > 0) { + merged = (MergeCellsRecord) mergedRecords.get(mergedRecords.size() - 1); + } else { + merged = null; + } } } } @@ -587,10 +582,10 @@ public class Sheet implements Model //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()) { @@ -607,7 +602,7 @@ public class Sheet implements Model pos = n; break; } - startNumRegions += record.getNumAreas(); + startNumRegions += record.getNumAreas(); } } return ((MergeCellsRecord) mergedRecords.get(pos)).getAreaAt(index - startNumRegions); @@ -620,62 +615,62 @@ public class Sheet implements Model // Find correct position to add new CF record private int findConditionalFormattingPosition() { - // This is default. - // If the algorithm does not find the right position, - // this one will be used (this is a position before EOF record) - int index = records.size()-2; - - for( int i=index; i>=0; i-- ) - { - Record rec = (Record)records.get(i); - short sid = rec.getSid(); - - // CFRecordsAggregate records already exist, just add to the end - if (rec instanceof CFRecordsAggregate) { return i+1; } - - if( sid == (short)0x00ef ) { return i+1; }// PHONETICPR - if( sid == (short)0x015f ) { return i+1; }// LABELRANGES - if( sid == MergeCellsRecord.sid ) { return i+1; } - if( sid == (short)0x0099 ) { return i+1; }// STANDARDWIDTH - if( sid == SelectionRecord.sid ) { return i+1; } - if( sid == PaneRecord.sid ) { return i+1; } - if( sid == SCLRecord.sid ) { return i+1; } - if( sid == WindowTwoRecord.sid ) { return i+1; } - } - - return index; + // This is default. + // If the algorithm does not find the right position, + // this one will be used (this is a position before EOF record) + int index = records.size()-2; + + for( int i=index; i>=0; i-- ) + { + Record rec = (Record)records.get(i); + short sid = rec.getSid(); + + // CFRecordsAggregate records already exist, just add to the end + if (rec instanceof CFRecordsAggregate) { return i+1; } + + if( sid == (short)0x00ef ) { return i+1; }// PHONETICPR + if( sid == (short)0x015f ) { return i+1; }// LABELRANGES + if( sid == MergeCellsRecord.sid ) { return i+1; } + if( sid == (short)0x0099 ) { return i+1; }// STANDARDWIDTH + if( sid == SelectionRecord.sid ) { return i+1; } + if( sid == PaneRecord.sid ) { return i+1; } + if( sid == SCLRecord.sid ) { return i+1; } + if( sid == WindowTwoRecord.sid ) { return i+1; } + } + + return index; } public int addConditionalFormatting(CFRecordsAggregate cfAggregate) { - int index = findConditionalFormattingPosition(); - records.add(index, cfAggregate); - condFormatting.add(cfAggregate); - return condFormatting.size()-1; + int index = findConditionalFormattingPosition(); + records.add(index, cfAggregate); + condFormatting.add(cfAggregate); + return condFormatting.size()-1; } public void removeConditionalFormatting(int index) { if (index >= 0 && index <= condFormatting.size()-1 ) { - CFRecordsAggregate cfAggregate = getCFRecordsAggregateAt(index); - records.remove(cfAggregate); - condFormatting.remove(index); + CFRecordsAggregate cfAggregate = getCFRecordsAggregateAt(index); + records.remove(cfAggregate); + condFormatting.remove(index); } } - + public CFRecordsAggregate getCFRecordsAggregateAt(int index) { if (index >= 0 && index <= condFormatting.size()-1 ) { - return (CFRecordsAggregate) condFormatting.get(index); + return (CFRecordsAggregate) condFormatting.get(index); } return null; } - + public int getNumConditionalFormattings() { - return condFormatting.size(); + return condFormatting.size(); } /** @@ -711,8 +706,6 @@ public class Sheet implements Model * * @see org.apache.poi.hssf.record.DimensionsRecord */ - - //public void setDimensions(short firstrow, short firstcol, short lastrow, public void setDimensions(int firstrow, short firstcol, int lastrow, short lastcol) { @@ -735,7 +728,7 @@ public class Sheet implements Model /** * set the locator for where we should look for the next value record. The - * algorythm will actually start here and find the correct location so you + * algorithm will actually start here and find the correct location so you * can set this to 0 and watch performance go down the tubes but it will work. * After a value is set this is automatically advanced. Its also set by the * create method. So you probably shouldn't mess with this unless you have @@ -813,13 +806,13 @@ public class Sheet implements Model for (int k = 0; k < records.size(); k++) { Record record = (( Record ) records.get(k)); - + // Don't write out UncalcedRecord entries, as // we handle those specially just below if (record instanceof UncalcedRecord) { - continue; + continue; } - + // Once the rows have been found in the list of records, start // writing out the blocked row information. This includes the DBCell references if (record instanceof RowRecordsAggregate) { @@ -829,13 +822,13 @@ public class Sheet implements Model } else { pos += record.serialize(pos, data ); // rec.length; } - + // If the BOF record was just serialized then add the IndexRecord if (record.getSid() == BOFRecord.sid) { // Add an optional UncalcedRecord if (uncalced) { - UncalcedRecord rec = new UncalcedRecord(); - pos += rec.serialize(pos, data); + UncalcedRecord rec = new UncalcedRecord(); + pos += rec.serialize(pos, data); } //Can there be more than one BOF for a sheet? If not then we can //remove this guard. So be safe it is left here. @@ -871,7 +864,7 @@ public class Sheet implements Model log.log(POILogger.DEBUG, "Sheet.serialize returning "); return pos-offset; } - + private int serializeIndexRecord(final int BOFRecordIndex, final int offset, byte[] data) { IndexRecord index = new IndexRecord(); index.setFirstRow(rows.getFirstRowNum()); @@ -906,7 +899,7 @@ public class Sheet implements Model } return index.serialize(offset, data); } - + /** * Create a row record. (does not add it to the records contained in this sheet) @@ -930,8 +923,6 @@ public class Sheet implements Model * @return LabelSSTRecord newly created containing your SST Index, row,col. * @see org.apache.poi.hssf.record.SSTRecord */ - - //public LabelSSTRecord createLabelSST(short row, short col, int index) public LabelSSTRecord createLabelSST(int row, short col, int index) { log.logFormatted(POILogger.DEBUG, "create labelsst row,col,index %,%,%", @@ -957,8 +948,6 @@ public class Sheet implements Model * * @return NumberRecord for that row, col containing that value as added to the sheet */ - - //public NumberRecord createNumber(short row, short col, double value) public NumberRecord createNumber(int row, short col, double value) { log.logFormatted(POILogger.DEBUG, "create number row,col,value %,%,%", @@ -968,7 +957,6 @@ public class Sheet implements Model }); NumberRecord rec = new NumberRecord(); - //rec.setRow(( short ) row); rec.setRow(row); rec.setColumn(col); rec.setValue(value); @@ -982,18 +970,14 @@ public class Sheet implements Model * @param row - the row the BlankRecord is a member of * @param col - the column the BlankRecord is a member of */ - - //public BlankRecord createBlank(short row, short col) public BlankRecord createBlank(int row, short col) { - //log.logFormatted(POILogger.DEBUG, "create blank row,col %,%", new short[] log.logFormatted(POILogger.DEBUG, "create blank row,col %,%", new int[] { row, col }); BlankRecord rec = new BlankRecord(); - //rec.setRow(( short ) row); rec.setRow(row); rec.setColumn(col); rec.setXFIndex(( short ) 0x0f); @@ -1009,12 +993,9 @@ public class Sheet implements Model * @param formula - a String representing the formula. To be parsed to PTGs * @return bogus/useless formula record */ - - //public FormulaRecord createFormula(short row, short col, String formula) public FormulaRecord createFormula(int row, short col, String formula) { log.logFormatted(POILogger.DEBUG, "create formula row,col,formula %,%,%", - //new short[] new int[] { row, col @@ -1052,8 +1033,6 @@ public class Sheet implements Model * @param row the row to add the cell value to * @param col the cell value record itself. */ - - //public void addValueRecord(short row, CellValueRecordInterface col) public void addValueRecord(int row, CellValueRecordInterface col) { checkCells(); @@ -1075,29 +1054,6 @@ public class Sheet implements Model d.setFirstCol(col.getColumn()); } cells.insertCell(col); - - /* - * for (int k = loc; k < records.size(); k++) - * { - * Record rec = ( Record ) records.get(k); - * - * if (rec.getSid() == RowRecord.sid) - * { - * RowRecord rowrec = ( RowRecord ) rec; - * - * if (rowrec.getRowNumber() == col.getRow()) - * { - * records.add(k + 1, col); - * loc = k; - * if (rowrec.getLastCol() <= col.getColumn()) - * { - * rowrec.setLastCol((( short ) (col.getColumn() + 1))); - * } - * break; - * } - * } - * } - */ } /** @@ -1109,8 +1065,6 @@ public class Sheet implements Model * @param col - a record supporting the CellValueRecordInterface. * @see org.apache.poi.hssf.record.CellValueRecordInterface */ - - //public void removeValueRecord(short row, CellValueRecordInterface col) public void removeValueRecord(int row, CellValueRecordInterface col) { checkCells(); @@ -1118,27 +1072,6 @@ public class Sheet implements Model new int[]{row, dimsloc} ); loc = dimsloc; cells.removeCell(col); - - /* - * for (int k = loc; k < records.size(); k++) - * { - * Record rec = ( Record ) records.get(k); - * - * // checkDimsLoc(rec,k); - * if (rec.isValue()) - * { - * CellValueRecordInterface cell = - * ( CellValueRecordInterface ) rec; - * - * if ((cell.getRow() == col.getRow()) - * && (cell.getColumn() == col.getColumn())) - * { - * records.remove(k); - * break; - * } - * } - * } - */ } /** @@ -1160,26 +1093,10 @@ public class Sheet implements Model //The ValueRecordsAggregate use a tree map underneath. //The tree Map uses the CellValueRecordInterface as both the //key and the value, if we dont do a remove, then - //the previous instance of the key is retained, effectively using + //the previous instance of the key is retained, effectively using //double the memory cells.removeCell(newval); cells.insertCell(newval); - - /* - * CellValueRecordInterface oldval = getNextValueRecord(); - * - * while (oldval != null) - * { - * if (oldval.isEqual(newval)) - * { - * records.set(( short ) (getLoc() - 1), newval); - * return; - * } - * oldval = getNextValueRecord(); - * } - * addValueRecord(newval.getRow(), newval); - * setLoc(dimsloc); - */ } /** @@ -1218,41 +1135,6 @@ public class Sheet implements Model rows.insertRow(row); - /* - * for (int k = loc; k < records.size(); k++) - * { - * Record rec = ( Record ) records.get(k); - * - * if (rec.getSid() == IndexRecord.sid) - * { - * index = ( IndexRecord ) rec; - * } - * if (rec.getSid() == RowRecord.sid) - * { - * RowRecord rowrec = ( RowRecord ) rec; - * - * if (rowrec.getRowNumber() > row.getRowNumber()) - * { - * records.add(k, row); - * loc = k; - * break; - * } - * } - * if (rec.getSid() == WindowTwoRecord.sid) - * { - * records.add(k, row); - * loc = k; - * break; - * } - * } - * if (index != null) - * { - * if (index.getLastRowAdd1() <= row.getRowNumber()) - * { - * index.setLastRowAdd1(row.getRowNumber() + 1); - * } - * } - */ if (log.check( POILogger.DEBUG )) log.log(POILogger.DEBUG, "exit addRow"); } @@ -1268,33 +1150,9 @@ public class Sheet implements Model public void removeRow(RowRecord row) { checkRows(); - // IndexRecord index = null; setLoc(getDimsLoc()); rows.removeRow(row); - - /* - * for (int k = loc; k < records.size(); k++) - * { - * Record rec = ( Record ) records.get(k); - * - * // checkDimsLoc(rec,k); - * if (rec.getSid() == RowRecord.sid) - * { - * RowRecord rowrec = ( RowRecord ) rec; - * - * if (rowrec.getRowNumber() == row.getRowNumber()) - * { - * records.remove(k); - * break; - * } - * } - * if (rec.getSid() == WindowTwoRecord.sid) - * { - * break; - * } - * } - */ } /** @@ -1325,65 +1183,7 @@ public class Sheet implements Model return null; } return ( CellValueRecordInterface ) valueRecIterator.next(); - - /* - * if (this.getLoc() < records.size()) - * { - * for (int k = getLoc(); k < records.size(); k++) - * { - * Record rec = ( Record ) records.get(k); - * - * this.setLoc(k + 1); - * if (rec instanceof CellValueRecordInterface) - * { - * return ( CellValueRecordInterface ) rec; - * } - * } - * } - * return null; - */ - } - - /** - * get the NEXT RowRecord or CellValueRecord(from LOC). The first record that - * is a Row record or CellValueRecord(starting at LOC) will be returned. - *

- * This method is "loc" sensitive. Meaning you need to set LOC to where you - * want it to start searching. If you don't know do this: setLoc(getDimsLoc). - * When adding several rows you can just start at the last one by leaving loc - * at what this sets it to. For this method, set loc to dimsloc to start with. - * subsequent calls will return rows in (physical) sequence or NULL when you get to the end. - * - * @return RowRecord representing the next row record or CellValueRecordInterface - * representing the next cellvalue or NULL if there are no more - * @see #setLoc(int) - * - */ - -/* public Record getNextRowOrValue() - { - POILogger.DEBUG((new StringBuffer("getNextRow loc= ")).append(loc) - .toString()); - if (this.getLoc() < records.size()) - { - for (int k = this.getLoc(); k < records.size(); k++) - { - Record rec = ( Record ) records.get(k); - - this.setLoc(k + 1); - if (rec.getSid() == RowRecord.sid) - { - return rec; - } - else if (rec.isValue()) - { - return rec; - } - } - } - return null; } - */ /** * get the NEXT RowRecord (from LOC). The first record that is a Row record @@ -1413,20 +1213,6 @@ public class Sheet implements Model return null; } return ( RowRecord ) rowRecIterator.next(); - -/* if (this.getLoc() < records.size()) - { - for (int k = this.getLoc(); k < records.size(); k++) - { - Record rec = ( Record ) records.get(k); - - this.setLoc(k + 1); - if (rec.getSid() == RowRecord.sid) - { - return ( RowRecord ) rec; - } - } - }*/ } /** @@ -1445,34 +1231,10 @@ public class Sheet implements Model * @see #setLoc(int) * */ - - //public RowRecord getRow(short rownum) - public RowRecord getRow(int rownum) - { + public RowRecord getRow(int rownum) { if (log.check( POILogger.DEBUG )) log.log(POILogger.DEBUG, "getNextRow loc= " + loc); return rows.getRow(rownum); - - /* - * if (this.getLoc() < records.size()) - * { - * for (int k = this.getLoc(); k < records.size(); k++) - * { - * Record rec = ( Record ) records.get(k); - * - * this.setLoc(k + 1); - * if (rec.getSid() == RowRecord.sid) - * { - * if ((( RowRecord ) rec).getRowNumber() == rownum) - * { - * return ( RowRecord ) rec; - * } - * } - * } - * } - */ - - // return null; } /** @@ -1489,7 +1251,6 @@ public class Sheet implements Model retval.setVersion(( short ) 0x600); retval.setType(( short ) 0x010); - // retval.setBuild((short)0x10d3); retval.setBuild(( short ) 0x0dbb); retval.setBuildYear(( short ) 1996); retval.setHistoryBitMask(0xc1); @@ -1807,7 +1568,7 @@ public class Sheet implements Model * @see org.apache.poi.hssf.record.ColumnInfoRecord * @return record containing a ColumnInfoRecord */ - + // TODO change return type to ColumnInfoRecord protected Record createColInfo() { return ColumnInfoRecordsAggregate.createColInfo(); @@ -1830,12 +1591,12 @@ public class Sheet implements Model public boolean isGridsPrinted() { - if (gridset == null) { - gridset = (GridsetRecord)createGridset(); - //Insert the newlycreated Gridset record at the end of the record (just before the EOF) - int loc = findFirstRecordLocBySid(EOFRecord.sid); - records.add(loc, gridset); - } + if (gridset == null) { + gridset = (GridsetRecord)createGridset(); + //Insert the newlycreated Gridset record at the end of the record (just before the EOF) + int loc = findFirstRecordLocBySid(EOFRecord.sid); + records.add(loc, gridset); + } return !gridset.getGridset(); } @@ -1918,16 +1679,16 @@ public class Sheet implements Model } return retval; } - + /** - * get the index to the ExtendedFormatRecord "associated" with - * the column at specified 0-based index. (In this case, an - * ExtendedFormatRecord index is actually associated with a + * get the index to the ExtendedFormatRecord "associated" with + * the column at specified 0-based index. (In this case, an + * ExtendedFormatRecord index is actually associated with a * ColumnInfoRecord which spans 1 or more columns) *
* Returns the index to the default ExtendedFormatRecord (0xF) * if no ColumnInfoRecord exists that includes the column - * index specified. + * index specified. * @param column * @return index of ExtendedFormatRecord associated with * ColumnInfoRecord that includes the column index or the @@ -2116,38 +1877,38 @@ public class Sheet implements Model retval.setNumRefs(( short ) 0x0); return retval; } - - public short getTopRow() + + public short getTopRow() { - return (windowTwo==null) ? (short) 0 : windowTwo.getTopRow(); + return (windowTwo==null) ? (short) 0 : windowTwo.getTopRow(); } - - public void setTopRow(short topRow) + + public void setTopRow(short topRow) { - if (windowTwo!=null) - { - windowTwo.setTopRow(topRow); - } + if (windowTwo!=null) + { + windowTwo.setTopRow(topRow); + } } - + /** * Sets the left column to show in desktop window pane. * @param leftCol the left column to show in desktop window pane */ public void setLeftCol(short leftCol){ - if (windowTwo!=null) - { - windowTwo.setLeftCol(leftCol); - } + if (windowTwo!=null) + { + windowTwo.setLeftCol(leftCol); + } } - - public short getLeftCol() + + public short getLeftCol() { - return (windowTwo==null) ? (short) 0 : windowTwo.getLeftCol(); + return (windowTwo==null) ? (short) 0 : windowTwo.getLeftCol(); } - - - + + + /** * Returns the active row * @@ -2162,7 +1923,7 @@ public class Sheet implements Model } return selection.getActiveCellRow(); } - + /** * Sets the active row * @@ -2177,7 +1938,7 @@ public class Sheet implements Model selection.setActiveCellRow(row); } } - + /** * Returns the active column * @@ -2192,7 +1953,7 @@ public class Sheet implements Model } return selection.getActiveCellCol(); } - + /** * Sets the active column * @@ -2278,9 +2039,9 @@ public class Sheet implements Model } // Add space for UncalcedRecord if (uncalced) { - retval += UncalcedRecord.getStaticRecordSize(); + retval += UncalcedRecord.getStaticRecordSize(); } - + return retval; } @@ -2367,16 +2128,19 @@ public class Sheet implements Model */ public HeaderRecord getHeader () { - return header; + return header; } + public WindowTwoRecord getWindowTwo() { + return windowTwo; + } /** * Sets the HeaderRecord. * @param newHeader The new HeaderRecord for the sheet. */ public void setHeader (HeaderRecord newHeader) { - header = newHeader; + header = newHeader; } /** @@ -2385,7 +2149,7 @@ public class Sheet implements Model */ public FooterRecord getFooter () { - return footer; + return footer; } /** @@ -2394,7 +2158,7 @@ public class Sheet implements Model */ public void setFooter (FooterRecord newFooter) { - footer = newFooter; + footer = newFooter; } /** @@ -2403,7 +2167,7 @@ public class Sheet implements Model */ public PrintSetupRecord getPrintSetup () { - return printSetup; + return printSetup; } /** @@ -2412,7 +2176,7 @@ public class Sheet implements Model */ public void setPrintSetup (PrintSetupRecord newPrintSetup) { - printSetup = newPrintSetup; + printSetup = newPrintSetup; } /** @@ -2421,7 +2185,7 @@ public class Sheet implements Model */ public PrintGridlinesRecord getPrintGridlines () { - return printGridlines; + return printGridlines; } /** @@ -2430,7 +2194,7 @@ public class Sheet implements Model */ public void setPrintGridlines (PrintGridlinesRecord newPrintGridlines) { - printGridlines = newPrintGridlines; + printGridlines = newPrintGridlines; } /** @@ -2447,23 +2211,23 @@ public class Sheet implements Model * @return the size of the margin */ public double getMargin(short margin) { - if (getMargins()[margin] != null) - return margins[margin].getMargin(); - else { - switch ( margin ) - { - case LeftMargin: - return .75; - case RightMargin: - return .75; - case TopMargin: - return 1.0; - case BottomMargin: - return 1.0; - default : - throw new RuntimeException( "Unknown margin constant: " + margin ); - } - } + if (getMargins()[margin] != null) + return margins[margin].getMargin(); + else { + switch ( margin ) + { + case LeftMargin: + return .75; + case RightMargin: + return .75; + case TopMargin: + return 1.0; + case BottomMargin: + return 1.0; + default : + throw new RuntimeException( "Unknown margin constant: " + margin ); + } + } } /** @@ -2472,32 +2236,32 @@ public class Sheet implements Model * @param size the size of the margin */ public void setMargin(short margin, double size) { - Margin m = getMargins()[margin]; - if (m == null) { - switch ( margin ) - { - case LeftMargin: - m = new LeftMarginRecord(); - records.add( getDimsLoc() + 1, m ); - break; - case RightMargin: - m = new RightMarginRecord(); - records.add( getDimsLoc() + 1, m ); - break; - case TopMargin: - m = new TopMarginRecord(); - records.add( getDimsLoc() + 1, m ); - break; - case BottomMargin: - m = new BottomMarginRecord(); - records.add( getDimsLoc() + 1, m ); - break; - default : - throw new RuntimeException( "Unknown margin constant: " + margin ); - } - margins[margin] = m; - } - m.setMargin( size ); + Margin m = getMargins()[margin]; + if (m == null) { + switch ( margin ) + { + case LeftMargin: + m = new LeftMarginRecord(); + records.add( getDimsLoc() + 1, m ); + break; + case RightMargin: + m = new RightMarginRecord(); + records.add( getDimsLoc() + 1, m ); + break; + case TopMargin: + m = new TopMarginRecord(); + records.add( getDimsLoc() + 1, m ); + break; + case BottomMargin: + m = new BottomMarginRecord(); + records.add( getDimsLoc() + 1, m ); + break; + default : + throw new RuntimeException( "Unknown margin constant: " + margin ); + } + margins[margin] = m; + } + m.setMargin( size ); } public int getEofLoc() @@ -2514,10 +2278,10 @@ public class Sheet implements Model */ public void createFreezePane(int colSplit, int rowSplit, int topRow, int leftmostColumn ) { - int paneLoc = findFirstRecordLocBySid(PaneRecord.sid); - if (paneLoc != -1) - records.remove(paneLoc); - + int paneLoc = findFirstRecordLocBySid(PaneRecord.sid); + if (paneLoc != -1) + records.remove(paneLoc); + int loc = findFirstRecordLocBySid(WindowTwoRecord.sid); PaneRecord pane = new PaneRecord(); pane.setX((short)colSplit); @@ -2563,10 +2327,10 @@ public class Sheet implements Model */ public void createSplitPane(int xSplitPos, int ySplitPos, int topRow, int leftmostColumn, int activePane ) { - int paneLoc = findFirstRecordLocBySid(PaneRecord.sid); - if (paneLoc != -1) - records.remove(paneLoc); - + int paneLoc = findFirstRecordLocBySid(PaneRecord.sid); + if (paneLoc != -1) + records.remove(paneLoc); + int loc = findFirstRecordLocBySid(WindowTwoRecord.sid); PaneRecord r = new PaneRecord(); r.setX((short)xSplitPos); @@ -2583,7 +2347,7 @@ public class Sheet implements Model sel.setPane(PANE_LOWER_RIGHT); } - + /** * Returns the information regarding the currently configured pane (split or freeze). * @return null if no pane configured, or the pane information. @@ -2592,9 +2356,9 @@ public class Sheet implements Model PaneRecord rec = (PaneRecord)findFirstRecordBySid(PaneRecord.sid); if (rec == null) return null; - + return new PaneInformation(rec.getX(), rec.getY(), rec.getTopRow(), - rec.getLeftColumn(), (byte)rec.getActivePane(), windowTwo.getFreezePanes()); + rec.getLeftColumn(), (byte)rec.getActivePane(), windowTwo.getFreezePanes()); } public SelectionRecord getSelection() @@ -2660,12 +2424,12 @@ public class Sheet implements Model */ public ProtectRecord getProtect() { - if (protect == null) { - protect = (ProtectRecord)createProtect(); - //Insert the newlycreated protect record at the end of the record (just before the EOF) - int loc = findFirstRecordLocBySid(EOFRecord.sid); - records.add(loc, protect); - } + if (protect == null) { + protect = (ProtectRecord)createProtect(); + //Insert the newlycreated protect record at the end of the record (just before the EOF) + int loc = findFirstRecordLocBySid(EOFRecord.sid); + records.add(loc, protect); + } return protect; } @@ -2674,12 +2438,12 @@ public class Sheet implements Model */ public PasswordRecord getPassword() { - if (password == null) { - password = createPassword(); - //Insert the newly created password record at the end of the record (just before the EOF) - int loc = findFirstRecordLocBySid(EOFRecord.sid); - records.add(loc, password); - } + if (password == null) { + password = createPassword(); + //Insert the newly created password record at the end of the record (just before the EOF) + int loc = findFirstRecordLocBySid(EOFRecord.sid); + records.add(loc, password); + } return password; } @@ -2714,7 +2478,7 @@ public class Sheet implements Model * @return whether gridlines are displayed */ public boolean isDisplayGridlines() { - return windowTwo.getDisplayGridlines(); + return windowTwo.getDisplayGridlines(); } /** @@ -2730,7 +2494,7 @@ public class Sheet implements Model * @return whether formulas are displayed */ public boolean isDisplayFormulas() { - return windowTwo.getDisplayFormulas(); + return windowTwo.getDisplayFormulas(); } /** @@ -2746,24 +2510,24 @@ public class Sheet implements Model * @return whether RowColHeadings are displayed */ public boolean isDisplayRowColHeadings() { - return windowTwo.getDisplayRowColHeadings(); + return windowTwo.getDisplayRowColHeadings(); } - + /** - * @return whether an uncalced record must be inserted or not at generation - */ - public boolean getUncalced() { - return uncalced; - } - /** - * @param uncalced whether an uncalced record must be inserted or not at generation - */ - public void setUncalced(boolean uncalced) { - this.uncalced = uncalced; - } + * @return whether an uncalced record must be inserted or not at generation + */ + public boolean getUncalced() { + return uncalced; + } + /** + * @param uncalced whether an uncalced record must be inserted or not at generation + */ + public void setUncalced(boolean uncalced) { + this.uncalced = uncalced; + } - /** + /** * Returns the array of margins. If not created, will create. * * @return the array of marings. @@ -2771,7 +2535,7 @@ public class Sheet implements Model protected Margin[] getMargins() { if (margins == null) margins = new Margin[4]; - return margins; + return margins; } /** @@ -2789,11 +2553,11 @@ public class Sheet implements Model boolean noDrawingRecordsFound = (loc == -1); if (noDrawingRecordsFound) { - if(!createIfMissing) { - // None found, and not allowed to add in - return -1; - } - + if(!createIfMissing) { + // None found, and not allowed to add in + return -1; + } + EscherAggregate aggregate = new EscherAggregate( drawingManager ); loc = findFirstRecordLocBySid(EscherAggregate.sid); if (loc == -1) @@ -2847,43 +2611,43 @@ public class Sheet implements Model * @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()) - { - PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); - short breakLocation = breakItem.main; - boolean inStart = (breakLocation >= start); - boolean inEnd = (breakLocation <= stop); - if(inStart && inEnd) - shiftedBreak.add(breakItem); - } - - iterator = shiftedBreak.iterator(); - while (iterator.hasNext()) { - PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); - breaks.removeBreak(breakItem.main); - breaks.addBreak((short)(breakItem.main+count), breakItem.subFrom, breakItem.subTo); - } - } - + + if(rowBreaks == null) + return; + Iterator iterator = breaks.getBreaksIterator(); + List shiftedBreak = new ArrayList(); + while(iterator.hasNext()) + { + PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); + short breakLocation = breakItem.main; + boolean inStart = (breakLocation >= start); + boolean inEnd = (breakLocation <= stop); + if(inStart && inEnd) + shiftedBreak.add(breakItem); + } + + iterator = shiftedBreak.iterator(); + 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) { - if (rowBreaks == null) { + public void setRowBreak(int row, short fromCol, short toCol) { + if (rowBreaks == null) { int loc = findFirstRecordLocBySid(WindowTwoRecord.sid); rowBreaks = new PageBreakRecord(PageBreakRecord.HORIZONTAL_SID); records.add(loc, rowBreaks); - } - rowBreaks.addBreak((short)row, fromCol, toCol); + } + rowBreaks.addBreak((short)row, fromCol, toCol); } /** @@ -2891,9 +2655,9 @@ public class Sheet implements Model * @param row */ public void removeRowBreak(int row) { - if (rowBreaks == null) - throw new IllegalArgumentException("Sheet does not define any row breaks"); - rowBreaks.removeBreak((short)row); + if (rowBreaks == null) + throw new IllegalArgumentException("Sheet does not define any row breaks"); + rowBreaks.removeBreak((short)row); } /** @@ -2902,7 +2666,7 @@ public class Sheet implements Model * @return true if the specified row has a page break */ public boolean isRowBroken(int row) { - return (rowBreaks == null) ? false : rowBreaks.getBreak((short)row) != null; + return (rowBreaks == null) ? false : rowBreaks.getBreak((short)row) != null; } /** @@ -2910,12 +2674,12 @@ public class Sheet implements Model * */ public void setColumnBreak(short column, short fromRow, short toRow) { - if (colBreaks == null) { + if (colBreaks == null) { int loc = findFirstRecordLocBySid(WindowTwoRecord.sid); colBreaks = new PageBreakRecord(PageBreakRecord.VERTICAL_SID); records.add(loc, colBreaks); - } - colBreaks.addBreak(column, fromRow, toRow); + } + colBreaks.addBreak(column, fromRow, toRow); } /** @@ -2923,10 +2687,10 @@ public class Sheet implements Model * */ public void removeColumnBreak(short column) { - if (colBreaks == null) - throw new IllegalArgumentException("Sheet does not define any column breaks"); - - colBreaks.removeBreak(column); + if (colBreaks == null) + throw new IllegalArgumentException("Sheet does not define any column breaks"); + + colBreaks.removeBreak(column); } /** @@ -2935,9 +2699,9 @@ public class Sheet implements Model * @return true if the specified column has a page break */ public boolean isColumnBroken(short column) { - return (colBreaks == null) ? false : colBreaks.getBreak(column) != null; + return (colBreaks == null) ? false : colBreaks.getBreak(column) != null; } - + /** * Shifts the horizontal page breaks for the indicated count * @param startingRow @@ -2945,7 +2709,7 @@ public class Sheet implements Model * @param count */ public void shiftRowBreaks(int startingRow, int endingRow, int count) { - shiftBreaks(rowBreaks, (short)startingRow, (short)endingRow, (short)count); + shiftBreaks(rowBreaks, (short)startingRow, (short)endingRow, (short)count); } /** @@ -2955,39 +2719,39 @@ public class Sheet implements Model * @param count */ public void shiftColumnBreaks(short startingCol, short endingCol, short count) { - shiftBreaks(colBreaks, startingCol, endingCol, count); + shiftBreaks(colBreaks, startingCol, endingCol, count); } - + /** * Returns all the row page breaks * @return all the row page breaks */ public Iterator getRowBreaks() { - return rowBreaks.getBreaksIterator(); + return rowBreaks.getBreaksIterator(); } - + /** * Returns the number of row page breaks * @return the number of row page breaks */ public int getNumRowBreaks(){ - return (rowBreaks == null) ? 0 : (int)rowBreaks.getNumBreaks(); + return (rowBreaks == null) ? 0 : (int)rowBreaks.getNumBreaks(); } - + /** * Returns all the column page breaks * @return all the column page breaks */ public Iterator getColumnBreaks(){ - return colBreaks.getBreaksIterator(); + return colBreaks.getBreaksIterator(); } - + /** * Returns the number of column page breaks * @return the number of column page breaks */ public int getNumColumnBreaks(){ - return (colBreaks == null) ? 0 : (int)colBreaks.getNumBreaks(); + return (colBreaks == null) ? 0 : (int)colBreaks.getNumBreaks(); } public void setColumnGroupCollapsed( short columnNumber, boolean collapsed ) @@ -3030,213 +2794,40 @@ public class Sheet implements Model records.add(protIdx+2,srec); scenprotect = srec; } - } + } /** - * unprotect objects in the sheet (will not protect them, but any set to false are + * unprotect objects in the sheet (will not protect them, but any set to false are * unprotected. * @param sheet is unprotected (false = unprotect) * @param objects are unprotected (false = unprotect) * @param scenarios are unprotected (false = unprotect) */ public void unprotectSheet( boolean sheet, boolean objects, boolean scenarios ) { - int protIdx = -1; + if (!sheet) { ProtectRecord prec = getProtect(); prec.setProtect(sheet); PasswordRecord pass = getPassword(); pass.setPassword((short)00); - } + } if(objprotect != null && !objects) { objprotect.setProtect(false); } if(scenprotect != null && !scenarios) { scenprotect.setProtect(false); } - } + } /** * @return {sheet is protected, objects are proteced, scenarios are protected} */ public boolean[] isProtected() { - return new boolean[] { (protect != null && protect.getProtect()), + return new boolean[] { (protect != null && protect.getProtect()), (objprotect != null && objprotect.getProtect()), (scenprotect != null && scenprotect.getProtect())}; } - -// private void collapseColumn( short columnNumber ) -// { -// int idx = findColumnIdx( columnNumber, 0 ); -// if (idx == -1) -// return; -// -// // Find the start of the group. -// ColumnInfoRecord columnInfo = (ColumnInfoRecord) columnSizes.get( findStartOfColumnOutlineGroup( idx ) ); -// -// // Hide all the columns until the end of the group -// columnInfo = writeHidden( columnInfo, idx, true ); -// -// // Write collapse field -// setColumn( (short) ( columnInfo.getLastColumn() + 1 ), null, null, null, Boolean.TRUE); -// } - -// private void expandColumn( short columnNumber ) -// { -// int idx = findColumnIdx( columnNumber, 0 ); -// if (idx == -1) -// return; -// -// // If it is already exapanded do nothing. -// if (!isColumnGroupCollapsed(idx)) -// return; -// -// // Find the start of the group. -// int startIdx = findStartOfColumnOutlineGroup( idx ); -// ColumnInfoRecord columnInfo = getColInfo( startIdx ); -// -// // Find the end of the group. -// int endIdx = findEndOfColumnOutlineGroup( idx ); -// ColumnInfoRecord endColumnInfo = getColInfo( endIdx ); -// -// // expand: -// // colapsed bit must be unset -// // hidden bit gets unset _if_ surrounding groups are expanded you can determine -// // this by looking at the hidden bit of the enclosing group. You will have -// // to look at the start and the end of the current group to determine which -// // is the enclosing group -// // hidden bit only is altered for this outline level. ie. don't uncollapse contained groups -// if (!isColumnGroupHiddenByParent( idx )) -// { -// for (int i = startIdx; i <= endIdx; i++) -// { -// if (columnInfo.getOutlineLevel() == getColInfo(i).getOutlineLevel()) -// getColInfo(i).setHidden( false ); -// } -// } -// -// // Write collapse field -// setColumn( (short) ( columnInfo.getLastColumn() + 1 ), null, null, null, Boolean.FALSE); -// } - -// private boolean isColumnGroupCollapsed( int idx ) -// { -// int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup( idx ); -// if (endOfOutlineGroupIdx >= columnSizes.size()) -// return false; -// if (getColInfo(endOfOutlineGroupIdx).getLastColumn() + 1 != getColInfo(endOfOutlineGroupIdx + 1).getFirstColumn()) -// return false; -// else -// return getColInfo(endOfOutlineGroupIdx+1).getCollapsed(); -// } - -// private boolean isColumnGroupHiddenByParent( int idx ) -// { -// // Look out outline details of end -// int endLevel; -// boolean endHidden; -// int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup( idx ); -// if (endOfOutlineGroupIdx >= columnSizes.size()) -// { -// endLevel = 0; -// endHidden = false; -// } -// else if (getColInfo(endOfOutlineGroupIdx).getLastColumn() + 1 != getColInfo(endOfOutlineGroupIdx + 1).getFirstColumn()) -// { -// endLevel = 0; -// endHidden = false; -// } -// else -// { -// endLevel = getColInfo( endOfOutlineGroupIdx + 1).getOutlineLevel(); -// endHidden = getColInfo( endOfOutlineGroupIdx + 1).getHidden(); -// } -// -// // Look out outline details of start -// int startLevel; -// boolean startHidden; -// int startOfOutlineGroupIdx = findStartOfColumnOutlineGroup( idx ); -// if (startOfOutlineGroupIdx <= 0) -// { -// startLevel = 0; -// startHidden = false; -// } -// else if (getColInfo(startOfOutlineGroupIdx).getFirstColumn() - 1 != getColInfo(startOfOutlineGroupIdx - 1).getLastColumn()) -// { -// startLevel = 0; -// startHidden = false; -// } -// else -// { -// startLevel = getColInfo( startOfOutlineGroupIdx - 1).getOutlineLevel(); -// startHidden = getColInfo( startOfOutlineGroupIdx - 1 ).getHidden(); -// } -// -// if (endLevel > startLevel) -// { -// return endHidden; -// } -// else -// { -// return startHidden; -// } -// } - -// private ColumnInfoRecord getColInfo(int idx) -// { -// return columns.getColInfo( idx ); -// } - -// private int findStartOfColumnOutlineGroup(int idx) -// { -// // Find the start of the group. -// ColumnInfoRecord columnInfo = (ColumnInfoRecord) columnSizes.get( idx ); -// int level = columnInfo.getOutlineLevel(); -// while (idx != 0) -// { -// ColumnInfoRecord prevColumnInfo = (ColumnInfoRecord) columnSizes.get( idx - 1 ); -// if (columnInfo.getFirstColumn() - 1 == prevColumnInfo.getLastColumn()) -// { -// if (prevColumnInfo.getOutlineLevel() < level) -// { -// break; -// } -// idx--; -// columnInfo = prevColumnInfo; -// } -// else -// { -// break; -// } -// } -// -// return idx; -// } - -// private int findEndOfColumnOutlineGroup(int idx) -// { -// // Find the end of the group. -// ColumnInfoRecord columnInfo = (ColumnInfoRecord) columnSizes.get( idx ); -// int level = columnInfo.getOutlineLevel(); -// while (idx < columnSizes.size() - 1) -// { -// ColumnInfoRecord nextColumnInfo = (ColumnInfoRecord) columnSizes.get( idx + 1 ); -// if (columnInfo.getLastColumn() + 1 == nextColumnInfo.getFirstColumn()) -// { -// if (nextColumnInfo.getOutlineLevel() < level) -// { -// break; -// } -// idx++; -// columnInfo = nextColumnInfo; -// } -// else -// { -// break; -// } -// } -// -// return idx; -// } + public void groupRowRange(int fromRow, int toRow, boolean indent) { @@ -3272,8 +2863,8 @@ public class Sheet implements Model // Grab the guts record, adding if needed GutsRecord guts = (GutsRecord) findFirstRecordBySid( GutsRecord.sid ); if(guts == null) { - guts = new GutsRecord(); - records.add(guts); + guts = new GutsRecord(); + records.add(guts); } // Set the levels onto it guts.setRowLevelMax( (short) ( maxLevel + 1 ) ); @@ -3291,126 +2882,4 @@ public class Sheet implements Model rows.expandRow( row ); } } - - -// private void collapseRow( int rowNumber ) -// { -// -// // Find the start of the group. -// int startRow = rows.findStartOfRowOutlineGroup( rowNumber ); -// RowRecord rowRecord = (RowRecord) rows.getRow( startRow ); -// -// // Hide all the columns until the end of the group -// int lastRow = rows.writeHidden( rowRecord, startRow, true ); -// -// // Write collapse field -// if (getRow(lastRow + 1) != null) -// { -// getRow(lastRow + 1).setColapsed( true ); -// } -// else -// { -// RowRecord row = createRow( lastRow + 1); -// row.setColapsed( true ); -// rows.insertRow( row ); -// } -// } - -// private int findStartOfRowOutlineGroup(int row) -// { -// // Find the start of the group. -// RowRecord rowRecord = rows.getRow( row ); -// int level = rowRecord.getOutlineLevel(); -// int currentRow = row; -// while (rows.getRow( currentRow ) != null) -// { -// rowRecord = rows.getRow( currentRow ); -// if (rowRecord.getOutlineLevel() < level) -// return currentRow + 1; -// currentRow--; -// } -// -// return currentRow + 1; -// } - -// private int writeHidden( RowRecord rowRecord, int row, boolean hidden ) -// { -// int level = rowRecord.getOutlineLevel(); -// while (rowRecord != null && rows.getRow(row).getOutlineLevel() >= level) -// { -// rowRecord.setZeroHeight( hidden ); -// row++; -// rowRecord = rows.getRow( row ); -// } -// return row - 1; -// } - -// private int findEndOfRowOutlineGroup( int row ) -// { -// int level = getRow( row ).getOutlineLevel(); -// int currentRow; -// for (currentRow = row; currentRow < rows.getLastRowNum(); currentRow++) -// { -// if (getRow(currentRow) == null || getRow(currentRow).getOutlineLevel() < level) -// { -// break; -// } -// } -// -// return currentRow-1; -// } - -// private boolean isRowGroupCollapsed( int row ) -// { -// int collapseRow = rows.findEndOfRowOutlineGroup( row ) + 1; -// -// if (getRow(collapseRow) == null) -// return false; -// else -// return getRow( collapseRow ).getColapsed(); -// } - - -// private boolean isRowGroupHiddenByParent( int row ) -// { -// // Look out outline details of end -// int endLevel; -// boolean endHidden; -// int endOfOutlineGroupIdx = rows.findEndOfRowOutlineGroup( row ); -// if (getRow( endOfOutlineGroupIdx + 1 ) == null) -// { -// endLevel = 0; -// endHidden = false; -// } -// else -// { -// endLevel = getRow( endOfOutlineGroupIdx + 1).getOutlineLevel(); -// endHidden = getRow( endOfOutlineGroupIdx + 1).getZeroHeight(); -// } -// -// // Look out outline details of start -// int startLevel; -// boolean startHidden; -// int startOfOutlineGroupIdx = rows.findStartOfRowOutlineGroup( row ); -// if (startOfOutlineGroupIdx - 1 < 0 || getRow(startOfOutlineGroupIdx - 1) == null) -// { -// startLevel = 0; -// startHidden = false; -// } -// else -// { -// startLevel = getRow( startOfOutlineGroupIdx - 1).getOutlineLevel(); -// startHidden = getRow( startOfOutlineGroupIdx - 1 ).getZeroHeight(); -// } -// -// if (endLevel > startLevel) -// { -// return endHidden; -// } -// else -// { -// return startHidden; -// } -// } - } diff --git a/src/java/org/apache/poi/hssf/record/PaneRecord.java b/src/java/org/apache/poi/hssf/record/PaneRecord.java index 6f13ad0922..f02e411655 100644 --- a/src/java/org/apache/poi/hssf/record/PaneRecord.java +++ b/src/java/org/apache/poi/hssf/record/PaneRecord.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -15,13 +14,12 @@ 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.*; +import org.apache.poi.util.HexDump; +import org.apache.poi.util.LittleEndian; /** * Describes the frozen and unfozen panes. @@ -30,9 +28,7 @@ import org.apache.poi.util.*; * @author Glen Stampoultzis (glens at apache.org) */ -public class PaneRecord - extends Record -{ +public final class PaneRecord extends Record { public final static short sid = 0x41; private short field_1_x; private short field_2_y; @@ -42,7 +38,10 @@ public class PaneRecord public final static short ACTIVE_PANE_LOWER_RIGHT = 0; public final static short ACTIVE_PANE_UPPER_RIGHT = 1; public final static short ACTIVE_PANE_LOWER_LEFT = 2; + // TODO - remove obsolete field (it was deprecated May-2008 v3.1) + /** @deprecated use ACTIVE_PANE_UPPER_LEFT */ public final static short ACTIVE_PANE_UPER_LEFT = 3; + public final static short ACTIVE_PANE_UPPER_LEFT = 3; public PaneRecord() @@ -82,7 +81,6 @@ public class PaneRecord field_3_topRow = in.readShort(); field_4_leftColumn = in.readShort(); field_5_activePane = in.readShort(); - } public String toString() @@ -229,7 +227,7 @@ public class PaneRecord * ACTIVE_PANE_LOWER_RIGHT * ACTIVE_PANE_UPPER_RIGHT * ACTIVE_PANE_LOWER_LEFT - * ACTIVE_PANE_UPER_LEFT + * ACTIVE_PANE_UPPER_LEFT */ public short getActivePane() { @@ -244,16 +242,10 @@ public class PaneRecord * ACTIVE_PANE_LOWER_RIGHT * ACTIVE_PANE_UPPER_RIGHT * ACTIVE_PANE_LOWER_LEFT - * ACTIVE_PANE_UPER_LEFT + * ACTIVE_PANE_UPPER_LEFT */ public void setActivePane(short field_5_activePane) { this.field_5_activePane = field_5_activePane; } - - -} // END OF CLASS - - - - +} diff --git a/src/java/org/apache/poi/hssf/record/RowRecord.java b/src/java/org/apache/poi/hssf/record/RowRecord.java index a2815d2873..cbfc0ec594 100644 --- a/src/java/org/apache/poi/hssf/record/RowRecord.java +++ b/src/java/org/apache/poi/hssf/record/RowRecord.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -15,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record; @@ -31,20 +29,18 @@ import org.apache.poi.util.LittleEndian; * @author Jason Height (jheight at chariot dot net dot au) * @version 2.0-pre */ - -public class RowRecord - extends Record - implements Comparable -{ - public final static short sid = 0x208; +public final class RowRecord extends Record implements Comparable { + public final static short sid = 0x208; - /** The maximum row number that excel can handle (zero bazed) ie 65536 rows is + private static final int OPTION_BITS_ALWAYS_SET = 0x0100; + private static final int DEFAULT_HEIGHT_BIT = 0x8000; + + /** The maximum row number that excel can handle (zero based) ie 65536 rows is * max number of rows. */ public final static int MAX_ROW_NUMBER = 65535; - //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; @@ -52,7 +48,8 @@ public class RowRecord // for generated sheets. private short field_6_reserved; - private short field_7_option_flags; + /** 16 bit options flags */ + private int field_7_option_flags; private static final BitField outlineLevel = BitFieldFactory.getInstance(0x07); // bit 3 reserved @@ -62,8 +59,17 @@ public class RowRecord private static final BitField formatted = BitFieldFactory.getInstance(0x80); private short field_8_xf_index; // only if isFormatted - public RowRecord() - { + public RowRecord(int rowNumber) { + field_1_row_number = rowNumber; + field_2_first_col = -1; + field_3_last_col = -1; + field_4_height = (short)DEFAULT_HEIGHT_BIT; + field_4_height = (short)DEFAULT_HEIGHT_BIT; + field_5_optimize = ( short ) 0; + field_6_reserved = ( short ) 0; + field_7_option_flags = OPTION_BITS_ALWAYS_SET; // seems necessary for outlining + + field_8_xf_index = ( short ) 0xf; } /** @@ -86,7 +92,6 @@ public class RowRecord protected void fillFields(RecordInputStream in) { - //field_1_row_number = LittleEndian.getShort(data, 0 + offset); field_1_row_number = in.readUShort(); field_2_first_col = in.readShort(); field_3_last_col = in.readShort(); @@ -156,7 +161,7 @@ public class RowRecord public void setOptionFlags(short options) { - field_7_option_flags = options; + field_7_option_flags = options | OPTION_BITS_ALWAYS_SET; } // option bitfields @@ -169,20 +174,18 @@ public class RowRecord public void setOutlineLevel(short ol) { - field_7_option_flags = - outlineLevel.setShortValue(field_7_option_flags, ol); + field_7_option_flags = outlineLevel.setValue(field_7_option_flags, ol); } /** - * set whether or not to colapse this row - * @param c - colapse or not + * set whether or not to collapse this row + * @param c - collapse or not * @see #setOptionFlags(short) */ public void setColapsed(boolean c) { - field_7_option_flags = colapsed.setShortBoolean(field_7_option_flags, - c); + field_7_option_flags = colapsed.setBoolean(field_7_option_flags, c); } /** @@ -193,8 +196,7 @@ public class RowRecord public void setZeroHeight(boolean z) { - field_7_option_flags = - zeroHeight.setShortBoolean(field_7_option_flags, z); + field_7_option_flags = zeroHeight.setBoolean(field_7_option_flags, z); } /** @@ -205,8 +207,7 @@ public class RowRecord public void setBadFontHeight(boolean f) { - field_7_option_flags = - badFontHeight.setShortBoolean(field_7_option_flags, f); + field_7_option_flags = badFontHeight.setBoolean(field_7_option_flags, f); } /** @@ -217,8 +218,7 @@ public class RowRecord public void setFormatted(boolean f) { - field_7_option_flags = formatted.setShortBoolean(field_7_option_flags, - f); + field_7_option_flags = formatted.setBoolean(field_7_option_flags, f); } // end bitfields @@ -293,7 +293,7 @@ public class RowRecord public short getOptionFlags() { - return field_7_option_flags; + return (short)field_7_option_flags; } // option bitfields @@ -306,7 +306,7 @@ public class RowRecord public short getOutlineLevel() { - return outlineLevel.getShortValue(field_7_option_flags); + return (short)outlineLevel.getValue(field_7_option_flags); } /** @@ -410,7 +410,6 @@ public class RowRecord { LittleEndian.putShort(data, 0 + offset, sid); LittleEndian.putShort(data, 2 + offset, ( short ) 16); - //LittleEndian.putShort(data, 4 + offset, getRowNumber()); LittleEndian.putShort(data, 4 + offset, ( short ) getRowNumber()); LittleEndian.putShort(data, 6 + offset, getFirstCol() == -1 ? (short)0 : getFirstCol()); LittleEndian.putShort(data, 8 + offset, getLastCol() == -1 ? (short)0 : getLastCol()); @@ -419,7 +418,6 @@ public class RowRecord LittleEndian.putShort(data, 14 + offset, field_6_reserved); LittleEndian.putShort(data, 16 + offset, getOptionFlags()); -// LittleEndian.putShort(data,18,getOutlineLevel()); LittleEndian.putShort(data, 18 + offset, getXFIndex()); return getRecordSize(); } @@ -469,8 +467,7 @@ public class RowRecord } public Object clone() { - RowRecord rec = new RowRecord(); - rec.field_1_row_number = field_1_row_number; + RowRecord rec = new RowRecord(field_1_row_number); rec.field_2_first_col = field_2_first_col; rec.field_3_last_col = field_3_last_col; rec.field_4_height = field_4_height; diff --git a/src/java/org/apache/poi/hssf/record/WindowOneRecord.java b/src/java/org/apache/poi/hssf/record/WindowOneRecord.java index f101cb59af..4c836f2ee8 100644 --- a/src/java/org/apache/poi/hssf/record/WindowOneRecord.java +++ b/src/java/org/apache/poi/hssf/record/WindowOneRecord.java @@ -57,8 +57,8 @@ public class WindowOneRecord BitFieldFactory.getInstance(0x20); // display tabs at the bottom // all the rest are "reserved" - private short field_6_selected_tab; - private short field_7_displayed_tab; + private int field_6_active_sheet; + private int field_7_first_visible_tab; private short field_8_num_selected_tabs; private short field_9_tab_width_ratio; @@ -91,8 +91,8 @@ public class WindowOneRecord field_3_width = in.readShort(); field_4_height = in.readShort(); field_5_options = in.readShort(); - field_6_selected_tab = in.readShort(); - field_7_displayed_tab = in.readShort(); + field_6_active_sheet = in.readShort(); + field_7_first_visible_tab = in.readShort(); field_8_num_selected_tabs = in.readShort(); field_9_tab_width_ratio = in.readShort(); } @@ -202,24 +202,33 @@ public class WindowOneRecord // end bitfields + public void setActiveSheetIndex(int index) { + field_6_active_sheet = index; + } /** - * set the selected tab number - * @param s tab number + * deprecated May 2008 + * @deprecated - Misleading name - use setActiveSheetIndex() */ - public void setSelectedTab(short s) { - field_6_selected_tab = s; + setActiveSheetIndex(s); } /** - * set the displayed tab number - * @param t tab number + * Sets the first visible sheet in the worksheet tab-bar. This method does not + * hide, select or focus sheets. It just sets the scroll position in the tab-bar. + * @param t the sheet index of the tab that will become the first in the tab-bar */ + public void setFirstVisibleTab(int t) { + field_7_first_visible_tab = t; + } - public void setDisplayedTab(short t) - { - field_7_displayed_tab = t; + /** + * deprecated May 2008 + * @deprecated - Misleading name - use setFirstVisibleTab() + */ + public void setDisplayedTab(short t) { + setFirstVisibleTab(t); } /** @@ -347,24 +356,36 @@ public class WindowOneRecord // end options bitfields + /** - * get the selected tab number - * @return Tab number + * @return the index of the currently displayed sheet + */ + public int getActiveSheetIndex() { + return field_6_active_sheet; + } + /** + * deprecated May 2008 + * @deprecated - Misleading name - use getActiveSheetIndex() */ - public short getSelectedTab() { - return field_6_selected_tab; + return (short) getActiveSheetIndex(); } /** - * get the displayed tab number - * @return Tab number + * @return the first visible sheet in the worksheet tab-bar. + * I.E. the scroll position of the tab-bar. + */ + public int getFirstVisibleTab() { + return field_7_first_visible_tab; + } + /** + * deprecated May 2008 + * @deprecated - Misleading name - use getFirstVisibleTab() */ - public short getDisplayedTab() { - return field_7_displayed_tab; + return (short) getFirstVisibleTab(); } /** @@ -412,10 +433,10 @@ public class WindowOneRecord .append(getDisplayVerticalScrollbar()).append("\n"); buffer.append(" .tabs = ").append(getDisplayTabs()) .append("\n"); - buffer.append(" .selectedtab = ") - .append(Integer.toHexString(getSelectedTab())).append("\n"); - buffer.append(" .displayedtab = ") - .append(Integer.toHexString(getDisplayedTab())).append("\n"); + buffer.append(" .activeSheet = ") + .append(Integer.toHexString(getActiveSheetIndex())).append("\n"); + buffer.append(" .firstVisibleTab = ") + .append(Integer.toHexString(getFirstVisibleTab())).append("\n"); buffer.append(" .numselectedtabs = ") .append(Integer.toHexString(getNumSelectedTabs())).append("\n"); buffer.append(" .tabwidthratio = ") @@ -434,8 +455,8 @@ public class WindowOneRecord LittleEndian.putShort(data, 8 + offset, getWidth()); LittleEndian.putShort(data, 10 + offset, getHeight()); LittleEndian.putShort(data, 12 + offset, getOptions()); - LittleEndian.putShort(data, 14 + offset, getSelectedTab()); - LittleEndian.putShort(data, 16 + offset, getDisplayedTab()); + LittleEndian.putUShort(data, 14 + offset, getActiveSheetIndex()); + LittleEndian.putUShort(data, 16 + offset, getFirstVisibleTab()); LittleEndian.putShort(data, 18 + offset, getNumSelectedTabs()); LittleEndian.putShort(data, 20 + offset, getTabWidthRatio()); return getRecordSize(); diff --git a/src/java/org/apache/poi/hssf/record/WindowTwoRecord.java b/src/java/org/apache/poi/hssf/record/WindowTwoRecord.java index f6b51996d5..e2bb6d5609 100644 --- a/src/java/org/apache/poi/hssf/record/WindowTwoRecord.java +++ b/src/java/org/apache/poi/hssf/record/WindowTwoRecord.java @@ -54,7 +54,7 @@ public class WindowTwoRecord private BitField displayGuts = BitFieldFactory.getInstance(0x80); private BitField freezePanesNoSplit = BitFieldFactory.getInstance(0x100); private BitField selected = BitFieldFactory.getInstance(0x200); - private BitField paged = BitFieldFactory.getInstance(0x400); + private BitField active = BitFieldFactory.getInstance(0x400); private BitField savedInPageBreakPreview = BitFieldFactory.getInstance(0x800); // 4-7 reserved @@ -222,12 +222,16 @@ public class WindowTwoRecord * is the sheet currently displayed in the window * @param p displayed or not */ - - public void setPaged(boolean p) - { - field_1_options = paged.setShortBoolean(field_1_options, p); + public void setActive(boolean p) { + field_1_options = active.setShortBoolean(field_1_options, p); + } + /** + * deprecated May 2008 + * @deprecated use setActive() + */ + public void setPaged(boolean p) { + setActive(p); } - /** * was the sheet saved in page break view * @param p pagebreaksaved or not @@ -416,9 +420,15 @@ public class WindowTwoRecord * @return displayed or not */ - public boolean getPaged() - { - return paged.isSet(field_1_options); + public boolean isActive() { + return active.isSet(field_1_options); + } + /** + * deprecated May 2008 + * @deprecated use isActive() + */ + public boolean getPaged() { + return isActive(); } /** @@ -520,7 +530,7 @@ public class WindowTwoRecord .append(getFreezePanesNoSplit()).append("\n"); buffer.append(" .selected = ").append(getSelected()) .append("\n"); - buffer.append(" .paged = ").append(getPaged()) + buffer.append(" .active = ").append(isActive()) .append("\n"); buffer.append(" .svdinpgbrkpv= ") .append(getSavedInPageBreakPreview()).append("\n"); diff --git a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java index bed1f0748e..65af632d3f 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java @@ -35,19 +35,17 @@ import java.util.TreeMap; * @author Jason Height (jheight at chariot dot net dot au) */ -public class RowRecordsAggregate - extends Record -{ - int firstrow = -1; - int lastrow = -1; - Map records = null; - int size = 0; +public final class RowRecordsAggregate extends Record { + private int firstrow = -1; + private int lastrow = -1; + private Map records = null; // TODO - use a proper key in this map + private int size = 0; /** Creates a new instance of ValueRecordsAggregate */ public RowRecordsAggregate() { - records = new TreeMap(); + records = new TreeMap(); } public void insertRow(RowRecord row) @@ -74,15 +72,13 @@ public class RowRecordsAggregate records.remove(row); } - public RowRecord getRow(int rownum) - { - // Row must be between 0 and 65535 - if(rownum < 0 || rownum > 65535) { - throw new IllegalArgumentException("The row number must be between 0 and 65535"); - } + public RowRecord getRow(int rownum) { + // Row must be between 0 and 65535 + if(rownum < 0 || rownum > 65535) { + throw new IllegalArgumentException("The row number must be between 0 and 65535"); + } - RowRecord row = new RowRecord(); - row.setRowNumber(rownum); + RowRecord row = new RowRecord(rownum); return ( RowRecord ) records.get(row); } @@ -333,7 +329,7 @@ public class RowRecordsAggregate // Find the start of the group. int startRow = findStartOfRowOutlineGroup( rowNumber ); - RowRecord rowRecord = (RowRecord) getRow( startRow ); + RowRecord rowRecord = getRow( startRow ); // Hide all the columns until the end of the group int lastRow = writeHidden( rowRecord, startRow, true ); @@ -358,17 +354,8 @@ public class RowRecordsAggregate * @return RowRecord created for the passed in row number * @see org.apache.poi.hssf.record.RowRecord */ - public static RowRecord createRow(int row) - { - RowRecord rowrec = new RowRecord(); - - //rowrec.setRowNumber(( short ) row); - rowrec.setRowNumber(row); - rowrec.setHeight(( short ) 0xff); - rowrec.setOptimize(( short ) 0x0); - rowrec.setOptionFlags(( short ) 0x100); // seems necessary for outlining - rowrec.setXFIndex(( short ) 0xf); - return rowrec; + public static RowRecord createRow(int rowNumber) { + return new RowRecord(rowNumber); } public boolean isRowGroupCollapsed( int row ) @@ -399,12 +386,12 @@ public class RowRecordsAggregate int endIdx = findEndOfRowOutlineGroup( idx ); // expand: - // colapsed bit must be unset + // collapsed bit must be unset // hidden bit gets unset _if_ surrounding groups are expanded you can determine // this by looking at the hidden bit of the enclosing group. You will have // to look at the start and the end of the current group to determine which // is the enclosing group - // hidden bit only is altered for this outline level. ie. don't uncollapse contained groups + // hidden bit only is altered for this outline level. ie. don't un-collapse contained groups if ( !isRowGroupHiddenByParent( idx ) ) { for ( int i = startIdx; i <= endIdx; i++ ) diff --git a/src/java/org/apache/poi/hssf/record/formula/FuncPtg.java b/src/java/org/apache/poi/hssf/record/formula/FuncPtg.java index 7901fb675d..364ddf5a02 100644 --- a/src/java/org/apache/poi/hssf/record/formula/FuncPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/FuncPtg.java @@ -32,18 +32,6 @@ public final class FuncPtg extends AbstractFunctionPtg { public final static int SIZE = 3; private int numParams=0; - /** - * FuncPtgs are defined to be 4 bytes but the actual FuncPtg uses only 2 bytes. - * If we have leftOvers that are read from the file we should serialize them back out. - *

- * If the leftovers are removed, a prompt "Warning: Data may have been lost occurs in Excel" - */ - //protected byte[] leftOvers = null; - - private FuncPtg() { - //Required for clone methods - } - /**Creates new function pointer from a byte array * usually called while reading an excel file. */ @@ -75,11 +63,9 @@ public final class FuncPtg extends AbstractFunctionPtg { } public Object clone() { - FuncPtg ptg = new FuncPtg(); - //ptg.field_1_num_args = field_1_num_args; - ptg.field_2_fnc_index = field_2_fnc_index; - ptg.setClass(ptgClass); - return ptg; + FuncPtg ptg = new FuncPtg(field_2_fnc_index); + ptg.setClass(ptgClass); + return ptg; } public int getSize() { diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/Area2DEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/Area2DEval.java index 4b9a64c1c0..5ae98b39fe 100644 --- a/src/java/org/apache/poi/hssf/record/formula/eval/Area2DEval.java +++ b/src/java/org/apache/poi/hssf/record/formula/eval/Area2DEval.java @@ -22,79 +22,11 @@ import org.apache.poi.hssf.record.formula.Ptg; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * + * */ -public final class Area2DEval implements AreaEval { -// TODO -refactor with Area3DEval - private final AreaPtg _delegate; +public final class Area2DEval extends AreaEvalBase { - private final ValueEval[] _values; - - public Area2DEval(Ptg ptg, ValueEval[] values) { - if(ptg == null) { - throw new IllegalArgumentException("ptg must not be null"); - } - if(values == null) { - throw new IllegalArgumentException("values must not be null"); - } - for(int i=values.length-1; i>=0; i--) { - if(values[i] == null) { - throw new IllegalArgumentException("value array elements must not be null"); - } - } - // TODO - check size of array vs size of AreaPtg - _delegate = (AreaPtg) ptg; - _values = values; - } - - public int getFirstColumn() { - return _delegate.getFirstColumn(); - } - - public int getFirstRow() { - return _delegate.getFirstRow(); - } - - public int getLastColumn() { - return _delegate.getLastColumn(); - } - - public int getLastRow() { - return _delegate.getLastRow(); - } - - public ValueEval[] getValues() { - return _values; - } - - public ValueEval getValueAt(int row, int col) { - ValueEval retval; - int index = ((row-getFirstRow())*(getLastColumn()-getFirstColumn()+1))+(col-getFirstColumn()); - if (index <0 || index >= _values.length) - retval = ErrorEval.VALUE_INVALID; - else - retval = _values[index]; - return retval; - } - - public boolean contains(int row, int col) { - return (getFirstRow() <= row) && (getLastRow() >= row) - && (getFirstColumn() <= col) && (getLastColumn() >= col); - } - - public boolean containsRow(int row) { - return (getFirstRow() <= row) && (getLastRow() >= row); - } - - public boolean containsColumn(short col) { - return (getFirstColumn() <= col) && (getLastColumn() >= col); - } - - public boolean isColumn() { - return _delegate.getFirstColumn() == _delegate.getLastColumn(); - } - - public boolean isRow() { - return _delegate.getFirstRow() == _delegate.getLastRow(); - } -} + public Area2DEval(Ptg ptg, ValueEval[] values) { + super((AreaPtg) ptg, values); + } +} \ No newline at end of file diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/Area3DEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/Area3DEval.java index 2f539142d1..89209e21b6 100644 --- a/src/java/org/apache/poi/hssf/record/formula/eval/Area3DEval.java +++ b/src/java/org/apache/poi/hssf/record/formula/eval/Area3DEval.java @@ -22,84 +22,18 @@ import org.apache.poi.hssf.record.formula.Ptg; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - * + * */ -public final class Area3DEval implements AreaEval { - // TODO -refactor with Area3DEval - private final Area3DPtg _delegate; +public final class Area3DEval extends AreaEvalBase { - private final ValueEval[] _values; + private final int _externSheetIndex; - public Area3DEval(Ptg ptg, ValueEval[] values) { - if(ptg == null) { - throw new IllegalArgumentException("ptg must not be null"); - } - if(values == null) { - throw new IllegalArgumentException("values must not be null"); - } - for(int i=values.length-1; i>=0; i--) { - if(values[i] == null) { - throw new IllegalArgumentException("value array elements must not be null"); - } - } - // TODO - check size of array vs size of AreaPtg - _values = values; - _delegate = (Area3DPtg) ptg; - } + public Area3DEval(Ptg ptg, ValueEval[] values) { + super((Area3DPtg) ptg, values); + _externSheetIndex = ((Area3DPtg) ptg).getExternSheetIndex(); + } - public int getFirstColumn() { - return _delegate.getFirstColumn(); - } - - public int getFirstRow() { - return _delegate.getFirstRow(); - } - - public int getLastColumn() { - return (short) _delegate.getLastColumn(); - } - - public int getLastRow() { - return _delegate.getLastRow(); - } - - public ValueEval[] getValues() { - return _values; - } - - public ValueEval getValueAt(int row, int col) { - ValueEval retval; - int index = (row-getFirstRow())*(col-getFirstColumn()); - if (index <0 || index >= _values.length) - retval = ErrorEval.VALUE_INVALID; - else - retval = _values[index]; - return retval; - } - - public boolean contains(int row, int col) { - return (getFirstRow() <= row) && (getLastRow() >= row) - && (getFirstColumn() <= col) && (getLastColumn() >= col); - } - - public boolean containsRow(int row) { - return (getFirstRow() <= row) && (getLastRow() >= row); - } - - public boolean containsColumn(short col) { - return (getFirstColumn() <= col) && (getLastColumn() >= col); - } - - - public boolean isColumn() { - return _delegate.getFirstColumn() == _delegate.getLastColumn(); - } - - public boolean isRow() { - return _delegate.getFirstRow() == _delegate.getLastRow(); - } - - public int getExternSheetIndex() { - return _delegate.getExternSheetIndex(); - } + public int getExternSheetIndex() { + return _externSheetIndex; + } } diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/AreaEvalBase.java b/src/java/org/apache/poi/hssf/record/formula/eval/AreaEvalBase.java new file mode 100644 index 0000000000..9436ae0aa9 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/formula/eval/AreaEvalBase.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.poi.hssf.record.formula.eval; + +import org.apache.poi.hssf.record.formula.AreaI; + +/** + * @author Josh Micich + */ +abstract class AreaEvalBase implements AreaEval { + + private final int _firstColumn; + private final int _firstRow; + private final int _lastColumn; + private final int _lastRow; + private final ValueEval[] _values; + private final int _nColumns; + private final int _nRows; + + protected AreaEvalBase(AreaI ptg, ValueEval[] values) { + if (values == null) { + throw new IllegalArgumentException("values must not be null"); + } + _firstRow = ptg.getFirstRow(); + _firstColumn = ptg.getFirstColumn(); + _lastRow = ptg.getLastRow(); + _lastColumn = ptg.getLastColumn(); + + _nColumns = _lastColumn - _firstColumn + 1; + _nRows = _lastRow - _firstRow + 1; + + int expectedItemCount = _nRows * _nColumns; + if ((values.length != expectedItemCount)) { + // Note - this math may need alteration when POI starts to support full column or full row refs + throw new IllegalArgumentException("Array size should be (" + expectedItemCount + + ") but was (" + values.length + ")"); + } + + + + for (int i = values.length - 1; i >= 0; i--) { + if (values[i] == null) { + throw new IllegalArgumentException("value array elements must not be null"); + } + } + _values = values; + } + + public final int getFirstColumn() { + return _firstColumn; + } + + public final int getFirstRow() { + return _firstRow; + } + + public final int getLastColumn() { + return _lastColumn; + } + + public final int getLastRow() { + return _lastRow; + } + + public final ValueEval[] getValues() { + // TODO - clone() - but some junits rely on not cloning at the moment + return _values; + } + + public final ValueEval getValueAt(int row, int col) { + int rowOffsetIx = row - _firstRow; + int colOffsetIx = col - _firstColumn; + + if(rowOffsetIx < 0 || rowOffsetIx >= _nRows) { + throw new IllegalArgumentException("Specified row index (" + row + + ") is outside the allowed range (" + _firstRow + ".." + _lastRow + ")"); + } + if(colOffsetIx < 0 || colOffsetIx >= _nColumns) { + throw new IllegalArgumentException("Specified column index (" + col + + ") is outside the allowed range (" + _firstColumn + ".." + col + ")"); + } + + int index = rowOffsetIx * _nColumns + colOffsetIx; + return _values[index]; + } + + public final boolean contains(int row, int col) { + return _firstRow <= row && _lastRow >= row + && _firstColumn <= col && _lastColumn >= col; + } + + public final boolean containsRow(int row) { + return (_firstRow <= row) && (_lastRow >= row); + } + + public final boolean containsColumn(short col) { + return (_firstColumn <= col) && (_lastColumn >= col); + } + + public final boolean isColumn() { + return _firstColumn == _lastColumn; + } + + public final boolean isRow() { + return _firstRow == _lastRow; + } +} diff --git a/src/java/org/apache/poi/hssf/record/formula/function/FunctionMetadataReader.java b/src/java/org/apache/poi/hssf/record/formula/function/FunctionMetadataReader.java index 9ea428c8df..5ce7327199 100644 --- a/src/java/org/apache/poi/hssf/record/formula/function/FunctionMetadataReader.java +++ b/src/java/org/apache/poi/hssf/record/formula/function/FunctionMetadataReader.java @@ -37,15 +37,14 @@ import org.apache.poi.hssf.record.formula.Ptg; final class FunctionMetadataReader { private static final String METADATA_FILE_NAME = "functionMetadata.txt"; + + /** plain ASCII text metadata file uses three dots for ellipsis */ + private static final String ELLIPSIS = "..."; private static final Pattern TAB_DELIM_PATTERN = Pattern.compile("\t"); private static final Pattern SPACE_DELIM_PATTERN = Pattern.compile(" "); private static final byte[] EMPTY_BYTE_ARRAY = { }; - // special characters from the ooo document - private static final int CHAR_ELLIPSIS_8230 = 8230; - private static final int CHAR_NDASH_8211 = 8211; - private static final String[] DIGIT_ENDING_FUNCTION_NAMES = { // Digits at the end of a function might be due to a left-over footnote marker. // except in these cases @@ -59,10 +58,12 @@ final class FunctionMetadataReader { throw new RuntimeException("resource '" + METADATA_FILE_NAME + "' not found"); } - BufferedReader br = null; + BufferedReader br; try { br = new BufferedReader(new InputStreamReader(is,"UTF-8")); - } catch(UnsupportedEncodingException e) { /* never happens */ } + } catch(UnsupportedEncodingException e) { + throw new RuntimeException(e); + } FunctionDataBuilder fdb = new FunctionDataBuilder(400); try { @@ -127,7 +128,9 @@ final class FunctionMetadataReader { } String[] array = SPACE_DELIM_PATTERN.split(codes); int nItems = array.length; - if(array[nItems-1].charAt(0) == CHAR_ELLIPSIS_8230) { + if(ELLIPSIS.equals(array[nItems-1])) { + // final ellipsis is optional, and ignored + // (all unspecified params are assumed to be the same as the last) nItems --; } byte[] result = new byte[nItems]; @@ -141,7 +144,6 @@ final class FunctionMetadataReader { if(codes.length() == 1) { switch (codes.charAt(0)) { case '-': - case CHAR_NDASH_8211: // this is what the ooo doc has return true; } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java index 0d2cfade4c..2c82348949 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java @@ -826,8 +826,7 @@ public class HSSFCell implements Cell int row=record.getRow(); short col=record.getColumn(); short styleIndex=record.getXFIndex(); - if ((cellType != CELL_TYPE_ERROR) && (cellType != CELL_TYPE_FORMULA)) - { + if (cellType != CELL_TYPE_ERROR) { setCellType(CELL_TYPE_ERROR, false, row, col, styleIndex); } (( BoolErrRecord ) record).setValue(value); diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java b/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java index 353ba18456..d62a7c23a0 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java @@ -21,7 +21,6 @@ import java.util.Iterator; import java.util.NoSuchElementException; import org.apache.poi.hssf.model.Sheet; -import org.apache.poi.hssf.model.Workbook; import org.apache.poi.hssf.record.CellValueRecordInterface; import org.apache.poi.hssf.record.RowRecord; import org.apache.poi.ss.usermodel.Cell; @@ -39,11 +38,9 @@ public final class HSSFRow implements Comparable, Row { // used for collections public final static int INITIAL_CAPACITY = 5; - //private short rowNum; + private int rowNum; private HSSFCell[] cells=new HSSFCell[INITIAL_CAPACITY]; -// private short firstcell = -1; -// private short lastcell = -1; /** * reference to low level representation @@ -63,7 +60,8 @@ public final class HSSFRow implements Comparable, Row { private Sheet sheet; - protected HSSFRow() + // TODO - ditch this constructor + HSSFRow() { } @@ -75,18 +73,12 @@ public final class HSSFRow implements Comparable, Row { * @param rowNum the row number of this row (0 based) * @see org.apache.poi.hssf.usermodel.HSSFSheet#createRow(int) */ - - //protected HSSFRow(Workbook book, Sheet sheet, short rowNum) - protected HSSFRow(HSSFWorkbook book, Sheet sheet, int rowNum) + HSSFRow(HSSFWorkbook book, Sheet sheet, int rowNum) { this.rowNum = rowNum; this.book = book; this.sheet = sheet; - row = new RowRecord(); - row.setOptionFlags( (short)0x100 ); // seems necessary for outlining to work. - row.setHeight((short) 0xff); - row.setLastCol((short) -1); - row.setFirstCol((short) -1); + row = new RowRecord(rowNum); setRowNum(rowNum); } @@ -100,8 +92,7 @@ public final class HSSFRow implements Comparable, Row { * @param record the low level api object this row should represent * @see org.apache.poi.hssf.usermodel.HSSFSheet#createRow(int) */ - - protected HSSFRow(HSSFWorkbook book, Sheet sheet, RowRecord record) + HSSFRow(HSSFWorkbook book, Sheet sheet, RowRecord record) { this.book = book; this.sheet = sheet; @@ -219,12 +210,11 @@ public final class HSSFRow implements Comparable, Row { * @param rowNum the row number (0-based) * @throws IndexOutOfBoundsException if the row number is not within the range 0-65535. */ - - //public void setRowNum(short rowNum) - public void setRowNum(int rowNum) - { - if ((rowNum < 0) || (rowNum > RowRecord.MAX_ROW_NUMBER)) - throw new IndexOutOfBoundsException("Row number must be between 0 and "+RowRecord.MAX_ROW_NUMBER+", was <"+rowNum+">"); + public void setRowNum(int rowNum) { + if ((rowNum < 0) || (rowNum > RowRecord.MAX_ROW_NUMBER)) { + throw new IllegalArgumentException("Invalid row number (" + rowNum + + ") outside allowable range (0.." + RowRecord.MAX_ROW_NUMBER + ")"); + } this.rowNum = rowNum; if (row != null) { @@ -236,8 +226,6 @@ public final class HSSFRow implements Comparable, Row { * get row number this row represents * @return the row number (0 based) */ - - //public short getRowNum() public int getRowNum() { return rowNum; diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index 0098e03a9d..f33570c10c 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -153,6 +153,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet { int sloc = sheet.getLoc(); RowRecord row = sheet.getNextRow(); + boolean rowRecordsAlreadyPresent = row!=null; while (row != null) { @@ -177,6 +178,18 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet if ( ( lastrow == null ) || ( lastrow.getRowNum() != cval.getRow() ) ) { hrow = getRow( cval.getRow() ); + if (hrow == null) { + // Some tools (like Perl module Spreadsheet::WriteExcel - bug 41187) skip the RowRecords + // Excel, OpenOffice.org and GoogleDocs are all OK with this, so POI should be too. + if (rowRecordsAlreadyPresent) { + // if at least one row record is present, all should be present. + throw new RuntimeException("Unexpected missing row when some rows already present"); + } + // create the row record on the fly now. + RowRecord rowRec = new RowRecord(cval.getRow()); + sheet.addRow(rowRec); + hrow = createRowFromRecord(rowRec); + } } if ( hrow != null ) { @@ -982,13 +995,34 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet return new HSSFFooter( getSheet().getFooter() ); } + /** + * Note - this is not the same as whether the sheet is focused (isActive) + * @return true if this sheet is currently selected + */ + public boolean isSelected() { + return getSheet().getWindowTwo().getSelected(); + } /** * Sets whether sheet is selected. * @param sel Whether to select the sheet or deselect the sheet. */ public void setSelected( boolean sel ) { - getSheet().setSelected( sel ); + getSheet().getWindowTwo().setSelected(sel); + } + /** + * @return true if this sheet is currently focused + */ + public boolean isActive() { + return getSheet().getWindowTwo().isActive(); + } + /** + * Sets whether sheet is selected. + * @param sel Whether to select the sheet or deselect the sheet. + */ + public void setActive(boolean sel ) + { + getSheet().getWindowTwo().setActive(sel); } /** @@ -1690,6 +1724,23 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet * @param column the column index */ public void autoSizeColumn(short column) { + autoSizeColumn(column, false); + } + + /** + * Adjusts the column width to fit the contents. + * + * This process can be relatively slow on large sheets, so this should + * normally only be called once per column, at the end of your + * processing. + * + * You can specify whether the content of merged cells should be considered or ignored. + * Default is to ignore merged cells. + * + * @param column the column index + * @param useMergedCells whether to use the contents of merged cells when calculating the width of the column + */ + public void autoSizeColumn(short column, boolean useMergedCells) { AttributedString str; TextLayout layout; /** @@ -1698,13 +1749,13 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet * '0' looks to be a good choice. */ char defaultChar = '0'; - + /** * This is the multiple that the font height is scaled by when determining the * boundary of rotated text. */ double fontHeightMultiple = 2.0; - + FontRenderContext frc = new FontRenderContext(null, true, true); HSSFWorkbook wb = new HSSFWorkbook(book); @@ -1716,21 +1767,27 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet int defaultCharWidth = (int)layout.getAdvance(); double width = -1; + rows: for (Iterator it = rowIterator(); it.hasNext();) { HSSFRow row = (HSSFRow) it.next(); HSSFCell cell = row.getCell(column); - boolean isCellInMergedRegion = false; - for (int i = 0 ; i < getNumMergedRegions() && ! isCellInMergedRegion; i++) { - isCellInMergedRegion = getMergedRegionAt(i).contains(row.getRowNum(), column); + if (cell == null) continue; + + int colspan = 1; + for (int i = 0 ; i < getNumMergedRegions(); i++) { + if (getMergedRegionAt(i).contains(row.getRowNum(), column)) { + if (!useMergedCells) { + // If we're not using merged cells, skip this one and move on to the next. + continue rows; + } + cell = row.getCell(getMergedRegionAt(i).getColumnFrom()); + colspan = 1+ getMergedRegionAt(i).getColumnTo() - getMergedRegionAt(i).getColumnFrom(); + } } - if (cell == null | isCellInMergedRegion) continue; - HSSFCellStyle style = cell.getCellStyle(); HSSFFont font = wb.getFontAt(style.getFontIndex()); - //the number of spaces to indent the text in the cell - int indention = style.getIndention(); if (cell.getCellType() == HSSFCell.CELL_TYPE_STRING) { HSSFRichTextString rt = cell.getRichStringCellValue(); @@ -1763,9 +1820,9 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet trans.concatenate( AffineTransform.getScaleInstance(1, fontHeightMultiple) ); - width = Math.max(width, layout.getOutline(trans).getBounds().getWidth() / defaultCharWidth + indention); + width = Math.max(width, ((layout.getOutline(trans).getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention()); } else { - width = Math.max(width, layout.getBounds().getWidth() / defaultCharWidth + indention); + width = Math.max(width, ((layout.getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention()); } } } else { @@ -1808,19 +1865,19 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet trans.concatenate( AffineTransform.getScaleInstance(1, fontHeightMultiple) ); - width = Math.max(width, layout.getOutline(trans).getBounds().getWidth() / defaultCharWidth + indention); + width = Math.max(width, ((layout.getOutline(trans).getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention()); } else { - width = Math.max(width, layout.getBounds().getWidth() / defaultCharWidth + indention); + width = Math.max(width, ((layout.getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention()); } } } - if (width != -1) { - if (width > Short.MAX_VALUE) { //calculated width can be greater that Short.MAX_VALUE! - width = Short.MAX_VALUE; - } - sheet.setColumnWidth(column, (short) (width * 256)); + } + if (width != -1) { + if (width > Short.MAX_VALUE) { //width can be bigger that Short.MAX_VALUE! + width = Short.MAX_VALUE; } + sheet.setColumnWidth(column, (short) (width * 256)); } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index 547f761fb7..b4c3cf3c7d 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -382,16 +382,66 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm workbook.setSheetOrder(sheetname, pos); } + private void validateSheetIndex(int index) { + int lastSheetIx = sheets.size() - 1; + if (index < 0 || index > lastSheetIx) { + throw new IllegalArgumentException("Sheet index (" + + index +") is out of range (0.." + lastSheetIx + ")"); + } + } + /** - * sets the tab whose data is actually seen when the sheet is opened. - * This may be different from the "selected sheet" since excel seems to - * allow you to show the data of one sheet when another is seen "selected" - * in the tabs (at the bottom). - * @see org.apache.poi.hssf.usermodel.HSSFSheet#setSelected(boolean) - * @param index + * Selects a single sheet. This may be different to + * the 'active' sheet (which is the sheet with focus). + */ + public void setSelectedTab(int index) { + + validateSheetIndex(index); + int nSheets = sheets.size(); + for (int i=0; i - + diff --git a/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata-asGenerated.txt b/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata-asGenerated.txt index 8ec4bc62d3..475131e1c0 100644 --- a/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata-asGenerated.txt +++ b/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata-asGenerated.txt @@ -29,7 +29,7 @@ 7 MAX 1 30 V R 8 ROW 0 1 V R 9 COLUMN 0 1 V R -10 NA 0 0 V – +10 NA 0 0 V - 11 NPV 2 30 V V R 12 STDEV 1 30 V R 13 DOLLAR 1 2 V V V @@ -38,7 +38,7 @@ 16 COS 1 1 V V 17 TAN 1 1 V V 18 ARCTAN 1 1 V V -19 PI 0 0 V – +19 PI 0 0 V - 20 SQRT 1 1 V V 21 EXP 1 1 V V 22 LN 1 1 V V @@ -53,8 +53,8 @@ 31 MID 3 3 V V V V 32 LEN 1 1 V V 33 VALUE 1 1 V V -34 TRUE 0 0 V – -35 FALSE 0 0 V – +34 TRUE 0 0 V - +35 FALSE 0 0 V - 36 AND 1 30 V R 37 OR 1 30 V R 38 NOT 1 1 V V @@ -80,7 +80,7 @@ 60 RATE 3 6 V V V V V V V 61 MIRR 3 3 V R V V 62 IRR 1 2 V R V -63 RAND 0 0 V – x +63 RAND 0 0 V - x 64 MATCH 2 3 V V R R 65 DATE 3 3 V V V V 66 TIME 3 3 V V V V @@ -91,7 +91,7 @@ 71 HOUR 1 1 V V 72 MINUTE 1 1 V V 73 SECOND 1 1 V V -74 NOW 0 0 V – x +74 NOW 0 0 V - x 75 AREAS 1 1 V R 76 ROWS 1 1 V R 77 COLUMNS 1 1 V R @@ -170,10 +170,10 @@ 215 JIS 1 1 V V x 219 ADDRESS 2 5 V V V V V V 220 DAYS360 2 2 V V V x -221 TODAY 0 0 V – x +221 TODAY 0 0 V - x 222 VDB 5 7 V V V V V V V V -227 MEDIAN 1 30 V R … -228 SUMPRODUCT 1 30 V A … +227 MEDIAN 1 30 V R ... +228 SUMPRODUCT 1 30 V A ... 229 SINH 1 1 V V 230 COSH 1 1 V V 231 TANH 1 1 V V @@ -188,7 +188,7 @@ 247 DB 4 5 V V V V V V 252 FREQUENCY 2 2 A R R 261 ERROR.TYPE 1 1 V V -269 AVEDEV 1 30 V R … +269 AVEDEV 1 30 V R ... 270 BETADIST 3 5 V V V V V V 271 GAMMALN 1 1 V V 272 BETAINV 3 5 V V V V V V @@ -237,12 +237,12 @@ 315 SLOPE 2 2 V A A 316 TTEST 4 4 V A A V V 317 PROB 3 4 V A A V V -318 DEVSQ 1 30 V R … -319 GEOMEAN 1 30 V R … -320 HARMEAN 1 30 V R … -321 SUMSQ 0 30 V R … -322 KURT 1 30 V R … -323 SKEW 1 30 V R … +318 DEVSQ 1 30 V R ... +319 GEOMEAN 1 30 V R ... +320 HARMEAN 1 30 V R ... +321 SUMSQ 0 30 V R ... +322 KURT 1 30 V R ... +323 SKEW 1 30 V R ... 324 ZTEST 2 3 V R V V 325 LARGE 2 2 V R V 326 SMALL 2 2 V R V @@ -274,10 +274,10 @@ 358 GETPIVOTDATA 2 30 359 HYPERLINK 1 2 V V V 360 PHONETIC 1 1 V R -361 AVERAGEA 1 30 V R … -362 MAXA 1 30 V R … -363 MINA 1 30 V R … -364 STDEVPA 1 30 V R … -365 VARPA 1 30 V R … -366 STDEVA 1 30 V R … -367 VARA 1 30 V R … +361 AVERAGEA 1 30 V R ... +362 MAXA 1 30 V R ... +363 MINA 1 30 V R ... +364 STDEVPA 1 30 V R ... +365 VARPA 1 30 V R ... +366 STDEVA 1 30 V R ... +367 VARA 1 30 V R ... diff --git a/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata.txt b/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata.txt index e46e4174c4..6902027de9 100644 --- a/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata.txt +++ b/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata.txt @@ -31,7 +31,7 @@ 7 MAX 1 30 V R 8 ROW 0 1 V R 9 COLUMN 0 1 V R -10 NA 0 0 V – +10 NA 0 0 V - 11 NPV 2 30 V V R 12 STDEV 1 30 V R 13 DOLLAR 1 2 V V V @@ -40,7 +40,7 @@ 16 COS 1 1 V V 17 TAN 1 1 V V 18 ATAN 1 1 V V -19 PI 0 0 V – +19 PI 0 0 V - 20 SQRT 1 1 V V 21 EXP 1 1 V V 22 LN 1 1 V V @@ -55,8 +55,8 @@ 31 MID 3 3 V V V V 32 LEN 1 1 V V 33 VALUE 1 1 V V -34 TRUE 0 0 V – -35 FALSE 0 0 V – +34 TRUE 0 0 V - +35 FALSE 0 0 V - 36 AND 1 30 V R 37 OR 1 30 V R 38 NOT 1 1 V V @@ -82,7 +82,7 @@ 60 RATE 3 6 V V V V V V V 61 MIRR 3 3 V R V V 62 IRR 1 2 V R V -63 RAND 0 0 V – x +63 RAND 0 0 V - x 64 MATCH 2 3 V V R R 65 DATE 3 3 V V V V 66 TIME 3 3 V V V V @@ -93,7 +93,7 @@ 71 HOUR 1 1 V V 72 MINUTE 1 1 V V 73 SECOND 1 1 V V -74 NOW 0 0 V – x +74 NOW 0 0 V - x 75 AREAS 1 1 V R 76 ROWS 1 1 V R 77 COLUMNS 1 1 V R @@ -172,10 +172,10 @@ 215 JIS 1 1 V V x 219 ADDRESS 2 5 V V V V V V 220 DAYS360 2 2 V V V x -221 TODAY 0 0 V – x +221 TODAY 0 0 V - x 222 VDB 5 7 V V V V V V V V -227 MEDIAN 1 30 V R … -228 SUMPRODUCT 1 30 V A … +227 MEDIAN 1 30 V R ... +228 SUMPRODUCT 1 30 V A ... 229 SINH 1 1 V V 230 COSH 1 1 V V 231 TANH 1 1 V V @@ -192,7 +192,7 @@ 247 DB 4 5 V V V V V V 252 FREQUENCY 2 2 A R R 261 ERROR.TYPE 1 1 V V -269 AVEDEV 1 30 V R … +269 AVEDEV 1 30 V R ... 270 BETADIST 3 5 V V V V V V 271 GAMMALN 1 1 V V 272 BETAINV 3 5 V V V V V V @@ -241,12 +241,12 @@ 315 SLOPE 2 2 V A A 316 TTEST 4 4 V A A V V 317 PROB 3 4 V A A V V -318 DEVSQ 1 30 V R … -319 GEOMEAN 1 30 V R … -320 HARMEAN 1 30 V R … -321 SUMSQ 0 30 V R … -322 KURT 1 30 V R … -323 SKEW 1 30 V R … +318 DEVSQ 1 30 V R ... +319 GEOMEAN 1 30 V R ... +320 HARMEAN 1 30 V R ... +321 SUMSQ 0 30 V R ... +322 KURT 1 30 V R ... +323 SKEW 1 30 V R ... 324 ZTEST 2 3 V R V V 325 LARGE 2 2 V R V 326 SMALL 2 2 V R V @@ -278,10 +278,10 @@ 358 GETPIVOTDATA 2 30 359 HYPERLINK 1 2 V V V 360 PHONETIC 1 1 V R -361 AVERAGEA 1 30 V R … -362 MAXA 1 30 V R … -363 MINA 1 30 V R … -364 STDEVPA 1 30 V R … -365 VARPA 1 30 V R … -366 STDEVA 1 30 V R … -367 VARA 1 30 V R … +361 AVERAGEA 1 30 V R ... +362 MAXA 1 30 V R ... +363 MINA 1 30 V R ... +364 STDEVPA 1 30 V R ... +365 VARPA 1 30 V R ... +366 STDEVA 1 30 V R ... +367 VARA 1 30 V R ... diff --git a/src/scratchpad/examples/src/org/apache/poi/hslf/examples/DataExtraction.java b/src/scratchpad/examples/src/org/apache/poi/hslf/examples/DataExtraction.java index 05bf82472f..611466c924 100755 --- a/src/scratchpad/examples/src/org/apache/poi/hslf/examples/DataExtraction.java +++ b/src/scratchpad/examples/src/org/apache/poi/hslf/examples/DataExtraction.java @@ -69,16 +69,9 @@ public class DataExtraction { String name = ole.getInstanceName(); if ("Worksheet".equals(name)) { - //save xls on disk - FileOutputStream out = new FileOutputStream(name + "-("+(j)+").xls"); - InputStream dis = data.getData(); - byte[] chunk = new byte[2048]; - int count; - while ((count = dis.read(chunk)) >= 0) { - out.write(chunk,0,count); - } - is.close(); - out.close(); + //read xls + HSSFWorkbook wb = new HSSFWorkbook(data.getData()); + } else if ("Document".equals(name)) { HWPFDocument doc = new HWPFDocument(data.getData()); //read the word document @@ -93,7 +86,15 @@ public class DataExtraction { doc.write(out); out.close(); } else { - System.err.println("Processing " + name); + FileOutputStream out = new FileOutputStream(ole.getProgID() + "-"+(j+1)+".dat"); + InputStream dis = data.getData(); + byte[] chunk = new byte[2048]; + int count; + while ((count = dis.read(chunk)) >= 0) { + out.write(chunk,0,count); + } + is.close(); + out.close(); } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java index 4abc8c1c00..4bef9033db 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java @@ -76,6 +76,7 @@ public class ShapeFactory { case ShapeTypes.TextBox: shape = new TextBox(spContainer, parent); break; + case ShapeTypes.HostControl: case ShapeTypes.PictureFrame: { EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID); EscherProperty prop = Shape.getEscherProperty(opt, EscherProperties.BLIP__PICTUREID); diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java index 5dac650258..4030ddc0c2 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java @@ -45,7 +45,6 @@ public class TextRun protected TextBytesAtom _byteAtom; protected TextCharsAtom _charAtom; protected StyleTextPropAtom _styleAtom; - protected TextSpecInfoAtom _specAtom; protected boolean _isUnicode; protected RichTextRun[] _rtRuns; private SlideShow slideShow; @@ -319,9 +318,9 @@ public class TextRun * touch the stylings. */ private void storeText(String s) { - // Remove a single trailing \n, as there is an implicit one at the + // Remove a single trailing \r, as there is an implicit one at the // end of every record - if(s.endsWith("\n")) { + if(s.endsWith("\r")) { s = s.substring(0, s.length()-1); } @@ -361,6 +360,18 @@ public class TextRun _isUnicode = true; } } + /** + * If TextSpecInfoAtom is present, we must update the text size in it, + * otherwise the ppt will be corrupted + */ + if(_records != null) for (int i = 0; i < _records.length; i++) { + if(_records[i] instanceof TextSpecInfoAtom){ + TextSpecInfoAtom specAtom = (TextSpecInfoAtom)_records[i]; + if((s.length() + 1) != specAtom.getCharactersCovered()){ + specAtom.reset(s.length() + 1); + } + } + } } /** @@ -446,7 +457,7 @@ public class TextRun * as the the first character has. * If you care about styling, do setText on a RichTextRun instead */ - public synchronized void setText(String s) { + public synchronized void setRawText(String s) { // Save the new text to the atoms storeText(s); RichTextRun fst = _rtRuns[0]; @@ -474,20 +485,18 @@ public class TextRun _rtRuns[0] = new RichTextRun(this,0,s.length()); } - /** - * If TextSpecInfoAtom is present, we must update the text size, - * otherwise the ppt will be corrupted - */ - if(_records != null) for (int i = 0; i < _records.length; i++) { - if(_records[i] instanceof TextSpecInfoAtom){ - TextSpecInfoAtom specAtom = (TextSpecInfoAtom)_records[i]; - specAtom.setTextSize(s.length()); - } - - } } - /** + /** + * Changes the text. + * Converts '\r' into '\n' + */ + public synchronized void setText(String s) { + String text = normalize(s); + setRawText(text); + } + + /** * Ensure a StyleTextPropAtom is present for this run, * by adding if required. Normally for internal TextRun use. */ @@ -666,4 +675,12 @@ public class TextRun return null; } + + /** + * Returns a new string with line breaks converted into internal ppt representation + */ + public String normalize(String s){ + String ns = s.replaceAll("\\r?\\n", "\r"); + return ns; + } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/ExControl.java b/src/scratchpad/src/org/apache/poi/hslf/record/ExControl.java new file mode 100755 index 0000000000..e6e7da893c --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/record/ExControl.java @@ -0,0 +1,95 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hslf.record; + +import java.io.OutputStream; +import java.io.IOException; + +import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.POILogger; + +/** + * Container for OLE Control object. It contains: + *

+ * 1. ExControlAtom (4091) + * 2. ExOleObjAtom (4035) + * 3. CString (4026), Instance MenuName (1) used for menus and the Links dialog box. + * 4. CString (4026), Instance ProgID (2) that stores the OLE Programmatic Identifier. + * A ProgID is a string that uniquely identifies a given object. + * 5. CString (4026), Instance ClipboardName (3) that appears in the paste special dialog. + * 6. MetaFile( 4033), optional + *

+ * + * + * @author Yegor kozlov + */ +public class ExControl extends ExEmbed { + + // Links to our more interesting children + private ExControlAtom ctrlAtom; + + /** + * Set things up, and find our more interesting children + * + * @param source the source data as a byte array. + * @param start the start offset into the byte array. + * @param len the length of the slice in the byte array. + */ + protected ExControl(byte[] source, int start, int len) { + super(source, start, len); + } + + /** + * Create a new ExEmbed, with blank fields + */ + public ExControl() { + super(); + + _children[0] = ctrlAtom = new ExControlAtom(); + } + + /** + * Gets the {@link ExControlAtom}. + * + * @return the {@link ExControlAtom}. + */ + public ExControlAtom getExControlAtom() + { + return ctrlAtom; + } + + /** + * Returns the type (held as a little endian in bytes 3 and 4) + * that this class handles. + * + * @return the record type. + */ + public long getRecordType() { + return RecordTypes.ExControl.typeID; + } + + protected RecordAtom getEmbedAtom(Record[] children){ + RecordAtom atom = null; + if(_children[0] instanceof ExControlAtom) { + atom = (ExControlAtom)_children[0]; + } else { + logger.log(POILogger.ERROR, "First child record wasn't a ExControlAtom, was of type " + _children[0].getRecordType()); + } + return atom; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/ExControlAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/ExControlAtom.java new file mode 100755 index 0000000000..ae99d0a235 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/record/ExControlAtom.java @@ -0,0 +1,96 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hslf.record; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.poi.util.LittleEndian; + +/** + * Contains a long integer, slideID, which stores the unique slide identifier of the slide + * where this control resides. + * + * @author Yegor Kozlov + */ +public class ExControlAtom extends RecordAtom { + + + /** + * Record header. + */ + private byte[] _header; + + /** + * slideId. + */ + private int _id; + + /** + * Constructs a brand new embedded object atom record. + */ + protected ExControlAtom() { + _header = new byte[8]; + + LittleEndian.putShort(_header, 2, (short) getRecordType()); + LittleEndian.putInt(_header, 4, 4); + + } + + /** + * Constructs the ExControlAtom record from its source data. + * + * @param source the source data as a byte array. + * @param start the start offset into the byte array. + * @param len the length of the slice in the byte array. + */ + protected ExControlAtom(byte[] source, int start, int len) { + // Get the header. + _header = new byte[8]; + System.arraycopy(source, start, _header, 0, 8); + + _id = LittleEndian.getInt(source, start + 8); + } + + public int getSlideId() { + return _id; + } + + /** + * Gets the record type. + * @return the record type. + */ + public long getRecordType() { + return RecordTypes.ExControlAtom.typeID; + } + + /** + * Write the contents of the record back, so it can be written + * to disk + * + * @param out the output stream to write to. + * @throws java.io.IOException if an error occurs. + */ + public void writeOut(OutputStream out) throws IOException { + out.write(_header); + byte[] data = new byte[4]; + LittleEndian.putInt(data, _id); + out.write(data); + } + +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java b/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java index 9e58e8ae18..501712e9d5 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java @@ -36,7 +36,7 @@ public class ExEmbed extends RecordContainer { private byte[] _header; // Links to our more interesting children - private ExEmbedAtom embedAtom; + private RecordAtom embedAtom; private ExOleObjAtom oleObjAtom; private CString menuName; private CString progId; @@ -91,11 +91,7 @@ public class ExEmbed extends RecordContainer { private void findInterestingChildren() { // First child should be the ExHyperlinkAtom - if(_children[0] instanceof ExEmbedAtom) { - embedAtom = (ExEmbedAtom)_children[0]; - } else { - logger.log(POILogger.ERROR, "First child record wasn't a ExEmbedAtom, was of type " + _children[0].getRecordType()); - } + embedAtom = getEmbedAtom(_children); // Second child should be the ExOleObjAtom if (_children[1] instanceof ExOleObjAtom) { @@ -115,6 +111,16 @@ public class ExEmbed extends RecordContainer { } } + protected RecordAtom getEmbedAtom(Record[] children){ + RecordAtom atom = null; + if(_children[0] instanceof ExEmbedAtom) { + atom = (ExEmbedAtom)_children[0]; + } else { + logger.log(POILogger.ERROR, "First child record wasn't a ExEmbedAtom, was of type " + _children[0].getRecordType()); + } + return atom; + } + /** * Gets the {@link ExEmbedAtom}. * @@ -122,7 +128,7 @@ public class ExEmbed extends RecordContainer { */ public ExEmbedAtom getExEmbedAtom() { - return embedAtom; + return (ExEmbedAtom)embedAtom; } /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/ExOleObjStg.java b/src/scratchpad/src/org/apache/poi/hslf/record/ExOleObjStg.java index 197497fd02..c7408b0fe4 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/ExOleObjStg.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/ExOleObjStg.java @@ -17,11 +17,9 @@ package org.apache.poi.hslf.record; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.io.*; import java.util.zip.InflaterInputStream; +import java.util.zip.DeflaterOutputStream; import org.apache.poi.util.LittleEndian; @@ -92,6 +90,25 @@ public class ExOleObjStg extends RecordAtom implements PersistRecord { return new InflaterInputStream(compressedStream); } + /** + * Sets the embedded data. + * + * @param data the embedded data. + */ + public void setData(byte[] data) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + //first four bytes is the length of the raw data + byte[] b = new byte[4]; + LittleEndian.putInt(b, data.length); + out.write(b); + + DeflaterOutputStream def = new DeflaterOutputStream(out); + def.write(data, 0, data.length); + def.finish(); + _data = out.toByteArray(); + LittleEndian.putInt(_header, 4, _data.length); + } + /** * Gets the record type. * diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java b/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java index cedc99ce0a..a6f00da124 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java @@ -119,7 +119,7 @@ public class RecordTypes { public static final Type RecolorInfoAtom = new Type(4071,null); public static final Type ExQuickTimeMovie = new Type(4074,null); public static final Type ExQuickTimeMovieData = new Type(4075,null); - public static final Type ExControl = new Type(4078,null); + public static final Type ExControl = new Type(4078,ExControl.class); public static final Type SlideListWithText = new Type(4080,SlideListWithText.class); public static final Type InteractiveInfo = new Type(4082,InteractiveInfo.class); public static final Type InteractiveInfoAtom = new Type(4083,InteractiveInfoAtom.class); diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/TextSpecInfoAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/TextSpecInfoAtom.java index a8915f0498..85cdd1e156 100755 --- a/src/scratchpad/src/org/apache/poi/hslf/record/TextSpecInfoAtom.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/TextSpecInfoAtom.java @@ -20,6 +20,7 @@ import org.apache.poi.util.LittleEndian; import java.io.OutputStream; import java.io.IOException; +import java.util.ArrayList; /** * The special info runs contained in this text. @@ -82,4 +83,118 @@ public class TextSpecInfoAtom extends RecordAtom { public void setTextSize(int size){ LittleEndian.putInt(_data, 0, size); } + + /** + * Reset the content to one info run with the default values + * @param size the site of parent text + */ + public void reset(int size){ + _data = new byte[10]; + // 01 00 00 00 + LittleEndian.putInt(_data, 0, size); + // 01 00 00 00 + LittleEndian.putInt(_data, 4, 1); //mask + // 00 00 + LittleEndian.putShort(_data, 8, (short)0); //langId + + // Update the size (header bytes 5-8) + LittleEndian.putInt(_header, 4, _data.length); + } + + /** + * Get the number of characters covered by this records + * + * @return the number of characters covered by this records + */ + public int getCharactersCovered(){ + int covered = 0; + TextSpecInfoRun[] runs = getTextSpecInfoRuns(); + for (int i = 0; i < runs.length; i++) covered += runs[i].len; + return covered; + } + + public TextSpecInfoRun[] getTextSpecInfoRuns(){ + ArrayList lst = new ArrayList(); + int pos = 0; + int[] bits = {1, 0, 2}; + while(pos < _data.length) { + TextSpecInfoRun run = new TextSpecInfoRun(); + run.len = LittleEndian.getInt(_data, pos); pos += 4; + run.mask = LittleEndian.getInt(_data, pos); pos += 4; + for (int i = 0; i < bits.length; i++) { + if((run.mask & 1 << bits[i]) != 0){ + switch (bits[i]){ + case 0: + run.spellInfo = LittleEndian.getShort(_data, pos); pos += 2; + break; + case 1: + run.langId = LittleEndian.getShort(_data, pos); pos += 2; + break; + case 2: + run.altLangId = LittleEndian.getShort(_data, pos); pos += 2; + break; + } + } + } + lst.add(run); + } + return (TextSpecInfoRun[])lst.toArray(new TextSpecInfoRun[lst.size()]); + + } + + public static class TextSpecInfoRun { + //Length of special info run. + protected int len; + + //Special info mask of this run; + protected int mask; + + // info fields as indicated by the mask. + // -1 means the bit is not set + protected short spellInfo = -1; + protected short langId = -1; + protected short altLangId = -1; + + /** + * Spelling status of this text. See Spell Info table below. + * + *

Spell Info Types:

+ *
  • 0 Unchecked + *
  • 1 Previously incorrect, needs rechecking + *
  • 2 Correct + *
  • 3 Incorrect + * + * @return Spelling status of this text + */ + public short getSpellInfo(){ + return spellInfo; + } + + /** + * Windows LANGID for this text. + * + * @return Windows LANGID for this text. + */ + public short getLangId(){ + return spellInfo; + } + + /** + * Alternate Windows LANGID of this text; + * must be a valid non-East Asian LANGID if the text has an East Asian language, + * otherwise may be an East Asian LANGID or language neutral (zero). + * + * @return Alternate Windows LANGID of this text + */ + public short getAltLangId(){ + return altLangId; + } + + /** + * @return Length of special info run. + */ + public int length(){ + return len; + } + } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/ObjectData.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/ObjectData.java index 957e78868e..bbef87a96c 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/ObjectData.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/ObjectData.java @@ -17,6 +17,7 @@ package org.apache.poi.hslf.usermodel; import java.io.InputStream; +import java.io.IOException; import org.apache.poi.hslf.record.ExOleObjStg; @@ -49,6 +50,15 @@ public class ObjectData { return storage.getData(); } + /** + * Sets the embedded data. + * + * @param data the embedded data. + */ + public void setData(byte[] data) throws IOException { + storage.setData(data); + } + /** * Return the record that contains the object data. * diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java index 7458df7e63..6bc203b658 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java @@ -162,10 +162,18 @@ public class RichTextRun { * Change the text */ public void setText(String text) { - length = text.length(); - parentRun.changeTextInRichTextRun(this,text); + String s = parentRun.normalize(text); + setRawText(s); } + /** + * Change the text + */ + public void setRawText(String text) { + length = text.length(); + parentRun.changeTextInRichTextRun(this,text); + } + /** * Tells the RichTextRun its new position in the parent TextRun * @param startAt diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/ListLevel.java b/src/scratchpad/src/org/apache/poi/hwpf/model/ListLevel.java index 0adfe617f1..f6b4d8594f 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/ListLevel.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/ListLevel.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -16,22 +15,20 @@ limitations under the License. ==================================================================== */ - package org.apache.poi.hwpf.model; +import java.util.Arrays; + import org.apache.poi.util.BitField; import org.apache.poi.util.LittleEndian; -import org.apache.poi.hwpf.usermodel.CharacterProperties; -import org.apache.poi.hwpf.usermodel.ParagraphProperties; - -import org.apache.poi.hwpf.sprm.ParagraphSprmCompressor; -import org.apache.poi.hwpf.sprm.CharacterSprmCompressor; - -import java.util.Arrays; - -public class ListLevel +/** + * + */ +public final class ListLevel { + private static final int RGBXCH_NUMS_SIZE = 9; + private int _iStartAt; private byte _nfc; private byte _info; @@ -70,7 +67,7 @@ public class ListLevel _grpprlPapx = new byte[0]; _grpprlChpx = new byte[0]; _numberText = new char[0]; - _rgbxchNums = new byte[9]; + _rgbxchNums = new byte[RGBXCH_NUMS_SIZE]; if (numbered) { @@ -90,12 +87,11 @@ public class ListLevel _nfc = buf[offset++]; _info = buf[offset++]; - _rgbxchNums = new byte[9]; - for (int x = 0; x < 9; x++) - { - _rgbxchNums[x] = buf[offset++]; - } - _ixchFollow = buf[offset++]; + _rgbxchNums = new byte[RGBXCH_NUMS_SIZE]; + System.arraycopy(buf, offset, _rgbxchNums, 0, RGBXCH_NUMS_SIZE); + offset += RGBXCH_NUMS_SIZE; + + _ixchFollow = buf[offset++]; _dxaSpace = LittleEndian.getInt(buf, offset); offset += LittleEndian.INT_SIZE; _dxaIndent = LittleEndian.getInt(buf, offset); @@ -207,8 +203,8 @@ public class ListLevel offset += LittleEndian.INT_SIZE; buf[offset++] = _nfc; buf[offset++] = _info; - System.arraycopy(_rgbxchNums, 0, buf, offset, _rgbxchNums.length); - offset += _rgbxchNums.length; + System.arraycopy(_rgbxchNums, 0, buf, offset, RGBXCH_NUMS_SIZE); + offset += RGBXCH_NUMS_SIZE; buf[offset++] = _ixchFollow; LittleEndian.putInt(buf, offset, _dxaSpace); offset += LittleEndian.INT_SIZE; @@ -225,23 +221,33 @@ public class ListLevel System.arraycopy(_grpprlPapx, 0, buf, offset, _cbGrpprlPapx); offset += _cbGrpprlPapx; - LittleEndian.putShort(buf, offset, (short)_numberText.length); - offset += LittleEndian.SHORT_SIZE; - for (int x = 0; x < _numberText.length; x++) - { - LittleEndian.putShort(buf, offset, (short)_numberText[x]); + if (_numberText == null) { + // TODO - write junit to test this flow + LittleEndian.putUShort(buf, offset, 0); + } else { + LittleEndian.putUShort(buf, offset, _numberText.length); offset += LittleEndian.SHORT_SIZE; + for (int x = 0; x < _numberText.length; x++) + { + LittleEndian.putUShort(buf, offset, _numberText[x]); + offset += LittleEndian.SHORT_SIZE; + } } return buf; } public int getSizeInBytes() { - if (_numberText!=null) - { - return 28 + _cbGrpprlChpx + _cbGrpprlPapx + (_numberText.length * LittleEndian.SHORT_SIZE) + 2; - } else { - return 28 + _cbGrpprlChpx + _cbGrpprlPapx + 2; - } + int result = + 6 // int byte byte + + RGBXCH_NUMS_SIZE + + 13 // byte int int byte byte short + + _cbGrpprlChpx + + _cbGrpprlPapx + + 2; // numberText length + if (_numberText != null) { + result += _numberText.length * LittleEndian.SHORT_SIZE; + } + return result; } } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestTextSpecInfoAtom.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestTextSpecInfoAtom.java new file mode 100755 index 0000000000..5079628aec --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestTextSpecInfoAtom.java @@ -0,0 +1,95 @@ + +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + + + +package org.apache.poi.hslf.record; + +import org.apache.poi.hslf.HSLFSlideShow; +import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp; +import org.apache.poi.hslf.model.textproperties.TextProp; +import org.apache.poi.hslf.model.textproperties.TextPropCollection; +import org.apache.poi.hslf.record.StyleTextPropAtom.*; +import org.apache.poi.hslf.usermodel.SlideShow; +import org.apache.poi.util.HexDump; + +import junit.framework.TestCase; +import java.io.ByteArrayOutputStream; +import java.util.LinkedList; +import java.util.Arrays; + +/** + * Tests TextSpecInfoAtom + * + * @author Yegor Kozlov + */ +public class TestTextSpecInfoAtom extends TestCase { + + //from a real file + private byte[] data_1 = new byte[] { + 0x00, 0x00, (byte)0xAA, 0x0F, 0x2C, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + + public void testRead() throws Exception { + TextSpecInfoAtom spec = new TextSpecInfoAtom(data_1, 0, data_1.length); + TextSpecInfoAtom.TextSpecInfoRun[] run = spec.getTextSpecInfoRuns(); + assertEquals(5, run.length); + + assertEquals(10, run[0].length()); + assertEquals(1, run[1].length()); + assertEquals(70, run[2].length()); + assertEquals(9, run[3].length()); + assertEquals(32, run[4].length()); + + } + + public void testWrite() throws Exception { + TextSpecInfoAtom spec = new TextSpecInfoAtom(data_1, 0, data_1.length); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + spec.writeOut(out); + + byte[] result = out.toByteArray(); + assertTrue(Arrays.equals(result, data_1)); + } + + public void testReset() throws Exception { + TextSpecInfoAtom spec = new TextSpecInfoAtom(data_1, 0, data_1.length); + spec.reset(32); //length of the parent text + + TextSpecInfoAtom.TextSpecInfoRun[] run = spec.getTextSpecInfoRuns(); + assertEquals(1, run.length); + + assertEquals(32, run[0].length()); + + //serialize and read again + ByteArrayOutputStream out = new ByteArrayOutputStream(); + spec.writeOut(out); + + byte[] result = out.toByteArray(); + TextSpecInfoAtom spec2 = new TextSpecInfoAtom(result, 0, result.length); + TextSpecInfoAtom.TextSpecInfoRun[] run2 = spec2.getTextSpecInfoRuns(); + assertEquals(1, run2.length); + + assertEquals(32, run2[0].length()); + } +} diff --git a/src/testcases/org/apache/poi/hssf/HSSFTests.java b/src/testcases/org/apache/poi/hssf/HSSFTests.java index 5b597a67c8..0a4fa66af7 100644 --- a/src/testcases/org/apache/poi/hssf/HSSFTests.java +++ b/src/testcases/org/apache/poi/hssf/HSSFTests.java @@ -22,9 +22,7 @@ import junit.framework.TestSuite; import org.apache.poi.hssf.eventmodel.TestEventRecordFactory; import org.apache.poi.hssf.eventmodel.TestModelFactory; -import org.apache.poi.hssf.model.TestDrawingManager; -import org.apache.poi.hssf.model.TestFormulaParser; -import org.apache.poi.hssf.model.TestSheet; +import org.apache.poi.hssf.model.AllModelTests; import org.apache.poi.hssf.record.AllRecordTests; import org.apache.poi.hssf.usermodel.AllUserModelTests; import org.apache.poi.hssf.util.TestAreaReference; @@ -50,10 +48,10 @@ public final class HSSFTests { TestSuite suite = new TestSuite("Tests for org.apache.poi.hssf"); // $JUnit-BEGIN$ + suite.addTest(AllModelTests.suite()); suite.addTest(AllUserModelTests.suite()); suite.addTest(AllRecordTests.suite()); - suite.addTest(new TestSuite(TestFormulaParser.class)); suite.addTest(new TestSuite(TestAreaReference.class)); suite.addTest(new TestSuite(TestCellReference.class)); suite.addTest(new TestSuite(TestRangeAddress.class)); @@ -61,8 +59,6 @@ public final class HSSFTests { suite.addTest(new TestSuite(TestSheetReferences.class)); suite.addTest(new TestSuite(TestEventRecordFactory.class)); suite.addTest(new TestSuite(TestModelFactory.class)); - suite.addTest(new TestSuite(TestDrawingManager.class)); - suite.addTest(new TestSuite(TestSheet.class)); // $JUnit-END$ return suite; } diff --git a/src/testcases/org/apache/poi/hssf/data/ex41187-19267.xls b/src/testcases/org/apache/poi/hssf/data/ex41187-19267.xls new file mode 100644 index 0000000000..c07bfca594 Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/ex41187-19267.xls differ diff --git a/src/testcases/org/apache/poi/hssf/model/AllModelTests.java b/src/testcases/org/apache/poi/hssf/model/AllModelTests.java new file mode 100755 index 0000000000..19ef437063 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/model/AllModelTests.java @@ -0,0 +1,40 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.model; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Collects all tests for org.apache.poi.hssf.model. + * + * @author Josh Micich + */ +public final class AllModelTests { + + public static Test suite() { + TestSuite result = new TestSuite(AllModelTests.class.getName()); + result.addTestSuite(TestDrawingManager.class); + result.addTestSuite(TestDrawingManager2.class); + result.addTestSuite(TestFormulaParser.class); + result.addTestSuite(TestFormulaParserEval.class); + result.addTestSuite(TestSheet.class); + result.addTestSuite(TestSheetAdditional.class); + return result; + } +} diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheet.java b/src/testcases/org/apache/poi/hssf/model/TestSheet.java index 964caedc2f..9281eb80d7 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestSheet.java +++ b/src/testcases/org/apache/poi/hssf/model/TestSheet.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -15,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.model; @@ -34,8 +32,7 @@ import java.util.List; * * @author Glen Stampoultzis (glens at apache.org) */ -public class TestSheet extends TestCase -{ +public final class TestSheet extends TestCase { public void testCreateSheet() throws Exception { // Check we're adding row and cell aggregates @@ -76,6 +73,21 @@ public class TestSheet extends TestCase if ((regionsToAdd % 1027) != 0) recordsExpected++; assertTrue("The " + regionsToAdd + " merged regions should have been spread out over " + recordsExpected + " records, not " + recordsAdded, recordsAdded == recordsExpected); + // Check we can't add one with invalid date + try { + sheet.addMergedRegion(10, (short)10, 9, (short)12); + fail("Expected an exception to occur"); + } catch(IllegalArgumentException e) { + // occurs during successful test + assertEquals("The 'to' row (9) must not be less than the 'from' row (10)", e.getMessage()); + } + try { + sheet.addMergedRegion(10, (short)10, 12, (short)9); + fail("Expected an exception to occur"); + } catch(IllegalArgumentException e) { + // occurs during successful test + assertEquals("The 'to' col (9) must not be less than the 'from' col (10)", e.getMessage()); + } } public void testRemoveMergedRegion() @@ -113,9 +125,9 @@ public class TestSheet extends TestCase MergeCellsRecord merged = new MergeCellsRecord(); merged.addArea(0, (short)0, 1, (short)2); - records.add(new RowRecord()); - records.add(new RowRecord()); - records.add(new RowRecord()); + records.add(new RowRecord(0)); + records.add(new RowRecord(1)); + records.add(new RowRecord(2)); records.add(merged); Sheet sheet = Sheet.createSheet(records, 0); @@ -142,20 +154,11 @@ public class TestSheet extends TestCase */ public void testRowAggregation() { List records = new ArrayList(); - RowRecord row = new RowRecord(); - row.setRowNumber(0); - records.add(row); - - row = new RowRecord(); - row.setRowNumber(1); - records.add(row); + records.add(new RowRecord(0)); + records.add(new RowRecord(1)); records.add(new StringRecord()); - - row = new RowRecord(); - row.setRowNumber(2); - records.add(row); - + records.add(new RowRecord(2)); Sheet sheet = Sheet.createSheet(records, 0); assertNotNull("Row [2] was skipped", sheet.getRow(2)); @@ -197,9 +200,9 @@ public class TestSheet extends TestCase Iterator iterator = sheet.getRowBreaks(); while (iterator.hasNext()) { PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); - int main = (int)breakItem.main; + int main = breakItem.main; if (main != 0 && main != 10 && main != 11) fail("Invalid page break"); - if (main == 0) is0 = true; + if (main == 0) is0 = true; if (main == 10) is10= true; if (main == 11) is11 = true; } @@ -216,8 +219,6 @@ public class TestSheet extends TestCase assertFalse("row should be removed", sheet.isRowBroken(10)); assertEquals("no more breaks", 0, sheet.getNumRowBreaks()); - - } /** @@ -256,10 +257,10 @@ public class TestSheet extends TestCase Iterator iterator = sheet.getColumnBreaks(); while (iterator.hasNext()) { PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); - int main = (int)breakItem.main; + int main = breakItem.main; if (main != 0 && main != 1 && main != 10 && main != 15) fail("Invalid page break"); - if (main == 0) is0 = true; - if (main == 1) is1 = true; + if (main == 0) is0 = true; + if (main == 1) is1 = true; if (main == 10) is10= true; if (main == 15) is15 = true; } @@ -286,72 +287,69 @@ public class TestSheet extends TestCase * works as designed. */ public void testXFIndexForColumn() { - try{ - final short TEST_IDX = 10; - final short DEFAULT_IDX = 0xF; // 15 - short xfindex = Short.MIN_VALUE; - Sheet sheet = Sheet.createSheet(); - - // without ColumnInfoRecord - xfindex = sheet.getXFIndexForColAt((short) 0); - assertEquals(DEFAULT_IDX, xfindex); - xfindex = sheet.getXFIndexForColAt((short) 1); - assertEquals(DEFAULT_IDX, xfindex); - - ColumnInfoRecord nci = ( ColumnInfoRecord ) sheet.createColInfo(); - sheet.columns.insertColumn(nci); - - // single column ColumnInfoRecord - nci.setFirstColumn((short) 2); - nci.setLastColumn((short) 2); - nci.setXFIndex(TEST_IDX); - xfindex = sheet.getXFIndexForColAt((short) 0); - assertEquals(DEFAULT_IDX, xfindex); - xfindex = sheet.getXFIndexForColAt((short) 1); - assertEquals(DEFAULT_IDX, xfindex); - xfindex = sheet.getXFIndexForColAt((short) 2); - assertEquals(TEST_IDX, xfindex); - xfindex = sheet.getXFIndexForColAt((short) 3); - assertEquals(DEFAULT_IDX, xfindex); - - // ten column ColumnInfoRecord - nci.setFirstColumn((short) 2); - nci.setLastColumn((short) 11); - nci.setXFIndex(TEST_IDX); - xfindex = sheet.getXFIndexForColAt((short) 1); - assertEquals(DEFAULT_IDX, xfindex); - xfindex = sheet.getXFIndexForColAt((short) 2); - assertEquals(TEST_IDX, xfindex); - xfindex = sheet.getXFIndexForColAt((short) 6); - assertEquals(TEST_IDX, xfindex); - xfindex = sheet.getXFIndexForColAt((short) 11); - assertEquals(TEST_IDX, xfindex); - xfindex = sheet.getXFIndexForColAt((short) 12); - assertEquals(DEFAULT_IDX, xfindex); - - // single column ColumnInfoRecord starting at index 0 - nci.setFirstColumn((short) 0); - nci.setLastColumn((short) 0); - nci.setXFIndex(TEST_IDX); - xfindex = sheet.getXFIndexForColAt((short) 0); - assertEquals(TEST_IDX, xfindex); - xfindex = sheet.getXFIndexForColAt((short) 1); - assertEquals(DEFAULT_IDX, xfindex); - - // ten column ColumnInfoRecord starting at index 0 - nci.setFirstColumn((short) 0); - nci.setLastColumn((short) 9); - nci.setXFIndex(TEST_IDX); - xfindex = sheet.getXFIndexForColAt((short) 0); - assertEquals(TEST_IDX, xfindex); - xfindex = sheet.getXFIndexForColAt((short) 7); - assertEquals(TEST_IDX, xfindex); - xfindex = sheet.getXFIndexForColAt((short) 9); - assertEquals(TEST_IDX, xfindex); - xfindex = sheet.getXFIndexForColAt((short) 10); - assertEquals(DEFAULT_IDX, xfindex); - } - catch(Exception e){e.printStackTrace();fail(e.getMessage());} + final short TEST_IDX = 10; + final short DEFAULT_IDX = 0xF; // 15 + short xfindex = Short.MIN_VALUE; + Sheet sheet = Sheet.createSheet(); + + // without ColumnInfoRecord + xfindex = sheet.getXFIndexForColAt((short) 0); + assertEquals(DEFAULT_IDX, xfindex); + xfindex = sheet.getXFIndexForColAt((short) 1); + assertEquals(DEFAULT_IDX, xfindex); + + ColumnInfoRecord nci = ( ColumnInfoRecord ) sheet.createColInfo(); + sheet.columns.insertColumn(nci); + + // single column ColumnInfoRecord + nci.setFirstColumn((short) 2); + nci.setLastColumn((short) 2); + nci.setXFIndex(TEST_IDX); + xfindex = sheet.getXFIndexForColAt((short) 0); + assertEquals(DEFAULT_IDX, xfindex); + xfindex = sheet.getXFIndexForColAt((short) 1); + assertEquals(DEFAULT_IDX, xfindex); + xfindex = sheet.getXFIndexForColAt((short) 2); + assertEquals(TEST_IDX, xfindex); + xfindex = sheet.getXFIndexForColAt((short) 3); + assertEquals(DEFAULT_IDX, xfindex); + + // ten column ColumnInfoRecord + nci.setFirstColumn((short) 2); + nci.setLastColumn((short) 11); + nci.setXFIndex(TEST_IDX); + xfindex = sheet.getXFIndexForColAt((short) 1); + assertEquals(DEFAULT_IDX, xfindex); + xfindex = sheet.getXFIndexForColAt((short) 2); + assertEquals(TEST_IDX, xfindex); + xfindex = sheet.getXFIndexForColAt((short) 6); + assertEquals(TEST_IDX, xfindex); + xfindex = sheet.getXFIndexForColAt((short) 11); + assertEquals(TEST_IDX, xfindex); + xfindex = sheet.getXFIndexForColAt((short) 12); + assertEquals(DEFAULT_IDX, xfindex); + + // single column ColumnInfoRecord starting at index 0 + nci.setFirstColumn((short) 0); + nci.setLastColumn((short) 0); + nci.setXFIndex(TEST_IDX); + xfindex = sheet.getXFIndexForColAt((short) 0); + assertEquals(TEST_IDX, xfindex); + xfindex = sheet.getXFIndexForColAt((short) 1); + assertEquals(DEFAULT_IDX, xfindex); + + // ten column ColumnInfoRecord starting at index 0 + nci.setFirstColumn((short) 0); + nci.setLastColumn((short) 9); + nci.setXFIndex(TEST_IDX); + xfindex = sheet.getXFIndexForColAt((short) 0); + assertEquals(TEST_IDX, xfindex); + xfindex = sheet.getXFIndexForColAt((short) 7); + assertEquals(TEST_IDX, xfindex); + xfindex = sheet.getXFIndexForColAt((short) 9); + assertEquals(TEST_IDX, xfindex); + xfindex = sheet.getXFIndexForColAt((short) 10); + assertEquals(DEFAULT_IDX, xfindex); } - } + diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java b/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java index 69ab3f2986..f1c3b7c9ca 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java +++ b/src/testcases/org/apache/poi/hssf/model/TestSheetAdditional.java @@ -19,125 +19,18 @@ package org.apache.poi.hssf.model; import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import junit.framework.TestCase; import org.apache.poi.hssf.record.ColumnInfoRecord; -import org.apache.poi.hssf.record.MergeCellsRecord; -import org.apache.poi.hssf.record.PageBreakRecord; -import org.apache.poi.hssf.record.RowRecord; -import org.apache.poi.hssf.record.StringRecord; /** * @author Tony Poppleton */ -public class TestSheetAdditional extends TestCase -{ - /** - * Constructor for SheetTest. - * @param arg0 - */ - public TestSheetAdditional(String arg0) - { - super(arg0); - } +public final class TestSheetAdditional extends TestCase { - public void testAddMergedRegion() - { - Sheet sheet = Sheet.createSheet(); - int regionsToAdd = 4096; - int startRecords = sheet.getRecords().size(); - - //simple test that adds a load of regions - for (int n = 0; n < regionsToAdd; n++) - { - int index = sheet.addMergedRegion(0, (short) 0, 1, (short) 1); - assertTrue("Merged region index expected to be " + n + " got " + index, index == n); - } - - //test all the regions were indeed added - assertTrue(sheet.getNumMergedRegions() == regionsToAdd); - - //test that the regions were spread out over the appropriate number of records - int recordsAdded = sheet.getRecords().size() - startRecords; - int recordsExpected = regionsToAdd/1027; - if ((regionsToAdd % 1027) != 0) - recordsExpected++; - assertTrue("The " + regionsToAdd + " merged regions should have been spread out over " + recordsExpected + " records, not " + recordsAdded, recordsAdded == recordsExpected); - - // Check we can't add one with invalud date - try { - sheet.addMergedRegion(10, (short)10, 9, (short)12); - fail(); - } catch(IllegalArgumentException e) {} - try { - sheet.addMergedRegion(10, (short)10, 12, (short)9); - fail(); - } catch(IllegalArgumentException e) {} - } - - public void testRemoveMergedRegion() - { - Sheet sheet = Sheet.createSheet(); - int regionsToAdd = 4096; - - for (int n = 0; n < regionsToAdd; n++) - sheet.addMergedRegion(0, (short) 0, 1, (short) 1); - - int records = sheet.getRecords().size(); - - //remove a third from the beginning - for (int n = 0; n < regionsToAdd/3; n++) - { - sheet.removeMergedRegion(0); - //assert they have been deleted - assertTrue("Num of regions should be " + (regionsToAdd - n - 1) + " not " + sheet.getNumMergedRegions(), sheet.getNumMergedRegions() == regionsToAdd - n - 1); - } - - //assert any record removing was done - int recordsRemoved = (regionsToAdd/3)/1027; //doesn't work for particular values of regionsToAdd - assertTrue("Expected " + recordsRemoved + " record to be removed from the starting " + records + ". Currently there are " + sheet.getRecords().size() + " records", records - sheet.getRecords().size() == recordsRemoved); - } - - /** - * Bug: 22922 (Reported by Xuemin Guan) - *

    - * Remove mergedregion fails when a sheet loses records after an initial CreateSheet - * fills up the records. - * - */ - public void testMovingMergedRegion() { - List records = new ArrayList(); - - MergeCellsRecord merged = new MergeCellsRecord(); - merged.addArea(0, (short)0, 1, (short)2); - records.add(new RowRecord()); - records.add(new RowRecord()); - records.add(new RowRecord()); - records.add(merged); - - Sheet sheet = Sheet.createSheet(records, 0); - sheet.records.remove(0); - - //stub object to throw off list INDEX operations - sheet.removeMergedRegion(0); - assertEquals("Should be no more merged regions", 0, sheet.getNumMergedRegions()); - } - - public void testGetMergedRegionAt() - { - //TODO - } - - public void testGetNumMergedRegions() - { - //TODO - } - - public void DISBALEDtestGetCellWidth() throws Exception - { + public void testGetCellWidth() { Sheet sheet = Sheet.createSheet(); ColumnInfoRecord nci = ( ColumnInfoRecord ) sheet.createColInfo(); @@ -146,14 +39,8 @@ public class TestSheetAdditional extends TestCase nci.setLastColumn((short)10); nci.setColumnWidth((short)100); - Field f = null; - f = Sheet.class.getDeclaredField("columnSizes"); - f.setAccessible(true); - List columnSizes = new ArrayList(); - f.set(sheet,columnSizes); - columnSizes.add(nci); - sheet.records.add(1 + sheet.dimsloc, nci); - sheet.dimsloc++; + + sheet.columns.insertColumn(nci); assertEquals((short)100,sheet.getColumnWidth((short)5)); assertEquals((short)100,sheet.getColumnWidth((short)6)); @@ -172,151 +59,6 @@ public class TestSheetAdditional extends TestCase assertEquals((short)100,sheet.getColumnWidth((short)10)); } - /** - * Makes sure all rows registered for this sheet are aggregated, they were being skipped - * - */ - public void testRowAggregation() { - List records = new ArrayList(); - RowRecord row = new RowRecord(); - row.setRowNumber(0); - records.add(row); - - row = new RowRecord(); - row.setRowNumber(1); - records.add(row); - - records.add(new StringRecord()); - - row = new RowRecord(); - row.setRowNumber(2); - records.add(row); - - - Sheet sheet = Sheet.createSheet(records, 0); - assertNotNull("Row [2] was skipped", sheet.getRow(2)); - - } - - /** - * Make sure page break functionality works (in memory) - * - */ - public void testRowPageBreaks(){ - short colFrom = 0; - short colTo = 255; - - Sheet sheet = Sheet.createSheet(); - sheet.setRowBreak(0, colFrom, colTo); - - assertTrue("no row break at 0", sheet.isRowBroken(0)); - assertEquals("1 row break available", 1, sheet.getNumRowBreaks()); - - sheet.setRowBreak(0, colFrom, colTo); - sheet.setRowBreak(0, colFrom, colTo); - - assertTrue("no row break at 0", sheet.isRowBroken(0)); - assertEquals("1 row break available", 1, sheet.getNumRowBreaks()); - - sheet.setRowBreak(10, colFrom, colTo); - sheet.setRowBreak(11, colFrom, colTo); - - assertTrue("no row break at 10", sheet.isRowBroken(10)); - assertTrue("no row break at 11", sheet.isRowBroken(11)); - assertEquals("3 row break available", 3, sheet.getNumRowBreaks()); - - - boolean is10 = false; - boolean is0 = false; - boolean is11 = false; - - Iterator iterator = sheet.getRowBreaks(); - while (iterator.hasNext()) { - PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); - int main = (int)breakItem.main; - if (main != 0 && main != 10 && main != 11) fail("Invalid page break"); - if (main == 0) is0 = true; - if (main == 10) is10= true; - if (main == 11) is11 = true; - } - - assertTrue("one of the breaks didnt make it", is0 && is10 && is11); - - sheet.removeRowBreak(11); - assertFalse("row should be removed", sheet.isRowBroken(11)); - - sheet.removeRowBreak(0); - assertFalse("row should be removed", sheet.isRowBroken(0)); - - sheet.removeRowBreak(10); - assertFalse("row should be removed", sheet.isRowBroken(10)); - - assertEquals("no more breaks", 0, sheet.getNumRowBreaks()); - - - } - - /** - * Make sure column pag breaks works properly (in-memory) - * - */ - public void testColPageBreaks(){ - short rowFrom = 0; - short rowTo = (short)65535; - - Sheet sheet = Sheet.createSheet(); - sheet.setColumnBreak((short)0, rowFrom, rowTo); - - assertTrue("no col break at 0", sheet.isColumnBroken((short)0)); - assertEquals("1 col break available", 1, sheet.getNumColumnBreaks()); - - sheet.setColumnBreak((short)0, rowFrom, rowTo); - - assertTrue("no col break at 0", sheet.isColumnBroken((short)0)); - assertEquals("1 col break available", 1, sheet.getNumColumnBreaks()); - - sheet.setColumnBreak((short)1, rowFrom, rowTo); - sheet.setColumnBreak((short)10, rowFrom, rowTo); - sheet.setColumnBreak((short)15, rowFrom, rowTo); - - assertTrue("no col break at 1", sheet.isColumnBroken((short)1)); - assertTrue("no col break at 10", sheet.isColumnBroken((short)10)); - assertTrue("no col break at 15", sheet.isColumnBroken((short)15)); - assertEquals("4 col break available", 4, sheet.getNumColumnBreaks()); - - boolean is10 = false; - boolean is0 = false; - boolean is1 = false; - boolean is15 = false; - - Iterator iterator = sheet.getColumnBreaks(); - while (iterator.hasNext()) { - PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); - int main = (int)breakItem.main; - if (main != 0 && main != 1 && main != 10 && main != 15) fail("Invalid page break"); - if (main == 0) is0 = true; - if (main == 1) is1 = true; - if (main == 10) is10= true; - if (main == 15) is15 = true; - } - - assertTrue("one of the breaks didnt make it", is0 && is1 && is10 && is15); - - sheet.removeColumnBreak((short)15); - assertFalse("column break should not be there", sheet.isColumnBroken((short)15)); - - sheet.removeColumnBreak((short)0); - assertFalse("column break should not be there", sheet.isColumnBroken((short)0)); - - sheet.removeColumnBreak((short)1); - assertFalse("column break should not be there", sheet.isColumnBroken((short)1)); - - sheet.removeColumnBreak((short)10); - assertFalse("column break should not be there", sheet.isColumnBroken((short)10)); - - assertEquals("no more breaks", 0, sheet.getNumColumnBreaks()); - } - } diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/TestRowRecordsAggregate.java b/src/testcases/org/apache/poi/hssf/record/aggregates/TestRowRecordsAggregate.java index 50f67129ce..239fc2b887 100644 --- a/src/testcases/org/apache/poi/hssf/record/aggregates/TestRowRecordsAggregate.java +++ b/src/testcases/org/apache/poi/hssf/record/aggregates/TestRowRecordsAggregate.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -15,34 +14,28 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - + package org.apache.poi.hssf.record.aggregates; -import org.apache.poi.hssf.record.*; +import junit.framework.TestCase; -public class TestRowRecordsAggregate extends junit.framework.TestCase { - public TestRowRecordsAggregate(String name) { - super (name); - } +import org.apache.poi.hssf.record.RowRecord; + +/** + * + */ +public final class TestRowRecordsAggregate extends TestCase { public void testRowGet() { RowRecordsAggregate rra = new RowRecordsAggregate(); - RowRecord rr = new RowRecord(); - rr.setRowNumber(( short ) 4); + RowRecord rr = new RowRecord(4); rra.insertRow(rr); - RowRecord rr2 = new RowRecord(); rr2.setRowNumber((short) 1); - rra.insertRow(rr2); + rra.insertRow(new RowRecord(1)); RowRecord rr1 = rra.getRow(4); - assertTrue("Row Record should not be null", rr1!=null); - assertTrue("Row number is 1",rr1.getRowNumber() == 4); + assertNotNull(rr1); + assertEquals("Row number is 1", 4, rr1.getRowNumber()); assertTrue("Row record retrieved is identical ", rr1 == rr); } - - public static void main(String [] args) { - System.out - .println("Testing org.apache.poi.hssf.record.aggregates.RowRecordAggregate"); - junit.textui.TestRunner.run(TestRowRecordsAggregate.class); - } } diff --git a/src/testcases/org/apache/poi/hssf/record/formula/TestFuncPtg.java b/src/testcases/org/apache/poi/hssf/record/formula/TestFuncPtg.java index fd2b1cd124..89997b59d1 100644 --- a/src/testcases/org/apache/poi/hssf/record/formula/TestFuncPtg.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/TestFuncPtg.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -26,45 +25,31 @@ import org.apache.poi.hssf.record.TestcaseRecordInputStream; * * @author Danny Mui (dmui at apache dot org) */ +public final class TestFuncPtg extends TestCase { -public class TestFuncPtg extends TestCase -{ - - public TestFuncPtg( String name ) - { - super( name ); - } - - - public static void main( java.lang.String[] args ) - { - junit.textui.TestRunner.run( TestFuncPtg.class ); - } - - /** - * Make sure the left overs are re-serialized on excel file reads to avoid - * the "Warning: Data may have been lost" prompt in excel. - *

    - * This ptg represents a LEN function extracted from excel - */ - - public void testLeftOvers() - { - byte[] fakeData = new byte[4]; - - //fakeData[0] = (byte) 0x41; - fakeData[0] = (byte) 0x20; //function index - fakeData[1] = (byte) 0; - fakeData[2] = (byte) 8; + public void testRead() { + // This ptg represents a LEN function extracted from excel + byte[] fakeData = { + 0x20, //function index + 0, + }; FuncPtg ptg = new FuncPtg( new TestcaseRecordInputStream((short)0, (short)fakeData.length, fakeData) ); - assertEquals( "Len formula index is not 32(20H)", (int) 0x20, ptg.getFunctionIndex() ); + assertEquals( "Len formula index is not 32(20H)", 0x20, ptg.getFunctionIndex() ); assertEquals( "Number of operands in the len formula", 1, ptg.getNumberOfOperands() ); assertEquals( "Function Name", "LEN", ptg.getName() ); assertEquals( "Ptg Size", 3, ptg.getSize() ); - //assertEquals("first leftover byte is not 0", (byte)0, ptg.leftOvers[0]); - //assertEquals("second leftover byte is not 8", (byte)8, ptg.leftOvers[1]); - + } + + public void testClone() { + FuncPtg funcPtg = new FuncPtg(27); // ROUND() - takes 2 args + + FuncPtg clone = (FuncPtg) funcPtg.clone(); + if (clone.getNumberOfOperands() == 0) { + fail("clone() did copy field numberOfOperands"); + } + assertEquals(2, clone.getNumberOfOperands()); + assertEquals("ROUND", clone.getName()); } } diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/AllFormulaEvalTests.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/AllFormulaEvalTests.java index 5098c789a7..8887445ad3 100755 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/AllFormulaEvalTests.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/AllFormulaEvalTests.java @@ -28,7 +28,8 @@ import junit.framework.TestSuite; public class AllFormulaEvalTests { public static Test suite() { - TestSuite result = new TestSuite("Tests for org.apache.poi.hssf.record.formula.eval"); + TestSuite result = new TestSuite(AllFormulaEvalTests.class.getName()); + result.addTestSuite(TestAreaEval.class); result.addTestSuite(TestCircularReferences.class); result.addTestSuite(TestExternalFunction.class); result.addTestSuite(TestFormulaBugs.class); diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestAreaEval.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestAreaEval.java new file mode 100644 index 0000000000..6c855707ba --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestAreaEval.java @@ -0,0 +1,62 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.formula.eval; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.record.formula.Area3DPtg; + +/** + * Tests for AreaEval + * + * @author Josh Micich + */ +public final class TestAreaEval extends TestCase { + + public void testGetValue_bug44950() { + + Area3DPtg ptg = new Area3DPtg("B2:D3", (short)0); + NumberEval one = new NumberEval(1); + ValueEval[] values = { + one, + new NumberEval(2), + new NumberEval(3), + new NumberEval(4), + new NumberEval(5), + new NumberEval(6), + }; + AreaEval ae = new Area3DEval(ptg, values); + if (one == ae.getValueAt(1, 2)) { + throw new AssertionFailedError("Identified bug 44950 a"); + } + confirm(1, ae, 1, 1); + confirm(2, ae, 1, 2); + confirm(3, ae, 1, 3); + confirm(4, ae, 2, 1); + confirm(5, ae, 2, 2); + confirm(6, ae, 2, 3); + + } + + private static void confirm(int expectedValue, AreaEval ae, int row, int col) { + NumberEval v = (NumberEval) ae.getValueAt(row, col); + assertEquals(expectedValue, v.getNumberValue(), 0.0); + } + +} diff --git a/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java b/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java index 351e85cf85..47137df4f6 100644 --- a/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java @@ -61,7 +61,32 @@ public final class ExcelFileFormatDocFunctionExtractor { private static final String SOURCE_DOC_FILE_NAME = "excelfileformat.odt"; + /** + * For simplicity, the output file is strictly simple ASCII. + * This method detects any unexpected characters. + */ + /* package */ static boolean isSimpleAscii(char c) { + + if (c>=0x21 && c<=0x7E) { + // everything from '!' to '~' (includes letters, digits, punctuation + return true; + } + // some specific whitespace chars below 0x21: + switch(c) { + case ' ': + case '\t': + case '\r': + case '\n': + return true; + } + return false; + } + + private static final class FunctionData { + // special characters from the ooo document + private static final int CHAR_ELLIPSIS_8230 = 8230; + private static final int CHAR_NDASH_8211 = 8211; private final int _index; private final boolean _hasFootnote; @@ -79,10 +104,30 @@ public final class ExcelFileFormatDocFunctionExtractor { _name = funcName; _minParams = minParams; _maxParams = maxParams; - _returnClass = returnClass; - _paramClasses = paramClasses; + _returnClass = convertSpecialChars(returnClass); + _paramClasses = convertSpecialChars(paramClasses); _isVolatile = isVolatile; } + private static String convertSpecialChars(String ss) { + StringBuffer sb = new StringBuffer(ss.length() + 4); + for(int i=0; i 2 + // =index(C:C,2,1) -> 2 HSSFRow rowIDX = sheet.getRow(3); - // =sum(C:C) -> 6 + // =sum(C:C) -> 6 HSSFRow rowSUM = sheet.getRow(4); - // =sum(C:D) -> 66 + // =sum(C:D) -> 66 HSSFRow rowSUM2D = sheet.getRow(5); // Test the sum - HSSFCell cellSUM = rowSUM.getCell((short)0); + HSSFCell cellSUM = rowSUM.getCell((short) 0); - FormulaRecordAggregate frec = - (FormulaRecordAggregate)cellSUM.getCellValueRecord(); + FormulaRecordAggregate frec = (FormulaRecordAggregate) cellSUM.getCellValueRecord(); List ops = frec.getFormulaRecord().getParsedExpression(); assertEquals(2, ops.size()); assertEquals(AreaPtg.class, ops.get(0).getClass()); assertEquals(FuncVarPtg.class, ops.get(1).getClass()); - // Actually stored as C1 to C65536 - // (last row is -1 === 65535) - AreaPtg ptg = (AreaPtg)ops.get(0); + // Actually stored as C1 to C65536 + // (last row is -1 === 65535) + AreaPtg ptg = (AreaPtg) ops.get(0); assertEquals(2, ptg.getFirstColumn()); assertEquals(2, ptg.getLastColumn()); assertEquals(0, ptg.getFirstRow()); @@ -207,26 +207,25 @@ public final class TestFormulaEvaluatorBugs extends TestCase { assertEquals("C:C", ptg.toFormulaString(wb)); // Will show as C:C, but won't know how many - // rows it covers as we don't have the sheet - // to hand when turning the Ptgs into a string + // rows it covers as we don't have the sheet + // to hand when turning the Ptgs into a string assertEquals("SUM(C:C)", cellSUM.getCellFormula()); eva.setCurrentRow(rowSUM); // But the evaluator knows the sheet, so it - // can do it properly + // can do it properly assertEquals(6, eva.evaluate(cellSUM).getNumberValue(), 0); - // Test the index // Again, the formula string will be right but - // lacking row count, evaluated will be right - HSSFCell cellIDX = rowIDX.getCell((short)0); + // lacking row count, evaluated will be right + HSSFCell cellIDX = rowIDX.getCell((short) 0); assertEquals("INDEX(C:C,2,1)", cellIDX.getCellFormula()); eva.setCurrentRow(rowIDX); assertEquals(2, eva.evaluate(cellIDX).getNumberValue(), 0); // Across two colums - HSSFCell cellSUM2D = rowSUM2D.getCell((short)0); + HSSFCell cellSUM2D = rowSUM2D.getCell((short) 0); assertEquals("SUM(C:D)", cellSUM2D.getCellFormula()); eva.setCurrentRow(rowSUM2D); assertEquals(66, eva.evaluate(cellSUM2D).getNumberValue(), 0); @@ -240,7 +239,7 @@ public final class TestFormulaEvaluatorBugs extends TestCase { HSSFSheet sheet = wb.createSheet(); wb.setSheetName(0, "Sheet1"); HSSFRow row = sheet.createRow(0); - HSSFCell cell = row.createCell((short)0); + HSSFCell cell = row.createCell((short) 0); cell.setCellFormula("1=1"); @@ -253,29 +252,46 @@ public final class TestFormulaEvaluatorBugs extends TestCase { } assertEquals(true, cell.getBooleanCellValue()); } - + public void testClassCast_bug44861() throws Exception { - HSSFWorkbook wb = HSSFTestDataSamples. - openSampleWorkbook("44861.xls"); - + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("44861.xls"); + // Check direct HSSFFormulaEvaluator.evaluateAllFormulaCells(wb); - + // And via calls int numSheets = wb.getNumberOfSheets(); - for(int i=0; i