X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetTabular.cpp;h=375d7561b68c7875c2c4af573821692f44fc2236;hb=7986ac2f322aeb9c764d1c518cedd159d62f32d7;hp=52c10489f5aec4e0e4218717f2ab62b782549893;hpb=93a43742a5f1db8a632233c15e2b8d61b4835f3a;p=lyx.git diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index 52c10489f5..375d7561b6 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 }, @@ -191,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 } }; @@ -256,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(); } @@ -318,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; @@ -522,7 +534,7 @@ string const featureAsString(Tabular::Feature action) } -DocIterator separatorPos(InsetTableCell * cell, docstring const & align_d) +DocIterator separatorPos(InsetTableCell const * cell, docstring const & align_d) { DocIterator dit = doc_iterator_begin(&(cell->buffer()), cell); for (; dit; dit.forwardChar()) @@ -538,11 +550,11 @@ 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); - tail.paragraphs().front().eraseChars(0, + tail.paragraphs().front().eraseChars(0, dit.pos() < psize ? dit.pos() + 1 : psize, false); } @@ -628,30 +640,6 @@ Tabular::CellData & Tabular::CellData::operator=(CellData const & cs) return *this; } -void Tabular::CellData::swap(CellData & rhs) -{ - std::swap(cellno, rhs.cellno); - std::swap(width, rhs.width); - std::swap(multicolumn, rhs.multicolumn); - std::swap(multirow, rhs.multirow); - std::swap(mroffset, rhs.mroffset); - std::swap(alignment, rhs.alignment); - std::swap(valignment, rhs.valignment); - std::swap(decimal_hoffset, rhs.decimal_hoffset); - std::swap(decimal_width, rhs.decimal_width); - std::swap(voffset, rhs.voffset); - std::swap(top_line, rhs.top_line); - std::swap(bottom_line, rhs.bottom_line); - std::swap(left_line, rhs.left_line); - std::swap(right_line, rhs.right_line); - std::swap(usebox, rhs.usebox); - std::swap(rotate, rhs.rotate); - std::swap(align_special, rhs.align_special); - p_width.swap(rhs.p_width); - inset.swap(rhs.inset); -} - - Tabular::RowData::RowData() : ascent(0), descent(0), @@ -676,7 +664,7 @@ Tabular::ColumnData::ColumnData() Tabular::ltType::ltType() - : topDL(false), + : set(false), topDL(false), bottomDL(false), empty(false) {} @@ -762,9 +750,9 @@ void Tabular::appendRow(row_type row) void Tabular::insertRow(row_type const row, bool copy) { row_info.insert(row_info.begin() + row + 1, RowData(row_info[row])); - cell_info.insert(cell_info.begin() + row + 1, + cell_info.insert(cell_info.begin() + row + 1, cell_vector(0, CellData(buffer_))); - + for (col_type c = 0; c < ncols(); ++c) { cell_info[row + 1].insert(cell_info[row + 1].begin() + c, copy ? CellData(cell_info[row][c]) : CellData(buffer_)); @@ -773,7 +761,7 @@ void Tabular::insertRow(row_type const row, bool copy) if (cell_info[row][c].multirow == CELL_BEGIN_OF_MULTIROW) cell_info[row + 1][c].multirow = CELL_PART_OF_MULTIROW; } - + updateIndexes(); for (col_type c = 0; c < ncols(); ++c) { if (isPartOfMultiRow(row, c)) @@ -870,7 +858,7 @@ void Tabular::copyColumn(col_type const col) void Tabular::appendColumn(col_type col) -{ +{ insertColumn(col, false); } @@ -896,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) @@ -968,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; } @@ -1052,8 +1040,8 @@ 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) - new_width = max(new_width, cellInfo(i).width + && cell_info[r][c].decimal_width != 0) + new_width = max(new_width, cellInfo(i).width + max_dwidth[c] - cellInfo(i).decimal_width); else new_width = max(new_width, cellInfo(i).width); @@ -1122,8 +1110,8 @@ void Tabular::setAlignment(idx_type cell, LyXAlignment align, if (align == LYX_ALIGN_DECIMAL && dpoint.empty()) dpoint = from_utf8(lyxrc.default_decimal_point); } else { - cellInfo(cell).alignment = align; - cellInset(cell).get()->setContentAlignment(align); + cellInfo(cell).alignment = align; + cellInset(cell)->setContentAlignment(align); } } @@ -1147,7 +1135,6 @@ namespace { */ void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, bool fixedWidth) { - inset->setAutoBreakRows(fixedWidth); inset->toggleFixedWidth(fixedWidth); if (fixedWidth) return; @@ -1165,7 +1152,7 @@ void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, bool fixedWidth) cur.pop(); } -} +} // namespace void Tabular::setColumnPWidth(Cursor & cur, idx_type cell, @@ -1313,7 +1300,7 @@ bool Tabular::columnRightLine(col_type c) const idx_type i = cellIndex(r, c); if (c == cellColumn(i) + columnSpan(i) - 1) { ++total; - bool left = (c + 1 < ncols() + bool left = (c + 1 < ncols() && cellInfo(cellIndex(r, c + 1)).left_line) || c + 1 == ncols(); if (cellInfo(i).right_line && left) @@ -1328,7 +1315,7 @@ LyXAlignment Tabular::getAlignment(idx_type cell, bool onlycolumn) const { if (!onlycolumn && (isMultiColumn(cell) || isMultiRow(cell))) return cellInfo(cell).alignment; - + return column_info[cellColumn(cell)].alignment; } @@ -1342,6 +1329,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)) @@ -1400,7 +1408,7 @@ int Tabular::textVOffset(idx_type cell) const int voffset = cellInfo(cell).voffset; if (isMultiRow(cell)) { row_type const row = cellRow(cell); - voffset += (cellHeight(cell) - rowAscent(row) - rowDescent(row))/2; + voffset += (cellHeight(cell) - rowAscent(row) - rowDescent(row))/2; } return voffset; } @@ -1675,7 +1683,7 @@ void Tabular::read(Lexer & lex) bool Tabular::isMultiColumn(idx_type cell) const { - return (cellInfo(cell).multicolumn == CELL_BEGIN_OF_MULTICOLUMN + return (cellInfo(cell).multicolumn == CELL_BEGIN_OF_MULTICOLUMN || cellInfo(cell).multicolumn == CELL_PART_OF_MULTICOLUMN); } @@ -1690,7 +1698,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)]; } @@ -1712,7 +1726,8 @@ Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number, cs.alignment = column_info[col].alignment; setRightLine(cell, right_border); - for (idx_type i = 1; i < number; ++i) { + idx_type lastcell = cellIndex(row, col + number - 1); + for (idx_type i = 1; i < lastcell - cell + 1; ++i) { CellData & cs1 = cellInfo(cell + i); cs1.multicolumn = CELL_PART_OF_MULTICOLUMN; cs.inset->appendParagraphs(cs1.inset->paragraphs()); @@ -1793,7 +1808,7 @@ Tabular::idx_type Tabular::rowSpan(idx_type cell) const col_type row = cellRow(cell) + 1; while (row < nrows() && isPartOfMultiRow(row, column)) ++row; - + return row - cellRow(cell); } @@ -1851,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) @@ -1873,7 +1888,7 @@ Tabular::idx_type Tabular::cellAbove(idx_type cell) const { if (cellRow(cell) == 0) return cell; - + col_type const col = cellColumn(cell); row_type r = cellRow(cell) - 1; while (r > 0 && cell_info[r][col].multirow == CELL_PART_OF_MULTIROW) @@ -1906,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; @@ -2164,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,28 +2211,28 @@ 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) ++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") + os << "\\expandafter" << (use_booktabs ? "\\cmidrule" : "\\cline") << "\\expandafter{\\expandafter" << c + 1 + offset << "\\string-"; else 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) ++offset; - + os << c + offset << "} "; } } @@ -2226,18 +2241,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) @@ -2247,15 +2263,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; } @@ -2269,13 +2285,13 @@ 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) ++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") @@ -2283,14 +2299,14 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang) << "\\expandafter{\\expandafter" << c + 1 + offset << "\\string-"; else 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) ++offset; - + os << c + offset << "} "; } } @@ -2300,7 +2316,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) @@ -2310,38 +2327,47 @@ 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); - bool nextcellleft = nextcol < ncols() + bool nextcellleft = nextcol < ncols() && leftLine(cellIndex(r, nextcol)); 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; @@ -2388,9 +2414,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 << "}{"; @@ -2444,7 +2470,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"; +} } @@ -2460,6 +2500,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) @@ -2470,7 +2512,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; @@ -2482,7 +2525,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 @@ -2491,7 +2534,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"; @@ -2505,7 +2548,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"; @@ -2517,7 +2560,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"; @@ -2531,7 +2574,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"; @@ -2551,15 +2594,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); + InsetTableCell const * inset = cellInset(cell); Paragraph const & par = inset->paragraphs().front(); 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) @@ -2579,7 +2623,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; @@ -2587,15 +2639,18 @@ void Tabular::TeXRow(otexstream & os, row_type row, if (isPartOfMultiRow(row, c) && column_info[c].alignment != LYX_ALIGN_DECIMAL) { - if (cell != getLastCellInRow(row)) - os << " & "; + 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() @@ -2623,22 +2678,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) @@ -2651,7 +2727,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 @@ -2674,7 +2750,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) @@ -2697,17 +2773,22 @@ 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) - 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}"; @@ -2716,6 +2797,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]"; @@ -2737,19 +2819,33 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const break; } } - + os << "{"; 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}"; @@ -2764,24 +2860,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: @@ -2799,12 +2924,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) + @@ -2812,7 +2937,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"; } @@ -2831,8 +2956,15 @@ 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); } @@ -3000,6 +3132,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: @@ -3031,7 +3170,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; @@ -3334,21 +3473,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; @@ -3362,15 +3506,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()); } } @@ -3380,11 +3537,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; } @@ -3414,18 +3572,17 @@ bool InsetTableCell::allowParagraphCustomization(idx_type) const } +bool InsetTableCell::forceLocalFontSwitch() const +{ + return isFixedWidth; +} + + bool InsetTableCell::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & status) const { 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; @@ -3438,7 +3595,7 @@ bool InsetTableCell::getStatus(Cursor & cur, FuncRequest const & cmd, return true; } -docstring InsetTableCell::asString(bool intoInsets) +docstring InsetTableCell::asString(bool intoInsets) { docstring retval; if (paragraphs().empty()) @@ -3457,9 +3614,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); } @@ -3480,14 +3638,15 @@ 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))), scx_(0), - rowselect_(false), colselect_(false) + : Inset(buf), tabular(buf, max(rows, row_type(1)), max(columns, col_type(1))), + rowselect_(false), colselect_(false) { } InsetTabular::InsetTabular(InsetTabular const & tab) - : Inset(tab), tabular(tab.tabular), scx_(0) + : Inset(tab), tabular(tab.tabular), + rowselect_(false), colselect_(false) { } @@ -3526,7 +3685,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"); } @@ -3574,7 +3733,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) @@ -3614,21 +3773,21 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const MetricsInfo m = mi; Length const p_width = tabular.getPWidth(cell); if (!p_width.zero()) - m.base.textwidth = p_width.inPixels(mi.base.textwidth); + m.base.textwidth = p_width.inPixels(mi.base); tabular.cellInset(cell)->metrics(m, dim); if (!p_width.zero()) dim.wid = m.base.textwidth; - tabular.cellInfo(cell).width = dim.wid + 2 * WIDTH_OF_LINE + tabular.cellInfo(cell).width = dim.wid + 2 * WIDTH_OF_LINE + tabular.interColumnSpace(cell); // FIXME(?): do we need a second metrics call? - TextMetrics const & tm = + TextMetrics const & tm = mi.base.bv->textMetrics(tabular.cellInset(cell)->getText(0)); // 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) @@ -3659,14 +3818,14 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const int const lastpardes = tm.last().second->descent() + TEXT_TO_INSET_OFFSET; int offset = 0; - switch (tabular.getVAlignment(cell)) { + switch (tabular.getVAlignment(cell)) { case Tabular::LYX_VALIGN_TOP: - break; + break; case Tabular::LYX_VALIGN_MIDDLE: - offset = -(dim.des - lastpardes)/2; - break; + offset = -(dim.des - lastpardes)/2; + break; case Tabular::LYX_VALIGN_BOTTOM: - offset = -(dim.des - lastpardes); + offset = -(dim.des - lastpardes); break; } tabular.cell_info[r][c].voffset = offset; @@ -3675,37 +3834,22 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const } int const top_space = tabular.row_info[r].top_space_default ? default_line_space : - tabular.row_info[r].top_space.inPixels(mi.base.textwidth); + tabular.row_info[r].top_space.inPixels(mi.base); 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.textwidth); + tabular.row_info[r].bottom_space.inPixels(mi.base); 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; } -bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col) +bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col) const { if (&cur.inset() == this && cur.selection()) { @@ -3713,15 +3857,15 @@ bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col) row_type rs, re; col_type cs, ce; getSelection(cur, rs, re, cs, ce); - + idx_type const cell = tabular.cellIndex(row, col); col_type const cspan = tabular.columnSpan(cell); row_type const rspan = tabular.rowSpan(cell); - if (col + cspan - 1 >= cs && col <= ce + if (col + cspan - 1 >= cs && col <= ce && row + rspan - 1 >= rs && row <= re) return true; - } else - if (col == tabular.cellColumn(cur.idx()) + } else + if (col == tabular.cellColumn(cur.idx()) && row == tabular.cellRow(cur.idx())) { CursorSlice const & beg = cur.selBegin(); CursorSlice const & end = cur.selEnd(); @@ -3738,11 +3882,10 @@ bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col) void InsetTabular::draw(PainterInfo & pi, int x, int y) const { - x += scx_ + ADD_TO_TABULAR_WIDTH; + x += ADD_TO_TABULAR_WIDTH; BufferView * bv = pi.base.bv; Cursor & cur = pi.base.bv->cursor(); - resetPos(cur); // FIXME: As the full background is painted in drawBackground(), // we have no choice but to do a full repaint for the Text cells. @@ -3751,25 +3894,21 @@ 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) { if (tabular.isPartOfMultiColumn(r, c)) continue; - + idx = tabular.cellIndex(r, c); - + if (tabular.isPartOfMultiRow(r, c)) { nx += tabular.cellWidth(idx); 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); @@ -3782,7 +3921,7 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const } if (r + 1 < tabular.nrows()) - yy += tabular.rowDescent(r) + tabular.rowAscent(r + 1) + yy += tabular.rowDescent(r) + tabular.rowAscent(r + 1) + tabular.interRowSpace(r + 1); } } @@ -3790,8 +3929,8 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const void InsetTabular::drawBackground(PainterInfo & pi, int x, int y) const { - x += scx_ + ADD_TO_TABULAR_WIDTH; - y += offset_valign_ - tabular.rowAscent(0); + x += ADD_TO_TABULAR_WIDTH; + y += tabular.offsetVAlignment() - tabular.rowAscent(0); pi.pain.fillRectangle(x, y, tabular.width(), tabular.height(), pi.backgroundColor(this)); } @@ -3800,9 +3939,8 @@ void InsetTabular::drawBackground(PainterInfo & pi, int x, int y) const void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const { Cursor & cur = pi.base.bv->cursor(); - resetPos(cur); - x += scx_ + ADD_TO_TABULAR_WIDTH; + x += ADD_TO_TABULAR_WIDTH; if (!cur.selection()) return; @@ -3829,7 +3967,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; @@ -3839,7 +3977,7 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const + tabular.interRowSpace(r + 1); } - } + } // FIXME: This code has no effect because InsetTableCell does not handle // drawSelection other than the trivial implementation in Inset. //else { @@ -3850,48 +3988,63 @@ 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.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); col_type next_cell_col = col + 1; - while (next_cell_col < tabular.ncols() + while (next_cell_col < tabular.ncols() && tabular.isMultiColumn(tabular.cellIndex(row, next_cell_col))) next_cell_col++; 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); } @@ -3899,7 +4052,6 @@ void InsetTabular::edit(Cursor & cur, bool front, EntryDirection) { //lyxerr << "InsetTabular::edit: " << this << endl; cur.finishUndo(); - cur.setSelection(false); cur.push(*this); if (front) { if (isRightToLeft(cur)) @@ -3918,7 +4070,6 @@ void InsetTabular::edit(Cursor & cur, bool front, EntryDirection) } cur.setCurrentFont(); // FIXME: this accesses the position cache before it is initialized - //resetPos(cur); //cur.bv().fitCursor(); } @@ -3949,13 +4100,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); } @@ -3967,45 +4142,46 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) Cursor & bvcur = cur.bv().cursor(); FuncCode const act = cmd.action(); - + switch (act) { 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); - bvcur = cur; + 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); - bvcur = cur; + cur.selection(true); + bvcur = cur; colselect_ = true; break; } // do not reset cursor/selection if we have selected // some cells (bug 2715). if (cmd.button() == mouse_button::button3 - && &bvcur.selBegin().inset() == this - && bvcur.selIsMultiCell()) + && &bvcur.selBegin().inset() == this + && bvcur.selIsMultiCell()) ; else // Let InsetTableCell do it @@ -4029,7 +4205,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 @@ -4041,7 +4217,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 @@ -4050,7 +4226,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()) { @@ -4067,12 +4243,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: @@ -4082,7 +4258,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CHAR_RIGHT_SELECT: case LFUN_CHAR_RIGHT: case LFUN_CHAR_LEFT_SELECT: - case LFUN_CHAR_LEFT: + case LFUN_CHAR_LEFT: case LFUN_WORD_FORWARD: case LFUN_WORD_FORWARD_SELECT: case LFUN_WORD_BACKWARD: @@ -4091,14 +4267,14 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_WORD_RIGHT_SELECT: case LFUN_WORD_LEFT: case LFUN_WORD_LEFT_SELECT: { - // determine whether we move to next or previous cell, where to enter + // determine whether we move to next or previous cell, where to enter // the new cell from, and which command to "finish" (i.e., exit the // inset) with: bool next_cell; EntryDirection entry_from = ENTRY_DIRECTION_IGNORE; FuncCode finish_lfun; - if (act == LFUN_CHAR_FORWARD + if (act == LFUN_CHAR_FORWARD || act == LFUN_CHAR_FORWARD_SELECT || act == LFUN_WORD_FORWARD || act == LFUN_WORD_FORWARD_SELECT) { @@ -4112,7 +4288,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) next_cell = false; finish_lfun = LFUN_FINISHED_BACKWARD; } - // LEFT or RIGHT commands --- the interpretation will depend on the + // LEFT or RIGHT commands --- the interpretation will depend on the // table's direction. else { bool const right = act == LFUN_CHAR_RIGHT @@ -4120,14 +4296,14 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) || act == LFUN_WORD_RIGHT || act == LFUN_WORD_RIGHT_SELECT; next_cell = isRightToLeft(cur) != right; - + if (lyxrc.visual_cursor) entry_from = right ? ENTRY_DIRECTION_LEFT:ENTRY_DIRECTION_RIGHT; finish_lfun = right ? LFUN_FINISHED_RIGHT : LFUN_FINISHED_LEFT; } - bool const select = act == LFUN_CHAR_FORWARD_SELECT + bool const select = act == LFUN_CHAR_FORWARD_SELECT || act == LFUN_CHAR_BACKWARD_SELECT || act == LFUN_CHAR_RIGHT_SELECT || act == LFUN_CHAR_LEFT_SELECT @@ -4136,15 +4312,15 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) || act == LFUN_WORD_BACKWARD_SELECT || act == LFUN_WORD_LEFT_SELECT; - // If we have a multicell selection or we're + // If we have a multicell selection or we're // not doing some LFUN_*_SELECT thing anyway... if (!cur.selIsMultiCell() || !select) { col_type const c = tabular.cellColumn(cur.idx()); row_type const r = tabular.cellRow(cur.idx()); - // Are we trying to select the whole cell and is the whole cell + // Are we trying to select the whole cell and is the whole cell // not yet selected? bool const select_whole = select && !isCellSelected(cur, r, c) && - ((next_cell && cur.pit() == cur.lastpit() + ((next_cell && cur.pit() == cur.lastpit() && cur.pos() == cur.lastpos()) || (!next_cell && cur.pit() == 0 && cur.pos() == 0)); @@ -4162,7 +4338,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) break; } - // FIXME: When we support the selection of an empty cell, remove + // FIXME: When we support the selection of an empty cell, remove // the !empty_cell from this condition. For now we jump to the next // cell if the current cell is empty. if (cur.result().dispatched() && !empty_cell) @@ -4179,9 +4355,10 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) else movePrevCell(cur, entry_from); // if we're exiting the table, call the appropriate FINISHED lfun - if (sl == cur.top()) + if (sl == cur.top()) { cmd = FuncRequest(finish_lfun); - else + cur.undispatched(); + } else cur.dispatched(); cur.screenUpdateFlags(Update::Force | Update::FitCursor); @@ -4193,7 +4370,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_DOWN: if (!(cur.selection() && cur.selIsMultiCell())) cell(cur.idx())->dispatch(cur, cmd); - + cur.dispatched(); // override the cell's decision if (sl == cur.top()) { // if our Text didn't do anything to the cursor @@ -4268,55 +4445,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: @@ -4327,7 +4470,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) FileName(to_utf8(cmd.argument()))); if (tmpstr.empty()) break; - cur.recordUndoInset(INSERT_UNDO); + cur.recordUndoInset(); if (insertPlaintextString(cur.bv(), tmpstr, false)) { // content has been replaced, // so cursor might be invalid @@ -4342,7 +4485,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CUT: if (cur.selIsMultiCell()) { if (copySelection(cur)) { - cur.recordUndoInset(DELETE_UNDO); + cur.recordUndoInset(); cutSelection(cur); } } else @@ -4351,14 +4494,14 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_SELF_INSERT: if (cur.selIsMultiCell()) { - cur.recordUndoInset(DELETE_UNDO); + cur.recordUndoInset(); cutSelection(cur); BufferView * bv = &cur.bv(); docstring::const_iterator cit = cmd.argument().begin(); docstring::const_iterator const end = cmd.argument().end(); for (; cit != end; ++cit) bv->translateAndInsert(*cit, getText(cur.idx()), cur); - + cur.resetAnchor(); bv->bookmarkEditPosition(); } else @@ -4368,7 +4511,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CHAR_DELETE_BACKWARD: case LFUN_CHAR_DELETE_FORWARD: if (cur.selIsMultiCell()) { - cur.recordUndoInset(DELETE_UNDO); + cur.recordUndoInset(); cutSelection(cur); } else cell(cur.idx())->dispatch(cur, cmd); @@ -4394,7 +4537,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) // pass to InsertPlaintextString, but // only if we have multi-cell content if (clip.find_first_of(from_ascii("\t\n")) != docstring::npos) { - cur.recordUndoInset(INSERT_UNDO); + cur.recordUndoInset(); if (insertPlaintextString(cur.bv(), clip, false)) { // content has been replaced, // so cursor might be invalid @@ -4416,7 +4559,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) break; } if (theClipboard().isInternal()) { - cur.recordUndoInset(INSERT_UNDO); + cur.recordUndoInset(); pasteClipboard(cur); } break; @@ -4435,6 +4578,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: @@ -4483,25 +4627,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; @@ -4517,8 +4645,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; @@ -4627,15 +4753,20 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, 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::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: @@ -4649,12 +4780,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; @@ -4663,22 +4796,25 @@ 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()) + status.setEnabled(!(tabular.isMultiRow(cur.idx()) && !tabular.getPWidth(cur.idx()).zero())); status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_RIGHT); break; case Tabular::M_ALIGN_CENTER: flag = false; + // fall through case Tabular::ALIGN_CENTER: - status.setEnabled(!(tabular.isMultiRow(cur.idx()) + status.setEnabled(!(tabular.isMultiRow(cur.idx()) && !tabular.getPWidth(cur.idx()).zero())); status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_CENTER); break; @@ -4690,13 +4826,14 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, break; case Tabular::ALIGN_DECIMAL: - status.setEnabled(!tabular.isMultiRow(cur.idx()) + status.setEnabled(!tabular.isMultiRow(cur.idx()) && !tabular.isMultiColumn(cur.idx())); status.setOnOff(tabular.getAlignment(cur.idx(), true) == LYX_ALIGN_DECIMAL); break; case Tabular::M_VALIGN_TOP: flag = false; + // fall through case Tabular::VALIGN_TOP: status.setEnabled(!tabular.getPWidth(cur.idx()).zero() && !tabular.isMultiRow(cur.idx())); @@ -4706,6 +4843,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())); @@ -4715,6 +4853,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())); @@ -4723,6 +4862,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) @@ -4743,30 +4883,30 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::TABULAR_VALIGN_TOP: status.setEnabled(tabular.tabular_width.zero()); - status.setOnOff(tabular.tabular_valignment + status.setOnOff(tabular.tabular_valignment == Tabular::LYX_VALIGN_TOP); break; case Tabular::TABULAR_VALIGN_MIDDLE: status.setEnabled(tabular.tabular_width.zero()); - status.setOnOff(tabular.tabular_valignment + status.setOnOff(tabular.tabular_valignment == Tabular::LYX_VALIGN_MIDDLE); break; case Tabular::TABULAR_VALIGN_BOTTOM: status.setEnabled(tabular.tabular_width.zero()); - status.setOnOff(tabular.tabular_valignment + status.setOnOff(tabular.tabular_valignment == Tabular::LYX_VALIGN_BOTTOM); break; case Tabular::LONGTABULAR_ALIGN_LEFT: - status.setOnOff(tabular.longtabular_alignment + status.setOnOff(tabular.longtabular_alignment == Tabular::LYX_LONGTABULAR_ALIGN_LEFT); break; case Tabular::LONGTABULAR_ALIGN_CENTER: - status.setOnOff(tabular.longtabular_alignment + status.setOnOff(tabular.longtabular_alignment == Tabular::LYX_LONGTABULAR_ALIGN_CENTER); break; case Tabular::LONGTABULAR_ALIGN_RIGHT: - status.setOnOff(tabular.longtabular_alignment + status.setOnOff(tabular.longtabular_alignment == Tabular::LYX_LONGTABULAR_ALIGN_RIGHT); break; @@ -4871,6 +5011,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; @@ -4885,6 +5026,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: { @@ -4901,7 +5075,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) { @@ -4958,6 +5132,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, status.setEnabled(false); return true; } + // fall through case LFUN_NEWLINE_INSERT: { if (tabular.getPWidth(cur.idx()).zero()) { status.setEnabled(false); @@ -4978,7 +5153,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, getSelection(cur, rs, re, cs, ce); if (paste_tabular && paste_tabular->ncols() == ce - cs + 1 && paste_tabular->nrows() == re - rs + 1) - status.setEnabled(true); + status.setEnabled(true); else { status.setEnabled(false); status.message(_("Selection size should match clipboard content.")); @@ -5071,13 +5246,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()); } @@ -5101,13 +5270,12 @@ 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()); x += tabular.textHOffset(sl.idx()); x += ADD_TO_TABULAR_WIDTH; - x += scx_; } @@ -5145,10 +5313,8 @@ 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); - resetPos(cur); return cur.bv().textMetrics(&cell(cur.idx())->text()).editXY(cur, x, y); } @@ -5182,7 +5348,7 @@ int InsetTabular::cellYPos(idx_type const cell) const row_type row = tabular.cellRow(cell); int ly = 0; for (row_type r = 0; r < row; ++r) - ly += tabular.rowDescent(r) + tabular.rowAscent(r + 1) + ly += tabular.rowDescent(r) + tabular.rowAscent(r + 1) + tabular.interRowSpace(r + 1); return ly; } @@ -5198,36 +5364,6 @@ int InsetTabular::cellXPos(idx_type const cell) const } -void InsetTabular::resetPos(Cursor & cur) const -{ - BufferView & bv = cur.bv(); - int const maxwidth = bv.workWidth(); - - int const scx_old = scx_; - int const i = cur.find(this); - if (i == -1) { - scx_ = 0; - } else { - int const X1 = 0; - int const X2 = maxwidth; - int const offset = ADD_TO_TABULAR_WIDTH + 2; - int const x1 = xo(cur.bv()) + cellXPos(cur[i].idx()) + offset; - int const x2 = x1 + tabular.cellWidth(cur[i].idx()); - - if (x1 < X1) - scx_ = X1 + 20 - x1; - else if (x2 > X2) - scx_ = X2 - 20 - x2; - else - scx_ = 0; - } - - // only update if offset changed - if (scx_ != scx_old) - cur.screenUpdateFlags(Update::Force | Update::FitCursor); -} - - void InsetTabular::moveNextCell(Cursor & cur, EntryDirection entry_from) { row_type const row = tabular.cellRow(cur.idx()); @@ -5262,7 +5398,6 @@ void InsetTabular::moveNextCell(Cursor & cur, EntryDirection entry_from) if (cur.selIsMultiCell()) { cur.pit() = cur.lastpit(); cur.pos() = cur.lastpos(); - resetPos(cur); return; } @@ -5270,7 +5405,7 @@ void InsetTabular::moveNextCell(Cursor & cur, EntryDirection entry_from) cur.pos() = 0; // in visual mode, place cursor at extreme left or right - + switch(entry_from) { case ENTRY_DIRECTION_RIGHT: @@ -5285,7 +5420,6 @@ void InsetTabular::moveNextCell(Cursor & cur, EntryDirection entry_from) } cur.setCurrentFont(); - resetPos(cur); } @@ -5320,7 +5454,6 @@ void InsetTabular::movePrevCell(Cursor & cur, EntryDirection entry_from) if (cur.selIsMultiCell()) { cur.pit() = cur.lastpit(); cur.pos() = cur.lastpos(); - resetPos(cur); return; } @@ -5328,7 +5461,7 @@ void InsetTabular::movePrevCell(Cursor & cur, EntryDirection entry_from) cur.pos() = cur.lastpos(); // in visual mode, place cursor at extreme left or right - + switch(entry_from) { case ENTRY_DIRECTION_RIGHT: @@ -5343,27 +5476,26 @@ void InsetTabular::movePrevCell(Cursor & cur, EntryDirection entry_from) } cur.setCurrentFont(); - resetPos(cur); } -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; @@ -5385,7 +5517,6 @@ bool InsetTabular::tabularFeatures(Cursor & cur, string const & argument) LYXERR(Debug::DEBUG, "Feature: " << s << "\t\tvalue: " << val); tabularFeatures(cur, action, val); } - return true; } @@ -5410,7 +5541,7 @@ static void checkLongtableSpecial(Tabular::ltType & ltt, bool InsetTabular::oneCellHasRotationState(bool rotated, row_type row_start, row_type row_end, - col_type col_start, col_type col_end) const + col_type col_start, col_type col_end) const { for (row_type r = row_start; r <= row_end; ++r) for (col_type c = col_start; c <= col_end; ++c) @@ -5433,6 +5564,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; @@ -5458,10 +5590,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; case Tabular::ALIGN_DECIMAL: - if (tabular.column_info[tabular.cellColumn(cur.idx())].alignment == LYX_ALIGN_DECIMAL) - setAlign = LYX_ALIGN_CENTER; - else - setAlign = LYX_ALIGN_DECIMAL; + setAlign = LYX_ALIGN_DECIMAL; break; case Tabular::M_VALIGN_TOP: @@ -5483,8 +5612,6 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; } - cur.recordUndoInset(ATOMIC_UNDO, this); - getSelection(cur, sel_row_start, sel_row_end, sel_col_start, sel_col_end); row_type const row = tabular.cellRow(cur.idx()); col_type const column = tabular.cellColumn(cur.idx()); @@ -5499,10 +5626,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; } @@ -5547,7 +5676,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: @@ -5570,7 +5699,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: @@ -5660,6 +5789,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: @@ -5686,7 +5816,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.rightLine(cur.selEnd().idx())); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; } @@ -5743,7 +5873,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.getAlignment(cur.selEnd().idx())); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; } @@ -5780,16 +5910,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; @@ -5804,6 +5944,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; @@ -5857,8 +6004,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) @@ -5899,6 +6044,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); @@ -5907,6 +6053,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); @@ -5915,6 +6062,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); @@ -5923,6 +6071,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); @@ -5931,6 +6080,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::UNSET_LTNEWPAGE: flag = false; + // fall through case Tabular::SET_LTNEWPAGE: tabular.setLTNewPage(row, flag); break; @@ -5941,21 +6091,23 @@ 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. - lyx::dispatch(FuncRequest(LFUN_INSET_SELECT_ALL)); + // Select cell if it is non-empty + if (cur.lastpos() > 0 || cur.lastpit() > 0) + lyx::dispatch(FuncRequest(LFUN_INSET_SELECT_ALL)); lyx::dispatch(FuncRequest(LFUN_CAPTION_INSERT)); break; } - + case Tabular::UNSET_LTCAPTION: { if (!tabular.ltCaption(row)) break; 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); @@ -5970,6 +6122,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; @@ -6127,6 +6283,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; @@ -6173,7 +6330,7 @@ bool InsetTabular::isRightToLeft(Cursor & cur) const } -docstring InsetTabular::asString(idx_type stidx, idx_type enidx, +docstring InsetTabular::asString(idx_type stidx, idx_type enidx, bool intoInsets) { LASSERT(stidx <= enidx, return docstring()); @@ -6286,7 +6443,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; @@ -6420,7 +6576,7 @@ bool InsetTabular::insertCompletion(Cursor & cur, docstring const & s, bool fini } -void InsetTabular::completionPosAndDim(Cursor const & cur, int & x, int & y, +void InsetTabular::completionPosAndDim(Cursor const & cur, int & x, int & y, Dimension & dim) const { TextMetrics const & tm = cur.bv().textMetrics(cur.text()); @@ -6466,4 +6622,22 @@ string InsetTabular::params2string(InsetTabular const & inset) } +void InsetTabular::setLayoutForHiddenCells(DocumentClass const & dc) +{ + for (Tabular::col_type c = 0; c < tabular.ncols(); ++c) { + for (Tabular::row_type r = 0; r < tabular.nrows(); ++r) { + if (!tabular.isPartOfMultiColumn(r,c) && + !tabular.isPartOfMultiRow(r,c)) + continue; + + ParagraphList & parlist = tabular.cellInset(r,c)->paragraphs(); + ParagraphList::iterator it = parlist.begin(); + ParagraphList::iterator const en = parlist.end(); + for (; it != en; ++it) + it->setLayout(dc.plainLayout()); + } + } +} + + } // namespace lyx