From 2bbf89e77967361022792d77551300fe9181fe48 Mon Sep 17 00:00:00 2001 From: "konstantina.galouni" Date: Tue, 8 Nov 2022 14:39:23 +0200 Subject: [PATCH] HtmlToWorldBuilder.java & WordBuilder.java: Added methods for exporting inputs of a question as table. --- .../documents/word/HtmlToWorldBuilder.java | 8 + .../utilities/documents/word/WordBuilder.java | 250 +++++++++++++++++- 2 files changed, 253 insertions(+), 5 deletions(-) diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/HtmlToWorldBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/HtmlToWorldBuilder.java index 8cc6368bb..5badc0f67 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/HtmlToWorldBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/HtmlToWorldBuilder.java @@ -25,6 +25,14 @@ public class HtmlToWorldBuilder implements NodeVisitor { private BigInteger numberingLevel; private XmlCursor cursor; + public static HtmlToWorldBuilder convertInTable(XWPFTableCell document, Document htmlDocument, float indentation) { + XWPFParagraph paragraph = document.addParagraph(); + paragraph.setIndentFromLeft(Math.round(400 * indentation)); + HtmlToWorldBuilder htmlToWorldBuilder = new HtmlToWorldBuilder(paragraph, indentation, null); + NodeTraversor.traverse(htmlToWorldBuilder, htmlDocument); + return htmlToWorldBuilder; + } + public static HtmlToWorldBuilder convert(XWPFDocument document, Document htmlDocument, float indentation) { XWPFParagraph paragraph = document.createParagraph(); paragraph.setIndentFromLeft(Math.round(400 * indentation)); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java index 0d34203a3..3023a888c 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java @@ -65,6 +65,7 @@ public class WordBuilder { ).collect(Collectors.toMap(objects -> (String)objects[0], o -> (Integer)o[1])); private Map> options = new HashMap<>(); + private Map> optionsInTable = new HashMap<>(); private CTAbstractNum cTAbstractNum; private BigInteger numId; private Integer indent; @@ -78,6 +79,42 @@ public class WordBuilder { this.imageCount = 0; this.mapper = new ObjectMapper(); this.buildOptions(environment); + this.buildOptionsInTable(environment); + } + + private void buildOptionsInTable(Environment environment) { + this.optionsInTable.put(ParagraphStyle.TEXT, (mainDocumentPart, item) -> { + XWPFParagraph paragraph = mainDocumentPart.addParagraph(); + XWPFRun run = paragraph.createRun(); + if (item != null) + run.setText("" + item); + run.setFontSize(11); + return paragraph; + }); + this.optionsInTable.put(ParagraphStyle.HTML, (mainDocumentPart, item) -> { + Document htmlDoc = Jsoup.parse(((String)item).replaceAll("\n", "
")); + HtmlToWorldBuilder htmlToWorldBuilder = HtmlToWorldBuilder.convertInTable(mainDocumentPart, htmlDoc, 0); + return htmlToWorldBuilder.getParagraph(); + }); + this.optionsInTable.put(ParagraphStyle.TITLE, (mainDocumentPart, item) -> { + XWPFParagraph paragraph = mainDocumentPart.addParagraph(); + paragraph.setStyle("Title"); + paragraph.setAlignment(ParagraphAlignment.CENTER); + XWPFRun run = paragraph.createRun(); + run.setText((String)item); + run.setBold(true); + run.setFontSize(14); + return paragraph; + }); + this.optionsInTable.put(ParagraphStyle.IMAGE, (mainDocumentPart, item) -> { + XWPFParagraph paragraph = mainDocumentPart.addParagraph(); + XWPFRun run = paragraph.createRun(); + if (item != null) + run.setText(((Map)item).get("name")); + run.setFontSize(11); + run.setItalic(true); + return paragraph; + }); } private void buildOptions(Environment environment) { @@ -91,7 +128,6 @@ public class WordBuilder { }); this.options.put(ParagraphStyle.HTML, (mainDocumentPart, item) -> { Document htmlDoc = Jsoup.parse(((String)item).replaceAll("\n", "
")); -// HtmlToWorldBuilder htmlToWorldBuilder = HtmlToWorldBuilder.convert(mainDocumentPart, htmlDoc, indent > 0 ? (indent/2.0F) * 0.8F : 0.8F); HtmlToWorldBuilder htmlToWorldBuilder = HtmlToWorldBuilder.convert(mainDocumentPart, htmlDoc, this.indent); return htmlToWorldBuilder.getParagraph(); }); @@ -287,6 +323,7 @@ public class WordBuilder { if (createListing) this.addListing(mainDocumentPart, indent, true, true); boolean hasValue = false; boolean returnedValue = false; + for (FieldSet compositeField: compositeFields) { if (visibilityRuleService.isElementVisible(compositeField.getId()) && hasVisibleFields(compositeField, visibilityRuleService)) { char c = 'a'; @@ -299,14 +336,30 @@ public class WordBuilder { // CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); // number.setVal(BigInteger.valueOf(indent)); paragraphPos = mainDocumentPart.getPosOfParagraph(paragraph); - if(compositeField.getMultiplicityItems() != null && !compositeField.getMultiplicityItems().isEmpty()){ + if(!compositeField.getMultiplicity().getTableView() && compositeField.getMultiplicityItems() != null && !compositeField.getMultiplicityItems().isEmpty()){ XWPFParagraph paragraphInner = addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.TEXT, numId, indent); paragraphPosInner = mainDocumentPart.getPosOfParagraph(paragraphInner); hasMultiplicityItems = true; multiplicityItems++; } } - hasValue = createFields(compositeField.getFields(), mainDocumentPart, indent, createListing, visibilityRuleService, hasMultiplicityItems); + XWPFTable tbl = null; + XWPFTableRow row = null; + int numOfRows = 0; + if(compositeField.getMultiplicity().getTableView()) { + tbl = mainDocumentPart.createTable(); + tbl.setTableAlignment(TableRowAlign.CENTER); + mainDocumentPart.createParagraph(); + createHeadersInTable(compositeField.getFields(), tbl, visibilityRuleService); + numOfRows = tbl.getRows().size(); + row = tbl.createRow(); + } + if(compositeField.getMultiplicity().getTableView()) { + hasValue = createFieldsInTable(compositeField.getFields(), row, indent, createListing, visibilityRuleService, hasMultiplicityItems, numOfRows); + numOfRows++; + } else { + hasValue = createFields(compositeField.getFields(), mainDocumentPart, indent, createListing, visibilityRuleService, hasMultiplicityItems); + } if(hasValue){ returnedValue = true; } else if(paragraphPosInner > -1){ @@ -318,7 +371,7 @@ public class WordBuilder { List
list = compositeField.getMultiplicityItems().stream().sorted(Comparator.comparingInt(FieldSet::getOrdinal)).collect(Collectors.toList()); for (FieldSet multiplicityFieldset : list) { paragraphPosInner = -1; - if(!createListing){ + if(!compositeField.getMultiplicity().getTableView() && !createListing){ c++; // addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.HEADER6, numId); XWPFParagraph paragraphInner = addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.TEXT, numId, indent); @@ -327,7 +380,14 @@ public class WordBuilder { multiplicityItems++; } // hasValue = createFields(multiplicityFieldset.getFields(), mainDocumentPart, 3, createListing, visibilityRuleService, hasMultiplicityItems); - boolean hasValueInner = createFields(multiplicityFieldset.getFields(), mainDocumentPart, indent, createListing, visibilityRuleService, hasMultiplicityItems); + boolean hasValueInner = false; + if(compositeField.getMultiplicity().getTableView()) { + row = tbl.createRow(); + hasValueInner = createFieldsInTable(multiplicityFieldset.getFields(), row, indent, createListing, visibilityRuleService, hasMultiplicityItems, numOfRows); + numOfRows++; + } else { + hasValueInner = createFields(multiplicityFieldset.getFields(), mainDocumentPart, indent, createListing, visibilityRuleService, hasMultiplicityItems); + } // if(hasValue){ if(hasValueInner){ hasValue = true; @@ -355,9 +415,159 @@ public class WordBuilder { } } } + return returnedValue; } + private void createHeadersInTable(List fields, XWPFTable table, VisibilityRuleService visibilityRuleService) { + boolean atLeastOneHeader = false; + List tempFields = fields.stream().sorted(Comparator.comparingInt(Field::getOrdinal)).collect(Collectors.toList()); + int index = 0; + XWPFTableRow row = table.getRow(0); + for (Field field: tempFields) { + if (visibilityRuleService.isElementVisible(field.getId()) && field.getExport()) { + XWPFTableCell cell; + if(index == 0) { + cell = row.getCell(0); + } else { + cell = row.createCell(); + } + cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.valueOf("CENTER")); + String label = ((FieldData) field.getData()).getLabel(); + if(label != null && label != "") { + XWPFParagraph paragraph = cell.getParagraphs().get(0); + paragraph.setIndentationFirstLine(50); + XWPFRun run = paragraph.createRun(); + run.setText(label); + run.setBold(true); + run.setFontSize(12); + paragraph.setAlignment(ParagraphAlignment.CENTER); + paragraph.setSpacingBefore(100); + + atLeastOneHeader = true; + } + } + index++; + } + + if(!atLeastOneHeader) { + table.removeRow(0); + } + } + + private Boolean createFieldsInTable(List fields, XWPFTableRow mainDocumentPart, Integer indent, Boolean createListing, VisibilityRuleService visibilityRuleService, boolean hasMultiplicityItems, int numOfRows) { + int numOfCells = 0; + boolean hasValue = false; + List tempFields = fields.stream().sorted(Comparator.comparingInt(Field::getOrdinal)).collect(Collectors.toList()); + for (Field field: tempFields) { + if (visibilityRuleService.isElementVisible(field.getId()) && field.getExport()) { + if (!createListing) { + try { + if(field.getViewStyle().getRenderStyle().equals("upload")){ + boolean isImage = false; + for(UploadData.Option type: ((UploadData)field.getData()).getTypes()){ + String fileFormat = type.getValue(); + if(IMAGE_TYPE_MAP.containsKey(fileFormat)){ + isImage = true; + break; + } + } + if(isImage){ + if (field.getValue() != null && !field.getValue().toString().isEmpty()) { + XWPFParagraph paragraph = addCellContent(mapper.convertValue(field.getValue(), Map.class), mainDocumentPart, ParagraphStyle.IMAGE, numId, 0, numOfRows, numOfCells, 0); + if (paragraph != null) { + hasValue = true; + } + if(hasMultiplicityItems){ + hasMultiplicityItems = false; + } + } + } + } + else if (field.getValue() != null && !field.getValue().toString().isEmpty()) { + this.indent = indent; + String format = this.formatter(field); + if (field.getViewStyle().getRenderStyle().equals("tags")) { + format = getCommaSeparatedFormatsFromJson(format, "name"); + } else if (field.getViewStyle().getRenderStyle().equals("combobox") && field.getData() instanceof AutoCompleteData) { + format = getCommaSeparatedFormatsFromJson(format, "label"); + } + boolean isResearcher = field.getViewStyle().getRenderStyle().equals("researchers"); + if(format != null && !format.isEmpty()){ + Object hasMultiAutoComplete = mapper.convertValue(field.getData(), Map.class).get("multiAutoComplete"); + boolean isMultiAutoComplete = hasMultiAutoComplete != null && (boolean)hasMultiAutoComplete; + boolean arrayStringFormat = format.charAt(0) == '['; + if(arrayStringFormat || isMultiAutoComplete){ + List values = (arrayStringFormat) ? Arrays.asList(format.substring(1, format.length() - 1).split(",[ ]*")) : Arrays.asList(format.split(",[ ]*")); + if(values.size() > 1) { + boolean orcidResearcher; + int numOfValuesInCell = 0; + for (String val : values) { + orcidResearcher = false; + String orcId = null; + if(isResearcher && val.contains("orcid:")){ + orcId = val.substring(val.indexOf(':') + 1, val.indexOf(')')); + val = val.substring(0, val.indexOf(':') + 1) + " "; + orcidResearcher = true; + } + format = "• " + val; + if(hasMultiplicityItems){ + XWPFParagraph paragraph = mainDocumentPart.getCell(mainDocumentPart.getTableCells().size()).addParagraph(); + paragraph.createRun().setText(format); + if(orcidResearcher){ + XWPFHyperlinkRun run = paragraph.createHyperlinkRun("https://orcid.org/" + orcId); + run.setText(orcId); + run.setUnderline(UnderlinePatterns.SINGLE); + run.setColor("0000FF"); + paragraph.createRun().setText(")"); + } + hasMultiplicityItems = false; + } + else{ + XWPFParagraph paragraph = addCellContent(format, mainDocumentPart, field.getViewStyle().getRenderStyle().equals("richTextarea") ? ParagraphStyle.HTML : ParagraphStyle.TEXT, numId, indent, numOfRows, numOfCells, numOfValuesInCell); + numOfValuesInCell++; + if(orcidResearcher){ + XWPFHyperlinkRun run = paragraph.createHyperlinkRun("https://orcid.org/" + orcId); + run.setText(orcId); + run.setUnderline(UnderlinePatterns.SINGLE); + run.setColor("0000FF"); + paragraph.createRun().setText(")"); + } + if (paragraph != null) { + hasValue = true; + } + } + format = null; + } + } + else if(values.size() == 1){ + format = values.get(0); + } + } + } + if(hasMultiplicityItems && format != null){ + XWPFParagraph paragraph = mainDocumentPart.getCell(mainDocumentPart.getTableCells().size()).addParagraph(); + paragraph.createRun().setText(format); + hasMultiplicityItems = false; + hasValue = true; + } + else{ + XWPFParagraph paragraph = addCellContent(format, mainDocumentPart, field.getViewStyle().getRenderStyle().equals("richTextarea") ? ParagraphStyle.HTML : ParagraphStyle.TEXT, numId, indent, numOfRows, numOfCells, 0); + if (paragraph != null) { + hasValue = true; + } + } + } + } catch (IOException e) { + logger.error(e.getMessage(), e); + } + } + numOfCells++; + } + } + return hasValue; + } + private Boolean createFields(List fields, XWPFDocument mainDocumentPart, Integer indent, Boolean createListing, VisibilityRuleService visibilityRuleService, boolean hasMultiplicityItems) { if (createListing) this.addListing(mainDocumentPart, indent, false, false); boolean hasValue = false; @@ -491,6 +701,36 @@ public class WordBuilder { } } + public XWPFParagraph addCellContent(Object content, XWPFTableRow mainDocumentPart, ParagraphStyle style, BigInteger numId, int indent, int numOfRows, int numOfCells, int numOfValuesInCell) { + if (content != null) { + if (content instanceof String && ((String)content).isEmpty()) { + return null; + } + this.indent = indent; + XWPFTableCell cell; + if(numOfRows > 0 || numOfValuesInCell > 0) { + cell = mainDocumentPart.getCell(numOfCells); + } else { + cell = mainDocumentPart.createCell(); + } + cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.valueOf("CENTER")); + if(numOfValuesInCell == 0) { + cell.removeParagraph(0); + } + + XWPFParagraph paragraph = this.optionsInTable.get(style).apply(cell, content); + if (paragraph != null) { + paragraph.setAlignment(ParagraphAlignment.CENTER); + paragraph.setSpacingBefore(100); + if (numId != null) { + paragraph.setNumID(numId); + } + return paragraph; + } + } + return null; + } + public XWPFParagraph addParagraphContent(Object content, XWPFDocument mainDocumentPart, ParagraphStyle style, BigInteger numId, int indent) { // this.indent = 0; if (content != null) {