diff --git a/jxls-poi/src/main/java/org/jxls/transform/poi/PoiCellData.java b/jxls-poi/src/main/java/org/jxls/transform/poi/PoiCellData.java index 09ba7ea7..ac9b7afe 100644 --- a/jxls-poi/src/main/java/org/jxls/transform/poi/PoiCellData.java +++ b/jxls-poi/src/main/java/org/jxls/transform/poi/PoiCellData.java @@ -151,7 +151,18 @@ public void writeToCell(Cell cell, Context context, PoiTransformer transformer) ((WritableCellValue) evaluationResult).writeToCell(cell, context); } else { updateCellGeneralInfo(cell); + + ValueWithCellAccess valueWithCellAccess = null; + if (evaluationResult instanceof ValueWithCellAccess) { + valueWithCellAccess = (ValueWithCellAccess) evaluationResult; + evaluationResult = valueWithCellAccess.getValue(); + valueWithCellAccess.applyBefore(cell); + } updateCellContents(cell); + if (valueWithCellAccess != null) { + valueWithCellAccess.applyAfter(cell); + } + CellStyle targetCellStyle = cellStyle; if (context.getConfig().isIgnoreSourceCellStyle()) { CellStyle dataFormatCellStyle = findCellStyle(evaluationResult, context.getConfig().getCellStyleMap(), transformer); diff --git a/jxls-poi/src/main/java/org/jxls/transform/poi/PoiUtil.java b/jxls-poi/src/main/java/org/jxls/transform/poi/PoiUtil.java index 235d41de..4670b2f5 100644 --- a/jxls-poi/src/main/java/org/jxls/transform/poi/PoiUtil.java +++ b/jxls-poi/src/main/java/org/jxls/transform/poi/PoiUtil.java @@ -23,17 +23,25 @@ public static void setCellComment(Cell cell, String commentText, String commentA Drawing drawing = sheet.createDrawingPatriarch(); CreationHelper factory = wb.getCreationHelper(); if (anchor == null) { - anchor = factory.createClientAnchor(); - anchor.setCol1(cell.getColumnIndex() + 1); - anchor.setCol2(cell.getColumnIndex() + 3); - anchor.setRow1(cell.getRowIndex()); - anchor.setRow2(cell.getRowIndex() + 2); + anchor = createAnchor(cell, 1, 3, 0, 2); } Comment comment = drawing.createCellComment(anchor); comment.setString(factory.createRichTextString(commentText)); comment.setAuthor(commentAuthor != null ? commentAuthor : ""); cell.setCellComment(comment); } + + public static ClientAnchor createAnchor(Cell cell, int addToCol1, int addToCol2, int addToRow1, int addToRow2) { + Sheet sheet = cell.getSheet(); + Workbook wb = sheet.getWorkbook(); + CreationHelper factory = wb.getCreationHelper(); + ClientAnchor anchor = factory.createClientAnchor(); + anchor.setCol1(cell.getColumnIndex() + addToCol1); + anchor.setCol2(cell.getColumnIndex() + addToCol2); + anchor.setRow1(cell.getRowIndex() + addToRow1); + anchor.setRow2(cell.getRowIndex() + addToRow2); + return anchor; + } public WritableCellValue hyperlink(String address, String link, String linkTypeString) { return new WritableHyperlink(address, link, linkTypeString); diff --git a/jxls-poi/src/main/java/org/jxls/transform/poi/ValueWithCellAccess.java b/jxls-poi/src/main/java/org/jxls/transform/poi/ValueWithCellAccess.java new file mode 100644 index 00000000..a856b8aa --- /dev/null +++ b/jxls-poi/src/main/java/org/jxls/transform/poi/ValueWithCellAccess.java @@ -0,0 +1,12 @@ +package org.jxls.transform.poi; + +import org.apache.poi.ss.usermodel.Cell; + +public interface ValueWithCellAccess { + + Object getValue(); + + void applyBefore(Cell cell); + + void applyAfter(Cell cell); +} diff --git a/jxls-poi/src/test/java/org/jxls/TestWorkbook.java b/jxls-poi/src/test/java/org/jxls/TestWorkbook.java index 2082a719..e3b28982 100644 --- a/jxls-poi/src/test/java/org/jxls/TestWorkbook.java +++ b/jxls-poi/src/test/java/org/jxls/TestWorkbook.java @@ -11,6 +11,7 @@ import org.apache.poi.ss.usermodel.SheetConditionalFormatting; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; +import org.apache.poi.ss.util.CellAddress; import org.apache.poi.ss.util.CellRangeAddress; /** @@ -124,6 +125,14 @@ public LocalDateTime getCellValueAsLocalDateTime(int row, int column) { } } + public String getCellComment(int row, int column) { + try { + return sheet.getCellComment(new CellAddress(row - 1, column - 1)).getString().getString(); + } catch (NullPointerException e) { + return null; + } + } + /** * @param row starts with 1 * @return row height in Twips diff --git a/jxls-poi/src/test/java/org/jxls/templatebasedtests/Issue17Test.java b/jxls-poi/src/test/java/org/jxls/templatebasedtests/Issue17Test.java index b745704a..88fac0eb 100644 --- a/jxls-poi/src/test/java/org/jxls/templatebasedtests/Issue17Test.java +++ b/jxls-poi/src/test/java/org/jxls/templatebasedtests/Issue17Test.java @@ -11,6 +11,7 @@ * Github issue 17: Image and multi sheet */ public class Issue17Test { + // ValueWithCellAccessTest uses code of this class. @Test public void test() throws Exception { @@ -27,7 +28,7 @@ public void test() throws Exception { // Each sheet with an image? } - private List getItems() { + static List getItems() { List items = new ArrayList<>(); Item item = new Item(); item.setId("registered_user"); diff --git a/jxls-poi/src/test/java/org/jxls/templatebasedtests/ValueWithCellAccessTest.java b/jxls-poi/src/test/java/org/jxls/templatebasedtests/ValueWithCellAccessTest.java new file mode 100644 index 00000000..3e736e74 --- /dev/null +++ b/jxls-poi/src/test/java/org/jxls/templatebasedtests/ValueWithCellAccessTest.java @@ -0,0 +1,103 @@ +package org.jxls.templatebasedtests; + +import static org.junit.Assert.assertEquals; + +import org.apache.poi.ss.usermodel.Cell; +import org.junit.Test; +import org.jxls.JxlsTester; +import org.jxls.TestWorkbook; +import org.jxls.common.Context; +import org.jxls.expression.JexlExpressionEvaluator; +import org.jxls.templatebasedtests.Issue17Test.Item; +import org.jxls.transform.poi.PoiUtil; +import org.jxls.transform.poi.ValueWithCellAccess; + +/** + * This testcase writes for every cell value its origin as a Excel cell comment. + */ +public class ValueWithCellAccessTest { + + @Test + public void test() throws Exception { + // Prepare + Context context = new Context(); + context.putVar("items", Issue17Test.getItems()); + context.putVar("_f", new Functions(context)); // withSource() method returns ValueWithCellAccess + + // Test + JxlsTester tester = JxlsTester.xlsx(getClass()); + tester.processTemplate(context); + + // Verify + try (TestWorkbook w = tester.getWorkbook()) { + w.selectSheet(0); + // cell values: + assertEquals("ANDROID", w.getCellValueAsString(2, 2)); + assertEquals("JP", w.getCellValueAsString(2, 3)); + // origins as comments: + assertEquals("class=org.jxls.templatebasedtests.Issue17Test$Item\nfield=app_type\nid=registered_user", w.getCellComment(2, 2)); + assertEquals("class=org.jxls.templatebasedtests.Issue17Test$Item\nfield=country_code\nid=registered_user", w.getCellComment(2, 3)); + } + } + + public static class Functions { + private final Context context; + + public Functions(Context ctx) { + this.context = ctx; + } + + public ValueWithCellAccess withSource(String path) { + if (path == null || !path.contains(".")) { + throw new RuntimeException("path must not be null and must contain '.'"); + } + int o = path.lastIndexOf("."); + String head = path.substring(0, o); + String tail = path.substring(o + 1); // field name + Item pe = (Item) evaluate(head); + Object value; + switch (tail) { + case "app_type": + value = pe.getApp_type(); + break; + case "country_code": + value = pe.getCountry_code(); + break; + default: + throw new RuntimeException("Unknown field: " + tail); + } + return new MyValueWithCellAccess(pe, tail, value); + } + + private Object evaluate(String expression) { + return new JexlExpressionEvaluator(expression).evaluate(context.toMap()); + } + } + + public static class MyValueWithCellAccess implements ValueWithCellAccess { + private Item pe; + private String fieldName; + private Object value; + + public MyValueWithCellAccess(Item pe, String fieldName, Object value) { + this.pe = pe; + this.fieldName = fieldName; + this.value = value; + } + + @Override + public Object getValue() { + return value; + } + + @Override + public void applyBefore(Cell cell) { + String note = "class=" + pe.getClass().getName() + "\nfield=" + fieldName + "\nid=" + pe.getId(); + PoiUtil.setCellComment(cell, note, "auto", PoiUtil.createAnchor(cell, 1, 3, 0, 4)); + } + + @Override + public void applyAfter(Cell cell) { + } + } +} diff --git a/jxls-poi/src/test/resources/org/jxls/templatebasedtests/ValueWithCellAccessTest.xlsx b/jxls-poi/src/test/resources/org/jxls/templatebasedtests/ValueWithCellAccessTest.xlsx new file mode 100644 index 00000000..289a81ab Binary files /dev/null and b/jxls-poi/src/test/resources/org/jxls/templatebasedtests/ValueWithCellAccessTest.xlsx differ