X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetTabular.cpp;h=324987c8a445e6474f0b61d8a370b5e59e3c4e15;hb=d6a93143ec2146210d79f58cac42f9608da86100;hp=6d8f7d0737138f45d5a1b6183e0290c2f96b66d9;hpb=a3b19c60a7440794933af1137ea3e538c4ffbff4;p=lyx.git diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index 6d8f7d0737..324987c8a4 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -33,6 +33,7 @@ #include "DispatchResult.h" #include "FuncRequest.h" #include "FuncStatus.h" +#include "InsetIterator.h" #include "InsetList.h" #include "Language.h" #include "LaTeXFeatures.h" @@ -45,6 +46,8 @@ #include "Paragraph.h" #include "ParagraphParameters.h" #include "ParIterator.h" +#include "TexRow.h" +#include "texstream.h" #include "TextClass.h" #include "TextMetrics.h" @@ -61,10 +64,10 @@ #include "support/gettext.h" #include "support/lassert.h" #include "support/lstrings.h" - -#include +#include "support/unique_ptr.h" #include +#include #include #include #include @@ -96,7 +99,7 @@ int const WIDTH_OF_LINE = 5; // space between double lines /// -boost::scoped_ptr paste_tabular; +unique_ptr paste_tabular; struct TabularFeature { @@ -158,6 +161,7 @@ TabularFeature tabularFeature[] = { Tabular::UNSET_LONGTABULAR, "unset-longtabular", false }, { Tabular::SET_PWIDTH, "set-pwidth", true }, { Tabular::SET_MPWIDTH, "set-mpwidth", true }, + { Tabular::TOGGLE_VARWIDTH_COLUMN, "toggle-varwidth-column", true }, { Tabular::SET_ROTATE_TABULAR, "set-rotate-tabular", true }, { Tabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular", true }, { Tabular::TOGGLE_ROTATE_TABULAR, "toggle-rotate-tabular", true }, @@ -260,6 +264,8 @@ string const tostr(Tabular::BoxType const & num) return "parbox"; case Tabular::BOX_MINIPAGE: return "minipage"; + case Tabular::BOX_VARWIDTH: + return "varwidth"; } return string(); } @@ -322,6 +328,8 @@ bool string2type(string const & str, Tabular::BoxType & num) num = Tabular::BOX_PARBOX; else if (str == "minipage") num = Tabular::BOX_MINIPAGE; + else if (str == "varwidth") + num = Tabular::BOX_VARWIDTH; else return false; return true; @@ -526,7 +534,7 @@ string const featureAsString(Tabular::Feature action) } -DocIterator separatorPos(InsetTableCell * cell, docstring const & align_d) +DocIterator separatorPos(InsetTableCell const * cell, docstring const & align_d) { DocIterator dit = doc_iterator_begin(&(cell->buffer()), cell); for (; dit; dit.forwardChar()) @@ -542,7 +550,7 @@ InsetTableCell splitCell(InsetTableCell & head, docstring const & align_d, bool { InsetTableCell tail = InsetTableCell(head); DocIterator const dit = separatorPos(&head, align_d); - hassep = dit; + hassep = (bool)dit; if (hassep) { pit_type const psize = head.paragraphs().front().size(); head.paragraphs().front().eraseChars(dit.pos(), psize, false); @@ -650,7 +658,8 @@ Tabular::RowData::RowData() Tabular::ColumnData::ColumnData() : alignment(LYX_ALIGN_CENTER), valignment(LYX_VALIGN_TOP), - width(0) + width(0), + varwidth(false) { } @@ -876,8 +885,8 @@ void Tabular::insertColumn(col_type const col, bool copy) setBottomLine(i, bottomLine(j)); setTopLine(i, topLine(j)); setLeftLine(i, leftLine(j)); + setRightLine(i, rightLine(j)); if (rightLine(i) && rightLine(j)) { - setRightLine(i, true); setRightLine(j, false); } if (buffer().params().track_changes) @@ -908,8 +917,11 @@ void Tabular::updateIndexes() // reset column and row of cells and update their width and alignment for (row_type row = 0; row < nrows(); ++row) for (col_type column = 0; column < ncols(); ++column) { - if (isPartOfMultiColumn(row, column)) + if (isPartOfMultiColumn(row, column)) { + cell_info[row][column].inset->toggleMultiCol(true); continue; + } + cell_info[row][column].inset->toggleMultiCol(false); // columnofcell needs to be called before setting width and aligment // multirow cells inherit the width from the column width if (!isPartOfMultiRow(row, column)) { @@ -917,8 +929,11 @@ void Tabular::updateIndexes() rowofcell[i] = row; } setFixedWidth(row, column); - if (isPartOfMultiRow(row, column)) + if (isPartOfMultiRow(row, column)) { + cell_info[row][column].inset->toggleMultiRow(true); continue; + } + cell_info[row][column].inset->toggleMultiRow(false); cell_info[row][column].inset->setContentAlignment( getAlignment(cellIndex(row, column))); ++i; @@ -1014,15 +1029,60 @@ int Tabular::cellHeight(idx_type cell) const } -bool Tabular::updateColumnWidths() +bool Tabular::updateColumnWidths(MetricsInfo & mi) { vector max_dwidth(ncols(), 0); + // collect max. fixed width of column + map max_pwidth; + // collect max. variable width of column + map max_width; + for(col_type c = 0; c < ncols(); ++c) for(row_type r = 0; r < nrows(); ++r) { idx_type const i = cellIndex(r, c); if (getAlignment(i) == LYX_ALIGN_DECIMAL) max_dwidth[c] = max(max_dwidth[c], cell_info[r][c].decimal_width); + if (!getPWidth(i).zero()) + max_pwidth[c] = max(max_pwidth[c], cell_info[r][c].width); + else if (!column_info[c].varwidth) + max_width[c] = max(max_width[c], cell_info[r][c].width); + } + + // If we have a fixed tabular width, we take this into account + Length tab_width = tabular_width; + bool const tabularx = hasVarwidthColumn(); + if (tabularx && tab_width.zero()) + // If no tabular width is specified with X columns, + // we use 100% colwidth + tab_width = Length(100, Length::PCW); + int restwidth = -1; + if (!tab_width.zero()) { + restwidth = mi.base.inPixels(tab_width); + // Substract the fixed widths from the table width + for (auto const w : max_pwidth) + restwidth -= w.second; + } + + // If we have a fixed width, distribute the available table width + // (minus the fixed widths) to the variable-width columns + int vcolwidth = -1; + int restcols = ncols() - max_pwidth.size(); + if (restwidth > 0) + vcolwidth = restwidth / restcols; + + // Now consider that some variable width columns exceed the vcolwidth + if (vcolwidth > 0) { + bool changed = false; + for (auto const w : max_width) { + if (tabularx || w.second > vcolwidth) { + --restcols; + restwidth -= w.second; + changed = true; + } } + if (changed && restwidth > 0) + vcolwidth = restwidth / restcols; + } bool update = false; // for each col get max of single col cells @@ -1032,17 +1092,26 @@ bool Tabular::updateColumnWidths() idx_type const i = cellIndex(r, c); if (columnSpan(i) == 1) { if (getAlignment(i) == LYX_ALIGN_DECIMAL - && cell_info[r][c].decimal_width!=0) + && cell_info[r][c].decimal_width != 0) new_width = max(new_width, cellInfo(i).width + max_dwidth[c] - cellInfo(i).decimal_width); - else + else if (getPWidth(i).zero() && vcolwidth > 0) { + if (tabularx && !column_info[c].varwidth) + new_width = max(new_width, cellInfo(i).width); + else if (tabularx) + new_width = vcolwidth; + else + new_width = max(vcolwidth, max(new_width, cellInfo(i).width)); + } else new_width = max(new_width, cellInfo(i).width); } } if (column_info[c].width != new_width) { column_info[c].width = new_width; - update = true; + // Do not trigger update when no space is left for variable + // columns, as this will loop + update = tab_width.zero() || restwidth > 0; } } // update col widths to fit merged cells @@ -1059,7 +1128,9 @@ bool Tabular::updateColumnWidths() if (cellInfo(i).width > old_width) { column_info[c + span - 1].width += cellInfo(i).width - old_width; - update = true; + // Do not trigger update when no space is left for variable + // columns, as this will loop + update = tab_width.zero() || restwidth > 0; } } @@ -1103,7 +1174,7 @@ void Tabular::setAlignment(idx_type cell, LyXAlignment align, dpoint = from_utf8(lyxrc.default_decimal_point); } else { cellInfo(cell).alignment = align; - cellInset(cell).get()->setContentAlignment(align); + cellInset(cell)->setContentAlignment(align); } } @@ -1121,14 +1192,16 @@ void Tabular::setVAlignment(idx_type cell, VAlignment align, namespace { /** - * Allow line and paragraph breaks for fixed width cells or disallow them, - * merge cell paragraphs and reset layout to standard for variable width - * cells. + * Allow line and paragraph breaks for fixed width multicol/multirow cells + * or disallow them, merge cell paragraphs and reset layout to standard + * for variable width multicol cells. */ -void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, bool fixedWidth) +void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, + bool const fixedWidth, bool const multicol, + bool const multirow) { inset->toggleFixedWidth(fixedWidth); - if (fixedWidth) + if (!multirow && (fixedWidth || !multicol)) return; // merge all paragraphs to one @@ -1136,6 +1209,19 @@ void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, bool fixedWidth) while (inset->paragraphs().size() > 1) mergeParagraph(bp, inset->paragraphs(), 0); + // This is relevant for multirows + if (fixedWidth) + return; + + // remove newlines + ParagraphList::iterator pit = inset->paragraphs().begin(); + for (; pit != inset->paragraphs().end(); ++pit) { + for (pos_type j = 0; j != pit->size(); ++j) { + if (pit->isNewline(j)) + pit->eraseChar(j, bp.track_changes); + } + } + // reset layout cur.push(*inset); // undo information has already been recorded @@ -1144,7 +1230,7 @@ void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, bool fixedWidth) cur.pop(); } -} +} // namespace void Tabular::setColumnPWidth(Cursor & cur, idx_type cell, @@ -1159,19 +1245,16 @@ void Tabular::setColumnPWidth(Cursor & cur, idx_type cell, if (column_info[c].p_width.zero()) column_info[c].valignment = LYX_VALIGN_TOP; for (row_type r = 0; r < nrows(); ++r) { - idx_type const cell = cellIndex(r, c); + idx_type const cidx = cellIndex(r, c); // because of multicolumns - toggleFixedWidth(cur, cellInset(cell).get(), - !getPWidth(cell).zero()); - if (isMultiRow(cell)) - setAlignment(cell, LYX_ALIGN_LEFT, false); + toggleFixedWidth(cur, cellInset(cidx).get(), + !getPWidth(cidx).zero(), isMultiColumn(cidx), + isMultiRow(cidx)); + if (isMultiRow(cidx)) + setAlignment(cidx, LYX_ALIGN_LEFT, false); } - // cur paragraph can become invalid after paragraphs were merged - if (cur.pit() > cur.lastpit()) - cur.pit() = cur.lastpit(); - // cur position can become invalid after newlines were removed - if (cur.pos() > cur.lastpos()) - cur.pos() = cur.lastpos(); + // cur can become invalid after paragraphs were merged + cur.fixIfBroken(); } @@ -1192,13 +1275,17 @@ bool Tabular::setMColumnPWidth(Cursor & cur, idx_type cell, return false; cellInfo(cell).p_width = width; - toggleFixedWidth(cur, cellInset(cell).get(), !width.zero()); - // cur paragraph can become invalid after paragraphs were merged - if (cur.pit() > cur.lastpit()) - cur.pit() = cur.lastpit(); - // cur position can become invalid after newlines were removed - if (cur.pos() > cur.lastpos()) - cur.pos() = cur.lastpos(); + toggleFixedWidth(cur, cellInset(cell).get(), !width.zero(), + isMultiColumn(cell), isMultiRow(cell)); + // cur can become invalid after paragraphs were merged + cur.fixIfBroken(); + return true; +} + + +bool Tabular::toggleVarwidth(idx_type cell, bool const varwidth) +{ + column_info[cellColumn(cell)].varwidth = varwidth; return true; } @@ -1321,6 +1408,27 @@ Tabular::getVAlignment(idx_type cell, bool onlycolumn) const } +int Tabular::offsetVAlignment() const +{ + // 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 + int offset_valign = 0; + switch (tabular_valignment) { + case Tabular::LYX_VALIGN_BOTTOM: + offset_valign = rowAscent(0) - height(); + break; + case Tabular::LYX_VALIGN_MIDDLE: + offset_valign = (- height()) / 2 + rowAscent(0); + break; + case Tabular::LYX_VALIGN_TOP: + offset_valign = rowAscent(0); + break; + } + return offset_valign; +} + + Length const Tabular::getPWidth(idx_type cell) const { if (isMultiColumn(cell)) @@ -1458,10 +1566,9 @@ void Tabular::write(ostream & os) const << 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); - } + os << write_attribute("tabularwidth", tabular_width); if (is_long_tabular) os << write_attribute("longtabularalignment", longtabular_alignment); os << ">\n"; @@ -1472,6 +1579,7 @@ void Tabular::write(ostream & os) const os << write_attribute("decimal_point", column_info[c].decimal_point); os << write_attribute("valignment", column_info[c].valignment) << write_attribute("width", column_info[c].p_width.asString()) + << write_attribute("varwidth", column_info[c].varwidth) << write_attribute("special", column_info[c].align_special) << ">\n"; } @@ -1584,6 +1692,7 @@ void Tabular::read(Lexer & lex) getTokenValue(line, "valignment", column_info[c].valignment); getTokenValue(line, "width", column_info[c].p_width); getTokenValue(line, "special", column_info[c].align_special); + getTokenValue(line, "varwidth", column_info[c].varwidth); } for (row_type i = 0; i < nrows(); ++i) { @@ -1669,13 +1778,40 @@ bool Tabular::hasMultiColumn(col_type c) const } -Tabular::CellData & Tabular::cellInfo(idx_type cell) const +bool Tabular::hasVarwidthColumn() const +{ + for (col_type c = 0; c < ncols(); ++c) { + if (column_info[c].varwidth) + return true; + } + return false; +} + + +bool Tabular::isVTypeColumn(col_type c) const +{ + for (row_type r = 0; r < nrows(); ++r) { + idx_type idx = cellIndex(r, c); + if (getRotateCell(idx) == 0 && useBox(idx) == BOX_VARWIDTH) + return true; + } + return false; +} + + +Tabular::CellData const & Tabular::cellInfo(idx_type cell) const { return cell_info[cellRow(cell)][cellColumn(cell)]; } -Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number, +Tabular::CellData & Tabular::cellInfo(idx_type cell) +{ + return cell_info[cellRow(cell)][cellColumn(cell)]; +} + + +Tabular::idx_type Tabular::setMultiColumn(Cursor & cur, idx_type cell, idx_type number, bool const right_border) { idx_type const col = cellColumn(cell); @@ -1690,6 +1826,14 @@ Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number, if (column_info[col].alignment != LYX_ALIGN_DECIMAL) cs.alignment = column_info[col].alignment; setRightLine(cell, right_border); + // non-fixed width multicolumns cannot have multiple paragraphs + if (getPWidth(cell).zero()) { + toggleFixedWidth(cur, cellInset(cell).get(), + !getPWidth(cell).zero(), isMultiColumn(cell), + isMultiRow(cell)); + // cur can become invalid after paragraphs were merged + cur.fixIfBroken(); + } idx_type lastcell = cellIndex(row, col + number - 1); for (idx_type i = 1; i < lastcell - cell + 1; ++i) { @@ -1718,7 +1862,7 @@ bool Tabular::hasMultiRow(row_type r) const return false; } -Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number, +Tabular::idx_type Tabular::setMultiRow(Cursor & cur, idx_type cell, idx_type number, bool const bottom_border, LyXAlignment const halign) { @@ -1741,6 +1885,15 @@ Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number, else cs.alignment = LYX_ALIGN_LEFT; + // Multirows cannot have multiple paragraphs + if (getPWidth(cell).zero()) { + toggleFixedWidth(cur, cellInset(cell).get(), + !getPWidth(cell).zero(), + isMultiColumn(cell), isMultiRow(cell)); + // cur can become invalid after paragraphs were merged + cur.fixIfBroken(); + } + // set the bottom line of the last selected cell setBottomLine(cell, bottom_border); @@ -1831,7 +1984,7 @@ int Tabular::getRotateCell(idx_type cell) const bool Tabular::needRotating() const { - if (rotate) + if (rotate && !is_long_tabular) return true; for (row_type r = 0; r < nrows(); ++r) for (col_type c = 0; c < ncols(); ++c) @@ -1886,16 +2039,15 @@ void Tabular::setUsebox(idx_type cell, BoxType type) } -// FIXME: Remove this routine because we cannot insert \parboxes when the user -// adds line breaks, see bug 4886. Tabular::BoxType Tabular::getUsebox(idx_type cell) const { - if ((!column_info[cellColumn(cell)].p_width.zero() && !isMultiColumn(cell)) || - (isMultiColumn(cell) && !cellInfo(cell).p_width.zero())) + if (getRotateCell(cell) == 0 + && ((!column_info[cellColumn(cell)].p_width.zero() && !isMultiColumn(cell)) || + (isMultiColumn(cell) && !cellInfo(cell).p_width.zero()))) return BOX_NONE; if (cellInfo(cell).usebox > 1) return cellInfo(cell).usebox; - return useParbox(cell); + return useBox(cell); } @@ -2024,11 +2176,11 @@ bool Tabular::haveLTLastFoot(bool withcaptions) const } -Tabular::idx_type Tabular::setLTCaption(row_type row, bool what) +Tabular::idx_type Tabular::setLTCaption(Cursor & cur, row_type row, bool what) { idx_type i = getFirstCellInRow(row); if (what) { - setMultiColumn(i, numberOfCellsInRow(row), false); + setMultiColumn(cur, i, numberOfCellsInRow(row), false); setTopLine(i, false); setBottomLine(i, false); setLeftLine(i, false); @@ -2144,23 +2296,24 @@ bool Tabular::isPartOfMultiRow(row_type row, col_type column) const } -void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang) const +void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang, + list columns) const { // we only output complete row lines and the 1st row here, the rest // is done in Tabular::TeXBottomHLine(...) // get for each column the topline (if any) - vector topline; + map topline; col_type nset = 0; - for (col_type c = 0; c < ncols(); ++c) { - topline.push_back(topLine(cellIndex(row, c))); + for (auto const & c : columns) { + topline[c] = topLine(cellIndex(row, c)); // If cell is part of a multirow and not the first cell of the // multirow, no line must be drawn. if (row != 0) if (isMultiRow(cellIndex(row, c)) && cell_info[row][c].multirow != CELL_BEGIN_OF_MULTIROW) topline[c] = false; - if (topline[c]) + if (topline.find(c) != topline.end() && topline.find(c)->second) ++nset; } @@ -2176,8 +2329,8 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang) co os << "\\hline "; } } else if (row == 0) { - for (col_type c = 0; c < ncols(); ++c) { - if (topline[c]) { + for (auto & c : columns) { + if (topline.find(c)->second) { col_type offset = 0; for (col_type j = 0 ; j < c; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) @@ -2192,7 +2345,7 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang) co os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 + offset << '-'; col_type cstart = c; - for ( ; c < ncols() && topline[c]; ++c) {} + for ( ; c < ncols() && topline.find(c)->second; ++c) {} for (col_type j = cstart ; j < c ; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) @@ -2206,18 +2359,19 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang) co } -void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang) const +void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang, + list columns) const { // we output bottomlines of row r and the toplines of row r+1 // if the latter do not span the whole tabular // get the bottomlines of row r, and toplines in next row bool lastrow = row == nrows() - 1; - vector bottomline, topline; + map bottomline, topline; bool nextrowset = true; - for (col_type c = 0; c < ncols(); ++c) { - bottomline.push_back(bottomLine(cellIndex(row, c))); - topline.push_back(!lastrow && topLine(cellIndex(row + 1, c))); + for (auto const & c : columns) { + bottomline[c] = bottomLine(cellIndex(row, c)); + topline[c] = !lastrow && topLine(cellIndex(row + 1, c)); // If cell is part of a multirow and not the last cell of the // multirow, no line must be drawn. if (!lastrow) @@ -2227,15 +2381,15 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang) bottomline[c] = false; topline[c] = false; } - nextrowset &= topline[c]; + nextrowset &= topline.find(c) != topline.end() && topline.find(c)->second; } // combine this row's bottom lines and next row's toplines if necessary col_type nset = 0; - for (col_type c = 0; c < ncols(); ++c) { + for (auto const & c : columns) { if (!nextrowset) - bottomline[c] = bottomline[c] || topline[c]; - if (bottomline[c]) + bottomline[c] = bottomline.find(c)->second || topline.find(c)->second; + if (bottomline.find(c)->second) ++nset; } @@ -2249,8 +2403,8 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang) else os << "\\hline "; } else { - for (col_type c = 0; c < ncols(); ++c) { - if (bottomline[c]) { + for (auto & c : columns) { + if (bottomline.find(c)->second) { col_type offset = 0; for (col_type j = 0 ; j < c; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) @@ -2265,7 +2419,7 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang) os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 + offset << '-'; col_type cstart = c; - for ( ; c < ncols() && bottomline[c]; ++c) {} + for ( ; c < ncols() && bottomline.find(c)->second; ++c) {} for (col_type j = cstart ; j < c ; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) @@ -2280,7 +2434,8 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang) void Tabular::TeXCellPreamble(otexstream & os, idx_type cell, - bool & ismulticol, bool & ismultirow) const + bool & ismulticol, bool & ismultirow, + bool const bidi) const { row_type const r = cellRow(cell); if (is_long_tabular && row_info[r].caption) @@ -2290,8 +2445,10 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell, LyXAlignment align = getAlignment(cell, !isMultiColumn(cell)); // figure out how to set the lines // we always set double lines to the right of the cell + // or left in bidi RTL, respectively. col_type const c = cellColumn(cell); col_type const nextcol = c + columnSpan(cell); + bool const decimal = column_info[c].alignment == LYX_ALIGN_DECIMAL; bool colright = columnRightLine(c); bool colleft = columnLeftLine(c); bool nextcolleft = nextcol < ncols() && columnLeftLine(nextcol); @@ -2300,28 +2457,35 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell, bool coldouble = colright && nextcolleft; bool celldouble = rightLine(cell) && nextcellleft; - ismulticol = isMultiColumn(cell) - || (c == 0 && colleft != leftLine(cell)) - || ((colright || nextcolleft) && !rightLine(cell) && !nextcellleft) - || (!colright && !nextcolleft && (rightLine(cell) || nextcellleft)) - || (coldouble != celldouble); + ismulticol = (isMultiColumn(cell) + || (c == 0 && colleft != leftLine(cell)) + || ((colright || nextcolleft) && !rightLine(cell) && !nextcellleft) + || (!colright && !nextcolleft && (rightLine(cell) || nextcellleft)) + || (coldouble != celldouble)) + && !decimal; // we center in multicol when no decimal point - if (column_info[c].alignment == LYX_ALIGN_DECIMAL) { + if (decimal) { docstring const align_d = column_info[c].decimal_point; - DocIterator const dit = separatorPos(cellInset(cell).get(), align_d); - ismulticol |= !dit; + DocIterator const dit = separatorPos(cellInset(cell), align_d); + bool const nosep = !dit; + ismulticol |= nosep; + celldouble &= nosep; } // up counter by 1 for each decimally aligned col since they use 2 latex cols int latexcolspan = columnSpan(cell); - for(col_type col = c; col < c + columnSpan(cell); ++col) + for (col_type col = c; col < c + columnSpan(cell); ++col) if (column_info[col].alignment == LYX_ALIGN_DECIMAL) ++latexcolspan; if (ismulticol) { os << "\\multicolumn{" << latexcolspan << "}{"; - if (c ==0 && leftLine(cell)) + if (((bidi && c == getLastCellInRow(cellRow(0)) && rightLine(cell)) + || (!bidi && c == 0 && leftLine(cell)))) + os << '|'; + if (bidi && celldouble) + // add extra vertical line if we want a double one os << '|'; if (!cellInfo(cell).align_special.empty()) { os << cellInfo(cell).align_special; @@ -2368,9 +2532,9 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell, } } // end if else !getPWidth } // end if else !cellinfo_of_cell - if (rightLine(cell) || nextcellleft) + if ((bidi && leftLine(cell)) || (!bidi && rightLine(cell)) || nextcellleft) os << '|'; - if (celldouble) + if (!bidi && celldouble) // add extra vertical line if we want a double one os << '|'; os << "}{"; @@ -2424,7 +2588,21 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell, } os << "]{" << from_ascii(getPWidth(cell).asLatexString()) << "}\n"; + } else if (getRotateCell(cell) != 0 && getUsebox(cell) == BOX_VARWIDTH) { + os << "\\begin{varwidth}["; + switch (valign) { + case LYX_VALIGN_TOP: + os << 't'; + break; + case LYX_VALIGN_MIDDLE: + os << 'm'; + break; + case LYX_VALIGN_BOTTOM: + os << 'b'; + break; } + os << "]{\\linewidth}\n"; +} } @@ -2440,6 +2618,8 @@ void Tabular::TeXCellPostamble(otexstream & os, idx_type cell, os << '}'; else if (getUsebox(cell) == BOX_MINIPAGE) os << breakln << "\\end{minipage}"; + else if (getRotateCell(cell) != 0 && getUsebox(cell) == BOX_VARWIDTH) + os << breakln << "\\end{varwidth}"; if (getRotateCell(cell) != 0) os << breakln << "\\end{turn}"; if (ismultirow) @@ -2450,7 +2630,8 @@ void Tabular::TeXCellPostamble(otexstream & os, idx_type cell, void Tabular::TeXLongtableHeaderFooter(otexstream & os, - OutputParams const & runparams) const + OutputParams const & runparams, + list columns) const { if (!is_long_tabular) return; @@ -2462,7 +2643,7 @@ void Tabular::TeXLongtableHeaderFooter(otexstream & os, if (row_info[r].caption && !row_info[r].endfirsthead && !row_info[r].endhead && !row_info[r].endfoot && !row_info[r].endlastfoot) - TeXRow(os, r, runparams); + TeXRow(os, r, runparams, columns); } } // output first header info @@ -2471,7 +2652,7 @@ void Tabular::TeXLongtableHeaderFooter(otexstream & os, os << "\\hline\n"; for (row_type r = 0; r < nrows(); ++r) { if (row_info[r].endfirsthead) - TeXRow(os, r, runparams); + TeXRow(os, r, runparams, columns); } if (endfirsthead.bottomDL) os << "\\hline\n"; @@ -2485,7 +2666,7 @@ void Tabular::TeXLongtableHeaderFooter(otexstream & os, os << "\\hline\n"; for (row_type r = 0; r < nrows(); ++r) { if (row_info[r].endhead) - TeXRow(os, r, runparams); + TeXRow(os, r, runparams, columns); } if (endhead.bottomDL) os << "\\hline\n"; @@ -2497,7 +2678,7 @@ void Tabular::TeXLongtableHeaderFooter(otexstream & os, os << "\\hline\n"; for (row_type r = 0; r < nrows(); ++r) { if (row_info[r].endfoot) - TeXRow(os, r, runparams); + TeXRow(os, r, runparams, columns); } if (endfoot.bottomDL) os << "\\hline\n"; @@ -2511,7 +2692,7 @@ void Tabular::TeXLongtableHeaderFooter(otexstream & os, os << "\\hline\n"; for (row_type r = 0; r < nrows(); ++r) { if (row_info[r].endlastfoot) - TeXRow(os, r, runparams); + TeXRow(os, r, runparams, columns); } if (endlastfoot.bottomDL) os << "\\hline\n"; @@ -2531,15 +2712,16 @@ bool Tabular::isValidRow(row_type row) const void Tabular::TeXRow(otexstream & os, row_type row, - OutputParams const & runparams) const + OutputParams const & runparams, + list columns) const { idx_type cell = cellIndex(row, 0); - shared_ptr inset = cellInset(cell); - Paragraph const & par = inset->paragraphs().front(); - string const lang = par.getParLanguage(buffer().params())->lang(); + InsetTableCell const * cinset = cellInset(cell); + Paragraph const & cpar = cinset->paragraphs().front(); + string const clang = cpar.getParLanguage(buffer().params())->lang(); //output the top line - TeXTopHLine(os, row, lang); + TeXTopHLine(os, row, clang, columns); if (row_info[row].top_space_default) { if (use_booktabs) @@ -2559,7 +2741,15 @@ void Tabular::TeXRow(otexstream & os, row_type row, } bool ismulticol = false; bool ismultirow = false; - for (col_type c = 0; c < ncols(); ++c) { + + // The bidi package (loaded by polyglossia) reverses RTL table columns + bool const bidi_rtl = + runparams.local_font->isRightToLeft() + && runparams.use_polyglossia; + idx_type lastcell = + bidi_rtl ? getFirstCellInRow(row) : getLastCellInRow(row); + + for (auto const & c : columns) { if (isPartOfMultiColumn(row, c)) continue; @@ -2567,13 +2757,13 @@ void Tabular::TeXRow(otexstream & os, row_type row, if (isPartOfMultiRow(row, c) && column_info[c].alignment != LYX_ALIGN_DECIMAL) { - if (cell != getLastCellInRow(row)) + if (cell != lastcell) os << " & "; continue; } - TeXCellPreamble(os, cell, ismulticol, ismultirow); - shared_ptr inset = cellInset(cell); + TeXCellPreamble(os, cell, ismulticol, ismultirow, bidi_rtl); + InsetTableCell const * inset = cellInset(cell); Paragraph const & par = inset->paragraphs().front(); @@ -2606,22 +2796,43 @@ void Tabular::TeXRow(otexstream & os, row_type row, if (getAlignment(cell) == LYX_ALIGN_DECIMAL) { // copy cell and split in 2 - InsetTableCell head = InsetTableCell(*cellInset(cell).get()); - head.setBuffer(buffer()); + InsetTableCell head = InsetTableCell(*cellInset(cell)); + head.setBuffer(const_cast(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); if (hassep) { - os << '&'; tail.setBuffer(head.buffer()); dit.pop_back(); dit.push_back(CursorSlice(tail)); tail.setMacrocontextPositionRecursive(dit); - tail.latex(os, newrp); + } + if (bidi_rtl) { + if (hassep) { + tail.latex(os, newrp); + os << '&'; + } + head.latex(os, newrp); + } else { + head.latex(os, newrp); + if (hassep) { + os << '&'; + tail.latex(os, newrp); + } + } + } 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(inset)); + InsetIterator i_end = inset_iterator_end(*const_cast(inset)); + for (; it != i_end; ++it) { + if (it->lyxCode() != CAPTION_CODE) + continue; + it->latex(os, runparams); + break; } } else if (!isPartOfMultiRow(row, c)) { if (!runparams.nice) @@ -2634,7 +2845,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, os << '}'; TeXCellPostamble(os, cell, ismulticol, ismultirow); - if (cell != getLastCellInRow(row)) { // not last cell in row + if (cell != lastcell) { // not last cell in row if (runparams.nice) os << " & "; else @@ -2657,7 +2868,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, os << '\n'; //output the bottom line - TeXBottomHLine(os, row, lang); + TeXBottomHLine(os, row, clang, columns); if (row_info[row].interline_space_default) { if (use_booktabs) @@ -2679,9 +2890,11 @@ void Tabular::TeXRow(otexstream & os, row_type row, void Tabular::latex(otexstream & os, OutputParams const & runparams) const { - bool const is_tabular_star = !tabular_width.zero(); - TexRow::RowEntry pos = TexRow::textEntry(runparams.lastid, - runparams.lastpos); + bool const is_tabular_star = !is_long_tabular && !tabular_width.zero() + && !hasVarwidthColumn(); + bool const is_xltabular = is_long_tabular + && (hasVarwidthColumn() || !tabular_width.zero()); + TexRow::RowEntry pos = TexRow::textEntry(runparams.lastid, runparams.lastpos); //+--------------------------------------------------------------------- //+ first the opening preamble + @@ -2691,25 +2904,45 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const if (!TexRow::isNone(pos)) os.texrow().start(pos); - if (rotate != 0) - os << "\\begin{turn}{" << convert(rotate) << "}\n"; + if (rotate != 0) { + if (is_long_tabular) + os << "\\begin{landscape}\n"; + else + os << "\\begin{turn}{" << convert(rotate) << "}\n"; + } if (is_long_tabular) { - os << "\\begin{longtable}"; + if (is_xltabular) + os << "\\begin{xltabular}"; + else + os << "\\begin{longtable}"; switch (longtabular_alignment) { case LYX_LONGTABULAR_ALIGN_LEFT: os << "[l]"; break; case LYX_LONGTABULAR_ALIGN_CENTER: + os << "[c]"; break; case LYX_LONGTABULAR_ALIGN_RIGHT: os << "[r]"; break; } + if (is_xltabular) { + if (tabular_width.zero()) + os << "{" << from_ascii("\\columnwidth") << "}"; + else + os << "{" << from_ascii(tabular_width.asLatexString()) << "}"; + } } else { if (is_tabular_star) os << "\\begin{tabular*}{" << from_ascii(tabular_width.asLatexString()) << "}"; - else + else if (hasVarwidthColumn()) { + os << "\\begin{tabularx}{"; + if (tabular_width.zero()) + os << from_ascii("\\columnwidth") << "}"; + else + os << from_ascii(tabular_width.asLatexString()) << "}"; + } else os << "\\begin{tabular}"; switch (tabular_valignment) { case LYX_VALIGN_TOP: @@ -2728,13 +2961,27 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const if (is_tabular_star) os << "@{\\extracolsep{\\fill}}"; - for (col_type c = 0; c < ncols(); ++c) { - if (columnLeftLine(c)) + // The bidi package (loaded by polyglossia) swaps the column + // order for RTL (#9686). Thus we use this list. + bool const bidi_rtl = + runparams.local_font->isRightToLeft() + && runparams.use_polyglossia; + list columns; + for (col_type cl = 0; cl < ncols(); ++cl) { + if (bidi_rtl) + columns.push_front(cl); + else + columns.push_back(cl); + } + + for (auto const & c : columns) { + if ((bidi_rtl && columnRightLine(c)) || (!bidi_rtl && columnLeftLine(c))) os << '|'; if (!column_info[c].align_special.empty()) { os << column_info[c].align_special; } else { if (!column_info[c].p_width.zero()) { + bool decimal = false; switch (column_info[c].alignment) { case LYX_ALIGN_LEFT: os << ">{\\raggedright}"; @@ -2749,24 +2996,91 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const case LYX_ALIGN_BLOCK: case LYX_ALIGN_LAYOUT: case LYX_ALIGN_SPECIAL: - case LYX_ALIGN_DECIMAL: break; + case LYX_ALIGN_DECIMAL: { + if (bidi_rtl) + os << ">{\\raggedright}"; + else + os << ">{\\raggedleft}"; + decimal = true; + break; + } } + char valign = 'p'; switch (column_info[c].valignment) { case LYX_VALIGN_TOP: - os << 'p'; + // this is the default break; case LYX_VALIGN_MIDDLE: - os << 'm'; + valign = 'm'; break; case LYX_VALIGN_BOTTOM: - os << 'b'; + valign = 'b'; break; - } - os << '{' - << from_ascii(column_info[c].p_width.asLatexString()) - << '}'; + } + os << valign; + + // Fixed-width cells with alignment at decimal separator + // are output as two cells of half the width with the decimal + // separator as column sep. This effectively puts the content + // centered, which differs from the normal decimal sep alignment + // and is not ideal, but we cannot do better ATM (see #9568). + // FIXME: Implement proper decimal sep alignment, e.g. via siunitx. + if (decimal) { + docstring const halffixedwith = + from_ascii(Length(column_info[c].p_width.value() / 2, + column_info[c].p_width.unit()).asLatexString()); + os << '{' + << halffixedwith + << '}' + << "@{\\extracolsep{0pt}" << column_info[c].decimal_point << "}" + << valign + << '{' + << halffixedwith + << '}'; + } else + os << '{' + << from_ascii(column_info[c].p_width.asLatexString()) + << '}'; + } else if (column_info[c].varwidth) { + switch (column_info[c].alignment) { + case LYX_ALIGN_LEFT: + os << ">{\\raggedright\\arraybackslash}"; + break; + case LYX_ALIGN_RIGHT: + os << ">{\\raggedleft\\arraybackslash}"; + break; + case LYX_ALIGN_CENTER: + os << ">{\\centering\\arraybackslash}"; + break; + case LYX_ALIGN_NONE: + case LYX_ALIGN_BLOCK: + case LYX_ALIGN_LAYOUT: + case LYX_ALIGN_SPECIAL: + case LYX_ALIGN_DECIMAL: + break; + } + os << 'X'; + } else if (isVTypeColumn(c)) { + switch (column_info[c].alignment) { + case LYX_ALIGN_LEFT: + os << ">{\\raggedright}"; + break; + case LYX_ALIGN_RIGHT: + os << ">{\\raggedleft}"; + break; + case LYX_ALIGN_CENTER: + os << ">{\\centering}"; + break; + case LYX_ALIGN_NONE: + case LYX_ALIGN_BLOCK: + case LYX_ALIGN_LAYOUT: + case LYX_ALIGN_SPECIAL: + case LYX_ALIGN_DECIMAL: + break; + } + os << "V{\\linewidth}"; } else { switch (column_info[c].alignment) { case LYX_ALIGN_LEFT: @@ -2784,12 +3098,12 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const } } // end if else !column_info[i].p_width } // end if else !column_info[i].align_special - if (columnRightLine(c)) + if ((bidi_rtl && columnLeftLine(c)) || (!bidi_rtl && columnRightLine(c))) os << '|'; } os << "}\n"; - TeXLongtableHeaderFooter(os, runparams); + TeXLongtableHeaderFooter(os, runparams, columns); //+--------------------------------------------------------------------- //+ the single row and columns (cells) + @@ -2797,7 +3111,7 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const for (row_type r = 0; r < nrows(); ++r) { if (isValidRow(r)) { - TeXRow(os, r, runparams); + TeXRow(os, r, runparams, columns); if (is_long_tabular && row_info[r].newpage) os << "\\newpage\n"; } @@ -2807,17 +3121,26 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const //+ the closing of the tabular + //+--------------------------------------------------------------------- - if (is_long_tabular) - os << "\\end{longtable}"; - else { + if (is_long_tabular) { + if (is_xltabular) + os << "\\end{xltabular}"; + else + os << "\\end{longtable}"; + } else { if (is_tabular_star) os << "\\end{tabular*}"; + else if (hasVarwidthColumn()) + os << "\\end{tabularx}"; else os << "\\end{tabular}"; } - if (rotate != 0) - os << breakln << "\\end{turn}"; + if (rotate != 0) { + if (is_long_tabular) + os << breakln << "\\end{landscape}"; + else + os << breakln << "\\end{turn}"; + } if (!TexRow::isNone(pos)) os.texrow().start(pos); @@ -2988,6 +3311,13 @@ docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row, continue; stringstream attr; + + Length const cwidth = column_info[c].p_width; + if (!cwidth.zero()) { + string const hwidth = cwidth.asHTMLString(); + attr << "style =\"width: " << hwidth << ";\" "; + } + attr << "align='"; switch (getAlignment(cell)) { case LYX_ALIGN_LEFT: @@ -3019,7 +3349,7 @@ docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row, else if (isMultiRow(cell)) attr << " rowspan='" << rowSpan(cell) << "'"; - xs << html::StartTag(celltag, attr.str()) << html::CR(); + xs << html::StartTag(celltag, attr.str(), true) << html::CR(); ret += cellInset(cell)->xhtml(xs, runparams); xs << html::EndTag(celltag) << html::CR(); ++cell; @@ -3322,21 +3652,26 @@ void Tabular::plaintext(odocstringstream & os, } -shared_ptr Tabular::cellInset(idx_type cell) const +shared_ptr Tabular::cellInset(idx_type cell) { return cell_info[cellRow(cell)][cellColumn(cell)].inset; } -shared_ptr Tabular::cellInset(row_type row, - col_type column) const +shared_ptr Tabular::cellInset(row_type row, col_type column) { return cell_info[row][column].inset; } +InsetTableCell const * Tabular::cellInset(idx_type cell) const +{ + return cell_info[cellRow(cell)][cellColumn(cell)].inset.get(); +} + + void Tabular::setCellInset(row_type row, col_type column, - shared_ptr ins) const + shared_ptr ins) { CellData & cd = cell_info[row][column]; cd.inset = ins; @@ -3348,31 +3683,58 @@ void Tabular::validate(LaTeXFeatures & features) const features.require("NeedTabularnewline"); if (use_booktabs) features.require("booktabs"); - if (is_long_tabular) - features.require("longtable"); + if (is_long_tabular && !hasVarwidthColumn()) { + if (tabular_width.zero()) + features.require("longtable"); + else + features.require("xltabular"); + } + if (rotate && is_long_tabular) + features.require("lscape"); if (needRotating()) features.require("rotating"); + if (hasVarwidthColumn()) { + if (is_long_tabular) + features.require("xltabular"); + else + features.require("tabularx"); + } for (idx_type cell = 0; cell < numberofcells; ++cell) { if (isMultiRow(cell)) features.require("multirow"); + if (getUsebox(cell) == BOX_VARWIDTH) + features.require("varwidth"); if (getVAlignment(cell) != LYX_VALIGN_TOP - || !getPWidth(cell).zero()) + || !getPWidth(cell).zero() + || isVTypeColumn(cellColumn(cell))) features.require("array"); + // Tell footnote that we need a savenote + // environment in non-long tables or + // longtable headers/footers + else if (!is_long_tabular && !features.inFloat()) + features.saveNoteEnv("tabular"); + else if (!isValidRow(cellRow(cell))) + features.saveNoteEnv("longtable"); + cellInset(cell)->validate(features); + features.saveNoteEnv(string()); } } -Tabular::BoxType Tabular::useParbox(idx_type cell) const +Tabular::BoxType Tabular::useBox(idx_type cell) const { ParagraphList const & parlist = cellInset(cell)->paragraphs(); + if (parlist.size() > 1) + return BOX_VARWIDTH; + 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 BOX_PARBOX; + if (cit->isNewline(i) || cit->layout().isEnvironment()) + return BOX_VARWIDTH; return BOX_NONE; } @@ -3386,13 +3748,13 @@ Tabular::BoxType Tabular::useParbox(idx_type cell) const InsetTableCell::InsetTableCell(Buffer * buf) : InsetText(buf, InsetText::PlainLayout), isFixedWidth(false), - contentAlign(LYX_ALIGN_CENTER) + isMultiColumn(false), isMultiRow(false), contentAlign(LYX_ALIGN_CENTER) {} bool InsetTableCell::forcePlainLayout(idx_type) const { - return !isFixedWidth; + return isMultiRow || (isMultiColumn && !isFixedWidth); } @@ -3413,13 +3775,6 @@ bool InsetTableCell::getStatus(Cursor & cur, FuncRequest const & cmd, { bool enabled = true; switch (cmd.action()) { - case LFUN_LAYOUT: - enabled = !forcePlainLayout(); - break; - case LFUN_LAYOUT_PARAGRAPH: - enabled = allowParagraphCustomization(); - break; - case LFUN_MATH_DISPLAY: if (!hasFixedWidth()) { enabled = false; @@ -3452,9 +3807,9 @@ docstring InsetTableCell::asString(bool intoInsets) void InsetTableCell::addToToc(DocIterator const & di, bool output_active, - UpdateType utype) const + UpdateType utype, TocBackend & backend) const { - InsetText::iterateForToc(di, output_active, utype); + InsetText::iterateForToc(di, output_active, utype, backend); } @@ -3466,6 +3821,33 @@ docstring InsetTableCell::xhtml(XHTMLStream & xs, OutputParams const & rp) const } +void InsetTableCell::metrics(MetricsInfo & mi, Dimension & dim) const +{ + TextMetrics & tm = mi.base.bv->textMetrics(&text()); + + // Hand font through to contained lyxtext: + tm.font_.fontInfo() = mi.base.font; + mi.base.textwidth -= 2 * TEXT_TO_INSET_OFFSET; + + // This can happen when a layout has a left and right margin, + // and the view is made very narrow. We can't do better than + // to draw it partly out of view (bug 5890). + if (mi.base.textwidth < 1) + mi.base.textwidth = 1; + + // We tell metrics here not to expand on multiple pars + // This is the difference to InsetText::Metrics + if (hasFixedWidth()) + tm.metrics(mi, dim, mi.base.textwidth, false); + else + tm.metrics(mi, dim, 0, false); + mi.base.textwidth += 2 * TEXT_TO_INSET_OFFSET; + dim.asc += TEXT_TO_INSET_OFFSET; + dim.des += TEXT_TO_INSET_OFFSET; + dim.wid += 2 * TEXT_TO_INSET_OFFSET; +} + + ///////////////////////////////////////////////////////////////////// // @@ -3476,13 +3858,14 @@ docstring InsetTableCell::xhtml(XHTMLStream & xs, OutputParams const & rp) const InsetTabular::InsetTabular(Buffer * buf, row_type rows, col_type columns) : Inset(buf), tabular(buf, max(rows, row_type(1)), max(columns, col_type(1))), - first_visible_cell_(0), offset_valign_(0), rowselect_(false), colselect_(false) + rowselect_(false), colselect_(false) { } InsetTabular::InsetTabular(InsetTabular const & tab) - : Inset(tab), tabular(tab.tabular) + : Inset(tab), tabular(tab.tabular), + rowselect_(false), colselect_(false) { } @@ -3521,7 +3904,7 @@ bool InsetTabular::insetAllowed(InsetCode code) const bool InsetTabular::allowsCaptionVariation(std::string const & newtype) const { return tabular.is_long_tabular && - (newtype == "Standard" || newtype == "LongTableNoNumber"); + (newtype == "Standard" || newtype == "Unnumbered"); } @@ -3569,7 +3952,7 @@ void InsetTabular::read(Lexer & lex) int InsetTabular::rowFromY(Cursor & cur, int y) const { // top y coordinate of tabular - int h = yo(cur.bv()) - tabular.rowAscent(0) + offset_valign_; + int h = yo(cur.bv()) - tabular.rowAscent(0) + tabular.offsetVAlignment(); row_type r = 0; for (; r < tabular.nrows() && y > h; ++r) h += tabular.rowAscent(r) + tabular.rowDescent(r) @@ -3605,15 +3988,17 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const // multicolumn or multirow cell, but not first one continue; idx_type const cell = tabular.cellIndex(r, c); - Dimension dim; + Dimension dim0; MetricsInfo m = mi; Length const p_width = tabular.getPWidth(cell); if (!p_width.zero()) - m.base.textwidth = p_width.inPixels(mi.base); - tabular.cellInset(cell)->metrics(m, dim); - if (!p_width.zero()) - dim.wid = m.base.textwidth; - tabular.cellInfo(cell).width = dim.wid + 2 * WIDTH_OF_LINE + m.base.textwidth = mi.base.inPixels(p_width); + else if (tabular.column_info[c].varwidth) + m.base.textwidth = tabular.column_info[c].width; + tabular.cellInset(cell)->metrics(m, dim0); + if (!p_width.zero() || tabular.column_info[c].varwidth) + dim0.wid = m.base.textwidth; + tabular.cellInfo(cell).width = dim0.wid + 2 * WIDTH_OF_LINE + tabular.interColumnSpace(cell); // FIXME(?): do we need a second metrics call? @@ -3623,7 +4008,7 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const // determine horizontal offset because of decimal align (if necessary) int decimal_width = 0; if (tabular.getAlignment(cell) == LYX_ALIGN_DECIMAL) { - InsetTableCell tail = InsetTableCell(*tabular.cellInset(cell).get()); + InsetTableCell tail = InsetTableCell(*tabular.cellInset(cell)); tail.setBuffer(tabular.buffer()); // we need to set macrocontext position everywhere // otherwise we crash with nested insets (e.g. footnotes) @@ -3658,50 +4043,37 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const case Tabular::LYX_VALIGN_TOP: break; case Tabular::LYX_VALIGN_MIDDLE: - offset = -(dim.des - lastpardes)/2; + offset = -(dim0.des - lastpardes)/2; break; case Tabular::LYX_VALIGN_BOTTOM: - offset = -(dim.des - lastpardes); + offset = -(dim0.des - lastpardes); break; } tabular.cell_info[r][c].voffset = offset; - maxasc = max(maxasc, dim.asc - offset); - maxdes = max(maxdes, dim.des + offset); + maxasc = max(maxasc, dim0.asc - offset); + maxdes = max(maxdes, dim0.des + offset); } int const top_space = tabular.row_info[r].top_space_default ? - default_line_space : - tabular.row_info[r].top_space.inPixels(mi.base); + default_line_space : + mi.base.inPixels(tabular.row_info[r].top_space); tabular.setRowAscent(r, maxasc + ADD_TO_HEIGHT + top_space); int const bottom_space = tabular.row_info[r].bottom_space_default ? - default_line_space : - tabular.row_info[r].bottom_space.inPixels(mi.base); + default_line_space : + mi.base.inPixels(tabular.row_info[r].bottom_space); 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) - offset_valign_; + // We need to recalculate the metrics after column width calculation + // with xtabular (possibly multiple times, so the call is recursive). + if (tabular.updateColumnWidths(mi) && tabular.hasVarwidthColumn()) + metrics(mi, dim); + dim.asc = tabular.rowAscent(0) - tabular.offsetVAlignment(); dim.des = tabular.height() - dim.asc; dim.wid = tabular.width() + 2 * ADD_TO_TABULAR_WIDTH; } -bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col) - const +bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col) const { if (&cur.inset() == this && cur.selection()) { if (cur.selIsMultiCell()) { @@ -3745,9 +4117,8 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const bool const original_selection_state = pi.selected; idx_type idx = 0; - first_visible_cell_ = Tabular::npos; - int yy = y + offset_valign_; + int yy = y + tabular.offsetVAlignment(); for (row_type r = 0; r < tabular.nrows(); ++r) { int nx = x; for (col_type c = 0; c < tabular.ncols(); ++c) { @@ -3761,9 +4132,6 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const continue; } - if (first_visible_cell_ == Tabular::npos) - first_visible_cell_ = idx; - pi.selected |= isCellSelected(cur, r, c); int const cx = nx + tabular.textHOffset(idx); int const cy = yy + tabular.textVOffset(idx); @@ -3785,7 +4153,7 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const void InsetTabular::drawBackground(PainterInfo & pi, int x, int y) const { x += ADD_TO_TABULAR_WIDTH; - y += offset_valign_ - tabular.rowAscent(0); + y += tabular.offsetVAlignment() - tabular.rowAscent(0); pi.pain.fillRectangle(x, y, tabular.width(), tabular.height(), pi.backgroundColor(this)); } @@ -3822,7 +4190,7 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const } int const w = tabular.cellWidth(cell); int const h = tabular.cellHeight(cell); - int const yy = y - tabular.rowAscent(r) + offset_valign_; + int const yy = y - tabular.rowAscent(r) + tabular.offsetVAlignment(); if (isCellSelected(cur, r, c)) pi.pain.fillRectangle(xx, yy, w, h, Color_selection); xx += w; @@ -3843,35 +4211,44 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const } +namespace { + +void tabline(PainterInfo const & pi, int x1, int y1, int x2, int y2, + bool drawline, bool heavy = false) +{ + ColorCode const col = drawline ? Color_tabularline : Color_tabularonoffline; + pi.pain.line(x1, y1, x2, y2, pi.textColor(col), + drawline ? Painter::line_solid : Painter::line_onoffdash, + (heavy ? 2 : 1) * Painter::thin_line); +} + +} + + void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y, row_type row, idx_type cell) const { y -= tabular.rowAscent(row); int const w = tabular.cellWidth(cell); int const h = tabular.cellHeight(cell); - Color const linecolor = pi.textColor(Color_tabularline); - Color const gridcolor = pi.textColor(Color_tabularonoffline); // Top bool drawline = tabular.topLine(cell) || (row > 0 && tabular.bottomLine(tabular.cellAbove(cell))); - pi.pain.line(x, y, x + w, y, - drawline ? linecolor : gridcolor, - drawline ? Painter::line_solid : Painter::line_onoffdash); + bool heavy = tabular.use_booktabs && row == 0 && tabular.rowTopLine(row); + tabline(pi, x, y, x + w, y, drawline, heavy); // Bottom drawline = tabular.bottomLine(cell); - pi.pain.line(x, y + h, x + w, y + h, - drawline ? linecolor : gridcolor, - drawline ? Painter::line_solid : Painter::line_onoffdash); + heavy = tabular.use_booktabs && row == tabular.nrows() - 1 + && tabular.rowBottomLine(row); + tabline(pi, x, y + h, x + w, y + h, drawline, heavy); // Left col_type const col = tabular.cellColumn(cell); drawline = tabular.leftLine(cell) || (col > 0 && tabular.rightLine(tabular.cellIndex(row, col - 1))); - pi.pain.line(x, y, x, y + h, - drawline ? linecolor : gridcolor, - drawline ? Painter::line_solid : Painter::line_onoffdash); + tabline(pi, x, y, x, y + h, drawline); // Right x -= tabular.interColumnSpace(cell); @@ -3882,9 +4259,7 @@ void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y, drawline = tabular.rightLine(cell) || (next_cell_col < tabular.ncols() && tabular.leftLine(tabular.cellIndex(row, next_cell_col))); - pi.pain.line(x + w, y, x + w, y + h, - drawline ? linecolor : gridcolor, - drawline ? Painter::line_solid : Painter::line_onoffdash); + tabline(pi, x + w, y, x + w, y + h, drawline); } @@ -3941,13 +4316,36 @@ void InsetTabular::updateBuffer(ParIterator const & it, UpdateType utype) void InsetTabular::addToToc(DocIterator const & cpit, bool output_active, - UpdateType utype) const + UpdateType utype, TocBackend & backend) const { DocIterator dit = cpit; dit.forwardPos(); size_t const end = dit.nargs(); for ( ; dit.idx() < end; dit.top().forwardIdx()) - cell(dit.idx())->addToToc(dit, output_active, utype); + cell(dit.idx())->addToToc(dit, output_active, utype, backend); +} + + +bool InsetTabular::hitSelectRow(BufferView const & bv, int x) const +{ + int const x0 = xo(bv) + ADD_TO_TABULAR_WIDTH; + return x < x0 || x > x0 + tabular.width(); +} + + +bool InsetTabular::hitSelectColumn(BufferView const & bv, int y) const +{ + int const y0 = yo(bv) - tabular.rowAscent(0) + tabular.offsetVAlignment(); + // FIXME: using ADD_TO_TABULAR_WIDTH is not really correct since + // there is no margin added vertically to tabular insets. + // However, it works for now. + return y < y0 + ADD_TO_TABULAR_WIDTH || y > y0 + tabular.height() - ADD_TO_TABULAR_WIDTH; +} + + +bool InsetTabular::clickable(BufferView const & bv, int x, int y) const +{ + return hitSelectRow(bv, x) || hitSelectColumn(bv, y); } @@ -3965,8 +4363,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_MOUSE_PRESS: { //lyxerr << "# InsetTabular::MousePress\n" << cur.bv().cursor() << endl; // select row - if (cmd.x() < xo(cur.bv()) + ADD_TO_TABULAR_WIDTH - || cmd.x() > xo(cur.bv()) + tabular.width()) { + if (hitSelectRow(cur.bv(), cmd.x())) { row_type r = rowFromY(cur, cmd.y()); cur.idx() = tabular.getFirstCellInRow(r); cur.pit() = 0; @@ -3975,15 +4372,13 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.idx() = tabular.getLastCellInRow(r); cur.pit() = cur.lastpit(); cur.pos() = cur.lastpos(); - cur.setSelection(true); + cur.selection(true); bvcur = cur; rowselect_ = true; break; } // select column - int const y0 = yo(cur.bv()) - tabular.rowAscent(0) + offset_valign_; - if (cmd.y() < y0 + ADD_TO_TABULAR_WIDTH - || cmd.y() > y0 + tabular.height()) { + if (hitSelectColumn(cur.bv(), cmd.y())) { col_type c = columnFromX(cur, cmd.x()); cur.idx() = tabular.cellIndex(0, c); cur.pit() = 0; @@ -3992,7 +4387,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.idx() = tabular.cellIndex(tabular.nrows() - 1, c); cur.pit() = cur.lastpit(); cur.pos() = cur.lastpos(); - cur.setSelection(true); + cur.selection(true); bvcur = cur; colselect_ = true; break; @@ -4025,7 +4420,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.pit() = 0; cur.pos() = 0; bvcur.setCursor(cur); - bvcur.setSelection(true); + bvcur.selection(true); break; } // select (additional) column @@ -4037,7 +4432,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.pit() = 0; cur.pos() = 0; bvcur.setCursor(cur); - bvcur.setSelection(true); + bvcur.selection(true); break; } // only update if selection changes @@ -4046,7 +4441,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.noScreenUpdate(); setCursorFromCoordinates(cur, cmd.x(), cmd.y()); bvcur.setCursor(cur); - bvcur.setSelection(true); + bvcur.selection(true); // if this is a multicell selection, we just set the cursor to // the beginning of the cell's text. if (bvcur.selIsMultiCell()) { @@ -4063,12 +4458,12 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CELL_BACKWARD: movePrevCell(cur); - cur.setSelection(false); + cur.selection(false); break; case LFUN_CELL_FORWARD: moveNextCell(cur); - cur.setSelection(false); + cur.selection(false); break; case LFUN_CHAR_FORWARD_SELECT: @@ -4265,41 +4660,6 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.screenUpdateFlags(Update::Force | Update::FitCursor); break; -// case LFUN_SCREEN_DOWN: { -// //if (hasSelection()) -// // cur.selection() = false; -// col_type const col = tabular.cellColumn(cur.idx()); -// int const t = cur.bv().top_y() + cur.bv().height(); -// if (t < yo() + tabular.getHeightOfTabular()) { -// cur.bv().scrollDocView(t, true); -// cur.idx() = tabular.cellBelow(first_visible_cell_) + col; -// } else { -// cur.idx() = tabular.getFirstCellInRow(tabular.rows() - 1) + col; -// } -// cur.par() = 0; -// cur.pos() = 0; -// break; -// } -// -// case LFUN_SCREEN_UP: { -// //if (hasSelection()) -// // cur.selection() = false; -// col_type const col = tabular.cellColumn(cur.idx()); -// int const t = cur.bv().top_y() + cur.bv().height(); -// if (yo() < 0) { -// cur.bv().scrollDocView(t, true); -// if (yo() > 0) -// cur.idx() = col; -// else -// cur.idx() = tabular.cellBelow(first_visible_cell_) + col; -// } else { -// cur.idx() = col; -// } -// cur.par() = cur.lastpar(); -// cur.pos() = cur.lastpos(); -// break; -// } - case LFUN_LAYOUT_TABULAR: cur.bv().showDialog("tabular"); break; @@ -4433,6 +4793,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_FONT_SIZE: case LFUN_FONT_UNDERLINE: case LFUN_FONT_STRIKEOUT: + case LFUN_FONT_CROSSOUT: case LFUN_FONT_UNDERUNDERLINE: case LFUN_FONT_UNDERWAVE: case LFUN_LANGUAGE: @@ -4511,6 +4872,7 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s, switch (action) { case Tabular::SET_PWIDTH: case Tabular::SET_MPWIDTH: + case Tabular::TOGGLE_VARWIDTH_COLUMN: case Tabular::SET_SPECIAL_COLUMN: case Tabular::SET_SPECIAL_MULTICOLUMN: case Tabular::APPEND_ROW: @@ -4526,7 +4888,7 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s, return true; case Tabular::SET_TABULAR_WIDTH: - status.setEnabled(!tabular.rotate && !tabular.is_long_tabular + status.setEnabled(!tabular.rotate && tabular.tabular_valignment == Tabular::LYX_VALIGN_MIDDLE); break; @@ -4649,12 +5011,14 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s, // therefore allow always left but right and center only if there is no width case Tabular::M_ALIGN_LEFT: flag = false; + // fall through case Tabular::ALIGN_LEFT: status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_LEFT); break; case Tabular::M_ALIGN_RIGHT: flag = false; + // fall through case Tabular::ALIGN_RIGHT: status.setEnabled(!(tabular.isMultiRow(cur.idx()) && !tabular.getPWidth(cur.idx()).zero())); @@ -4663,6 +5027,7 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s, case Tabular::M_ALIGN_CENTER: flag = false; + // fall through case Tabular::ALIGN_CENTER: status.setEnabled(!(tabular.isMultiRow(cur.idx()) && !tabular.getPWidth(cur.idx()).zero())); @@ -4683,6 +5048,7 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s, case Tabular::M_VALIGN_TOP: flag = false; + // fall through case Tabular::VALIGN_TOP: status.setEnabled(!tabular.getPWidth(cur.idx()).zero() && !tabular.isMultiRow(cur.idx())); @@ -4692,6 +5058,7 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s, case Tabular::M_VALIGN_BOTTOM: flag = false; + // fall through case Tabular::VALIGN_BOTTOM: status.setEnabled(!tabular.getPWidth(cur.idx()).zero() && !tabular.isMultiRow(cur.idx())); @@ -4701,6 +5068,7 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s, case Tabular::M_VALIGN_MIDDLE: flag = false; + // fall through case Tabular::VALIGN_MIDDLE: status.setEnabled(!tabular.getPWidth(cur.idx()).zero() && !tabular.isMultiRow(cur.idx())); @@ -4904,7 +5272,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, if (&cur.inset() != this) break; string action = cmd.getArg(0); - string arg = cmd.getLongArg(1); + string arg = cmd.getLongArg(1); return getFeatureStatus(cur, action, arg, status); } @@ -4922,7 +5290,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, } // check if there is already a caption bool have_caption = false; - InsetTableCell itc = InsetTableCell(*tabular.cellInset(cur.idx()).get()); + InsetTableCell itc = InsetTableCell(*tabular.cellInset(cur.idx())); ParagraphList::const_iterator pit = itc.paragraphs().begin(); ParagraphList::const_iterator pend = itc.paragraphs().end(); for (; pit != pend; ++pit) { @@ -4979,14 +5347,14 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, status.setEnabled(false); return true; } - // Fall back - case LFUN_NEWLINE_INSERT: { - if (tabular.getPWidth(cur.idx()).zero()) { + // fall through + case LFUN_NEWLINE_INSERT: + if ((tabular.isMultiColumn(cur.idx()) || tabular.isMultiRow(cur.idx())) + && tabular.getPWidth(cur.idx()).zero()) { status.setEnabled(false); return true; - } else - return cell(cur.idx())->getStatus(cur, cmd, status); - } + } + return cell(cur.idx())->getStatus(cur, cmd, status); case LFUN_NEWPAGE_INSERT: status.setEnabled(false); @@ -5093,13 +5461,7 @@ docstring InsetTabular::xhtml(XHTMLStream & xs, OutputParams const & rp) const void InsetTabular::validate(LaTeXFeatures & features) const { tabular.validate(features); - // 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. - if (features.runparams().flavor == OutputParams::HTML) - features.addCSSSnippet( - "table { border: 1px solid black; display: inline-block; }\n" - "td { border: 1px solid black; padding: 0.5ex; }"); + features.useInsetLayout(getLayout()); } @@ -5123,7 +5485,7 @@ void InsetTabular::cursorPos(BufferView const & bv, // y offset correction y += cellYPos(sl.idx()); y += tabular.textVOffset(sl.idx()); - y += offset_valign_; + y += tabular.offsetVAlignment(); // x offset correction x += cellXPos(sl.idx()); @@ -5166,7 +5528,6 @@ int InsetTabular::dist(BufferView & bv, idx_type const cell, int x, int y) const Inset * InsetTabular::editXY(Cursor & cur, int x, int y) { //lyxerr << "InsetTabular::editXY: " << this << endl; - cur.setSelection(false); cur.push(*this); cur.idx() = getNearestCell(cur.bv(), x, y); return cur.bv().textMetrics(&cell(cur.idx())->text()).editXY(cur, x, y); @@ -5338,6 +5699,8 @@ void InsetTabular::tabularFeatures(Cursor & cur, string const & argument) cur.recordUndoInset(this); istringstream is(argument); + // limit the size of strings we read to avoid memory problems + is >> setw(65636); string s; // Safe guard. size_t safe_guard = 0; @@ -5477,10 +5840,12 @@ void InsetTabular::tabularFeatures(Cursor & cur, 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()); + for (col_type c = sel_col_start; c <= sel_col_end; ++c) { + tabular.setColumnPWidth(cur, tabular.cellIndex(row, c), len); + if (len.zero() + && tabular.getAlignment(tabular.cellIndex(row, c), true) == LYX_ALIGN_BLOCK) + tabularFeatures(cur, Tabular::ALIGN_CENTER, string()); + } break; } @@ -5488,6 +5853,13 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.setMColumnPWidth(cur, cur.idx(), Length(value)); break; + case Tabular::TOGGLE_VARWIDTH_COLUMN: { + bool const varwidth = value == "on"; + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.toggleVarwidth(tabular.cellIndex(row, c), varwidth); + break; + } + case Tabular::SET_MROFFSET: tabular.setMROffset(cur, cur.idx(), Length(value)); break; @@ -5525,7 +5897,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, cur.idx() = tabular.cellIndex(sel_row_start, column); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; case Tabular::DELETE_COLUMN: @@ -5548,7 +5920,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, cur.idx() = tabular.cellIndex(row, sel_col_start); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; case Tabular::COPY_ROW: @@ -5638,6 +6010,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::M_VALIGN_BOTTOM: case Tabular::M_VALIGN_MIDDLE: flag = false; + // fall through case Tabular::VALIGN_TOP: case Tabular::VALIGN_BOTTOM: case Tabular::VALIGN_MIDDLE: @@ -5651,7 +6024,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, // just multicol for one single cell // check whether we are completely in a multicol if (!tabular.isMultiColumn(cur.idx())) - tabular.setMultiColumn(cur.idx(), 1, + tabular.setMultiColumn(cur, cur.idx(), 1, tabular.rightLine(cur.idx())); break; } @@ -5660,11 +6033,11 @@ void InsetTabular::tabularFeatures(Cursor & cur, idx_type const s_start = cur.selBegin().idx(); row_type const col_start = tabular.cellColumn(s_start); row_type const col_end = tabular.cellColumn(cur.selEnd().idx()); - cur.idx() = tabular.setMultiColumn(s_start, col_end - col_start + 1, + cur.idx() = tabular.setMultiColumn(cur, s_start, col_end - col_start + 1, tabular.rightLine(cur.selEnd().idx())); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; } @@ -5706,7 +6079,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, // 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, cur.idx(), 1, tabular.bottomLine(cur.idx()), tabular.getAlignment(cur.idx())); break; @@ -5716,12 +6089,12 @@ void InsetTabular::tabularFeatures(Cursor & cur, 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(cur, s_start, row_end - row_start + 1, tabular.bottomLine(cur.selEnd().idx()), tabular.getAlignment(cur.selEnd().idx())); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; } @@ -5760,6 +6133,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::SET_ALL_LINES: setLines = true; + // fall through case Tabular::UNSET_ALL_LINES: for (row_type r = sel_row_start; r <= sel_row_end; ++r) for (col_type c = sel_col_start; c <= sel_col_end; ++c) { @@ -5842,8 +6216,6 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.longtabular_alignment = Tabular::LYX_LONGTABULAR_ALIGN_RIGHT; break; - - case Tabular::SET_ROTATE_CELL: for (row_type r = sel_row_start; r <= sel_row_end; ++r) for (col_type c = sel_col_start; c <= sel_col_end; ++c) @@ -5884,6 +6256,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::UNSET_LTFIRSTHEAD: flag = false; + // fall through case Tabular::SET_LTFIRSTHEAD: tabular.getRowOfLTFirstHead(row, ltt); checkLongtableSpecial(ltt, value, flag); @@ -5892,6 +6265,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::UNSET_LTHEAD: flag = false; + // fall through case Tabular::SET_LTHEAD: tabular.getRowOfLTHead(row, ltt); checkLongtableSpecial(ltt, value, flag); @@ -5900,6 +6274,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::UNSET_LTFOOT: flag = false; + // fall through case Tabular::SET_LTFOOT: tabular.getRowOfLTFoot(row, ltt); checkLongtableSpecial(ltt, value, flag); @@ -5908,6 +6283,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::UNSET_LTLASTFOOT: flag = false; + // fall through case Tabular::SET_LTLASTFOOT: tabular.getRowOfLTLastFoot(row, ltt); checkLongtableSpecial(ltt, value, flag); @@ -5916,6 +6292,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::UNSET_LTNEWPAGE: flag = false; + // fall through case Tabular::SET_LTNEWPAGE: tabular.setLTNewPage(row, flag); break; @@ -5923,10 +6300,10 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::SET_LTCAPTION: { if (tabular.ltCaption(row)) break; - cur.idx() = tabular.setLTCaption(row, true); + cur.idx() = tabular.setLTCaption(cur, row, true); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); // If a row is set as caption, then also insert // a caption. Otherwise the LaTeX output is broken. // Select cell if it is non-empty @@ -5939,10 +6316,10 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::UNSET_LTCAPTION: { if (!tabular.ltCaption(row)) break; - cur.idx() = tabular.setLTCaption(row, false); + cur.idx() = tabular.setLTCaption(cur, row, false); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); FuncRequest fr(LFUN_INSET_DISSOLVE, "caption"); if (lyx::getStatus(fr).enabled()) lyx::dispatch(fr); @@ -6118,6 +6495,7 @@ bool InsetTabular::pasteClipboard(Cursor & cur) inset->setChange(Change(buffer().params().track_changes ? Change::INSERTED : Change::UNCHANGED)); cur.pos() = 0; + cur.pit() = 0; } } return true; @@ -6194,12 +6572,12 @@ void InsetTabular::getSelection(Cursor & cur, cs = tabular.cellColumn(beg.idx()); ce = tabular.cellColumn(end.idx()); if (cs > ce) - swap(cs, ce); + std::swap(cs, ce); rs = tabular.cellRow(beg.idx()); re = tabular.cellRow(end.idx()); if (rs > re) - swap(rs, re); + std::swap(rs, re); } @@ -6238,7 +6616,7 @@ bool InsetTabular::allowParagraphCustomization(idx_type cell) const bool InsetTabular::forcePlainLayout(idx_type cell) const { - return !tabular.getPWidth(cell).zero(); + return tabular.isMultiColumn(cell) && !tabular.getPWidth(cell).zero(); }