#include "InsetTabular.h"
+#include "Author.h"
#include "buffer_funcs.h"
#include "Buffer.h"
#include "BufferParams.h"
template <>
-string const write_attribute(string const & name, Tabular::idx_type const & i)
+string const write_attribute(string const & name, idx_type const & i)
{
// we write only true attribute values so we remove a bit of the
// file format bloat for tabulars.
{
InsetTableCell tail = InsetTableCell(head);
DocIterator const dit = separatorPos(&head, align_d);
- hassep = (bool)dit;
+ hassep = static_cast<bool>(dit);
if (hassep) {
pos_type const psize = head.paragraphs().front().size();
head.paragraphs().front().eraseChars(dit.pos(), psize, false);
}
-Tabular::idx_type Tabular::numberOfCellsInRow(row_type const row) const
+idx_type Tabular::numberOfCellsInRow(row_type const row) const
{
idx_type result = 0;
for (col_type c = 0; c < ncols(); ++c)
if (!tab_width.zero()) {
restwidth = mi.base.inPixels(tab_width);
// Subtract the fixed widths from the table width
- for (auto const w : max_pwidth)
+ for (auto const & w : max_pwidth)
restwidth -= w.second;
}
// Now consider that some variable width columns exceed the vcolwidth
if (vcolwidth > 0) {
bool changed = false;
- for (auto const w : max_width) {
+ for (auto const & w : max_width) {
if (tabularx || w.second > vcolwidth) {
--restcols;
restwidth -= w.second;
}
-Tabular::idx_type Tabular::getFirstCellInRow(row_type row, bool const ct) const
+idx_type Tabular::getFirstCellInRow(row_type row, bool const ct) const
{
col_type c = 0;
idx_type const numcells = numberOfCellsInRow(row);
}
-Tabular::idx_type Tabular::getLastCellInRow(row_type row, bool const ct) const
+idx_type Tabular::getLastCellInRow(row_type row, bool const ct) const
{
col_type c = ncols() - 1;
// of course we check against 0 so we don't crash. but we have the same
}
-Tabular::row_type Tabular::getFirstRow(bool const ct) const
+row_type Tabular::getFirstRow(bool const ct) const
{
row_type r = 0;
if (!ct)
}
-Tabular::row_type Tabular::getLastRow(bool const ct) const
+row_type Tabular::getLastRow(bool const ct) const
{
row_type r = nrows() - 1;
if (!ct)
}
-Tabular::row_type Tabular::cellRow(idx_type cell) const
+row_type Tabular::cellRow(idx_type cell) const
{
if (cell >= numberofcells)
return nrows() - 1;
}
-Tabular::col_type Tabular::cellColumn(idx_type cell) const
+col_type Tabular::cellColumn(idx_type cell) const
{
if (cell >= numberofcells)
return ncols() - 1;
}
-Tabular::idx_type Tabular::setMultiColumn(Cursor & cur, idx_type cell, idx_type number,
+idx_type Tabular::setMultiColumn(Cursor & cur, idx_type cell, idx_type number,
bool const right_border)
{
idx_type const col = cellColumn(cell);
return false;
}
-Tabular::idx_type Tabular::setMultiRow(Cursor & cur, idx_type cell, idx_type number,
+idx_type Tabular::setMultiRow(Cursor & cur, idx_type cell, idx_type number,
bool const bottom_border,
LyXAlignment const halign)
{
}
-Tabular::idx_type Tabular::columnSpan(idx_type cell) const
+idx_type Tabular::columnSpan(idx_type cell) const
{
row_type const row = cellRow(cell);
col_type const col = cellColumn(cell);
}
-Tabular::idx_type Tabular::rowSpan(idx_type cell) const
+idx_type Tabular::rowSpan(idx_type cell) const
{
col_type const column = cellColumn(cell);
col_type row = cellRow(cell) + 1;
bool Tabular::isLastCell(idx_type cell) const
{
- if (cell + 1 < numberofcells)
- return false;
- return true;
+ return cell + 1 >= numberofcells;
}
-Tabular::idx_type Tabular::cellAbove(idx_type cell) const
+idx_type Tabular::cellAbove(idx_type cell) const
{
if (cellRow(cell) == 0)
return cell;
}
-Tabular::idx_type Tabular::cellBelow(idx_type cell) const
+idx_type Tabular::cellBelow(idx_type cell) const
{
row_type const nextrow = cellRow(cell) + rowSpan(cell);
if (nextrow < nrows())
}
-Tabular::idx_type Tabular::cellIndex(row_type row, col_type column) const
+idx_type Tabular::cellIndex(row_type row, col_type column) const
{
LASSERT(column != npos && column < ncols(), column = 0);
LASSERT(row != npos && row < nrows(), row = 0);
}
-Tabular::idx_type Tabular::setLTCaption(Cursor & cur, row_type row, bool what)
+idx_type Tabular::setLTCaption(Cursor & cur, row_type row, bool what)
{
idx_type i = getFirstCellInRow(row);
if (what) {
} else if (ltCaption(row)) {
// Inside longtable caption rows, we must only output the caption inset
// with its content and omit anything outside of that (see #10791)
- InsetIterator it = inset_iterator_begin(*const_cast<InsetTableCell *>(inset));
- InsetIterator i_end = inset_iterator_end(*const_cast<InsetTableCell *>(inset));
- for (; it != i_end; ++it) {
- if (it->lyxCode() != CAPTION_CODE)
+ InsetTableCell & tc_inset = *const_cast<InsetTableCell *>(inset);
+ for (Inset const & it : tc_inset) {
+ if (it.lyxCode() != CAPTION_CODE)
continue;
- it->latex(os, runparams);
+ it.latex(os, runparams);
break;
}
} else if (!isPartOfMultiRow(row, c)) {
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);
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;
++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();
}
docstring ret;
// Some tables are inline. Likely limitation: cannot output a table within a table; is that really a limitation?
- bool hasTableStarted = xs.isTagOpen(xml::StartTag("informaltable")) || xs.isTagOpen(xml::StartTag("table"));
- if (!hasTableStarted) {
+ if (!runparams.docbook_in_table) { // Check on the *outer* set of parameters, so that the table can be closed
+ // properly at the end of this function.
xs << xml::StartTag("informaltable");
xs << xml::CR();
}
- // "Formal" tables have a caption and use the tag <table>; the distinction with <informaltable> is done outside.
+ // "Formal" tables have a title and use the tag <table>; the distinction with <informaltable> 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);
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)
xs << xml::EndTag("tbody");
xs << xml::CR();
- if (!hasTableStarted) {
+ // If this method started the table tag, also make it close it.
+ if (!runparams.docbook_in_table) {
xs << xml::EndTag("informaltable");
xs << xml::CR();
}
isMultiColumn(false), isMultiRow(false), contentAlign(LYX_ALIGN_CENTER)
{}
-
bool InsetTableCell::forcePlainLayout(idx_type) const
{
return isMultiRow || (isMultiColumn && !isFixedWidth);
void InsetTableCell::docbook(XMLStream & xs, OutputParams const & runparams) const
{
- InsetText::docbook(xs, runparams);
+ InsetText::docbook(xs, runparams);
}
}
+bool InsetTabular::allowMultiPar() const
+{
+ for (col_type c = 0; c < tabular.ncols(); ++c) {
+ for (row_type r = 0; r < tabular.nrows(); ++r) {
+ if (tabular.cellInset(r,c)->allowMultiPar())
+ return true;
+ }
+ }
+ return false;
+}
+
+
bool InsetTabular::allowsCaptionVariation(std::string const & newtype) const
{
return tabular.is_long_tabular &&
case Tabular::SET_LONGTABULAR:
case Tabular::TOGGLE_LONGTABULAR:
// setting as longtable is not allowed when table is inside a float
- if (cur.innerInsetOfType(FLOAT_CODE) != 0
- || cur.innerInsetOfType(WRAP_CODE) != 0)
+ if (cur.innerInsetOfType(FLOAT_CODE) != nullptr
+ || cur.innerInsetOfType(WRAP_CODE) != nullptr)
status.setEnabled(false);
else
status.setEnabled(true);
}
-InsetTabular::idx_type InsetTabular::getNearestCell(BufferView & bv, int x, int y) const
+idx_type InsetTabular::getNearestCell(BufferView & bv, int x, int y) const
{
idx_type idx_min = 0;
int dist_min = numeric_limits<int>::max();
paste_tabular->setBuffer(tabular.buffer());
odocstringstream os;
- OutputParams const runparams(0);
+ OutputParams const runparams(nullptr);
paste_tabular->plaintext(os, runparams, 0, true, '\t', INT_MAX);
// Needed for the "Edit->Paste recent" menu and the system clipboard.
cap::copySelection(cur, os.str());
row_type const row2 = tabular.cellRow(enidx);
for (col_type col = col1; col <= col2; col++)
for (row_type row = row1; row <= row2; row++)
- for (auto par : tabular.cellInset(row, col)->paragraphs())
+ for (auto const & par : tabular.cellInset(row, col)->paragraphs())
retval.push_back(par);
return retval;
}
Text * InsetTabular::getText(int idx) const
{
- return size_t(idx) < nargs() ? cell(idx)->getText(0) : 0;
+ return size_t(idx) < nargs() ? cell(idx)->getText(0) : nullptr;
}
CompletionList const * InsetTabular::createCompletionList(Cursor const & cur) const
{
- return completionSupported(cur) ? cur.text()->createCompletionList(cur) : 0;
+ return completionSupported(cur) ? cur.text()->createCompletionList(cur) : nullptr;
}
void InsetTabular::setLayoutForHiddenCells(DocumentClass const & dc)
{
- for (Tabular::col_type c = 0; c < tabular.ncols(); ++c) {
- for (Tabular::row_type r = 0; r < tabular.nrows(); ++r) {
+ for (col_type c = 0; c < tabular.ncols(); ++c) {
+ for (row_type r = 0; r < tabular.nrows(); ++r) {
if (!tabular.isPartOfMultiColumn(r,c) &&
!tabular.isPartOfMultiRow(r,c))
continue;