X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetTabular.cpp;h=ba8cfb944567889bb25126e72de7fb49bb5c145e;hb=e43ba7cf46779c6a8394310b9487ebe2c75132b2;hp=be88ad64e8882f3d97e9b840e9a4c043005cdb78;hpb=08fe2803c610a8ee84e5209d24fb97dd4ed5daf5;p=lyx.git diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index be88ad64e8..ba8cfb9445 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -33,6 +33,7 @@ #include "DispatchResult.h" #include "FuncRequest.h" #include "FuncStatus.h" +#include "InsetIterator.h" #include "InsetList.h" #include "Language.h" #include "LaTeXFeatures.h" @@ -45,6 +46,8 @@ #include "Paragraph.h" #include "ParagraphParameters.h" #include "ParIterator.h" +#include "TexRow.h" +#include "texstream.h" #include "TextClass.h" #include "TextMetrics.h" @@ -61,10 +64,10 @@ #include "support/gettext.h" #include "support/lassert.h" #include "support/lstrings.h" - -#include +#include "support/unique_ptr.h" #include +#include #include #include #include @@ -96,7 +99,7 @@ int const WIDTH_OF_LINE = 5; // space between double lines /// -boost::scoped_ptr paste_tabular; +unique_ptr paste_tabular; struct TabularFeature { @@ -110,6 +113,8 @@ TabularFeature tabularFeature[] = { // the SET/UNSET actions are used by the table dialog, // the TOGGLE actions by the table toolbar buttons + // FIXME: these values have been hardcoded in InsetMathGrid and other + // math insets. { Tabular::APPEND_ROW, "append-row", false }, { Tabular::APPEND_COLUMN, "append-column", false }, { Tabular::DELETE_ROW, "delete-row", false }, @@ -151,6 +156,7 @@ TabularFeature tabularFeature[] = { Tabular::SET_MROFFSET, "set-mroffset", true }, { Tabular::SET_ALL_LINES, "set-all-lines", 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 }, @@ -177,6 +183,7 @@ TabularFeature tabularFeature[] = { Tabular::UNSET_LTCAPTION, "unset-ltcaption", false }, { Tabular::SET_SPECIAL_COLUMN, "set-special-column", true }, { Tabular::SET_SPECIAL_MULTICOLUMN, "set-special-multicolumn", true }, + { Tabular::TOGGLE_BOOKTABS, "toggle-booktabs", false }, { Tabular::SET_BOOKTABS, "set-booktabs", false }, { Tabular::UNSET_BOOKTABS, "unset-booktabs", false }, { Tabular::SET_TOP_SPACE, "set-top-space", true }, @@ -522,7 +529,7 @@ string const featureAsString(Tabular::Feature action) } -DocIterator separatorPos(InsetTableCell * cell, docstring const & align_d) +DocIterator separatorPos(InsetTableCell const * cell, docstring const & align_d) { DocIterator dit = doc_iterator_begin(&(cell->buffer()), cell); for (; dit; dit.forwardChar()) @@ -538,7 +545,7 @@ InsetTableCell splitCell(InsetTableCell & head, docstring const & align_d, bool { InsetTableCell tail = InsetTableCell(head); DocIterator const dit = separatorPos(&head, align_d); - hassep = dit; + hassep = (bool)dit; if (hassep) { pit_type const psize = head.paragraphs().front().size(); head.paragraphs().front().eraseChars(dit.pos(), psize, false); @@ -652,7 +659,7 @@ Tabular::ColumnData::ColumnData() Tabular::ltType::ltType() - : topDL(false), + : set(false), topDL(false), bottomDL(false), empty(false) {} @@ -872,8 +879,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) @@ -1028,7 +1035,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 @@ -1099,7 +1106,7 @@ void Tabular::setAlignment(idx_type cell, LyXAlignment align, dpoint = from_utf8(lyxrc.default_decimal_point); } else { cellInfo(cell).alignment = align; - cellInset(cell).get()->setContentAlignment(align); + cellInset(cell)->setContentAlignment(align); } } @@ -1140,7 +1147,7 @@ void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, bool fixedWidth) cur.pop(); } -} +} // namespace void Tabular::setColumnPWidth(Cursor & cur, idx_type cell, @@ -1155,12 +1162,12 @@ void Tabular::setColumnPWidth(Cursor & cur, idx_type cell, if (column_info[c].p_width.zero()) column_info[c].valignment = LYX_VALIGN_TOP; for (row_type r = 0; r < nrows(); ++r) { - idx_type const cell = cellIndex(r, c); + idx_type const cidx = cellIndex(r, c); // because of multicolumns - toggleFixedWidth(cur, cellInset(cell).get(), - !getPWidth(cell).zero()); - if (isMultiRow(cell)) - setAlignment(cell, LYX_ALIGN_LEFT, false); + toggleFixedWidth(cur, cellInset(cidx).get(), + !getPWidth(cidx).zero()); + if (isMultiRow(cidx)) + setAlignment(cidx, LYX_ALIGN_LEFT, false); } // cur paragraph can become invalid after paragraphs were merged if (cur.pit() > cur.lastpit()) @@ -1317,6 +1324,27 @@ Tabular::getVAlignment(idx_type cell, bool onlycolumn) const } +int Tabular::offsetVAlignment() const +{ + // for top-alignment the first horizontal table line must be exactly at + // the position of the base line of the surrounding text line + // for bottom alignment, the same is for the last table line + int offset_valign = 0; + switch (tabular_valignment) { + case Tabular::LYX_VALIGN_BOTTOM: + offset_valign = rowAscent(0) - height(); + break; + case Tabular::LYX_VALIGN_MIDDLE: + offset_valign = (- height()) / 2 + rowAscent(0); + break; + case Tabular::LYX_VALIGN_TOP: + offset_valign = rowAscent(0); + break; + } + return offset_valign; +} + + Length const Tabular::getPWidth(idx_type cell) const { if (isMultiColumn(cell)) @@ -1665,7 +1693,13 @@ bool Tabular::hasMultiColumn(col_type c) const } -Tabular::CellData & Tabular::cellInfo(idx_type cell) const +Tabular::CellData const & Tabular::cellInfo(idx_type cell) const +{ + return cell_info[cellRow(cell)][cellColumn(cell)]; +} + + +Tabular::CellData & Tabular::cellInfo(idx_type cell) { return cell_info[cellRow(cell)][cellColumn(cell)]; } @@ -1827,7 +1861,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) @@ -2140,23 +2174,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; } @@ -2172,8 +2207,8 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang) co os << "\\hline "; } } else if (row == 0) { - for (col_type c = 0; c < ncols(); ++c) { - if (topline[c]) { + for (auto & c : columns) { + if (topline.find(c)->second) { col_type offset = 0; for (col_type j = 0 ; j < c; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) @@ -2188,7 +2223,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) @@ -2202,18 +2237,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) @@ -2223,15 +2259,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; } @@ -2245,8 +2281,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) @@ -2261,7 +2297,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) @@ -2276,7 +2312,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) @@ -2286,8 +2323,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); @@ -2296,28 +2335,35 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell, bool coldouble = colright && nextcolleft; bool celldouble = rightLine(cell) && nextcellleft; - ismulticol = isMultiColumn(cell) - || (c == 0 && colleft != leftLine(cell)) - || ((colright || nextcolleft) && !rightLine(cell) && !nextcellleft) - || (!colright && !nextcolleft && (rightLine(cell) || nextcellleft)) - || (coldouble != celldouble); + ismulticol = (isMultiColumn(cell) + || (c == 0 && colleft != leftLine(cell)) + || ((colright || nextcolleft) && !rightLine(cell) && !nextcellleft) + || (!colright && !nextcolleft && (rightLine(cell) || nextcellleft)) + || (coldouble != celldouble)) + && !decimal; // we center in multicol when no decimal point - if (column_info[c].alignment == LYX_ALIGN_DECIMAL) { + if (decimal) { docstring const align_d = column_info[c].decimal_point; - DocIterator const dit = separatorPos(cellInset(cell).get(), align_d); - ismulticol |= !dit; + DocIterator const dit = separatorPos(cellInset(cell), align_d); + bool const nosep = !dit; + ismulticol |= nosep; + celldouble &= nosep; } // up counter by 1 for each decimally aligned col since they use 2 latex cols int latexcolspan = columnSpan(cell); - for(col_type col = c; col < c + columnSpan(cell); ++col) + for (col_type col = c; col < c + columnSpan(cell); ++col) if (column_info[col].alignment == LYX_ALIGN_DECIMAL) ++latexcolspan; if (ismulticol) { os << "\\multicolumn{" << latexcolspan << "}{"; - if (c ==0 && leftLine(cell)) + if (((bidi && c == getLastCellInRow(cellRow(0)) && rightLine(cell)) + || (!bidi && c == 0 && leftLine(cell)))) + os << '|'; + if (bidi && celldouble) + // add extra vertical line if we want a double one os << '|'; if (!cellInfo(cell).align_special.empty()) { os << cellInfo(cell).align_special; @@ -2364,9 +2410,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 << "}{"; @@ -2446,7 +2492,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; @@ -2458,7 +2505,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 @@ -2467,7 +2514,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"; @@ -2481,7 +2528,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"; @@ -2493,7 +2540,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"; @@ -2507,7 +2554,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"; @@ -2527,15 +2574,16 @@ bool Tabular::isValidRow(row_type row) const void Tabular::TeXRow(otexstream & os, row_type row, - OutputParams const & runparams) const + OutputParams const & runparams, + list columns) const { idx_type cell = cellIndex(row, 0); - shared_ptr inset = cellInset(cell); - Paragraph const & par = inset->paragraphs().front(); - string const lang = par.getParLanguage(buffer().params())->lang(); + InsetTableCell const * cinset = cellInset(cell); + Paragraph const & cpar = cinset->paragraphs().front(); + string const clang = cpar.getParLanguage(buffer().params())->lang(); //output the top line - TeXTopHLine(os, row, lang); + TeXTopHLine(os, row, clang, columns); if (row_info[row].top_space_default) { if (use_booktabs) @@ -2555,7 +2603,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; @@ -2563,15 +2619,18 @@ void Tabular::TeXRow(otexstream & os, row_type row, if (isPartOfMultiRow(row, c) && column_info[c].alignment != LYX_ALIGN_DECIMAL) { - if (cell != getLastCellInRow(row)) + if (cell != lastcell) os << " & "; continue; } - TeXCellPreamble(os, cell, ismulticol, ismultirow); - shared_ptr inset = cellInset(cell); + TeXCellPreamble(os, cell, ismulticol, ismultirow, bidi_rtl); + InsetTableCell const * inset = cellInset(cell); Paragraph const & par = inset->paragraphs().front(); + + os.texrow().forceStart(par.id(), 0); + bool rtl = par.isRTL(buffer().params()) && !par.empty() && getPWidth(cell).zero() @@ -2599,22 +2658,43 @@ void Tabular::TeXRow(otexstream & os, row_type row, if (getAlignment(cell) == LYX_ALIGN_DECIMAL) { // copy cell and split in 2 - InsetTableCell head = InsetTableCell(*cellInset(cell).get()); - head.setBuffer(buffer()); + InsetTableCell head = InsetTableCell(*cellInset(cell)); + head.setBuffer(const_cast(buffer())); DocIterator dit = cellInset(cell)->getText(0)->macrocontextPosition(); dit.pop_back(); dit.push_back(CursorSlice(head)); head.setMacrocontextPositionRecursive(dit); bool hassep = false; InsetTableCell tail = splitCell(head, column_info[c].decimal_point, hassep); - head.latex(os, newrp); if (hassep) { - os << '&'; tail.setBuffer(head.buffer()); dit.pop_back(); dit.push_back(CursorSlice(tail)); tail.setMacrocontextPositionRecursive(dit); - tail.latex(os, newrp); + } + if (bidi_rtl) { + if (hassep) { + tail.latex(os, newrp); + os << '&'; + } + head.latex(os, newrp); + } else { + head.latex(os, newrp); + if (hassep) { + os << '&'; + tail.latex(os, newrp); + } + } + } else if (ltCaption(row)) { + // Inside longtable caption rows, we must only output the caption inset + // with its content and omit anything outside of that (see #10791) + InsetIterator it = inset_iterator_begin(*const_cast(inset)); + InsetIterator i_end = inset_iterator_end(*const_cast(inset)); + for (; it != i_end; ++it) { + if (it->lyxCode() != CAPTION_CODE) + continue; + it->latex(os, runparams); + break; } } else if (!isPartOfMultiRow(row, c)) { if (!runparams.nice) @@ -2627,7 +2707,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 @@ -2650,7 +2730,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, os << '\n'; //output the bottom line - TeXBottomHLine(os, row, lang); + TeXBottomHLine(os, row, clang, columns); if (row_info[row].interline_space_default) { if (use_booktabs) @@ -2673,16 +2753,17 @@ void Tabular::TeXRow(otexstream & os, row_type row, void Tabular::latex(otexstream & os, OutputParams const & runparams) const { bool const is_tabular_star = !tabular_width.zero(); + TexRow::RowEntry pos = TexRow::textEntry(runparams.lastid, runparams.lastpos); //+--------------------------------------------------------------------- //+ first the opening preamble + //+--------------------------------------------------------------------- os << safebreakln; - if (runparams.lastid != -1) - os.texrow().start(runparams.lastid, runparams.lastpos); + if (!TexRow::isNone(pos)) + os.texrow().start(pos); - if (rotate != 0) + if (rotate != 0 && !is_long_tabular) os << "\\begin{turn}{" << convert(rotate) << "}\n"; if (is_long_tabular) { @@ -2719,13 +2800,27 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const if (is_tabular_star) os << "@{\\extracolsep{\\fill}}"; - for (col_type c = 0; c < ncols(); ++c) { - if (columnLeftLine(c)) + // The bidi package (loaded by polyglossia) swaps the column + // order for RTL (#9686). Thus we use this list. + bool const bidi_rtl = + runparams.local_font->isRightToLeft() + && runparams.use_polyglossia; + list columns; + for (col_type cl = 0; cl < ncols(); ++cl) { + if (bidi_rtl) + columns.push_front(cl); + else + columns.push_back(cl); + } + + for (auto const & c : columns) { + if ((bidi_rtl && columnRightLine(c)) || (!bidi_rtl && columnLeftLine(c))) os << '|'; if (!column_info[c].align_special.empty()) { os << column_info[c].align_special; } else { if (!column_info[c].p_width.zero()) { + bool decimal = false; switch (column_info[c].alignment) { case LYX_ALIGN_LEFT: os << ">{\\raggedright}"; @@ -2740,24 +2835,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: @@ -2775,12 +2899,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) + @@ -2788,7 +2912,7 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const for (row_type r = 0; r < nrows(); ++r) { if (isValidRow(r)) { - TeXRow(os, r, runparams); + TeXRow(os, r, runparams, columns); if (is_long_tabular && row_info[r].newpage) os << "\\newpage\n"; } @@ -2807,8 +2931,11 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const os << "\\end{tabular}"; } - if (rotate != 0) + if (rotate != 0 && !is_long_tabular) os << breakln << "\\end{turn}"; + + if (!TexRow::isNone(pos)) + os.texrow().start(pos); } @@ -2976,6 +3103,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: @@ -3007,7 +3141,7 @@ docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row, else if (isMultiRow(cell)) attr << " rowspan='" << rowSpan(cell) << "'"; - xs << html::StartTag(celltag, attr.str()) << html::CR(); + xs << html::StartTag(celltag, attr.str(), true) << html::CR(); ret += cellInset(cell)->xhtml(xs, runparams); xs << html::EndTag(celltag) << html::CR(); ++cell; @@ -3310,21 +3444,26 @@ void Tabular::plaintext(odocstringstream & os, } -shared_ptr Tabular::cellInset(idx_type cell) const +shared_ptr Tabular::cellInset(idx_type cell) { return cell_info[cellRow(cell)][cellColumn(cell)].inset; } -shared_ptr Tabular::cellInset(row_type row, - col_type column) const +shared_ptr Tabular::cellInset(row_type row, col_type column) { return cell_info[row][column].inset; } +InsetTableCell const * Tabular::cellInset(idx_type cell) const +{ + return cell_info[cellRow(cell)][cellColumn(cell)].inset.get(); +} + + void Tabular::setCellInset(row_type row, col_type column, - shared_ptr ins) const + shared_ptr ins) { CellData & cd = cell_info[row][column]; cd.inset = ins; @@ -3346,7 +3485,16 @@ void Tabular::validate(LaTeXFeatures & features) const 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()); } } @@ -3401,13 +3549,6 @@ bool InsetTableCell::getStatus(Cursor & cur, FuncRequest const & cmd, { bool enabled = true; switch (cmd.action()) { - case LFUN_LAYOUT: - enabled = !forcePlainLayout(); - break; - case LFUN_LAYOUT_PARAGRAPH: - enabled = allowParagraphCustomization(); - break; - case LFUN_MATH_DISPLAY: if (!hasFixedWidth()) { enabled = false; @@ -3439,9 +3580,10 @@ docstring InsetTableCell::asString(bool intoInsets) } -void InsetTableCell::addToToc(DocIterator const & di, bool output_active) const +void InsetTableCell::addToToc(DocIterator const & di, bool output_active, + UpdateType utype, TocBackend & backend) const { - InsetText::iterateForToc(di, output_active); + InsetText::iterateForToc(di, output_active, utype, backend); } @@ -3463,13 +3605,14 @@ docstring InsetTableCell::xhtml(XHTMLStream & xs, OutputParams const & rp) const InsetTabular::InsetTabular(Buffer * buf, row_type rows, col_type columns) : Inset(buf), tabular(buf, max(rows, row_type(1)), max(columns, col_type(1))), - first_visible_cell_(0), offset_valign_(0), rowselect_(false), colselect_(false) + rowselect_(false), colselect_(false) { } InsetTabular::InsetTabular(InsetTabular const & tab) - : Inset(tab), tabular(tab.tabular) + : Inset(tab), tabular(tab.tabular), + rowselect_(false), colselect_(false) { } @@ -3508,7 +3651,7 @@ bool InsetTabular::insetAllowed(InsetCode code) const bool InsetTabular::allowsCaptionVariation(std::string const & newtype) const { return tabular.is_long_tabular && - (newtype == "Standard" || newtype == "LongTableNoNumber"); + (newtype == "Standard" || newtype == "Unnumbered"); } @@ -3556,7 +3699,7 @@ void InsetTabular::read(Lexer & lex) int InsetTabular::rowFromY(Cursor & cur, int y) const { // top y coordinate of tabular - int h = yo(cur.bv()) - tabular.rowAscent(0) + offset_valign_; + int h = yo(cur.bv()) - tabular.rowAscent(0) + tabular.offsetVAlignment(); row_type r = 0; for (; r < tabular.nrows() && y > h; ++r) h += tabular.rowAscent(r) + tabular.rowDescent(r) @@ -3592,15 +3735,15 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const // multicolumn or multirow cell, but not first one continue; idx_type const cell = tabular.cellIndex(r, c); - Dimension dim; + Dimension dim0; MetricsInfo m = mi; Length const p_width = tabular.getPWidth(cell); if (!p_width.zero()) - m.base.textwidth = p_width.inPixels(mi.base); - tabular.cellInset(cell)->metrics(m, dim); + m.base.textwidth = mi.base.inPixels(p_width); + tabular.cellInset(cell)->metrics(m, dim0); if (!p_width.zero()) - dim.wid = m.base.textwidth; - tabular.cellInfo(cell).width = dim.wid + 2 * WIDTH_OF_LINE + dim0.wid = m.base.textwidth; + tabular.cellInfo(cell).width = dim0.wid + 2 * WIDTH_OF_LINE + tabular.interColumnSpace(cell); // FIXME(?): do we need a second metrics call? @@ -3610,7 +3753,7 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const // determine horizontal offset because of decimal align (if necessary) int decimal_width = 0; if (tabular.getAlignment(cell) == LYX_ALIGN_DECIMAL) { - InsetTableCell tail = InsetTableCell(*tabular.cellInset(cell).get()); + InsetTableCell tail = InsetTableCell(*tabular.cellInset(cell)); tail.setBuffer(tabular.buffer()); // we need to set macrocontext position everywhere // otherwise we crash with nested insets (e.g. footnotes) @@ -3645,43 +3788,28 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const case Tabular::LYX_VALIGN_TOP: break; case Tabular::LYX_VALIGN_MIDDLE: - offset = -(dim.des - lastpardes)/2; + offset = -(dim0.des - lastpardes)/2; break; case Tabular::LYX_VALIGN_BOTTOM: - offset = -(dim.des - lastpardes); + offset = -(dim0.des - lastpardes); break; } tabular.cell_info[r][c].voffset = offset; - maxasc = max(maxasc, dim.asc - offset); - maxdes = max(maxdes, dim.des + offset); + maxasc = max(maxasc, dim0.asc - offset); + maxdes = max(maxdes, dim0.des + offset); } int const top_space = tabular.row_info[r].top_space_default ? - default_line_space : - tabular.row_info[r].top_space.inPixels(mi.base); + default_line_space : + mi.base.inPixels(tabular.row_info[r].top_space); tabular.setRowAscent(r, maxasc + ADD_TO_HEIGHT + top_space); int const bottom_space = tabular.row_info[r].bottom_space_default ? - default_line_space : - tabular.row_info[r].bottom_space.inPixels(mi.base); + default_line_space : + mi.base.inPixels(tabular.row_info[r].bottom_space); tabular.setRowDescent(r, maxdes + ADD_TO_HEIGHT + bottom_space); } - // for top-alignment the first horizontal table line must be exactly at - // the position of the base line of the surrounding text line - // for bottom alignment, the same is for the last table line - switch (tabular.tabular_valignment) { - case Tabular::LYX_VALIGN_BOTTOM: - offset_valign_ = tabular.rowAscent(0) - tabular.height(); - break; - case Tabular::LYX_VALIGN_MIDDLE: - offset_valign_ = (- tabular.height()) / 2 + tabular.rowAscent(0); - break; - case Tabular::LYX_VALIGN_TOP: - offset_valign_ = tabular.rowAscent(0); - break; - } - tabular.updateColumnWidths(); - dim.asc = tabular.rowAscent(0) - offset_valign_; + dim.asc = tabular.rowAscent(0) - tabular.offsetVAlignment(); dim.des = tabular.height() - dim.asc; dim.wid = tabular.width() + 2 * ADD_TO_TABULAR_WIDTH; } @@ -3732,9 +3860,8 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const bool const original_selection_state = pi.selected; idx_type idx = 0; - first_visible_cell_ = Tabular::npos; - int yy = y + offset_valign_; + int yy = y + tabular.offsetVAlignment(); for (row_type r = 0; r < tabular.nrows(); ++r) { int nx = x; for (col_type c = 0; c < tabular.ncols(); ++c) { @@ -3748,9 +3875,6 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const continue; } - if (first_visible_cell_ == Tabular::npos) - first_visible_cell_ = idx; - pi.selected |= isCellSelected(cur, r, c); int const cx = nx + tabular.textHOffset(idx); int const cy = yy + tabular.textVOffset(idx); @@ -3772,7 +3896,7 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const void InsetTabular::drawBackground(PainterInfo & pi, int x, int y) const { x += ADD_TO_TABULAR_WIDTH; - y += offset_valign_ - tabular.rowAscent(0); + y += tabular.offsetVAlignment() - tabular.rowAscent(0); pi.pain.fillRectangle(x, y, tabular.width(), tabular.height(), pi.backgroundColor(this)); } @@ -3809,7 +3933,7 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const } int const w = tabular.cellWidth(cell); int const h = tabular.cellHeight(cell); - int const yy = y - tabular.rowAscent(r) + offset_valign_; + int const yy = y - tabular.rowAscent(r) + tabular.offsetVAlignment(); if (isCellSelected(cur, r, c)) pi.pain.fillRectangle(xx, yy, w, h, Color_selection); xx += w; @@ -3927,13 +4051,37 @@ void InsetTabular::updateBuffer(ParIterator const & it, UpdateType utype) } -void InsetTabular::addToToc(DocIterator const & cpit, bool output_active) const +void InsetTabular::addToToc(DocIterator const & cpit, bool output_active, + 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); + cell(dit.idx())->addToToc(dit, output_active, utype, backend); +} + + +bool InsetTabular::hitSelectRow(BufferView const & bv, int x) const +{ + int const x0 = xo(bv) + ADD_TO_TABULAR_WIDTH; + return x < x0 || x > x0 + tabular.width(); +} + + +bool InsetTabular::hitSelectColumn(BufferView const & bv, int y) const +{ + int const y0 = yo(bv) - tabular.rowAscent(0) + tabular.offsetVAlignment(); + // FIXME: using ADD_TO_TABULAR_WIDTH is not really correct since + // there is no margin added vertically to tabular insets. + // However, it works for now. + return y < y0 + ADD_TO_TABULAR_WIDTH || y > y0 + tabular.height() - ADD_TO_TABULAR_WIDTH; +} + + +bool InsetTabular::clickable(BufferView const & bv, int x, int y) const +{ + return hitSelectRow(bv, x) || hitSelectColumn(bv, y); } @@ -3951,30 +4099,31 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_MOUSE_PRESS: { //lyxerr << "# InsetTabular::MousePress\n" << cur.bv().cursor() << endl; // select row - if (cmd.x() < xo(cur.bv()) + ADD_TO_TABULAR_WIDTH - || cmd.x() > xo(cur.bv()) + tabular.width()) { + if (hitSelectRow(cur.bv(), cmd.x())) { row_type r = rowFromY(cur, cmd.y()); cur.idx() = tabular.getFirstCellInRow(r); + cur.pit() = 0; cur.pos() = 0; cur.resetAnchor(); cur.idx() = tabular.getLastCellInRow(r); + cur.pit() = cur.lastpit(); cur.pos() = cur.lastpos(); - cur.setSelection(true); + cur.selection(true); bvcur = cur; rowselect_ = true; break; } // select column - int const y0 = yo(cur.bv()) - tabular.rowAscent(0) + offset_valign_; - if (cmd.y() < y0 + ADD_TO_TABULAR_WIDTH - || cmd.y() > y0 + tabular.height()) { + if (hitSelectColumn(cur.bv(), cmd.y())) { col_type c = columnFromX(cur, cmd.x()); cur.idx() = tabular.cellIndex(0, c); + cur.pit() = 0; cur.pos() = 0; cur.resetAnchor(); cur.idx() = tabular.cellIndex(tabular.nrows() - 1, c); + cur.pit() = cur.lastpit(); cur.pos() = cur.lastpos(); - cur.setSelection(true); + cur.selection(true); bvcur = cur; colselect_ = true; break; @@ -4007,7 +4156,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.pit() = 0; cur.pos() = 0; bvcur.setCursor(cur); - bvcur.setSelection(true); + bvcur.selection(true); break; } // select (additional) column @@ -4019,7 +4168,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.pit() = 0; cur.pos() = 0; bvcur.setCursor(cur); - bvcur.setSelection(true); + bvcur.selection(true); break; } // only update if selection changes @@ -4028,7 +4177,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.noScreenUpdate(); setCursorFromCoordinates(cur, cmd.x(), cmd.y()); bvcur.setCursor(cur); - bvcur.setSelection(true); + bvcur.selection(true); // if this is a multicell selection, we just set the cursor to // the beginning of the cell's text. if (bvcur.selIsMultiCell()) { @@ -4045,12 +4194,12 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CELL_BACKWARD: movePrevCell(cur); - cur.setSelection(false); + cur.selection(false); break; case LFUN_CELL_FORWARD: moveNextCell(cur); - cur.setSelection(false); + cur.selection(false); break; case LFUN_CHAR_FORWARD_SELECT: @@ -4247,55 +4396,21 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.screenUpdateFlags(Update::Force | Update::FitCursor); break; -// case LFUN_SCREEN_DOWN: { -// //if (hasSelection()) -// // cur.selection() = false; -// col_type const col = tabular.cellColumn(cur.idx()); -// int const t = cur.bv().top_y() + cur.bv().height(); -// if (t < yo() + tabular.getHeightOfTabular()) { -// cur.bv().scrollDocView(t, true); -// cur.idx() = tabular.cellBelow(first_visible_cell_) + col; -// } else { -// cur.idx() = tabular.getFirstCellInRow(tabular.rows() - 1) + col; -// } -// cur.par() = 0; -// cur.pos() = 0; -// break; -// } -// -// case LFUN_SCREEN_UP: { -// //if (hasSelection()) -// // cur.selection() = false; -// col_type const col = tabular.cellColumn(cur.idx()); -// int const t = cur.bv().top_y() + cur.bv().height(); -// if (yo() < 0) { -// cur.bv().scrollDocView(t, true); -// if (yo() > 0) -// cur.idx() = col; -// else -// cur.idx() = tabular.cellBelow(first_visible_cell_) + col; -// } else { -// cur.idx() = col; -// } -// cur.par() = cur.lastpar(); -// cur.pos() = cur.lastpos(); -// break; -// } - case LFUN_LAYOUT_TABULAR: cur.bv().showDialog("tabular"); break; - case LFUN_INSET_MODIFY: { - string arg; - if (cmd.getArg(1) == "from-dialog") - arg = cmd.getArg(0) + to_utf8(cmd.argument().substr(19)); + case LFUN_INSET_MODIFY: + // we come from the dialog + if (cmd.getArg(0) == "tabular") + tabularFeatures(cur, cmd.getLongArg(1)); else - arg = to_utf8(cmd.argument()); - if (!tabularFeatures(cur, arg)) cur.undispatched(); break; - } + + case LFUN_TABULAR_FEATURE: + tabularFeatures(cur, to_utf8(cmd.argument())); + break; // insert file functions case LFUN_FILE_INSERT_PLAINTEXT_PARA: @@ -4414,6 +4529,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: @@ -4462,25 +4578,9 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) } -// function sets an object as defined in func_status.h: -// states OK, Unknown, Disabled, On, Off. -bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, - FuncStatus & status) const +bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s, + string const & argument, FuncStatus & status) const { - switch (cmd.action()) { - case LFUN_INSET_MODIFY: { - if (&cur.inset() != this || cmd.getArg(0) != "tabular") - break; - - // FIXME: We only check for the very first argument... - string const s = cmd.getArg(1); - // We always enable the lfun if it is coming from the dialog - // because the dialog makes sure all the settings are valid, - // even though the first argument might not be valid now. - if (s == "from-dialog") { - status.setEnabled(true); - return true; - } int action = Tabular::LAST_ACTION; int i = 0; @@ -4496,8 +4596,6 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, return true; } - string const argument = cmd.getLongArg(2); - row_type sel_row_start = 0; row_type sel_row_end = 0; col_type sel_col_start = 0; @@ -4612,9 +4710,13 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::SET_LINE_TOP: case Tabular::SET_LINE_BOTTOM: + status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); + break; + case Tabular::SET_LINE_LEFT: case Tabular::SET_LINE_RIGHT: - status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setEnabled(!tabular.use_booktabs + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); break; case Tabular::TOGGLE_LINE_TOP: @@ -4628,12 +4730,14 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, break; case Tabular::TOGGLE_LINE_LEFT: - status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setEnabled(!tabular.use_booktabs + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); status.setOnOff(tabular.leftLine(cur.idx())); break; case Tabular::TOGGLE_LINE_RIGHT: - status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setEnabled(!tabular.use_booktabs + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); status.setOnOff(tabular.rightLine(cur.idx())); break; @@ -4642,12 +4746,14 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, // 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())); @@ -4656,6 +4762,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::M_ALIGN_CENTER: flag = false; + // fall through case Tabular::ALIGN_CENTER: status.setEnabled(!(tabular.isMultiRow(cur.idx()) && !tabular.getPWidth(cur.idx()).zero())); @@ -4676,6 +4783,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::M_VALIGN_TOP: flag = false; + // fall through case Tabular::VALIGN_TOP: status.setEnabled(!tabular.getPWidth(cur.idx()).zero() && !tabular.isMultiRow(cur.idx())); @@ -4685,6 +4793,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::M_VALIGN_BOTTOM: flag = false; + // fall through case Tabular::VALIGN_BOTTOM: status.setEnabled(!tabular.getPWidth(cur.idx()).zero() && !tabular.isMultiRow(cur.idx())); @@ -4694,6 +4803,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::M_VALIGN_MIDDLE: flag = false; + // fall through case Tabular::VALIGN_MIDDLE: status.setEnabled(!tabular.getPWidth(cur.idx()).zero() && !tabular.isMultiRow(cur.idx())); @@ -4702,6 +4812,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, break; case Tabular::SET_LONGTABULAR: + case Tabular::TOGGLE_LONGTABULAR: // setting as longtable is not allowed when table is inside a float if (cur.innerInsetOfType(FLOAT_CODE) != 0 || cur.innerInsetOfType(WRAP_CODE) != 0) @@ -4850,6 +4961,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, status.setOnOff(tabular.ltCaption(sel_row_start)); break; + case Tabular::TOGGLE_BOOKTABS: case Tabular::SET_BOOKTABS: status.setOnOff(tabular.use_booktabs); break; @@ -4864,6 +4976,39 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, break; } return true; +} + + +// function sets an object as defined in FuncStatus.h: +// states OK, Unknown, Disabled, On, Off. +bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, + FuncStatus & status) const +{ + switch (cmd.action()) { + case LFUN_INSET_MODIFY: + if (cmd.getArg(0) != "tabular") + break; + if (cmd.getArg(1) == "for-dialog") { + // The dialog is asking the status of a command + if (&cur.inset() != this) + break; + string action = cmd.getArg(2); + string arg = cmd.getLongArg(3); + return getFeatureStatus(cur, action, arg, status); + } else { + // We always enable the lfun if it is coming from the dialog + // because the dialog makes sure all the settings are valid, + // even though the first argument might not be valid now. + status.setEnabled(true); + return true; + } + + case LFUN_TABULAR_FEATURE: { + if (&cur.inset() != this) + break; + string action = cmd.getArg(0); + string arg = cmd.getLongArg(1); + return getFeatureStatus(cur, action, arg, status); } case LFUN_CAPTION_INSERT: { @@ -4880,7 +5025,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, } // check if there is already a caption bool have_caption = false; - InsetTableCell itc = InsetTableCell(*tabular.cellInset(cur.idx()).get()); + InsetTableCell itc = InsetTableCell(*tabular.cellInset(cur.idx())); ParagraphList::const_iterator pit = itc.paragraphs().begin(); ParagraphList::const_iterator pend = itc.paragraphs().end(); for (; pit != pend; ++pit) { @@ -4937,7 +5082,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); @@ -5051,13 +5196,7 @@ docstring InsetTabular::xhtml(XHTMLStream & xs, OutputParams const & rp) const void InsetTabular::validate(LaTeXFeatures & features) const { tabular.validate(features); - // FIXME XHTML - // It'd be better to be able to get this from an InsetLayout, but at present - // InsetLayouts do not seem really to work for things that aren't InsetTexts. - if (features.runparams().flavor == OutputParams::HTML) - features.addCSSSnippet( - "table { border: 1px solid black; display: inline-block; }\n" - "td { border: 1px solid black; padding: 0.5ex; }"); + features.useInsetLayout(getLayout()); } @@ -5081,7 +5220,7 @@ void InsetTabular::cursorPos(BufferView const & bv, // y offset correction y += cellYPos(sl.idx()); y += tabular.textVOffset(sl.idx()); - y += offset_valign_; + y += tabular.offsetVAlignment(); // x offset correction x += cellXPos(sl.idx()); @@ -5124,7 +5263,6 @@ int InsetTabular::dist(BufferView & bv, idx_type const cell, int x, int y) const Inset * InsetTabular::editXY(Cursor & cur, int x, int y) { //lyxerr << "InsetTabular::editXY: " << this << endl; - cur.setSelection(false); cur.push(*this); cur.idx() = getNearestCell(cur.bv(), x, y); return cur.bv().textMetrics(&cell(cur.idx())->text()).editXY(cur, x, y); @@ -5291,23 +5429,23 @@ void InsetTabular::movePrevCell(Cursor & cur, EntryDirection entry_from) } -bool InsetTabular::tabularFeatures(Cursor & cur, string const & argument) +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; - is >> s; - if (insetCode(s) != TABULAR_CODE) - return false; - // Safe guard. size_t safe_guard = 0; for (;;) { if (is.eof()) - break; + return; safe_guard++; if (safe_guard > 1000) { LYXERR0("parameter max count reached!"); - break; + return; } is >> s; Tabular::Feature action = Tabular::LAST_ACTION; @@ -5329,7 +5467,6 @@ bool InsetTabular::tabularFeatures(Cursor & cur, string const & argument) LYXERR(Debug::DEBUG, "Feature: " << s << "\t\tvalue: " << val); tabularFeatures(cur, action, val); } - return true; } @@ -5424,8 +5561,6 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; } - cur.recordUndoInset(this); - getSelection(cur, sel_row_start, sel_row_end, sel_col_start, sel_col_end); row_type const row = tabular.cellRow(cur.idx()); col_type const column = tabular.cellColumn(cur.idx()); @@ -5488,7 +5623,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, cur.idx() = tabular.cellIndex(sel_row_start, column); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; case Tabular::DELETE_COLUMN: @@ -5511,7 +5646,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, cur.idx() = tabular.cellIndex(row, sel_col_start); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; case Tabular::COPY_ROW: @@ -5601,6 +5736,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: @@ -5627,7 +5763,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.rightLine(cur.selEnd().idx())); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; } @@ -5684,7 +5820,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.getAlignment(cur.selEnd().idx())); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; } @@ -5723,6 +5859,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::SET_ALL_LINES: setLines = true; + // fall through case Tabular::UNSET_ALL_LINES: for (row_type r = sel_row_start; r <= sel_row_end; ++r) for (col_type c = sel_col_start; c <= sel_col_end; ++c) { @@ -5745,6 +5882,13 @@ void InsetTabular::tabularFeatures(Cursor & cur, } break; + case Tabular::TOGGLE_LONGTABULAR: + if (tabular.is_long_tabular) + tabularFeatures(cur, Tabular::UNSET_LONGTABULAR); + else + tabular.is_long_tabular = true; + break; + case Tabular::SET_LONGTABULAR: tabular.is_long_tabular = true; break; @@ -5840,6 +5984,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); @@ -5848,6 +5993,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); @@ -5856,6 +6002,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); @@ -5864,6 +6011,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); @@ -5872,6 +6020,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::UNSET_LTNEWPAGE: flag = false; + // fall through case Tabular::SET_LTNEWPAGE: tabular.setLTNewPage(row, flag); break; @@ -5882,7 +6031,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, cur.idx() = tabular.setLTCaption(row, true); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); // If a row is set as caption, then also insert // a caption. Otherwise the LaTeX output is broken. // Select cell if it is non-empty @@ -5898,7 +6047,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, cur.idx() = tabular.setLTCaption(row, false); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); FuncRequest fr(LFUN_INSET_DISSOLVE, "caption"); if (lyx::getStatus(fr).enabled()) lyx::dispatch(fr); @@ -5913,6 +6062,10 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; } + case Tabular::TOGGLE_BOOKTABS: + tabular.use_booktabs = !tabular.use_booktabs; + break; + case Tabular::SET_BOOKTABS: tabular.use_booktabs = true; break; @@ -6070,6 +6223,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; @@ -6229,7 +6383,6 @@ bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf, if (usePaste) { paste_tabular.reset(new Tabular(buffer_, rows, maxCols)); loctab = paste_tabular.get(); - cols = 0; dirtyTabularStack(true); } else { loctab = &tabular;