X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetTabular.cpp;h=9df7d463c3832dde51d9d04e4bd87868c4b9a12a;hb=ebc2b1295a0464dde6c20a09ddc249c463a21c79;hp=4425c0aed225704083e52b4564f0e5aa3c00058e;hpb=55462786d0286b2c00e5961f517497d36d109052;p=lyx.git diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index 4425c0aed2..9df7d463c3 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -127,12 +127,20 @@ TabularFeature tabularFeature[] = { Tabular::MOVE_ROW_UP, "move-row-up", false }, { Tabular::SET_LINE_TOP, "set-line-top", true }, { Tabular::SET_LINE_BOTTOM, "set-line-bottom", true }, + { Tabular::SET_LTRIM_TOP, "set-ltrim-top", true }, + { Tabular::SET_LTRIM_BOTTOM, "set-ltrim-bottom", true }, + { Tabular::SET_RTRIM_TOP, "set-rtrim-top", true }, + { Tabular::SET_RTRIM_BOTTOM, "set-rtrim-bottom", true }, { Tabular::SET_LINE_LEFT, "set-line-left", true }, { Tabular::SET_LINE_RIGHT, "set-line-right", true }, { Tabular::TOGGLE_LINE_TOP, "toggle-line-top", false }, { Tabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom", false }, { Tabular::TOGGLE_LINE_LEFT, "toggle-line-left", false }, { Tabular::TOGGLE_LINE_RIGHT, "toggle-line-right", false }, + { Tabular::TOGGLE_LTRIM_TOP, "toggle-ltrim-top", false }, + { Tabular::TOGGLE_LTRIM_BOTTOM, "toggle-ltrim-bottom", false }, + { Tabular::TOGGLE_RTRIM_TOP, "toggle-rtrim-top", false }, + { Tabular::TOGGLE_RTRIM_BOTTOM, "toggle-rtrim-bottom", false }, { Tabular::ALIGN_LEFT, "align-left", false }, { Tabular::ALIGN_RIGHT, "align-right", false }, { Tabular::ALIGN_CENTER, "align-center", false }, @@ -155,12 +163,14 @@ TabularFeature tabularFeature[] = { Tabular::UNSET_MULTIROW, "unset-multirow", false }, { Tabular::SET_MROFFSET, "set-mroffset", true }, { Tabular::SET_ALL_LINES, "set-all-lines", false }, + { Tabular::RESET_FORMAL_DEFAULT, "reset-formal-default", false }, { Tabular::UNSET_ALL_LINES, "unset-all-lines", false }, { Tabular::TOGGLE_LONGTABULAR, "toggle-longtabular", false }, { Tabular::SET_LONGTABULAR, "set-longtabular", false }, { 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 }, @@ -198,6 +208,7 @@ TabularFeature tabularFeature[] = { 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::SET_INNER_LINES, "set-inner-lines", false }, { Tabular::LAST_ACTION, "", false } }; @@ -263,6 +274,8 @@ string const tostr(Tabular::BoxType const & num) return "parbox"; case Tabular::BOX_MINIPAGE: return "minipage"; + case Tabular::BOX_VARWIDTH: + return "varwidth"; } return string(); } @@ -325,6 +338,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; @@ -578,6 +593,10 @@ Tabular::CellData::CellData(Buffer * buf) bottom_line(false), left_line(false), right_line(false), + top_line_rtrimmed(false), + top_line_ltrimmed(false), + bottom_line_rtrimmed(false), + bottom_line_ltrimmed(false), usebox(BOX_NONE), rotate(0), inset(new InsetTableCell(buf)) @@ -601,6 +620,10 @@ Tabular::CellData::CellData(CellData const & cs) bottom_line(cs.bottom_line), left_line(cs.left_line), right_line(cs.right_line), + top_line_rtrimmed(cs.top_line_rtrimmed), + top_line_ltrimmed(cs.top_line_ltrimmed), + bottom_line_rtrimmed(cs.bottom_line_rtrimmed), + bottom_line_ltrimmed(cs.bottom_line_ltrimmed), usebox(cs.usebox), rotate(cs.rotate), align_special(cs.align_special), @@ -627,6 +650,10 @@ Tabular::CellData & Tabular::CellData::operator=(CellData const & cs) bottom_line = cs.bottom_line; left_line = cs.left_line; right_line = cs.right_line; + top_line_rtrimmed = cs.top_line_rtrimmed; + top_line_ltrimmed = cs.top_line_ltrimmed; + bottom_line_rtrimmed = cs.bottom_line_rtrimmed; + bottom_line_rtrimmed = cs.bottom_line_rtrimmed; usebox = cs.usebox; rotate = cs.rotate; align_special = cs.align_special; @@ -653,7 +680,8 @@ Tabular::RowData::RowData() Tabular::ColumnData::ColumnData() : alignment(LYX_ALIGN_CENTER), valignment(LYX_VALIGN_TOP), - width(0) + width(0), + varwidth(false) { } @@ -911,8 +939,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)) { @@ -920,8 +951,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; @@ -951,22 +985,40 @@ bool Tabular::bottomLine(idx_type const cell) const } -bool Tabular::leftLine(idx_type cell) const +bool Tabular::leftLine(idx_type cell, bool const ignore_bt) const { - if (use_booktabs) + if (use_booktabs && !ignore_bt) return false; return cellInfo(cell).left_line; } -bool Tabular::rightLine(idx_type cell) const +bool Tabular::rightLine(idx_type cell, bool const ignore_bt) const { - if (use_booktabs) + if (use_booktabs && !ignore_bt) return false; return cellInfo(cell).right_line; } +pair Tabular::topLineTrim(idx_type const cell) const +{ + if (!use_booktabs) + return make_pair(false, false); + return make_pair(cellInfo(cell).top_line_ltrimmed, + cellInfo(cell).top_line_rtrimmed); +} + + +pair Tabular::bottomLineTrim(idx_type const cell) const +{ + if (!use_booktabs) + return make_pair(false, false); + return make_pair(cellInfo(cell).bottom_line_ltrimmed, + cellInfo(cell).bottom_line_rtrimmed); +} + + int Tabular::interRowSpace(row_type row) const { if (!row || row >= nrows()) @@ -1017,15 +1069,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 @@ -1038,14 +1135,23 @@ bool Tabular::updateColumnWidths() && 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 @@ -1062,7 +1168,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; } } @@ -1124,14 +1232,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 @@ -1139,6 +1249,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 @@ -1165,16 +1288,13 @@ void Tabular::setColumnPWidth(Cursor & cur, idx_type cell, idx_type const cidx = cellIndex(r, c); // because of multicolumns toggleFixedWidth(cur, cellInset(cidx).get(), - !getPWidth(cidx).zero()); + !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(); } @@ -1195,13 +1315,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; } @@ -1235,6 +1359,42 @@ void Tabular::setBottomLine(idx_type i, bool line) } +void Tabular::setTopLineLTrim(idx_type i, bool val) +{ + cellInfo(i).top_line_ltrimmed = val; +} + + +void Tabular::setTopLineRTrim(idx_type i, bool val) +{ + cellInfo(i).top_line_rtrimmed = val; +} + + +void Tabular::setBottomLineLTrim(idx_type i, bool val) +{ + cellInfo(i).bottom_line_ltrimmed = val; +} + + +void Tabular::setBottomLineRTrim(idx_type i, bool val) +{ + cellInfo(i).bottom_line_rtrimmed = val; +} + + +void Tabular::setTopLineTrim(idx_type i, pair trim) +{ + setTopLineLTrim(i, trim.first); + setTopLineRTrim(i, trim.second); +} + +void Tabular::setBottomLineTrim(idx_type i, pair trim) +{ + setBottomLineLTrim(i, trim.first); + setBottomLineRTrim(i, trim.second); +} + void Tabular::setLeftLine(idx_type cell, bool line) { cellInfo(cell).left_line = line; @@ -1482,10 +1642,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"; @@ -1496,6 +1655,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"; } @@ -1529,7 +1689,11 @@ void Tabular::write(ostream & os) const << write_attribute("alignment", cell_info[r][c].alignment) << write_attribute("valignment", cell_info[r][c].valignment) << write_attribute("topline", cell_info[r][c].top_line) + << write_attribute("toplineltrim", cell_info[r][c].top_line_ltrimmed) + << write_attribute("toplinertrim", cell_info[r][c].top_line_rtrimmed) << write_attribute("bottomline", cell_info[r][c].bottom_line) + << write_attribute("bottomlineltrim", cell_info[r][c].bottom_line_ltrimmed) + << write_attribute("bottomlinertrim", cell_info[r][c].bottom_line_rtrimmed) << write_attribute("leftline", cell_info[r][c].left_line) << write_attribute("rightline", cell_info[r][c].right_line) << write_attribute("rotate", cell_info[r][c].rotate) @@ -1608,6 +1772,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) { @@ -1642,7 +1807,11 @@ void Tabular::read(Lexer & lex) getTokenValue(line, "alignment", cell_info[i][j].alignment); getTokenValue(line, "valignment", cell_info[i][j].valignment); getTokenValue(line, "topline", cell_info[i][j].top_line); + getTokenValue(line, "toplineltrim", cell_info[i][j].top_line_ltrimmed); + getTokenValue(line, "toplinertrim", cell_info[i][j].top_line_rtrimmed); getTokenValue(line, "bottomline", cell_info[i][j].bottom_line); + getTokenValue(line, "bottomlineltrim", cell_info[i][j].bottom_line_ltrimmed); + getTokenValue(line, "bottomlinertrim", cell_info[i][j].bottom_line_rtrimmed); getTokenValue(line, "leftline", cell_info[i][j].left_line); getTokenValue(line, "rightline", cell_info[i][j].right_line); getTokenValue(line, "rotate", cell_info[i][j].rotate); @@ -1693,6 +1862,27 @@ bool Tabular::hasMultiColumn(col_type c) 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)]; @@ -1705,7 +1895,7 @@ Tabular::CellData & Tabular::cellInfo(idx_type cell) } -Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number, +Tabular::idx_type Tabular::setMultiColumn(Cursor & cur, idx_type cell, idx_type number, bool const right_border) { idx_type const col = cellColumn(cell); @@ -1720,6 +1910,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) { @@ -1748,7 +1946,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) { @@ -1771,6 +1969,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); @@ -1916,16 +2123,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); } @@ -2054,11 +2260,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); @@ -2174,24 +2380,39 @@ 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, topltrims, toprtrims; col_type nset = 0; - for (col_type c = 0; c < ncols(); ++c) { - topline.push_back(topLine(cellIndex(row, c))); + bool have_trims = false; + for (auto const & c : columns) { + topline[c] = topLine(cellIndex(row, c)); + topltrims[c] = topLineTrim(cellIndex(row, c)).first; + toprtrims[c] = topLineTrim(cellIndex(row, c)).second; // 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) + && cell_info[row][c].multirow != CELL_BEGIN_OF_MULTIROW) { topline[c] = false; - if (topline[c]) + topltrims[c] = false; + toprtrims[c] = false; + } + // copy trimming to multicolumn parts + if (isPartOfMultiColumn(row, c)) { + topltrims[c] = topltrims[c-1]; + toprtrims[c] = toprtrims[c-1]; + } + if (topline.find(c) != topline.end() && topline.find(c)->second) ++nset; + if ((topltrims.find(c) != topltrims.end() && topltrims.find(c)->second) + || (toprtrims.find(c) != toprtrims.end() && toprtrims.find(c)->second)) + have_trims = true; } // do nothing if empty first row, or incomplete row line after @@ -2199,36 +2420,66 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang) co return; // only output complete row lines and the 1st row's clines - if (nset == ncols()) { + if (nset == ncols() && !have_trims) { if (use_booktabs) { os << (row == 0 ? "\\toprule " : "\\midrule "); } else { os << "\\hline "; } - } else if (row == 0) { - for (col_type c = 0; c < ncols(); ++c) { - if (topline[c]) { + } else if (row == 0 || have_trims) { + string const cline = use_booktabs ? "\\cmidrule" : "\\cline"; + 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) ++offset; - - //babel makes the "-" character an active one, so we have to suppress this here - //see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289# - if (lang == "slovak" || lang == "czech") - os << "\\expandafter" << (use_booktabs ? "\\cmidrule" : "\\cline") - << "\\expandafter{\\expandafter" << c + 1 + offset << "\\string-"; - else - os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 + offset << '-'; - + while (isPartOfMultiColumn(row, c)) + ++c; + string trim; + if (topltrims.find(c) != topltrims.end() + && topltrims.find(c)->second) + trim = "l"; + string const firstcol = convert(c + 1 + offset); col_type cstart = c; - for ( ; c < ncols() && topline[c]; ++c) {} + for ( ; c < ncols() - 1 && topline.find(c)->second ; ++c) { + if (isMultiColumn(cellIndex(row, c)) + && c < ncols() - 1 && isPartOfMultiColumn(row, c + 1)) + continue; + if (c > cstart && topltrims.find(c) != topltrims.end() + && topltrims.find(c)->second) { + if (!isPartOfMultiColumn(row, c)) + --c; + break; + } else if (toprtrims.find(c) != toprtrims.end() + && toprtrims.find(c)->second) + break; + } for (col_type j = cstart ; j < c ; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) ++offset; + col_type const lastcol = c + 1 + offset; + if (toprtrims.find(c) != toprtrims.end() + && toprtrims.find(c)->second) + trim += "r"; - os << c + offset << "} "; + //babel makes the "-" character an active one, so we have to suppress this here + //see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289# + if (lang == "slovak" || lang == "czech") { + os << "\\expandafter" << cline; + if (!trim.empty()) + os << "(" << trim << ")"; + os << "\\expandafter{\\expandafter" << firstcol << "\\string-"; + } else { + os << cline; + if (!trim.empty()) + os << "(" << trim << ")"; + os << "{" << firstcol << '-'; + } + os << lastcol << "}"; + if (c == ncols() - 1) + break; } } } @@ -2236,18 +2487,24 @@ 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, topltrims, toprtrims, bottomltrims, bottomrtrims; 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) { + idx_type const idx = cellIndex(row, c); + bottomline[c] = bottomLine(cellIndex(row, c)); + bottomltrims[c] = bottomLineTrim(idx).first; + bottomrtrims[c] = bottomLineTrim(idx).second; + topline[c] = !lastrow && topLine(cellIndex(row + 1, c)); + topltrims[c] = !lastrow && topLineTrim(cellIndex(row + 1, c)).first; + toprtrims[c] = !lastrow && topLineTrim(cellIndex(row + 1, c)).second; // If cell is part of a multirow and not the last cell of the // multirow, no line must be drawn. if (!lastrow) @@ -2256,52 +2513,103 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang) && cell_info[row + 1][c].multirow != CELL_BEGIN_OF_MULTIROW) { bottomline[c] = false; topline[c] = false; - } - nextrowset &= topline[c]; + bottomltrims[c] = false; + bottomrtrims[c] = false; + topltrims[c] = false; + toprtrims[c] = false; + } + // copy trimming in multicolumn parts + if (isPartOfMultiColumn(row, c)) { + topltrims[c] = topltrims[c-1]; + toprtrims[c] = toprtrims[c-1]; + bottomltrims[c] = bottomltrims[c-1]; + bottomrtrims[c] = bottomrtrims[c-1]; + } + + 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) { + bool have_trims = false; + 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; + bottomltrims[c] = (bottomltrims.find(c) != bottomltrims.end() && bottomltrims.find(c)->second) + || (topltrims.find(c) != topltrims.end() && topltrims.find(c)->second); + bottomrtrims[c] =(bottomrtrims.find(c) != bottomrtrims.end() && bottomrtrims.find(c)->second) + || (toprtrims.find(c) != toprtrims.end() && toprtrims.find(c)->second); + if (bottomline.find(c)->second) ++nset; + if ((bottomltrims.find(c) != bottomltrims.end() && bottomltrims.find(c)->second) + || (bottomrtrims.find(c) != bottomrtrims.end() && bottomrtrims.find(c)->second)) + have_trims = true; } // do nothing if empty, OR incomplete row line with a topline in next row if (nset == 0 || (nextrowset && nset != ncols())) return; - if (nset == ncols()) { + if (nset == ncols() && !have_trims) { if (use_booktabs) os << (lastrow ? "\\bottomrule" : "\\midrule"); else os << "\\hline "; } else { - for (col_type c = 0; c < ncols(); ++c) { - if (bottomline[c]) { + string const cline = use_booktabs ? "\\cmidrule" : "\\cline"; + 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) ++offset; - - //babel makes the "-" character an active one, so we have to suppress this here - //see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289# - if (lang == "slovak" || lang == "czech") - os << "\\expandafter" << (use_booktabs ? "\\cmidrule" : "\\cline") - << "\\expandafter{\\expandafter" << c + 1 + offset << "\\string-"; - else - os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 + offset << '-'; - + while (isPartOfMultiColumn(row, c)) + ++c; + string trim; + if (bottomltrims.find(c) != bottomltrims.end() + && bottomltrims.find(c)->second) + trim = "l"; + string const firstcol = convert(c + 1 + offset); col_type cstart = c; - for ( ; c < ncols() && bottomline[c]; ++c) {} + for ( ; c < ncols() - 1 && bottomline.find(c)->second ; ++c) { + if (isMultiColumn(cellIndex(row, c)) + && c < ncols() - 1 + && isPartOfMultiColumn(row, c + 1)) + continue; + if (c > cstart && bottomltrims.find(c) != bottomltrims.end() + && bottomltrims.find(c)->second) { + if (!isPartOfMultiColumn(row, c)) + --c; + break; + } else if (bottomrtrims.find(c) != bottomrtrims.end() + && bottomrtrims.find(c)->second) + break; + } for (col_type j = cstart ; j < c ; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) ++offset; + col_type const lastcol = c + 1 + offset; + if (bottomrtrims.find(c) != bottomrtrims.end() + && bottomrtrims.find(c)->second) + trim += "r"; - os << c + offset << "} "; + //babel makes the "-" character an active one, so we have to suppress this here + //see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289# + if (lang == "slovak" || lang == "czech") { + os << "\\expandafter" << cline; + if (!trim.empty()) + os << "(" << trim << ")"; + os << "\\expandafter{\\expandafter" << firstcol << "\\string-"; + } else { + os << cline; + if (!trim.empty()) + os << "(" << trim << ")"; + os << "{" << firstcol << '-'; + } + os << lastcol << "}"; + if (c == ncols() - 1) + break; } } } @@ -2310,7 +2618,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) @@ -2320,8 +2629,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); @@ -2330,28 +2641,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), align_d); - ismulticol |= !dit; + 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; @@ -2398,9 +2716,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 << "}{"; @@ -2454,7 +2772,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"; +} } @@ -2470,6 +2802,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) @@ -2480,7 +2814,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; @@ -2492,7 +2827,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 @@ -2501,7 +2836,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"; @@ -2515,7 +2850,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"; @@ -2527,7 +2862,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"; @@ -2541,7 +2876,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"; @@ -2561,7 +2896,8 @@ 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); InsetTableCell const * cinset = cellInset(cell); @@ -2569,7 +2905,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, string const clang = cpar.getParLanguage(buffer().params())->lang(); //output the top line - TeXTopHLine(os, row, clang); + TeXTopHLine(os, row, clang, columns); if (row_info[row].top_space_default) { if (use_booktabs) @@ -2589,7 +2925,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; @@ -2597,12 +2941,12 @@ 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); + TeXCellPreamble(os, cell, ismulticol, ismultirow, bidi_rtl); InsetTableCell const * inset = cellInset(cell); Paragraph const & par = inset->paragraphs().front(); @@ -2644,14 +2988,24 @@ void Tabular::TeXRow(otexstream & os, row_type row, 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 @@ -2675,7 +3029,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 @@ -2698,7 +3052,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, os << '\n'; //output the bottom line - TeXBottomHLine(os, row, clang); + TeXBottomHLine(os, row, clang, columns); if (row_info[row].interline_space_default) { if (use_booktabs) @@ -2720,7 +3074,10 @@ 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(); + 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); //+--------------------------------------------------------------------- @@ -2731,25 +3088,45 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const if (!TexRow::isNone(pos)) os.texrow().start(pos); - if (rotate != 0 && !is_long_tabular) - 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: @@ -2768,8 +3145,21 @@ 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; @@ -2791,11 +3181,15 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const case LYX_ALIGN_LAYOUT: case LYX_ALIGN_SPECIAL: break; - case LYX_ALIGN_DECIMAL: - os << ">{\\raggedleft}"; + case LYX_ALIGN_DECIMAL: { + if (bidi_rtl) + os << ">{\\raggedright}"; + else + os << ">{\\raggedleft}"; decimal = true; break; } + } char valign = 'p'; switch (column_info[c].valignment) { @@ -2833,6 +3227,44 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const 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: @@ -2850,12 +3282,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) + @@ -2863,7 +3295,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"; } @@ -2873,17 +3305,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 && !is_long_tabular) - 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); @@ -3426,15 +3867,30 @@ 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 @@ -3450,16 +3906,19 @@ void Tabular::validate(LaTeXFeatures & features) const } -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; } @@ -3473,13 +3932,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); } @@ -3546,6 +4005,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; +} + + ///////////////////////////////////////////////////////////////////// // @@ -3691,8 +4177,10 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const Length const p_width = tabular.getPWidth(cell); if (!p_width.zero()) 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()) + 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); @@ -3759,15 +4247,17 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const tabular.setRowDescent(r, maxdes + ADD_TO_HEIGHT + bottom_space); } - tabular.updateColumnWidths(); + // 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()) { @@ -3905,35 +4395,73 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const } +namespace { + +void tabline(PainterInfo const & pi, int x1, int y1, int x2, int y2, int lt, int rt, + bool drawline, bool heavy = false) +{ + ColorCode const col = drawline ? Color_tabularline : Color_tabularonoffline; + if (drawline && lt > 0) + pi.pain.line(x1, y1, x1 + lt, y2, pi.textColor(Color_tabularonoffline), + Painter::line_onoffdash, + Painter::thin_line); + pi.pain.line(x1 + lt, y1, x2 - rt, y2, pi.textColor(col), + drawline ? Painter::line_solid : Painter::line_onoffdash, + (heavy ? 2 : 1) * Painter::thin_line); + if (drawline && rt > 0) + pi.pain.line(x2 - rt, y1, x2, y2, pi.textColor(Color_tabularonoffline), + Painter::line_onoffdash, + 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); + int lt = 0; + int rt = 0; + + col_type const col = tabular.cellColumn(cell); // 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); + if (tabular.topLineTrim(cell).first + || (row > 0 && tabular.bottomLineTrim(tabular.cellIndex(row - 1, col)).first)) + lt = 10; + if (tabular.topLineTrim(cell).second + || (row > 0 && tabular.bottomLineTrim(tabular.cellIndex(row - 1, col)).second)) + rt = 10; + tabline(pi, x, y, x + w, y, lt, rt, drawline, heavy); // Bottom + lt = rt = 0; drawline = tabular.bottomLine(cell); - pi.pain.line(x, y + h, x + w, y + h, - drawline ? linecolor : gridcolor, - drawline ? Painter::line_solid : Painter::line_onoffdash); + row_type const lastrow = tabular.nrows() - 1; + // Consider multi-rows + row_type r = row; + while (r < lastrow && tabular.isMultiRow(tabular.cellIndex(r, col)) + && tabular.isPartOfMultiRow(r + 1, col)) + r++; + heavy = tabular.use_booktabs + && ((row == lastrow && tabular.rowBottomLine(row)) + || (r == lastrow && tabular.rowBottomLine(r))); + if (tabular.bottomLineTrim(cell).first) + lt = 10; + if (tabular.bottomLineTrim(cell).second) + rt = 10; + tabline(pi, x, y + h, x + w, y + h, lt, rt, 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, 0, 0, drawline); // Right x -= tabular.interColumnSpace(cell); @@ -3944,9 +4472,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, 0, 0, drawline); } @@ -4456,6 +4982,18 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_PASTE: if (!tabularStackDirty()) { + // Check if we have plain text or HTML with rows/columns. + // and if so, pass over to LFUN_CLIPBOARD_PASTE + if (theClipboard().hasTextContents(Clipboard::AnyTextType) + && !theClipboard().hasTextContents(Clipboard::LyXTextType)) { + docstring const clip = + theClipboard().getAsText(Clipboard::AnyTextType); + if (clip.find_first_of(from_ascii("\t\n")) != docstring::npos) { + FuncRequest ncmd = FuncRequest(LFUN_CLIPBOARD_PASTE, cmd.argument()); + doDispatch(cur, ncmd); + break; + } + } if (!cur.selIsMultiCell()) cell(cur.idx())->dispatch(cur, cmd); break; @@ -4559,6 +5097,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: @@ -4574,7 +5113,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; @@ -4655,10 +5194,15 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s, case Tabular::SET_ALL_LINES: case Tabular::UNSET_ALL_LINES: + case Tabular::SET_INNER_LINES: case Tabular::SET_BORDER_LINES: status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); break; + case Tabular::RESET_FORMAL_DEFAULT: + status.setEnabled(tabular.use_booktabs); + break; + case Tabular::SET_LINE_TOP: case Tabular::SET_LINE_BOTTOM: status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); @@ -4670,6 +5214,20 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s, && !tabular.ltCaption(tabular.cellRow(cur.idx()))); break; + case Tabular::SET_LTRIM_TOP: + case Tabular::SET_RTRIM_TOP: + status.setEnabled(tabular.use_booktabs + && tabular.cellRow(cur.idx()) != 0 + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); + break; + + case Tabular::SET_LTRIM_BOTTOM: + case Tabular::SET_RTRIM_BOTTOM: + status.setEnabled(tabular.use_booktabs + && tabular.cellRow(cur.idx()) != tabular.nrows() - 1 + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); + break; + case Tabular::TOGGLE_LINE_TOP: status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); status.setOnOff(tabular.topLine(cur.idx())); @@ -4692,6 +5250,30 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s, status.setOnOff(tabular.rightLine(cur.idx())); break; + case Tabular::TOGGLE_LTRIM_TOP: + status.setEnabled(tabular.use_booktabs + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setOnOff(tabular.topLineTrim(cur.idx()).first); + break; + + case Tabular::TOGGLE_RTRIM_TOP: + status.setEnabled(tabular.use_booktabs + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setOnOff(tabular.topLineTrim(cur.idx()).second); + break; + + case Tabular::TOGGLE_LTRIM_BOTTOM: + status.setEnabled(tabular.use_booktabs + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setOnOff(tabular.bottomLineTrim(cur.idx()).first); + break; + + case Tabular::TOGGLE_RTRIM_BOTTOM: + status.setEnabled(tabular.use_booktabs + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setOnOff(tabular.bottomLineTrim(cur.idx()).second); + break; + // multirow cells only inherit the alignment of the column if the column has // no width, otherwise they are left-aligned // therefore allow always left but right and center only if there is no width @@ -5002,6 +5584,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, // disable these with multiple cells selected case LFUN_INSET_INSERT: case LFUN_TABULAR_INSERT: + case LFUN_TABULAR_STYLE_INSERT: case LFUN_FLEX_INSERT: case LFUN_FLOAT_INSERT: case LFUN_FLOAT_WIDE_INSERT: @@ -5034,13 +5617,13 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, return true; } // fall through - case LFUN_NEWLINE_INSERT: { - if (tabular.getPWidth(cur.idx()).zero()) { + 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); @@ -5465,6 +6048,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, row_type sel_row_start; row_type sel_row_end; bool setLines = false; + bool setLinesInnerOnly = false; LyXAlignment setAlign = LYX_ALIGN_LEFT; Tabular::VAlignment setVAlign = Tabular::LYX_VALIGN_TOP; @@ -5526,10 +6110,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; } @@ -5537,6 +6123,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; @@ -5562,9 +6155,12 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::DELETE_ROW: if (sel_row_end == tabular.nrows() - 1 && sel_row_start != 0) { - for (col_type c = 0; c < tabular.ncols(); c++) + for (col_type c = 0; c < tabular.ncols(); c++) { tabular.setBottomLine(tabular.cellIndex(sel_row_start - 1, c), tabular.bottomLine(tabular.cellIndex(sel_row_end, c))); + tabular.setBottomLineTrim(tabular.cellIndex(sel_row_start - 1, c), + tabular.bottomLineTrim(tabular.cellIndex(sel_row_end, c))); + } } for (row_type r = sel_row_start; r <= sel_row_end; ++r) @@ -5649,6 +6245,46 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; } + case Tabular::SET_LTRIM_TOP: + case Tabular::TOGGLE_LTRIM_TOP: { + bool l = (feature == Tabular::SET_LTRIM_TOP) + ? (value == "true") : !tabular.topLineTrim(cur.idx()).first; + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setTopLineLTrim(tabular.cellIndex(r, c), l); + break; + } + + case Tabular::SET_RTRIM_TOP: + case Tabular::TOGGLE_RTRIM_TOP: { + bool l = (feature == Tabular::SET_RTRIM_TOP) + ? (value == "true") : !tabular.topLineTrim(cur.idx()).second; + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setTopLineRTrim(tabular.cellIndex(r, c), l); + break; + } + + case Tabular::SET_LTRIM_BOTTOM: + case Tabular::TOGGLE_LTRIM_BOTTOM: { + bool l = (feature == Tabular::SET_LTRIM_BOTTOM) + ? (value == "true") : !tabular.bottomLineTrim(cur.idx()).first; + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setBottomLineLTrim(tabular.cellIndex(r, c), l); + break; + } + + case Tabular::SET_RTRIM_BOTTOM: + case Tabular::TOGGLE_RTRIM_BOTTOM: { + bool l = (feature == Tabular::SET_RTRIM_BOTTOM) + ? (value == "true") : !tabular.bottomLineTrim(cur.idx()).second; + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setBottomLineRTrim(tabular.cellIndex(r, c), l); + break; + } + case Tabular::SET_LINE_LEFT: case Tabular::TOGGLE_LINE_LEFT: { bool lineSet = (feature == Tabular::SET_LINE_LEFT) @@ -5701,7 +6337,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; } @@ -5710,7 +6346,7 @@ 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; @@ -5756,7 +6392,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; @@ -5766,7 +6402,7 @@ 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; @@ -5808,6 +6444,9 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; } + case Tabular::SET_INNER_LINES: + setLinesInnerOnly = true; + // fall through case Tabular::SET_ALL_LINES: setLines = true; // fall through @@ -5815,13 +6454,30 @@ void InsetTabular::tabularFeatures(Cursor & cur, for (row_type r = sel_row_start; r <= sel_row_end; ++r) for (col_type c = sel_col_start; c <= sel_col_end; ++c) { idx_type const cell = tabular.cellIndex(r, c); - tabular.setTopLine(cell, setLines); - tabular.setBottomLine(cell, setLines); - tabular.setRightLine(cell, setLines); - tabular.setLeftLine(cell, setLines); + if (!setLinesInnerOnly || r != sel_row_start) + tabular.setTopLine(cell, setLines); + if ((!setLinesInnerOnly || r != sel_row_end) + && (!setLines || r == sel_row_end)) + tabular.setBottomLine(cell, setLines); + if ((!setLinesInnerOnly || c != sel_col_end) + && (!setLines || c == sel_col_end)) + tabular.setRightLine(cell, setLines); + if ((!setLinesInnerOnly || c != sel_col_start)) + tabular.setLeftLine(cell, setLines); } break; + case Tabular::RESET_FORMAL_DEFAULT: + for (row_type r = 0; r < tabular.nrows(); ++r) { + bool const head_or_foot = r == 0 || r == tabular.nrows() - 1; + for (col_type c = 0; c < tabular.ncols(); ++c) { + idx_type const cell = tabular.cellIndex(r, c); + tabular.setTopLine(cell, head_or_foot); + tabular.setBottomLine(cell, head_or_foot); + } + } + break; + case Tabular::SET_BORDER_LINES: for (row_type r = sel_row_start; r <= sel_row_end; ++r) { tabular.setLeftLine(tabular.cellIndex(r, sel_col_start), true); @@ -5893,8 +6549,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) @@ -5979,7 +6633,7 @@ 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.selection(false); @@ -5995,7 +6649,7 @@ 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.selection(false); @@ -6295,7 +6949,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(); } @@ -6343,20 +6997,26 @@ bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf, } size_t op = 0; - idx_type const cells = loctab->numberofcells; + idx_type cells = loctab->numberofcells; p = 0; cols = ocol; rows = loctab->nrows(); - col_type const columns = loctab->ncols(); + col_type columns = loctab->ncols(); - while (cell < cells && p < len && row < rows && + while (p < len && (p = buf.find_first_of(from_ascii("\t\n"), p)) != docstring::npos) { if (p >= len) break; switch (buf[p]) { case '\t': - // we can only set this if we are not too far right + // append column if necessary + if (cols == columns) { + loctab->appendColumn(cols - 1); + columns = loctab->ncols(); + cells = loctab->numberofcells; + ++cell; + } if (cols < columns) { shared_ptr inset = loctab->cellInset(cell); Font const font = bv.textMetrics(&inset->text()). @@ -6378,6 +7038,12 @@ bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf, } cols = ocol; ++row; + // append row if necessary + if (row == rows && p < len - 1) { + loctab->appendRow(row - 1); + rows = loctab->nrows(); + cells = loctab->numberofcells; + } if (row < rows) cell = loctab->cellIndex(row, cols); break;