Skip to content
Snippets Groups Projects
Commit 6e3cc4ab authored by srosse's avatar srosse
Browse files

OO-1781: beautify the docx export of forum

parent 97f83280
No related branches found
No related tags found
No related merge requests found
......@@ -26,7 +26,10 @@ import java.util.Deque;
import java.util.List;
import org.olat.core.util.StringHelper;
import org.olat.core.util.openxml.OpenXMLDocument.Border;
import org.olat.core.util.openxml.OpenXMLDocument.Indent;
import org.olat.core.util.openxml.OpenXMLDocument.ListParagraph;
import org.olat.core.util.openxml.OpenXMLDocument.PredefinedStyle;
import org.olat.core.util.openxml.OpenXMLDocument.Spacing;
import org.olat.core.util.openxml.OpenXMLDocument.Style;
import org.w3c.dom.Element;
......@@ -44,6 +47,8 @@ import org.xml.sax.helpers.DefaultHandler;
*
*/
public class HTMLToOpenXMLHandler extends DefaultHandler {
private static final Border QUOTE_BORDER = new Border(400, 24, "EEEEEE");
private boolean latex = false;
private StringBuilder textBuffer;
......@@ -81,12 +86,12 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
flushText();
addContent(currentParagraph);
}
if(startSpacing == null) {
currentParagraph = factory.createParagraphEl();
} else {
currentParagraph = factory.createParagraphEl(startSpacing);
startSpacing = null;//consumed
}
Indent indent = getCurrentIndent();
Border leftBorder = getCurrentLeftBorder();
PredefinedStyle predefinedStyle = getCurrentPredefinedStyle();
currentParagraph = factory.createParagraphEl(indent, leftBorder, startSpacing, predefinedStyle);
startSpacing = null;//consumed
}
return currentParagraph;
}
......@@ -97,8 +102,10 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
flushText();
addContent(currentParagraph);
}
currentParagraph = factory.createParagraphEl(spacing);
Indent indent = getCurrentIndent();
Border leftBorder = getCurrentLeftBorder();
PredefinedStyle predefinedStyle = getCurrentPredefinedStyle();
currentParagraph = factory.createParagraphEl(indent, leftBorder, spacing, predefinedStyle);
return currentParagraph;
}
......@@ -166,7 +173,11 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
private Element getCurrentRun() {
Element paragraphEl;
if(currentParagraph == null) {
paragraphEl = currentParagraph = factory.createParagraphEl();
Indent indent = getCurrentIndent();
Border leftBorder = getCurrentLeftBorder();
PredefinedStyle predefinedStyle = getCurrentPredefinedStyle();
paragraphEl = currentParagraph = factory.createParagraphEl(indent, leftBorder, startSpacing, predefinedStyle);
startSpacing = null;
} else {
paragraphEl = currentParagraph;
}
......@@ -174,7 +185,9 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
if(lastChild != null && "w:r".equals(lastChild.getNodeName())) {
return (Element)lastChild;
}
return (Element)paragraphEl.appendChild(factory.createRunEl(null));
PredefinedStyle runStyle = getCurrentPredefinedStyle();
return (Element)paragraphEl.appendChild(factory.createRunEl(null, runStyle));
}
private Style[] setTextPreferences(String cssStyles) {
......@@ -218,7 +231,8 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
}
if(runPrefs == null) {
run = paragraphEl.appendChild(factory.createRunEl(null));
PredefinedStyle style = getCurrentPredefinedStyle();
run = paragraphEl.appendChild(factory.createRunEl(null, style));
runPrefs = run.appendChild(factory.createRunPrefsEl());
}
......@@ -233,6 +247,55 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
return styleStack.getLast().getStyles();
}
public Indent getCurrentIndent() {
if(styleStack.isEmpty()) return null;
int indent = 0;
for(StyleStatus style:styleStack) {
if(style.isQuote()) {
indent++;
}
}
int emuIndent = 0;
if(indent > 0) {
emuIndent = 700;
}
if(indent > 1) {
emuIndent += (indent - 1) * 100;
}
return emuIndent == 0 ? null : new Indent(emuIndent);
}
public Border getCurrentLeftBorder() {
if(styleStack.isEmpty()) return null;
int indent = 0;
for(StyleStatus style:styleStack) {
if(style.isQuote()) {
indent++;
}
}
String val;
switch(indent) {
case 1: val = "single"; break;
case 2: val = "double"; break;
default: val = "triple";
}
return indent == 0 ? null : new Border(QUOTE_BORDER, val);
}
public PredefinedStyle getCurrentPredefinedStyle() {
if(styleStack.isEmpty()) return null;
boolean quote = false;
for(StyleStatus style:styleStack) {
quote |= style.isQuote();
}
return quote ? PredefinedStyle.quote : null;
}
public Style[] popStyle(String tag) {
StyleStatus status = styleStack.pollLast();
if(status != null && status.getTag().equals(tag)) {
......@@ -244,7 +307,8 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
private void setImage(String path) {
Element imgEl = factory.createImageEl(path);
if(imgEl != null) {
Element runEl = factory.createRunEl(Collections.singletonList(imgEl));
PredefinedStyle style = getCurrentPredefinedStyle();
Element runEl = factory.createRunEl(Collections.singletonList(imgEl), style);
Element paragrapheEl = getCurrentParagraph(false);
paragrapheEl.appendChild(runEl);
}
......@@ -293,19 +357,17 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
currentListParagraph = factory.createListParagraph();
} else if("li".equals(tag)) {
getCurrentListParagraph(true);
} else if("blockquote".equals(tag)) {
Style[] styles = setTextPreferences(Style.italic);
styleStack.add(new StyleStatus(tag, true, styles));
appendParagraph(new Spacing(90, 0));
} else if("div".equals(tag)) {
String cl = attributes.getValue("class");
if(StringHelper.containsNonWhitespace(cl)) {
if(cl.contains("o_quote_author")) {
appendParagraph(new Spacing(180, 0));
Style[] styles = setTextPreferences(Style.italic);
styleStack.add(new StyleStatus(tag, styles));
} else if(cl.contains("o_quote_wrapper")) {
//
} else if(cl.contains("o_quote")) {
styleStack.add(new StyleStatus(tag, true, styles));
appendParagraph(new Spacing(120, 0));
Style[] styles = setTextPreferences(Style.italic);
styleStack.add(new StyleStatus(tag, styles));
} else {
styleStack.add(new StyleStatus(tag, new Style[0]));
}
......@@ -362,6 +424,8 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
currentListParagraph = null;
} else if("li".equals(tag)) {
//do nothing
} else if("blockquote".equals(tag)) {
popStyle(tag);
} else if("div".equals(tag)) {
popStyle(tag);
}
......@@ -380,9 +444,15 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
private static class StyleStatus {
private final String tag;
private final Style[] styles;
private final boolean quote;
public StyleStatus(String tag, Style[] styles) {
this(tag, false, styles);
}
public StyleStatus(String tag, boolean quote, Style[] styles) {
this.tag = tag;
this.quote = quote;
this.styles = styles;
}
......@@ -390,6 +460,10 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
return tag;
}
public boolean isQuote() {
return quote;
}
public Style[] getStyles() {
return styles;
}
......
......@@ -164,25 +164,25 @@ public class OpenXMLDocument {
}
public void appendTitle(String text) {
appendHeading(text, Heading.title, null);
appendHeading(text, PredefinedStyle.title, null);
}
public void appendHeading1(String text, String additionalText) {
appendHeading(text, Heading.heading1, additionalText);
appendHeading(text, PredefinedStyle.heading1, additionalText);
}
public void appendHeading2(String text, String additionalText) {
appendHeading(text, Heading.heading2, additionalText);
appendHeading(text, PredefinedStyle.heading2, additionalText);
}
private void appendHeading(String text, Heading style, String additionalText) {
private void appendHeading(String text, PredefinedStyle style, String additionalText) {
if(!StringHelper.containsNonWhitespace(text)) return;
Element textEl = createTextEl(text);
List<Element> runsEl = new ArrayList<Element>(2);
Element runEl = createRunEl(Collections.singletonList(textEl));
runsEl.add(runEl);
Element styleEl = createParagraphStyle(style.styleId(), style.runStyleId());
Element styleEl = createParagraphStyle(style);
if(StringHelper.containsNonWhitespace(additionalText)) {
//add an "insecable" blank between the title and the additional text
Element blankRunEl = document.createElement("w:r");
......@@ -212,9 +212,9 @@ public class OpenXMLDocument {
public void appendSubtitle(String text) {
Element textEl = createTextEl(text);
List<Element> runsEl = new ArrayList<Element>(2);
Element runEl = createRunEl(Collections.singletonList(textEl), Heading.subSubtleEmphasis.runStyleId());
Element runEl = createRunEl(Collections.singletonList(textEl), PredefinedStyle.subSubtleEmphasis);
runsEl.add(runEl);
Element styleEl = createParagraphStyle(Heading.subSubtleEmphasis.styleId(), Heading.subSubtleEmphasis.runStyleId());
Element styleEl = createParagraphStyle(PredefinedStyle.subSubtleEmphasis);
Element paragraphEl = createParagraphEl(styleEl, runsEl);
getCursor().appendChild(paragraphEl);
}
......@@ -422,14 +422,17 @@ public class OpenXMLDocument {
</w:rPr>
</w:pPr>
*/
public Element createParagraphStyle(String styleId, String runStyleId) {
public Element createParagraphStyle(PredefinedStyle styleId) {
Element paragraphEl = document.createElement("w:pPr");
Element styleEl = (Element)paragraphEl.appendChild(document.createElement("w:pStyle"));
styleEl.setAttribute("w:val", styleId);
if(StringHelper.containsNonWhitespace(runStyleId)) {
if(styleId != null && styleId.paragraphStyleId() != null) {
Element styleEl = (Element)paragraphEl.appendChild(document.createElement("w:pStyle"));
styleEl.setAttribute("w:val", styleId.paragraphStyleId());
}
if(styleId != null && styleId.runStyleId() != null) {
Element runPrefsEl = (Element)paragraphEl.appendChild(document.createElement("w:rPr"));
Element rStyleEl = (Element)runPrefsEl.appendChild(document.createElement("w:rStyle"));
rStyleEl.setAttribute("w:val", runStyleId);
rStyleEl.setAttribute("w:val", styleId.runStyleId());
}
return paragraphEl;
}
......@@ -462,14 +465,41 @@ public class OpenXMLDocument {
<w:spacing w:before="120" w:after="120" w:beforeAutospacing="0" w:afterAutospacing="0"/>
</w:pPr>
*/
public Element createParagraphEl(Spacing spacing) {
public Element createParagraphEl(Indent indent, Border leftBorder, Spacing spacing, PredefinedStyle predefinedStyle) {
Element paragraphEl = document.createElement("w:p");
Element paragraphPrefsEl = (Element)paragraphEl.appendChild(document.createElement("w:pPr"));
Element spacingEl = (Element)paragraphPrefsEl.appendChild(document.createElement("w:spacing"));
spacingEl.setAttribute("w:before", Integer.toString(spacing.getBefore()));
spacingEl.setAttribute("w:after", Integer.toString(spacing.getAfter()));
spacingEl.setAttribute("w:beforeAutospacing", "0");
spacingEl.setAttribute("w:afterAutospacing", "0");
if(indent != null) {
//<w:ind w:left="1440" w:right="1440" w:hanging="1080" />
Element indEl = (Element)paragraphPrefsEl.appendChild(document.createElement("w:ind"));
if(indent.getLeft() > 0) {
indEl.setAttribute("w:left", Integer.toString(indent.getLeft()));
}
}
if(predefinedStyle != null && predefinedStyle.paragraphStyleId() != null) {
Element styleEl = (Element)paragraphPrefsEl.appendChild(document.createElement("w:pStyle"));
styleEl.setAttribute("w:val", predefinedStyle.paragraphStyleId());
}
if(leftBorder != null) {
//<w:pBdr>
// <w:left w:val="single" w:sz="24" w:space="4" w:color="B97034" w:themeColor="accent6" w:themeShade="BF" />
Element borderEl = (Element)paragraphPrefsEl.appendChild(document.createElement("w:pBdr"));
Element leftEl = (Element)borderEl.appendChild(document.createElement("w:left"));
leftEl.setAttribute("w:val", leftBorder.getVal());
leftEl.setAttribute("w:sz", Integer.toString(leftBorder.getSize()));
leftEl.setAttribute("w:space", Integer.toString(leftBorder.getSpace()));
leftEl.setAttribute("w:color", leftBorder.getColor());
}
if(spacing != null) {
Element spacingEl = (Element)paragraphPrefsEl.appendChild(document.createElement("w:spacing"));
spacingEl.setAttribute("w:before", Integer.toString(spacing.getBefore()));
spacingEl.setAttribute("w:after", Integer.toString(spacing.getAfter()));
spacingEl.setAttribute("w:beforeAutospacing", "0");
spacingEl.setAttribute("w:afterAutospacing", "0");
}
return paragraphEl;
}
......@@ -477,12 +507,12 @@ public class OpenXMLDocument {
return createRunEl(textEls, null);
}
public Element createRunEl(Collection<? extends Node> textEls, String runStyleId) {
public Element createRunEl(Collection<? extends Node> textEls, PredefinedStyle style) {
Element runEl = document.createElement("w:r");
if(StringHelper.containsNonWhitespace(runStyleId)) {
if(style != null && style.runStyleId() != null) {
Element runPrefsEl = (Element)runEl.appendChild(document.createElement("w:rPr"));
Element rStyleEl = (Element)runPrefsEl.appendChild(document.createElement("w:rStyle"));
rStyleEl.setAttribute("w:val", runStyleId);
rStyleEl.setAttribute("w:val", style.runStyleId());
}
if(textEls != null && textEls.size() > 0) {
for(Node textEl:textEls) {
......@@ -1154,23 +1184,24 @@ public class OpenXMLDocument {
}
}
public enum Heading {
public enum PredefinedStyle {
title("ooTitle", null),
heading1("ooHeading1", null),
heading2("ooHeading2", null),
subTitle("ooUntertitel", "ooUntertitelZeichen"),
subSubtleEmphasis("ooSubtleEmphasis", "ooSubtleEmphasisZeichen");
subSubtleEmphasis("ooSubtleEmphasis", "ooSubtleEmphasisZeichen"),
quote("ooQuote", "ooQuoteZeichen");
private final String styleId;
private final String paragraphStyleId;
private final String runStyleId;
private Heading(String styleId, String runStyleId) {
this.styleId = styleId;
private PredefinedStyle(String paragraphStyleId, String runStyleId) {
this.paragraphStyleId = paragraphStyleId;
this.runStyleId = runStyleId;
}
public String styleId() {
return styleId;
public String paragraphStyleId() {
return paragraphStyleId;
}
public String runStyleId() {
......@@ -1219,6 +1250,68 @@ public class OpenXMLDocument {
}
}
public static class Border {
private final int space;
private final int size;
private final String val;
private final String color;
public Border(int space, int size, String color) {
this.space = space;
this.size = size;
this.color = color;
val = "single";
}
public Border(Border border, String val) {
this.space = border.space;
this.size = border.size;
this.color = border.color;
this.val = val;
}
public int getSpace() {
return space;
}
public int getSize() {
return size;
}
public String getColor() {
return color;
}
public String getVal() {
return val;
}
public boolean same(Border border) {
return color.equals(border.color) && size == border.size && space == border.space;
}
public Border cloneAndStack(Border border) {
String stackedVal = border.val;
switch(border.val) {
case "single": stackedVal = "double"; break;
case "double": stackedVal = "triple"; break;
}
return new Border(this, stackedVal);
}
}
public static class Indent {
private final int left;
public Indent(int left) {
this.left = left;
}
public int getLeft() {
return left;
}
}
public static class ListParagraph {
private final int abstractNumId;
......
......@@ -517,4 +517,40 @@
<w:szCs w:val="20" />
</w:rPr>
</w:style>
<w:style w:type="paragraph" w:styleId="ooQuote">
<w:name w:val="OO Quote" />
<w:basedOn w:val="Standard" />
<w:next w:val="Standard" />
<w:link w:val="ooQuoteZeichen" />
<w:uiPriority w:val="11" />
<w:qFormat />
<w:rsid w:val="00384E21" />
<w:pPr>
<w:numPr>
<w:ilvl w:val="1" />
</w:numPr>
</w:pPr>
<w:rPr>
<w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi" />
<w:i />
<w:iCs />
<w:color w:val="555555" w:themeColor="quote1" />
<w:sz w:val="20" />
<w:szCs w:val="20" />
</w:rPr>
</w:style>
<w:style w:type="character" w:styleId="ooQuoteZeichen">
<w:name w:val="OO Quote" />
<w:basedOn w:val="Absatzstandardschriftart" />
<w:uiPriority w:val="19" />
<w:qFormat />
<w:rsid w:val="00384E22" />
<w:rPr>
<w:i />
<w:iCs />
<w:color w:val="555555" w:themeColor="quote1" />
<w:sz w:val="20" />
<w:szCs w:val="20" />
</w:rPr>
</w:style>
</w:styles>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment