X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetTabular.cpp;h=69f9e73e59f0f0f11e125f2c80e4ba5449048455;hb=8124e6c02ea1fd6779bb6c47ffe2bca2c8bd2d97;hp=e813fc7e3d29902df47e3a66a8fa43e71525a5e4;hpb=3637d6d408332c9acd293e0afde073de0a5dfa6e;p=lyx.git diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index e813fc7e3d..69f9e73e59 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -3007,7 +3007,7 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell, << "}\n"; } else if (getUsebox(cell) == BOX_VARWIDTH && (getRotateCell(cell) != 0 || align != LYX_ALIGN_LEFT - || valign != LYX_VALIGN_TOP)) { + || valign != LYX_VALIGN_TOP || hasNewlines(cell))) { os << "\\begin{cellvarwidth}["; switch (valign) { case LYX_VALIGN_TOP: @@ -3056,7 +3056,7 @@ void Tabular::TeXCellPostamble(otexstream & os, idx_type cell, os << breakln << "\\end{minipage}"; else if (getUsebox(cell) == BOX_VARWIDTH && (getRotateCell(cell) != 0 || getAlignment(cell) != LYX_ALIGN_LEFT - || getVAlignment(cell) != LYX_VALIGN_TOP)) + || getVAlignment(cell) != LYX_VALIGN_TOP || hasNewlines(cell))) os << breakln << "\\end{cellvarwidth}"; if (getRotateCell(cell) != 0) os << breakln << "\\end{turn}"; @@ -3208,7 +3208,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, bool rtl = par.isRTL(buffer().params()) && !par.empty() && getPWidth(cell).zero() - && !runparams.use_polyglossia; + && !runparams.isFullUnicode(); if (rtl) { string const lang = @@ -3272,7 +3272,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, } else if (!isPartOfMultiRow(row, c)) { if (!runparams.nice) os.texrow().start(par.id(), 0); - if (isMultiRow(cell) && !LaTeXFeatures::isAvailable("multirow-2021/01/29")) + if (isMultiRow(cell) && !LaTeXFeatures::isAvailableAtLeastFrom("multirow", 2021, 1, 29)) newrp.isNonLong = true; inset->latex(os, newrp); } @@ -3628,32 +3628,63 @@ std::string Tabular::getVAlignAsXmlAttribute(idx_type cell) const } -std::string Tabular::getHAlignAsXmlAttribute(idx_type cell, bool is_xhtml) const +std::string Tabular::getVAlignAsCssAttribute(idx_type cell) const +{ + switch (getVAlignment(cell)) { + case LYX_VALIGN_TOP: + return "vertical-align: top"; + case LYX_VALIGN_BOTTOM: + return "vertical-align: bottom"; + case LYX_VALIGN_MIDDLE: + return "vertical-align: middle"; + default: + // This case only silences a compiler warning, as all the cases are covered above. + return ""; + } +} + + +std::string Tabular::getHAlignAsXmlAttribute(idx_type cell) const { - // TODO: the Boolean flag isn't really clean; switch to an enum at some point. switch (getAlignment(cell)) { case LYX_ALIGN_LEFT: return "align='left'"; case LYX_ALIGN_RIGHT: return "align='right'"; + case LYX_ALIGN_BLOCK: + return "align='justify'"; + case LYX_ALIGN_DECIMAL: { + Language const *lang = buffer().paragraphs().front().getParLanguage(buffer().params()); + return "align='char' char='" + to_utf8(lang->decimalSeparator()) + "'"; + } + default: + return "align='center'"; + } +} + +std::string Tabular::getHAlignAsCssAttribute(idx_type cell) const +{ + switch (getAlignment(cell)) { + case LYX_ALIGN_LEFT: + return "text-align: left"; + case LYX_ALIGN_RIGHT: + return "text-align: right"; + case LYX_ALIGN_BLOCK: + return "text-align: justify"; + case LYX_ALIGN_DECIMAL: { + // In theory, character-level alignment is supported for CSS4, but it's + // experimental. + // https://www.w3.org/TR/css-text-4/#character-alignment + Language const *lang = buffer().paragraphs().front().getParLanguage(buffer().params()); + return "text-align: \"" + to_utf8(lang->decimalSeparator()) + "\""; + } default: - // HTML only supports left, right, and center. - if (is_xhtml) - return "align='center'"; - - // DocBook also has justify and decimal. - if (getAlignment(cell) == LYX_ALIGN_BLOCK) { - return "align='justify'"; - } else if (getAlignment(cell) == LYX_ALIGN_DECIMAL) { - Language const *tlang = buffer().paragraphs().front().getParLanguage(buffer().params()); - return "align='char' char='" + to_utf8(tlang->decimalSeparator()) + "'"; - } else { - return "align='center'"; - } + return "text-align: center"; } } + Tabular::XmlRowWiseBorders Tabular::computeXmlBorders(row_type row) const { Tabular::XmlRowWiseBorders borders; @@ -3727,11 +3758,13 @@ std::vector Tabular::computeCssStylePerCell(row_type row, col_type docstring Tabular::xmlRow(XMLStream & xs, const row_type row, OutputParams const & runparams, - const bool header, const bool is_xhtml, BufferParams::TableOutput docbook_table_output) const + const bool header, const XmlOutputFormat output_format, BufferParams::TableOutput docbook_table_output) const { docstring ret; - const bool is_xhtml_table = is_xhtml || docbook_table_output == BufferParams::TableOutput::HTMLTable; - const bool is_cals_table = !is_xhtml && docbook_table_output == BufferParams::TableOutput::CALSTable; + const bool is_xhtml_table = output_format == XmlOutputFormat::XHTML || + docbook_table_output == BufferParams::TableOutput::HTMLTable; + const bool is_cals_table = output_format == XmlOutputFormat::DOCBOOK && + docbook_table_output == BufferParams::TableOutput::CALSTable; std::string const row_tag = is_xhtml_table ? "tr" : "row"; std::string const cell_tag = is_xhtml_table ? (header ? "th" : "td") : "entry"; @@ -3754,25 +3787,24 @@ docstring Tabular::xmlRow(XMLStream & xs, const row_type row, OutputParams const if (isPartOfMultiColumn(row, c) || isPartOfMultiRow(row, c)) continue; - stringstream attr; - - if (is_xhtml_table) { - const std::vector styles = computeCssStylePerCell(row, c, cell); - attr << "style='" ; - for (auto it = styles.begin(); it != styles.end(); ++it) { - attr << *it; - if (it != styles.end() - 1) - attr << "; "; - } - attr << "' "; - } + stringstream attr; // Tag-level attributes, both for HTML and CALS. + stringstream style; // Tag-level CSS, only for HTML tables output in HTML. if (is_cals_table) { if (!cals_row_has_rowsep && bottomLine(cell)) attr << "rowsep='1' "; } - attr << getHAlignAsXmlAttribute(cell, false) << " " << getVAlignAsXmlAttribute(cell); + if (output_format == XmlOutputFormat::XHTML) { + // In HTML5, prefer to use CSS instead of attributes for alignment + // (align and valign). + style << getHAlignAsCssAttribute(cell) << "; " + << getVAlignAsCssAttribute(cell); + } else { + // In DocBook, both for HTML and CALS tables, stick to attributes. + attr << getHAlignAsXmlAttribute(cell) << " " + << getVAlignAsXmlAttribute(cell); + } if (is_xhtml_table) { if (isMultiColumn(cell)) @@ -3788,11 +3820,29 @@ docstring Tabular::xmlRow(XMLStream & xs, const row_type row, OutputParams const attr << " colname='c" << (c + 1) << "'"; // CALS column numbering starts at 1. } + // Final step: prepend the CSS style. + std::string attr_str = attr.str(); + if (is_xhtml_table) { + const std::vector styles = computeCssStylePerCell(row, c, cell); + + std::string attr_str_prefix = "style='" + style.str(); + if (!styles.empty()) + attr_str_prefix += "; "; + for (auto it = styles.begin(); it != styles.end(); ++it) { + attr_str_prefix += *it; + if (it != styles.end() - 1) + attr_str_prefix += "; "; + } + attr_str_prefix += "' "; + + attr_str.insert(0, attr_str_prefix); + } + // Render the cell as either XHTML or DocBook. - xs << xml::StartTag(cell_tag, attr.str(), true); - if (is_xhtml) { + xs << xml::StartTag(cell_tag, attr_str, true); + if (output_format == XmlOutputFormat::XHTML) { ret += cellInset(cell)->xhtml(xs, runparams); - } else { + } else if (output_format == XmlOutputFormat::DOCBOOK) { // DocBook: no return value for this function. OutputParams rp = runparams; rp.docbook_in_par = false; @@ -3809,7 +3859,7 @@ docstring Tabular::xmlRow(XMLStream & xs, const row_type row, OutputParams const } -void Tabular::xmlHeader(XMLStream & xs, OutputParams const & runparams, const bool is_xhtml) const +void Tabular::xmlHeader(XMLStream & xs, OutputParams const & runparams, const XmlOutputFormat output_format) const { // Output the header of the table. For both HTML and CALS, this is surrounded by a thead. bool const have_first_head = haveLTFirstHead(false); @@ -3824,7 +3874,7 @@ void Tabular::xmlHeader(XMLStream & xs, OutputParams const & runparams, const bo if (((have_first_head && row_info[r].endfirsthead) || (have_head && row_info[r].endhead)) && !row_info[r].caption) { - xmlRow(xs, r, runparams, true, is_xhtml, buffer().params().docbook_table_output); + xmlRow(xs, r, runparams, true, output_format, buffer().params().docbook_table_output); } } xs << xml::EndTag("thead"); @@ -3833,7 +3883,7 @@ void Tabular::xmlHeader(XMLStream & xs, OutputParams const & runparams, const bo } -void Tabular::xmlFooter(XMLStream & xs, OutputParams const & runparams, const bool is_xhtml) const +void Tabular::xmlFooter(XMLStream & xs, OutputParams const & runparams, const XmlOutputFormat output_format) const { // 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). @@ -3846,7 +3896,7 @@ void Tabular::xmlFooter(XMLStream & xs, OutputParams const & runparams, const bo if (((have_last_foot && row_info[r].endlastfoot) || (have_foot && row_info[r].endfoot)) && !row_info[r].caption) { - xmlRow(xs, r, runparams, false, is_xhtml, buffer().params().docbook_table_output); + xmlRow(xs, r, runparams, false, output_format, buffer().params().docbook_table_output); } } xs << xml::EndTag("tfoot"); @@ -3855,7 +3905,7 @@ void Tabular::xmlFooter(XMLStream & xs, OutputParams const & runparams, const bo } -void Tabular::xmlBody(XMLStream & xs, OutputParams const & runparams, const bool is_xhtml) const +void Tabular::xmlBody(XMLStream & xs, OutputParams const & runparams, const XmlOutputFormat output_format) const { // 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. @@ -3863,7 +3913,7 @@ void Tabular::xmlBody(XMLStream & xs, OutputParams const & runparams, const bool xs << xml::CR(); for (row_type r = 0; r < nrows(); ++r) if (isValidRow(r)) - xmlRow(xs, r, runparams, false, is_xhtml, buffer().params().docbook_table_output); + xmlRow(xs, r, runparams, false, output_format, buffer().params().docbook_table_output); xs << xml::EndTag("tbody"); xs << xml::CR(); } @@ -3886,7 +3936,7 @@ void Tabular::docbook(XMLStream & xs, OutputParams const & runparams) const xs << xml::StartTag(caption_tag); for (row_type r = 0; r < nrows(); ++r) if (row_info[r].caption) - xmlRow(xs, r, runparams, false, false, buffer().params().docbook_table_output); + xmlRow(xs, r, runparams, false, XmlOutputFormat::DOCBOOK, buffer().params().docbook_table_output); xs << xml::EndTag(caption_tag); xs << xml::CR(); } @@ -3908,9 +3958,9 @@ void Tabular::docbook(XMLStream & xs, OutputParams const & runparams) const } } - xmlHeader(xs, runparams, false); - xmlFooter(xs, runparams, false); - xmlBody(xs, runparams, false); + xmlHeader(xs, runparams, XmlOutputFormat::DOCBOOK); + xmlFooter(xs, runparams, XmlOutputFormat::DOCBOOK); + xmlBody(xs, runparams, XmlOutputFormat::DOCBOOK); // If this method started the table tag, also make it close it. if (!runparams.docbook_in_table) { @@ -3947,7 +3997,7 @@ docstring Tabular::xhtml(XMLStream & xs, OutputParams const & runparams) const xs << xml::CR(); for (row_type r = 0; r < nrows(); ++r) if (row_info[r].caption) - ret += xmlRow(xs, r, runparams, false, true); + ret += xmlRow(xs, r, runparams, false, XmlOutputFormat::XHTML); xs << xml::EndTag("div"); xs << xml::CR(); } @@ -3956,9 +4006,9 @@ docstring Tabular::xhtml(XMLStream & xs, OutputParams const & runparams) const xs << xml::StartTag("table"); xs << xml::CR(); - xmlHeader(xs, runparams, true); - xmlFooter(xs, runparams, true); - xmlBody(xs, runparams, true); + xmlHeader(xs, runparams, XmlOutputFormat::XHTML); + xmlFooter(xs, runparams, XmlOutputFormat::XHTML); + xmlBody(xs, runparams, XmlOutputFormat::XHTML); xs << xml::EndTag("table"); xs << xml::CR(); @@ -4271,6 +4321,21 @@ Tabular::BoxType Tabular::useBox(idx_type cell) const } +bool Tabular::hasNewlines(idx_type cell) const +{ + ParagraphList const & parlist = cellInset(cell)->paragraphs(); + ParagraphList::const_iterator cit = parlist.begin(); + ParagraphList::const_iterator end = parlist.end(); + + for (; cit != end; ++cit) + for (int i = 0; i < cit->size(); ++i) + if (cit->isNewline(i)) + return true; + + return false; +} + + ///////////////////////////////////////////////////////////////////// // // InsetTableCell @@ -7451,10 +7516,15 @@ docstring InsetTabular::asString(idx_type stidx, idx_type enidx, { LASSERT(stidx <= enidx, return docstring()); docstring retval; - col_type const col1 = tabular.cellColumn(stidx); - col_type const col2 = tabular.cellColumn(enidx); - row_type const row1 = tabular.cellRow(stidx); - row_type const row2 = tabular.cellRow(enidx); + col_type col1 = tabular.cellColumn(stidx); + col_type col2 = tabular.cellColumn(enidx); + row_type row1 = tabular.cellRow(stidx); + row_type row2 = tabular.cellRow(enidx); + // stidx might be in a later column or row than enidx + if (col1 > col2) + swap(col1, col2); + if (row1 > row2) + swap(row1, row2); bool first = true; for (col_type col = col1; col <= col2; col++) for (row_type row = row1; row <= row2; row++) { @@ -7472,10 +7542,15 @@ ParagraphList InsetTabular::asParList(idx_type stidx, idx_type enidx) { LASSERT(stidx <= enidx, return ParagraphList()); ParagraphList retval; - col_type const col1 = tabular.cellColumn(stidx); - col_type const col2 = tabular.cellColumn(enidx); - row_type const row1 = tabular.cellRow(stidx); - row_type const row2 = tabular.cellRow(enidx); + col_type col1 = tabular.cellColumn(stidx); + col_type col2 = tabular.cellColumn(enidx); + row_type row1 = tabular.cellRow(stidx); + row_type row2 = tabular.cellRow(enidx); + // stidx might be in a later column or row than enidx + if (col1 > col2) + swap(col1, col2); + if (row1 > row2) + swap(row1, row2); for (col_type col = col1; col <= col2; col++) for (row_type row = row1; row <= row2; row++) for (auto const & par : tabular.cellInset(row, col)->paragraphs()) @@ -7746,12 +7821,12 @@ docstring InsetTabular::completionPrefix(Cursor const & cur) const } -bool InsetTabular::insertCompletion(Cursor & cur, docstring const & s, bool finished) +bool InsetTabular::insertCompletion(Cursor & cur, docstring const & s, bool /*finished*/) { if (!completionSupported(cur)) return false; - return cur.text()->insertCompletion(cur, s, finished); + return cur.text()->insertCompletion(cur, s); }