X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetTabular.cpp;h=30a5b853105a6d4c811b810186701138a54ef5ed;hb=c1e10c71850adf8e5a19160e24e32c696aaf01a6;hp=4df92329361634ac2e304bfcff63c587ff8e6293;hpb=f0959cc292c4bea1171114e83696aa6fc661db7c;p=lyx.git diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index 4df9232936..30a5b85310 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" @@ -66,6 +67,7 @@ #include "support/unique_ptr.h" #include +#include #include #include #include @@ -196,6 +198,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 } }; @@ -261,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(); } @@ -323,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; @@ -877,8 +884,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) @@ -949,17 +956,17 @@ 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; } @@ -1033,7 +1040,7 @@ 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 @@ -1145,7 +1152,7 @@ void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, bool fixedWidth) cur.pop(); } -} +} // namespace void Tabular::setColumnPWidth(Cursor & cur, idx_type cell, @@ -1859,7 +1866,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) @@ -1914,12 +1921,11 @@ 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; @@ -2172,23 +2178,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; } @@ -2196,16 +2203,20 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang) co if ((row == 0 && nset == 0) || (row > 0 && nset != ncols())) return; + // Is this the actual first row (excluding longtable caption row)? + bool const realfirstrow = (row == 0 + || (is_long_tabular && row == 1 && ltCaption(0))); + // only output complete row lines and the 1st row's clines if (nset == ncols()) { if (use_booktabs) { - os << (row == 0 ? "\\toprule " : "\\midrule "); + os << (realfirstrow ? "\\toprule " : "\\midrule "); } else { os << "\\hline "; } - } else if (row == 0) { - for (col_type c = 0; c < ncols(); ++c) { - if (topline[c]) { + } else if (realfirstrow) { + 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) @@ -2220,7 +2231,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) @@ -2234,18 +2245,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) @@ -2255,15 +2267,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; } @@ -2277,8 +2289,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) @@ -2293,7 +2305,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) @@ -2308,7 +2320,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) @@ -2318,8 +2331,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); @@ -2328,28 +2343,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; @@ -2396,9 +2418,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 << "}{"; @@ -2452,7 +2474,21 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell, } os << "]{" << from_ascii(getPWidth(cell).asLatexString()) << "}\n"; + } else if (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"; +} } @@ -2468,6 +2504,8 @@ void Tabular::TeXCellPostamble(otexstream & os, idx_type cell, os << '}'; else if (getUsebox(cell) == BOX_MINIPAGE) os << breakln << "\\end{minipage}"; + else if (getUsebox(cell) == BOX_VARWIDTH) + os << breakln << "\\end{varwidth}"; if (getRotateCell(cell) != 0) os << breakln << "\\end{turn}"; if (ismultirow) @@ -2478,7 +2516,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; @@ -2490,7 +2529,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 @@ -2499,7 +2538,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"; @@ -2513,7 +2552,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"; @@ -2525,7 +2564,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"; @@ -2539,7 +2578,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"; @@ -2559,7 +2598,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 * inset = cellInset(cell); @@ -2567,7 +2607,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, string const lang = par.getParLanguage(buffer().params())->lang(); //output the top line - TeXTopHLine(os, row, lang); + TeXTopHLine(os, row, lang, columns); if (row_info[row].top_space_default) { if (use_booktabs) @@ -2587,7 +2627,16 @@ 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 with XeTeX) reverses RTL table columns + // Luabibdi (used by LuaTeX) behaves like classic + bool const bidi_rtl = + runparams.local_font->isRightToLeft() + && runparams.use_polyglossia && runparams.flavor == OutputParams::XETEX; + idx_type lastcell = + bidi_rtl ? getFirstCellInRow(row) : getLastCellInRow(row); + + for (auto const & c : columns) { if (isPartOfMultiColumn(row, c)) continue; @@ -2595,12 +2644,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(); @@ -2642,14 +2691,35 @@ 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 + // 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) @@ -2662,7 +2732,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 @@ -2685,7 +2755,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, os << '\n'; //output the bottom line - TeXBottomHLine(os, row, lang); + TeXBottomHLine(os, row, lang, columns); if (row_info[row].interline_space_default) { if (use_booktabs) @@ -2708,7 +2778,7 @@ 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(); - RowEntry pos = TexRow::textEntry(runparams.lastid, runparams.lastpos); + TexRow::RowEntry pos = TexRow::textEntry(runparams.lastid, runparams.lastpos); //+--------------------------------------------------------------------- //+ first the opening preamble + @@ -2718,8 +2788,12 @@ 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}"; @@ -2728,6 +2802,7 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const os << "[l]"; break; case LYX_LONGTABULAR_ALIGN_CENTER: + os << "[c]"; break; case LYX_LONGTABULAR_ALIGN_RIGHT: os << "[r]"; @@ -2755,13 +2830,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 with XeTeX) swaps the column + // order for RTL (#9686). Thus we use this list. + bool const bidi_rtl = + runparams.local_font->isRightToLeft() + && runparams.use_polyglossia && runparams.flavor == OutputParams::XETEX; + 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}"; @@ -2776,24 +2865,53 @@ 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 { switch (column_info[c].alignment) { case LYX_ALIGN_LEFT: @@ -2811,12 +2929,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) + @@ -2824,7 +2942,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"; } @@ -2843,8 +2961,12 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const 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); @@ -3015,13 +3137,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: @@ -3389,15 +3511,28 @@ void Tabular::validate(LaTeXFeatures & features) const features.require("booktabs"); if (is_long_tabular) features.require("longtable"); + if (rotate && is_long_tabular) + features.require("lscape"); if (needRotating()) features.require("rotating"); 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()) 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()); } } @@ -3407,11 +3542,12 @@ Tabular::BoxType Tabular::useParbox(idx_type cell) const ParagraphList const & parlist = cellInset(cell)->paragraphs(); ParagraphList::const_iterator cit = parlist.begin(); ParagraphList::const_iterator end = parlist.end(); + bool const turned = getRotateCell(cell) != 0; for (; cit != end; ++cit) for (int i = 0; i < cit->size(); ++i) if (cit->isNewline(i)) - return BOX_PARBOX; + return turned ? BOX_VARWIDTH : BOX_PARBOX; return BOX_NONE; } @@ -3452,6 +3588,9 @@ bool InsetTableCell::getStatus(Cursor & cur, FuncRequest const & cmd, { bool enabled = true; switch (cmd.action()) { + case LFUN_INSET_DISSOLVE: + enabled = false; + break; case LFUN_MATH_DISPLAY: if (!hasFixedWidth()) { enabled = false; @@ -3484,9 +3623,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); } @@ -3857,35 +3996,54 @@ 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); + + 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.is_long_tabular && row == 1 && tabular.ltCaption(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); + 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))); + 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); @@ -3896,9 +4054,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); } @@ -3955,13 +4111,13 @@ 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); } @@ -4336,6 +4492,13 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) } break; + case LFUN_COPY: + if (cur.selIsMultiCell()) + copySelection(cur); + else + cell(cur.idx())->dispatch(cur, cmd); + break; + case LFUN_CUT: if (cur.selIsMultiCell()) { if (copySelection(cur)) { @@ -4371,16 +4534,6 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cell(cur.idx())->dispatch(cur, cmd); break; - case LFUN_COPY: - if (!cur.selection()) - break; - if (cur.selIsMultiCell()) { - cur.finishUndo(); - copySelection(cur); - } else - cell(cur.idx())->dispatch(cur, cmd); - break; - case LFUN_CLIPBOARD_PASTE: case LFUN_PRIMARY_SELECTION_PASTE: { docstring const clip = (act == LFUN_CLIPBOARD_PASTE) ? @@ -4432,6 +4585,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: @@ -4606,6 +4760,7 @@ 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; @@ -4648,12 +4803,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())); @@ -4662,6 +4819,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())); @@ -4682,6 +4840,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())); @@ -4691,6 +4850,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())); @@ -4700,6 +4860,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())); @@ -4903,7 +5064,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); } @@ -4978,7 +5139,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, status.setEnabled(false); return true; } - // Fall back + // fall through case LFUN_NEWLINE_INSERT: { if (tabular.getPWidth(cur.idx()).zero()) { status.setEnabled(false); @@ -5159,7 +5320,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.selection(false); cur.push(*this); cur.idx() = getNearestCell(cur.bv(), x, y); return cur.bv().textMetrics(&cell(cur.idx())->text()).editXY(cur, x, y); @@ -5331,6 +5491,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; @@ -5409,6 +5571,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; @@ -5470,10 +5633,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; } @@ -5631,6 +5796,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: @@ -5751,16 +5917,26 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; } + case Tabular::SET_INNER_LINES: + setLinesInnerOnly = true; + // fall through 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) { 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; @@ -5835,8 +6011,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) @@ -5877,6 +6051,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); @@ -5885,6 +6060,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); @@ -5893,6 +6069,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); @@ -5901,6 +6078,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); @@ -5909,6 +6087,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::UNSET_LTNEWPAGE: flag = false; + // fall through case Tabular::SET_LTNEWPAGE: tabular.setLTNewPage(row, flag); break; @@ -6111,6 +6290,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;