All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hfg.xml.msofficexml.xlsx.spreadsheetml.style.StylesPart Maven / Gradle / Ivy

There is a newer version: 20240423
Show newest version
package com.hfg.xml.msofficexml.xlsx.spreadsheetml.style;

import java.io.BufferedInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.hfg.datetime.DateUtil;
import com.hfg.util.StringUtil;
import com.hfg.util.collection.OrderedMap;
import com.hfg.util.collection.OrderedSet;
import com.hfg.xml.XMLDoc;
import com.hfg.util.StackTraceUtil;
import com.hfg.xml.XMLTag;
import com.hfg.xml.msofficexml.OfficeOpenXMLContentType;
import com.hfg.xml.msofficexml.OfficeOpenXmlException;
import com.hfg.xml.msofficexml.OfficeXML;
import com.hfg.xml.msofficexml.docx.part.WmlContentType;
import com.hfg.xml.msofficexml.xlsx.SsmlRelationshipType;
import com.hfg.xml.msofficexml.xlsx.Xlsx;
import com.hfg.xml.msofficexml.xlsx.part.SsmlContentType;
import com.hfg.xml.msofficexml.xlsx.part.XlsxPart;
import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlCell;
import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlRow;
import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlSheetData;
import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlWorksheet;
import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlXML;
import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlXMLTag;

