package org.etsi.mts.tdl.tools.to.docx.poi; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.math.BigInteger; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import org.apache.poi.xwpf.usermodel.IBodyElement; import org.apache.poi.xwpf.usermodel.ParagraphAlignment; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.apache.poi.xwpf.usermodel.XWPFStyles; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableCell; import org.apache.poi.xwpf.usermodel.XWPFTableRow; import org.apache.xmlbeans.XmlException; import org.eclipse.core.runtime.Platform; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.EcoreUtil2; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.etsi.mts.tdl.Package; import org.etsi.mts.tdl.TestConfiguration; import org.etsi.mts.tdl.structuredobjectives.StructuredTestObjective; import org.etsi.mts.tdl.structuredobjectives.Variant; import org.etsi.mts.tdl.structuredobjectives.VariantBinding; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; import org.osgi.framework.Bundle; public class Generator { int index = 0; String templateFilename = "template.docx"; public static String selectedTemplate = "TO_4_TABLE_TEMPLATE_EDITHELP"; XWPFDocument template; private boolean hierarchical = true; //DONE: integrate with model //DONE: check export and build configuration //DONE: supersede current implementation //TODO: move filters where applicable //DONE: add support for headings based on packages //TODO: check for other relevant legacy adaptations //DONE: update all other icons //DONE: make configurable //TODO: Restructure and refactor public void generate(Resource resource, String filename, String title) throws Exception { generate(resource, filename, title, selectedTemplate); } public void generate(Resource resource, String filename, String title, String templateName) throws Exception { selectedTemplate = templateName; XWPFDocument document = createDocument(); template = loadTemplate(); loadStyles(document, template); createTitle(title, document); int hLevel = 3; if (hierarchical ) { String prefix = "X.Y"; generatePackageHeadings(resource, document, prefix, hLevel); } else { //flat generation List stos = EcoreUtil2.getAllContentsOfType(resource.getContents().get(0), StructuredTestObjective.class); for (StructuredTestObjective sto : stos) { String sectionTitle = sto.getName(); LinkedHashMap map = getReplacementMap(sto); generateTable(document, sectionTitle, map); LinkedHashMap> variants = getVariantsMap(sto); generateVariants(document, variants); } } storeDocument(filename, document); template.close(); } private void generatePackageHeadings(Resource resource, XWPFDocument document, String prefix, int hLevel) { //hierarchical generation List packages = getContentsOfType(resource, Package.class); generatePackageHeadings(document, packages, prefix, hLevel); } private void generatePackageHeadings(XWPFDocument document, List packages, String prefix, int hLevel) { int i = 1; for (Package p : packages) { generatePackageHeading(document, prefix, i, p, hLevel); List stos = getContentsOfType(p, StructuredTestObjective.class); for (StructuredTestObjective sto : stos) { String sectionTitle = sto.getName(); LinkedHashMap map = getReplacementMap(sto); generateTable(document, sectionTitle, map); LinkedHashMap> variants = getVariantsMap(sto); generateVariants(document, variants); } generatePackageHeadings(document, getContentsOfType(p, Package.class), prefix+"."+i, hLevel+1); i++; } } private void generatePackageHeading(XWPFDocument document, String prefix, int i, Package p, int hLevel) { System.out.println(p.getName()); XWPFParagraph par = document.createParagraph(); par.setStyle(template.getStyles().getStyleWithName("heading "+hLevel).getStyleId()); XWPFRun titleRun = par.createRun(); titleRun.setText(prefix+"."+i); titleRun.addTab(); titleRun.setText(p.getName()); } private List getContentsOfType(Resource resource, Class type) { List elements = resource.getContents() .stream() .filter(e -> type.isInstance(e)) .map(e -> (T) e) .collect(Collectors.toList()) ; return elements; } private List getContentsOfType(EObject eObject, Class type) { List elements = eObject.eContents() .stream() .filter(e -> type.isInstance(e)) .map(e -> (T) e) .collect(Collectors.toList()) ; return elements; } //TODO: cleanup and restructure private void generateVariants(XWPFDocument document, LinkedHashMap> variants) { LinkedHashSet headers = new LinkedHashSet<>(); for (LinkedHashMap e : variants.values()) { headers.addAll(e.keySet()); } if (headers.size() > 0) { XWPFTable table = loadTemplate(template, selectedTemplate+"_VARIANT"); if (table == null) { return; } // XWPFParagraph par = document.createParagraph(); // //par.setStyle("heading 2"); // par.setSpacingBeforeLines(120); // par.setSpacingAfterLines(120); // // //optional: title // XWPFRun titleRun = par.createRun(); // titleRun.setText("Variants"); // titleRun.setFontSize(24); CTTbl tbl = document.getDocument().getBody().insertNewTbl(document.getDocument().getBody().sizeOfTblArray()); tbl.set(table.getCTTbl()); XWPFTable target = new XWPFTable(tbl, document); target.getRow(0).getCell(0) .getParagraphs().get(0) .getRuns().get(0) .setText("REPLACE", 0); target.removeRow(0); ArrayList hList = new ArrayList<>(headers); target.getCTTbl().addNewTblGrid(); for (int i = 0; i 0) { // target.addNewCol(); // XWPFTableCell cell = target.getRow(0).addNewTableCell(); XWPFTableCell cell = target.getRow(0).createCell(); // target.addNewCol(); } XWPFTableCell cell = target.getRow(0).getCell(i+1); cell.getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(1200)); // cell.getCTTc().getTcPr().getTcW().setW(BigInteger.valueOf(100)); // cell.setWidth("10"); // cell.setWidthType(TableWidthType.PCT); // cell.setText(hList.get(i)); XWPFParagraph p = target.getRow(0).getCell(0).getParagraphs().get(0); // cell.getParagraphs().get(0).setStyle(p.getStyle()); cell.getParagraphs().get(0).getCTP().set(p.getCTP()); cell.getParagraphs().get(0).getCTP().getRList().get(0).getTList().get(0).setStringValue(hList.get(i)); // cell // .getParagraphs().get(0) // .getRuns().get(0) // .setText(hList.get(i), 0); } int r = 1; for (String id : variants.keySet()) { XWPFTableRow row = target.getRow(r); XWPFParagraph rp = target.getRow(1).getCell(0).getParagraphs().get(0); // row.getCell(0).getParagraphs().get(0).getRuns().get(0).setText(id,0); // cell.getParagraphs().get(0).createRun().getCTR().set(p.getRuns().get(0).getCTR()); if (r > 1) { target.createRow(); //XWPFTableCell hCell = target.getRow(r).createCell(); } XWPFTableCell hCell = target.getRow(r).getCell(0); hCell.getParagraphs().get(0).getCTP().set(rp.getCTP()); hCell.getParagraphs().get(0).getCTP().getRList().get(0).getTList().get(0).setStringValue(id); for (int i = 0; i 0) { // XWPFTableCell cell = target.getRow(r).addNewTableCell(); XWPFTableCell cell = target.getRow(r).createCell(); // target.addNewCol(); } XWPFTableCell cell = target.getRow(r).getCell(i+1); cell.getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(1200)); // cell.getCTTc().getTcPr().getTcW().setW(BigInteger.valueOf(100)); // cell.setWidth("10"); // cell.setWidthType(TableWidthType.PCT); if (variants.get(id).containsKey(hList.get(i))) { // cell.setText(variants.get(id).get(hList.get(i))); XWPFParagraph p = target.getRow(r).getCell(0).getParagraphs().get(0); // cell.getParagraphs().get(0).createRun().getCTR().set(p.getRuns().get(0).getCTR()); cell.getParagraphs().get(0).getCTP().set(p.getCTP()); cell.getParagraphs().get(0).getCTP().getRList().get(0).getTList().get(0).setStringValue(variants.get(id).get(hList.get(i))); // cell // .getParagraphs().get(0) // .getRuns().get(0) // .setText(variants.get(id).get(hList.get(i)), 0); } } r++; } target.getCTTbl().addNewTblGrid(); for (XWPFTableCell cell : target.getRow(0).getTableCells()) { table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(3200)); } XWPFParagraph par = document.createParagraph(); } } void generateExample(String filename, String title) throws Exception { XWPFDocument document = createDocument(); template = loadTemplate(); loadStyles(document, template); createTitle(title, document); for (int i = 0; i < 5; i++) { String sectionTitle = "Test "+i; LinkedHashMap map = getReplacementMap(); generateTable(document, sectionTitle, map); } storeDocument(filename, document); template.close(); } private XWPFDocument loadTemplate() throws Exception { String templateLocation = getTemplateLocation(templateFilename); template = loadTemplateDocument(templateLocation); return template; } private void generateTable(XWPFDocument document, String sectionTitle, LinkedHashMap map) { //clone table XWPFTable table = loadTemplate(template, selectedTemplate); CTTbl tbl = document.getDocument().getBody().insertNewTbl(document.getDocument().getBody().sizeOfTblArray()); tbl.set(table.getCTTbl()); XWPFTable target = new XWPFTable(tbl, document); target.getRow(0).getCell(0) .getParagraphs().get(0) .getRuns().get(0) .setText("REPLACE", 0); target.removeRow(0); makeReplacements(target, map); cleanUp(target); XWPFParagraph par = document.createParagraph(); } private void cleanUp(XWPFTable target) { //clean up //collect colored rows and colors to clear LinkedHashMap> colors = new LinkedHashMap<>(); List cleanColors = new ArrayList<>(); int rn = 0; for (XWPFTableRow r : target.getRows()) { for (XWPFTableCell c : r.getTableCells()) { if (c.getColor()!=null && !c.getColor().equals("auto")) { colors.putIfAbsent(c.getColor(), new TreeSet<>()); colors.get(c.getColor()).add(rn); if (c.getText().trim().isEmpty()) { cleanColors.add(c.getColor()); } } } rn++; } //clear colored rows int o = 0; for (String c : colors.keySet()) { if (cleanColors.contains(c)) { for (int r : colors.get(c)) { target.removeRow(r-o); o++; } } } //reset remaining colors for (XWPFTableRow r : target.getRows()) { for (XWPFTableCell c : r.getTableCells()) { if (c.getColor()!=null && !c.getColor().equals("auto")) { c.setColor(null); c.getCTTc().getTcPr().getShd().unsetThemeFill(); // c.getCTTc().getTcPr().getShd().unsetThemeFillTint(); } if (c.getColor()!=null) { } } } } private void makeReplacements(XWPFTable target, LinkedHashMap map) { //replace for (XWPFTableRow r : target.getRows()) { for (XWPFTableCell c : r.getTableCells()) { for (XWPFParagraph p : c.getParagraphs()) { for (XWPFRun run : p.getRuns()) { if (map.containsKey(run.getText(0))) { String text = map.get(run.getText(0)); if (text.isEmpty()) { for (XWPFRun rr : p.getRuns()) { rr.setText("", 0); } } else { String[] lines = text.split("\n"); run.setText("", 0); int l = 0; for (String line : lines) { l++; run.setText(line); if (l < lines.length) { run.addBreak(); } } } } } } } } } private LinkedHashMap> getVariantsMap(StructuredTestObjective sto) { LinkedHashMap> variants = new LinkedHashMap<>(); if (sto.getVariants() != null) { for (Variant v : sto.getVariants().getVariants()) { variants.put(v.getName(), new LinkedHashMap<>()); if (v.getDescription() != null) { variants.get(v.getName()).put("Description", v.getDescription()); } if (!v.getObjectiveURI().isEmpty()) { variants.get(v.getName()).put("Reference", String.join("\n",v.getObjectiveURI())); } if (!v.getPicsReference().isEmpty()) { String pics = String.join(" ", v.getPicsReference() .stream() .map(p -> NodeModelUtils.getNode(p).getText()) .collect(Collectors.toList())) .trim() ; variants.get(v.getName()).put("PICS", pics); } for (VariantBinding b : v.getBindings()) { String value = NodeModelUtils.getNode(b.getValue()).getText(); String boundTo = NodeModelUtils.getNode(b.getBoundTo()).getText(); variants.get(v.getName()).put(value, boundTo); } } } return variants; } private LinkedHashMap getReplacementMap(StructuredTestObjective sto) { //map //TODO: complete, refine, restructure //TODO: transfer to variants as well LinkedHashMap map = new LinkedHashMap<>(); map.put(Placeholders.NAME, sto.getName()); map.put(Placeholders.DESCRIPTION, sto.getDescription().replaceAll("\"", "")); String uri = String.join("\n", sto.getObjectiveURI()).trim(); map.put(Placeholders.URI, uri.replaceAll("\"","")); TestConfiguration configuration = sto.getConfiguration(); String config = ""; if (configuration != null) { config = configuration.getName(); } map.put(Placeholders.CONFIGURATION, config); String pics = String.join(" ", sto.getPicsReference() .stream() .map(p -> NodeModelUtils.getNode(p).getText()) .collect(Collectors.toList())) .trim() ; map.put(Placeholders.PICS, pics); map.put(Placeholders.INITIAL, ""); if (sto.getInitialConditions()!=null) { //TODO: filter extra new line String initialConditions = NodeModelUtils.getNode(sto.getInitialConditions()).getText(); initialConditions = initialConditions.replaceAll("\\s*Initial conditions", ""); initialConditions = filterSource(initialConditions, "\n", "\\w").trim(); map.put(Placeholders.INITIAL, initialConditions); } //TODO:check if defined? String expected = NodeModelUtils.getNode(sto.getExpectedBehaviour()).getText(); expected = expected.replaceAll("\\s*Expected behaviour", ""); expected = filterSource(expected, "\n", "ensure").trim(); map.put(Placeholders.EXPECTED, expected); map.put(Placeholders.FINAL, ""); if (sto.getFinalConditions()!=null) { //TODO: filter extra new line String finalConditions = NodeModelUtils.getNode(sto.getFinalConditions()).getText(); finalConditions = finalConditions.replaceAll("\\s*Final conditions", ""); finalConditions = filterSource(finalConditions, "\n", "\\w"); map.put(Placeholders.FINAL, finalConditions); } String when = NodeModelUtils.getNode(sto.getExpectedBehaviour().getWhenClause()).getText(); String then = NodeModelUtils.getNode(sto.getExpectedBehaviour().getThenClause()).getText(); //TODO: a bit of a hack when = filterSource(when, "\n", "\\s\\s\\s\\s\\w"); then = filterSource(then, "\n", "\\s\\s\\s\\s\\w"); map.put(Placeholders.WHEN, "when {"+when+"\n}"); map.put(Placeholders.THEN, "then {"+then+"\n}"); return map; } private String filterSource(String source, String prefix, String offsetKeyword) { Matcher matcher = Pattern.compile(prefix+"(.+?)"+offsetKeyword).matcher(source); matcher.find(); String offset = matcher.group(1); System.out.println("|"+offset+"|"); source = source .replaceAll("\t", " ") //tabs .replaceAll("\n"+offset, "\n") //leading space // .replaceAll("\n ", "\n") //leading space -> detect automatically .replaceAll("[\\s\n\r]+"+prefix, prefix) .replaceAll(" \\((typed|predefined)\\) ", " ") //shall be optional .replaceAll(" entity ", " ") //shall be optional .replaceAll(";", "") //shall be optional .replaceAll("\\(|\\)", "") //shall be optional ; return source; } private LinkedHashMap getReplacementMap() { //map LinkedHashMap map = new LinkedHashMap<>(); map.put(Placeholders.NAME, "Name"); map.put(Placeholders.DESCRIPTION, "Descripion"); map.put(Placeholders.URI, "URI"); map.put(Placeholders.CONFIGURATION, "Configuration"); map.put(Placeholders.PICS, "PICS"); map.put(Placeholders.INITIAL, "Initial"); // map.put(Placeholders.INITIAL, ""); map.put(Placeholders.EXPECTED, "Expected\nWhen\n {\n }\nThen\n {\n }"); map.put(Placeholders.FINAL, "Final"); map.put(Placeholders.FINAL, ""); map.put(Placeholders.WHEN, "When"); map.put(Placeholders.THEN, "Then"); return map; } private XWPFTable loadTemplate(XWPFDocument template, String selectedTemplate) { XWPFTable table = null; List bodyElements = template.getBodyElements(); for (IBodyElement e : bodyElements) { if (e instanceof XWPFTable) { String id = ((XWPFTable) e).getRow(0).getCell(0).getText(); if (id.trim().equals(selectedTemplate)) { table = (XWPFTable) e; } } } return table; } private String getTemplateLocation(String templateFilename) { String template = "resource/"+templateFilename; if (Platform.isRunning()) { Bundle bundle = Platform.getBundle("org.etsi.mts.tdl.tools.to.docx.poi"); template = bundle.getLocation().substring(15)+"resource/"+templateFilename; try { template = org.eclipse.core.runtime.FileLocator.toFileURL(bundle.getEntry("resource/"+templateFilename)).getPath(); } catch (IOException e) { e.printStackTrace(); } } return template; } private XWPFDocument createDocument() { XWPFDocument report = new XWPFDocument(); return report; } private XWPFDocument loadTemplateDocument(String templateLocation) throws Exception { File file = new File(templateLocation); FileInputStream fis = new FileInputStream(file.getAbsolutePath()); XWPFDocument document = new XWPFDocument(fis); fis.close(); return document; } private void storeDocument(String reportLocation, XWPFDocument report) { try { FileOutputStream out = new FileOutputStream(reportLocation); report.write(out); out.close(); report.close(); } catch (Exception e) { e.printStackTrace(); } } private void createTitle(String title, XWPFDocument report) { XWPFParagraph titleParagraph = report.createParagraph(); titleParagraph.setAlignment(ParagraphAlignment.CENTER); XWPFRun titleRun = titleParagraph.createRun(); titleRun.setText("Export: "+title); titleRun.setColor("444444"); titleRun.setBold(true); titleRun.setFontFamily("Helvetica"); titleRun.setFontSize(20); } private void loadStyles(XWPFDocument report, XWPFDocument templateDocument) { XWPFStyles newStyles = report.createStyles(); try { newStyles.setStyles(templateDocument.getStyle()); } catch (XmlException | IOException e) { e.printStackTrace(); } } }