diff --git a/src/main/java/net/signbit/samx/AttributeVisitor.java b/src/main/java/net/signbit/samx/AttributeVisitor.java index 50a4cd5..6f7500b 100644 --- a/src/main/java/net/signbit/samx/AttributeVisitor.java +++ b/src/main/java/net/signbit/samx/AttributeVisitor.java @@ -45,6 +45,7 @@ public String getReference() private String idAttribute = null; private String nameAttribute = null; private String referenceAttribute = null; + private String citationAttribute = null; @Override public Void visitClassAttr(SamXParser.ClassAttrContext ctx) @@ -84,6 +85,13 @@ public Void visitReferenceAttr(SamXParser.ReferenceAttrContext ctx) return null; } + @Override + public Void visitCitationAttr(SamXParser.CitationAttrContext ctx) + { + citationAttribute = ctx.text().getText(); + return null; + } + @Override public String toString() { @@ -91,12 +99,12 @@ public String toString() boolean isEmpty = true; - if ((! classAttributes.isEmpty()) || (idAttribute != null) || (nameAttribute != null)) + if ((!classAttributes.isEmpty()) || (idAttribute != null) || (nameAttribute != null)) { builder.append(' '); } - if (! classAttributes.isEmpty()) + if (!classAttributes.isEmpty()) { if (docBookMode) { @@ -162,11 +170,48 @@ public String toString() public void setDocBookMode() { - docBookMode = true; + docBookMode = true; } public void setDitaMode() { - ditaMode = true; + ditaMode = true; + } + + private StringBuilder visitAttribute(char sigil, String text) + { + StringBuilder builder = new StringBuilder(); + + builder.append('('); + builder.append(sigil); + builder.append(text); + builder.append(')'); + + return builder; } + + public String toPlainString() + { + StringBuilder builder = new StringBuilder(); + + boolean isEmpty = true; + + if (idAttribute != null) + { + builder.append(visitAttribute('#', idAttribute)); + } + + if (nameAttribute != null) + { + builder.append(visitAttribute('*', nameAttribute)); + } + + for (String className : classAttributes) + { + builder.append(visitAttribute('.', className)); + } + + return builder.toString(); + } + } diff --git a/src/main/java/net/signbit/samx/GridVisitor.java b/src/main/java/net/signbit/samx/GridVisitor.java new file mode 100644 index 0000000..6e15e8a --- /dev/null +++ b/src/main/java/net/signbit/samx/GridVisitor.java @@ -0,0 +1,220 @@ +/* + Copyright 2020 Florin Iucha + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package net.signbit.samx; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import org.antlr.v4.runtime.BufferedTokenStream; + +import net.signbit.samx.parser.SamXParser; +import net.signbit.samx.parser.SamXParserBaseVisitor; +import net.signbit.samx.parser.SamXParserVisitor; + +public class GridVisitor extends SamXParserBaseVisitor +{ + private final BufferedTokenStream tokenStream; + + public GridVisitor(BufferedTokenStream tokenStream) + { + this.tokenStream = tokenStream; + } + + static class GridCell + { + int rowSpan = 1; + int colSpan = 1; + + final List attributes; + final SamXParser.FlowContext flow; + + GridCell(List attributes, SamXParser.OptionalFlowContext optionalFlowContext) + { + this.attributes = attributes; + if (optionalFlowContext != null) + { + flow = optionalFlowContext.flow(); + } + else + { + flow = null; + } + } + + void setSpan(String span) + { + for (char ch : span.toCharArray()) + { + if (ch == '|') + { + colSpan++; + } + else if (ch == '-') + { + rowSpan++; + } + else + { + // error + } + } + + if (colSpan > 1) + { + colSpan--; + } + + if (rowSpan > 1) + { + rowSpan--; + } + } + + public String getContent(SamXParserVisitor visitor) + { + StringBuilder builder = new StringBuilder(); + if (flow != null) + { + builder.append(visitor.visitFlow(flow)); + } + return builder.toString(); + } + + public boolean hasContent() + { + return flow != null && (!flow.getText().isEmpty()); + } + + public Object renderContent(SamXParserVisitor visitor) + { + return visitor.visitFlow(flow); + } + + public String getAttributesPlain() + { + AttributeVisitor av = new AttributeVisitor(); + for (SamXParser.AttributeContext ac : attributes) + { + av.visit(ac); + } + return av.toPlainString(); + } + } + + static class GeneralGridRow + { + final SamXParser.MetadataContext metadataContext; + + final ArrayList cells = new ArrayList<>(); + + public int getColumnCount() + { + return cells.size(); + } + + GeneralGridRow(SamXParser.GeneralGridRowDataContext rdc) + { + metadataContext = rdc.metadata(); + + for (SamXParser.GeneralGridElementContext ggec : rdc.generalGridElement()) + { + if (ggec.gridElement() != null) + { + GridVisitor.GridCell gc = new GridVisitor.GridCell(ggec.gridElement().attribute(), ggec.gridElement().optionalFlow()); + cells.add(gc); + } + else if (ggec.spanGridElement() != null) + { + GridVisitor.GridCell gc = new GridVisitor.GridCell(ggec.spanGridElement().attribute(), ggec.spanGridElement().optionalFlow()); + gc.setSpan(ggec.spanGridElement().MUL_COLSEP().getText()); + + for (int ii = 0; ii < gc.colSpan; ++ii) + { + cells.add(gc); + } + } + } + } + } + + static class GeneralGridGroup + { + ArrayList rows = new ArrayList<>(); + + int conditionColumnWidth = 0; + int columnWidths[]; + + GeneralGridGroup(SamXParser.GeneralGridGroupContext gggc, SamXParserVisitor visitor) + { + HashSet columnCount = new HashSet<>(); + for (SamXParser.GeneralGridRowContext rc : gggc.generalGridRow()) + { + final SamXParser.GeneralGridRowDataContext rdc = rc.generalGridRowData(); + if (rdc != null) + { + final GridVisitor.GeneralGridRow ggr = new GridVisitor.GeneralGridRow(rdc); + + if (visitor != null) + { + final String attributeCondition = visitor.visitMetadata(ggr.metadataContext).toString(); + + if (conditionColumnWidth < attributeCondition.length()) + { + conditionColumnWidth = attributeCondition.length(); + } + } + + rows.add(ggr); + columnCount.add(ggr.getColumnCount()); + } + } + + if (columnCount.size() != 1) + { + throw new RuntimeException("Invalid table specification: multiple table column sizes: " + columnCount.toString()); + } + + columnWidths = new int[columnCount.iterator().next()]; + + if (visitor != null) + { + for (GridVisitor.GeneralGridRow ggr : rows) + { + for (int ii = 0; ii < ggr.cells.size(); ++ii) + { + final GridVisitor.GridCell gc = ggr.cells.get(ii); + final String content = gc.getContent(visitor); + + int rowSpanIndicator = 0; + if (gc.rowSpan > 1) + { + rowSpanIndicator = gc.rowSpan; + } + + final int thisWidth = (int) Math.ceil((content.length() + rowSpanIndicator) / (double) (gc.colSpan)); + + if (columnWidths[ii] < thisWidth) + { + columnWidths[ii] = thisWidth; + } + } + } + } + } + } +} diff --git a/src/main/java/net/signbit/samx/PrettyPrinterVisitor.java b/src/main/java/net/signbit/samx/PrettyPrinterVisitor.java index 4c7b82a..578f7a9 100644 --- a/src/main/java/net/signbit/samx/PrettyPrinterVisitor.java +++ b/src/main/java/net/signbit/samx/PrettyPrinterVisitor.java @@ -17,7 +17,6 @@ package net.signbit.samx; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import org.antlr.v4.runtime.BufferedTokenStream; @@ -86,7 +85,7 @@ private StringBuilder wrapText(String rawText, int wrapLength, boolean indentFir StringTokenizer tokenizer = new StringTokenizer(paragraphText, '\n'); while (tokenizer.hasNext()) { - if (! indentFirst) + if (!indentFirst) { indentFirst = true; } @@ -176,7 +175,7 @@ public StringBuilder visitListElement(SamXParser.ListElementContext ctx) ArrayList blocks = new ArrayList<>(ctx.block()); boolean joined = false; - if (! blocks.isEmpty()) + if (!blocks.isEmpty()) { if (ctx.separator == null) { @@ -201,12 +200,12 @@ public StringBuilder visitListElement(SamXParser.ListElementContext ctx) StringBuilder builder = new StringBuilder(); - indentLevel ++; + indentLevel++; final int wrapLength = wrapParagraphAtColumn - indentLevel * indentString.length(); builder.append(wrapText(firstLineFlow.toString(), wrapLength, false)); - indentLevel --; + indentLevel--; - if (! blocks.isEmpty()) + if (!blocks.isEmpty()) { if ((ctx.separator != null) || joined) { @@ -337,7 +336,7 @@ public StringBuilder visitRecordSet(SamXParser.RecordSetContext ctx) { builder.append(' '); - for (int jj = 0; jj < columnWidths[0]; ++ jj) + for (int jj = 0; jj < columnWidths[0]; ++jj) { builder.append(' '); } @@ -859,7 +858,7 @@ private void visitNestedBlock(StringBuilder builder, List renderGridElementList(SamXParser.ConditionContext cond private void renderConditionAndAttributes(ParserRuleContext prc, StringBuilder builder) { final SamXParser.MetadataContext metadata = prc.getRuleContext(SamXParser.MetadataContext.class, 0); + builder.append(visitMetadata(metadata)); + } - final SamXParser.ConditionContext cond = metadata.condition(); + @Override + public StringBuilder visitMetadata(SamXParser.MetadataContext mc) + { + StringBuilder builder = new StringBuilder(); + final SamXParser.ConditionContext cond = mc.condition(); if (cond != null) { builder.append(visit(cond)); } - for (SamXParser.AttributeContext ac : metadata.attribute()) + for (SamXParser.AttributeContext ac : mc.attribute()) { builder.append(visit(ac)); } + return builder; } @Override @@ -1020,7 +1026,7 @@ public StringBuilder visitGrid(SamXParser.GridContext ctx) int length = value.length(); if (value.charAt(0) == '(') { - length --; + length--; } columnWidths[ii] = length; isInteger[ii] = true; @@ -1047,7 +1053,7 @@ public StringBuilder visitGrid(SamXParser.GridContext ctx) int length = value.length(); if ((!value.isEmpty()) && (value.charAt(0) == '(')) { - length --; + length--; } if (columnWidths[ii] < length) { @@ -1134,194 +1140,23 @@ public StringBuilder visitGrid(SamXParser.GridContext ctx) return builder; } - private class GridCell - { - int rowSpan = 1; - int colSpan = 1; - - private final String attributes0; - private final String content0; - - GridCell(List attributes, SamXParser.OptionalFlowContext optionalFlowContext) - { - { - StringBuilder builder = new StringBuilder(); - for (SamXParser.AttributeContext ac : attributes) - { - builder.append(visit(ac)); - } - this.attributes0 = builder.toString(); - } - - StringBuilder builder = new StringBuilder(); - if (optionalFlowContext != null) - { - final SamXParser.FlowContext fc = optionalFlowContext.flow(); - if (fc != null) - { - if (builder.length() > 0) - { - builder.append(' '); - } - - builder.append(visitFlow(fc)); - } - } - content0 = builder.toString(); - } - - int getLength() - { - int length = attributes0.length(); - if (length > 0) - { - length++; - } - length += content0.length(); - return length; - } - - void setSpan(String span) - { - for (char ch: span.toCharArray()) - { - if (ch == '|') - { - colSpan ++; - } - else if (ch == '-') - { - rowSpan ++; - } - else - { - // error - } - } - - if (colSpan > 1) - { - colSpan --; - } - } - - public String getContent() - { - return content0; - } - - public String getAttributes() - { - return attributes0; - } - } - - - private class GeneralGridRow - { - String attributeCondition; - ArrayList cells; - - public int getColumnCount() - { - return cells.size(); - } - - GeneralGridRow(SamXParser.GeneralGridRowDataContext rdc) - { - StringBuilder builder = new StringBuilder(); - renderConditionAndAttributes(rdc, builder); - attributeCondition = builder.toString(); - - cells = new ArrayList<>(); - - for (SamXParser.GeneralGridElementContext ggec: rdc.generalGridElement()) - { - if (ggec.gridElement() != null) - { - GridCell gc = new GridCell(ggec.gridElement().attribute(), ggec.gridElement().optionalFlow()); - cells.add(gc); - } - else if (ggec.spanGridElement() != null) - { - GridCell gc = new GridCell(ggec.spanGridElement().attribute(), ggec.spanGridElement().optionalFlow()); - gc.setSpan(ggec.spanGridElement().MUL_COLSEP().getText()); - - for (int ii = 0; ii < gc.colSpan; ++ ii) - { - cells.add(gc); - } - } - } - } - } - - private class GeneralGridGroup - { - ArrayList rows = new ArrayList<>(); - - int conditionColumnWidth = 0; - int columnWidths[]; - - GeneralGridGroup(SamXParser.GeneralGridGroupContext gggc) - { - HashSet columnCount = new HashSet<>(); - for (SamXParser.GeneralGridRowContext rc : gggc.generalGridRow()) - { - final SamXParser.GeneralGridRowDataContext rdc = rc.generalGridRowData(); - if (rdc != null) - { - final GeneralGridRow ggr = new GeneralGridRow(rdc); - - if (conditionColumnWidth < ggr.attributeCondition.length()) - { - conditionColumnWidth = ggr.attributeCondition.length(); - } - - rows.add(ggr); - columnCount.add(ggr.getColumnCount()); - } - } - - if (columnCount.size() != 1) - { - throw new RuntimeException("Invalid table specification: multiple table column sizes: " + columnCount.toString()); - } - - columnWidths = new int[columnCount.iterator().next()]; - - for (GeneralGridRow ggr: rows) - { - for (int ii = 0; ii < ggr.cells.size(); ++ii) - { - final GridCell gc = ggr.cells.get(ii); - final int thisWidth = (int) Math.ceil((gc.getContent().length() + gc.rowSpan - 1) / (double) (gc.colSpan)); - - if (columnWidths[ii] < thisWidth) - { - columnWidths[ii] = thisWidth; - } - } - } - } - } @Override public StringBuilder visitGeneralGrid(SamXParser.GeneralGridContext ctx) { - final GeneralGridGroup body = new GeneralGridGroup(ctx.body); + final GridVisitor.GeneralGridGroup body = new GridVisitor.GeneralGridGroup(ctx.body, this); int conditionColumnWidth = body.conditionColumnWidth; int columnWidths[] = new int[body.columnWidths.length]; - for (int ii = 0; ii < body.columnWidths.length; ++ ii) + for (int ii = 0; ii < body.columnWidths.length; ++ii) { columnWidths[ii] = body.columnWidths[ii]; } - GeneralGridGroup header = null; + GridVisitor.GeneralGridGroup header = null; if (ctx.header != null) { - header = new GeneralGridGroup(ctx.header); + header = new GridVisitor.GeneralGridGroup(ctx.header, this); if (header.columnWidths.length != body.columnWidths.length) { throw new RuntimeException(String.format("Invalid table specification: multiple table column sizes between header (%d) and body (%d)", header.columnWidths.length, body.columnWidths.length)); @@ -1332,7 +1167,7 @@ public StringBuilder visitGeneralGrid(SamXParser.GeneralGridContext ctx) conditionColumnWidth = header.conditionColumnWidth; } - for (int ii = 0; ii < body.columnWidths.length; ++ ii) + for (int ii = 0; ii < body.columnWidths.length; ++ii) { if (columnWidths[ii] < header.columnWidths[ii]) { @@ -1341,10 +1176,10 @@ public StringBuilder visitGeneralGrid(SamXParser.GeneralGridContext ctx) } } - GeneralGridGroup footer = null; + GridVisitor.GeneralGridGroup footer = null; if (ctx.footer != null) { - footer = new GeneralGridGroup(ctx.footer); + footer = new GridVisitor.GeneralGridGroup(ctx.footer, this); if (footer.columnWidths.length != body.columnWidths.length) { throw new RuntimeException(String.format("Invalid table specification: multiple table column sizes between footer (%d) and body (%d)", footer.columnWidths.length, body.columnWidths.length)); @@ -1355,7 +1190,7 @@ public StringBuilder visitGeneralGrid(SamXParser.GeneralGridContext ctx) conditionColumnWidth = footer.conditionColumnWidth; } - for (int ii = 0; ii < body.columnWidths.length; ++ ii) + for (int ii = 0; ii < body.columnWidths.length; ++ii) { if (columnWidths[ii] < footer.columnWidths[ii]) { @@ -1388,7 +1223,7 @@ public StringBuilder visitGeneralGrid(SamXParser.GeneralGridContext ctx) renderGeneralTableGroup(conditionColumnWidth, columnWidths, footer, builder); } - indentLevel --; + indentLevel--; builder.append('\n'); @@ -1414,41 +1249,47 @@ private void renderGeneralTableSeparator(int conditionColumnWidth, int[] columnW builder.append("+\n"); } - private void renderGeneralTableGroup(int conditionColumnWidth, int[] columnWidths, GeneralGridGroup header, StringBuilder builder) + private void renderGeneralTableGroup(int conditionColumnWidth, int[] columnWidths, GridVisitor.GeneralGridGroup gridGroup, StringBuilder builder) { - for (GeneralGridRow ggr: header.rows) + for (GridVisitor.GeneralGridRow ggr : gridGroup.rows) { addIndent(builder); if (conditionColumnWidth > 0) { - builder.append(String.format("%1$-" + conditionColumnWidth + "s", ggr.attributeCondition)); + final String attributeCondition = visitMetadata(ggr.metadataContext).toString(); + builder.append(String.format("%1$-" + conditionColumnWidth + "s", attributeCondition)); } - for (int jj = 0; jj < columnWidths.length; ++ jj) + for (int jj = 0; jj < columnWidths.length; ++jj) { - final GridCell gc = ggr.cells.get(jj); + final GridVisitor.GridCell gc = ggr.cells.get(jj); if (gc.colSpan > 0) { builder.append(" |"); int columnWidth = columnWidths[jj]; final int colSpan = gc.colSpan; - for (int kk = 1; kk < colSpan; ++ kk) + for (int kk = 1; kk < colSpan; ++kk) { columnWidth += columnWidths[jj + kk] + 2; ggr.cells.get(jj + kk).colSpan = 0; builder.append('|'); } - for (int kk = 1; kk < gc.rowSpan; ++ kk) + if (gc.rowSpan > 1) { builder.append('-'); - columnWidth --; + columnWidth--; + for (int kk = 1; kk < gc.rowSpan; ++kk) + { + builder.append('-'); + columnWidth--; + } } - final String attributes = gc.getAttributes(); + final String attributes = gc.getAttributesPlain(); builder.append(attributes); builder.append(' '); columnWidth -= attributes.length(); - builder.append(String.format("%1$-" + columnWidth + "s", gc.getContent())); + builder.append(String.format("%1$-" + columnWidth + "s", gc.getContent(PrettyPrinterVisitor.this))); } } diff --git a/src/main/java/net/signbit/samx/RendererVisitor.java b/src/main/java/net/signbit/samx/RendererVisitor.java index 53f0ee1..879ef2d 100644 --- a/src/main/java/net/signbit/samx/RendererVisitor.java +++ b/src/main/java/net/signbit/samx/RendererVisitor.java @@ -1,3 +1,19 @@ +/* + Copyright 2020 Florin Iucha + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + package net.signbit.samx; import java.io.IOException; @@ -182,6 +198,19 @@ public Object visitNotBelongsToSetCondition(SamXParser.NotBelongsToSetConditionC return Boolean.FALSE; } + public boolean isDisabled(SamXParser.ConditionContext cc) + { + if (cc != null) + { + Object enabled = visit(cc); + return !Boolean.TRUE.equals(enabled); + } + else + { + return false; + } + } + public boolean isDisabled(ParserRuleContext prc) { final SamXParser.MetadataContext metadata = prc.getRuleContext(SamXParser.MetadataContext.class, 0); diff --git a/src/main/java/net/signbit/samx/VisitorUtils.java b/src/main/java/net/signbit/samx/VisitorUtils.java index 102e9a9..fa63214 100644 --- a/src/main/java/net/signbit/samx/VisitorUtils.java +++ b/src/main/java/net/signbit/samx/VisitorUtils.java @@ -102,7 +102,7 @@ public static boolean compareFilesExceptWhitespace(String original, String prett prettyIdx++; prettyColumn++; - commonSubstring ++; + commonSubstring++; continue; } diff --git a/src/main/java/net/signbit/samx/XmlTextVisitor.java b/src/main/java/net/signbit/samx/XmlTextVisitor.java index 80c24dd..1554299 100644 --- a/src/main/java/net/signbit/samx/XmlTextVisitor.java +++ b/src/main/java/net/signbit/samx/XmlTextVisitor.java @@ -207,10 +207,10 @@ public Object visitPhrase(SamXParser.PhraseContext ctx) return null; } - if (! ctx.annotation().isEmpty()) + if (!ctx.annotation().isEmpty()) { final List url = ctx.annotation(0).flow().url(); - if ((url != null) && (! url.isEmpty())) + if ((url != null) && (!url.isEmpty())) { if (docBookMode) { @@ -378,7 +378,7 @@ private void visitGenericList(String tagType, List blocks = new ArrayList<>(lec.block()); - if (! blocks.isEmpty()) + if (!blocks.isEmpty()) { if (lec.separator == null) { @@ -403,21 +403,21 @@ private void visitGenericList(String tagType, List'); - if (! blocks.isEmpty()) + if (!blocks.isEmpty()) { appendNewline(); } indentParagraph = true; - indentLevel ++; - for (SamXParser.BlockContext bc: blocks) + indentLevel++; + for (SamXParser.BlockContext bc : blocks) { visit(bc); //appendNewline(); } - indentLevel --; + indentLevel--; - if (! blocks.isEmpty()) + if (!blocks.isEmpty()) { addIndent(); } @@ -613,11 +613,11 @@ public Exception visitIncludeFile(SamXParser.IncludeFileContext ctx) visitor.setIndentLevel(indentLevel + 1); if (docBookMode) { - visitor.setDocBookMode(); + visitor.setDocBookMode(); } if (ditaMode) { - visitor.setDitaMode(); + visitor.setDitaMode(); } visitor.visit(includedResult.document); @@ -835,7 +835,7 @@ private void renderDocBookFigure(SamXParser.InsertImageContext ctx) final String elementId = attributeVisitor.getId(); append(String.format("
", elementId)); appendNewline(); - indentLevel ++; + indentLevel++; addIndent(); @@ -844,12 +844,12 @@ private void renderDocBookFigure(SamXParser.InsertImageContext ctx) addIndent(); append(""); appendNewline(); - indentLevel ++; - + indentLevel++; + addIndent(); append(""); appendNewline(); - indentLevel ++; + indentLevel++; addIndent(); append(""); appendNewline(); - indentLevel --; + indentLevel--; addIndent(); append(""); appendNewline(); - indentLevel --; + indentLevel--; addIndent(); append(""); appendNewline(); - indentLevel --; + indentLevel--; addIndent(); append("
"); appendNewline(); @@ -879,7 +879,7 @@ private void renderFigure(SamXParser.InsertImageContext ctx) AttributeVisitor attributeVisitor = new AttributeVisitor(); if (ditaMode) { - attributeVisitor.setDitaMode(); + attributeVisitor.setDitaMode(); } for (SamXParser.AttributeContext ac : ctx.blockMetadata().metadata().attribute()) { @@ -913,11 +913,11 @@ public Object visitInsertImage(SamXParser.InsertImageContext ctx) addIndent(); if (docBookMode) { - renderDocBookFigure(ctx); + renderDocBookFigure(ctx); } else { - renderFigure(ctx); + renderFigure(ctx); } appendNewline(); @@ -962,11 +962,11 @@ private void renderElementWithAttributesOpen(String tagType, List renderGeneralGridRow(SamXParser.GeneralGridRowDataContext ggrdc) { - int rowSpan = 1; - int colSpan = 1; - - final List attribute; - final SamXParser.FlowContext flow; + ArrayList rowCells = new ArrayList<>(); - GridCell(List attributes, SamXParser.OptionalFlowContext optionalFlowContext) - { - this.attribute = attributes; - if (optionalFlowContext != null) - { - flow = optionalFlowContext.flow(); - } - else - { - flow = null; - } - } - - void setSpan(String span) - { - for (char ch: span.toCharArray()) - { - if (ch == '|') - { - colSpan ++; - } - else if (ch == '-') - { - rowSpan ++; - } - else - { - // error - } - } - - if (colSpan > 1) - { - colSpan --; - } - } - } - - private ArrayList renderGeneralGridRow(SamXParser.GeneralGridRowDataContext ggrdc) - { - ArrayList rowCells = new ArrayList<>(); - - for (SamXParser.GeneralGridElementContext ggec: ggrdc.generalGridElement()) + for (SamXParser.GeneralGridElementContext ggec : ggrdc.generalGridElement()) { if (ggec.gridElement() != null) { - GridCell gc = new GridCell(ggec.gridElement().attribute(), ggec.gridElement().optionalFlow()); + GridVisitor.GridCell gc = new GridVisitor.GridCell(ggec.gridElement().attribute(), ggec.gridElement().optionalFlow()); rowCells.add(gc); } else if (ggec.spanGridElement() != null) { - GridCell gc = new GridCell(ggec.spanGridElement().attribute(), ggec.spanGridElement().optionalFlow()); + GridVisitor.GridCell gc = new GridVisitor.GridCell(ggec.spanGridElement().attribute(), ggec.spanGridElement().optionalFlow()); gc.setSpan(ggec.spanGridElement().MUL_COLSEP().getText()); - for (int ii = 0; ii < gc.colSpan; ++ ii) + for (int ii = 0; ii < gc.colSpan; ++ii) { rowCells.add(gc); } @@ -1174,44 +1128,36 @@ public StringBuilder visitGeneralGrid(SamXParser.GeneralGridContext ctx) return null; } - ArrayList> cells = new ArrayList<>(); - ArrayList> rowAttributes = new ArrayList<>(); + /* + * parse + */ + + final GridVisitor.GeneralGridGroup body = new GridVisitor.GeneralGridGroup(ctx.body, null); + GridVisitor.GeneralGridGroup header = null; if (ctx.header != null) { - for (SamXParser.GeneralGridRowContext rc : ctx.header.generalGridRow()) + header = new GridVisitor.GeneralGridGroup(ctx.header, null); + if (header.columnWidths.length != body.columnWidths.length) { - final SamXParser.GeneralGridRowDataContext rdc = rc.generalGridRowData(); - if (rdc != null) - { - if (! isDisabled(rdc)) - { - ArrayList rowCells = renderGeneralGridRow(rdc); - cells.add(rowCells); - - rowAttributes.add(rdc.metadata().attribute()); - } - } + throw new RuntimeException(String.format("Invalid table specification: multiple table column sizes between header (%d) and body (%d)", header.columnWidths.length, body.columnWidths.length)); } } - int headerOffsetAt = cells.size(); - - for (SamXParser.GeneralGridRowContext rc: ctx.body.generalGridRow()) + GridVisitor.GeneralGridGroup footer = null; + if (ctx.footer != null) { - final SamXParser.GeneralGridRowDataContext rdc = rc.generalGridRowData(); - if (rdc != null) + footer = new GridVisitor.GeneralGridGroup(ctx.footer, null); + if (footer.columnWidths.length != body.columnWidths.length) { - if (! isDisabled(rdc)) - { - ArrayList rowCells = renderGeneralGridRow(rdc); - cells.add(rowCells); - - rowAttributes.add(rdc.metadata().attribute()); - } + throw new RuntimeException(String.format("Invalid table specification: multiple table column sizes between footer (%d) and body (%d)", footer.columnWidths.length, body.columnWidths.length)); } } + /* + * render + */ + addIndent(); renderElementWithAttributes("table", ctx.blockMetadata().metadata().attribute()); appendNewline(); @@ -1220,6 +1166,154 @@ public StringBuilder visitGeneralGrid(SamXParser.GeneralGridContext ctx) renderTitle(ctx); + if (docBookMode) + { + addIndent(); + append(String.format("", body.columnWidths.length)); + appendNewline(); + + for (int ii = 1; ii <= body.columnWidths.length; ++ ii) + { + addIndent(); + append(String.format("", ii)); + appendNewline(); + } + } + + if (header != null) + { + renderGeneralTableGroup(header, "thead", getTableHeaderDataTag()); + } + + if (footer != null) + { + renderGeneralTableGroup(footer, "tfoot", getTableDataTag()); + } + + renderGeneralTableGroup(body, "tbody", getTableDataTag()); + + if (docBookMode) + { + indentLevel--; + addIndent(); + append(""); + appendNewline(); + } + + indentLevel--; + + appendCloseTag("table"); + + return null; + } + + private void renderGeneralTableGroup(GridVisitor.GeneralGridGroup gridGroup, String groupName, String dataName) + { + if (docBookMode) + { + addIndent(); + append('<'); + append(groupName); + append('>'); + appendNewline(); + indentLevel++; + } + + int rowSpans[] = new int[gridGroup.columnWidths.length]; + + for (GridVisitor.GeneralGridRow ggr : gridGroup.rows) + { + if (isDisabled(ggr.metadataContext.condition())) + { + continue; + } + + addIndent(); + renderElementWithAttributes(getTableRowTag(), ggr.metadataContext.attribute()); + appendNewline(); + indentLevel++; + + final ArrayList rowCells = ggr.cells; + int jj = 0; + while (jj < rowCells.size()) + { + if (rowSpans[jj] > 0) + { + rowSpans[jj] --; + final int beginEmptySpan = jj; + + jj ++; + while ((jj < rowCells.size()) && (rowSpans[jj] > 0)) + { + rowSpans[jj] --; + + jj ++; + } + + final int endEmptySpan = jj; + addIndent(); + append(String.format("", beginEmptySpan, endEmptySpan)); + appendNewline(); + + continue; + } + + final GridVisitor.GridCell gc = rowCells.get(jj); + + addIndent(); + + renderElementWithAttributesOpen(dataName, gc.attributes); + if (gc.colSpan > 1) + { + if (docBookMode) + { + append(String.format(" namest=\"c%d\" nameend=\"c%d\"", jj + 1, jj + gc.colSpan)); + } + else + { + append(String.format(" colspan=\"%d\"", gc.colSpan)); + } + } + if (gc.rowSpan > 1) + { + if (docBookMode) + { + append(String.format(" morerows=\"%d\"", gc.rowSpan - 1)); + for (int kk = jj; kk < jj + gc.colSpan; ++kk) + { + rowSpans[kk] = gc.rowSpan - 1; + } + } + else + { + append(String.format("", gc.rowSpan)); + } + } + + if ((gc.flow != null && (!gc.flow.getText().isEmpty()))) + { + append('>'); + gc.renderContent(this); + append('<'); + append('/'); + append(dataName); + } + else + { + append('/'); + } + append('>'); + appendNewline(); + + jj += gc.colSpan; + } + + indentLevel--; + appendCloseTag(getTableRowTag()); + } + + // TODO: +/* for (int ii = 0; ii < cells.size(); ++ii) { String cellTag = "td"; @@ -1232,26 +1326,26 @@ public StringBuilder visitGeneralGrid(SamXParser.GeneralGridContext ctx) renderElementWithAttributes("tr", rowAttributes.get(ii)); appendNewline(); - indentLevel ++; + indentLevel++; - final ArrayList rowCells = cells.get(ii); + final ArrayList rowCells = cells.get(ii); int jj = 0; while (jj < rowCells.size()) { - final GridCell gc = rowCells.get(jj); + final GridVisitor.GridCell gc = rowCells.get(jj); addIndent(); - renderElementWithAttributesOpen(cellTag, gc.attribute); + renderElementWithAttributesOpen(cellTag, gc.attributes); if (gc.colSpan > 1) { append(String.format(" colspan=\"%d\"", gc.colSpan)); } - if ((gc.flow != null && (! gc.flow.getText().isEmpty()))) + if ((gc.flow != null && (!gc.flow.getText().isEmpty()))) { append('>'); - visitFlow(gc.flow); + gc.renderContent(this); append('<'); append('/'); append(cellTag); @@ -1266,76 +1360,84 @@ public StringBuilder visitGeneralGrid(SamXParser.GeneralGridContext ctx) jj += gc.colSpan; } - indentLevel --; + indentLevel--; addIndent(); append(""); appendNewline(); } - indentLevel--; + */ - appendCloseTag("table"); - return null; + if (docBookMode) + { + indentLevel--; + addIndent(); + append('<'); + append('/'); + append(groupName); + append('>'); + appendNewline(); + } } public void setDocBookMode() { - docBookMode = true; + docBookMode = true; } public void setDitaMode() { - ditaMode = true; + ditaMode = true; } private String getParagraphTag() { - if (docBookMode) - { - return "para"; - } - else - { - return "p"; - } + if (docBookMode) + { + return "para"; + } + else + { + return "p"; + } } private String getOrderedListTag() { - if (docBookMode) - { - return "orderedlist"; - } - else - { - return "ol"; - } + if (docBookMode) + { + return "orderedlist"; + } + else + { + return "ol"; + } } private String getUnorderedListTag() { - if (docBookMode) - { - return "itemizedlist"; - } - else - { - return "ul"; - } + if (docBookMode) + { + return "itemizedlist"; + } + else + { + return "ul"; + } } private String getListItemTag() { - if (docBookMode) - { - return "listitem"; - } - else - { - return "li"; - } + if (docBookMode) + { + return "listitem"; + } + else + { + return "li"; + } } private String getTableRowTag() diff --git a/src/test/java/net/signbit/samx/parser/PrettyPrinterTest.java b/src/test/java/net/signbit/samx/parser/PrettyPrinterTest.java index 9772957..12f88bc 100644 --- a/src/test/java/net/signbit/samx/parser/PrettyPrinterTest.java +++ b/src/test/java/net/signbit/samx/parser/PrettyPrinterTest.java @@ -181,5 +181,7 @@ public void testGrids() testIsPretty("grids/missing_cells.samx"); testIsPretty("grids/gengrid_rowspan_only.samx"); + + testIsPretty("grids/multispan.samx"); } } diff --git a/src/test/java/net/signbit/samx/parser/XmlConverterTest.java b/src/test/java/net/signbit/samx/parser/XmlConverterTest.java index 39c27bd..25af80c 100644 --- a/src/test/java/net/signbit/samx/parser/XmlConverterTest.java +++ b/src/test/java/net/signbit/samx/parser/XmlConverterTest.java @@ -104,8 +104,15 @@ public void testGrids() throws IOException testConversion("grids/missing_cells.samx", "grids/missing_cells.xml"); + + testDocBook("build/resources/test/grids/simple.samx", "article", "grids/simple-docbook.xml"); + } + + @Test + public void testGeneralGrids() throws IOException + { testConversion("grids/gengrid_rowspan_only.samx", "grids/gengrid_rowspan_only.xml"); - testDocBook("build/resources/test/grids/simple.samx", "article", "grids/simple-docbook.samx"); + testDocBook("build/resources/test/grids/multispan.samx", "article", "grids/multispan.xml"); } } diff --git a/src/test/resources/grids/multispan.xml b/src/test/resources/grids/multispan.xml new file mode 100644 index 0000000..ace0bf4 --- /dev/null +++ b/src/test/resources/grids/multispan.xml @@ -0,0 +1,51 @@ + +
+ + Example CALS table from DocBook Guide + + + + + + + + + Horizontal Span + a3 + a4 + a5 + + + + + f1 + f2 + f3 + f4 + f5 + + + + + b1 + b2 + b3 + b4 + Vertical Span + + + c1 + Span Both + c4 + + + + d1 + + d4 + d5 + + + +
+
diff --git a/src/test/resources/grids/simple-docbook.samx b/src/test/resources/grids/simple-docbook.xml similarity index 100% rename from src/test/resources/grids/simple-docbook.samx rename to src/test/resources/grids/simple-docbook.xml