diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFColor.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFColor.java
index ce142b78c8..441f42fdb6 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFColor.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFColor.java
@@ -16,8 +16,11 @@
==================================================================== */
package org.apache.poi.xssf.usermodel;
+import java.util.Arrays;
+
import org.apache.poi.ss.usermodel.Color;
import org.apache.poi.ss.usermodel.ExtendedColor;
+import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.util.Internal;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor;
@@ -50,6 +53,11 @@ public class XSSFColor extends ExtendedColor {
this();
ctColor.setRgb(rgb);
}
+
+ public XSSFColor(IndexedColors indexedColor) {
+ this();
+ ctColor.setIndexed(indexedColor.index);
+ }
/**
* A boolean value indicating the ctColor is automatic and system ctColor dependent.
@@ -304,7 +312,17 @@ public class XSSFColor extends ExtendedColor {
return ctColor;
}
+ /**
+ * Checked type cast color to an XSSFColor.
+ *
+ * @param color the color to type cast
+ * @return the type casted color
+ * @throws IllegalArgumentException if color is null or is not an instance of XSSFColor
+ */
public static XSSFColor toXSSFColor(Color color) {
+ // FIXME: this method would be more useful if it could convert any Color to an XSSFColor
+ // Currently the only benefit of this method is to throw an IllegalArgumentException
+ // instead of a ClassCastException.
if (color != null && !(color instanceof XSSFColor)) {
throw new IllegalArgumentException("Only XSSFColor objects are supported");
}
@@ -316,13 +334,62 @@ public class XSSFColor extends ExtendedColor {
return ctColor.toString().hashCode();
}
+ // Helper methods for {@link #equals(Object)}
+ private boolean sameIndexed(XSSFColor other) {
+ if (isIndexed() == other.isIndexed()) {
+ if (isIndexed()) {
+ return getIndexed() == other.getIndexed();
+ }
+ return true;
+ }
+ return false;
+ }
+ private boolean sameARGB(XSSFColor other) {
+ if (isRGB() == other.isRGB()) {
+ if (isRGB()) {
+ return Arrays.equals(getARGB(), other.getARGB());
+ }
+ return true;
+ }
+ return false;
+ }
+ private boolean sameTheme(XSSFColor other) {
+ if (isThemed() == other.isThemed()) {
+ if (isThemed()) {
+ return getTheme() == other.getTheme();
+ }
+ return true;
+ }
+ return false;
+ }
+ private boolean sameTint(XSSFColor other) {
+ if (hasTint() == other.hasTint()) {
+ if (hasTint()) {
+ return getTint() == other.getTint();
+ }
+ return true;
+ }
+ return false;
+ }
+ private boolean sameAuto(XSSFColor other) {
+ return isAuto() == other.isAuto();
+ }
+
@Override
public boolean equals(Object o){
if(!(o instanceof XSSFColor)) {
return false;
}
- XSSFColor cf = (XSSFColor)o;
- return ctColor.toString().equals(cf.getCTColor().toString());
+ XSSFColor other = (XSSFColor)o;
+
+ // Compare each field in ctColor.
+ // Cannot compare ctColor's XML string representation because equivalent
+ // colors may have different relation namespace URI's
+ return sameARGB(other)
+ && sameTheme(other)
+ && sameIndexed(other)
+ && sameTint(other)
+ && sameAuto(other);
}
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
index 501f6f5075..98d7f6c1cf 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
@@ -63,6 +63,7 @@ import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.Footer;
import org.apache.poi.ss.usermodel.Header;
import org.apache.poi.ss.usermodel.IgnoredErrorType;
+import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.AreaReference;
@@ -3846,21 +3847,45 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
public XSSFSheetConditionalFormatting getSheetConditionalFormatting(){
return new XSSFSheetConditionalFormatting(this);
}
+
+ /**
+ * Get background color of the sheet tab.
+ * Returns null if no sheet tab color is set.
+ *
+ * @return the background color of the sheet tab
+ */
+ public XSSFColor getTabColor() {
+ CTSheetPr pr = worksheet.getSheetPr();
+ if(pr == null) pr = worksheet.addNewSheetPr();
+ if (!pr.isSetTabColor()) {
+ return null;
+ }
+ return new XSSFColor(pr.getTabColor());
+ }
/**
* Set background color of the sheet tab
*
- * @param colorIndex the indexed color to set, must be a constant from {@link IndexedColors}
+ * @param colorIndex the indexed color to set, must be a constant from {@link org.apache.poi.ss.usermodel.IndexedColors}
+ * @deprecated 3.15-beta2. Removed in 3.17. Use {@link #setTabColor(XSSFColor)}.
*/
- public void setTabColor(int colorIndex){
+ public void setTabColor(int colorIndex) {
+ IndexedColors indexedColor = IndexedColors.fromInt(colorIndex);
+ XSSFColor color = new XSSFColor(indexedColor);
+ setTabColor(color);
+ }
+
+ /**
+ * Set background color of the sheet tab
+ *
+ * @param color the color to set
+ */
+ public void setTabColor(XSSFColor color) {
CTSheetPr pr = worksheet.getSheetPr();
if(pr == null) pr = worksheet.addNewSheetPr();
- CTColor color = CTColor.Factory.newInstance();
- color.setIndexed(colorIndex);
- pr.setTabColor(color);
+ pr.setTabColor(color.getCTColor());
}
-
@Override
public CellRangeAddress getRepeatingRows() {
return getRepeatingRowsOrColums(true);
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
index 7bcd67835a..1e641c64e7 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
@@ -1911,7 +1911,7 @@ public final class TestXSSFSheet extends BaseTestSheet {
try {
XSSFSheet sh = wb.createSheet();
assertTrue(sh.getCTWorksheet().getSheetPr() == null || !sh.getCTWorksheet().getSheetPr().isSetTabColor());
- sh.setTabColor(IndexedColors.RED);
+ sh.setTabColor(new XSSFColor(IndexedColors.RED));
assertTrue(sh.getCTWorksheet().getSheetPr().isSetTabColor());
assertEquals(IndexedColors.RED.index,
sh.getCTWorksheet().getSheetPr().getTabColor().getIndexed());
@@ -1919,4 +1919,40 @@ public final class TestXSSFSheet extends BaseTestSheet {
wb.close();
}
}
+
+ @Test
+ public void getTabColor() throws IOException {
+ XSSFWorkbook wb = new XSSFWorkbook();
+ try {
+ XSSFSheet sh = wb.createSheet();
+ assertTrue(sh.getCTWorksheet().getSheetPr() == null || !sh.getCTWorksheet().getSheetPr().isSetTabColor());
+ assertNull(sh.getTabColor());
+ sh.setTabColor(new XSSFColor(IndexedColors.RED));
+ XSSFColor expected = new XSSFColor(IndexedColors.RED);
+ assertEquals(expected, sh.getTabColor());
+ } finally {
+ wb.close();
+ }
+ }
+
+ // Test using an existing workbook saved by Excel
+ @Test
+ public void tabColor() throws IOException {
+ XSSFWorkbook wb = openSampleWorkbook("SheetTabColors.xlsx");
+ try {
+ // non-colored sheets do not have a color
+ assertNull(wb.getSheet("default").getTabColor());
+
+ // test indexed-colored sheet
+ XSSFColor expected = new XSSFColor(IndexedColors.RED);
+ assertEquals(expected, wb.getSheet("indexedRed").getTabColor());
+
+ // test regular-colored (non-indexed, ARGB) sheet
+ expected = new XSSFColor();
+ expected.setARGBHex("FF7F2700");
+ assertEquals(expected, wb.getSheet("customOrange").getTabColor());
+ } finally {
+ wb.close();
+ }
+ }
}
diff --git a/test-data/spreadsheet/SheetTabColors.xlsx b/test-data/spreadsheet/SheetTabColors.xlsx
new file mode 100644
index 0000000000..1894f69ea3
Binary files /dev/null and b/test-data/spreadsheet/SheetTabColors.xlsx differ