X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetTabular.cpp;h=b12474344606c04db87920a5ca81e3f92c5408a4;hb=4824f7c9db8301550c1bc53c340fbeae916a46f3;hp=fe33dbeef013b866feceacfd29467787ee9b5c41;hpb=c7cb9fdc43b82127622564710abe7b0850c17c1c;p=lyx.git diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index fe33dbeef0..b124743446 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -13,6 +13,7 @@ * \author Jürgen Vigna * \author Uwe Stöhr * \author Edwin Leuven + * \author Scott Kostyshak * * Full author contact details are available in file CREDITS. */ @@ -32,6 +33,7 @@ #include "DispatchResult.h" #include "FuncRequest.h" #include "FuncStatus.h" +#include "InsetList.h" #include "Language.h" #include "LaTeXFeatures.h" #include "Lexer.h" @@ -62,10 +64,10 @@ #include -#include +#include #include #include -#include +#include using namespace std; using namespace lyx::support; @@ -114,6 +116,10 @@ TabularFeature tabularFeature[] = { Tabular::DELETE_COLUMN, "delete-column", false }, { Tabular::COPY_ROW, "copy-row", false }, { Tabular::COPY_COLUMN, "copy-column", false }, + { Tabular::MOVE_COLUMN_RIGHT, "move-column-right", false }, + { Tabular::MOVE_COLUMN_LEFT, "move-column-left", false }, + { Tabular::MOVE_ROW_DOWN, "move-row-down", false }, + { Tabular::MOVE_ROW_UP, "move-row-up", false }, { Tabular::SET_LINE_TOP, "set-line-top", true }, { Tabular::SET_LINE_BOTTOM, "set-line-bottom", true }, { Tabular::SET_LINE_LEFT, "set-line-left", true }, @@ -149,12 +155,12 @@ TabularFeature tabularFeature[] = { Tabular::UNSET_LONGTABULAR, "unset-longtabular", false }, { Tabular::SET_PWIDTH, "set-pwidth", true }, { Tabular::SET_MPWIDTH, "set-mpwidth", true }, - { Tabular::SET_ROTATE_TABULAR, "set-rotate-tabular", false }, - { Tabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular", false }, - { Tabular::TOGGLE_ROTATE_TABULAR, "toggle-rotate-tabular", false }, - { Tabular::SET_ROTATE_CELL, "set-rotate-cell", false }, - { Tabular::UNSET_ROTATE_CELL, "unset-rotate-cell", false }, - { Tabular::TOGGLE_ROTATE_CELL, "toggle-rotate-cell", false }, + { Tabular::SET_ROTATE_TABULAR, "set-rotate-tabular", true }, + { Tabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular", true }, + { Tabular::TOGGLE_ROTATE_TABULAR, "toggle-rotate-tabular", true }, + { Tabular::SET_ROTATE_CELL, "set-rotate-cell", true }, + { Tabular::UNSET_ROTATE_CELL, "unset-rotate-cell", true }, + { Tabular::TOGGLE_ROTATE_CELL, "toggle-rotate-cell", true }, { Tabular::SET_USEBOX, "set-usebox", true }, { Tabular::SET_LTHEAD, "set-lthead", true }, { Tabular::UNSET_LTHEAD, "unset-lthead", true }, @@ -165,6 +171,7 @@ TabularFeature tabularFeature[] = { Tabular::SET_LTLASTFOOT, "set-ltlastfoot", true }, { Tabular::UNSET_LTLASTFOOT, "unset-ltlastfoot", true }, { Tabular::SET_LTNEWPAGE, "set-ltnewpage", false }, + { Tabular::UNSET_LTNEWPAGE, "unset-ltnewpage", false }, { Tabular::TOGGLE_LTCAPTION, "toggle-ltcaption", false }, { Tabular::SET_LTCAPTION, "set-ltcaption", false }, { Tabular::UNSET_LTCAPTION, "unset-ltcaption", false }, @@ -188,62 +195,6 @@ TabularFeature tabularFeature[] = }; -template -string const write_attribute(string const & name, T const & t) -{ - string const s = tostr(t); - return s.empty() ? s : " " + name + "=\"" + s + "\""; -} - -template <> -string const write_attribute(string const & name, string const & t) -{ - return t.empty() ? t : " " + name + "=\"" + t + "\""; -} - - -template <> -string const write_attribute(string const & name, docstring const & t) -{ - return t.empty() ? string() : " " + name + "=\"" + to_utf8(t) + "\""; -} - - -template <> -string const write_attribute(string const & name, bool const & b) -{ - // we write only true attribute values so we remove a bit of the - // file format bloat for tabulars. - return b ? write_attribute(name, convert(b)) : string(); -} - - -template <> -string const write_attribute(string const & name, int const & i) -{ - // we write only true attribute values so we remove a bit of the - // file format bloat for tabulars. - return i ? write_attribute(name, convert(i)) : string(); -} - - -template <> -string const write_attribute(string const & name, Tabular::idx_type const & i) -{ - // we write only true attribute values so we remove a bit of the - // file format bloat for tabulars. - return i ? write_attribute(name, convert(i)) : string(); -} - - -template <> -string const write_attribute(string const & name, Length const & value) -{ - // we write only the value if we really have one same reson as above. - return value.zero() ? string() : write_attribute(name, value.asString()); -} - - string const tostr(LyXAlignment const & num) { switch (num) { @@ -503,6 +454,61 @@ void l_getline(istream & is, string & str) } } +template +string const write_attribute(string const & name, T const & t) +{ + string const s = tostr(t); + return s.empty() ? s : " " + name + "=\"" + s + "\""; +} + +template <> +string const write_attribute(string const & name, string const & t) +{ + return t.empty() ? t : " " + name + "=\"" + t + "\""; +} + + +template <> +string const write_attribute(string const & name, docstring const & t) +{ + return t.empty() ? string() : " " + name + "=\"" + to_utf8(t) + "\""; +} + + +template <> +string const write_attribute(string const & name, bool const & b) +{ + // we write only true attribute values so we remove a bit of the + // file format bloat for tabulars. + return b ? write_attribute(name, convert(b)) : string(); +} + + +template <> +string const write_attribute(string const & name, int const & i) +{ + // we write only true attribute values so we remove a bit of the + // file format bloat for tabulars. + return i ? write_attribute(name, convert(i)) : string(); +} + + +template <> +string const write_attribute(string const & name, Tabular::idx_type const & i) +{ + // we write only true attribute values so we remove a bit of the + // file format bloat for tabulars. + return i ? write_attribute(name, convert(i)) : string(); +} + + +template <> +string const write_attribute(string const & name, Length const & value) +{ + // we write only the value if we really have one same reson as above. + return value.zero() ? string() : write_attribute(name, value.asString()); +} + } // namespace @@ -516,19 +522,25 @@ string const featureAsString(Tabular::Feature action) } -InsetTableCell splitCell(InsetTableCell & head, docstring const align_d, bool & hassep) +DocIterator separatorPos(InsetTableCell * cell, docstring const & align_d) { - InsetTableCell tail = InsetTableCell(head); - - DocIterator dit = doc_iterator_begin(&head.buffer(), &head); + DocIterator dit = doc_iterator_begin(&(cell->buffer()), cell); for (; dit; dit.forwardChar()) if (dit.inTexted() && dit.depth() == 1 && dit.paragraph().find(align_d, false, false, dit.pos())) break; - pit_type const psize = head.paragraphs().front().size(); + return dit; +} + + +InsetTableCell splitCell(InsetTableCell & head, docstring const align_d, bool & hassep) +{ + InsetTableCell tail = InsetTableCell(head); + DocIterator const dit = separatorPos(&head, align_d); hassep = dit; if (hassep) { + pit_type const psize = head.paragraphs().front().size(); head.paragraphs().front().eraseChars(dit.pos(), psize, false); tail.paragraphs().front().eraseChars(0, dit.pos() < psize ? dit.pos() + 1 : psize, false); @@ -560,7 +572,7 @@ Tabular::CellData::CellData(Buffer * buf) left_line(false), right_line(false), usebox(BOX_NONE), - rotate(false), + rotate(0), inset(new InsetTableCell(buf)) { inset->setBuffer(*buf); @@ -681,7 +693,7 @@ void Tabular::init(Buffer * buf, row_type rows_arg, tabular_valignment = LYX_VALIGN_MIDDLE; tabular_width = Length(); longtabular_alignment = LYX_LONGTABULAR_ALIGN_CENTER; - rotate = false; + rotate = 0; use_booktabs = false; // set silly default lines for (row_type r = 0; r < nrows(); ++r) @@ -695,23 +707,54 @@ void Tabular::init(Buffer * buf, row_type rows_arg, } -void Tabular::appendRow(idx_type const cell) +void Tabular::deleteRow(row_type const row) { - row_type const row = cellRow(cell); + // Not allowed to delete last row + if (nrows() == 1) + return; + + for (col_type c = 0; c < ncols(); ++c) { + // Care about multirow cells + if (row + 1 < nrows() && + cell_info[row][c].multirow == CELL_BEGIN_OF_MULTIROW && + cell_info[row + 1][c].multirow == CELL_PART_OF_MULTIROW) { + cell_info[row + 1][c].multirow = CELL_BEGIN_OF_MULTIROW; + } + } + row_info.erase(row_info.begin() + row); + cell_info.erase(cell_info.begin() + row); + updateIndexes(); +} - row_info.insert(row_info.begin() + row + 1, RowData()); - row_info[row + 1] = row_info[row]; - cell_info.insert(cell_info.begin() + row + 1, - cell_vector(ncols(), CellData(buffer_))); +void Tabular::copyRow(row_type const row) +{ + insertRow(row, true); +} + + +void Tabular::appendRow(row_type row) +{ + insertRow(row, false); +} + + +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_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_)); + if (buffer().params().trackChanges) + cell_info[row + 1][c].inset->setChange(Change(Change::INSERTED)); if (cell_info[row][c].multirow == CELL_BEGIN_OF_MULTIROW) cell_info[row + 1][c].multirow = CELL_PART_OF_MULTIROW; - else - cell_info[row + 1][c].multirow = cell_info[row][c].multirow; } + updateIndexes(); - for (col_type c = 0; c < ncols(); ++c) { if (isPartOfMultiRow(row, c)) continue; @@ -732,69 +775,51 @@ void Tabular::appendRow(idx_type const cell) } -void Tabular::deleteRow(row_type const row) +void Tabular::moveColumn(col_type col, ColDirection direction) { - // Not allowed to delete last row - if (nrows() == 1) - return; + if (direction == Tabular::LEFT) + col = col - 1; - for (col_type c = 0; c < ncols(); ++c) { - // Care about multirow cells - if (row + 1 < nrows() && - cell_info[row][c].multirow == CELL_BEGIN_OF_MULTIROW && - cell_info[row + 1][c].multirow == CELL_PART_OF_MULTIROW) { - cell_info[row + 1][c].multirow = CELL_BEGIN_OF_MULTIROW; + std::swap(column_info[col], column_info[col + 1]); + + for (row_type r = 0; r < nrows(); ++r) { + std::swap(cell_info[r][col], cell_info[r][col + 1]); + std::swap(cell_info[r][col].left_line, cell_info[r][col + 1].left_line); + std::swap(cell_info[r][col].right_line, cell_info[r][col + 1].right_line); + + // FIXME track changes is broken for tabular features (#8469) + idx_type const i = cellIndex(r, col); + idx_type const j = cellIndex(r, col + 1); + if (buffer().params().trackChanges) { + cellInfo(i).inset->setChange(Change(Change::INSERTED)); + cellInfo(j).inset->setChange(Change(Change::INSERTED)); } } - row_info.erase(row_info.begin() + row); - cell_info.erase(cell_info.begin() + row); updateIndexes(); } -void Tabular::copyRow(row_type const row) +void Tabular::moveRow(row_type row, RowDirection direction) { - row_info.insert(row_info.begin() + row, row_info[row]); - cell_info.insert(cell_info.begin() + row, cell_info[row]); - - if (buffer().params().trackChanges) - for (col_type c = 0; c < ncols(); ++c) - cell_info[row + 1][c].inset->setChange(Change(Change::INSERTED)); - - updateIndexes(); -} + if (direction == Tabular::UP) + row = row - 1; + std::swap(row_info[row], row_info[row + 1]); -void Tabular::appendColumn(idx_type const cell) -{ - col_type const c = cellColumn(cell); - - column_info.insert(column_info.begin() + c + 1, ColumnData()); - column_info[c + 1] = column_info[c]; - - for (row_type r = 0; r < nrows(); ++r) { - cell_info[r].insert(cell_info[r].begin() + c + 1, - CellData(buffer_)); - if (cell_info[r][c].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) - cell_info[r][c + 1].multicolumn = CELL_PART_OF_MULTICOLUMN; - else - cell_info[r][c + 1].multicolumn = cell_info[r][c].multicolumn; - } - updateIndexes(); - for (row_type r = 0; r < nrows(); ++r) { - // inherit line settings - idx_type const i = cellIndex(r, c + 1); - idx_type const j = cellIndex(r, c); - setBottomLine(i, bottomLine(j)); - setTopLine(i, topLine(j)); - setLeftLine(i, leftLine(j)); - if (rightLine(j) && rightLine(j)) { - setRightLine(i, true); - setRightLine(j, false); - } - if (buffer().params().trackChanges) + for (col_type c = 0; c < ncols(); ++c) { + std::swap(cell_info[row][c], cell_info[row + 1][c]); + std::swap(cell_info[row][c].top_line, cell_info[row + 1][c].top_line); + std::swap(cell_info[row][c].bottom_line, cell_info[row + 1][c].bottom_line); + + // FIXME track changes is broken for tabular features (#8469) + idx_type const i = cellIndex(row, c); + idx_type const j = cellIndex(row + 1, c); + if (buffer().params().trackChanges) { cellInfo(i).inset->setChange(Change(Change::INSERTED)); + cellInfo(j).inset->setChange(Change(Change::INSERTED)); + } } + updateIndexes(); } @@ -819,16 +844,45 @@ void Tabular::deleteColumn(col_type const col) void Tabular::copyColumn(col_type const col) +{ + insertColumn(col, true); +} + + +void Tabular::appendColumn(col_type col) +{ + insertColumn(col, false); +} + + +void Tabular::insertColumn(col_type const col, bool copy) { BufferParams const & bp = buffer().params(); - column_info.insert(column_info.begin() + col, column_info[col]); + column_info.insert(column_info.begin() + col + 1, ColumnData(column_info[col])); for (row_type r = 0; r < nrows(); ++r) { - cell_info[r].insert(cell_info[r].begin() + col, cell_info[r][col]); + cell_info[r].insert(cell_info[r].begin() + col + 1, + copy ? CellData(cell_info[r][col]) : CellData(buffer_)); if (bp.trackChanges) cell_info[r][col + 1].inset->setChange(Change(Change::INSERTED)); + if (cell_info[r][col].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) + cell_info[r][col + 1].multicolumn = CELL_PART_OF_MULTICOLUMN; } updateIndexes(); + for (row_type r = 0; r < nrows(); ++r) { + // inherit line settings + idx_type const i = cellIndex(r, col + 1); + idx_type const j = cellIndex(r, col); + setBottomLine(i, bottomLine(j)); + setTopLine(i, topLine(j)); + setLeftLine(i, leftLine(j)); + if (rightLine(j) && rightLine(j)) { + setRightLine(i, true); + setRightLine(j, false); + } + if (buffer().params().trackChanges) + cellInfo(i).inset->setChange(Change(Change::INSERTED)); + } } @@ -1333,7 +1387,13 @@ int Tabular::textVOffset(idx_type cell) const Tabular::idx_type Tabular::getFirstCellInRow(row_type row) const { col_type c = 0; - while (cell_info[row][c].multirow == CELL_PART_OF_MULTIROW) + idx_type const numcells = numberOfCellsInRow(row); + // we check against numcells to make sure we do not crash if all the + // cells are multirow (bug #7535), but in that case our return value + // is really invalid, i.e., it is NOT the first cell in the row. but + // i do not know what to do here. (rgh) + while (c < numcells - 1 + && cell_info[row][c].multirow == CELL_PART_OF_MULTIROW) ++c; return cell_info[row][c].cellno; } @@ -1342,6 +1402,9 @@ Tabular::idx_type Tabular::getFirstCellInRow(row_type row) const Tabular::idx_type Tabular::getLastCellInRow(row_type row) const { col_type c = ncols() - 1; + // of course we check against 0 so we don't crash. but we have the same + // problem as in the previous routine: if all the cells are part of a + // multirow or part of a multi column, then our return value is invalid. while (c > 0 && (cell_info[row][c].multirow == CELL_PART_OF_MULTIROW || cell_info[row][c].multicolumn == CELL_PART_OF_MULTICOLUMN)) @@ -1380,7 +1443,7 @@ void Tabular::write(ostream & os) const << ">\n"; // global longtable options os << "(rotate)) << write_attribute("booktabs", use_booktabs) << write_attribute("islongtable", is_long_tabular) << write_attribute("firstHeadTopDL", endfirsthead.topDL) @@ -1468,14 +1531,13 @@ void Tabular::read(Lexer & lex) l_getline(is, line); if (!prefixIs(line, "= 2, /**/); + LATTEST(version >= 2); int rows_arg; if (!getTokenValue(line, "rows", rows_arg)) @@ -1594,13 +1656,24 @@ bool Tabular::isMultiColumn(idx_type cell) const } +bool Tabular::hasMultiColumn(col_type c) const +{ + for (row_type r = 0; r < nrows(); ++r) { + if (isMultiColumn(cellIndex(r, c))) + return true; + } + return false; +} + + Tabular::CellData & Tabular::cellInfo(idx_type cell) const { return cell_info[cellRow(cell)][cellColumn(cell)]; } -Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number) +Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number, + bool const right_border) { idx_type const col = cellColumn(cell); idx_type const row = cellRow(cell); @@ -1613,8 +1686,7 @@ Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number) cs.multicolumn = CELL_BEGIN_OF_MULTICOLUMN; if (column_info[col].alignment != LYX_ALIGN_DECIMAL) cs.alignment = column_info[col].alignment; - if (col > 0) - setRightLine(cell, rightLine(cellIndex(row, col - 1))); + setRightLine(cell, right_border); for (idx_type i = 1; i < number; ++i) { CellData & cs1 = cellInfo(cell + i); @@ -1633,8 +1705,17 @@ bool Tabular::isMultiRow(idx_type cell) const || cellInfo(cell).multirow == CELL_PART_OF_MULTIROW); } +bool Tabular::hasMultiRow(row_type r) const +{ + for (col_type c = 0; c < ncols(); ++c) { + if (isMultiRow(cellIndex(r, c))) + return true; + } + return false; +} -Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number) +Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number, + bool const bottom_border) { idx_type const col = cellColumn(cell); idx_type const row = cellRow(cell); @@ -1653,10 +1734,10 @@ Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number) // this feature would be a fileformat change // until LyX supports this, use the deault alignment of multirow // cells: left - cs.alignment = LYX_ALIGN_LEFT; + cs.alignment = LYX_ALIGN_LEFT; - // set the bottom row of the last selected cell - setBottomLine(cell, bottomLine(cell + (number - 1)*ncols())); + // set the bottom line of the last selected cell + setBottomLine(cell, bottom_border); for (idx_type i = 1; i < number; ++i) { CellData & cs1 = cell_info[row + i][col]; @@ -1731,13 +1812,13 @@ void Tabular::unsetMultiRow(idx_type cell) } -void Tabular::setRotateCell(idx_type cell, bool flag) +void Tabular::setRotateCell(idx_type cell, int value) { - cellInfo(cell).rotate = flag; + cellInfo(cell).rotate = value; } -bool Tabular::getRotateCell(idx_type cell) const +int Tabular::getRotateCell(idx_type cell) const { return cellInfo(cell).rotate; } @@ -1749,7 +1830,7 @@ bool Tabular::needRotating() const return true; for (row_type r = 0; r < nrows(); ++r) for (col_type c = 0; c < ncols(); ++c) - if (cell_info[r][c].rotate) + if (cell_info[r][c].rotate != 0) return true; return false; } @@ -1788,8 +1869,8 @@ Tabular::idx_type Tabular::cellBelow(idx_type cell) const Tabular::idx_type Tabular::cellIndex(row_type row, col_type column) const { - LASSERT(column != npos && column < ncols() - && row != npos && row < nrows(), /**/); + LASSERT(column != npos && column < ncols(), column = 0); + LASSERT(row != npos && row < nrows(), row = 0); return cell_info[row][column].cellno; } @@ -1890,45 +1971,49 @@ bool Tabular::getLTNewPage(row_type row) const } -bool Tabular::haveLTHead() const +bool Tabular::haveLTHead(bool withcaptions) const { if (!is_long_tabular) return false; for (row_type i = 0; i < nrows(); ++i) - if (row_info[i].endhead) + if (row_info[i].endhead && + (withcaptions || !row_info[i].caption)) return true; return false; } -bool Tabular::haveLTFirstHead() const +bool Tabular::haveLTFirstHead(bool withcaptions) const { if (!is_long_tabular || endfirsthead.empty) return false; for (row_type r = 0; r < nrows(); ++r) - if (row_info[r].endfirsthead) + if (row_info[r].endfirsthead && + (withcaptions || !row_info[r].caption)) return true; return false; } -bool Tabular::haveLTFoot() const +bool Tabular::haveLTFoot(bool withcaptions) const { if (!is_long_tabular) return false; for (row_type r = 0; r < nrows(); ++r) - if (row_info[r].endfoot) + if (row_info[r].endfoot && + (withcaptions || !row_info[r].caption)) return true; return false; } -bool Tabular::haveLTLastFoot() const +bool Tabular::haveLTLastFoot(bool withcaptions) const { if (!is_long_tabular || endlastfoot.empty) return false; for (row_type r = 0; r < nrows(); ++r) - if (row_info[r].endlastfoot) + if (row_info[r].endlastfoot && + (withcaptions || !row_info[r].caption)) return true; return false; } @@ -1938,11 +2023,16 @@ Tabular::idx_type Tabular::setLTCaption(row_type row, bool what) { idx_type i = getFirstCellInRow(row); if (what) { - setMultiColumn(i, numberOfCellsInRow(row)); + setMultiColumn(i, numberOfCellsInRow(row), false); setTopLine(i, false); setBottomLine(i, false); setLeftLine(i, false); setRightLine(i, false); + if (!row_info[row].endfirsthead && !row_info[row].endhead && + !row_info[row].endfoot && !row_info[row].endlastfoot) { + setLTHead(row, true, endfirsthead, true); + row_info[row].endfirsthead = true; + } } else { unsetMultiColumn(i); // When unsetting a caption row, also all existing @@ -1959,13 +2049,34 @@ bool Tabular::ltCaption(row_type row) const } -bool Tabular::haveLTCaption() const +bool Tabular::haveLTCaption(CaptionType captiontype) const { if (!is_long_tabular) return false; - for (row_type r = 0; r < nrows(); ++r) - if (row_info[r].caption) - return true; + for (row_type r = 0; r < nrows(); ++r) { + if (row_info[r].caption) { + switch (captiontype) { + case CAPTION_FIRSTHEAD: + if (row_info[r].endfirsthead) + return true; + break; + case CAPTION_HEAD: + if (row_info[r].endhead) + return true; + break; + case CAPTION_FOOT: + if (row_info[r].endfoot) + return true; + break; + case CAPTION_LASTFOOT: + if (row_info[r].endlastfoot) + return true; + break; + case CAPTION_ANY: + return true; + } + } + } return false; } @@ -1990,14 +2101,14 @@ void Tabular::setRowDescent(row_type row, int height) int Tabular::rowAscent(row_type row) const { - LASSERT(row < nrows(), /**/); + LASSERT(row < nrows(), row = 0); return row_info[row].ascent; } int Tabular::rowDescent(row_type row) const { - LASSERT(row < nrows(), /**/); + LASSERT(row < nrows(), row = 0); return row_info[row].descent; } @@ -2014,16 +2125,16 @@ int Tabular::height() const bool Tabular::isPartOfMultiColumn(row_type row, col_type column) const { - LASSERT(row < nrows(), /**/); - LASSERT(column < ncols(), /**/); + LASSERT(row < nrows(), return false); + LASSERT(column < ncols(), return false); return cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN; } bool Tabular::isPartOfMultiRow(row_type row, col_type column) const { - LASSERT(row < nrows(), /**/); - LASSERT(column < ncols(), /**/); + LASSERT(row < nrows(), return false); + LASSERT(column < ncols(), return false); return cell_info[row][column].multirow == CELL_PART_OF_MULTIROW; } @@ -2042,8 +2153,8 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, string const lang) cons // multirow, no line must be drawn. if (row != 0) if (isMultiRow(cellIndex(row, c)) - && isMultiRow(cellIndex(row - 1, c))) - topline[c] = false; + && cell_info[row][c].multirow != CELL_BEGIN_OF_MULTIROW) + topline[c] = false; if (topline[c]) ++nset; } @@ -2102,13 +2213,14 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const lang) c for (col_type c = 0; c < ncols(); ++c) { bottomline.push_back(bottomLine(cellIndex(row, c))); topline.push_back(!lastrow && topLine(cellIndex(row + 1, c))); - // If cell is part of a multirow and not the last or first cell of the + // If cell is part of a multirow and not the last cell of the // multirow, no line must be drawn. if (!lastrow) if (isMultiRow(cellIndex(row, c)) - && isMultiRow(cellIndex(row + 1, c))) { - bottomline[c] = false; - topline[c] = false; + && isMultiRow(cellIndex(row + 1, c)) + && cell_info[row + 1][c].multirow != CELL_BEGIN_OF_MULTIROW) { + bottomline[c] = false; + topline[c] = false; } nextrowset &= topline[c]; } @@ -2190,8 +2302,11 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell, || (coldouble != celldouble); // we center in multicol when no decimal point - ismulticol |= ((column_info[c].alignment == LYX_ALIGN_DECIMAL) - && (cellInfo(cell).decimal_width == 0)); + if (column_info[c].alignment == LYX_ALIGN_DECIMAL) { + docstring const align_d = column_info[c].decimal_point; + DocIterator const dit = separatorPos(cellInset(cell).get(), align_d); + ismulticol |= !dit; + } // up counter by 1 for each decimally aligned col since they use 2 latex cols int latexcolspan = columnSpan(cell); @@ -2271,9 +2386,9 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell, os << "{"; } // end if ismultirow - if (getRotateCell(cell)) { - os << "\\begin{sideways}\n"; - } + if (getRotateCell(cell) != 0) + os << "\\begin{turn}{" << convert(getRotateCell(cell)) << "}\n"; + if (getUsebox(cell) == BOX_PARBOX) { os << "\\parbox["; switch (valign) { @@ -2320,8 +2435,8 @@ void Tabular::TeXCellPostamble(otexstream & os, idx_type cell, os << '}'; else if (getUsebox(cell) == BOX_MINIPAGE) os << breakln << "\\end{minipage}"; - if (getRotateCell(cell)) - os << breakln << "\\end{sideways}"; + if (getRotateCell(cell) != 0) + os << breakln << "\\end{turn}"; if (ismultirow) os << '}'; if (ismulticol) @@ -2336,16 +2451,16 @@ void Tabular::TeXLongtableHeaderFooter(otexstream & os, return; // caption handling - // the caption must be output before the headers + // output caption which is in no header or footer if (haveLTCaption()) { for (row_type r = 0; r < nrows(); ++r) { - if (row_info[r].caption) + 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); } } // output first header info - // first header must be output before the header, otherwise the - // correct caption placement becomes really weird if (haveLTFirstHead()) { if (endfirsthead.topDL) os << "\\hline\n"; @@ -2458,7 +2573,8 @@ void Tabular::TeXRow(otexstream & os, row_type row, Paragraph const & par = inset->paragraphs().front(); bool rtl = par.isRTL(buffer().params()) && !par.empty() - && getPWidth(cell).zero(); + && getPWidth(cell).zero() + && !runparams.use_polyglossia; if (rtl) { string const lang = @@ -2467,7 +2583,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, os << "\\textFR{"; else if (lang == "arabic_arabi") os << "\\textAR{"; - // currently, remaning RTL languages are + // currently, remaining RTL languages are // arabic_arabtex and hebrew else os << "\\R{"; @@ -2480,8 +2596,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, ? OutputParams::PLAIN : OutputParams::ALIGNED; - if (getAlignment(cell) == LYX_ALIGN_DECIMAL - && cellInfo(cell).decimal_width != 0) { + if (getAlignment(cell) == LYX_ALIGN_DECIMAL) { // copy cell and split in 2 InsetTableCell head = InsetTableCell(*cellInset(cell).get()); head.setBuffer(buffer()); @@ -2491,13 +2606,15 @@ void Tabular::TeXRow(otexstream & os, row_type row, head.setMacrocontextPositionRecursive(dit); bool hassep = false; InsetTableCell tail = splitCell(head, column_info[c].decimal_point, hassep); - tail.setBuffer(head.buffer()); - dit.pop_back(); - dit.push_back(CursorSlice(tail)); - tail.setMacrocontextPositionRecursive(dit); head.latex(os, newrp); - os << '&'; - tail.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); + } } else if (!isPartOfMultiRow(row, c)) { if (!runparams.nice) os.texrow().start(par.id(), 0); @@ -2516,13 +2633,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, os << " &\n"; } } - if (row_info[row].caption && !endfirsthead.empty && !haveLTFirstHead()) - // if no first header and no empty first header is used, - // the caption needs to be terminated by \endfirsthead - // (bug 6057) - os << "\\endfirsthead"; - else - os << "\\tabularnewline"; + os << "\\tabularnewline"; if (row_info[row].bottom_space_default) { if (use_booktabs) os << "\\addlinespace"; @@ -2570,8 +2681,8 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const if (runparams.lastid != -1) os.texrow().start(runparams.lastid, runparams.lastpos); - if (rotate) - os << "\\begin{sideways}\n"; + if (rotate != 0) + os << "\\begin{turn}{" << convert(rotate) << "}\n"; if (is_long_tabular) { os << "\\begin{longtable}"; @@ -2695,8 +2806,8 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const os << "\\end{tabular}"; } - if (rotate) - os << breakln << "\\end{sideways}"; + if (rotate != 0) + os << breakln << "\\end{turn}"; } @@ -2788,6 +2899,7 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const //+--------------------------------------------------------------------- // output caption info + // The caption flag wins over head/foot if (haveLTCaption()) { os << "\n"; ++ret; @@ -2800,11 +2912,12 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const ++ret; } // output header info - if (haveLTHead() || haveLTFirstHead()) { + if (haveLTHead(false) || haveLTFirstHead(false)) { os << "\n"; ++ret; for (row_type r = 0; r < nrows(); ++r) { - if (row_info[r].endhead || row_info[r].endfirsthead) { + if ((row_info[r].endhead || row_info[r].endfirsthead) && + !row_info[r].caption) { ret += docbookRow(os, r, runparams); } } @@ -2812,11 +2925,12 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const ++ret; } // output footer info - if (haveLTFoot() || haveLTLastFoot()) { + if (haveLTFoot(false) || haveLTLastFoot(false)) { os << "\n"; ++ret; for (row_type r = 0; r < nrows(); ++r) { - if (row_info[r].endfoot || row_info[r].endlastfoot) { + if ((row_info[r].endfoot || row_info[r].endlastfoot) && + !row_info[r].caption) { ret += docbookRow(os, r, runparams); } } @@ -2857,7 +2971,7 @@ docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row, xs << html::StartTag("tr"); for (col_type c = 0; c < ncols(); ++c) { - if (isPartOfMultiColumn(row, c)) + if (isPartOfMultiColumn(row, c) || isPartOfMultiRow(row, c)) continue; stringstream attr; @@ -2889,6 +3003,8 @@ docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row, if (isMultiColumn(cell)) attr << " colspan='" << columnSpan(cell) << "'"; + else if (isMultiRow(cell)) + attr << " rowspan='" << rowSpan(cell) << "'"; xs << html::StartTag(celltag, attr.str()) << html::CR(); ret += cellInset(cell)->xhtml(xs, runparams); @@ -2920,6 +3036,7 @@ docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const } xs << html::StartTag("div", "class='longtable' style='text-align: " + align + ";'") << html::CR(); + // The caption flag wins over head/foot if (haveLTCaption()) { xs << html::StartTag("div", "class='longtable-caption' style='text-align: " + align + ";'") << html::CR(); @@ -2933,30 +3050,32 @@ docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const xs << html::StartTag("table") << html::CR(); // output header info - bool const havefirsthead = haveLTFirstHead(); + bool const havefirsthead = haveLTFirstHead(false); // if we have a first head, then we are going to ignore the // headers for the additional pages, since there aren't any // in XHTML. this test accomplishes that. - bool const havehead = !havefirsthead && haveLTHead(); + bool const havehead = !havefirsthead && haveLTHead(false); if (havehead || havefirsthead) { xs << html::StartTag("thead") << html::CR(); for (row_type r = 0; r < nrows(); ++r) { - if ((havefirsthead && row_info[r].endfirsthead) - || (havehead && row_info[r].endhead)) { + if (((havefirsthead && row_info[r].endfirsthead) || + (havehead && row_info[r].endhead)) && + !row_info[r].caption) { ret += xhtmlRow(xs, r, runparams, true); } } xs << html::EndTag("thead") << html::CR(); } // output footer info - bool const havelastfoot = haveLTLastFoot(); + bool const havelastfoot = haveLTLastFoot(false); // as before. - bool const havefoot = !havelastfoot && haveLTFoot(); + bool const havefoot = !havelastfoot && haveLTFoot(false); if (havefoot || havelastfoot) { xs << html::StartTag("tfoot") << html::CR(); for (row_type r = 0; r < nrows(); ++r) { - if ((havelastfoot && row_info[r].endlastfoot) - || (havefoot && row_info[r].endfoot)) { + if (((havelastfoot && row_info[r].endlastfoot) || + (havefoot && row_info[r].endfoot)) && + !row_info[r].caption) { ret += xhtmlRow(xs, r, runparams); } } @@ -2979,7 +3098,7 @@ docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const } -bool Tabular::plaintextTopHLine(odocstream & os, row_type row, +bool Tabular::plaintextTopHLine(odocstringstream & os, row_type row, vector const & clen) const { idx_type const fcell = getFirstCellInRow(row); @@ -3027,7 +3146,7 @@ bool Tabular::plaintextTopHLine(odocstream & os, row_type row, } -bool Tabular::plaintextBottomHLine(odocstream & os, row_type row, +bool Tabular::plaintextBottomHLine(odocstringstream & os, row_type row, vector const & clen) const { idx_type const fcell = getFirstCellInRow(row); @@ -3074,14 +3193,14 @@ bool Tabular::plaintextBottomHLine(odocstream & os, row_type row, } -void Tabular::plaintextPrintCell(odocstream & os, +void Tabular::plaintextPrintCell(odocstringstream & os, OutputParams const & runparams, idx_type cell, row_type row, col_type column, vector const & clen, - bool onlydata) const + bool onlydata, size_t max_length) const { odocstringstream sstr; - cellInset(cell)->plaintext(sstr, runparams); + cellInset(cell)->plaintext(sstr, runparams, max_length); if (onlydata) { os << sstr.str(); @@ -3124,9 +3243,9 @@ void Tabular::plaintextPrintCell(odocstream & os, } -void Tabular::plaintext(odocstream & os, +void Tabular::plaintext(odocstringstream & os, OutputParams const & runparams, int const depth, - bool onlydata, char_type delim) const + bool onlydata, char_type delim, size_t max_length) const { // first calculate the width of the single columns vector clen(ncols()); @@ -3140,7 +3259,7 @@ void Tabular::plaintext(odocstream & os, if (isMultiColumn(cell)) continue; odocstringstream sstr; - cellInset(cell)->plaintext(sstr, runparams); + cellInset(cell)->plaintext(sstr, runparams, max_length); if (clen[c] < sstr.str().length()) clen[c] = sstr.str().length(); } @@ -3152,7 +3271,7 @@ void Tabular::plaintext(odocstream & os, if (cell_info[r][c].multicolumn != CELL_BEGIN_OF_MULTICOLUMN) continue; odocstringstream sstr; - cellInset(cell)->plaintext(sstr, runparams); + cellInset(cell)->plaintext(sstr, runparams, max_length); int len = int(sstr.str().length()); idx_type const n = columnSpan(cell); for (col_type k = c; len > 0 && k < c + n - 1; ++k) @@ -3167,14 +3286,16 @@ void Tabular::plaintext(odocstream & os, if (!onlydata && plaintextTopHLine(os, r, clen)) os << docstring(depth * 2, ' '); for (col_type c = 0; c < ncols(); ++c) { - if (isPartOfMultiColumn(r, c)) + if (isPartOfMultiColumn(r, c) || isPartOfMultiRow(r,c)) continue; if (onlydata && c > 0) // we don't use operator<< for single UCS4 character. // see explanation in docstream.h os.put(delim); - plaintextPrintCell(os, runparams, cell, r, c, clen, onlydata); + plaintextPrintCell(os, runparams, cell, r, c, clen, onlydata, max_length); ++cell; + if (os.str().size() > max_length) + break; } os << endl; if (!onlydata) { @@ -3182,6 +3303,8 @@ void Tabular::plaintext(odocstream & os, if (plaintextBottomHLine(os, r, clen)) os << docstring(depth * 2, ' '); } + if (os.str().size() > max_length) + break; } } @@ -3309,6 +3432,12 @@ docstring InsetTableCell::asString(bool intoInsets) } +void InsetTableCell::addToToc(DocIterator const & di, bool output_active) const +{ + InsetText::iterateForToc(di, output_active); +} + + docstring InsetTableCell::xhtml(XHTMLStream & xs, OutputParams const & rp) const { if (!isFixedWidth) @@ -3369,6 +3498,13 @@ bool InsetTabular::insetAllowed(InsetCode code) const } +bool InsetTabular::allowsCaptionVariation(std::string const & newtype) const +{ + return tabular.is_long_tabular && + (newtype == "Standard" || newtype == "LongTableNoNumber"); +} + + void InsetTabular::write(ostream & os) const { os << "Tabular" << endl; @@ -3376,7 +3512,7 @@ void InsetTabular::write(ostream & os) const } -docstring InsetTabular::contextMenu(BufferView const &, int, int) const +string InsetTabular::contextMenu(BufferView const &, int, int) const { // FIXME: depending on the selection state, // we could offer a different menu. @@ -3384,9 +3520,9 @@ docstring InsetTabular::contextMenu(BufferView const &, int, int) const } -docstring InsetTabular::contextMenuName() const +string InsetTabular::contextMenuName() const { - return from_ascii("context-tabular"); + return "context-tabular"; } @@ -3438,10 +3574,7 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const { //lyxerr << "InsetTabular::metrics: " << mi.base.bv << " width: " << // mi.base.textwidth << "\n"; - if (!mi.base.bv) { - LYXERR0("need bv"); - LASSERT(false, /**/); - } + LBUFERR(mi.base.bv); for (row_type r = 0; r < tabular.nrows(); ++r) { int maxasc = 0; @@ -3482,11 +3615,7 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const // remove text leading decimal point docstring const align_d = tabular.column_info[c].decimal_point; - dit = doc_iterator_begin(&tail.buffer(), &tail); - for (; dit; dit.forwardChar()) - if (dit.inTexted() && dit.depth()==1 - && dit.paragraph().find(align_d, false, false, dit.pos())) - break; + dit = separatorPos(&tail, align_d); pit_type const psize = tail.paragraphs().front().size(); if (dit) { @@ -3728,9 +3857,13 @@ void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y, // Right x -= tabular.interColumnSpace(cell); + col_type next_cell_col = col + 1; + while (next_cell_col < tabular.ncols() + && tabular.isMultiColumn(tabular.cellIndex(row, next_cell_col))) + next_cell_col++; drawline = tabular.rightLine(cell) - || (col + 1 < tabular.ncols() - && tabular.leftLine(tabular.cellIndex(row, col + 1))); + || (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); @@ -3770,8 +3903,12 @@ void InsetTabular::updateBuffer(ParIterator const & it, UpdateType utype) // In a longtable, tell captions what the current float is Counters & cnts = buffer().masterBuffer()->params().documentClass().counters(); string const saveflt = cnts.current_float(); - if (tabular.is_long_tabular) + if (tabular.is_long_tabular) { cnts.current_float("table"); + // in longtables, we only step the counter once + cnts.step(from_ascii("table"), utype); + cnts.isLongtable(true); + } ParIterator it2 = it; it2.forwardPos(); @@ -3780,18 +3917,20 @@ void InsetTabular::updateBuffer(ParIterator const & it, UpdateType utype) buffer().updateBuffer(it2, utype); //reset afterwards - if (tabular.is_long_tabular) + if (tabular.is_long_tabular) { cnts.current_float(saveflt); + cnts.isLongtable(false); + } } -void InsetTabular::addToToc(DocIterator const & cpit) const +void InsetTabular::addToToc(DocIterator const & cpit, bool output_active) const { DocIterator dit = cpit; dit.forwardPos(); size_t const end = dit.nargs(); for ( ; dit.idx() < end; dit.top().forwardIdx()) - cell(dit.idx())->addToToc(dit); + cell(dit.idx())->addToToc(dit, output_active); } @@ -3994,6 +4133,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) if (select_whole && !empty_cell){ getText(cur.idx())->selectAll(cur); cur.dispatched(); + cur.screenUpdateFlags(Update::Force | Update::FitCursor); break; } @@ -4036,11 +4176,15 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) // setting also the right targetX. cur.selHandle(act == LFUN_DOWN_SELECT); if (tabular.cellRow(cur.idx()) != tabular.nrows() - 1) { + int const xtarget = cur.targetX(); + // WARNING: Once cur.idx() has been reset, the cursor is in + // an inconsistent state until pos() has been set. Be careful + // what you do with it! cur.idx() = tabular.cellBelow(cur.idx()); cur.pit() = 0; TextMetrics const & tm = cur.bv().textMetrics(cell(cur.idx())->getText(0)); - cur.pos() = tm.x2pos(cur.pit(), 0, cur.targetX()); + cur.pos() = tm.x2pos(cur.pit(), 0, xtarget); cur.setCurrentFont(); } } @@ -4054,9 +4198,10 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.pit() = cur.lastpit(); cur.pos() = cur.lastpos(); cur.setCurrentFont(); + cur.screenUpdateFlags(Update::Force | Update::FitCursor); return; } - cur.screenUpdateFlags(Update::FitCursor); + cur.screenUpdateFlags(Update::Force | Update::FitCursor); break; case LFUN_UP_SELECT: @@ -4070,13 +4215,17 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) // setting also the right targetX. cur.selHandle(act == LFUN_UP_SELECT); if (tabular.cellRow(cur.idx()) != 0) { + int const xtarget = cur.targetX(); + // WARNING: Once cur.idx() has been reset, the cursor is in + // an inconsistent state until pos() has been set. Be careful + // what you do with it! cur.idx() = tabular.cellAbove(cur.idx()); cur.pit() = cur.lastpit(); Text const * text = cell(cur.idx())->getText(0); TextMetrics const & tm = cur.bv().textMetrics(text); ParagraphMetrics const & pm = tm.parMetrics(cur.lastpit()); - cur.pos() = tm.x2pos(cur.pit(), pm.rows().size()-1, cur.targetX()); + cur.pos() = tm.x2pos(cur.pit(), pm.rows().size()-1, xtarget); cur.setCurrentFont(); } } @@ -4088,9 +4237,10 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.pit() = 0; cur.pos() = cur.lastpos(); cur.setCurrentFont(); + cur.screenUpdateFlags(Update::Force | Update::FitCursor); return; } - cur.screenUpdateFlags(Update::FitCursor); + cur.screenUpdateFlags(Update::Force | Update::FitCursor); break; // case LFUN_SCREEN_DOWN: { @@ -4132,10 +4282,16 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.bv().showDialog("tabular"); break; - case LFUN_INSET_MODIFY: - if (!tabularFeatures(cur, to_utf8(cmd.argument()))) + case LFUN_INSET_MODIFY: { + string arg; + if (cmd.getArg(1) == "from-dialog") + arg = cmd.getArg(0) + to_utf8(cmd.argument().substr(19)); + else + arg = to_utf8(cmd.argument()); + if (!tabularFeatures(cur, arg)) cur.undispatched(); break; + } // insert file functions case LFUN_FILE_INSERT_PLAINTEXT_PARA: @@ -4172,8 +4328,16 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) if (cur.selIsMultiCell()) { cur.recordUndoInset(DELETE_UNDO); cutSelection(cur); - } - cell(cur.idx())->dispatch(cur, cmd); + 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 + cell(cur.idx())->dispatch(cur, cmd); break; case LFUN_CHAR_DELETE_BACKWARD: @@ -4198,7 +4362,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CLIPBOARD_PASTE: case LFUN_PRIMARY_SELECTION_PASTE: { docstring const clip = (act == LFUN_CLIPBOARD_PASTE) ? - theClipboard().getAsText() : + theClipboard().getAsText(Clipboard::PlainTextType) : theSelection().get(); if (clip.empty()) break; @@ -4246,9 +4410,11 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_FONT_SIZE: case LFUN_FONT_UNDERLINE: case LFUN_FONT_STRIKEOUT: - case LFUN_FONT_UULINE: - case LFUN_FONT_UWAVE: + case LFUN_FONT_UNDERUNDERLINE: + case LFUN_FONT_UNDERWAVE: case LFUN_LANGUAGE: + case LFUN_PARAGRAPH_PARAMS_APPLY: + case LFUN_PARAGRAPH_PARAMS: case LFUN_WORD_CAPITALIZE: case LFUN_WORD_UPCASE: case LFUN_WORD_LOWCASE: @@ -4359,6 +4525,56 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, && tabular.tabular_valignment == Tabular::LYX_VALIGN_MIDDLE); break; + case Tabular::MOVE_COLUMN_RIGHT: + case Tabular::MOVE_COLUMN_LEFT: + case Tabular::MOVE_ROW_DOWN: + case Tabular::MOVE_ROW_UP: { + if (cur.selection()) { + status.message(_("Selections not supported.")); + status.setEnabled(false); + break; + } + + if ((action == Tabular::MOVE_COLUMN_RIGHT && + tabular.ncols() == tabular.cellColumn(cur.idx()) + 1) || + (action == Tabular::MOVE_COLUMN_LEFT && + tabular.cellColumn(cur.idx()) == 0) || + (action == Tabular::MOVE_ROW_DOWN && + tabular.nrows() == tabular.cellRow(cur.idx()) + 1) || + (action == Tabular::MOVE_ROW_UP && + tabular.cellRow(cur.idx()) == 0)) { + status.setEnabled(false); + break; + } + + if (action == Tabular::MOVE_COLUMN_RIGHT || + action == Tabular::MOVE_COLUMN_LEFT) { + if (tabular.hasMultiColumn(tabular.cellColumn(cur.idx())) || + tabular.hasMultiColumn(tabular.cellColumn(cur.idx()) + + (action == Tabular::MOVE_COLUMN_RIGHT ? 1 : -1))) { + status.message(_("Multi-column in current or" + " destination column.")); + status.setEnabled(false); + break; + } + } + + if (action == Tabular::MOVE_ROW_DOWN || + action == Tabular::MOVE_ROW_UP) { + if (tabular.hasMultiRow(tabular.cellRow(cur.idx())) || + tabular.hasMultiRow(tabular.cellRow(cur.idx()) + + (action == Tabular::MOVE_ROW_DOWN ? 1 : -1))) { + status.message(_("Multi-row in current or" + " destination row.")); + status.setEnabled(false); + break; + } + } + + status.setEnabled(true); + break; + } + case Tabular::SET_DECIMAL_POINT: status.setEnabled( tabular.getAlignment(cur.idx()) == LYX_ALIGN_DECIMAL); @@ -4497,8 +4713,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::TOGGLE_ROTATE_TABULAR: case Tabular::SET_ROTATE_TABULAR: - status.setEnabled(tabular.tabular_width.zero()); - status.setOnOff(tabular.rotate); + status.setOnOff(tabular.rotate != 0); break; case Tabular::TABULAR_VALIGN_TOP: @@ -4531,7 +4746,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, break; case Tabular::UNSET_ROTATE_TABULAR: - status.setOnOff(!tabular.rotate); + status.setOnOff(tabular.rotate == 0); break; case Tabular::TOGGLE_ROTATE_CELL: @@ -4550,67 +4765,87 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, break; // every row can only be one thing: - // either a footer or header or caption + // either a footer or header case Tabular::SET_LTFIRSTHEAD: - status.setEnabled(sel_row_start == sel_row_end - && !tabular.ltCaption(sel_row_start)); + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(tabular.getRowOfLTFirstHead(sel_row_start, dummyltt)); break; case Tabular::UNSET_LTFIRSTHEAD: + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(!tabular.getRowOfLTFirstHead(sel_row_start, dummyltt)); break; case Tabular::SET_LTHEAD: - status.setEnabled(sel_row_start == sel_row_end - && !tabular.ltCaption(sel_row_start)); + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(tabular.getRowOfLTHead(sel_row_start, dummyltt)); break; case Tabular::UNSET_LTHEAD: + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(!tabular.getRowOfLTHead(sel_row_start, dummyltt)); break; case Tabular::SET_LTFOOT: - status.setEnabled(sel_row_start == sel_row_end - && !tabular.ltCaption(sel_row_start)); + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(tabular.getRowOfLTFoot(sel_row_start, dummyltt)); break; case Tabular::UNSET_LTFOOT: + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(!tabular.getRowOfLTFoot(sel_row_start, dummyltt)); break; case Tabular::SET_LTLASTFOOT: - status.setEnabled(sel_row_start == sel_row_end - && !tabular.ltCaption(sel_row_start)); + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(tabular.getRowOfLTLastFoot(sel_row_start, dummyltt)); break; case Tabular::UNSET_LTLASTFOOT: + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(!tabular.getRowOfLTLastFoot(sel_row_start, dummyltt)); break; case Tabular::SET_LTNEWPAGE: status.setOnOff(tabular.getLTNewPage(sel_row_start)); break; + case Tabular::UNSET_LTNEWPAGE: + status.setOnOff(!tabular.getLTNewPage(sel_row_start)); + break; - // only one row can be the caption + // only one row in head/firsthead/foot/lasthead can be the caption // and a multirow cannot be set as caption case Tabular::SET_LTCAPTION: - case Tabular::UNSET_LTCAPTION: - case Tabular::TOGGLE_LTCAPTION: status.setEnabled(sel_row_start == sel_row_end - && !tabular.getRowOfLTFirstHead(sel_row_start, dummyltt) - && !tabular.getRowOfLTHead(sel_row_start, dummyltt) - && !tabular.getRowOfLTFoot(sel_row_start, dummyltt) - && !tabular.getRowOfLTLastFoot(sel_row_start, dummyltt) - && (!tabular.haveLTCaption() - || tabular.ltCaption(sel_row_start)) + && (!tabular.getRowOfLTFirstHead(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_FIRSTHEAD)) + && (!tabular.getRowOfLTHead(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_HEAD)) + && (!tabular.getRowOfLTFoot(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_FOOT)) + && (!tabular.getRowOfLTLastFoot(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_LASTFOOT)) && !tabular.isMultiRow(sel_row_start)); status.setOnOff(tabular.ltCaption(sel_row_start)); break; + case Tabular::UNSET_LTCAPTION: + status.setEnabled(sel_row_start == sel_row_end && tabular.ltCaption(sel_row_start)); + break; + + case Tabular::TOGGLE_LTCAPTION: + status.setEnabled(sel_row_start == sel_row_end && (tabular.ltCaption(sel_row_start) + || ((!tabular.getRowOfLTFirstHead(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_FIRSTHEAD)) + && (!tabular.getRowOfLTHead(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_HEAD)) + && (!tabular.getRowOfLTFoot(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_FOOT)) + && (!tabular.getRowOfLTLastFoot(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_LASTFOOT))))); + status.setOnOff(tabular.ltCaption(sel_row_start)); + break; + case Tabular::SET_BOOKTABS: status.setOnOff(tabular.use_booktabs); break; @@ -4627,6 +4862,37 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, return true; } + case LFUN_CAPTION_INSERT: { + // caption is only allowed in caption cell of longtable + if (!tabular.ltCaption(tabular.cellRow(cur.idx()))) { + status.setEnabled(false); + return true; + } + // only standard caption is allowed + string arg = cmd.getArg(0); + if (!arg.empty() && arg != "Standard") { + status.setEnabled(false); + return true; + } + // check if there is already a caption + bool have_caption = false; + InsetTableCell itc = InsetTableCell(*tabular.cellInset(cur.idx()).get()); + ParagraphList::const_iterator pit = itc.paragraphs().begin(); + ParagraphList::const_iterator pend = itc.paragraphs().end(); + for (; pit != pend; ++pit) { + InsetList::const_iterator it = pit->insetList().begin(); + InsetList::const_iterator end = pit->insetList().end(); + for (; it != end; ++it) { + if (it->inset->lyxCode() == CAPTION_CODE) { + have_caption = true; + break; + } + } + } + status.setEnabled(!have_caption); + return true; + } + // These are only enabled inside tabular case LFUN_CELL_BACKWARD: case LFUN_CELL_FORWARD: @@ -4661,7 +4927,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, } // disable in non-fixed-width cells - case LFUN_BREAK_PARAGRAPH: + case LFUN_PARAGRAPH_BREAK: // multirow does not allow paragraph breaks if (tabular.isMultiRow(cur.idx())) { status.setEnabled(false); @@ -4734,11 +5000,12 @@ void InsetTabular::latex(otexstream & os, OutputParams const & runparams) const } -int InsetTabular::plaintext(odocstream & os, OutputParams const & runparams) const +int InsetTabular::plaintext(odocstringstream & os, + OutputParams const & runparams, size_t max_length) const { os << '\n'; // output table on a new line int const dp = runparams.linelen > 0 ? runparams.depth : 0; - tabular.plaintext(os, runparams, dp, false, 0); + tabular.plaintext(os, runparams, dp, false, 0, max_length); return PLAINTEXT_NEWLINE; } @@ -4783,10 +5050,9 @@ void InsetTabular::validate(LaTeXFeatures & features) const // 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.addPreambleSnippet(""); + features.addCSSSnippet( + "table { border: 1px solid black; display: inline-block; }\n" + "td { border: 1px solid black; padding: 0.5ex; }"); } @@ -4830,7 +5096,7 @@ int InsetTabular::dist(BufferView & bv, idx_type const cell, int x, int y) const int const xend = xbeg + tabular.cellWidth(cell); row_type const row = tabular.cellRow(cell); int const ybeg = o.y_ - tabular.rowAscent(row) - - tabular.interRowSpace(row); + - tabular.interRowSpace(row) - tabular.textVOffset(cell); int const yend = ybeg + tabular.cellHeight(cell); if (x < xbeg) @@ -5081,7 +5347,6 @@ bool InsetTabular::tabularFeatures(Cursor & cur, string const & argument) for (; tabularFeature[i].action != Tabular::LAST_ACTION; ++i) { if (s != tabularFeature[i].feature) continue; - action = tabularFeature[i].action; break; } @@ -5124,12 +5389,17 @@ bool InsetTabular::oneCellHasRotationState(bool rotated, { for (row_type r = row_start; r <= row_end; ++r) for (col_type c = col_start; c <= col_end; ++c) - if (tabular.getRotateCell(tabular.cellIndex(r, c)) == rotated) - return true; - + if (rotated) { + if (tabular.getRotateCell(tabular.cellIndex(r, c)) != 0) + return true; + } else { + if (tabular.getRotateCell(tabular.cellIndex(r, c)) == 0) + return true; + } return false; } + void InsetTabular::tabularFeatures(Cursor & cur, Tabular::Feature feature, string const & value) { @@ -5163,7 +5433,10 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; case Tabular::ALIGN_DECIMAL: - setAlign = LYX_ALIGN_DECIMAL; + if (tabular.column_info[tabular.cellColumn(cur.idx())].alignment == LYX_ALIGN_DECIMAL) + setAlign = LYX_ALIGN_CENTER; + else + setAlign = LYX_ALIGN_DECIMAL; break; case Tabular::M_VALIGN_TOP: @@ -5226,16 +5499,22 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::APPEND_ROW: // append the row into the tabular - tabular.appendRow(cur.idx()); + tabular.appendRow(row); break; case Tabular::APPEND_COLUMN: // append the column into the tabular - tabular.appendColumn(cur.idx()); + tabular.appendColumn(column); cur.idx() = tabular.cellIndex(row, column); break; case Tabular::DELETE_ROW: + if (sel_row_end == tabular.nrows() - 1 && sel_row_start != 0) { + for (col_type c = 0; c < tabular.ncols(); c++) + tabular.setBottomLine(tabular.cellIndex(sel_row_start - 1, c), + tabular.bottomLine(tabular.cellIndex(sel_row_end, c))); + } + for (row_type r = sel_row_start; r <= sel_row_end; ++r) tabular.deleteRow(sel_row_start); if (sel_row_start >= tabular.nrows()) @@ -5247,6 +5526,18 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; case Tabular::DELETE_COLUMN: + if (sel_col_end == tabular.ncols() - 1 && sel_col_start != 0) { + for (row_type r = 0; r < tabular.nrows(); r++) + tabular.setRightLine(tabular.cellIndex(r, sel_col_start - 1), + tabular.rightLine(tabular.cellIndex(r, sel_col_end))); + } + + if (sel_col_start == 0 && sel_col_end != tabular.ncols() - 1) { + for (row_type r = 0; r < tabular.nrows(); r++) + tabular.setLeftLine(tabular.cellIndex(r, sel_col_end + 1), + tabular.leftLine(tabular.cellIndex(r, 0))); + } + for (col_type c = sel_col_start; c <= sel_col_end; ++c) tabular.deleteColumn(sel_col_start); if (sel_col_start >= tabular.ncols()) @@ -5266,6 +5557,26 @@ void InsetTabular::tabularFeatures(Cursor & cur, cur.idx() = tabular.cellIndex(row, column); break; + case Tabular::MOVE_COLUMN_RIGHT: + tabular.moveColumn(column, Tabular::RIGHT); + cur.idx() = tabular.cellIndex(row, column + 1); + break; + + case Tabular::MOVE_COLUMN_LEFT: + tabular.moveColumn(column, Tabular::LEFT); + cur.idx() = tabular.cellIndex(row, column - 1); + break; + + case Tabular::MOVE_ROW_DOWN: + tabular.moveRow(row, Tabular::DOWN); + cur.idx() = tabular.cellIndex(row + 1, column); + break; + + case Tabular::MOVE_ROW_UP: + tabular.moveRow(row, Tabular::UP); + cur.idx() = tabular.cellIndex(row - 1, column); + break; + case Tabular::SET_LINE_TOP: case Tabular::TOGGLE_LINE_TOP: { bool lineSet = (feature == Tabular::SET_LINE_TOP) @@ -5337,15 +5648,17 @@ void InsetTabular::tabularFeatures(Cursor & cur, // just multicol for one single cell // check whether we are completely in a multicol if (!tabular.isMultiColumn(cur.idx())) - tabular.setMultiColumn(cur.idx(), 1); + tabular.setMultiColumn(cur.idx(), 1, + tabular.rightLine(cur.idx())); break; } - // we have a selection so this means we just add all this + // we have a selection so this means we just add all these // cells to form a multicolumn cell idx_type const s_start = cur.selBegin().idx(); row_type const col_start = tabular.cellColumn(s_start); row_type const col_end = tabular.cellColumn(cur.selEnd().idx()); - cur.idx() = tabular.setMultiColumn(s_start, col_end - col_start + 1); + cur.idx() = tabular.setMultiColumn(s_start, col_end - col_start + 1, + tabular.rightLine(cur.selEnd().idx())); cur.pit() = 0; cur.pos() = 0; cur.setSelection(false); @@ -5361,10 +5674,27 @@ void InsetTabular::tabularFeatures(Cursor & cur, } case Tabular::MULTICOLUMN: { - if (tabular.isMultiColumn(cur.idx())) - tabularFeatures(cur, Tabular::UNSET_MULTICOLUMN); - else + if (!cur.selection()) { + if (tabular.isMultiColumn(cur.idx())) + tabularFeatures(cur, Tabular::UNSET_MULTICOLUMN); + else + tabularFeatures(cur, Tabular::SET_MULTICOLUMN); + break; + } + bool merge = false; + for (col_type c = sel_col_start; c <= sel_col_end; ++c) { + row_type const r = sel_row_start; + if (!tabular.isMultiColumn(tabular.cellIndex(r, c)) + || (r > sel_row_start && !tabular.isPartOfMultiColumn(r, c))) + merge = true; + } + // If the selection contains at least one singlecol cell + // or multiple multicol cells, + // we assume the user will merge is to a single multicol + if (merge) tabularFeatures(cur, Tabular::SET_MULTICOLUMN); + else + tabularFeatures(cur, Tabular::UNSET_MULTICOLUMN); break; } @@ -5373,7 +5703,8 @@ void InsetTabular::tabularFeatures(Cursor & cur, // just multirow for one single cell // check whether we are completely in a multirow if (!tabular.isMultiRow(cur.idx())) - tabular.setMultiRow(cur.idx(), 1); + tabular.setMultiRow(cur.idx(), 1, + tabular.bottomLine(cur.idx())); break; } // we have a selection so this means we just add all this @@ -5381,7 +5712,8 @@ void InsetTabular::tabularFeatures(Cursor & cur, idx_type const s_start = cur.selBegin().idx(); row_type const row_start = tabular.cellRow(s_start); row_type const row_end = tabular.cellRow(cur.selEnd().idx()); - cur.idx() = tabular.setMultiRow(s_start, row_end - row_start + 1); + cur.idx() = tabular.setMultiRow(s_start, row_end - row_start + 1, + tabular.bottomLine(cur.selEnd().idx())); cur.pit() = 0; cur.pos() = 0; cur.setSelection(false); @@ -5397,10 +5729,27 @@ void InsetTabular::tabularFeatures(Cursor & cur, } case Tabular::MULTIROW: { - if (tabular.isMultiRow(cur.idx())) - tabularFeatures(cur, Tabular::UNSET_MULTIROW); - else + if (!cur.selection()) { + if (tabular.isMultiRow(cur.idx())) + tabularFeatures(cur, Tabular::UNSET_MULTIROW); + else + tabularFeatures(cur, Tabular::SET_MULTIROW); + break; + } + bool merge = false; + for (row_type r = sel_row_start; r <= sel_row_end; ++r) { + col_type const c = sel_col_start; + if (!tabular.isMultiRow(tabular.cellIndex(r, c)) + || (r > sel_row_start && !tabular.isPartOfMultiRow(r, c))) + merge = true; + } + // If the selection contains at least one singlerow cell + // or multiple multirow cells, + // we assume the user will merge is to a single multirow + if (merge) tabularFeatures(cur, Tabular::SET_MULTIROW); + else + tabularFeatures(cur, Tabular::UNSET_MULTIROW); break; } @@ -5445,15 +5794,16 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; case Tabular::SET_ROTATE_TABULAR: - tabular.rotate = true; + tabular.rotate = convert(value); break; case Tabular::UNSET_ROTATE_TABULAR: - tabular.rotate = false; + tabular.rotate = 0; break; case Tabular::TOGGLE_ROTATE_TABULAR: - tabular.rotate = !tabular.rotate; + // when pressing the rotate button we default to 90° rotation + tabular.rotate != 0 ? tabular.rotate = 0 : tabular.rotate = 90; break; case Tabular::TABULAR_VALIGN_TOP: @@ -5485,13 +5835,13 @@ void InsetTabular::tabularFeatures(Cursor & cur, 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) - tabular.setRotateCell(tabular.cellIndex(r, c), true); + tabular.setRotateCell(tabular.cellIndex(r, c), convert(value)); break; case Tabular::UNSET_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) - tabular.setRotateCell(tabular.cellIndex(r, c), false); + tabular.setRotateCell(tabular.cellIndex(r, c), 0); break; case Tabular::TOGGLE_ROTATE_CELL: @@ -5500,9 +5850,13 @@ void InsetTabular::tabularFeatures(Cursor & cur, sel_row_start, sel_row_end, sel_col_start, sel_col_end); for (row_type r = sel_row_start; r <= sel_row_end; ++r) - for (col_type c = sel_col_start; c <= sel_col_end; ++c) - tabular.setRotateCell(tabular.cellIndex(r, c), - oneNotRotated); + for (col_type c = sel_col_start; c <= sel_col_end; ++c) { + // when pressing the rotate cell button we default to 90° rotation + if (oneNotRotated) + tabular.setRotateCell(tabular.cellIndex(r, c), 90); + else + tabular.setRotateCell(tabular.cellIndex(r, c), 0); + } } break; @@ -5548,8 +5902,10 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.setLTFoot(row, flag, ltt, true); break; + case Tabular::UNSET_LTNEWPAGE: + flag = false; case Tabular::SET_LTNEWPAGE: - tabular.setLTNewPage(row, !tabular.getLTNewPage(row)); + tabular.setLTNewPage(row, flag); break; case Tabular::SET_LTCAPTION: { @@ -5690,7 +6046,7 @@ bool InsetTabular::copySelection(Cursor & cur) odocstringstream os; OutputParams const runparams(0); - paste_tabular->plaintext(os, runparams, 0, true, '\t'); + paste_tabular->plaintext(os, runparams, 0, true, '\t', INT_MAX); // Needed for the "Edit->Paste recent" menu and the system clipboard. cap::copySelection(cur, os.str()); @@ -5781,7 +6137,8 @@ void InsetTabular::cutSelection(Cursor & cur) bool InsetTabular::isRightToLeft(Cursor & cur) const { - LASSERT(cur.depth() > 1, /**/); + // LASSERT: It might be better to abandon this Buffer. + LASSERT(cur.depth() > 1, return false); Paragraph const & parentpar = cur[cur.depth() - 2].paragraph(); pos_type const parentpos = cur[cur.depth() - 2].pos(); return parentpar.getFontSettings(buffer().params(),