diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java b/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java
index 71920a9ff..ebbec778c 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java
@@ -314,4 +314,12 @@ public final class HSSFConditionalFormattingRule implements ConditionalFormattin
}
return HSSFFormulaParser.toFormulaString(workbook, parsedExpression);
}
+
+ /**
+ * Conditional format rules don't define stripes, so always 0
+ * @see org.apache.poi.ss.usermodel.DifferentialStyleProvider#getStripeSize()
+ */
+ public int getStripeSize() {
+ return 0;
+ }
}
diff --git a/src/java/org/apache/poi/ss/usermodel/DifferentialStyleProvider.java b/src/java/org/apache/poi/ss/usermodel/DifferentialStyleProvider.java
index 1b488353c..ce6ad535e 100644
--- a/src/java/org/apache/poi/ss/usermodel/DifferentialStyleProvider.java
+++ b/src/java/org/apache/poi/ss/usermodel/DifferentialStyleProvider.java
@@ -46,4 +46,11 @@ public interface DifferentialStyleProvider {
*/
PatternFormatting getPatternFormatting();
+ /**
+ * This is the number of rows or columns in a band or stripe.
+ * For styles that represent stripes, it must be > 1, for all others it is 0.
+ * Not the greatest overloading by the OOXML spec.
+ * @return number of rows/columns in a stripe for stripe styles, 0 for all others
+ */
+ int getStripeSize();
}
diff --git a/src/java/org/apache/poi/ss/usermodel/Table.java b/src/java/org/apache/poi/ss/usermodel/Table.java
index 01e0394aa..4d8aba1d3 100644
--- a/src/java/org/apache/poi/ss/usermodel/Table.java
+++ b/src/java/org/apache/poi/ss/usermodel/Table.java
@@ -59,6 +59,12 @@ public interface Table {
*/
String getName();
+ /**
+ * @return name of the table style, if there is one. May be a built-in name or user-defined.
+ * @since 3.17 beta 1
+ */
+ String getStyleName();
+
/**
* Returns the index of a given named column in the table (names are case insensitive in XSSF).
* Note this list is lazily loaded and cached for performance.
@@ -70,16 +76,46 @@ public interface Table {
int findColumnIndex(String columnHeader);
/**
* Returns the sheet name that the table belongs to.
+ * @return sheet name
*/
String getSheetName();
+
/**
- * Returns true iff the table has a 'Totals' row
+ * Note: This is misleading. The OOXML spec indicates this is true if the totals row
+ * has ever been shown, not whether or not it is currently displayed.
+ * Use {@link #getTotalsRowCount()} > 0 to decide whether or not the totals row is visible.
+ * @return true if a totals row has ever been shown for this table
+ * @since 3.15 beta 2
+ * @see #getTotalsRowCount()
*/
boolean isHasTotalsRow();
+ /**
+ * @return 0 for no totals rows, 1 for totals row shown.
+ * Values > 1 are not currently used by Excel up through 2016, and the OOXML spec
+ * doesn't define how they would be implemented.
+ * @since 3.17 beta 1
+ */
+ int getTotalsRowCount();
+
+ /**
+ * @return 0 for no header rows, 1 for table headers shown.
+ * Values > 1 might be used by Excel for pivot tables?
+ * @since 3.17 beta 1
+ */
+ int getHeaderRowCount();
+
/**
* @return TableStyleInfo for this instance
* @since 3.17 beta 1
*/
TableStyleInfo getStyle();
+
+ /**
+ * checks if the given cell is part of the table. Includes checking that they are on the same sheet.
+ * @param cell
+ * @return true if the table and cell are on the same sheet and the cell is within the table range.
+ * @since 3.17 beta 1
+ */
+ boolean contains(Cell cell);
}
diff --git a/src/java/org/apache/poi/ss/usermodel/TableStyle.java b/src/java/org/apache/poi/ss/usermodel/TableStyle.java
index e80e0ced7..b4e5e1983 100644
--- a/src/java/org/apache/poi/ss/usermodel/TableStyle.java
+++ b/src/java/org/apache/poi/ss/usermodel/TableStyle.java
@@ -27,10 +27,25 @@ package org.apache.poi.ss.usermodel;
public interface TableStyle {
/**
- * @return name (may be a builtin name)
+ * @return name (may be a built-in name)
*/
String getName();
+ /**
+ * Some clients may care where in the table style list this definition came from, so we'll track it.
+ * The spec only references these by name, unlike Dxf records, which these definitions reference by index
+ * (XML definition order). Nice of MS to be consistent when defining the ECMA standard.
+ * Use org.apache.poi.xssf.usermodel.XSSFBuiltinTableStyle.isBuiltinStyle(TableStyle) to determine whether the index is for a built-in style or explicit user style
+ * @return index from org.apache.poi.xssf.model.StylesTable.getExplicitTableStyle(String) or org.apache.poi.xssf.usermodel.XSSFBuiltinTableStyle.ordinal()
+ */
+ int getIndex();
+
+ /**
+ *
+ * @return true if this is a built-in style defined in the OOXML specification, false if it is a user style
+ */
+ boolean isBuiltin();
+
/**
*
* @param type
diff --git a/src/java/org/apache/poi/ss/usermodel/TableStyleType.java b/src/java/org/apache/poi/ss/usermodel/TableStyleType.java
index 04bfb4ce5..e6fa9dce2 100644
--- a/src/java/org/apache/poi/ss/usermodel/TableStyleType.java
+++ b/src/java/org/apache/poi/ss/usermodel/TableStyleType.java
@@ -17,6 +17,11 @@
package org.apache.poi.ss.usermodel;
+import java.util.EnumSet;
+
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellRangeAddressBase;
+
/**
* Ordered list of table style elements, for both data tables and pivot tables.
* Some elements only apply to pivot tables, but any style definition can omit any number,
@@ -33,34 +38,243 @@ package org.apache.poi.ss.usermodel;
* @since 3.17 beta 1
*/
public enum TableStyleType {
+ /***/
+ wholeTable {
+ CellRangeAddressBase getRange(Table table, Cell cell) {
+ return new CellRangeAddress(table.getStartRowIndex(), table.getEndRowIndex(), table.getStartColIndex(), table.getEndColIndex());
+ }
+ },
+ /***/
+ pageFieldLabels, // pivot only
+ /***/
+ pageFieldValues, // pivot only
+ /***/
+ firstColumnStripe{
+ CellRangeAddressBase getRange(Table table, Cell cell) {
+ TableStyleInfo info = table.getStyle();
+ if (! info.isShowColumnStripes()) return null;
+ DifferentialStyleProvider c1Style = info.getStyle().getStyle(firstColumnStripe);
+ DifferentialStyleProvider c2Style = info.getStyle().getStyle(secondColumnStripe);
+ int c1Stripe = c1Style == null ? 1 : Math.max(1, c1Style.getStripeSize());
+ int c2Stripe = c2Style == null ? 1 : Math.max(1, c2Style.getStripeSize());
+
+ int firstStart = table.getStartColIndex();
+ int secondStart = firstStart + c1Stripe;
+ int c = cell.getColumnIndex();
+
+ // look for the stripe containing c, accounting for the style element stripe size
+ // could do fancy math, but tables can't be that wide, a simple loop is fine
+ // if not in this type of stripe, return null
+ while (true) {
+ if (firstStart > c) break;
+ if (c >= firstStart && c <= secondStart -1) return new CellRangeAddress(table.getStartRowIndex(), table.getEndRowIndex(), firstStart, secondStart - 1);
+ firstStart = secondStart + c2Stripe;
+ secondStart = firstStart + c1Stripe;
+ }
+ return null;
+ }
+ },
+ /***/
+ secondColumnStripe{
+ CellRangeAddressBase getRange(Table table, Cell cell) {
+ TableStyleInfo info = table.getStyle();
+ if (! info.isShowColumnStripes()) return null;
+
+ DifferentialStyleProvider c1Style = info.getStyle().getStyle(firstColumnStripe);
+ DifferentialStyleProvider c2Style = info.getStyle().getStyle(secondColumnStripe);
+ int c1Stripe = c1Style == null ? 1 : Math.max(1, c1Style.getStripeSize());
+ int c2Stripe = c2Style == null ? 1 : Math.max(1, c2Style.getStripeSize());
- wholeTable,
- headerRow,
- totalRow,
- firstColumn,
- lastColumn,
- firstRowStripe,
- secondRowStripe,
- firstColumnStripe,
- secondColumnStripe,
- firstHeaderCell,
- lastHeaderCell,
- firstTotalCell,
- lastTotalCell,
+ int firstStart = table.getStartColIndex();
+ int secondStart = firstStart + c1Stripe;
+ int c = cell.getColumnIndex();
+
+ // look for the stripe containing c, accounting for the style element stripe size
+ // could do fancy math, but tables can't be that wide, a simple loop is fine
+ // if not in this type of stripe, return null
+ while (true) {
+ if (firstStart > c) break;
+ if (c >= secondStart && c <= secondStart + c2Stripe -1) return new CellRangeAddress(table.getStartRowIndex(), table.getEndRowIndex(), secondStart, secondStart + c2Stripe - 1);
+ firstStart = secondStart + c2Stripe;
+ secondStart = firstStart + c1Stripe;
+ }
+ return null;
+ }
+ },
+ /***/
+ firstRowStripe {
+ CellRangeAddressBase getRange(Table table, Cell cell) {
+ TableStyleInfo info = table.getStyle();
+ if (! info.isShowRowStripes()) return null;
+
+ DifferentialStyleProvider c1Style = info.getStyle().getStyle(firstRowStripe);
+ DifferentialStyleProvider c2Style = info.getStyle().getStyle(secondRowStripe);
+ int c1Stripe = c1Style == null ? 1 : Math.max(1, c1Style.getStripeSize());
+ int c2Stripe = c2Style == null ? 1 : Math.max(1, c2Style.getStripeSize());
+
+ int firstStart = table.getStartRowIndex() + table.getHeaderRowCount();
+ int secondStart = firstStart + c1Stripe;
+ int c = cell.getRowIndex();
+
+ // look for the stripe containing c, accounting for the style element stripe size
+ // could do fancy math, but tables can't be that wide, a simple loop is fine
+ // if not in this type of stripe, return null
+ while (true) {
+ if (firstStart > c) break;
+ if (c >= firstStart && c <= secondStart -1) return new CellRangeAddress(firstStart, secondStart - 1, table.getStartColIndex(), table.getEndColIndex());
+ firstStart = secondStart + c2Stripe;
+ secondStart = firstStart + c1Stripe;
+ }
+ return null;
+ }
+ },
+ /***/
+ secondRowStripe{
+ CellRangeAddressBase getRange(Table table, Cell cell) {
+ TableStyleInfo info = table.getStyle();
+ if (! info.isShowRowStripes()) return null;
+
+ DifferentialStyleProvider c1Style = info.getStyle().getStyle(firstRowStripe);
+ DifferentialStyleProvider c2Style = info.getStyle().getStyle(secondRowStripe);
+ int c1Stripe = c1Style == null ? 1 : Math.max(1, c1Style.getStripeSize());
+ int c2Stripe = c2Style == null ? 1 : Math.max(1, c2Style.getStripeSize());
+
+ int firstStart = table.getStartRowIndex() + table.getHeaderRowCount();
+ int secondStart = firstStart + c1Stripe;
+ int c = cell.getRowIndex();
+
+ // look for the stripe containing c, accounting for the style element stripe size
+ // could do fancy math, but tables can't be that wide, a simple loop is fine
+ // if not in this type of stripe, return null
+ while (true) {
+ if (firstStart > c) break;
+ if (c >= secondStart && c <= secondStart +c2Stripe -1) return new CellRangeAddress(secondStart, secondStart + c2Stripe - 1, table.getStartColIndex(), table.getEndColIndex());
+ firstStart = secondStart + c2Stripe;
+ secondStart = firstStart + c1Stripe;
+ }
+ return null;
+ }
+ },
+ /***/
+ lastColumn {
+ CellRangeAddressBase getRange(Table table, Cell cell) {
+ if (! table.getStyle().isShowLastColumn()) return null;
+ return new CellRangeAddress(table.getStartRowIndex(), table.getEndRowIndex(), table.getEndColIndex(), table.getEndColIndex());
+ }
+ },
+ /***/
+ firstColumn {
+ CellRangeAddressBase getRange(Table table, Cell cell) {
+ if (! table.getStyle().isShowFirstColumn()) return null;
+ return new CellRangeAddress(table.getStartRowIndex(), table.getEndRowIndex(), table.getStartColIndex(), table.getStartColIndex());
+ }
+ },
+ /***/
+ headerRow {
+ CellRangeAddressBase getRange(Table table, Cell cell) {
+ if (table.getHeaderRowCount() < 1) return null;
+ return new CellRangeAddress(table.getStartRowIndex(), table.getStartRowIndex() + table.getHeaderRowCount() -1, table.getStartColIndex(), table.getEndColIndex());
+ }
+ },
+ /***/
+ totalRow {
+ CellRangeAddressBase getRange(Table table, Cell cell) {
+ if (table.getTotalsRowCount() < 1) return null;
+ return new CellRangeAddress(table.getEndRowIndex() - table.getTotalsRowCount() +1, table.getEndRowIndex(), table.getStartColIndex(), table.getEndColIndex());
+ }
+ },
+ /***/
+ firstHeaderCell {
+ CellRangeAddressBase getRange(Table table, Cell cell) {
+ if (table.getHeaderRowCount() < 1) return null;
+ return new CellRangeAddress(table.getStartRowIndex(), table.getStartRowIndex(), table.getStartColIndex(), table.getStartColIndex());
+ }
+ },
+ /***/
+ lastHeaderCell {
+ CellRangeAddressBase getRange(Table table, Cell cell) {
+ if (table.getHeaderRowCount() < 1) return null;
+ return new CellRangeAddress(table.getStartRowIndex(), table.getStartRowIndex(), table.getEndColIndex(), table.getEndColIndex());
+ }
+ },
+ /***/
+ firstTotalCell {
+ CellRangeAddressBase getRange(Table table, Cell cell) {
+ if (table.getTotalsRowCount() < 1) return null;
+ return new CellRangeAddress(table.getEndRowIndex() - table.getTotalsRowCount() +1, table.getEndRowIndex(), table.getStartColIndex(), table.getStartColIndex());
+ }
+ },
+ /***/
+ lastTotalCell {
+ CellRangeAddressBase getRange(Table table, Cell cell) {
+ if (table.getTotalsRowCount() < 1) return null;
+ return new CellRangeAddress(table.getEndRowIndex() - table.getTotalsRowCount() +1, table.getEndRowIndex(), table.getEndColIndex(), table.getEndColIndex());
+ }
+ },
+ /* these are for pivot tables only */
+ /***/
firstSubtotalColumn,
+ /***/
secondSubtotalColumn,
+ /***/
thirdSubtotalColumn,
- firstSubtotalRow,
- secondSubtotalRow,
- thirdSubtotalRow,
+ /***/
blankRow,
+ /***/
+ firstSubtotalRow,
+ /***/
+ secondSubtotalRow,
+ /***/
+ thirdSubtotalRow,
+ /***/
firstColumnSubheading,
+ /***/
secondColumnSubheading,
+ /***/
thirdColumnSubheading,
+ /***/
firstRowSubheading,
+ /***/
secondRowSubheading,
+ /***/
thirdRowSubheading,
- pageFieldLabels,
- pageFieldValues,
;
+
+ /**
+ * A range is returned only for the part of the table matching this enum instance and containing the given cell.
+ * Null is returned for all other cases, such as:
+ *
+ * - Cell on a different sheet than the table
+ *
- Cell outside the table
+ *
- this Enum part is not included in the table (i.e. no header/totals row)
+ *
- this Enum is for a table part not yet implemented in POI, such as pivot table elements
+ *
+ * The returned range can be used to determine how style options may or may not apply to this cell.
+ * For example, {@link #wholeTable} borders only apply to the outer boundary of a table, while the
+ * rest of the styling, such as font and color, could apply to all the interior cells as well.
+ *
+ * @param table table to evaluate
+ * @param cell to evaluate
+ * @return range in the table representing this class of cells, if it contains the given cell, or null if not applicable.
+ * Stripe style types return only the stripe range containing the given cell, or null.
+ */
+ public CellRangeAddressBase appliesTo(Table table, Cell cell) {
+ if (table == null || cell == null) return null;
+ if ( ! cell.getSheet().getSheetName().equals(table.getSheetName())) return null;
+ if ( ! table.contains(cell)) return null;
+
+ final CellRangeAddressBase range = getRange(table, cell);
+ if (range != null && range.isInRange(cell.getRowIndex(), cell.getColumnIndex())) return range;
+ // else
+ return null;
+ }
+
+ /**
+ * @param table
+ * @param cell
+ * @return default is unimplemented/null
+ */
+ CellRangeAddressBase getRange(Table table, Cell cell) {
+ return null;
+ }
}
diff --git a/src/java/org/apache/poi/ss/util/CellRangeAddressBase.java b/src/java/org/apache/poi/ss/util/CellRangeAddressBase.java
index e4dc4aeee..cd1052ef2 100644
--- a/src/java/org/apache/poi/ss/util/CellRangeAddressBase.java
+++ b/src/java/org/apache/poi/ss/util/CellRangeAddressBase.java
@@ -17,6 +17,9 @@
package org.apache.poi.ss.util;
+import java.util.EnumSet;
+import java.util.Set;
+
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.usermodel.Cell;
@@ -28,6 +31,23 @@ import org.apache.poi.ss.usermodel.Cell;
*/
public abstract class CellRangeAddressBase {
+ /**
+ * Indicates a cell or range is in the given relative position in a range.
+ * More than one of these may apply at once.
+ */
+ public static enum CellPosition {
+ /** range starting rows are equal */
+ TOP,
+ /** range ending rows are equal */
+ BOTTOM,
+ /** range starting columns are equal */
+ LEFT,
+ /** range ending columns are equal */
+ RIGHT,
+ /** a cell or range is completely inside another range, without touching any edges (a cell in this position can't be in any others) */
+ INSIDE,
+ ;
+ }
private int _firstRow;
private int _firstCol;
private int _lastRow;
@@ -188,6 +208,28 @@ public abstract class CellRangeAddressBase {
other._firstCol <= this._lastCol;
}
+ /**
+ * Useful for logic like table/range styling, where some elements apply based on relative position in a range.
+ * @param rowInd
+ * @param colInd
+ * @return set of {@link CellPosition}s occupied by the given coordinates. Empty if the coordinates are not in the range, never null.
+ * @since 3.17 beta 1
+ */
+ public Set getPosition(int rowInd, int colInd) {
+ Set positions = EnumSet.noneOf(CellPosition.class);
+ if (rowInd > getFirstRow() && rowInd < getLastRow() && colInd > getFirstColumn() && colInd < getLastColumn()) {
+ positions.add(CellPosition.INSIDE);
+ return positions; // entirely inside, matches no boundaries
+ }
+ // check edges
+ if (rowInd == getFirstRow()) positions.add(CellPosition.TOP);
+ if (rowInd == getLastRow()) positions.add(CellPosition.BOTTOM);
+ if (colInd == getFirstColumn()) positions.add(CellPosition.LEFT);
+ if (colInd == getLastColumn()) positions.add(CellPosition.RIGHT);
+
+ return positions;
+ }
+
/**
* @param firstCol column number for the upper left hand corner
*/
diff --git a/src/ooxml/java/org/apache/poi/xssf/model/StylesTable.java b/src/ooxml/java/org/apache/poi/xssf/model/StylesTable.java
index 901757582..8582cf398 100644
--- a/src/ooxml/java/org/apache/poi/xssf/model/StylesTable.java
+++ b/src/ooxml/java/org/apache/poi/xssf/model/StylesTable.java
@@ -29,6 +29,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
@@ -246,8 +247,10 @@ public class StylesTable extends POIXMLDocumentPart {
CTTableStyles ctTableStyles = styleSheet.getTableStyles();
if (ctTableStyles != null) {
+ int idx = 0;
for (CTTableStyle style : Arrays.asList(ctTableStyles.getTableStyleArray())) {
- tableStyles.put(style.getName(), new XSSFTableStyle(styleDxfs, style));
+ tableStyles.put(style.getName(), new XSSFTableStyle(idx, styleDxfs, style));
+ idx++;
}
}
@@ -792,6 +795,14 @@ public class StylesTable extends POIXMLDocumentPart {
return tableStyles.get(name);
}
+ /**
+ * @return names of all explicitly defined table styles in the workbook
+ * @since 3.17 beta 1
+ */
+ public Set getExplicitTableStyleNames() {
+ return tableStyles.keySet();
+ }
+
/**
* @param name of the table style
* @return defined style, either explicit or built-in, or null if not found
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFBuiltinTableStyle.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFBuiltinTableStyle.java
index bf7431b59..aab86abca 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFBuiltinTableStyle.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFBuiltinTableStyle.java
@@ -20,16 +20,15 @@ package org.apache.poi.xssf.usermodel;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
-import java.util.HashMap;
+import java.util.EnumMap;
import java.util.Map;
+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.DocumentHelper;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.model.StylesTable;
-import org.apache.xmlbeans.XmlOptions;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDxfs;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableStyle;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -332,7 +331,10 @@ public enum XSSFBuiltinTableStyle {
PivotStyleDark28,
;
- private static final Map styleMap = new HashMap(60);
+ /**
+ * Interestingly, this is initialized after the enum instances, so using an {@link EnumMap} works.
+ */
+ private static final Map styleMap = new EnumMap(XSSFBuiltinTableStyle.class);
private XSSFBuiltinTableStyle() {
}
@@ -399,7 +401,8 @@ public enum XSSFBuiltinTableStyle {
// - build a fake styles.xml file with just this built-in
StylesTable styles = new StylesTable();
styles.readFrom(new ByteArrayInputStream(styleXML(dxfsNode, tableStyleNode).getBytes(Charset.forName("UTF-8"))));
- styleMap.put(XSSFBuiltinTableStyle.valueOf(styleName), styles.getExplicitTableStyle(styleName));
+ XSSFBuiltinTableStyle builtIn = XSSFBuiltinTableStyle.valueOf(styleName);
+ styleMap.put(builtIn, new XSSFBuiltinTypeStyleStyle(builtIn, styles.getExplicitTableStyle(styleName)));
}
} finally {
IOUtils.closeQuietly(is);
@@ -410,6 +413,10 @@ public enum XSSFBuiltinTableStyle {
}
private static String styleXML(Node dxfsNode, Node tableStyleNode) {
+ // 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());
+
DOMImplementationLS lsImpl = (DOMImplementationLS)dxfsNode.getOwnerDocument().getImplementation().getFeature("LS", "3.0");
LSSerializer lsSerializer = lsImpl.createLSSerializer();
lsSerializer.getDomConfig().setParameter("xml-declaration", false);
@@ -425,4 +432,39 @@ public enum XSSFBuiltinTableStyle {
sb.append("");
return sb.toString();
}
+
+ /**
+ * implementation for built-in styles
+ */
+ protected static class XSSFBuiltinTypeStyleStyle implements TableStyle {
+
+ private final XSSFBuiltinTableStyle builtIn;
+ private final TableStyle style;
+
+ /**
+ * @param builtIn
+ * @param style
+ */
+ protected XSSFBuiltinTypeStyleStyle(XSSFBuiltinTableStyle builtIn, TableStyle style) {
+ this.builtIn = builtIn;
+ this.style = style;
+ }
+
+ public String getName() {
+ return style.getName();
+ }
+
+ public int getIndex() {
+ return builtIn.ordinal();
+ }
+
+ public boolean isBuiltin() {
+ return true;
+ }
+
+ public DifferentialStyleProvider getStyle(TableStyleType type) {
+ return style.getStyle(type);
+ }
+
+ }
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFConditionalFormattingRule.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFConditionalFormattingRule.java
index 5ab6c299a..ec72a5da7 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFConditionalFormattingRule.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFConditionalFormattingRule.java
@@ -412,4 +412,12 @@ public class XSSFConditionalFormattingRule implements ConditionalFormattingRule
public String getFormula2(){
return _cfRule.sizeOfFormulaArray() == 2 ? _cfRule.getFormulaArray(1) : null;
}
+
+ /**
+ * Conditional format rules don't define stripes, so always 0
+ * @see org.apache.poi.ss.usermodel.DifferentialStyleProvider#getStripeSize()
+ */
+ public int getStripeSize() {
+ return 0;
+ }
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDxfStyleProvider.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDxfStyleProvider.java
index 8e03712a0..b725258fa 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDxfStyleProvider.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDxfStyleProvider.java
@@ -34,11 +34,14 @@ public class XSSFDxfStyleProvider implements DifferentialStyleProvider {
private final FontFormatting font;
private final ExcelNumberFormat number;
private final PatternFormatting fill;
+ private final int stripeSize;
/**
* @param dxf
+ * @param stripeSize 0 for non-stripe styles, > 1 for stripes
*/
- public XSSFDxfStyleProvider(CTDxf dxf) {
+ public XSSFDxfStyleProvider(CTDxf dxf, int stripeSize) {
+ this.stripeSize = stripeSize;
if (dxf == null) {
border = null;
font = null;
@@ -72,5 +75,9 @@ public class XSSFDxfStyleProvider implements DifferentialStyleProvider {
public PatternFormatting getPatternFormatting() {
return fill;
}
+
+ public int getStripeSize() {
+ return stripeSize;
+ }
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTable.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTable.java
index f1a31b0f9..ad9e09bef 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTable.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTable.java
@@ -30,6 +30,7 @@ import java.util.Locale;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Table;
import org.apache.poi.ss.usermodel.TableStyleInfo;
import org.apache.poi.ss.util.CellReference;
@@ -62,14 +63,20 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
private transient CellReference startCellReference;
private transient CellReference endCellReference;
private transient String commonXPath;
+ private transient String name;
+ private transient String styleName;
-
+ /**
+ * empty implementation, not attached to a workbook/worksheet yet
+ */
public XSSFTable() {
super();
ctTable = CTTable.Factory.newInstance();
}
/**
+ * @param part
+ * @throws IOException
* @since POI 3.14-Beta1
*/
public XSSFTable(PackagePart part) throws IOException {
@@ -77,6 +84,11 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
readFrom(part.getInputStream());
}
+ /**
+ * read table XML
+ * @param is
+ * @throws IOException
+ */
public void readFrom(InputStream is) throws IOException {
try {
TableDocument doc = TableDocument.Factory.parse(is, DEFAULT_XML_OPTIONS);
@@ -86,10 +98,18 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
}
}
+ /**
+ * @return owning sheet
+ */
public XSSFSheet getXSSFSheet(){
return (XSSFSheet) getParent();
}
+ /**
+ * write table XML to stream
+ * @param out
+ * @throws IOException
+ */
public void writeTo(OutputStream out) throws IOException {
updateHeaders();
@@ -108,6 +128,7 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
/**
* get the underlying CTTable XML bean
+ * @return underlying OOXML object
*/
@Internal(since="POI 3.15 beta 3")
public CTTable getCTTable() {
@@ -209,20 +230,57 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
* @return the name of the Table, if set
*/
public String getName() {
- return ctTable.getName();
+ if (name == null) {
+ setName(ctTable.getName());
+ }
+ return name;
}
/**
* Changes the name of the Table
+ * @param newName
*/
- public void setName(String name) {
- if (name == null) {
+ public void setName(String newName) {
+ if (newName == null) {
ctTable.unsetName();
+ name = null;
return;
}
- ctTable.setName(name);
+ ctTable.setName(newName);
+ name = newName;
}
+ /**
+ * @return the table style name, if set
+ * @since 3.17 beta 1
+ */
+ public String getStyleName() {
+ if (styleName == null && ctTable.isSetTableStyleInfo()) {
+ setStyleName(ctTable.getTableStyleInfo().getName());
+ }
+ return styleName;
+ }
+
+ /**
+ * Changes the name of the Table
+ * @param newStyleName
+ * @since 3.17 beta 1
+ */
+ public void setStyleName(String newStyleName) {
+ if (newStyleName == null) {
+ if (ctTable.isSetTableStyleInfo()) {
+ ctTable.getTableStyleInfo().unsetName();
+ }
+ styleName = null;
+ return;
+ }
+ if (! ctTable.isSetTableStyleInfo()) {
+ ctTable.addNewTableStyleInfo();
+ }
+ ctTable.getTableStyleInfo().setName(newStyleName);
+ styleName = newStyleName;
+ }
+
/**
* @return the display name of the Table, if set
*/
@@ -232,6 +290,7 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
/**
* Changes the display name of the Table
+ * @param name to use
*/
public void setDisplayName(String name) {
ctTable.setDisplayName(name);
@@ -412,12 +471,35 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
}
/**
+ * Note: This is misleading. The Spec indicates this is true if the totals row
+ * has ever been shown, not whether or not it is currently displayed.
+ * Use {@link #getTotalsRowCount()} > 0 to decide whether or not the totals row is visible.
* @since 3.15 beta 2
+ * @see #getTotalsRowCount()
*/
public boolean isHasTotalsRow() {
return ctTable.getTotalsRowShown();
}
+
+ /**
+ * @return 0 for no totals rows, 1 for totals row shown.
+ * Values > 1 are not currently used by Excel up through 2016, and the OOXML spec
+ * doesn't define how they would be implemented.
+ * @since 3.17 beta 1
+ */
+ public int getTotalsRowCount() {
+ return (int) ctTable.getTotalsRowCount();
+ }
+ /**
+ * @return 0 for no header rows, 1 for table headers shown.
+ * Values > 1 might be used by Excel for pivot tables?
+ * @since 3.17 beta 1
+ */
+ public int getHeaderRowCount() {
+ return (int) ctTable.getHeaderRowCount();
+ }
+
/**
* @since 3.15 beta 2
*/
@@ -447,11 +529,27 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
}
/**
- *
* @since 3.17 beta 1
*/
public TableStyleInfo getStyle() {
if (! ctTable.isSetTableStyleInfo()) return null;
return new XSSFTableStyleInfo(((XSSFSheet) getParent()).getWorkbook().getStylesSource(), ctTable.getTableStyleInfo());
}
-}
+
+ /**
+ * @see org.apache.poi.ss.usermodel.Table#contains(org.apache.poi.ss.usermodel.Cell)
+ * @since 3.17 beta 1
+ */
+ public boolean contains(Cell cell) {
+ if (cell == null) return false;
+ // check if cell is on the same sheet as the table
+ if ( ! getSheetName().equals(cell.getSheet().getSheetName())) return false;
+ // check if the cell is inside the table
+ if (cell.getRowIndex() >= getStartRowIndex()
+ && cell.getRowIndex() <= getEndRowIndex()
+ && cell.getColumnIndex() >= getStartColIndex()
+ && cell.getColumnIndex() <= getEndColIndex()) {
+ return true;
+ }
+ return false;
+ }}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTableStyle.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTableStyle.java
index a3333dce7..a46ab2d5b 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTableStyle.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTableStyle.java
@@ -35,26 +35,32 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableStyleElement;
public class XSSFTableStyle implements TableStyle {
private final String name;
+ private final int index;
private final Map elementMap = new EnumMap(TableStyleType.class);
/**
+ * @param index style definition index or built-in ordinal depending on use
* @param dxfs
* @param tableStyle
+ * @see TableStyle#getIndex()
*/
- public XSSFTableStyle(CTDxfs dxfs, CTTableStyle tableStyle) {
+ public XSSFTableStyle(int index, CTDxfs dxfs, CTTableStyle tableStyle) {
this.name = tableStyle.getName();
+ this.index = index;
for (CTTableStyleElement element : tableStyle.getTableStyleElementList()) {
TableStyleType type = TableStyleType.valueOf(element.getType().toString());
DifferentialStyleProvider dstyle = null;
if (element.isSetDxfId()) {
- int idx = (int) element.getDxfId() -1;
+ int idx = (int) element.getDxfId();
CTDxf dxf;
if (idx >= 0 && idx < dxfs.getCount()) {
dxf = dxfs.getDxfArray(idx);
} else {
dxf = null;
}
- if (dxf != null) dstyle = new XSSFDxfStyleProvider(dxf);
+ int stripeSize = 0;
+ if (element.isSetSize()) stripeSize = (int) element.getSize();
+ if (dxf != null) dstyle = new XSSFDxfStyleProvider(dxf, stripeSize);
}
elementMap.put(type, dstyle);
}
@@ -64,6 +70,17 @@ public class XSSFTableStyle implements TableStyle {
return name;
}
+ public int getIndex() {
+ return index;
+ }
+
+ /**
+ * Always false for these, these are user defined styles
+ */
+ public boolean isBuiltin() {
+ return false;
+ }
+
public DifferentialStyleProvider getStyle(TableStyleType type) {
return elementMap.get(type);
}