namespace {
int const ADD_TO_HEIGHT = 2; // in cell
-int const ADD_TO_TABULAR_WIDTH = 6; // horiz space before and after the table
+int const ADD_TO_TABULAR_WIDTH = 6; // horizontal space before and after the table
int const default_line_space = 10; // ?
int const WIDTH_OF_LINE = 5; // space between double lines
{ Tabular::LONGTABULAR_ALIGN_CENTER, "longtabular-align-center", false },
{ Tabular::LONGTABULAR_ALIGN_RIGHT, "longtabular-align-right", false },
{ Tabular::SET_DECIMAL_POINT, "set-decimal-point", true },
+ { Tabular::SET_TABULAR_WIDTH, "set-tabular-width", true },
{ Tabular::LAST_ACTION, "", false }
};
}
-InsetTableCell splitCell(InsetTableCell & head, docstring const align_d, bool & hassep)
+DocIterator separatorPos(InsetTableCell * cell, docstring const & align_d)
{
- InsetTableCell tail = InsetTableCell(head);
- tail.getText(0)->setMacrocontextPosition(
- head.getText(0)->macrocontextPosition());
- tail.setBuffer(head.buffer());
-
- DocIterator dit = doc_iterator_begin(&head.buffer(), &head);
+ DocIterator dit = doc_iterator_begin(&(cell->buffer()), cell);
for (; dit; dit.forwardChar())
- if (dit.inTexted() && dit.depth()==1
+ if (dit.inTexted() && dit.depth() == 1
&& dit.paragraph().find(align_d, false, false, dit.pos()))
break;
- pit_type const psize = head.paragraphs().front().size();
+ return dit;
+}
+
+
+InsetTableCell splitCell(InsetTableCell & head, docstring const align_d, bool & hassep)
+{
+ InsetTableCell tail = InsetTableCell(head);
+ DocIterator const dit = separatorPos(&head, align_d);
hassep = dit;
if (hassep) {
+ pit_type const psize = head.paragraphs().front().size();
head.paragraphs().front().eraseChars(dit.pos(), psize, false);
tail.paragraphs().front().eraseChars(0,
dit.pos() < psize ? dit.pos() + 1 : psize, false);
updateIndexes();
is_long_tabular = false;
tabular_valignment = LYX_VALIGN_MIDDLE;
+ tabular_width = Length();
longtabular_alignment = LYX_LONGTABULAR_ALIGN_CENTER;
rotate = false;
use_booktabs = false;
Tabular::idx_type Tabular::getFirstCellInRow(row_type row) const
{
col_type c = 0;
- while (cell_info[row][c].multirow == CELL_PART_OF_MULTIROW)
+ idx_type const numcells = numberOfCellsInRow(row);
+ // we check against numcells to make sure we do not crash if all the
+ // cells are multirow (bug #7535), but in that case our return value
+ // is really invalid, i.e., it is NOT the first cell in the row. but
+ // i do not know what to do here. (rgh)
+ while (c < numcells - 1
+ && cell_info[row][c].multirow == CELL_PART_OF_MULTIROW)
++c;
return cell_info[row][c].cellno;
}
Tabular::idx_type Tabular::getLastCellInRow(row_type row) const
{
col_type c = ncols() - 1;
- while (cell_info[row][c].multirow == CELL_PART_OF_MULTIROW
- || cell_info[row][c].multicolumn == CELL_PART_OF_MULTICOLUMN)
+ // of course we check against 0 so we don't crash. but we have the same
+ // problem as in the previous routine: if all the cells are part of a
+ // multirow or part of a multi column, then our return value is invalid.
+ while (c > 0
+ && (cell_info[row][c].multirow == CELL_PART_OF_MULTIROW
+ || cell_info[row][c].multicolumn == CELL_PART_OF_MULTICOLUMN))
--c;
return cell_info[row][c].cellno;
}
<< write_attribute("lastFootBottomDL", endlastfoot.bottomDL)
<< write_attribute("lastFootEmpty", endlastfoot.empty);
// longtables cannot be aligned vertically
- if (!is_long_tabular)
+ if (!is_long_tabular) {
os << write_attribute("tabularvalignment", tabular_valignment);
+ os << write_attribute("tabularwidth", tabular_width);
+ }
if (is_long_tabular)
os << write_attribute("longtabularalignment",
longtabular_alignment);
getTokenValue(line, "booktabs", use_booktabs);
getTokenValue(line, "islongtable", is_long_tabular);
getTokenValue(line, "tabularvalignment", tabular_valignment);
+ getTokenValue(line, "tabularwidth", tabular_width);
getTokenValue(line, "longtabularalignment", longtabular_alignment);
getTokenValue(line, "firstHeadTopDL", endfirsthead.topDL);
getTokenValue(line, "firstHeadBottomDL", endfirsthead.bottomDL);
}
-Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number)
+Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number,
+ bool const bottom_border)
{
idx_type const col = cellColumn(cell);
idx_type const row = cellRow(cell);
// cells: left
cs.alignment = LYX_ALIGN_LEFT;
- // set the bottom row of the last selected cell
- setBottomLine(cell, bottomLine(cell + (number - 1)*ncols()));
+ // set the bottom line of the last selected cell
+ setBottomLine(cell, bottom_border);
for (idx_type i = 1; i < number; ++i) {
CellData & cs1 = cell_info[row + i][col];
bool Tabular::haveLTHead() const
{
+ if (!is_long_tabular)
+ return false;
for (row_type i = 0; i < nrows(); ++i)
if (row_info[i].endhead)
return true;
bool Tabular::haveLTFirstHead() const
{
- if (endfirsthead.empty)
+ if (!is_long_tabular || endfirsthead.empty)
return false;
for (row_type r = 0; r < nrows(); ++r)
if (row_info[r].endfirsthead)
bool Tabular::haveLTFoot() const
{
+ if (!is_long_tabular)
+ return false;
for (row_type r = 0; r < nrows(); ++r)
if (row_info[r].endfoot)
return true;
bool Tabular::haveLTLastFoot() const
{
- if (endlastfoot.empty)
+ if (!is_long_tabular || endlastfoot.empty)
return false;
for (row_type r = 0; r < nrows(); ++r)
if (row_info[r].endlastfoot)
bool Tabular::haveLTCaption() const
{
+ if (!is_long_tabular)
+ return false;
for (row_type r = 0; r < nrows(); ++r)
if (row_info[r].caption)
return true;
}
-int Tabular::TeXTopHLine(odocstream & os, row_type row, string const lang) const
+void Tabular::TeXTopHLine(otexstream & os, row_type row, string const lang) const
{
// we only output complete row lines and the 1st row here, the rest
// is done in Tabular::TeXBottomHLine(...)
// multirow, no line must be drawn.
if (row != 0)
if (isMultiRow(cellIndex(row, c))
- && isMultiRow(cellIndex(row - 1, c)))
- topline[c] = false;
+ && cell_info[row][c].multirow != CELL_BEGIN_OF_MULTIROW)
+ topline[c] = false;
if (topline[c])
++nset;
}
// do nothing if empty first row, or incomplete row line after
if ((row == 0 && nset == 0) || (row > 0 && nset != ncols()))
- return 0;
+ return;
// only output complete row lines and the 1st row's clines
if (nset == ncols()) {
}
}
os << "\n";
- return 1;
}
-int Tabular::TeXBottomHLine(odocstream & os, row_type row, string const lang) const
+void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const lang) const
{
// we output bottomlines of row r and the toplines of row r+1
// if the latter do not span the whole tabular
for (col_type c = 0; c < ncols(); ++c) {
bottomline.push_back(bottomLine(cellIndex(row, c)));
topline.push_back(!lastrow && topLine(cellIndex(row + 1, c)));
- // If cell is part of a multirow and not the last or first cell of the
+ // If cell is part of a multirow and not the last cell of the
// multirow, no line must be drawn.
if (!lastrow)
if (isMultiRow(cellIndex(row, c))
- && isMultiRow(cellIndex(row + 1, c))) {
- bottomline[c] = false;
- topline[c] = false;
+ && isMultiRow(cellIndex(row + 1, c))
+ && cell_info[row + 1][c].multirow != CELL_BEGIN_OF_MULTIROW) {
+ bottomline[c] = false;
+ topline[c] = false;
}
nextrowset &= topline[c];
}
// do nothing if empty, OR incomplete row line with a topline in next row
if (nset == 0 || (nextrowset && nset != ncols()))
- return 0;
+ return;
if (nset == ncols()) {
if (use_booktabs)
}
}
os << "\n";
- return 1;
}
-int Tabular::TeXCellPreamble(odocstream & os, idx_type cell,
- bool & ismulticol, bool & ismultirow) const
+void Tabular::TeXCellPreamble(otexstream & os, idx_type cell,
+ bool & ismulticol, bool & ismultirow) const
{
- int ret = 0;
row_type const r = cellRow(cell);
if (is_long_tabular && row_info[r].caption)
- return ret;
+ return;
Tabular::VAlignment valign = getVAlignment(cell, !isMultiColumn(cell));
LyXAlignment align = getAlignment(cell, !isMultiColumn(cell));
|| (coldouble != celldouble);
// we center in multicol when no decimal point
- ismulticol |= ((column_info[c].alignment == LYX_ALIGN_DECIMAL)
- && (cellInfo(cell).decimal_width == 0));
+ if (column_info[c].alignment == LYX_ALIGN_DECIMAL) {
+ docstring const align_d = column_info[c].decimal_point;
+ DocIterator const dit = separatorPos(cellInset(cell).get(), align_d);
+ ismulticol |= !dit;
+ }
// up counter by 1 for each decimally aligned col since they use 2 latex cols
int latexcolspan = columnSpan(cell);
if (getRotateCell(cell)) {
os << "\\begin{sideways}\n";
- ++ret;
}
if (getUsebox(cell) == BOX_PARBOX) {
os << "\\parbox[";
}
os << "]{" << from_ascii(getPWidth(cell).asLatexString())
<< "}\n";
- ++ret;
}
- return ret;
}
-int Tabular::TeXCellPostamble(odocstream & os, idx_type cell,
- bool ismulticol, bool ismultirow) const
+void Tabular::TeXCellPostamble(otexstream & os, idx_type cell,
+ bool ismulticol, bool ismultirow) const
{
- int ret = 0;
row_type const r = cellRow(cell);
if (is_long_tabular && row_info[r].caption)
- return ret;
+ return;
// usual cells
if (getUsebox(cell) == BOX_PARBOX)
os << '}';
- else if (getUsebox(cell) == BOX_MINIPAGE) {
- os << "%\n\\end{minipage}";
- ret += 2;
- }
- if (getRotateCell(cell)) {
- os << "%\n\\end{sideways}";
- ++ret;
- }
+ else if (getUsebox(cell) == BOX_MINIPAGE)
+ os << breakln << "\\end{minipage}";
+ if (getRotateCell(cell))
+ os << breakln << "\\end{sideways}";
if (ismultirow)
os << '}';
if (ismulticol)
os << '}';
-
- return ret;
}
-int Tabular::TeXLongtableHeaderFooter(odocstream & os,
- OutputParams const & runparams) const
+void Tabular::TeXLongtableHeaderFooter(otexstream & os,
+ OutputParams const & runparams) const
{
if (!is_long_tabular)
- return 0;
+ return;
- int ret = 0;
// caption handling
// the caption must be output before the headers
if (haveLTCaption()) {
for (row_type r = 0; r < nrows(); ++r) {
- if (row_info[r].caption) {
- ret += TeXRow(os, r, runparams);
- }
+ if (row_info[r].caption)
+ TeXRow(os, r, runparams);
}
}
// output first header info
// first header must be output before the header, otherwise the
// correct caption placement becomes really weird
if (haveLTFirstHead()) {
- if (endfirsthead.topDL) {
+ if (endfirsthead.topDL)
os << "\\hline\n";
- ++ret;
- }
for (row_type r = 0; r < nrows(); ++r) {
- if (row_info[r].endfirsthead) {
- ret += TeXRow(os, r, runparams);
- }
+ if (row_info[r].endfirsthead)
+ TeXRow(os, r, runparams);
}
- if (endfirsthead.bottomDL) {
+ if (endfirsthead.bottomDL)
os << "\\hline\n";
- ++ret;
- }
os << "\\endfirsthead\n";
- ++ret;
}
// output header info
if (haveLTHead()) {
- if (endfirsthead.empty && !haveLTFirstHead()) {
+ if (endfirsthead.empty && !haveLTFirstHead())
os << "\\endfirsthead\n";
- ++ret;
- }
- if (endhead.topDL) {
+ if (endhead.topDL)
os << "\\hline\n";
- ++ret;
- }
for (row_type r = 0; r < nrows(); ++r) {
- if (row_info[r].endhead) {
- ret += TeXRow(os, r, runparams);
- }
+ if (row_info[r].endhead)
+ TeXRow(os, r, runparams);
}
- if (endhead.bottomDL) {
+ if (endhead.bottomDL)
os << "\\hline\n";
- ++ret;
- }
os << "\\endhead\n";
- ++ret;
}
// output footer info
if (haveLTFoot()) {
- if (endfoot.topDL) {
+ if (endfoot.topDL)
os << "\\hline\n";
- ++ret;
- }
for (row_type r = 0; r < nrows(); ++r) {
- if (row_info[r].endfoot) {
- ret += TeXRow(os, r, runparams);
- }
+ if (row_info[r].endfoot)
+ TeXRow(os, r, runparams);
}
- if (endfoot.bottomDL) {
+ if (endfoot.bottomDL)
os << "\\hline\n";
- ++ret;
- }
os << "\\endfoot\n";
- ++ret;
- if (endlastfoot.empty && !haveLTLastFoot()) {
+ if (endlastfoot.empty && !haveLTLastFoot())
os << "\\endlastfoot\n";
- ++ret;
- }
}
// output lastfooter info
if (haveLTLastFoot()) {
- if (endlastfoot.topDL) {
+ if (endlastfoot.topDL)
os << "\\hline\n";
- ++ret;
- }
for (row_type r = 0; r < nrows(); ++r) {
- if (row_info[r].endlastfoot) {
- ret += TeXRow(os, r, runparams);
- }
+ if (row_info[r].endlastfoot)
+ TeXRow(os, r, runparams);
}
- if (endlastfoot.bottomDL) {
+ if (endlastfoot.bottomDL)
os << "\\hline\n";
- ++ret;
- }
os << "\\endlastfoot\n";
- ++ret;
}
- return ret;
}
}
-int Tabular::TeXRow(odocstream & os, row_type row,
- OutputParams const & runparams) const
+void Tabular::TeXRow(otexstream & os, row_type row,
+ OutputParams const & runparams) const
{
idx_type cell = cellIndex(row, 0);
shared_ptr<InsetTableCell> inset = cellInset(cell);
string const lang = par.getParLanguage(buffer().params())->lang();
//output the top line
- int ret = TeXTopHLine(os, row, lang);
+ TeXTopHLine(os, row, lang);
if (row_info[row].top_space_default) {
if (use_booktabs)
os << "\\addlinespace\n";
else
os << "\\noalign{\\vskip\\doublerulesep}\n";
- ++ret;
} else if(!row_info[row].top_space.zero()) {
if (use_booktabs)
os << "\\addlinespace["
<< from_ascii(row_info[row].top_space.asLatexString())
<< "}\n";
}
- ++ret;
}
bool ismulticol = false;
bool ismultirow = false;
for (col_type c = 0; c < ncols(); ++c) {
if (isPartOfMultiColumn(row, c))
continue;
-
- if (isPartOfMultiRow(row, c) &&
- column_info[c].alignment != LYX_ALIGN_DECIMAL) {
- os << " & ";
+
+ cell = cellIndex(row, c);
+
+ if (isPartOfMultiRow(row, c)
+ && column_info[c].alignment != LYX_ALIGN_DECIMAL) {
+ if (cell != getLastCellInRow(row))
+ os << " & ";
continue;
}
- cell = cellIndex(row, c);
- ret += TeXCellPreamble(os, cell, ismulticol, ismultirow);
+ TeXCellPreamble(os, cell, ismulticol, ismultirow);
shared_ptr<InsetTableCell> inset = cellInset(cell);
Paragraph const & par = inset->paragraphs().front();
? OutputParams::PLAIN
: OutputParams::ALIGNED;
- if (getAlignment(cell) == LYX_ALIGN_DECIMAL
- && cellInfo(cell).decimal_width != 0) {
+ if (getAlignment(cell) == LYX_ALIGN_DECIMAL) {
// copy cell and split in 2
InsetTableCell head = InsetTableCell(*cellInset(cell).get());
- head.getText(0)->setMacrocontextPosition(
- cellInset(cell)->getText(0)->macrocontextPosition());
head.setBuffer(buffer());
+ DocIterator dit = cellInset(cell)->getText(0)->macrocontextPosition();
+ dit.pop_back();
+ dit.push_back(CursorSlice(head));
+ head.setMacrocontextPositionRecursive(dit);
bool hassep = false;
InsetTableCell tail = splitCell(head, column_info[c].decimal_point, hassep);
head.latex(os, newrp);
- os << '&';
- ret += tail.latex(os, newrp);
- } else if (!isPartOfMultiRow(row, c))
- ret += inset->latex(os, newrp);
+ if (hassep) {
+ os << '&';
+ tail.setBuffer(head.buffer());
+ dit.pop_back();
+ dit.push_back(CursorSlice(tail));
+ tail.setMacrocontextPositionRecursive(dit);
+ tail.latex(os, newrp);
+ }
+ } else if (!isPartOfMultiRow(row, c)) {
+ if (!runparams.nice)
+ os.texrow().start(par.id(), 0);
+ inset->latex(os, newrp);
+ }
runparams.encoding = newrp.encoding;
if (rtl)
os << '}';
- ret += TeXCellPostamble(os, cell, ismulticol, ismultirow);
+ TeXCellPostamble(os, cell, ismulticol, ismultirow);
if (cell != getLastCellInRow(row)) { // not last cell in row
- os << " & ";
+ if (runparams.nice)
+ os << " & ";
+ else
+ os << " &\n";
}
}
if (row_info[row].caption && !endfirsthead.empty && !haveLTFirstHead())
<< ']';
}
os << '\n';
- ++ret;
//output the bottom line
- ret += TeXBottomHLine(os, row, lang);
+ TeXBottomHLine(os, row, lang);
if (row_info[row].interline_space_default) {
if (use_booktabs)
os << "\\addlinespace\n";
else
os << "\\noalign{\\vskip\\doublerulesep}\n";
- ++ret;
} else if (!row_info[row].interline_space.zero()) {
if (use_booktabs)
os << "\\addlinespace["
os << "\\noalign{\\vskip"
<< from_ascii(row_info[row].interline_space.asLatexString())
<< "}\n";
- ++ret;
}
- return ret;
}
-int Tabular::latex(odocstream & os, OutputParams const & runparams) const
+void Tabular::latex(otexstream & os, OutputParams const & runparams) const
{
- int ret = 0;
+ bool const is_tabular_star = !tabular_width.zero();
//+---------------------------------------------------------------------
//+ first the opening preamble +
//+---------------------------------------------------------------------
- if (rotate) {
+ os << safebreakln;
+ if (runparams.lastid != -1)
+ os.texrow().start(runparams.lastid, runparams.lastpos);
+
+ if (rotate)
os << "\\begin{sideways}\n";
- ++ret;
- }
+
if (is_long_tabular) {
os << "\\begin{longtable}";
switch (longtabular_alignment) {
break;
}
} else {
- os << "\\begin{tabular}";
+ if (is_tabular_star)
+ os << "\\begin{tabular*}{" << from_ascii(tabular_width.asLatexString()) << "}";
+ else
+ os << "\\begin{tabular}";
switch (tabular_valignment) {
case LYX_VALIGN_TOP:
os << "[t]";
os << "{";
+ if (is_tabular_star)
+ os << "@{\\extracolsep{\\fill}}";
+
for (col_type c = 0; c < ncols(); ++c) {
if (columnLeftLine(c))
os << '|';
os << '|';
}
os << "}\n";
- ++ret;
- ret += TeXLongtableHeaderFooter(os, runparams);
+ TeXLongtableHeaderFooter(os, runparams);
//+---------------------------------------------------------------------
//+ the single row and columns (cells) +
for (row_type r = 0; r < nrows(); ++r) {
if (isValidRow(r)) {
- ret += TeXRow(os, r, runparams);
- if (is_long_tabular && row_info[r].newpage) {
+ TeXRow(os, r, runparams);
+ if (is_long_tabular && row_info[r].newpage)
os << "\\newpage\n";
- ++ret;
- }
}
}
if (is_long_tabular)
os << "\\end{longtable}";
- else
- os << "\\end{tabular}";
- if (rotate) {
- os << "\n\\end{sideways}";
- ++ret;
+ else {
+ if (is_tabular_star)
+ os << "\\end{tabular*}";
+ else
+ os << "\\end{tabular}";
}
- return ret;
+ if (rotate)
+ os << breakln << "\\end{sideways}";
}
docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row,
- OutputParams const & runparams) const
+ OutputParams const & runparams, bool header) const
{
docstring ret;
+ string const celltag = header ? "th" : "td";
idx_type cell = getFirstCellInRow(row);
xs << html::StartTag("tr");
for (col_type c = 0; c < ncols(); ++c) {
- if (isPartOfMultiColumn(row, c))
+ if (isPartOfMultiColumn(row, c) || isPartOfMultiRow(row, c))
continue;
stringstream attr;
if (isMultiColumn(cell))
attr << " colspan='" << columnSpan(cell) << "'";
+ else if (isMultiRow(cell))
+ attr << " rowspan='" << rowSpan(cell) << "'";
- xs << html::StartTag("td", attr.str());
+ xs << html::StartTag(celltag, attr.str()) << html::CR();
ret += cellInset(cell)->xhtml(xs, runparams);
- xs << html::EndTag("td");
+ xs << html::EndTag(celltag) << html::CR();
++cell;
}
xs << html::EndTag("tr");
docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const
{
docstring ret;
- // It's unclear to me if we need to mess with the long table stuff.
- // We can borrow that too from docbook, if so.
- xs << html::StartTag("tbody");
+ if (is_long_tabular) {
+ // we'll wrap it in a div, so as to deal with alignment
+ string align;
+ switch (longtabular_alignment) {
+ case LYX_LONGTABULAR_ALIGN_LEFT:
+ align = "left";
+ break;
+ case LYX_LONGTABULAR_ALIGN_CENTER:
+ align = "center";
+ break;
+ case LYX_LONGTABULAR_ALIGN_RIGHT:
+ align = "right";
+ break;
+ }
+ xs << html::StartTag("div", "class='longtable' style='text-align: " + align + ";'")
+ << html::CR();
+ if (haveLTCaption()) {
+ xs << html::StartTag("div", "class='longtable-caption' style='text-align: " + align + ";'")
+ << html::CR();
+ for (row_type r = 0; r < nrows(); ++r)
+ if (row_info[r].caption)
+ ret += xhtmlRow(xs, r, runparams);
+ xs << html::EndTag("div") << html::CR();
+ }
+ }
+
+ xs << html::StartTag("table") << html::CR();
+
+ // output header info
+ bool const havefirsthead = haveLTFirstHead();
+ // 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.
+ bool const havehead = !havefirsthead && haveLTHead();
+ if (havehead || havefirsthead) {
+ xs << html::StartTag("thead") << html::CR();
+ for (row_type r = 0; r < nrows(); ++r) {
+ if ((havefirsthead && row_info[r].endfirsthead)
+ || (havehead && row_info[r].endhead)) {
+ ret += xhtmlRow(xs, r, runparams, true);
+ }
+ }
+ xs << html::EndTag("thead") << html::CR();
+ }
+ // output footer info
+ bool const havelastfoot = haveLTLastFoot();
+ // as before.
+ bool const havefoot = !havelastfoot && haveLTFoot();
+ if (havefoot || havelastfoot) {
+ xs << html::StartTag("tfoot") << html::CR();
+ for (row_type r = 0; r < nrows(); ++r) {
+ if ((havelastfoot && row_info[r].endlastfoot)
+ || (havefoot && row_info[r].endfoot)) {
+ ret += xhtmlRow(xs, r, runparams);
+ }
+ }
+ xs << html::EndTag("tfoot") << html::CR();
+ }
+
+ xs << html::StartTag("tbody") << html::CR();
for (row_type r = 0; r < nrows(); ++r) {
if (isValidRow(r)) {
ret += xhtmlRow(xs, r, runparams);
}
}
- xs << html::EndTag("tbody");
+ xs << html::EndTag("tbody")
+ << html::CR()
+ << html::EndTag("table")
+ << html::CR();
+ if (is_long_tabular)
+ xs << html::EndTag("div") << html::CR();
return ret;
}
if (!onlydata && plaintextTopHLine(os, r, clen))
os << docstring(depth * 2, ' ');
for (col_type c = 0; c < ncols(); ++c) {
- if (isPartOfMultiColumn(r, c))
+ if (isPartOfMultiColumn(r, c) || isPartOfMultiRow(r,c))
continue;
if (onlydata && c > 0)
// we don't use operator<< for single UCS4 character.
bool InsetTableCell::getStatus(Cursor & cur, FuncRequest const & cmd,
FuncStatus & status) const
{
- bool enabled;
+ bool enabled = true;
switch (cmd.action()) {
case LFUN_LAYOUT:
enabled = !forcePlainLayout();
case LFUN_LAYOUT_PARAGRAPH:
enabled = allowParagraphCustomization();
break;
+
+ case LFUN_MATH_DISPLAY:
+ if (!hasFixedWidth()) {
+ enabled = false;
+ break;
+ } //fall-through
default:
return InsetText::getStatus(cur, cmd, status);
}
docstring InsetTabular::contextMenu(BufferView const &, int, int) const
{
- // FIXME: depending on the selection state, we could offer a different menu.
+ // FIXME: depending on the selection state,
+ // we could offer a different menu.
+ return cell(0)->contextMenuName() + ";" + contextMenuName();
+}
+
+
+docstring InsetTabular::contextMenuName() const
+{
return from_ascii("context-tabular");
}
int InsetTabular::rowFromY(Cursor & cur, int y) const
{
// top y coordinate of tabular
- int h = yo(cur.bv()) - tabular.rowAscent(0);
+ int h = yo(cur.bv()) - tabular.rowAscent(0) + offset_valign_;
row_type r = 0;
for (; r < tabular.nrows() && y > h; ++r)
h += tabular.rowAscent(r) + tabular.rowDescent(r)
- + tabular.interRowSpace(r);
+ + tabular.interRowSpace(r);
return r - 1;
}
TextMetrics const & tm =
mi.base.bv->textMetrics(tabular.cellInset(cell)->getText(0));
- // determine horiz offset because of decimal align (if necessary)
- int decimal_hoffset = 0;
+ // determine horizontal offset because of decimal align (if necessary)
int decimal_width = 0;
if (tabular.getAlignment(cell) == LYX_ALIGN_DECIMAL) {
- // make a copy which we will split in 2
- InsetTableCell head = InsetTableCell(*tabular.cellInset(cell).get());
- head.getText(0)->setMacrocontextPosition(
- tabular.cellInset(cell)->getText(0)->macrocontextPosition());
- head.setBuffer(tabular.buffer());
- // split in 2 and calculate width of each part
- bool hassep = false;
- InsetTableCell tail =
- splitCell(head, tabular.column_info[c].decimal_point, hassep);
- Dimension dim1;
- head.metrics(m, dim1);
- decimal_hoffset = dim1.width();
- if (hassep) {
+ InsetTableCell tail = InsetTableCell(*tabular.cellInset(cell).get());
+ tail.setBuffer(tabular.buffer());
+ // we need to set macrocontext position everywhere
+ // otherwise we crash with nested insets (e.g. footnotes)
+ // after decimal point
+ DocIterator dit = tabular.cellInset(cell)->getText(0)->macrocontextPosition();
+ dit.pop_back();
+ dit.push_back(CursorSlice(tail));
+ tail.setMacrocontextPositionRecursive(dit);
+
+ // remove text leading decimal point
+ docstring const align_d = tabular.column_info[c].decimal_point;
+ dit = separatorPos(&tail, align_d);
+
+ pit_type const psize = tail.paragraphs().front().size();
+ if (dit) {
+ tail.paragraphs().front().eraseChars(0,
+ dit.pos() < psize ? dit.pos() + 1 : psize, false);
+ Dimension dim1;
tail.metrics(m, dim1);
decimal_width = dim1.width();
}
}
- tabular.cell_info[r][c].decimal_hoffset = decimal_hoffset;
+ tabular.cell_info[r][c].decimal_hoffset = tm.width() - decimal_width;
tabular.cell_info[r][c].decimal_width = decimal_width;
// with LYX_VALIGN_BOTTOM the descent is relative to the last par
tabular.row_info[r].bottom_space.inPixels(mi.base.textwidth);
tabular.setRowDescent(r, maxdes + ADD_TO_HEIGHT + bottom_space);
}
+
+ // for top-alignment the first horizontal table line must be exactly at
+ // the position of the base line of the surrounding text line
+ // for bottom alignment, the same is for the last table line
+ switch (tabular.tabular_valignment) {
+ case Tabular::LYX_VALIGN_BOTTOM:
+ offset_valign_ = tabular.rowAscent(0) - tabular.height();
+ break;
+ case Tabular::LYX_VALIGN_MIDDLE:
+ offset_valign_ = (- tabular.height()) / 2 + tabular.rowAscent(0);
+ break;
+ case Tabular::LYX_VALIGN_TOP:
+ offset_valign_ = tabular.rowAscent(0);
+ break;
+ }
+
tabular.updateColumnWidths();
- dim.asc = tabular.rowAscent(0);
+ dim.asc = tabular.rowAscent(0) - offset_valign_;
dim.des = tabular.height() - dim.asc;
dim.wid = tabular.width() + 2 * ADD_TO_TABULAR_WIDTH;
}
idx_type idx = 0;
first_visible_cell = Tabular::npos;
+
+ int yy = y + offset_valign_;
for (row_type r = 0; r < tabular.nrows(); ++r) {
int nx = x;
for (col_type c = 0; c < tabular.ncols(); ++c) {
pi.selected |= isCellSelected(cur, r, c);
int const cx = nx + tabular.textHOffset(idx);
- int const cy = y + tabular.textVOffset(idx);
+ int const cy = yy + tabular.textVOffset(idx);
// Cache the Inset position.
bv->coordCache().insets().add(cell(idx).get(), cx, cy);
cell(idx)->draw(pi, cx, cy);
- drawCellLines(pi, nx, y, r, idx);
+ drawCellLines(pi, nx, yy, r, idx);
nx += tabular.cellWidth(idx);
pi.selected = original_selection_state;
}
if (r + 1 < tabular.nrows())
- y += tabular.rowDescent(r) + tabular.rowAscent(r + 1)
+ yy += tabular.rowDescent(r) + tabular.rowAscent(r + 1)
+ tabular.interRowSpace(r + 1);
}
}
void InsetTabular::drawBackground(PainterInfo & pi, int x, int y) const
{
x += scx_ + ADD_TO_TABULAR_WIDTH;
- y -= tabular.rowAscent(0);
+ y += offset_valign_ - tabular.rowAscent(0);
pi.pain.fillRectangle(x, y, tabular.width(), tabular.height(),
pi.backgroundColor(this));
}
}
int const w = tabular.cellWidth(cell);
int const h = tabular.cellHeight(cell);
- int const yy = y - tabular.rowAscent(r);
+ int const yy = y - tabular.rowAscent(r) + offset_valign_;
if (isCellSelected(cur, r, c))
pi.pain.fillRectangle(xx, yy, w, h, Color_selection);
xx += w;
}
-void InsetTabular::addToToc(DocIterator const & cpit)
+void InsetTabular::addToToc(DocIterator const & cpit) const
{
DocIterator dit = cpit;
dit.forwardPos();
break;
}
// select column
- int const y0 = yo(cur.bv()) - tabular.rowAscent(0);
+ int const y0 = yo(cur.bv()) - tabular.rowAscent(0) + offset_valign_;
if (cmd.y() < y0 + ADD_TO_TABULAR_WIDTH
|| cmd.y() > y0 + tabular.height()) {
col_type c = columnFromX(cur, cmd.x());
cmd = FuncRequest(finish_lfun);
else
cur.dispatched();
+
+ cur.screenUpdateFlags(Update::Force | Update::FitCursor);
break;
}
// setting also the right targetX.
cur.selHandle(act == LFUN_DOWN_SELECT);
if (tabular.cellRow(cur.idx()) != tabular.nrows() - 1) {
+ int const xtarget = cur.targetX();
+ // WARNING: Once cur.idx() has been reset, the cursor is in
+ // an inconsistent state until pos() has been set. Be careful
+ // what you do with it!
cur.idx() = tabular.cellBelow(cur.idx());
cur.pit() = 0;
TextMetrics const & tm =
cur.bv().textMetrics(cell(cur.idx())->getText(0));
- cur.pos() = tm.x2pos(cur.pit(), 0, cur.targetX());
+ cur.pos() = tm.x2pos(cur.pit(), 0, xtarget);
cur.setCurrentFont();
}
}
cur.setCurrentFont();
return;
}
+ cur.screenUpdateFlags(Update::FitCursor);
break;
case LFUN_UP_SELECT:
// setting also the right targetX.
cur.selHandle(act == LFUN_UP_SELECT);
if (tabular.cellRow(cur.idx()) != 0) {
+ int const xtarget = cur.targetX();
+ // WARNING: Once cur.idx() has been reset, the cursor is in
+ // an inconsistent state until pos() has been set. Be careful
+ // what you do with it!
cur.idx() = tabular.cellAbove(cur.idx());
cur.pit() = cur.lastpit();
Text const * text = cell(cur.idx())->getText(0);
TextMetrics const & tm = cur.bv().textMetrics(text);
ParagraphMetrics const & pm =
tm.parMetrics(cur.lastpit());
- cur.pos() = tm.x2pos(cur.pit(), pm.rows().size()-1, cur.targetX());
+ cur.pos() = tm.x2pos(cur.pit(), pm.rows().size()-1, xtarget);
cur.setCurrentFont();
}
}
cur.setCurrentFont();
return;
}
+ cur.screenUpdateFlags(Update::FitCursor);
break;
// case LFUN_SCREEN_DOWN: {
cell(cur.idx())->dispatch(cur, cmd);
break;
}
- if (theClipboard().isInternal() ||
- (!theClipboard().hasInternal() && theClipboard().hasLyXContents())) {
+ if (theClipboard().isInternal()) {
cur.recordUndoInset(INSERT_UNDO);
pasteClipboard(cur);
}
if (&cur.inset() != this || cmd.getArg(0) != "tabular")
break;
- string const s = cmd.getArg(1);
// FIXME: We only check for the very first argument...
+ string const s = cmd.getArg(1);
+ // We always enable the lfun if it is coming from the dialog
+ // because the dialog makes sure all the settings are valid,
+ // even though the first argument might not be valid now.
+ if (s == "from-dialog") {
+ status.setEnabled(true);
+ return true;
+ }
+
int action = Tabular::LAST_ACTION;
int i = 0;
for (; tabularFeature[i].action != Tabular::LAST_ACTION; ++i) {
status.clear();
return true;
+ case Tabular::SET_TABULAR_WIDTH:
+ status.setEnabled(!tabular.rotate && !tabular.is_long_tabular
+ && tabular.tabular_valignment == Tabular::LYX_VALIGN_MIDDLE);
+ break;
+
case Tabular::SET_DECIMAL_POINT:
status.setEnabled(
tabular.getAlignment(cur.idx()) == LYX_ALIGN_DECIMAL);
case Tabular::TOGGLE_ROTATE_TABULAR:
case Tabular::SET_ROTATE_TABULAR:
+ status.setEnabled(tabular.tabular_width.zero());
status.setOnOff(tabular.rotate);
break;
case Tabular::TABULAR_VALIGN_TOP:
+ status.setEnabled(tabular.tabular_width.zero());
status.setOnOff(tabular.tabular_valignment
== Tabular::LYX_VALIGN_TOP);
break;
case Tabular::TABULAR_VALIGN_MIDDLE:
+ status.setEnabled(tabular.tabular_width.zero());
status.setOnOff(tabular.tabular_valignment
== Tabular::LYX_VALIGN_MIDDLE);
break;
case Tabular::TABULAR_VALIGN_BOTTOM:
+ status.setEnabled(tabular.tabular_width.zero());
status.setOnOff(tabular.tabular_valignment
== Tabular::LYX_VALIGN_BOTTOM);
break;
}
// disable in non-fixed-width cells
- case LFUN_NEWLINE_INSERT:
- case LFUN_BREAK_PARAGRAPH: {
+ case LFUN_BREAK_PARAGRAPH:
+ // multirow does not allow paragraph breaks
+ if (tabular.isMultiRow(cur.idx())) {
+ status.setEnabled(false);
+ return true;
+ }
+ case LFUN_NEWLINE_INSERT: {
if (tabular.getPWidth(cur.idx()).zero()) {
status.setEnabled(false);
return true;
}
-int InsetTabular::latex(odocstream & os, OutputParams const & runparams) const
+void InsetTabular::latex(otexstream & os, OutputParams const & runparams) const
{
- return tabular.latex(os, runparams);
+ tabular.latex(os, runparams);
}
docstring InsetTabular::xhtml(XHTMLStream & xs, OutputParams const & rp) const
{
- // FIXME XHTML
- // It'd be better to be able to get this from an InsetLayout, but at present
- // InsetLayouts do not seem really to work for things that aren't InsetTexts.
- xs << html::StartTag("table");
- docstring ret = tabular.xhtml(xs, rp);
- xs << html::EndTag("table");
- return ret;
+ return tabular.xhtml(xs, rp);
}
{
cell(sl.idx())->cursorPos(bv, sl, boundary, x, y);
- int const row = tabular.cellRow(sl.idx());
- int const col = tabular.cellColumn(sl.idx());
-
// y offset correction
- for (int r = 0; r < row; ++r)
- y += tabular.rowDescent(r) + tabular.rowAscent(r + 1)
- + tabular.interRowSpace(r + 1);
-
+ y += cellYPos(sl.idx());
y += tabular.textVOffset(sl.idx());
+ y += offset_valign_;
// x offset correction
- for (int c = 0; c < col; ++c)
- x += tabular.column_info[c].width;
-
+ x += cellXPos(sl.idx());
x += tabular.textHOffset(sl.idx());
x += ADD_TO_TABULAR_WIDTH;
x += scx_;
}
+int InsetTabular::cellYPos(idx_type const cell) const
+{
+ row_type row = tabular.cellRow(cell);
+ int ly = 0;
+ for (row_type r = 0; r < row; ++r)
+ ly += tabular.rowDescent(r) + tabular.rowAscent(r + 1)
+ + tabular.interRowSpace(r + 1);
+ return ly;
+}
+
+
int InsetTabular::cellXPos(idx_type const cell) const
{
col_type col = tabular.cellColumn(cell);
int lx = 0;
for (col_type c = 0; c < col; ++c)
lx += tabular.column_info[c].width;
-
return lx;
}
break;
}
- cur.recordUndoInset(ATOMIC_UNDO);
+ cur.recordUndoInset(ATOMIC_UNDO, this);
getSelection(cur, sel_row_start, sel_row_end, sel_col_start, sel_col_end);
row_type const row = tabular.cellRow(cur.idx());
switch (feature) {
+ case Tabular::SET_TABULAR_WIDTH:
+ tabular.setTabularWidth(Length(value));
+ break;
+
case Tabular::SET_PWIDTH: {
Length const len(value);
tabular.setColumnPWidth(cur, cur.idx(), len);
if (len.zero()
&& tabular.getAlignment(cur.idx(), true) == LYX_ALIGN_BLOCK)
tabularFeatures(cur, Tabular::ALIGN_CENTER, string());
- // check if there is a 1-column multicolumn cell
- // if so it must get the same width
- for (row_type r = 0; r < tabular.nrows(); ++r) {
- if (tabular.isMultiColumn(tabular.cellIndex(r, column))
- && tabular.columnSpan(tabular.cellIndex(r, column)) == 1)
- tabular.setMColumnPWidth(cur, tabular.cellIndex(r, column), len);
- }
break;
}
case Tabular::SET_MPWIDTH:
tabular.setMColumnPWidth(cur, cur.idx(), Length(value));
- // if the multicolumn only spans 1 column, the width of the whole column
- // must have the same width, see bug #7055
- if (tabular.columnSpan(cur.idx()) == 1)
- for (row_type r = 0; r < tabular.nrows(); ++r) {
- if (!tabular.isMultiColumn(tabular.cellIndex(r, column)))
- tabular.setColumnPWidth(cur, tabular.cellIndex(r, column), Length(value));
- else if (tabular.isMultiColumn(tabular.cellIndex(r, column))
- && tabular.columnSpan(tabular.cellIndex(r, column)) == 1)
- tabular.setMColumnPWidth(cur, tabular.cellIndex(r, column), Length(value));
- }
break;
case Tabular::SET_MROFFSET:
// just multirow for one single cell
// check whether we are completely in a multirow
if (!tabular.isMultiRow(cur.idx()))
- tabular.setMultiRow(cur.idx(), 1);
+ tabular.setMultiRow(cur.idx(), 1,
+ tabular.bottomLine(cur.idx()));
break;
}
// we have a selection so this means we just add all this
idx_type const s_start = cur.selBegin().idx();
row_type const row_start = tabular.cellRow(s_start);
row_type const row_end = tabular.cellRow(cur.selEnd().idx());
- cur.idx() = tabular.setMultiRow(s_start, row_end - row_start + 1);
+ cur.idx() = tabular.setMultiRow(s_start, row_end - row_start + 1,
+ tabular.bottomLine(cur.selEnd().idx()));
cur.pit() = 0;
cur.pos() = 0;
cur.setSelection(false);