| /* ==================================================================== |
| 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.model; |
| |
| import static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertFalse; |
| import static org.junit.jupiter.api.Assertions.assertNotNull; |
| import static org.junit.jupiter.api.Assertions.assertNull; |
| import static org.junit.jupiter.api.Assertions.assertTrue; |
| |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.util.LinkedHashMap; |
| import java.util.Locale; |
| import java.util.Map; |
| |
| import org.apache.commons.codec.binary.Hex; |
| import org.apache.poi.ss.usermodel.FillPatternType; |
| import org.apache.poi.ss.util.CellReference; |
| import org.apache.poi.xssf.XSSFTestDataSamples; |
| import org.apache.poi.xssf.model.ThemesTable.ThemeElement; |
| import org.apache.poi.xssf.usermodel.XSSFCell; |
| import org.apache.poi.xssf.usermodel.XSSFCellStyle; |
| import org.apache.poi.xssf.usermodel.XSSFColor; |
| import org.apache.poi.xssf.usermodel.XSSFFont; |
| import org.apache.poi.xssf.usermodel.XSSFRow; |
| import org.apache.poi.xssf.usermodel.XSSFSheet; |
| import org.apache.poi.xssf.usermodel.XSSFWorkbook; |
| import org.junit.jupiter.api.Test; |
| import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor; |
| |
| class TestThemesTable { |
| private static final String testFileComplex = "Themes2.xlsx"; |
| // TODO .xls version available too, add HSSF support then check |
| |
| // For offline testing |
| private static final boolean createFiles = false; |
| |
| // What colours they should show up as |
| private static final String[] rgbExpected = { |
| "ffffff", // Lt1 |
| "000000", // Dk1 |
| "eeece1", // Lt2 |
| "1f497d", // DK2 |
| "4f81bd", // Accent1 |
| "c0504d", // Accent2 |
| "9bbb59", // Accent3 |
| "8064a2", // Accent4 |
| "4bacc6", // Accent5 |
| "f79646", // Accent6 |
| "0000ff", // Hlink |
| "800080" // FolHlink |
| }; |
| |
| @Test |
| void testThemesTableColors() throws Exception { |
| // Load our two test workbooks |
| String testFileSimple = "Themes.xlsx"; |
| XSSFWorkbook simple = XSSFTestDataSamples.openSampleWorkbook(testFileSimple); |
| XSSFWorkbook complex = XSSFTestDataSamples.openSampleWorkbook(testFileComplex); |
| // Save and re-load them, to check for stability across that |
| XSSFWorkbook simpleRS = XSSFTestDataSamples.writeOutAndReadBack(simple); |
| XSSFWorkbook complexRS = XSSFTestDataSamples.writeOutAndReadBack(complex); |
| // Fetch fresh copies to test with |
| simple.close(); |
| simple = XSSFTestDataSamples.openSampleWorkbook(testFileSimple); |
| complex.close(); |
| complex = XSSFTestDataSamples.openSampleWorkbook(testFileComplex); |
| // Files and descriptions |
| Map<String,XSSFWorkbook> workbooks = new LinkedHashMap<>(); |
| workbooks.put(testFileSimple, simple); |
| workbooks.put("Re-Saved_" + testFileSimple, simpleRS); |
| workbooks.put(testFileComplex, complex); |
| workbooks.put("Re-Saved_" + testFileComplex, complexRS); |
| |
| // Sanity check |
| assertEquals(12, rgbExpected.length); |
| |
| // Check each workbook in turn, and verify that the colours |
| // for the theme-applied cells in Column A are correct |
| for (String whatWorkbook : workbooks.keySet()) { |
| XSSFWorkbook workbook = workbooks.get(whatWorkbook); |
| XSSFSheet sheet = workbook.getSheetAt(0); |
| int startRN = 0; |
| if (whatWorkbook.endsWith(testFileComplex)) startRN++; |
| |
| for (int rn=startRN; rn<rgbExpected.length+startRN; rn++) { |
| XSSFRow row = sheet.getRow(rn); |
| assertNotNull(row, "Missing row " + rn + " in " + whatWorkbook); |
| String ref = (new CellReference(rn, 0)).formatAsString(); |
| XSSFCell cell = row.getCell(0); |
| assertNotNull(cell, "Missing cell " + ref + " in " + whatWorkbook); |
| |
| int expectedThemeIdx = rn-startRN; |
| ThemeElement themeElem = ThemeElement.byId(expectedThemeIdx); |
| assertEquals(themeElem.name.toLowerCase(Locale.ROOT), cell.getStringCellValue(), |
| "Wrong theme at " + ref + " in " + whatWorkbook); |
| |
| // Fonts are theme-based in their colours |
| XSSFFont font = cell.getCellStyle().getFont(); |
| CTColor ctColor = font.getCTFont().getColorArray(0); |
| assertNotNull(ctColor); |
| assertTrue(ctColor.isSetTheme()); |
| assertEquals(themeElem.idx, ctColor.getTheme()); |
| |
| // Get the colour, via the theme |
| XSSFColor color = font.getXSSFColor(); |
| // Theme colours aren't tinted |
| assertFalse(color.hasTint()); |
| // Check the RGB part (no tint) |
| assertEquals(rgbExpected[expectedThemeIdx], Hex.encodeHexString(color.getRGB()), |
| "Wrong theme colour " + themeElem.name + " on " + whatWorkbook); |
| long themeIdx = font.getCTFont().getColorArray(0).getTheme(); |
| assertEquals(expectedThemeIdx, themeIdx, |
| "Wrong theme index " + expectedThemeIdx + " on " + whatWorkbook); |
| |
| if (createFiles) { |
| XSSFCellStyle cs = row.getSheet().getWorkbook().createCellStyle(); |
| cs.setFillForegroundColor(color); |
| cs.setFillPattern(FillPatternType.SOLID_FOREGROUND); |
| row.createCell(1).setCellStyle(cs); |
| } |
| } |
| |
| if (createFiles) { |
| FileOutputStream fos = new FileOutputStream("Generated_"+whatWorkbook); |
| workbook.write(fos); |
| fos.close(); |
| } |
| } |
| |
| simpleRS.close(); |
| simple.close(); |
| complexRS.close(); |
| complex.close(); |
| } |
| |
| /** |
| * Ensure that, for a file with themes, we can correctly |
| * read both the themed and non-themed colours back. |
| * Column A = Theme Foreground |
| * Column B = Theme Foreground |
| * Column C = Explicit Colour Foreground |
| * Column E = Explicit Colour Background, Black Foreground |
| * Column G = Conditional Formatting Backgrounds |
| * |
| * Note - Grey Row has an odd way of doing the styling... |
| */ |
| @Test |
| void themedAndNonThemedColours() throws IOException { |
| try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook(testFileComplex)) { |
| XSSFSheet sheet = wb.getSheetAt(0); |
| |
| String[] names = {"White", "Black", "Grey", "Dark Blue", "Blue", "Red", "Green"}; |
| String[] explicitFHexes = {"FFFFFFFF", "FF000000", "FFC0C0C0", "FF002060", |
| "FF0070C0", "FFFF0000", "FF00B050"}; |
| String[] explicitBHexes = {"FFFFFFFF", "FF000000", "FFC0C0C0", "FF002060", |
| "FF0000FF", "FFFF0000", "FF00FF00"}; |
| assertEquals(7, names.length); |
| |
| // Check the non-CF colours in Columns A, B, C and E |
| for (int rn = 1; rn < 8; rn++) { |
| int idx = rn - 1; |
| XSSFRow row = sheet.getRow(rn); |
| assertNotNull(row, "Missing row " + rn); |
| |
| // Theme cells come first |
| XSSFCell themeCell = row.getCell(0); |
| ThemeElement themeElem = ThemeElement.byId(idx); |
| assertCellContents(themeElem.name, themeCell); |
| |
| // Sanity check names |
| assertCellContents(names[idx], row.getCell(1)); |
| assertCellContents(names[idx], row.getCell(2)); |
| assertCellContents(names[idx], row.getCell(4)); |
| |
| |
| // Check the colours |
| |
| // A: Theme Based, Foreground |
| XSSFCellStyle style = themeCell.getCellStyle(); |
| XSSFColor color = style.getFont().getXSSFColor(); |
| assertTrue(color.isThemed()); |
| assertEquals(idx, color.getTheme()); |
| assertEquals(rgbExpected[idx], Hex.encodeHexString(color.getRGB())); |
| |
| // B: Theme Based, Foreground |
| XSSFCell cell = row.getCell(1); |
| style = cell.getCellStyle(); |
| color = style.getFont().getXSSFColor(); |
| assertTrue(color.isThemed()); |
| if (idx != 2) { |
| assertEquals(idx, color.getTheme()); |
| assertEquals(rgbExpected[idx], Hex.encodeHexString(color.getRGB())); |
| } else { |
| assertEquals(1, color.getTheme()); |
| assertEquals(0.50, color.getTint(), 0.001); |
| } |
| |
| // C: Explicit, Foreground |
| cell = row.getCell(2); |
| style = cell.getCellStyle(); |
| color = style.getFont().getXSSFColor(); |
| assertFalse(color.isThemed()); |
| assertEquals(explicitFHexes[idx], color.getARGBHex()); |
| |
| // E: Explicit Background, Foreground all Black |
| cell = row.getCell(4); |
| style = cell.getCellStyle(); |
| |
| color = style.getFont().getXSSFColor(); |
| assertTrue(color.isThemed()); |
| assertEquals("FF000000", color.getARGBHex()); |
| |
| color = style.getFillForegroundXSSFColor(); |
| assertFalse(color.isThemed()); |
| assertEquals(explicitBHexes[idx], color.getARGBHex()); |
| color = style.getFillBackgroundColorColor(); |
| assertFalse(color.isThemed()); |
| assertNull(color.getARGBHex()); |
| } |
| } |
| |
| // Check the CF colours |
| // TODO |
| } |
| private static void assertCellContents(String expected, XSSFCell cell) { |
| assertNotNull(cell); |
| assertEquals(expected.toLowerCase(Locale.ROOT), |
| cell.getStringCellValue().toLowerCase(Locale.ROOT)); |
| } |
| |
| @Test |
| @SuppressWarnings("resource") |
| void testAddNew() { |
| XSSFWorkbook wb = new XSSFWorkbook(); |
| wb.createSheet(); |
| assertNull(wb.getTheme()); |
| |
| StylesTable styles = wb.getStylesSource(); |
| assertNull(styles.getTheme()); |
| |
| styles.ensureThemesTable(); |
| |
| assertNotNull(styles.getTheme()); |
| assertNotNull(wb.getTheme()); |
| |
| wb = XSSFTestDataSamples.writeOutAndReadBack(wb); |
| styles = wb.getStylesSource(); |
| assertNotNull(styles.getTheme()); |
| assertNotNull(wb.getTheme()); |
| } |
| } |