//------------------------------------------------------------------------------
/**
 Styles part specific to OfficeOpenXML SpreadsheetML.
 
@author J. Alex Taylor, hairyfatguy.com
*/ //------------------------------------------------------------------------------ // com.hfg XML/HTML Coding Library // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com // [email protected] //------------------------------------------------------------------------------ public class StylesPart extends XlsxPart { private XMLTag mStylesheetTag; private XMLTag mNumberFormatsTag; private XMLTag mFontsTag; private XMLTag mFillsTag; private XMLTag mBordersTag; private XMLTag mCellFormatsTag; private XMLTag mStyleFormatsTag; private XMLTag mCellStylesTag; private XMLTag mDifferentialFormatsTag; private SsmlFont mDefaultFont; private SsmlFill mDefaultFill; private SsmlBorder mDefaultBorder; private SsmlStyleFormat mDefaultStyleFormat; private SsmlCellFormat mDefaultCellFormat; private SsmlCellStyle mNormalStyle; private SsmlCellFormat mDefaultDateCellFormat; private List mNumberFormats = new ArrayList<>(); private List mFonts = new ArrayList<>(); private List mFills = new ArrayList<>(); private List mBorders = new ArrayList<>(); private List mCellFormats = new ArrayList<>(); private List mCellStyleFormats = new ArrayList<>(); private List mCellStyles = new ArrayList<>(); private List mDifferentialFormats = new ArrayList<>(); private final static Logger LOGGER = OfficeXML.getLogger(); //########################################################################## // CONSTRUCTORS //########################################################################## //--------------------------------------------------------------------------- /** This constructor should only be used by the Xlsx object. * @param inXlsx the parent Excel document */ public StylesPart(Xlsx inXlsx) { super(inXlsx); setFile(SsmlXML.STYLES_FILE); if (! (StackTraceUtil.getCallingClassName().equals(getClass().getName()) || StackTraceUtil.getCallingClassName().equals(Xlsx.class.getName()))) { throw new OfficeOpenXmlException("An Xlsx object can have only one styles part! Use xlsx.getStylesPart() to access it."); } // Register the content type inXlsx.getContentTypesPart().addOverride(this); // Register the relationship inXlsx.getWorkbookRelationshipPart().addRelationship(SsmlRelationshipType.STYLES, this); mStylesheetTag = new SsmlStylesheet(inXlsx); setRootNode(mStylesheetTag); // setDefaults(); } //--------------------------------------------------------------------------- public StylesPart(Xlsx inXlsx, BufferedInputStream inStream) { this(inXlsx); XMLDoc doc = new XMLDoc(inStream); mStylesheetTag = (XMLTag) doc.getRootNode(); setRootNode(doc.getRootNode()); mNumberFormatsTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.NUM_FORMATS); if (mNumberFormatsTag != null) { for (XMLTag subtag : (List) (Object) mNumberFormatsTag.getSubtagsByName(SsmlXML.NUM_FORMAT)) { mNumberFormats.add(new SsmlNumberFormat(inXlsx, subtag)); } } mFontsTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.FONTS); if (mFontsTag != null) { for (XMLTag subtag : (List) (Object) mFontsTag.getSubtagsByName(SsmlXML.FONT)) { SsmlFont font = new SsmlFont(inXlsx, subtag); mFonts.add(font); font.setIndex(mFonts.size() - 1); } } // TODO mFillsTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.FILLS); // TODO mBordersTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.BORDERS); mCellFormatsTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.CELL_FORMATS); if (mCellFormatsTag != null) { for (XMLTag subtag : (List) (Object) mCellFormatsTag.getSubtagsByName(SsmlXML.CELL_FORMAT)) { mCellFormats.add(new SsmlCellFormat(inXlsx, subtag)); } } mStyleFormatsTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.CELL_STYLE_FORMATS); mCellStylesTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.CELL_STYLES); mDifferentialFormatsTag = mStylesheetTag.getOptionalSubtagByName(SsmlXML.DIFFERENTIAL_FORMATS); } //--------------------------------------------------------------------------- public void setDefaults() { // mDefaultFont = new SsmlFont(this).setName("Verdana").setSize(10); mDefaultFont = new SsmlFont(this).setName("Calibri").setSize(11).lock(); mDefaultFill = new SsmlFill(this).setPatternType(SsmlPatternType.none); // Add a second default fill value that sometimes seems to be required new SsmlFill(this).setPatternType(SsmlPatternType.gray125); mDefaultBorder = new SsmlBorder(this); mDefaultStyleFormat = new SsmlStyleFormat(this) .setFont(mDefaultFont) .setFill(mDefaultFill) .setBorder(mDefaultBorder); mDefaultCellFormat = new SsmlCellFormat(this) .setFont(mDefaultFont) .setFill(mDefaultFill) .setBorder(mDefaultBorder) .setStyleFormat(mDefaultStyleFormat); mNormalStyle = new SsmlCellStyle(this) .setName("Normal") .setBuiltinId(1) .setStyleFormat(mDefaultStyleFormat); } //########################################################################## // PUBLIC METHODS //########################################################################## //--------------------------------------------------------------------------- @Override public OfficeOpenXMLContentType getContentType() { return SsmlContentType.SPREADSHEET_STYLES; } //--------------------------------------------------------------------------- public SsmlFont getDefaultFont() { return mDefaultFont; } //--------------------------------------------------------------------------- // The default font is special - it must occupy the 0 index position. public StylesPart setDefaultFont(SsmlFont inValue) { mFonts.remove(mDefaultFont); mFontsTag.removeSubtag(mDefaultFont); // Create a locked copy so the default font isn't inadvertently changed. mDefaultFont = inValue.clone(); // It has to go in the 0 position so we have to move it. // First pull it out using the index. mFonts.remove(mDefaultFont.getIndex()); mFonts.add(0, mDefaultFont); // Now do the same for the list of font tags. mFontsTag.removeSubtag(mDefaultFont.getIndex()); mFontsTag.addSubtag(0, mDefaultFont); mDefaultFont.setIndex(0); // We shouldn't have to adjust any other index values mDefaultFont.lock(); return this; } //--------------------------------------------------------------------------- public SsmlFill getDefaultFill() { return mDefaultFill; } //--------------------------------------------------------------------------- public SsmlBorder getDefaultBorder() { return mDefaultBorder; } //--------------------------------------------------------------------------- public SsmlStyleFormat getDefaultStyleFormat() { return mDefaultStyleFormat; } //--------------------------------------------------------------------------- public SsmlCellFormat getDefaultCellFormat() { return mDefaultCellFormat; } //--------------------------------------------------------------------------- public SsmlCellFormat getDefaultDateCellFormat() { if (null == mDefaultDateCellFormat) { mDefaultDateCellFormat = new SsmlCellFormat(this) .setNumberFormat(SsmlNumberFormat.DATE_MM_DD_YY) .setFont(mDefaultFont) .setFill(mDefaultFill) .setBorder(mDefaultBorder); } return mDefaultDateCellFormat; } //--------------------------------------------------------------------------- public List getNumberFormats() { return mNumberFormats; } //--------------------------------------------------------------------------- public int defineNumberFormat(SsmlNumberFormat inValue) { int index = mNumberFormats.size(); mNumberFormats.add(inValue); if (null == mNumberFormatsTag) { mNumberFormatsTag = new XMLTag(SsmlXML.NUM_FORMATS); mStylesheetTag.addSubtag(mNumberFormatsTag); } // Add it to a number formats tag mNumberFormatsTag.addSubtag(inValue); mNumberFormatsTag.setAttribute(SsmlXML.COUNT_ATT, mNumberFormats.size()); return index; } //--------------------------------------------------------------------------- public int defineFont(SsmlFont inValue) { int index = mFonts.size(); mFonts.add(inValue); if (null == mFontsTag) { mFontsTag = new XMLTag(SsmlXML.FONTS); mStylesheetTag.addSubtag(mFontsTag); } // Add it to a fonts tag mFontsTag.addSubtag(inValue); mFontsTag.setAttribute(SsmlXML.COUNT_ATT, mFonts.size()); return index; } //--------------------------------------------------------------------------- public List getFonts() { return mFonts; } //--------------------------------------------------------------------------- public List getFills() { return mFills; } //--------------------------------------------------------------------------- public int defineFill(SsmlFill inValue) { int index = mFills.size(); mFills.add(inValue); if (null == mFillsTag) { mFillsTag = new XMLTag(SsmlXML.FILLS); mStylesheetTag.addSubtag(mFillsTag); } // Add it to a fills tag mFillsTag.addSubtag(inValue); mFillsTag.setAttribute(SsmlXML.COUNT_ATT, mFills.size()); return index; } //--------------------------------------------------------------------------- public List getBorders() { return mBorders; } //--------------------------------------------------------------------------- public int defineBorder(SsmlBorder inValue) { int index = mBorders.size(); mBorders.add(inValue); if (null == mBordersTag) { mBordersTag = new XMLTag(SsmlXML.BORDERS); mStylesheetTag.addSubtag(mBordersTag); } // Add it to a borders tag mBordersTag.addSubtag(inValue); mBordersTag.setAttribute(SsmlXML.COUNT_ATT, mBorders.size()); return index; } //--------------------------------------------------------------------------- public int defineCellFormat(SsmlCellFormat inValue) { int index = mCellFormats.size(); mCellFormats.add(inValue); if (null == mCellFormatsTag) { mCellFormatsTag = new XMLTag(SsmlXML.CELL_FORMATS); mStylesheetTag.addSubtag(mCellFormatsTag); } // Add it to a cell formats (cellXfs) tag mCellFormatsTag.addSubtag(inValue); mCellFormatsTag.setAttribute(SsmlXML.COUNT_ATT, mCellFormats.size()); return index; } //--------------------------------------------------------------------------- public List getCellFormats() { return mCellFormats; } //--------------------------------------------------------------------------- public int defineDifferentialFormat(SsmlDifferentialFormat inValue) { int index = mDifferentialFormats.size(); mDifferentialFormats.add(inValue); if (null == mDifferentialFormatsTag) { mDifferentialFormatsTag = new XMLTag(SsmlXML.DIFFERENTIAL_FORMATS); mStylesheetTag.addSubtag(mDifferentialFormatsTag); } // Add it to a differential formats (dxfs) tag mDifferentialFormatsTag.addSubtag(inValue); mDifferentialFormatsTag.setAttribute(SsmlXML.COUNT_ATT, mDifferentialFormats.size()); return index; } //--------------------------------------------------------------------------- public List getDifferentialFormat() { return mDifferentialFormats; } //--------------------------------------------------------------------------- public int defineStyleFormat(SsmlStyleFormat inValue) { int index = mCellStyleFormats.size(); mCellStyleFormats.add(inValue); if (null == mCellFormatsTag) { mStyleFormatsTag = new XMLTag(SsmlXML.CELL_STYLE_FORMATS); mStylesheetTag.addSubtag(mStyleFormatsTag); } // Add it to a cell style formats (cellStyleXfs) tag mStyleFormatsTag.addSubtag(inValue); mStyleFormatsTag.setAttribute(SsmlXML.COUNT_ATT, mCellStyleFormats.size()); return index; } //--------------------------------------------------------------------------- public List getCellStyleFormats() { return Collections.unmodifiableList(mCellStyleFormats); } //--------------------------------------------------------------------------- public SsmlStyleFormat getStyleFormat(int inIndex) { SsmlStyleFormat requestedStyleFormat = null; if (inIndex >=0 && inIndex < mCellStyleFormats.size()) { requestedStyleFormat = mCellStyleFormats.get(inIndex); } return requestedStyleFormat; } //--------------------------------------------------------------------------- public int defineCellStyle(SsmlCellStyle inValue) { int index = mCellStyles.size(); mCellStyles.add(inValue); if (null == mCellStylesTag) { mCellStylesTag = new XMLTag(SsmlXML.CELL_STYLES); mStylesheetTag.addSubtag(mCellStylesTag); } // Add it to a cell styles (cellStyles) tag mCellStylesTag.addSubtag(inValue); mCellStylesTag.setAttribute(SsmlXML.COUNT_ATT, mCellStyles.size()); return index; } //--------------------------------------------------------------------------- public List getCellStyles() { return Collections.unmodifiableList(mCellStyles); } //--------------------------------------------------------------------------- public void finalizeStyles() { condenseFonts(); // TODO: condenseFills(); condenseBorders(); // TODO: condenseCellStyleFormats(); condenseCellFormats(); } //--------------------------------------------------------------------------- private void condenseFonts() { long startTime = System.currentTimeMillis(); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, getFonts().size() + " fonts before condensation."); } OrderedMap condensedFontMap = new OrderedMap<>(25); for (SsmlFont font : getFonts()) { if (0 == condensedFontMap.size()) { condensedFontMap.put(font.getIndex(), font); } else { boolean isDuplicate = false; for (SsmlFont condensedFont : condensedFontMap.values()) { if (font.equals(condensedFont)) { condensedFontMap.put(font.getIndex(), condensedFont); isDuplicate = true; break; } } if (! isDuplicate) { condensedFontMap.put(font.getIndex(), font); } } } OrderedSet condensedFonts = new OrderedSet<>(condensedFontMap.values()); mFontsTag.clearSubtags(); mFontsTag.setAttribute(SsmlXML.COUNT_ATT, condensedFonts.size()); int index = 0; for (SsmlFont condensedFont : condensedFonts) { condensedFont.setIndex(index++); mFontsTag.addSubtag(condensedFont); } // Now update font ids for (SsmlStyleFormat styleFormat : getCellStyleFormats()) { SsmlFont existingFont = styleFormat.getFont(); if (existingFont != null) { styleFormat.setFont(condensedFontMap.get(existingFont.getIndex())); } } for (SsmlCellFormat cellFormat : getCellFormats()) { cellFormat.setFont(condensedFontMap.get(cellFormat.getFontId())); } if (LOGGER.isLoggable(Level.INFO)) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, condensedFonts.size() + " fonts after condensation."); } LOGGER.log(Level.INFO, "condenseFonts() timing: " + DateUtil.generateElapsedTimeString(startTime)); } } //--------------------------------------------------------------------------- private void condenseBorders() { long startTime = System.currentTimeMillis(); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, getBorders().size() + " borders before condensation."); } OrderedMap condensedBorderMap = new OrderedMap<>(25); for (SsmlBorder border : getBorders()) { if (0 == condensedBorderMap.size()) { condensedBorderMap.put(border.getIndex(), border); } else { boolean isDuplicate = false; for (SsmlBorder condensedBorder : condensedBorderMap.values()) { if (border.equals(condensedBorder)) { condensedBorderMap.put(border.getIndex(), condensedBorder); isDuplicate = true; break; } } if (! isDuplicate) { condensedBorderMap.put(border.getIndex(), border); } } } OrderedSet condensedBorders = new OrderedSet<>(condensedBorderMap.values()); mBordersTag.clearSubtags(); mBordersTag.setAttribute(SsmlXML.COUNT_ATT, condensedBorders.size()); int index = 0; for (SsmlBorder condensedBorder : condensedBorders) { condensedBorder.setIndex(index++); mBordersTag.addSubtag(condensedBorder); } // Now update font ids for (SsmlStyleFormat styleFormat : getCellStyleFormats()) { SsmlBorder existingBorder = styleFormat.getBorder(); if (existingBorder != null) { styleFormat.setBorder(condensedBorderMap.get(existingBorder.getIndex())); } } for (SsmlCellFormat cellFormat : getCellFormats()) { cellFormat.setBorder(condensedBorderMap.get(cellFormat.getBorderId())); } if (LOGGER.isLoggable(Level.INFO)) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, condensedBorders.size() + " borders after condensation."); } LOGGER.log(Level.INFO, "condenseBorders() timing: " + DateUtil.generateElapsedTimeString(startTime)); } } //--------------------------------------------------------------------------- private void condenseCellFormats() { long startTime = System.currentTimeMillis(); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, getCellFormats().size() + " cell formats before condensation."); } // First, build a map of the existing indices to the condensed list of formats OrderedMap condensedCellFormatMap = new OrderedMap<>(25); for (SsmlCellFormat cellFormat : getCellFormats()) { if (0 == condensedCellFormatMap.size()) { condensedCellFormatMap.put(cellFormat.getIndex(), cellFormat); } else { boolean isDuplicate = false; for (SsmlCellFormat condensedCellFormat : condensedCellFormatMap.values()) { if (cellFormat.equals(condensedCellFormat)) { condensedCellFormatMap.put(cellFormat.getIndex(), condensedCellFormat); isDuplicate = true; break; } } if (! isDuplicate) { condensedCellFormatMap.put(cellFormat.getIndex(), cellFormat); } } } // Second, clear the cell format tags from the styles part mCellFormatsTag.clearSubtags(); // Third, add back the condensed list of cell formats OrderedSet condensedCellFormats = new OrderedSet<>(condensedCellFormatMap.values()); mCellFormatsTag.setAttribute(SsmlXML.COUNT_ATT, condensedCellFormats.size()); int index = 0; for (SsmlCellFormat condensedCellFormat : condensedCellFormats) { condensedCellFormat.setIndex(index++); mCellFormatsTag.addSubtag(condensedCellFormat); } // Fourth, update references to cell formats for (SsmlWorksheet worksheet : getParentDoc().getWorkbook().getWorksheets()) { SsmlSheetData sheetData = worksheet.getSheetData(); for (SsmlRow row : sheetData.getRows()) { for (SsmlCell cell : row.getCells()) { String style = cell.getAttributeValue(SsmlXML.STYLE_IDX_ATT); if (StringUtil.isSet(style)) { SsmlCellFormat newCellFormat = condensedCellFormatMap.get(Integer.parseInt(style)); if (newCellFormat != null) { cell.setAttribute(SsmlXML.STYLE_IDX_ATT, newCellFormat.getIndex()); } else { // This should never be the case. It means that something was referencing a non-existent cell format!? System.err.printf("Dangling cell format reference! Sheet:%s, Cell:%s, StyleIdx:%s%n", worksheet.getName(), cell.getRef(), style); } } } } } if (LOGGER.isLoggable(Level.INFO)) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, condensedCellFormats.size() + " cell formats after condensation."); } LOGGER.log(Level.INFO, "condenseCellFormats() timing: " + DateUtil.generateElapsedTimeString(startTime)); } } private class SsmlStylesheet extends SsmlXMLTag { //--------------------------------------------------------------------------- public SsmlStylesheet(Xlsx inXlsx) { super(SsmlXML.STYLESHEET, inXlsx); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy