From: Thibaut Cuvelier Date: Mon, 13 Jul 2020 01:31:48 +0000 (+0200) Subject: Add support for CALS tables in DocBook. X-Git-Tag: lyx-2.4.0dev-acb2ca7b~589 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=e3027574;p=lyx.git Add support for CALS tables in DocBook. --- diff --git a/development/FORMAT b/development/FORMAT index f903ed3ae9..b3968bf73e 100644 --- a/development/FORMAT +++ b/development/FORMAT @@ -7,6 +7,10 @@ changes happened in particular if possible. A good example would be ----------------------- +2020-07-14 Thibaut Cuvelier + * Format incremented to 598: DocBook can export to HTML and CALS tables, with the parameter + \docbook_table_output (0: HTML, only choice previously; CALS: 1). + 2020-03-13 Jürgen Spitzmüller * Format incremented to 593: Buffer param \maintain_unincluded_children is not longer a bool (true|false) but has three states: "no" (formerly "false"), "strict" (formerly "true") and diff --git a/lib/lyx2lyx/lyx_2_4.py b/lib/lyx2lyx/lyx_2_4.py index c4d63cab14..6283631d26 100644 --- a/lib/lyx2lyx/lyx_2_4.py +++ b/lib/lyx2lyx/lyx_2_4.py @@ -3922,6 +3922,20 @@ def revert_libertinus_sftt_fonts(document): add_to_preamble(document, ["\\renewcommand*{\\LibertinusMono@scale}{" + str(tt_scale / 100.0) + "}"]) +def convert_docbook_table_output(document): + if find_token(document.header, '\\docbook_table_output') != -1: + document.warning("Malformed LyX file: \\docbook_table_output found before format 598!") + else: + document.header.append('\\docbook_table_output 0') + + +def revert_docbook_table_output(document): + i = find_token(document.header, '\\docbook_table_output 0') + i = find_token(document.header, '\\docbook_table_output 1') if i == -1 else i + if i != -1: + del document.header[i] + + ## # Conversion hub # @@ -3980,10 +3994,12 @@ convert = [ [594, []], [595, []], [596, [convert_parskip]], - [597, [convert_libertinus_rm_fonts]] + [597, [convert_libertinus_rm_fonts]], + [598, [convert_docbook_table_output]] ] -revert = [[595, [revert_libertinus_rm_fonts,revert_libertinus_sftt_fonts]], +revert = [[597, [revert_docbook_table_output]], + [595, [revert_libertinus_rm_fonts,revert_libertinus_sftt_fonts]], [595, [revert_parskip,revert_line_vspaces]], [594, [revert_ams_spaces]], [593, [revert_counter_inset]], diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index 4ed8b4ea9a..722d7c1d8d 100644 --- a/src/BufferParams.cpp +++ b/src/BufferParams.cpp @@ -471,6 +471,7 @@ BufferParams::BufferParams() html_math_output = MathML; html_math_img_scale = 1.0; html_css_as_file = false; + docbook_table_output = HTMLTable; display_pixel_ratio = 1.0; shell_escape = false; @@ -1134,6 +1135,10 @@ string BufferParams::readToken(Lexer & lex, string const & token, } else if (token == "\\html_latex_end") { lex.eatLine(); html_latex_end = lex.getString(); + } else if (token == "\\docbook_table_output") { + int temp; + lex >> temp; + docbook_table_output = static_cast(temp); } else if (token == "\\output_sync") { lex >> output_sync; } else if (token == "\\output_sync_macro") { @@ -1491,6 +1496,8 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const << "\\html_css_as_file " << html_css_as_file << '\n' << "\\html_be_strict " << convert(html_be_strict) << '\n'; + os << "\\docbook_table_output " << docbook_table_output << '\n'; + if (html_math_img_scale != 1.0) os << "\\html_math_img_scale " << convert(html_math_img_scale) << '\n'; if (!html_latex_start.empty()) diff --git a/src/BufferParams.h b/src/BufferParams.h index 4e176c945e..b42d622fb3 100644 --- a/src/BufferParams.h +++ b/src/BufferParams.h @@ -558,6 +558,15 @@ public: std::string html_latex_end; /// bool html_css_as_file; + + // do not change these values. we rely upon them. + enum TableOutput { + HTMLTable = 0, + CALSTable = 1 + }; + /// what format to use for table output in DocBook. present choices are above + TableOutput docbook_table_output; + /// allow the LaTeX backend to run external programs bool shell_escape; /// generate output usable for reverse/forward search diff --git a/src/frontends/qt/GuiDocument.cpp b/src/frontends/qt/GuiDocument.cpp index 508a961177..adca094704 100644 --- a/src/frontends/qt/GuiDocument.cpp +++ b/src/frontends/qt/GuiDocument.cpp @@ -925,6 +925,8 @@ GuiDocument::GuiDocument(GuiView & lv) this, SLOT(change_adaptor())); connect(outputModule->mathoutCB, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor())); + connect(outputModule->tableoutCB, SIGNAL(currentIndexChanged(int)), + this, SLOT(change_adaptor())); connect(outputModule->shellescapeCB, SIGNAL(stateChanged(int)), this, SLOT(shellescapeChanged())); @@ -3718,6 +3720,13 @@ void GuiDocument::applyView() bp_.html_math_img_scale = outputModule->mathimgSB->value(); bp_.display_pixel_ratio = theGuiApp()->pixelRatio(); + int tablefmt = outputModule->tableoutCB->currentIndex(); + if (tablefmt == -1) + tablefmt = 0; + BufferParams::TableOutput const to = + static_cast(tablefmt); + bp_.docbook_table_output = to; + bp_.save_transient_properties = outputModule->saveTransientPropertiesCB->isChecked(); bp_.postpone_fragile_content = @@ -4355,6 +4364,8 @@ void GuiDocument::paramsToDialog() outputModule->strictCB->setChecked(bp_.html_be_strict); outputModule->cssCB->setChecked(bp_.html_css_as_file); + outputModule->tableoutCB->setCurrentIndex(bp_.docbook_table_output); + outputModule->saveTransientPropertiesCB ->setChecked(bp_.save_transient_properties); outputModule->postponeFragileCB diff --git a/src/frontends/qt/ui/OutputUi.ui b/src/frontends/qt/ui/OutputUi.ui index b828e2304a..6dc2a297ed 100644 --- a/src/frontends/qt/ui/OutputUi.ui +++ b/src/frontends/qt/ui/OutputUi.ui @@ -14,6 +14,95 @@ Form + + + + DocBook Output Options + + + true + + + + + + + 50 + false + + + + &Table output: + + + tableoutCB + + + + + + + + 50 + false + + + + Format to use for math output. + + + + HTML + + + + + CALS + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + LyX Format + + + true + + + false + + + + + + Save all parameters in the LyX file, including ones that are frequently switched or that are specific to the user (such as the output of the tracked changes, or the document directory path). Disabling this option plays nicer in collaborative settings and with version control systems. + + + Save &transient properties + + + + + + @@ -93,16 +182,6 @@ - - - - Runs the LaTeX backend with the -shell-escape option (Warning: use only when really necessary) - - - &Allow running external programs - - - @@ -164,7 +243,7 @@ &Math output: - mathoutCB + tableoutCB @@ -235,44 +314,16 @@ - - - - LyX Format - - - true + + + + Runs the LaTeX backend with the -shell-escape option (Warning: use only when really necessary) - - false + + &Allow running external programs - - - - - Save all parameters in the LyX file, including ones that are frequently switched or that are specific to the user (such as the output of the tracked changes, or the document directory path). Disabling this option plays nicer in collaborative settings and with version control systems. - - - Save &transient properties - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -359,6 +410,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index 2c38e3a7d9..87988afa70 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -3501,6 +3501,20 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const void Tabular::docbookRow(XMLStream & xs, row_type row, OutputParams const & runparams, bool header) const +{ + switch (buffer().params().docbook_table_output) { + case BufferParams::HTMLTable: + docbookRowAsHTML(xs, row, runparams, header); + break; + case BufferParams::CALSTable: + docbookRowAsCALS(xs, row, runparams); + break; + } +} + + +void Tabular::docbookRowAsHTML(XMLStream & xs, row_type row, + OutputParams const & runparams, bool header) const { string const celltag = header ? "th" : "td"; idx_type cell = getFirstCellInRow(row); @@ -3565,7 +3579,77 @@ void Tabular::docbookRow(XMLStream & xs, row_type row, ++cell; } xs << xml::EndTag("tr"); - xs<< xml::CR(); + xs << xml::CR(); +} + + +void Tabular::docbookRowAsCALS(XMLStream & xs, row_type row, + OutputParams const & runparams) const +{ + idx_type cell = getFirstCellInRow(row); + + xs << xml::StartTag("row"); + xs << xml::CR(); + for (col_type c = 0; c < ncols(); ++c) { + if (isPartOfMultiColumn(row, c) || isPartOfMultiRow(row, c)) + continue; + + stringstream attr; + + attr << "align='"; + switch (getAlignment(cell)) { + case LYX_ALIGN_BLOCK: + attr << "justify"; + break; + case LYX_ALIGN_DECIMAL: { + Language const *tlang = buffer().paragraphs().front().getParLanguage(buffer().params()); + attr << "char' char='" << to_utf8(tlang->decimalSeparator()); + } + break; + case LYX_ALIGN_LEFT: + attr << "left"; + break; + case LYX_ALIGN_RIGHT: + attr << "right"; + break; + + default: + attr << "center"; + break; + } + attr << "'"; + attr << " valign='"; + switch (getVAlignment(cell)) { + case LYX_VALIGN_TOP: + attr << "top"; + break; + case LYX_VALIGN_BOTTOM: + attr << "bottom"; + break; + case LYX_VALIGN_MIDDLE: + attr << "middle"; + } + attr << "'"; + + if (isMultiColumn(cell)) + attr << " colspan='" << columnSpan(cell) << "'"; + else if (isMultiRow(cell)) + attr << " rowspan='" << rowSpan(cell) << "'"; + else + attr << " colname='c" << (c + 1) << "'"; // Column numbering starts at 1. + + // All cases where there should be a line *below* this row. + if (row_info[row].bottom_space_default) + attr << " rowsep='1'"; + + xs << xml::StartTag("entry", attr.str(), true); + cellInset(cell)->docbook(xs, runparams); + xs << xml::EndTag("entry"); + xs << xml::CR(); + ++cell; + } + xs << xml::EndTag("row"); + xs << xml::CR(); } @@ -3580,35 +3664,57 @@ void Tabular::docbook(XMLStream & xs, OutputParams const & runparams) const xs << xml::CR(); } - // "Formal" tables have a caption and use the tag ; the distinction with is done outside. + // "Formal" tables have a title and use the tag
; the distinction with is done outside. + // HTML has the caption first with titles forbidden, and CALS has a title first. if (haveLTCaption()) { - xs << xml::StartTag("caption"); + std::string tag = ((buffer().params().docbook_table_output) == BufferParams::HTMLTable) ? "caption" : "title"; + + xs << xml::StartTag(tag); for (row_type r = 0; r < nrows(); ++r) if (row_info[r].caption) docbookRow(xs, r, runparams); - xs << xml::EndTag("caption"); + xs << xml::EndTag(tag); xs << xml::CR(); } - // output header info + // CALS header: describe all columns in this table. For names, take 'c' then the ID of the column. + // Start at one, as is customary with CALS! + if (buffer().params().docbook_table_output == BufferParams::CALSTable) { + for (col_type c = 0; c < ncols(); ++c) { + std::stringstream attr; + attr << "colnum='" << (c + 1) << "' "; + attr << "colname='c" << (c + 1) << "' "; + Length const cwidth = column_info[c].p_width; + if (!cwidth.zero()) + attr << "colwidth='" << cwidth.asHTMLString() << "' "; + attr << "rowheader='norowheader'"; // Last attribute, hence no space at the end. + + xs << xml::CompTag("colspec", attr.str()); + xs << xml::CR(); + } + } + + // Output the header of the table. For both HTML and CALS, this is surrounded by a thead. bool const havefirsthead = haveLTFirstHead(false); // if we have a first head, then we are going to ignore the // headers for the additional pages, since there aren't any - // in XHTML. this test accomplishes that. + // in DocBook. this test accomplishes that. bool const havehead = !havefirsthead && haveLTHead(false); if (havehead || havefirsthead) { xs << xml::StartTag("thead") << xml::CR(); for (row_type r = 0; r < nrows(); ++r) { if (((havefirsthead && row_info[r].endfirsthead) || - (havehead && row_info[r].endhead)) && - !row_info[r].caption) { - docbookRow(xs, r, runparams, true); + (havehead && row_info[r].endhead)) && + !row_info[r].caption) { + docbookRow(xs, r, runparams, true); // TODO: HTML vs CALS } } xs << xml::EndTag("thead"); xs << xml::CR(); } - // output footer info + + // Output the footer of the table. For both HTML and CALS, this is surrounded by a tfoot and output just after + // the header (and before the body). bool const havelastfoot = haveLTLastFoot(false); // as before. bool const havefoot = !havelastfoot && haveLTFoot(false); @@ -3616,15 +3722,17 @@ void Tabular::docbook(XMLStream & xs, OutputParams const & runparams) const xs << xml::StartTag("tfoot") << xml::CR(); for (row_type r = 0; r < nrows(); ++r) { if (((havelastfoot && row_info[r].endlastfoot) || - (havefoot && row_info[r].endfoot)) && - !row_info[r].caption) { - docbookRow(xs, r, runparams); + (havefoot && row_info[r].endfoot)) && + !row_info[r].caption) { + docbookRow(xs, r, runparams); // TODO: HTML vs CALS } } xs << xml::EndTag("tfoot"); xs << xml::CR(); } + // Output the main part of the table. The tbody container is mandatory for CALS, but optional for HTML (only if + // there is no header and no footer). It never hurts to have it, though. xs << xml::StartTag("tbody"); xs << xml::CR(); for (row_type r = 0; r < nrows(); ++r) @@ -3633,6 +3741,7 @@ void Tabular::docbook(XMLStream & xs, OutputParams const & runparams) const xs << xml::EndTag("tbody"); xs << xml::CR(); + // If this method started the table tag, also make it close it. if (!hasTableStarted) { xs << xml::EndTag("informaltable"); xs << xml::CR(); diff --git a/src/insets/InsetTabular.h b/src/insets/InsetTabular.h index 4166f316c3..de26070b7b 100644 --- a/src/insets/InsetTabular.h +++ b/src/insets/InsetTabular.h @@ -572,7 +572,7 @@ public: void read(Lexer &); /// void latex(otexstream &, OutputParams const &) const; - /// + /// serialise the table in DocBook, according to buffer parameters void docbook(XMLStream &, OutputParams const &) const; /// docstring xhtml(XMLStream &, OutputParams const &) const; @@ -907,9 +907,14 @@ public: idx_type cell, row_type row, col_type column, std::vector const &, bool onlydata, size_t max_length) const; - /// auxiliary function for docbook + /// auxiliary function for DocBook void docbookRow(XMLStream &, row_type, OutputParams const &, bool header = false) const; + /// auxiliary function for DocBook: export this row as HTML + void docbookRowAsHTML(XMLStream &, row_type, OutputParams const &, + bool header) const; + /// auxiliary function for DocBook: export this row as CALS + void docbookRowAsCALS(XMLStream &, row_type, OutputParams const &) const; /// docstring xhtmlRow(XMLStream & xs, row_type, OutputParams const &, bool header = false) const; diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index 005a103486..737ac6d316 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -543,6 +543,7 @@ Preamble::Preamble() : one_language(true), explicit_babel(false), h_html_be_strict = "false"; h_html_css_as_file = "0"; h_html_math_output = "0"; + h_docbook_table_output = "0"; h_index[0] = "Index"; h_index_command = "default"; h_inputencoding = "auto-legacy"; @@ -2117,6 +2118,7 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc, string const & outfiled << "\\html_math_output " << h_html_math_output << "\n" << "\\html_css_as_file " << h_html_css_as_file << "\n" << "\\html_be_strict " << h_html_be_strict << "\n" + << "\\docbook_table_output " << h_docbook_table_output << "\n" << authors_ << "\\end_header\n\n" << "\\begin_body\n"; diff --git a/src/tex2lyx/Preamble.h b/src/tex2lyx/Preamble.h index 42c6069fd2..dccd780a4e 100644 --- a/src/tex2lyx/Preamble.h +++ b/src/tex2lyx/Preamble.h @@ -190,6 +190,7 @@ private: std::string h_html_be_strict; std::string h_html_css_as_file; std::string h_html_math_output; + std::string h_docbook_table_output; std::string h_index[99]; std::string h_index_command; std::string h_inputencoding; diff --git a/src/version.h b/src/version.h index b6e5600cf5..770c308362 100644 --- a/src/version.h +++ b/src/version.h @@ -32,8 +32,8 @@ extern char const * const lyx_version_info; // Do not remove the comment below, so we get merge conflict in // independent branches. Instead add your own. -#define LYX_FORMAT_LYX 597 // spitz: libertinus fonts -#define LYX_FORMAT_TEX2LYX 597 +#define LYX_FORMAT_LYX 598 // tcuvelier: DocBook tables +#define LYX_FORMAT_TEX2LYX 598 #if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX #ifndef _MSC_VER