123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482 |
- /* ====================================================================
- 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.xssf.usermodel;
-
- import java.io.InputStream;
- import java.nio.charset.StandardCharsets;
- import java.util.EnumMap;
- import java.util.Map;
-
- import javax.xml.transform.OutputKeys;
- import javax.xml.transform.Transformer;
- import javax.xml.transform.TransformerException;
- import javax.xml.transform.dom.DOMSource;
- import javax.xml.transform.stream.StreamResult;
-
- import org.apache.commons.io.input.UnsynchronizedByteArrayInputStream;
- import org.apache.commons.io.output.StringBuilderWriter;
- import org.apache.poi.ooxml.util.DocumentHelper;
- import org.apache.poi.ss.usermodel.DifferentialStyleProvider;
- import org.apache.poi.ss.usermodel.TableStyle;
- import org.apache.poi.ss.usermodel.TableStyleType;
- import org.apache.poi.util.XMLHelper;
- import org.apache.poi.xssf.model.StylesTable;
- import org.w3c.dom.Document;
- import org.w3c.dom.Element;
- import org.w3c.dom.Node;
- import org.w3c.dom.NodeList;
-
- import static org.apache.poi.xssf.usermodel.XSSFRelation.NS_SPREADSHEETML;
-
- /**
- * Table style names defined in the OOXML spec.
- * The actual styling is defined in presetTableStyles.xml
- */
- public enum XSSFBuiltinTableStyle {
- /***/
- TableStyleDark1,
- /***/
- TableStyleDark2,
- /***/
- TableStyleDark3,
- /***/
- TableStyleDark4,
- /***/
- TableStyleDark5,
- /***/
- TableStyleDark6,
- /***/
- TableStyleDark7,
- /***/
- TableStyleDark8,
- /***/
- TableStyleDark9,
- /***/
- TableStyleDark10,
- /***/
- TableStyleDark11,
- /***/
- TableStyleLight1,
- /***/
- TableStyleLight2,
- /***/
- TableStyleLight3,
- /***/
- TableStyleLight4,
- /***/
- TableStyleLight5,
- /***/
- TableStyleLight6,
- /***/
- TableStyleLight7,
- /***/
- TableStyleLight8,
- /***/
- TableStyleLight9,
- /***/
- TableStyleLight10,
- /***/
- TableStyleLight11,
- /***/
- TableStyleLight12,
- /***/
- TableStyleLight13,
- /***/
- TableStyleLight14,
- /***/
- TableStyleLight15,
- /***/
- TableStyleLight16,
- /***/
- TableStyleLight17,
- /***/
- TableStyleLight18,
- /***/
- TableStyleLight19,
- /***/
- TableStyleLight20,
- /***/
- TableStyleLight21,
- /***/
- TableStyleMedium1,
- /***/
- TableStyleMedium2,
- /***/
- TableStyleMedium3,
- /***/
- TableStyleMedium4,
- /***/
- TableStyleMedium5,
- /***/
- TableStyleMedium6,
- /***/
- TableStyleMedium7,
- /***/
- TableStyleMedium8,
- /***/
- TableStyleMedium9,
- /***/
- TableStyleMedium10,
- /***/
- TableStyleMedium11,
- /***/
- TableStyleMedium12,
- /***/
- TableStyleMedium13,
- /***/
- TableStyleMedium14,
- /***/
- TableStyleMedium15,
- /***/
- TableStyleMedium16,
- /***/
- TableStyleMedium17,
- /***/
- TableStyleMedium18,
- /***/
- TableStyleMedium19,
- /***/
- TableStyleMedium20,
- /***/
- TableStyleMedium21,
- /***/
- TableStyleMedium22,
- /***/
- TableStyleMedium23,
- /***/
- TableStyleMedium24,
- /***/
- TableStyleMedium25,
- /***/
- TableStyleMedium26,
- /***/
- TableStyleMedium27,
- /***/
- TableStyleMedium28,
- /***/
- PivotStyleMedium1,
- /***/
- PivotStyleMedium2,
- /***/
- PivotStyleMedium3,
- /***/
- PivotStyleMedium4,
- /***/
- PivotStyleMedium5,
- /***/
- PivotStyleMedium6,
- /***/
- PivotStyleMedium7,
- /***/
- PivotStyleMedium8,
- /***/
- PivotStyleMedium9,
- /***/
- PivotStyleMedium10,
- /***/
- PivotStyleMedium11,
- /***/
- PivotStyleMedium12,
- /***/
- PivotStyleMedium13,
- /***/
- PivotStyleMedium14,
- /***/
- PivotStyleMedium15,
- /***/
- PivotStyleMedium16,
- /***/
- PivotStyleMedium17,
- /***/
- PivotStyleMedium18,
- /***/
- PivotStyleMedium19,
- /***/
- PivotStyleMedium20,
- /***/
- PivotStyleMedium21,
- /***/
- PivotStyleMedium22,
- /***/
- PivotStyleMedium23,
- /***/
- PivotStyleMedium24,
- /***/
- PivotStyleMedium25,
- /***/
- PivotStyleMedium26,
- /***/
- PivotStyleMedium27,
- /***/
- PivotStyleMedium28,
- /***/
- PivotStyleLight1,
- /***/
- PivotStyleLight2,
- /***/
- PivotStyleLight3,
- /***/
- PivotStyleLight4,
- /***/
- PivotStyleLight5,
- /***/
- PivotStyleLight6,
- /***/
- PivotStyleLight7,
- /***/
- PivotStyleLight8,
- /***/
- PivotStyleLight9,
- /***/
- PivotStyleLight10,
- /***/
- PivotStyleLight11,
- /***/
- PivotStyleLight12,
- /***/
- PivotStyleLight13,
- /***/
- PivotStyleLight14,
- /***/
- PivotStyleLight15,
- /***/
- PivotStyleLight16,
- /***/
- PivotStyleLight17,
- /***/
- PivotStyleLight18,
- /***/
- PivotStyleLight19,
- /***/
- PivotStyleLight20,
- /***/
- PivotStyleLight21,
- /***/
- PivotStyleLight22,
- /***/
- PivotStyleLight23,
- /***/
- PivotStyleLight24,
- /***/
- PivotStyleLight25,
- /***/
- PivotStyleLight26,
- /***/
- PivotStyleLight27,
- /***/
- PivotStyleLight28,
- /***/
- PivotStyleDark1,
- /***/
- PivotStyleDark2,
- /***/
- PivotStyleDark3,
- /***/
- PivotStyleDark4,
- /***/
- PivotStyleDark5,
- /***/
- PivotStyleDark6,
- /***/
- PivotStyleDark7,
- /***/
- PivotStyleDark8,
- /***/
- PivotStyleDark9,
- /***/
- PivotStyleDark10,
- /***/
- PivotStyleDark11,
- /***/
- PivotStyleDark12,
- /***/
- PivotStyleDark13,
- /***/
- PivotStyleDark14,
- /***/
- PivotStyleDark15,
- /***/
- PivotStyleDark16,
- /***/
- PivotStyleDark17,
- /***/
- PivotStyleDark18,
- /***/
- PivotStyleDark19,
- /***/
- PivotStyleDark20,
- /***/
- PivotStyleDark21,
- /***/
- PivotStyleDark22,
- /***/
- PivotStyleDark23,
- /***/
- PivotStyleDark24,
- /***/
- PivotStyleDark25,
- /***/
- PivotStyleDark26,
- /***/
- PivotStyleDark27,
- /***/
- PivotStyleDark28,
- ;
-
- /**
- * Interestingly, this is initialized after the enum instances, so using an {@link EnumMap} works.
- */
- private static final Map<XSSFBuiltinTableStyle, TableStyle> styleMap = new EnumMap<>(XSSFBuiltinTableStyle.class);
-
- XSSFBuiltinTableStyle() {
- }
-
- /**
- * @return built-in {@link TableStyle} definition
- */
- public TableStyle getStyle() {
- init();
- return styleMap.get(this);
- }
-
- /**
- * NOTE: only checks by name, not definition.
- *
- * @return true if the style represents a built-in style, false if it is null or a custom style
- */
- public static boolean isBuiltinStyle(TableStyle style) {
- if (style == null) return false;
- try {
- XSSFBuiltinTableStyle.valueOf(style.getName());
- return true;
- } catch (IllegalArgumentException e) {
- return false;
- }
- }
-
- /**
- * Only init once - thus the synchronized. Lazy, after creating instances,
- * and only when a style is actually needed, to avoid overhead for uses
- * that don't need the actual style definitions.
- * <p>
- * Public so clients can initialize the map on startup rather than lazily
- * during evaluation if desired.
- */
- public static synchronized void init() {
- if (!styleMap.isEmpty()) return;
-
- /*
- * initialize map. Every built-in has this format:
- * <styleName>
- * <dxfs>
- * <dxf>...</dxf>
- * ...
- * </dxfs>
- * <tableStyles count="1">
- * <tableStyle>...</tableStyle>
- * </tableStyles>
- * </styleName>
- */
- try (InputStream is = XSSFBuiltinTableStyle.class.getResourceAsStream("presetTableStyles.xml")) {
- final Document doc = DocumentHelper.readDocument(is);
-
- final NodeList styleNodes = doc.getDocumentElement().getChildNodes();
- for (int i = 0; i < styleNodes.getLength(); i++) {
- final Node node = styleNodes.item(i);
- if (node.getNodeType() != Node.ELEMENT_NODE) continue; // only care about elements
- final Element tag = (Element) node;
- String styleName = tag.getTagName();
- XSSFBuiltinTableStyle builtIn = XSSFBuiltinTableStyle.valueOf(styleName);
-
- Node dxfsNode = tag.getElementsByTagName("dxfs").item(0);
- Node tableStyleNode = tag.getElementsByTagName("tableStyles").item(0);
-
- // hack because I can't figure out how to get XMLBeans to parse a sub-element in a standalone manner
- // - build a fake styles.xml file with just this built-in
- StylesTable styles = new StylesTable();
- try (UnsynchronizedByteArrayInputStream bis = new UnsynchronizedByteArrayInputStream(
- styleXML(dxfsNode, tableStyleNode).getBytes(StandardCharsets.UTF_8))) {
- styles.readFrom(bis);
- }
- styleMap.put(builtIn, new XSSFBuiltinTypeStyleStyle(builtIn, styles.getExplicitTableStyle(styleName)));
- }
- } catch (Exception e) {
- throw new IllegalStateException(e);
- }
- }
-
- private static String styleXML(Node dxfsNode, Node tableStyleNode) throws TransformerException {
- // built-ins doc uses 1-based dxf indexing, Excel uses 0 based.
- // add a dummy node to adjust properly.
- dxfsNode.insertBefore(dxfsNode.getOwnerDocument().createElement("dxf"), dxfsNode.getFirstChild());
-
- return "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
- "<styleSheet xmlns=\"" + NS_SPREADSHEETML + "\" " +
- "xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" " +
- "xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\" " +
- "xmlns:x16r2=\"http://schemas.microsoft.com/office/spreadsheetml/2015/02/main\" " +
- "mc:Ignorable=\"x14ac x16r2\">\n" +
- writeToString(dxfsNode) +
- writeToString(tableStyleNode) +
- "</styleSheet>";
- }
-
- private static String writeToString(Node node) throws TransformerException {
- try (StringBuilderWriter sw = new StringBuilderWriter(1024)){
- Transformer transformer = XMLHelper.newTransformer();
- transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
- transformer.transform(new DOMSource(node), new StreamResult(sw));
- return sw.toString();
- }
- }
-
- /**
- * implementation for built-in styles
- */
- protected static class XSSFBuiltinTypeStyleStyle implements TableStyle {
-
- private final XSSFBuiltinTableStyle builtIn;
- private final TableStyle style;
-
- protected XSSFBuiltinTypeStyleStyle(XSSFBuiltinTableStyle builtIn, TableStyle style) {
- this.builtIn = builtIn;
- this.style = style;
- }
-
- @Override
- public String getName() {
- return style.getName();
- }
-
- @Override
- public int getIndex() {
- return builtIn.ordinal();
- }
-
- @Override
- public boolean isBuiltin() {
- return true;
- }
-
- @Override
- public DifferentialStyleProvider getStyle(TableStyleType type) {
- return style.getStyle(type);
- }
-
- }
- }
|