You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TestThemesTable.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.xssf.model;
  16. import java.io.FileOutputStream;
  17. import java.io.IOException;
  18. import java.io.InputStream;
  19. import java.util.LinkedHashMap;
  20. import java.util.List;
  21. import java.util.Locale;
  22. import java.util.Map;
  23. import org.apache.commons.codec.binary.Hex;
  24. import org.apache.poi.openxml4j.opc.PackagePart;
  25. import org.apache.poi.ss.usermodel.FillPatternType;
  26. import org.apache.poi.ss.util.CellReference;
  27. import org.apache.poi.xssf.XSSFTestDataSamples;
  28. import org.apache.poi.xssf.model.ThemesTable.ThemeElement;
  29. import org.apache.poi.xssf.usermodel.*;
  30. import org.junit.jupiter.api.Test;
  31. import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor;
  32. import static org.junit.jupiter.api.Assertions.*;
  33. class TestThemesTable {
  34. private static final String testFileComplex = "Themes2.xlsx";
  35. // TODO .xls version available too, add HSSF support then check
  36. // For offline testing
  37. private static final boolean createFiles = false;
  38. // What colours they should show up as
  39. private static final String[] rgbExpected = {
  40. "ffffff", // Lt1
  41. "000000", // Dk1
  42. "eeece1", // Lt2
  43. "1f497d", // DK2
  44. "4f81bd", // Accent1
  45. "c0504d", // Accent2
  46. "9bbb59", // Accent3
  47. "8064a2", // Accent4
  48. "4bacc6", // Accent5
  49. "f79646", // Accent6
  50. "0000ff", // Hlink
  51. "800080" // FolHlink
  52. };
  53. @Test
  54. void testThemesTableColors() throws Exception {
  55. // Load our two test workbooks
  56. String testFileSimple = "Themes.xlsx";
  57. XSSFWorkbook simple = XSSFTestDataSamples.openSampleWorkbook(testFileSimple);
  58. XSSFWorkbook complex = XSSFTestDataSamples.openSampleWorkbook(testFileComplex);
  59. // Save and re-load them, to check for stability across that
  60. XSSFWorkbook simpleRS = XSSFTestDataSamples.writeOutAndReadBack(simple);
  61. XSSFWorkbook complexRS = XSSFTestDataSamples.writeOutAndReadBack(complex);
  62. // Fetch fresh copies to test with
  63. simple.close();
  64. simple = XSSFTestDataSamples.openSampleWorkbook(testFileSimple);
  65. complex.close();
  66. complex = XSSFTestDataSamples.openSampleWorkbook(testFileComplex);
  67. // Files and descriptions
  68. Map<String,XSSFWorkbook> workbooks = new LinkedHashMap<>();
  69. workbooks.put(testFileSimple, simple);
  70. workbooks.put("Re-Saved_" + testFileSimple, simpleRS);
  71. workbooks.put(testFileComplex, complex);
  72. workbooks.put("Re-Saved_" + testFileComplex, complexRS);
  73. // Sanity check
  74. assertEquals(12, rgbExpected.length);
  75. // Check each workbook in turn, and verify that the colours
  76. // for the theme-applied cells in Column A are correct
  77. for (String whatWorkbook : workbooks.keySet()) {
  78. XSSFWorkbook workbook = workbooks.get(whatWorkbook);
  79. XSSFSheet sheet = workbook.getSheetAt(0);
  80. int startRN = 0;
  81. if (whatWorkbook.endsWith(testFileComplex)) startRN++;
  82. for (int rn=startRN; rn<rgbExpected.length+startRN; rn++) {
  83. XSSFRow row = sheet.getRow(rn);
  84. assertNotNull(row, "Missing row " + rn + " in " + whatWorkbook);
  85. String ref = (new CellReference(rn, 0)).formatAsString();
  86. XSSFCell cell = row.getCell(0);
  87. assertNotNull(cell, "Missing cell " + ref + " in " + whatWorkbook);
  88. int expectedThemeIdx = rn-startRN;
  89. ThemeElement themeElem = ThemeElement.byId(expectedThemeIdx);
  90. assertEquals(themeElem.name.toLowerCase(Locale.ROOT), cell.getStringCellValue(),
  91. "Wrong theme at " + ref + " in " + whatWorkbook);
  92. // Fonts are theme-based in their colours
  93. XSSFFont font = cell.getCellStyle().getFont();
  94. CTColor ctColor = font.getCTFont().getColorArray(0);
  95. assertNotNull(ctColor);
  96. assertTrue(ctColor.isSetTheme());
  97. assertEquals(themeElem.idx, ctColor.getTheme());
  98. // Get the colour, via the theme
  99. XSSFColor color = font.getXSSFColor();
  100. // Theme colours aren't tinted
  101. assertFalse(color.hasTint());
  102. // Check the RGB part (no tint)
  103. assertEquals(rgbExpected[expectedThemeIdx], Hex.encodeHexString(color.getRGB()),
  104. "Wrong theme colour " + themeElem.name + " on " + whatWorkbook);
  105. long themeIdx = font.getCTFont().getColorArray(0).getTheme();
  106. assertEquals(expectedThemeIdx, themeIdx,
  107. "Wrong theme index " + expectedThemeIdx + " on " + whatWorkbook);
  108. if (createFiles) {
  109. XSSFCellStyle cs = row.getSheet().getWorkbook().createCellStyle();
  110. cs.setFillForegroundColor(color);
  111. cs.setFillPattern(FillPatternType.SOLID_FOREGROUND);
  112. row.createCell(1).setCellStyle(cs);
  113. }
  114. }
  115. if (createFiles) {
  116. FileOutputStream fos = new FileOutputStream("Generated_"+whatWorkbook);
  117. workbook.write(fos);
  118. fos.close();
  119. }
  120. }
  121. simpleRS.close();
  122. simple.close();
  123. complexRS.close();
  124. complex.close();
  125. }
  126. /**
  127. * Ensure that, for a file with themes, we can correctly
  128. * read both the themed and non-themed colours back.
  129. * Column A = Theme Foreground
  130. * Column B = Theme Foreground
  131. * Column C = Explicit Colour Foreground
  132. * Column E = Explicit Colour Background, Black Foreground
  133. * Column G = Conditional Formatting Backgrounds
  134. *
  135. * Note - Grey Row has an odd way of doing the styling...
  136. */
  137. @Test
  138. void themedAndNonThemedColours() throws IOException {
  139. try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook(testFileComplex)) {
  140. XSSFSheet sheet = wb.getSheetAt(0);
  141. ThemesTable themesTable = wb.getTheme();
  142. XSSFColor color1 = themesTable.getThemeColor(0);
  143. assertNotNull(color1);
  144. assertNotEquals(0, color1.getRGB().length);
  145. List<PackagePart> themeParts = wb.getPackage().getPartsByContentType(XSSFRelation.THEME.getContentType());
  146. assertEquals(1, themeParts.size());
  147. try (InputStream themeStream = themeParts.get(0).getInputStream()) {
  148. ThemesTable themesTable2 = new ThemesTable(themeStream);
  149. assertArrayEquals(color1.getRGB(), themesTable2.getThemeColor(0).getRGB());
  150. }
  151. String[] names = {"White", "Black", "Grey", "Dark Blue", "Blue", "Red", "Green"};
  152. String[] explicitFHexes = {"FFFFFFFF", "FF000000", "FFC0C0C0", "FF002060",
  153. "FF0070C0", "FFFF0000", "FF00B050"};
  154. String[] explicitBHexes = {"FFFFFFFF", "FF000000", "FFC0C0C0", "FF002060",
  155. "FF0000FF", "FFFF0000", "FF00FF00"};
  156. assertEquals(7, names.length);
  157. // Check the non-CF colours in Columns A, B, C and E
  158. for (int rn = 1; rn < 8; rn++) {
  159. int idx = rn - 1;
  160. XSSFRow row = sheet.getRow(rn);
  161. assertNotNull(row, "Missing row " + rn);
  162. // Theme cells come first
  163. XSSFCell themeCell = row.getCell(0);
  164. ThemeElement themeElem = ThemeElement.byId(idx);
  165. assertCellContents(themeElem.name, themeCell);
  166. // Sanity check names
  167. assertCellContents(names[idx], row.getCell(1));
  168. assertCellContents(names[idx], row.getCell(2));
  169. assertCellContents(names[idx], row.getCell(4));
  170. // Check the colours
  171. // A: Theme Based, Foreground
  172. XSSFCellStyle style = themeCell.getCellStyle();
  173. XSSFColor color = style.getFont().getXSSFColor();
  174. assertTrue(color.isThemed());
  175. assertEquals(idx, color.getTheme());
  176. assertEquals(rgbExpected[idx], Hex.encodeHexString(color.getRGB()));
  177. // B: Theme Based, Foreground
  178. XSSFCell cell = row.getCell(1);
  179. style = cell.getCellStyle();
  180. color = style.getFont().getXSSFColor();
  181. assertTrue(color.isThemed());
  182. if (idx != 2) {
  183. assertEquals(idx, color.getTheme());
  184. assertEquals(rgbExpected[idx], Hex.encodeHexString(color.getRGB()));
  185. } else {
  186. assertEquals(1, color.getTheme());
  187. assertEquals(0.50, color.getTint(), 0.001);
  188. }
  189. // C: Explicit, Foreground
  190. cell = row.getCell(2);
  191. style = cell.getCellStyle();
  192. color = style.getFont().getXSSFColor();
  193. assertFalse(color.isThemed());
  194. assertEquals(explicitFHexes[idx], color.getARGBHex());
  195. // E: Explicit Background, Foreground all Black
  196. cell = row.getCell(4);
  197. style = cell.getCellStyle();
  198. color = style.getFont().getXSSFColor();
  199. assertTrue(color.isThemed());
  200. assertEquals("FF000000", color.getARGBHex());
  201. color = style.getFillForegroundXSSFColor();
  202. assertFalse(color.isThemed());
  203. assertEquals(explicitBHexes[idx], color.getARGBHex());
  204. color = style.getFillBackgroundColorColor();
  205. assertFalse(color.isThemed());
  206. assertNull(color.getARGBHex());
  207. }
  208. }
  209. // Check the CF colours
  210. // TODO
  211. }
  212. private static void assertCellContents(String expected, XSSFCell cell) {
  213. assertNotNull(cell);
  214. assertEquals(expected.toLowerCase(Locale.ROOT),
  215. cell.getStringCellValue().toLowerCase(Locale.ROOT));
  216. }
  217. @Test
  218. @SuppressWarnings("resource")
  219. void testAddNew() {
  220. XSSFWorkbook wb = new XSSFWorkbook();
  221. wb.createSheet();
  222. assertNull(wb.getTheme());
  223. StylesTable styles = wb.getStylesSource();
  224. assertNull(styles.getTheme());
  225. styles.ensureThemesTable();
  226. assertNotNull(styles.getTheme());
  227. assertNotNull(wb.getTheme());
  228. wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
  229. styles = wb.getStylesSource();
  230. assertNotNull(styles.getTheme());
  231. assertNotNull(wb.getTheme());
  232. }
  233. }