From ae438a69a11a066f1aa343c4577ad5043bb1d5b6 Mon Sep 17 00:00:00 2001 From: Danny Mui Date: Mon, 9 Feb 2004 22:41:27 +0000 Subject: [PATCH] Patch to support Horizontal and Vertical Page breaks, included testcases and files. PR: Obtained from: Submitted by: Reviewed by: CVS: ---------------------------------------------------------------------- CVS: PR: CVS: If this change addresses a PR in the problem report tracking CVS: database, then enter the PR number(s) here. CVS: Obtained from: CVS: If this change has been taken from another system, such as NCSA, CVS: then name the system in this line, otherwise delete it. CVS: Submitted by: CVS: If this code has been contributed to Apache by someone else; i.e., CVS: they sent us a patch or a new module, then include their name/email CVS: address here. If this is your work then delete this line. CVS: Reviewed by: CVS: If we are doing pre-commit code reviews and someone else has CVS: reviewed your changes, include their name(s) here. CVS: If you have not had it reviewed then delete this line. git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/branches/REL_2_BRANCH@353493 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/poi/hssf/dev/BiffViewer.java | 10 +- src/java/org/apache/poi/hssf/model/Sheet.java | 249 +++++++++++--- .../record/HorizontalPageBreakRecord.java | 107 ++++++ .../poi/hssf/record/PageBreakRecord.java | 304 ++++++++++++++++++ .../apache/poi/hssf/record/RecordFactory.java | 8 +- .../hssf/record/VerticalPageBreakRecord.java | 107 ++++++ .../apache/poi/hssf/usermodel/HSSFSheet.java | 115 ++++++- .../poi/hssf/data/SimpleWithPageBreaks.xls | Bin 0 -> 18432 bytes .../org/apache/poi/hssf/model/SheetTest.java | 121 +++++++ .../poi/hssf/usermodel/TestCloneSheet.java | 19 ++ .../poi/hssf/usermodel/TestHSSFSheet.java | 83 ++++- .../hssf/usermodel/TestSheetShiftRows.java | 36 ++- 12 files changed, 1075 insertions(+), 84 deletions(-) create mode 100644 src/java/org/apache/poi/hssf/record/HorizontalPageBreakRecord.java create mode 100644 src/java/org/apache/poi/hssf/record/PageBreakRecord.java create mode 100644 src/java/org/apache/poi/hssf/record/VerticalPageBreakRecord.java create mode 100644 src/testcases/org/apache/poi/hssf/data/SimpleWithPageBreaks.xls diff --git a/src/java/org/apache/poi/hssf/dev/BiffViewer.java b/src/java/org/apache/poi/hssf/dev/BiffViewer.java index da65d5920c..afc32e3e8c 100644 --- a/src/java/org/apache/poi/hssf/dev/BiffViewer.java +++ b/src/java/org/apache/poi/hssf/dev/BiffViewer.java @@ -2,7 +2,7 @@ * ==================================================================== * The Apache Software License, Version 1.1 * - * Copyright (c) 2003 The Apache Software Foundation. All rights + * Copyright (c) 2004 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -633,6 +633,14 @@ public class BiffViewer { case SharedFormulaRecord.sid: retval = new SharedFormulaRecord( rectype, size, data); break; + case HorizontalPageBreakRecord.sid: + retval = new HorizontalPageBreakRecord( rectype, size, data); + break; + case VerticalPageBreakRecord.sid: + retval = new VerticalPageBreakRecord( rectype, size, data); + break; + + default: retval = new UnknownRecord( rectype, size, data ); } diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java index c0f07b829a..b55c7422bf 100644 --- a/src/java/org/apache/poi/hssf/model/Sheet.java +++ b/src/java/org/apache/poi/hssf/model/Sheet.java @@ -2,7 +2,7 @@ /* ==================================================================== * The Apache Software License, Version 1.1 * - * Copyright (c) 2003 The Apache Software Foundation. All rights + * Copyright (c) 2004 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -111,7 +111,7 @@ public class Sheet implements Model protected WindowTwoRecord windowTwo = null; protected MergeCellsRecord merged = null; protected Margin margins[] = null; - protected List mergedRecords = new ArrayList(); + protected List mergedRecords = new ArrayList(); protected int numMergedRegions = 0; protected SelectionRecord selection = null; private static POILogger log = POILogFactory.getLogger(Sheet.class); @@ -121,8 +121,11 @@ public class Sheet implements Model private Iterator valueRecIterator = null; private Iterator rowRecIterator = null; protected int eofLoc = 0; - protected ProtectRecord protect = null; - + protected ProtectRecord protect = null; + protected PageBreakRecord rowBreaks = null; + protected PageBreakRecord colBreaks = null; + + public static final byte PANE_LOWER_RIGHT = (byte)0; public static final byte PANE_UPPER_RIGHT = (byte)1; public static final byte PANE_LOWER_LEFT = (byte)2; @@ -155,7 +158,7 @@ public class Sheet implements Model */ public static Sheet createSheet(List recs, int sheetnum, int offset) { - log.logFormatted(log.DEBUG, + log.logFormatted(POILogger.DEBUG, "Sheet createSheet (existing file) with %", new Integer(recs.size())); Sheet retval = new Sheet(); @@ -170,18 +173,18 @@ public class Sheet implements Model if (rec.getSid() == LabelRecord.sid) { - log.log(log.DEBUG, "Hit label record."); + log.log(POILogger.DEBUG, "Hit label record."); retval.containsLabels = true; } else if (rec.getSid() == BOFRecord.sid) { bofEofNestingLevel++; - log.log(log.DEBUG, "Hit BOF record. Nesting increased to " + bofEofNestingLevel); + log.log(POILogger.DEBUG, "Hit BOF record. Nesting increased to " + bofEofNestingLevel); } else if (rec.getSid() == EOFRecord.sid) { --bofEofNestingLevel; - log.log(log.DEBUG, "Hit EOF record. Nesting decreased to " + bofEofNestingLevel); + log.log(POILogger.DEBUG, "Hit EOF record. Nesting decreased to " + bofEofNestingLevel); if (bofEofNestingLevel == 0) { records.add(rec); retval.eofLoc = k; @@ -289,8 +292,16 @@ public class Sheet implements Model else if ( rec.getSid() == ProtectRecord.sid ) { retval.protect = (ProtectRecord) 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); @@ -307,7 +318,7 @@ public class Sheet implements Model // { // retval.cells = new ValueRecordsAggregate(); // } - log.log(log.DEBUG, "sheet createSheet (existing file) exited"); + log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited"); return retval; } @@ -366,7 +377,7 @@ public class Sheet implements Model public static Sheet createSheet(List records, int sheetnum) { - log.log(log.DEBUG, + log.log(POILogger.DEBUG, "Sheet createSheet (exisiting file) assumed offset 0"); return createSheet(records, sheetnum, 0); } @@ -381,7 +392,7 @@ public class Sheet implements Model public static Sheet createSheet() { - log.log(log.DEBUG, "Sheet createsheet from scratch called"); + log.log(POILogger.DEBUG, "Sheet createsheet from scratch called"); Sheet retval = new Sheet(); ArrayList records = new ArrayList(30); @@ -404,8 +415,14 @@ public class Sheet implements Model (DefaultRowHeightRecord) retval.createDefaultRowHeight(); records.add( retval.defaultrowheight ); records.add( retval.createWSBool() ); + + retval.rowBreaks = new PageBreakRecord(PageBreakRecord.HORIZONTAL_SID); + 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() ); @@ -415,9 +432,9 @@ public class Sheet implements Model retval.defaultcolwidth = (DefaultColWidthRecord) retval.createDefaultColWidth(); records.add( retval.defaultcolwidth); - retval.dims = ( DimensionsRecord ) retval.createDimensions(); - retval.dimsloc = 19; + retval.dims = ( DimensionsRecord ) retval.createDimensions(); records.add(retval.dims); + retval.dimsloc = records.size()-1; records.add(retval.windowTwo = retval.createWindowTwo()); retval.setLoc(records.size() - 1); retval.selection = @@ -426,8 +443,9 @@ public class Sheet implements Model retval.protect = (ProtectRecord) retval.createProtect(); records.add(retval.protect); records.add(retval.createEOF()); + retval.records = records; - log.log(log.DEBUG, "Sheet createsheet from scratch exit"); + log.log(POILogger.DEBUG, "Sheet createsheet from scratch exit"); return retval; } @@ -566,7 +584,7 @@ public class Sheet implements Model public void convertLabelRecords(Workbook wb) { - log.log(log.DEBUG, "convertLabelRecords called"); + log.log(POILogger.DEBUG, "convertLabelRecords called"); if (containsLabels) { for (int k = 0; k < records.size(); k++) @@ -590,7 +608,7 @@ public class Sheet implements Model } } } - log.log(log.DEBUG, "convertLabelRecords exit"); + log.log(POILogger.DEBUG, "convertLabelRecords exit"); } /** @@ -604,8 +622,8 @@ public class Sheet implements Model { checkCells(); checkRows(); - log.log(log.DEBUG, "Sheet.getNumRecords"); - log.logFormatted(log.DEBUG, "returning % + % + % - 2 = %", new int[] + log.log(POILogger.DEBUG, "Sheet.getNumRecords"); + log.logFormatted(POILogger.DEBUG, "returning % + % + % - 2 = %", new int[] { records.size(), cells.getPhysicalNumberOfCells(), rows.getPhysicalNumberOfRows(), @@ -628,8 +646,8 @@ public class Sheet implements Model public void setDimensions(int firstrow, short firstcol, int lastrow, short lastcol) { - log.log(log.DEBUG, "Sheet.setDimensions"); - log.log(log.DEBUG, + log.log(POILogger.DEBUG, "Sheet.setDimensions"); + log.log(POILogger.DEBUG, (new StringBuffer("firstrow")).append(firstrow) .append("firstcol").append(firstcol).append("lastrow") .append(lastrow).append("lastcol").append(lastcol) @@ -638,7 +656,7 @@ public class Sheet implements Model dims.setFirstRow(firstrow); dims.setLastCol(lastcol); dims.setLastRow(lastrow); - log.log(log.DEBUG, "Sheet.setDimensions exiting"); + log.log(POILogger.DEBUG, "Sheet.setDimensions exiting"); } /** @@ -660,7 +678,7 @@ public class Sheet implements Model public void setLoc(int loc) { valueRecIterator = null; - log.log(log.DEBUG, "sheet.setLoc(): " + loc); + log.log(POILogger.DEBUG, "sheet.setLoc(): " + loc); this.loc = loc; } @@ -671,7 +689,7 @@ public class Sheet implements Model public int getLoc() { - log.log(log.DEBUG, "sheet.getLoc():" + loc); + log.log(POILogger.DEBUG, "sheet.getLoc():" + loc); return loc; } @@ -709,7 +727,7 @@ public class Sheet implements Model public byte [] serialize() { - log.log(log.DEBUG, "Sheet.serialize"); + log.log(POILogger.DEBUG, "Sheet.serialize"); // addDBCellRecords(); byte[] retval = null; @@ -726,7 +744,7 @@ public class Sheet implements Model // for (int k = 0; k < bytes.size(); k++) // { // arraysize += (( byte [] ) bytes.get(k)).length; - // log.debug((new StringBuffer("arraysize=")).append(arraysize) + // POILogger.DEBUG((new StringBuffer("arraysize=")).append(arraysize) // .toString()); // } retval = new byte[ arraysize ]; @@ -738,7 +756,7 @@ public class Sheet implements Model pos += (( Record ) records.get(k)).serialize(pos, retval); // rec.length; } - log.log(log.DEBUG, "Sheet.serialize returning " + retval); + log.log(POILogger.DEBUG, "Sheet.serialize returning " + retval); return retval; } @@ -753,7 +771,7 @@ public class Sheet implements Model public int serialize(int offset, byte [] data) { - log.log(log.DEBUG, "Sheet.serialize using offsets"); + log.log(POILogger.DEBUG, "Sheet.serialize using offsets"); // addDBCellRecords(); // ArrayList bytes = new ArrayList(4096); @@ -768,7 +786,7 @@ public class Sheet implements Model // for (int k = 0; k < bytes.size(); k++) // { // arraysize += (( byte [] ) bytes.get(k)).length; - // log.debug((new StringBuffer("arraysize=")).append(arraysize) + // POILogger.DEBUG((new StringBuffer("arraysize=")).append(arraysize) // .toString()); // } for (int k = 0; k < records.size(); k++) @@ -787,7 +805,7 @@ public class Sheet implements Model pos += record.serialize(pos + offset, data ); // rec.length; } - log.log(log.DEBUG, "Sheet.serialize returning "); + log.log(POILogger.DEBUG, "Sheet.serialize returning "); return pos; } @@ -801,7 +819,7 @@ public class Sheet implements Model public RowRecord createRow(int row) { - log.log(log.DEBUG, "create row number " + row); + log.log(POILogger.DEBUG, "create row number " + row); RowRecord rowrec = new RowRecord(); //rowrec.setRowNumber(( short ) row); @@ -826,7 +844,7 @@ public class Sheet implements Model //public LabelSSTRecord createLabelSST(short row, short col, int index) public LabelSSTRecord createLabelSST(int row, short col, int index) { - log.logFormatted(log.DEBUG, "create labelsst row,col,index %,%,%", + log.logFormatted(POILogger.DEBUG, "create labelsst row,col,index %,%,%", new int[] { row, col, index @@ -853,7 +871,7 @@ public class Sheet implements Model //public NumberRecord createNumber(short row, short col, double value) public NumberRecord createNumber(int row, short col, double value) { - log.logFormatted(log.DEBUG, "create number row,col,value %,%,%", + log.logFormatted(POILogger.DEBUG, "create number row,col,value %,%,%", new double[] { row, col, value @@ -878,8 +896,8 @@ public class Sheet implements Model //public BlankRecord createBlank(short row, short col) public BlankRecord createBlank(int row, short col) { - //log.logFormatted(log.DEBUG, "create blank row,col %,%", new short[] - log.logFormatted(log.DEBUG, "create blank row,col %,%", new int[] + //log.logFormatted(POILogger.DEBUG, "create blank row,col %,%", new short[] + log.logFormatted(POILogger.DEBUG, "create blank row,col %,%", new int[] { row, col }); @@ -905,7 +923,7 @@ public class Sheet implements Model //public FormulaRecord createFormula(short row, short col, String formula) public FormulaRecord createFormula(int row, short col, String formula) { - log.logFormatted(log.DEBUG, "create formula row,col,formula %,%,%", + log.logFormatted(POILogger.DEBUG, "create formula row,col,formula %,%,%", //new short[] new int[] { @@ -949,7 +967,7 @@ public class Sheet implements Model public void addValueRecord(int row, CellValueRecordInterface col) { checkCells(); - log.logFormatted(log.DEBUG, "add value record row,loc %,%", new int[] + log.logFormatted(POILogger.DEBUG, "add value record row,loc %,%", new int[] { row, loc }); @@ -1003,7 +1021,7 @@ public class Sheet implements Model public void removeValueRecord(int row, CellValueRecordInterface col) { checkCells(); - log.logFormatted(log.DEBUG, "remove value record row,dimsloc %,%", + log.logFormatted(POILogger.DEBUG, "remove value record row,dimsloc %,%", new int[]{row, dimsloc} ); loc = dimsloc; cells.removeCell(col); @@ -1044,7 +1062,7 @@ public class Sheet implements Model { checkCells(); setLoc(dimsloc); - log.log(log.DEBUG, "replaceValueRecord "); + log.log(POILogger.DEBUG, "replaceValueRecord "); cells.insertCell(newval); /* @@ -1080,7 +1098,7 @@ public class Sheet implements Model public void addRow(RowRecord row) { checkRows(); - log.log(log.DEBUG, "addRow "); + log.log(POILogger.DEBUG, "addRow "); DimensionsRecord d = ( DimensionsRecord ) records.get(getDimsLoc()); if (row.getRowNumber() > d.getLastRow()) @@ -1134,7 +1152,7 @@ public class Sheet implements Model * } * } */ - log.log(log.DEBUG, "exit addRow"); + log.log(POILogger.DEBUG, "exit addRow"); } /** @@ -1194,7 +1212,7 @@ public class Sheet implements Model public CellValueRecordInterface getNextValueRecord() { - log.log(log.DEBUG, "getNextValue loc= " + loc); + log.log(POILogger.DEBUG, "getNextValue loc= " + loc); if (valueRecIterator == null) { valueRecIterator = cells.getIterator(); @@ -1241,7 +1259,7 @@ public class Sheet implements Model /* public Record getNextRowOrValue() { - log.debug((new StringBuffer("getNextRow loc= ")).append(loc) + POILogger.DEBUG((new StringBuffer("getNextRow loc= ")).append(loc) .toString()); if (this.getLoc() < records.size()) { @@ -1281,7 +1299,7 @@ public class Sheet implements Model public RowRecord getNextRow() { - log.log(log.DEBUG, "getNextRow loc= " + loc); + log.log(POILogger.DEBUG, "getNextRow loc= " + loc); if (rowRecIterator == null) { rowRecIterator = rows.getIterator(); @@ -1327,7 +1345,7 @@ public class Sheet implements Model //public RowRecord getRow(short rownum) public RowRecord getRow(int rownum) { - log.log(log.DEBUG, "getNextRow loc= " + loc); + log.log(POILogger.DEBUG, "getNextRow loc= " + loc); return rows.getRow(rownum); /* @@ -1543,7 +1561,7 @@ public class Sheet implements Model { RefModeRecord retval = new RefModeRecord(); - retval.setMode(retval.USE_A1_MODE); + retval.setMode(RefModeRecord.USE_A1_MODE); return retval; } @@ -2161,7 +2179,7 @@ public class Sheet implements Model public int getDimsLoc() { - log.log(log.DEBUG, "getDimsLoc dimsloc= " + dimsloc); + log.log(POILogger.DEBUG, "getDimsLoc dimsloc= " + dimsloc); return dimsloc; } @@ -2533,7 +2551,7 @@ public class Sheet implements Model protected Record createProtect() { - log.log(log.DEBUG, "create protect record with protection disabled"); + log.log(POILogger.DEBUG, "create protect record with protection disabled"); ProtectRecord retval = new ProtectRecord(); retval.setProtect(false); @@ -2604,4 +2622,137 @@ public class Sheet implements Model margins = new Margin[4]; return margins; } + + /** + * Shifts all the page breaks in the range "count" number of rows/columns + * @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 + */ + 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); + } + } + + /** + * Sets a page break at the indicated row + * @param row + */ + public void setRowBreak(int row, short fromCol, short toCol) { + rowBreaks.addBreak((short)row, fromCol, toCol); + } + + /** + * Removes a page break at the indicated row + * @param row + */ + public void removeRowBreak(int row) { + rowBreaks.removeBreak((short)row); + } + + /** + * Queries if the specified row has a page break + * @param row + * @return true if the specified row has a page break + */ + public boolean isRowBroken(int row) { + return rowBreaks.getBreak((short)row) != null; + } + + /** + * Sets a page break at the indicated column + * @param row + */ + public void setColumnBreak(short column, short fromRow, short toRow) { + colBreaks.addBreak(column, fromRow, toRow); + } + + /** + * Removes a page break at the indicated column + * @param row + */ + public void removeColumnBreak(short column) { + colBreaks.removeBreak(column); + } + + /** + * Queries if the specified column has a page break + * @param row + * @return true if the specified column has a page break + */ + public boolean isColumnBroken(short column) { + return colBreaks.getBreak(column) != null; + } + + /** + * Shifts the horizontal page breaks for the indicated count + * @param startingRow + * @param endingRow + * @param count + */ + public void shiftRowBreaks(int startingRow, int endingRow, int count) { + shiftBreaks(rowBreaks, (short)startingRow, (short)endingRow, (short)count); + } + + /** + * Shifts the vertical page breaks for the indicated count + * @param startingCol + * @param endingCol + * @param count + */ + public void shiftColumnBreaks(short startingCol, short endingCol, short count) { + shiftBreaks(colBreaks, startingCol, endingCol, count); + } + + /** + * Returns all the row page breaks + * @return + */ + public Iterator getRowBreaks() { + return rowBreaks.getBreaksIterator(); + } + + /** + * Returns the number of row page breaks + * @return + */ + public int getNumRowBreaks(){ + return (int)rowBreaks.getNumBreaks(); + } + + /** + * Returns all the column page breaks + * @return + */ + public Iterator getColumnBreaks(){ + return colBreaks.getBreaksIterator(); + } + + /** + * Returns the number of column page breaks + * @return + */ + public int getNumColumnBreaks(){ + return (int)colBreaks.getNumBreaks(); + } } diff --git a/src/java/org/apache/poi/hssf/record/HorizontalPageBreakRecord.java b/src/java/org/apache/poi/hssf/record/HorizontalPageBreakRecord.java new file mode 100644 index 0000000000..b7d1eb5121 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/HorizontalPageBreakRecord.java @@ -0,0 +1,107 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2004 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ +package org.apache.poi.hssf.record; + +/** + * HorizontalPageBreak record that stores page breaks at rows + *

+ * This class is just used so that SID compares work properly in the RecordFactory + * @see PageBreakRecord + * @author Danny Mui (dmui at apache dot org) + */ +public class HorizontalPageBreakRecord extends PageBreakRecord { + + public static final short sid = PageBreakRecord.HORIZONTAL_SID; + + /** + * + */ + public HorizontalPageBreakRecord() { + super(); + } + + /** + * @param sid + */ + public HorizontalPageBreakRecord(short sid) { + super(sid); + } + + /** + * @param id + * @param size + * @param data + */ + public HorizontalPageBreakRecord(short id, short size, byte[] data) { + super(id, size, data); + } + + /** + * @param id + * @param size + * @param data + * @param offset + */ + public HorizontalPageBreakRecord(short id, short size, byte[] data, int offset) { + super(id, size, data, offset); + } + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.Record#getSid() + */ + public short getSid() { + return sid; + } + +} diff --git a/src/java/org/apache/poi/hssf/record/PageBreakRecord.java b/src/java/org/apache/poi/hssf/record/PageBreakRecord.java new file mode 100644 index 0000000000..6420e5e400 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/PageBreakRecord.java @@ -0,0 +1,304 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2004 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ +package org.apache.poi.hssf.record; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.poi.util.LittleEndian; + +/** + * Record that contains the functionality page breaks (horizontal and vertical) + *

+ * The other two classes just specifically set the SIDS for record creation + * @see HorizontalPageBreakRecord + * @see VerticalPageBreakREcord + * + * REFERENCE: Microsoft Excel SDK page 322 and 420 + * @author Danny Mui (dmui at apache dot org) + */ +public class PageBreakRecord extends Record { + public static final short HORIZONTAL_SID = (short)0x1B; + public static final short VERTICAL_SID = (short)0x1A; + public short sid; + private short numBreaks; + private List breaks; + private Map BreakMap; + + /** + * Since both records store 2byte integers (short), no point in + * differentiating it in the records. + *

+ * The subs (rows or columns, don't seem to be able to set but excel sets + * them automatically) + */ + public class Break + { + + public short main; + public short subFrom; + public short subTo; + + public Break(short main, short subFrom, short subTo) + { + this.main = main; + this.subFrom = subFrom; + this.subTo = subTo; + } + } + + public PageBreakRecord() + { + + } + + /** + * + * @param sid + */ + public PageBreakRecord(short sid) { + super(); + this.sid = sid; + } + + public PageBreakRecord(short id, short size, byte data[]) + { + super(id, size, data); + this.sid = id; + } + + public PageBreakRecord(short id, short size, byte data[], int offset) + { + super(id, size, data, offset); + this.sid = id; + } + + protected void fillFields(byte data[], short size, int offset) + { + short loadedBreaks = LittleEndian.getShort(data, 0 + offset); + setNumBreaks(loadedBreaks); + int pos = 2; + for(int k = 0; k < loadedBreaks; k++) + { + addBreak((short)(LittleEndian.getShort(data, pos + offset) - 1), LittleEndian.getShort(data, pos + 2 + offset), LittleEndian.getShort(data, pos + 4 + offset)); + pos += 6; + } + + } + + public short getSid() + { + return sid; + } + + public int serialize(int offset, byte data[]) + { + int recordsize = getRecordSize(); + int pos = 6; + LittleEndian.putShort(data, offset + 0, getSid()); + LittleEndian.putShort(data, offset + 2, (short)(recordsize - 4)); + LittleEndian.putShort(data, offset + 4, getNumBreaks()); + for(Iterator iterator = getBreaksIterator(); iterator.hasNext();) + { + Break Break = (Break)iterator.next(); + LittleEndian.putShort(data, offset + pos, (short)(Break.main + 1)); + pos += 2; + LittleEndian.putShort(data, offset + pos, Break.subFrom); + pos += 2; + LittleEndian.putShort(data, offset + pos, Break.subTo); + pos += 2; + } + + return recordsize; + } + + protected void validateSid(short id) + { + if(id != HORIZONTAL_SID && id != VERTICAL_SID) + throw new RecordFormatException("NOT A HorizontalPageBreak or VerticalPageBreak RECORD!! " + id); + else + return; + } + + public short getNumBreaks() + { + return breaks != null ? (short)breaks.size() : numBreaks; + } + + public void setNumBreaks(short numBreaks) + { + this.numBreaks = numBreaks; + } + + public Iterator getBreaksIterator() + { + if(breaks == null) + return Collections.EMPTY_LIST.iterator(); + else + return breaks.iterator(); + } + + public String toString() + { + StringBuffer retval = new StringBuffer(); + + if (getSid() != HORIZONTAL_SID && getSid()!= VERTICAL_SID) + return "[INVALIDPAGEBREAK]\n .sid ="+getSid()+"[INVALIDPAGEBREAK]"; + + String label; + String mainLabel; + String subLabel; + + if (getSid() == HORIZONTAL_SID) { + label = "HORIZONTALPAGEBREAK"; + mainLabel = "row"; + subLabel = "col"; + } else { + label = "VERTICALPAGEBREAK"; + mainLabel = "column"; + subLabel = "row"; + } + + retval.append("["+label+"]").append("\n"); + retval.append(" .sid =").append(getSid()).append("\n"); + retval.append(" .numbreaks =").append(getNumBreaks()).append("\n"); + Iterator iterator = getBreaksIterator(); + for(int k = 0; k < getNumBreaks(); k++) + { + Break region = (Break)iterator.next(); + + retval.append(" .").append(mainLabel).append(" (zero-based) =").append(region.main).append("\n"); + retval.append(" .").append(subLabel).append("From =").append(region.subFrom).append("\n"); + retval.append(" .").append(subLabel).append("To =").append(region.subTo).append("\n"); + } + + retval.append("["+label+"]").append("\n"); + return retval.toString(); + } + + /** + * Adds the page break at the specified parameters + * @param main Depending on sid, will determine row or column to put page break (zero-based) + * @param subFrom No user-interface to set (defaults to minumum, 0) + * @param subTo No user-interface to set + */ + public void addBreak(short main, short subFrom, short subTo) + { + if(breaks == null) + { + breaks = new ArrayList(getNumBreaks() + 10); + BreakMap = new HashMap(); + } + Integer key = new Integer(main); + Break region = (Break)BreakMap.get(key); + if(region != null) + { + region.main = main; + region.subFrom = subFrom; + region.subTo = subTo; + } else + { + region = new Break(main, subFrom, subTo); + breaks.add(region); + } + BreakMap.put(key, region); + } + + /** + * Removes the break indicated by the parameter + * @param main (zero-based) + */ + public void removeBreak(short main) + { + Integer rowKey = new Integer(main); + Break region = (Break)BreakMap.get(rowKey); + breaks.remove(region); + BreakMap.remove(rowKey); + } + + public int getRecordSize() + { + return 6 + getNumBreaks() * 6; + } + + /** + * Retrieves the region at the row/column indicated + * @param main + * @return + */ + public Break getBreak(short main) + { + Integer rowKey = new Integer(main); + return (Break)BreakMap.get(rowKey); + } + + /* Clones the page break record + * @see java.lang.Object#clone() + */ + public Object clone() { + PageBreakRecord record = new PageBreakRecord(getSid()); + Iterator iterator = getBreaksIterator(); + while (iterator.hasNext()) { + Break original = (Break)iterator.next(); + record.addBreak(original.main, original.subFrom, original.subTo); + } + return record; + } + + +} diff --git a/src/java/org/apache/poi/hssf/record/RecordFactory.java b/src/java/org/apache/poi/hssf/record/RecordFactory.java index f12f903b06..6d6bb40314 100644 --- a/src/java/org/apache/poi/hssf/record/RecordFactory.java +++ b/src/java/org/apache/poi/hssf/record/RecordFactory.java @@ -2,7 +2,7 @@ /* ==================================================================== * The Apache Software License, Version 1.1 * - * Copyright (c) 2003 The Apache Software Foundation. All rights + * Copyright (c) 2004 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -112,7 +112,8 @@ public class RecordFactory FormulaRecord.class, BoolErrRecord.class, ExternSheetRecord.class, NameRecord.class, LeftMarginRecord.class, RightMarginRecord.class, TopMarginRecord.class, BottomMarginRecord.class, - PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class + PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class, + HorizontalPageBreakRecord.class, VerticalPageBreakRecord.class }; } else { records = new Class[] @@ -143,7 +144,8 @@ public class RecordFactory BoolErrRecord.class, ExternSheetRecord.class, NameRecord.class, LeftMarginRecord.class, RightMarginRecord.class, TopMarginRecord.class, BottomMarginRecord.class, - PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class + PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class, + HorizontalPageBreakRecord.class, VerticalPageBreakRecord.class }; } diff --git a/src/java/org/apache/poi/hssf/record/VerticalPageBreakRecord.java b/src/java/org/apache/poi/hssf/record/VerticalPageBreakRecord.java new file mode 100644 index 0000000000..10a9b7cd4b --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/VerticalPageBreakRecord.java @@ -0,0 +1,107 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2004 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ +package org.apache.poi.hssf.record; + +/** + * VerticalPageBreak record that stores page breaks at columns + *

+ * This class is just used so that SID compares work properly in the RecordFactory + * @see PageBreakRecord + * @author Danny Mui (dmui at apache dot org) + */ +public class VerticalPageBreakRecord extends PageBreakRecord { + + public static final short sid = PageBreakRecord.VERTICAL_SID; + + /** + * + */ + public VerticalPageBreakRecord() { + super(); + } + + /** + * @param sid + */ + public VerticalPageBreakRecord(short sid) { + super(sid); + } + + /** + * @param id + * @param size + * @param data + */ + public VerticalPageBreakRecord(short id, short size, byte[] data) { + super(id, size, data); + } + + /** + * @param id + * @param size + * @param data + * @param offset + */ + public VerticalPageBreakRecord(short id, short size, byte[] data, int offset) { + super(id, size, data, offset); + } + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.Record#getSid() + */ + public short getSid() { + return PageBreakRecord.VERTICAL_SID; + } + +} diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index 9fe691724c..f8c314b808 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -1,7 +1,7 @@ /* ==================================================================== * The Apache Software License, Version 1.1 * - * Copyright (c) 2003 The Apache Software Foundation. All rights + * Copyright (c) 2004 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -68,6 +68,7 @@ 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.HCenterRecord; +import org.apache.poi.hssf.record.PageBreakRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.RowRecord; import org.apache.poi.hssf.record.SCLRecord; @@ -981,6 +982,8 @@ public class HSSFSheet *

* Additionally shifts merged regions that are completely defined in these * rows (ie. merged 2 cells on a row to be shifted). + *

+ * TODO Might want to add bounds checking here * @param startRow the row to start shifting * @param endRow the row to end shifting * @param n the number of rows to shift @@ -1004,7 +1007,8 @@ public class HSSFSheet } shiftMerged(startRow, endRow, n, true); - + sheet.shiftRowBreaks(startRow, endRow, n); + for ( int rowNum = s; rowNum >= startRow && rowNum <= endRow && rowNum >= 0 && rowNum < 65536; rowNum += inc ) { HSSFRow row = getRow( rowNum ); @@ -1130,7 +1134,7 @@ public class HSSFSheet * @return whether formulas are displayed */ public boolean isDisplayFormulas() { - return sheet.isDisplayFormulas(); + return sheet.isDisplayFormulas(); } /** @@ -1146,6 +1150,109 @@ public class HSSFSheet * @return whether RowColHeadings are displayed */ public boolean isDisplayRowColHeadings() { - return sheet.isDisplayRowColHeadings(); + return sheet.isDisplayRowColHeadings(); + } + + /** + * Sets a page break at the indicated row + * @param row + */ + public void setRowBreak(int row) { + validateRow(row); + sheet.setRowBreak(row, (short)0, (short)255); + } + + /** + * Determines if there is a page break at the indicated row + * @param row + * @return + */ + public boolean isRowBroken(int row) { + return sheet.isRowBroken(row); + } + + /** + * Removes the page break at the indicated row + * @param row + */ + public void removeRowBreak(int row) { + sheet.removeRowBreak(row); + } + + /** + * Retrieves all the horizontal page breaks + * @return + */ + public int[] getRowBreaks(){ + //we can probably cache this information, but this should be a sparsely used function + int[] returnValue = new int[sheet.getNumRowBreaks()]; + Iterator iterator = sheet.getRowBreaks(); + int i = 0; + while (iterator.hasNext()) { + PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); + returnValue[i++] = (int)breakItem.main; + } + return returnValue; + } + + /** + * Retrieves all the vertical page breaks + * @return + */ + public short[] getColumnBreaks(){ + //we can probably cache this information, but this should be a sparsely used function + short[] returnValue = new short[sheet.getNumColumnBreaks()]; + Iterator iterator = sheet.getColumnBreaks(); + int i = 0; + while (iterator.hasNext()) { + PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next(); + returnValue[i++] = breakItem.main; + } + return returnValue; + } + + + /** + * Sets a page break at the indicated column + * @param column + */ + public void setColumnBreak(short column) { + validateColumn(column); + sheet.setColumnBreak(column, (short)0, (short)65535); + } + + /** + * Determines if there is a page break at the indicated column + * @param column + * @return + */ + public boolean isColumnBroken(short column) { + return sheet.isColumnBroken(column); + } + + /** + * Removes a page break at the indicated column + * @param column + */ + public void removeColumnBreak(short column) { + sheet.removeColumnBreak(column); + } + + /** + * Runs a bounds check for row numbers + * @param row + */ + protected void validateRow(int row) { + if (row > 65535) throw new IllegalArgumentException("Maximum row number is 65535"); + if (row < 0) throw new IllegalArgumentException("Minumum row number is 0"); + } + + /** + * Runs a bounds check for column numbers + * @param column + */ + protected void validateColumn(short column) { + if (column > 255) throw new IllegalArgumentException("Maximum column number is 255"); + if (column < 0) throw new IllegalArgumentException("Minimum column number is 0"); } } diff --git a/src/testcases/org/apache/poi/hssf/data/SimpleWithPageBreaks.xls b/src/testcases/org/apache/poi/hssf/data/SimpleWithPageBreaks.xls new file mode 100644 index 0000000000000000000000000000000000000000..bb2e8041e9e822b7f16ce46c283d6121e766a014 GIT binary patch literal 18432 zcmeHPYiLwQ6h3!zH`zQi8=p05yslc4nA+&JDq2kxEecI7N>MNxW8BrC$(Ce8l~UZc z3N2XBS}Y5K`lqxAwWXyGD0YK?{1MwCmD1vmX#7 zEoWr$Vtu(N>MNGT6~5z+tE4fjnmC~Yys%UAdGj#>2{$yxL zE^BIfoi3tzxJ$iGo%RX8PGfQ1+p?P`$nE~ywj@^2Knm+4y@Q%gb1G^K z@nd7<U+}5L5b_A6_;6uwX_Kn9?0G>uKyxF|7g}td!DZdYs z$`_Ps)Z)`v=8ZTy{Ows~RKA{uAQNHu<52`@ zgbT>TVlgBUibidU`h#fGMP0CG5^6(FL6p0=!-(|7eR9X#9<@+&3?*#1T^HKhc9fzh z+flSdzdb!YsXj>cgUIQq{Zch92gakB*HT*EmL;8Tvt zI1S*`E$3=|PXgu}I0**c!OA$K5)&K6Y53^ncDAp${=jUX z$M1xGfO1R}P^!dtfes%{1ff^{{OiceVL6GpFGa3PnfJQ(gFfs@{#4grt zFr7&a{C(7Y=;ZBt>vwz4V9Pmg?$>|tR_Zedwvn=Ps6}c*)6IR#-)*U_j9DSx>q4i=ElrsExK?_P1uzNWxls)dfekNj}!#(9JDkw(A! zHu89UK?jY1MnEH=5zq)|1T+E~0gZr0KqH_L&1CCu_|(CddRE;$Z}5G0^sB`G9;Z0u zw18X*|2&StbimK5$Uzm7P4M4FduYcajsyP#g}iU