package jxl.write.biff; import common.Assert; import common.Logger; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.TreeSet; import jxl.Cell; import jxl.Range; import jxl.SheetSettings; import jxl.WorkbookSettings; import jxl.biff.ByteData; import jxl.biff.WorkspaceInformationRecord; import jxl.biff.XFRecord; import jxl.biff.drawing.Chart; import jxl.biff.drawing.SheetDrawingWriter; import jxl.format.Border; import jxl.format.BorderLineStyle; import jxl.format.CellFormat; import jxl.format.Colour; import jxl.write.Blank; import jxl.write.WritableCell; import jxl.write.WritableCellFormat; import jxl.write.WritableHyperlink; import jxl.write.WriteException; final class SheetWriter { private static Logger logger = Logger.getLogger(SheetWriter.class); private File outputFile; private RowRecord[] rows; private int numRows; private int numCols; private HeaderRecord header; private FooterRecord footer; private SheetSettings settings; private WorkbookSettings workbookSettings; private ArrayList rowBreaks; private ArrayList hyperlinks; private DataValidation dataValidation; private MergedCells mergedCells; private PLSRecord plsRecord; private ButtonPropertySetRecord buttonPropertySet; private WorkspaceInformationRecord workspaceOptions; private TreeSet columnFormats; private SheetDrawingWriter drawingWriter; private boolean chartOnly; private WritableSheetImpl sheet; public SheetWriter(File of, WritableSheetImpl wsi, WorkbookSettings ws) { this.outputFile = of; this.sheet = wsi; this.workspaceOptions = new WorkspaceInformationRecord(); this.workbookSettings = ws; this.chartOnly = false; this.drawingWriter = new SheetDrawingWriter(ws); } public void write() throws IOException { Assert.verify((this.rows != null)); if (this.chartOnly) { this.drawingWriter.write(this.outputFile); return; } BOFRecord bof = new BOFRecord(BOFRecord.sheet); this.outputFile.write((ByteData)bof); int numBlocks = this.numRows / 32; if (this.numRows - numBlocks * 32 != 0) numBlocks++; int indexPos = this.outputFile.getPos(); IndexRecord indexRecord = new IndexRecord(0, this.numRows, numBlocks); this.outputFile.write((ByteData)indexRecord); if (this.settings.getAutomaticFormulaCalculation()) { CalcModeRecord cmr = new CalcModeRecord(CalcModeRecord.automatic); this.outputFile.write((ByteData)cmr); } else { CalcModeRecord cmr = new CalcModeRecord(CalcModeRecord.manual); this.outputFile.write((ByteData)cmr); } CalcCountRecord ccr = new CalcCountRecord(100); this.outputFile.write((ByteData)ccr); RefModeRecord rmr = new RefModeRecord(); this.outputFile.write((ByteData)rmr); IterationRecord itr = new IterationRecord(false); this.outputFile.write((ByteData)itr); DeltaRecord dtr = new DeltaRecord(0.001D); this.outputFile.write((ByteData)dtr); SaveRecalcRecord srr = new SaveRecalcRecord(this.settings.getRecalculateFormulasBeforeSave()); this.outputFile.write((ByteData)srr); PrintHeadersRecord phr = new PrintHeadersRecord(this.settings.getPrintHeaders()); this.outputFile.write((ByteData)phr); PrintGridLinesRecord pglr = new PrintGridLinesRecord(this.settings.getPrintGridLines()); this.outputFile.write((ByteData)pglr); GridSetRecord gsr = new GridSetRecord(true); this.outputFile.write((ByteData)gsr); GuttersRecord gutr = new GuttersRecord(); this.outputFile.write((ByteData)gutr); DefaultRowHeightRecord drhr = new DefaultRowHeightRecord(this.settings.getDefaultRowHeight(), (this.settings.getDefaultRowHeight() != 255)); this.outputFile.write((ByteData)drhr); this.workspaceOptions.setFitToPages(this.settings.getFitToPages()); this.outputFile.write((ByteData)this.workspaceOptions); if (this.rowBreaks.size() > 0) { int[] rb = new int[this.rowBreaks.size()]; for (int i = 0; i < rb.length; i++) rb[i] = ((Integer)this.rowBreaks.get(i)).intValue(); HorizontalPageBreaksRecord hpbr = new HorizontalPageBreaksRecord(rb); this.outputFile.write((ByteData)hpbr); } HeaderRecord header = new HeaderRecord(this.settings.getHeader().toString()); this.outputFile.write((ByteData)header); FooterRecord footer = new FooterRecord(this.settings.getFooter().toString()); this.outputFile.write((ByteData)footer); HorizontalCentreRecord hcr = new HorizontalCentreRecord(this.settings.isHorizontalCentre()); this.outputFile.write((ByteData)hcr); VerticalCentreRecord vcr = new VerticalCentreRecord(this.settings.isVerticalCentre()); this.outputFile.write((ByteData)vcr); if (this.settings.getLeftMargin() != this.settings.getDefaultWidthMargin()) { MarginRecord mr = new LeftMarginRecord(this.settings.getLeftMargin()); this.outputFile.write((ByteData)mr); } if (this.settings.getRightMargin() != this.settings.getDefaultWidthMargin()) { MarginRecord mr = new RightMarginRecord(this.settings.getRightMargin()); this.outputFile.write((ByteData)mr); } if (this.settings.getTopMargin() != this.settings.getDefaultHeightMargin()) { MarginRecord mr = new TopMarginRecord(this.settings.getTopMargin()); this.outputFile.write((ByteData)mr); } if (this.settings.getBottomMargin() != this.settings.getDefaultHeightMargin()) { MarginRecord mr = new BottomMarginRecord(this.settings.getBottomMargin()); this.outputFile.write((ByteData)mr); } if (this.plsRecord != null) this.outputFile.write((ByteData)this.plsRecord); SetupRecord setup = new SetupRecord(this.settings); this.outputFile.write((ByteData)setup); if (this.settings.isProtected()) { ProtectRecord pr = new ProtectRecord(this.settings.isProtected()); this.outputFile.write((ByteData)pr); ScenarioProtectRecord spr = new ScenarioProtectRecord(this.settings.isProtected()); this.outputFile.write((ByteData)spr); ObjectProtectRecord opr = new ObjectProtectRecord(this.settings.isProtected()); this.outputFile.write((ByteData)opr); if (this.settings.getPassword() != null) { PasswordRecord pw = new PasswordRecord(this.settings.getPassword()); this.outputFile.write((ByteData)pw); } else if (this.settings.getPasswordHash() != 0) { PasswordRecord pw = new PasswordRecord(this.settings.getPasswordHash()); this.outputFile.write((ByteData)pw); } } indexRecord.setDataStartPosition(this.outputFile.getPos()); DefaultColumnWidth dcw = new DefaultColumnWidth(this.settings.getDefaultColumnWidth()); this.outputFile.write((ByteData)dcw); WritableCellFormat normalStyle = this.sheet.getWorkbook().getStyles().getNormalStyle(); WritableCellFormat defaultDateFormat = this.sheet.getWorkbook().getStyles().getDefaultDateFormat(); ColumnInfoRecord cir = null; for (Iterator colit = this.columnFormats.iterator(); colit.hasNext(); ) { cir = colit.next(); if (cir.getColumn() < 256) this.outputFile.write((ByteData)cir); XFRecord xfr = cir.getCellFormat(); if (xfr != normalStyle && cir.getColumn() < 256) { Cell[] cells = getColumn(cir.getColumn()); for (int i = 0; i < cells.length; i++) { if (cells[i] != null && (cells[i].getCellFormat() == normalStyle || cells[i].getCellFormat() == defaultDateFormat)) ((WritableCell)cells[i]).setCellFormat((CellFormat)xfr); } } } DimensionRecord dr = new DimensionRecord(this.numRows, this.numCols); this.outputFile.write((ByteData)dr); for (int block = 0; block < numBlocks; block++) { DBCellRecord dbcell = new DBCellRecord(this.outputFile.getPos()); int blockRows = Math.min(32, this.numRows - block * 32); boolean firstRow = true; int i; for (i = block * 32; i < block * 32 + blockRows; i++) { if (this.rows[i] != null) { this.rows[i].write(this.outputFile); if (firstRow) { dbcell.setCellOffset(this.outputFile.getPos()); firstRow = false; } } } for (i = block * 32; i < block * 32 + blockRows; i++) { if (this.rows[i] != null) { dbcell.addCellRowPosition(this.outputFile.getPos()); this.rows[i].writeCells(this.outputFile); } } indexRecord.addBlockPosition(this.outputFile.getPos()); dbcell.setPosition(this.outputFile.getPos()); this.outputFile.write((ByteData)dbcell); } if (this.dataValidation != null) this.dataValidation.write(this.outputFile); if (!this.workbookSettings.getDrawingsDisabled()) this.drawingWriter.write(this.outputFile); Window2Record w2r = new Window2Record(this.settings); this.outputFile.write((ByteData)w2r); if (this.settings.getHorizontalFreeze() != 0 || this.settings.getVerticalFreeze() != 0) { PaneRecord pr = new PaneRecord(this.settings.getHorizontalFreeze(), this.settings.getVerticalFreeze()); this.outputFile.write((ByteData)pr); SelectionRecord sr = new SelectionRecord(SelectionRecord.upperLeft, 0, 0); this.outputFile.write((ByteData)sr); if (this.settings.getHorizontalFreeze() != 0) { sr = new SelectionRecord(SelectionRecord.upperRight, this.settings.getHorizontalFreeze(), 0); this.outputFile.write((ByteData)sr); } if (this.settings.getVerticalFreeze() != 0) { sr = new SelectionRecord(SelectionRecord.lowerLeft, 0, this.settings.getVerticalFreeze()); this.outputFile.write((ByteData)sr); } if (this.settings.getHorizontalFreeze() != 0 && this.settings.getVerticalFreeze() != 0) { sr = new SelectionRecord(SelectionRecord.lowerRight, this.settings.getHorizontalFreeze(), this.settings.getVerticalFreeze()); this.outputFile.write((ByteData)sr); } Weird1Record w1r = new Weird1Record(); this.outputFile.write((ByteData)w1r); } else { SelectionRecord sr = new SelectionRecord(SelectionRecord.upperLeft, 0, 0); this.outputFile.write((ByteData)sr); } if (this.settings.getZoomFactor() != 100) { SCLRecord sclr = new SCLRecord(this.settings.getZoomFactor()); this.outputFile.write((ByteData)sclr); } this.mergedCells.write(this.outputFile); Iterator hi = this.hyperlinks.iterator(); WritableHyperlink hlr = null; while (hi.hasNext()) { hlr = hi.next(); this.outputFile.write((ByteData)hlr); } if (this.buttonPropertySet != null) this.outputFile.write((ByteData)this.buttonPropertySet); EOFRecord eof = new EOFRecord(); this.outputFile.write((ByteData)eof); this.outputFile.setData(indexRecord.getData(), indexPos + 4); } final HeaderRecord getHeader() { return this.header; } final FooterRecord getFooter() { return this.footer; } void setWriteData(RowRecord[] rws, ArrayList rb, ArrayList hl, MergedCells mc, TreeSet cf) { this.rows = rws; this.rowBreaks = rb; this.hyperlinks = hl; this.mergedCells = mc; this.columnFormats = cf; } void setDimensions(int rws, int cls) { this.numRows = rws; this.numCols = cls; } void setSettings(SheetSettings sr) { this.settings = sr; } WorkspaceInformationRecord getWorkspaceOptions() { return this.workspaceOptions; } void setWorkspaceOptions(WorkspaceInformationRecord wo) { if (wo != null) this.workspaceOptions = wo; } void setCharts(Chart[] ch) { this.drawingWriter.setCharts(ch); } void setDrawings(ArrayList dr, boolean mod) { this.drawingWriter.setDrawings(dr, mod); } Chart[] getCharts() { return this.drawingWriter.getCharts(); } void checkMergedBorders() { Range[] mcells = this.mergedCells.getMergedCells(); ArrayList borderFormats = new ArrayList(); for (int mci = 0; mci < mcells.length; mci++) { Range range = mcells[mci]; Cell topLeft = range.getTopLeft(); XFRecord tlformat = (XFRecord)topLeft.getCellFormat(); if (tlformat != null && tlformat.hasBorders() == true && !tlformat.isRead()) try { CellXFRecord cf1 = new CellXFRecord(tlformat); Cell bottomRight = range.getBottomRight(); cf1.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); cf1.setBorder(Border.LEFT, tlformat.getBorderLine(Border.LEFT), tlformat.getBorderColour(Border.LEFT)); cf1.setBorder(Border.TOP, tlformat.getBorderLine(Border.TOP), tlformat.getBorderColour(Border.TOP)); if (topLeft.getRow() == bottomRight.getRow()) cf1.setBorder(Border.BOTTOM, tlformat.getBorderLine(Border.BOTTOM), tlformat.getBorderColour(Border.BOTTOM)); if (topLeft.getColumn() == bottomRight.getColumn()) cf1.setBorder(Border.RIGHT, tlformat.getBorderLine(Border.RIGHT), tlformat.getBorderColour(Border.RIGHT)); int index = borderFormats.indexOf(cf1); if (index != -1) { cf1 = borderFormats.get(index); } else { borderFormats.add(cf1); } ((WritableCell)topLeft).setCellFormat((CellFormat)cf1); if (bottomRight.getRow() > topLeft.getRow()) { if (bottomRight.getColumn() != topLeft.getColumn()) { CellXFRecord cf2 = new CellXFRecord(tlformat); cf2.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); cf2.setBorder(Border.LEFT, tlformat.getBorderLine(Border.LEFT), tlformat.getBorderColour(Border.LEFT)); cf2.setBorder(Border.BOTTOM, tlformat.getBorderLine(Border.BOTTOM), tlformat.getBorderColour(Border.BOTTOM)); index = borderFormats.indexOf(cf2); if (index != -1) { cf2 = borderFormats.get(index); } else { borderFormats.add(cf2); } this.sheet.addCell((WritableCell)new Blank(topLeft.getColumn(), bottomRight.getRow(), (CellFormat)cf2)); } for (int i = topLeft.getRow() + 1; i < bottomRight.getRow(); i++) { CellXFRecord cf3 = new CellXFRecord(tlformat); cf3.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); cf3.setBorder(Border.LEFT, tlformat.getBorderLine(Border.LEFT), tlformat.getBorderColour(Border.LEFT)); if (topLeft.getColumn() == bottomRight.getColumn()) cf3.setBorder(Border.RIGHT, tlformat.getBorderLine(Border.RIGHT), tlformat.getBorderColour(Border.RIGHT)); index = borderFormats.indexOf(cf3); if (index != -1) { cf3 = borderFormats.get(index); } else { borderFormats.add(cf3); } this.sheet.addCell((WritableCell)new Blank(topLeft.getColumn(), i, (CellFormat)cf3)); } } if (bottomRight.getColumn() > topLeft.getColumn()) { if (bottomRight.getRow() != topLeft.getRow()) { CellXFRecord cf6 = new CellXFRecord(tlformat); cf6.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); cf6.setBorder(Border.RIGHT, tlformat.getBorderLine(Border.RIGHT), tlformat.getBorderColour(Border.RIGHT)); cf6.setBorder(Border.TOP, tlformat.getBorderLine(Border.TOP), tlformat.getBorderColour(Border.TOP)); index = borderFormats.indexOf(cf6); if (index != -1) { cf6 = borderFormats.get(index); } else { borderFormats.add(cf6); } this.sheet.addCell((WritableCell)new Blank(bottomRight.getColumn(), topLeft.getRow(), (CellFormat)cf6)); } int i = topLeft.getRow() + 1; for (; i < bottomRight.getRow(); i++) { CellXFRecord cf7 = new CellXFRecord(tlformat); cf7.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); cf7.setBorder(Border.RIGHT, tlformat.getBorderLine(Border.RIGHT), tlformat.getBorderColour(Border.RIGHT)); index = borderFormats.indexOf(cf7); if (index != -1) { cf7 = borderFormats.get(index); } else { borderFormats.add(cf7); } this.sheet.addCell((WritableCell)new Blank(bottomRight.getColumn(), i, (CellFormat)cf7)); } i = topLeft.getColumn() + 1; for (; i < bottomRight.getColumn(); i++) { CellXFRecord cf8 = new CellXFRecord(tlformat); cf8.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); cf8.setBorder(Border.TOP, tlformat.getBorderLine(Border.TOP), tlformat.getBorderColour(Border.TOP)); if (topLeft.getRow() == bottomRight.getRow()) cf8.setBorder(Border.BOTTOM, tlformat.getBorderLine(Border.BOTTOM), tlformat.getBorderColour(Border.BOTTOM)); index = borderFormats.indexOf(cf8); if (index != -1) { cf8 = borderFormats.get(index); } else { borderFormats.add(cf8); } this.sheet.addCell((WritableCell)new Blank(i, topLeft.getRow(), (CellFormat)cf8)); } } if (bottomRight.getColumn() > topLeft.getColumn() || bottomRight.getRow() > topLeft.getRow()) { CellXFRecord cf4 = new CellXFRecord(tlformat); cf4.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); cf4.setBorder(Border.RIGHT, tlformat.getBorderLine(Border.RIGHT), tlformat.getBorderColour(Border.RIGHT)); cf4.setBorder(Border.BOTTOM, tlformat.getBorderLine(Border.BOTTOM), tlformat.getBorderColour(Border.BOTTOM)); if (bottomRight.getRow() == topLeft.getRow()) cf4.setBorder(Border.TOP, tlformat.getBorderLine(Border.TOP), tlformat.getBorderColour(Border.TOP)); if (bottomRight.getColumn() == topLeft.getColumn()) cf4.setBorder(Border.LEFT, tlformat.getBorderLine(Border.LEFT), tlformat.getBorderColour(Border.LEFT)); index = borderFormats.indexOf(cf4); if (index != -1) { cf4 = borderFormats.get(index); } else { borderFormats.add(cf4); } this.sheet.addCell((WritableCell)new Blank(bottomRight.getColumn(), bottomRight.getRow(), (CellFormat)cf4)); int i = topLeft.getColumn() + 1; for (; i < bottomRight.getColumn(); i++) { CellXFRecord cf5 = new CellXFRecord(tlformat); cf5.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); cf5.setBorder(Border.BOTTOM, tlformat.getBorderLine(Border.BOTTOM), tlformat.getBorderColour(Border.BOTTOM)); if (topLeft.getRow() == bottomRight.getRow()) cf5.setBorder(Border.TOP, tlformat.getBorderLine(Border.TOP), tlformat.getBorderColour(Border.TOP)); index = borderFormats.indexOf(cf5); if (index != -1) { cf5 = borderFormats.get(index); } else { borderFormats.add(cf5); } this.sheet.addCell((WritableCell)new Blank(i, bottomRight.getRow(), (CellFormat)cf5)); } } } catch (WriteException e) { logger.warn(e.toString()); } } } private Cell[] getColumn(int col) { boolean found = false; int row = this.numRows - 1; while (row >= 0 && !found) { if (this.rows[row] != null && this.rows[row].getCell(col) != null) { found = true; continue; } row--; } Cell[] cells = new Cell[row + 1]; for (int i = 0; i <= row; i++) cells[i] = (this.rows[i] != null) ? (Cell)this.rows[i].getCell(col) : null; return cells; } void setChartOnly() { this.chartOnly = true; } void setPLS(PLSRecord pls) { this.plsRecord = pls; } void setButtonPropertySet(ButtonPropertySetRecord bps) { this.buttonPropertySet = bps; } void setDataValidation(DataValidation dv) { this.dataValidation = dv; } }