<< "}\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:
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}";
bool rtl = par.isRTL(buffer().params())
&& !par.empty()
&& getPWidth(cell).zero()
- && !runparams.use_polyglossia;
+ && !runparams.isFullUnicode();
if (rtl) {
string const lang =
} 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);
}
}
-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;
}
-docstring Tabular::xmlRow(XMLStream & xs, row_type row, OutputParams const & runparams,
- bool header, bool is_xhtml, BufferParams::TableOutput docbook_table_output) const
+docstring Tabular::xmlRow(XMLStream & xs, const row_type row, OutputParams const & runparams,
+ 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";
if (isPartOfMultiColumn(row, c) || isPartOfMultiRow(row, c))
continue;
- stringstream attr;
-
- if (is_xhtml_table) {
- const std::vector<std::string> 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))
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<std::string> 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;
}
-void Tabular::xmlHeader(XMLStream & xs, OutputParams const & runparams) 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);
if (((have_first_head && row_info[r].endfirsthead) ||
(have_head && row_info[r].endhead)) &&
!row_info[r].caption) {
- xmlRow(xs, r, runparams, true, false, buffer().params().docbook_table_output);
+ xmlRow(xs, r, runparams, true, output_format, buffer().params().docbook_table_output);
}
}
xs << xml::EndTag("thead");
}
-void Tabular::xmlFooter(XMLStream & xs, OutputParams const & runparams) 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).
if (((have_last_foot && row_info[r].endlastfoot) ||
(have_foot && row_info[r].endfoot)) &&
!row_info[r].caption) {
- xmlRow(xs, r, runparams, false, false, buffer().params().docbook_table_output);
+ xmlRow(xs, r, runparams, false, output_format, buffer().params().docbook_table_output);
}
}
xs << xml::EndTag("tfoot");
}
-void Tabular::xmlBody(XMLStream & xs, OutputParams const & runparams) 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.
xs << xml::CR();
for (row_type r = 0; r < nrows(); ++r)
if (isValidRow(r))
- xmlRow(xs, r, runparams, false, false, buffer().params().docbook_table_output);
+ xmlRow(xs, r, runparams, false, output_format, buffer().params().docbook_table_output);
xs << xml::EndTag("tbody");
xs << xml::CR();
}
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();
}
}
}
- xmlHeader(xs, runparams);
- xmlFooter(xs, runparams);
- xmlBody(xs, runparams);
+ 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) {
docstring ret;
if (is_long_tabular) {
- // we'll wrap it in a div, so as to deal with alignment
+ // We'll wrap it in a div to deal with alignment.
string align;
switch (longtabular_alignment) {
case LYX_LONGTABULAR_ALIGN_LEFT:
}
xs << xml::StartTag("div", "class='longtable' style='text-align: " + align + ";'");
xs << xml::CR();
- // The caption flag wins over head/foot
+
+ // The caption flag is output before header/footer.
if (haveLTCaption()) {
xs << xml::StartTag("div", "class='longtable-caption' style='text-align: " + align + ";'");
xs << xml::CR();
for (row_type r = 0; r < nrows(); ++r)
if (row_info[r].caption)
- ret += xmlRow(xs, r, runparams);
+ ret += xmlRow(xs, r, runparams, false, XmlOutputFormat::XHTML);
xs << xml::EndTag("div");
xs << xml::CR();
}
xs << xml::StartTag("table");
xs << xml::CR();
- xmlHeader(xs, runparams);
- xmlFooter(xs, runparams);
- xmlBody(xs, runparams);
+ xmlHeader(xs, runparams, XmlOutputFormat::XHTML);
+ xmlFooter(xs, runparams, XmlOutputFormat::XHTML);
+ xmlBody(xs, runparams, XmlOutputFormat::XHTML);
xs << xml::EndTag("table");
xs << xml::CR();
}
+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
case LFUN_CHANGE_ACCEPT:
case LFUN_CHANGE_REJECT:
+ case LFUN_FONT_DEFAULT:
case LFUN_FONT_EMPH:
case LFUN_FONT_BOLD:
case LFUN_FONT_BOLDSYMBOL:
{
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++) {
{
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())
}
-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);
}