X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetTabular.cpp;h=68fff9b51f816e16746a13ee3571a60674876434;hb=110f8f67ac1afe9892dad5566d1c697044427cf0;hp=dec2961dd16c37617a44150aa4872f377d43b981;hpb=58804aa399933a12a1c5ee6ad1aed344289d2dc3;p=lyx.git diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index dec2961dd1..68fff9b51f 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -451,6 +451,49 @@ bool getTokenValue(string const & str, char const * token, Length & len) } +bool getTokenValue(string const & str, char const * token, Change & change, BufferParams & bp) +{ + // set the change to be Change() as default as this it should be if not + // in the file format. + change = Change(); + string tmp; + if (getTokenValue(str, token, tmp)) { + vector const changedata = getVectorFromString(tmp, " "); + if (changedata.size() != 3) { + Alert::warning(_("Change tracking data incomplete"), + _("Change tracking information for tabular row/column " + "is incomplete. I will ignore this.")); + return false; + } + BufferParams::AuthorMap const & am = bp.author_map_; + int aid = convert(changedata[1]); + if (am.find(aid) == am.end()) { + // FIXME Use ErrorList + Alert::warning(_("Change tracking author index missing"), + bformat(_("A change tracking author information for index " + "%1$d is missing. This can happen after a wrong " + "merge by a version control system. In this case, " + "either fix the merge, or have this information " + "missing until the corresponding tracked changes " + "are merged or this user edits the file again.\n"), + aid)); + bp.addAuthor(Author(aid)); + } + istringstream is(changedata[2]); + time_t ct; + is >> ct; + if (changedata[0] == "inserted") { + change = Change(Change::INSERTED, am.find(aid)->second, ct); + return true; + } else if (changedata[0] == "deleted") { + change = Change(Change::DELETED, am.find(aid)->second, ct); + return true; + } + } + return false; +} + + bool getTokenValue(string const & str, char const * token, Length & len, bool & flag) { len = Length(); @@ -527,10 +570,25 @@ string const write_attribute(string const & name, Tabular::idx_type const & i) 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. + // we write only the value if we really have one same reason as above. return value.zero() ? string() : write_attribute(name, value.asString()); } +string const write_attribute(string const & name, Change const & change, BufferParams const & bp) +{ + odocstringstream ods; + if (change.inserted()) + ods << from_ascii("inserted"); + else if (change.deleted()) + ods << from_ascii("deleted"); + if (change.changed()) { + ods << " " << bp.authors().get(change.author).bufferId() + << " " << change.changetime; + return write_attribute(name, ods.str()); + } + return string(); +} + } // namespace @@ -562,7 +620,7 @@ InsetTableCell splitCell(InsetTableCell & head, docstring const & align_d, bool DocIterator const dit = separatorPos(&head, align_d); hassep = (bool)dit; if (hassep) { - pit_type const psize = head.paragraphs().front().size(); + pos_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); @@ -653,7 +711,7 @@ Tabular::CellData & Tabular::CellData::operator=(CellData const & cs) top_line_rtrimmed = cs.top_line_rtrimmed; top_line_ltrimmed = cs.top_line_ltrimmed; bottom_line_rtrimmed = cs.bottom_line_rtrimmed; - bottom_line_rtrimmed = cs.bottom_line_rtrimmed; + bottom_line_ltrimmed = cs.bottom_line_ltrimmed; usebox = cs.usebox; rotate = cs.rotate; align_special = cs.align_special; @@ -673,7 +731,8 @@ Tabular::RowData::RowData() endfoot(false), endlastfoot(false), newpage(false), - caption(false) + caption(false), + change(Change()) {} @@ -681,7 +740,8 @@ Tabular::ColumnData::ColumnData() : alignment(LYX_ALIGN_CENTER), valignment(LYX_VALIGN_TOP), width(0), - varwidth(false) + varwidth(false), + change(Change()) { } @@ -738,12 +798,14 @@ void Tabular::init(Buffer * buf, row_type rows_arg, } -void Tabular::deleteRow(row_type const row) +void Tabular::deleteRow(row_type const row, bool const force) { // Not allowed to delete last row if (nrows() == 1) return; + bool const ct = force ? false : buffer().params().track_changes; + for (col_type c = 0; c < ncols(); ++c) { // Care about multirow cells if (row + 1 < nrows() && @@ -752,8 +814,12 @@ void Tabular::deleteRow(row_type const row) cell_info[row + 1][c].multirow = CELL_BEGIN_OF_MULTIROW; } } - row_info.erase(row_info.begin() + row); - cell_info.erase(cell_info.begin() + row); + if (ct) + row_info[row].change.setDeleted(); + else { + row_info.erase(row_info.begin() + row); + cell_info.erase(cell_info.begin() + row); + } updateIndexes(); } @@ -779,8 +845,6 @@ void Tabular::insertRow(row_type const row, bool copy) 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().track_changes) - 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; } @@ -799,9 +863,10 @@ void Tabular::insertRow(row_type const row, bool copy) setBottomLine(i, true); setBottomLine(j, false); } - // mark track changes - if (buffer().params().track_changes) - cellInfo(i).inset->setChange(Change(Change::INSERTED)); + } + if (buffer().params().track_changes) { + row_info[row + 1].change.setInserted(); + updateIndexes(); } } @@ -818,7 +883,6 @@ void Tabular::moveColumn(col_type col, ColDirection direction) 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().track_changes) { @@ -842,7 +906,6 @@ void Tabular::moveRow(row_type row, RowDirection direction) 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().track_changes) { @@ -854,12 +917,14 @@ void Tabular::moveRow(row_type row, RowDirection direction) } -void Tabular::deleteColumn(col_type const col) +void Tabular::deleteColumn(col_type const col, bool const force) { // Not allowed to delete last column if (ncols() == 1) return; + bool const ct = force ? false : buffer().params().track_changes; + for (row_type r = 0; r < nrows(); ++r) { // Care about multicolumn cells if (col + 1 < ncols() && @@ -867,9 +932,13 @@ void Tabular::deleteColumn(col_type const col) cell_info[r][col + 1].multicolumn == CELL_PART_OF_MULTICOLUMN) { cell_info[r][col + 1].multicolumn = CELL_BEGIN_OF_MULTICOLUMN; } - cell_info[r].erase(cell_info[r].begin() + col); + if (!ct) + cell_info[r].erase(cell_info[r].begin() + col); } - column_info.erase(column_info.begin() + col); + if (ct) + column_info[col].change.setDeleted(); + else + column_info.erase(column_info.begin() + col); updateIndexes(); } @@ -888,14 +957,12 @@ void Tabular::appendColumn(col_type col) void Tabular::insertColumn(col_type const col, bool copy) { - BufferParams const & bp = buffer().params(); + bool const ct = buffer().params().track_changes; 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 + 1, copy ? CellData(cell_info[r][col]) : CellData(buffer_)); - if (bp.track_changes) - 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; } @@ -911,8 +978,10 @@ void Tabular::insertColumn(col_type const col, bool copy) if (rightLine(i) && rightLine(j)) { setRightLine(j, false); } - if (buffer().params().track_changes) - cellInfo(i).inset->setChange(Change(Change::INSERTED)); + } + if (ct) { + column_info[col + 1].change.setInserted(); + updateIndexes(); } } @@ -936,15 +1005,15 @@ void Tabular::updateIndexes() rowofcell.resize(numberofcells); columnofcell.resize(numberofcells); idx_type i = 0; - // reset column and row of cells and update their width and alignment - for (row_type row = 0; row < nrows(); ++row) + // reset column and row of cells and update their width, alignment and ct status + for (row_type row = 0; row < nrows(); ++row) { for (col_type column = 0; column < ncols(); ++column) { if (isPartOfMultiColumn(row, column)) { cell_info[row][column].inset->toggleMultiCol(true); continue; } cell_info[row][column].inset->toggleMultiCol(false); - // columnofcell needs to be called before setting width and aligment + // columnofcell needs to be called before setting width and alignment // multirow cells inherit the width from the column width if (!isPartOfMultiRow(row, column)) { columnofcell[i] = column; @@ -958,8 +1027,15 @@ void Tabular::updateIndexes() cell_info[row][column].inset->toggleMultiRow(false); cell_info[row][column].inset->setContentAlignment( getAlignment(cellIndex(row, column))); + if (buffer().params().track_changes) { + if (row_info[row].change.changed()) + cell_info[row][column].inset->setChange(row_info[row].change); + if (column_info[column].change.changed()) + cell_info[row][column].inset->setChange(column_info[column].change); + } ++i; } + } } @@ -1098,7 +1174,7 @@ bool Tabular::updateColumnWidths(MetricsInfo & mi) int restwidth = -1; if (!tab_width.zero()) { restwidth = mi.base.inPixels(tab_width); - // Substract the fixed widths from the table width + // Subtract the fixed widths from the table width for (auto const w : max_pwidth) restwidth -= w.second; } @@ -1210,8 +1286,10 @@ void Tabular::setAlignment(idx_type cell, LyXAlignment align, } column_info[col].alignment = align; docstring & dpoint = column_info[col].decimal_point; - if (align == LYX_ALIGN_DECIMAL && dpoint.empty()) - dpoint = from_utf8(lyxrc.default_decimal_point); + if (align == LYX_ALIGN_DECIMAL && dpoint.empty()) { + Language const * tlang = buffer().paragraphs().front().getParLanguage(buffer().params()); + dpoint = tlang->decimalSeparator(); + } } else { cellInfo(cell).alignment = align; cellInset(cell)->setContentAlignment(align); @@ -1569,7 +1647,7 @@ int Tabular::textVOffset(idx_type cell) const } -Tabular::idx_type Tabular::getFirstCellInRow(row_type row) const +Tabular::idx_type Tabular::getFirstCellInRow(row_type row, bool const ct) const { col_type c = 0; idx_type const numcells = numberOfCellsInRow(row); @@ -1578,26 +1656,52 @@ Tabular::idx_type Tabular::getFirstCellInRow(row_type row) const // 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) + && (cell_info[row][c].multirow == CELL_PART_OF_MULTIROW + || (ct && column_info[c].change.deleted()))) ++c; return cell_info[row][c].cellno; } -Tabular::idx_type Tabular::getLastCellInRow(row_type row) const +Tabular::idx_type Tabular::getLastCellInRow(row_type row, bool const ct) 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)) + && ((cell_info[row][c].multirow == CELL_PART_OF_MULTIROW + || cell_info[row][c].multicolumn == CELL_PART_OF_MULTICOLUMN) + || (ct && column_info[c].change.deleted()))) --c; return cell_info[row][c].cellno; } +Tabular::row_type Tabular::getFirstRow(bool const ct) const +{ + row_type r = 0; + if (!ct) + return r; + // exclude deleted rows if ct == true + while (r < nrows() && row_info[r].change.deleted()) + ++r; + return r; +} + + +Tabular::row_type Tabular::getLastRow(bool const ct) const +{ + row_type r = nrows() - 1; + if (!ct) + return r; + // exclude deleted rows if ct == true + while (r > 0 && row_info[r].change.deleted()) + --r; + return r; +} + + Tabular::row_type Tabular::cellRow(idx_type cell) const { if (cell >= numberofcells) @@ -1652,8 +1756,9 @@ void Tabular::write(ostream & os) const os << " columns) const +void Tabular::TeXTopHLine(otexstream & os, row_type row, list columns, + list logical_columns) const { // we only output complete row lines and the 1st row here, the rest // is done in Tabular::TeXBottomHLine(...) @@ -2416,15 +2524,16 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang, } // do nothing if empty first row, or incomplete row line after - if ((row == 0 && nset == 0) || (row > 0 && nset != ncols())) + row_type first = getFirstRow(!buffer().params().output_changes); + if ((row == first && nset == 0) || (row > first && nset != columns.size())) return; // Is this the actual first row (excluding longtable caption row)? - bool const realfirstrow = (row == 0 - || (is_long_tabular && row == 1 && ltCaption(0))); + bool const realfirstrow = (row == first + || (is_long_tabular && row == first + 1 && ltCaption(first))); // only output complete row lines and the 1st row's clines - if (nset == ncols() && !have_trims) { + if (nset == columns.size() && !have_trims) { if (use_booktabs) { os << (realfirstrow ? "\\toprule " : "\\midrule "); } else { @@ -2432,21 +2541,31 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang, } } else if (realfirstrow || have_trims) { string const cline = use_booktabs ? "\\cmidrule" : "\\cline"; - for (auto & c : columns) { + col_type c = 0; + std::list::const_iterator it1 = logical_columns.begin(); + std::list::const_iterator it2 = columns.begin(); + // We need to iterate over the logical columns here, but take care for + // bidi swapping + for (; it1 != logical_columns.end() && it2 != columns.end(); ++it1, ++it2) { + col_type cl = *it1; + if (cl < c) + continue; + c = cl; 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; + // If the two iterators differ, we are in bidi with swapped columns + col_type firstcol = (*it1 == *it2) ? c + 1 + offset : columns.size() - c + offset; while (isPartOfMultiColumn(row, c)) ++c; string trim; if (topltrims.find(c) != topltrims.end() && topltrims.find(c)->second) trim = "l"; - string const firstcol = convert(c + 1 + offset); col_type cstart = c; - for ( ; c < ncols() - 1 && topline.find(c)->second ; ++c) { + for ( ; c < ncols() - 1 && topline.find(c + 1)->second ; ++c) { if (isMultiColumn(cellIndex(row, c)) && c < ncols() - 1 && isPartOfMultiColumn(row, c + 1)) continue; @@ -2463,27 +2582,22 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang, for (col_type j = cstart ; j < c ; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) ++offset; - col_type const lastcol = c + 1 + offset; + col_type lastcol = (*it1 == *it2) ? c + 1 + offset : columns.size() - c + offset; if (toprtrims.find(c) != toprtrims.end() && toprtrims.find(c)->second) trim += "r"; - //babel makes the "-" character an active one, so we have to suppress this here - //see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289# - if (lang == "slovak" || lang == "czech") { - os << "\\expandafter" << cline; - if (!trim.empty()) - os << "(" << trim << ")"; - os << "\\expandafter{\\expandafter" << firstcol << "\\string-"; - } else { - os << cline; - if (!trim.empty()) - os << "(" << trim << ")"; - os << "{" << firstcol << '-'; - } - os << lastcol << "}"; - if (c == ncols() - 1) + os << cline; + if (!trim.empty()) + os << "(" << trim << ")"; + if (firstcol > lastcol) + // This can happen with bidi (swapped columns) + os << "{" << lastcol << '-' << firstcol << "}"; + else + os << "{" << firstcol << '-' << lastcol << "}"; + if (c == columns.size() - 1) break; + ++c; } } } @@ -2491,14 +2605,14 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang, } -void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang, - list columns) const +void Tabular::TeXBottomHLine(otexstream & os, row_type row, list columns, + list logical_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; + bool lastrow = row == getLastRow(!buffer().params().output_changes); map bottomline, topline, topltrims, toprtrims, bottomltrims, bottomrtrims; bool nextrowset = true; for (auto const & c : columns) { @@ -2541,7 +2655,7 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang, bottomline[c] = bottomline.find(c)->second || topline.find(c)->second; bottomltrims[c] = (bottomltrims.find(c) != bottomltrims.end() && bottomltrims.find(c)->second) || (topltrims.find(c) != topltrims.end() && topltrims.find(c)->second); - bottomrtrims[c] =(bottomrtrims.find(c) != bottomrtrims.end() && bottomrtrims.find(c)->second) + bottomrtrims[c] = (bottomrtrims.find(c) != bottomrtrims.end() && bottomrtrims.find(c)->second) || (toprtrims.find(c) != toprtrims.end() && toprtrims.find(c)->second); if (bottomline.find(c)->second) ++nset; @@ -2551,36 +2665,47 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang, } // do nothing if empty, OR incomplete row line with a topline in next row - if (nset == 0 || (nextrowset && nset != ncols())) + if (nset == 0 || (nextrowset && nset != columns.size())) return; - if (nset == ncols() && !have_trims) { + if (nset == columns.size() && !have_trims) { if (use_booktabs) os << (lastrow ? "\\bottomrule" : "\\midrule"); else os << "\\hline "; } else { string const cline = use_booktabs ? "\\cmidrule" : "\\cline"; - for (auto & c : columns) { + col_type c = 0; + std::list::const_iterator it1 = logical_columns.begin(); + std::list::const_iterator it2 = columns.begin(); + // We need to iterate over the logical columns here, but take care for + // bidi swapping + for (; it1 != logical_columns.end() && it2 != columns.end(); ++it1, ++it2) { + col_type cl = *it1; + if (cl < c) + continue; + c = cl; 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; + // If the two iterators differ, we are in bidi with swapped columns + col_type firstcol = (*it1 == *it2) ? c + 1 + offset : columns.size() - c + offset; while (isPartOfMultiColumn(row, c)) ++c; string trim; if (bottomltrims.find(c) != bottomltrims.end() && bottomltrims.find(c)->second) trim = "l"; - string const firstcol = convert(c + 1 + offset); col_type cstart = c; - for ( ; c < ncols() - 1 && bottomline.find(c)->second ; ++c) { + for ( ; c < ncols() - 1 && bottomline.find(c + 1)->second ; ++c) { if (isMultiColumn(cellIndex(row, c)) && c < ncols() - 1 && isPartOfMultiColumn(row, c + 1)) continue; - if (c > cstart && bottomltrims.find(c) != bottomltrims.end() + if (c > cstart + && bottomltrims.find(c) != bottomltrims.end() && bottomltrims.find(c)->second) { if (!isPartOfMultiColumn(row, c)) --c; @@ -2593,27 +2718,22 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang, for (col_type j = cstart ; j < c ; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) ++offset; - col_type const lastcol = c + 1 + offset; + col_type lastcol = (*it1 == *it2) ? c + 1 + offset : columns.size() - c + offset; if (bottomrtrims.find(c) != bottomrtrims.end() && bottomrtrims.find(c)->second) trim += "r"; - //babel makes the "-" character an active one, so we have to suppress this here - //see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289# - if (lang == "slovak" || lang == "czech") { - os << "\\expandafter" << cline; - if (!trim.empty()) - os << "(" << trim << ")"; - os << "\\expandafter{\\expandafter" << firstcol << "\\string-"; - } else { - os << cline; - if (!trim.empty()) - os << "(" << trim << ")"; - os << "{" << firstcol << '-'; - } - os << lastcol << "}"; - if (c == ncols() - 1) + os << cline; + if (!trim.empty()) + os << "(" << trim << ")"; + if (firstcol > lastcol) + // This can happen with bidi (swapped columns) + os << "{" << lastcol << '-' << firstcol << "}"; + else + os << "{" << firstcol << '-' << lastcol << "}"; + if (c == columns.size() - 1) break; + ++c; } } } @@ -2819,7 +2939,8 @@ void Tabular::TeXCellPostamble(otexstream & os, idx_type cell, void Tabular::TeXLongtableHeaderFooter(otexstream & os, OutputParams const & runparams, - list columns) const + list columns, + list logical_columns) const { if (!is_long_tabular) return; @@ -2831,7 +2952,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, columns); + TeXRow(os, r, runparams, columns, logical_columns); } } // output first header info @@ -2840,7 +2961,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, columns); + TeXRow(os, r, runparams, columns, logical_columns); } if (endfirsthead.bottomDL) os << "\\hline\n"; @@ -2854,7 +2975,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, columns); + TeXRow(os, r, runparams, columns, logical_columns); } if (endhead.bottomDL) os << "\\hline\n"; @@ -2866,7 +2987,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, columns); + TeXRow(os, r, runparams, columns, logical_columns); } if (endfoot.bottomDL) os << "\\hline\n"; @@ -2880,7 +3001,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, columns); + TeXRow(os, r, runparams, columns, logical_columns); } if (endlastfoot.bottomDL) os << "\\hline\n"; @@ -2901,15 +3022,10 @@ bool Tabular::isValidRow(row_type row) const void Tabular::TeXRow(otexstream & os, row_type row, OutputParams const & runparams, - list columns) const + list columns, list logical_columns) const { - idx_type cell = cellIndex(row, 0); - InsetTableCell const * cinset = cellInset(cell); - Paragraph const & cpar = cinset->paragraphs().front(); - string const clang = cpar.getParLanguage(buffer().params())->lang(); - //output the top line - TeXTopHLine(os, row, clang, columns); + TeXTopHLine(os, row, columns, logical_columns); if (row_info[row].top_space_default) { if (use_booktabs) @@ -2930,18 +3046,20 @@ void Tabular::TeXRow(otexstream & os, row_type row, bool ismulticol = false; bool ismultirow = false; - // The bidi package (loaded by polyglossia) reverses RTL table columns + // The bidi package (loaded by polyglossia with XeTeX) reverses RTL table columns + // Luabibdi (used by LuaTeX) behaves like classic bool const bidi_rtl = runparams.local_font->isRightToLeft() - && runparams.use_polyglossia; + && runparams.useBidiPackage(); + bool const ct = !buffer().params().output_changes; idx_type lastcell = - bidi_rtl ? getFirstCellInRow(row) : getLastCellInRow(row); + bidi_rtl ? getFirstCellInRow(row, ct) : getLastCellInRow(row, ct); for (auto const & c : columns) { if (isPartOfMultiColumn(row, c)) continue; - cell = cellIndex(row, c); + idx_type cell = cellIndex(row, c); if (isPartOfMultiRow(row, c) && column_info[c].alignment != LYX_ALIGN_DECIMAL) { @@ -3056,7 +3174,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, os << '\n'; //output the bottom line - TeXBottomHLine(os, row, clang, columns); + TeXBottomHLine(os, row, columns, logical_columns); if (row_info[row].interline_space_default) { if (use_booktabs) @@ -3099,6 +3217,58 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const os << "\\begin{turn}{" << convert(rotate) << "}\n"; } + // The bidi package (loaded by polyglossia with XeTeX) swaps the column + // order for RTL (#9686). Thus we use this list. + bool const bidi_rtl = + runparams.local_font->isRightToLeft() + && runparams.useBidiPackage(); + list columns; + list logical_columns; + for (col_type cl = 0; cl < ncols(); ++cl) { + if (!buffer().params().output_changes && column_info[cl].change.deleted()) + continue; + if (bidi_rtl) + columns.push_front(cl); + else + columns.push_back(cl); + // for some calculations, we need the logical (non-swapped) + // columns also in bidi. + logical_columns.push_back(cl); + } + + // If we use \cline or \cmidrule, we need to locally de-activate + // the - character when using languages that activate it (e.g., Czech, Slovak). + bool deactivate_chars = false; + if ((runparams.use_babel || runparams.use_polyglossia) + && contains(runparams.active_chars, '-')) { + bool have_clines = false; + // Check if we use \cline or \cmidrule + for (row_type row = 0; row < nrows(); ++row) { + col_type bset = 0, tset = 0; + for (auto const & c : columns) { + idx_type const idx = cellIndex(row, c); + if (bottomLineTrim(idx).first || bottomLineTrim(idx).second + || topLineTrim(idx).first || topLineTrim(idx).second) { + have_clines = true; + break; + } + if (bottomLine(cellIndex(row, c))) + ++bset; + if (topLine(cellIndex(row, c))) + ++tset; + } + if ((bset > 0 && bset < ncols()) || (tset > 0 && tset < ncols())) { + have_clines = true; + break; + } + } + if (have_clines) { + deactivate_chars = true; + os << "\\begingroup\n" + << "\\catcode`\\-=12\n"; + } + } + if (is_long_tabular) { if (is_xltabular) os << "\\begin{xltabular}"; @@ -3149,19 +3319,6 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const if (is_tabular_star) os << "@{\\extracolsep{\\fill}}"; - // 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 << '|'; @@ -3291,15 +3448,17 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const } os << "}\n"; - TeXLongtableHeaderFooter(os, runparams, columns); + TeXLongtableHeaderFooter(os, runparams, columns, logical_columns); //+--------------------------------------------------------------------- //+ the single row and columns (cells) + //+--------------------------------------------------------------------- for (row_type r = 0; r < nrows(); ++r) { + if (!buffer().params().output_changes && row_info[r].change.deleted()) + continue; if (isValidRow(r)) { - TeXRow(os, r, runparams, columns); + TeXRow(os, r, runparams, columns, logical_columns); if (is_long_tabular && row_info[r].newpage) os << "\\newpage\n"; } @@ -3323,6 +3482,10 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const os << "\\end{tabular}"; } + if (deactivate_chars) + // close the group + os << "\n\\endgroup\n"; + if (rotate != 0) { if (is_long_tabular) os << breakln << "\\end{landscape}"; @@ -3486,14 +3649,14 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const } -docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row, +docstring Tabular::xhtmlRow(XMLStream & xs, row_type row, OutputParams const & runparams, bool header) const { docstring ret; string const celltag = header ? "th" : "td"; idx_type cell = getFirstCellInRow(row); - xs << html::StartTag("tr"); + xs << xml::StartTag("tr"); for (col_type c = 0; c < ncols(); ++c) { if (isPartOfMultiColumn(row, c) || isPartOfMultiRow(row, c)) continue; @@ -3537,17 +3700,17 @@ docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row, else if (isMultiRow(cell)) attr << " rowspan='" << rowSpan(cell) << "'"; - xs << html::StartTag(celltag, attr.str(), true) << html::CR(); + xs << xml::StartTag(celltag, attr.str(), true) << xml::CR(); ret += cellInset(cell)->xhtml(xs, runparams); - xs << html::EndTag(celltag) << html::CR(); + xs << xml::EndTag(celltag) << xml::CR(); ++cell; } - xs << html::EndTag("tr"); + xs << xml::EndTag("tr"); return ret; } -docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const +docstring Tabular::xhtml(XMLStream & xs, OutputParams const & runparams) const { docstring ret; @@ -3565,20 +3728,20 @@ docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const align = "right"; break; } - xs << html::StartTag("div", "class='longtable' style='text-align: " + align + ";'") - << html::CR(); + xs << xml::StartTag("div", "class='longtable' style='text-align: " + align + ";'") + << xml::CR(); // The caption flag wins over head/foot if (haveLTCaption()) { - xs << html::StartTag("div", "class='longtable-caption' style='text-align: " + align + ";'") - << html::CR(); + xs << xml::StartTag("div", "class='longtable-caption' style='text-align: " + align + ";'") + << xml::CR(); for (row_type r = 0; r < nrows(); ++r) if (row_info[r].caption) ret += xhtmlRow(xs, r, runparams); - xs << html::EndTag("div") << html::CR(); + xs << xml::EndTag("div") << xml::CR(); } } - xs << html::StartTag("table") << html::CR(); + xs << xml::StartTag("table") << xml::CR(); // output header info bool const havefirsthead = haveLTFirstHead(false); @@ -3587,7 +3750,7 @@ docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const // in XHTML. this test accomplishes that. bool const havehead = !havefirsthead && haveLTHead(false); if (havehead || havefirsthead) { - xs << html::StartTag("thead") << html::CR(); + xs << xml::StartTag("thead") << xml::CR(); for (row_type r = 0; r < nrows(); ++r) { if (((havefirsthead && row_info[r].endfirsthead) || (havehead && row_info[r].endhead)) && @@ -3595,14 +3758,14 @@ docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const ret += xhtmlRow(xs, r, runparams, true); } } - xs << html::EndTag("thead") << html::CR(); + xs << xml::EndTag("thead") << xml::CR(); } // output footer info bool const havelastfoot = haveLTLastFoot(false); // as before. bool const havefoot = !havelastfoot && haveLTFoot(false); if (havefoot || havelastfoot) { - xs << html::StartTag("tfoot") << html::CR(); + xs << xml::StartTag("tfoot") << xml::CR(); for (row_type r = 0; r < nrows(); ++r) { if (((havelastfoot && row_info[r].endlastfoot) || (havefoot && row_info[r].endfoot)) && @@ -3610,21 +3773,21 @@ docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const ret += xhtmlRow(xs, r, runparams); } } - xs << html::EndTag("tfoot") << html::CR(); + xs << xml::EndTag("tfoot") << xml::CR(); } - xs << html::StartTag("tbody") << html::CR(); + xs << xml::StartTag("tbody") << xml::CR(); for (row_type r = 0; r < nrows(); ++r) { if (isValidRow(r)) { ret += xhtmlRow(xs, r, runparams); } } - xs << html::EndTag("tbody") - << html::CR() - << html::EndTag("table") - << html::CR(); + xs << xml::EndTag("tbody") + << xml::CR() + << xml::EndTag("table") + << xml::CR(); if (is_long_tabular) - xs << html::EndTag("div") << html::CR(); + xs << xml::EndTag("div") << xml::CR(); return ret; } @@ -3954,7 +4117,7 @@ bool InsetTableCell::allowParagraphCustomization(idx_type) const bool InsetTableCell::forceLocalFontSwitch() const { - return isFixedWidth; + return true; } @@ -3963,6 +4126,9 @@ bool InsetTableCell::getStatus(Cursor & cur, FuncRequest const & cmd, { bool enabled = true; switch (cmd.action()) { + case LFUN_INSET_DISSOLVE: + enabled = false; + break; case LFUN_MATH_DISPLAY: if (!hasFixedWidth()) { enabled = false; @@ -4001,7 +4167,7 @@ void InsetTableCell::addToToc(DocIterator const & di, bool output_active, } -docstring InsetTableCell::xhtml(XHTMLStream & xs, OutputParams const & rp) const +docstring InsetTableCell::xhtml(XMLStream & xs, OutputParams const & rp) const { if (!isFixedWidth) return InsetText::insetAsXHTML(xs, rp, InsetText::JustText); @@ -4012,10 +4178,11 @@ docstring InsetTableCell::xhtml(XHTMLStream & xs, OutputParams const & rp) const void InsetTableCell::metrics(MetricsInfo & mi, Dimension & dim) const { TextMetrics & tm = mi.base.bv->textMetrics(&text()); + int const horiz_offset = leftOffset(mi.base.bv) + rightOffset(mi.base.bv); // Hand font through to contained lyxtext: tm.font_.fontInfo() = mi.base.font; - mi.base.textwidth -= 2 * TEXT_TO_INSET_OFFSET; + mi.base.textwidth -= horiz_offset; // This can happen when a layout has a left and right margin, // and the view is made very narrow. We can't do better than @@ -4029,14 +4196,13 @@ void InsetTableCell::metrics(MetricsInfo & mi, Dimension & dim) const tm.metrics(mi, dim, mi.base.textwidth, false); else tm.metrics(mi, dim, 0, false); - mi.base.textwidth += 2 * TEXT_TO_INSET_OFFSET; - dim.asc += TEXT_TO_INSET_OFFSET; - dim.des += TEXT_TO_INSET_OFFSET; - dim.wid += 2 * TEXT_TO_INSET_OFFSET; + mi.base.textwidth += horiz_offset; + dim.asc += topOffset(mi.base.bv); + dim.des += bottomOffset(mi.base.bv); + dim.wid += horiz_offset; } - ///////////////////////////////////////////////////////////////////// // // InsetTabular @@ -4210,7 +4376,7 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const docstring const align_d = tabular.column_info[c].decimal_point; dit = separatorPos(&tail, align_d); - pit_type const psize = tail.paragraphs().front().size(); + pos_type const psize = tail.paragraphs().front().size(); if (dit) { tail.paragraphs().front().eraseChars(0, dit.pos() < psize ? dit.pos() + 1 : psize, false); @@ -4223,9 +4389,9 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const tabular.cell_info[r][c].decimal_width = decimal_width; // with LYX_VALIGN_BOTTOM the descent is relative to the last par - // = descent of text in last par + TEXT_TO_INSET_OFFSET: + // = descent of text in last par + bottomOffset: int const lastpardes = tm.last().second->descent() - + TEXT_TO_INSET_OFFSET; + + bottomOffset(mi.base.bv); int offset = 0; switch (tabular.getVAlignment(cell)) { case Tabular::LYX_VALIGN_TOP: @@ -4305,6 +4471,9 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const bool const original_selection_state = pi.selected; idx_type idx = 0; + + // Save tabular change status + Change tab_change = pi.change; int yy = y + tabular.offsetVAlignment(); for (row_type r = 0; r < tabular.nrows(); ++r) { @@ -4321,6 +4490,15 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const } pi.selected |= isCellSelected(cur, r, c); + + // Mark deleted rows/columns + if (tabular.column_info[c].change.changed()) + pi.change = tabular.column_info[c].change; + else if (tabular.row_info[r].change.changed()) + pi.change = tabular.row_info[r].change; + else + pi.change = tab_change; + int const cx = nx + tabular.textHOffset(idx); int const cy = yy + tabular.textVOffset(idx); // Cache the Inset position. @@ -4402,9 +4580,9 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const namespace { void tabline(PainterInfo const & pi, int x1, int y1, int x2, int y2, int lt, int rt, - bool drawline, bool heavy = false) + Color const incol, bool drawline, bool heavy = false) { - ColorCode const col = drawline ? Color_tabularline : Color_tabularonoffline; + Color const col = drawline ? incol : Color_tabularonoffline; if (drawline && lt > 0) pi.pain.line(x1, y1, x1 + lt, y2, pi.textColor(Color_tabularonoffline), Painter::line_onoffdash, @@ -4432,6 +4610,12 @@ void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y, col_type const col = tabular.cellColumn(cell); + // Colour the frame if rows/columns are added or deleted + Color colour = Color_tabularline; + if (tabular.column_info[col].change.changed() + || tabular.row_info[row].change.changed()) + colour = InsetTableCell(*tabular.cellInset(cell)).paragraphs().front().lookupChange(0).color(); + // Top bool drawline = tabular.topLine(cell) || (row > 0 && tabular.bottomLine(tabular.cellAbove(cell))); @@ -4444,7 +4628,7 @@ void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y, if (tabular.topLineTrim(cell).second || (row > 0 && tabular.bottomLineTrim(tabular.cellIndex(row - 1, col)).second)) rt = 10; - tabline(pi, x, y, x + w, y, lt, rt, drawline, heavy); + tabline(pi, x, y, x + w, y, lt, rt, colour, drawline, heavy); // Bottom lt = rt = 0; @@ -4462,12 +4646,12 @@ void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y, lt = 10; if (tabular.bottomLineTrim(cell).second) rt = 10; - tabline(pi, x, y + h, x + w, y + h, lt, rt, drawline, heavy); + tabline(pi, x, y + h, x + w, y + h, lt, rt, colour, drawline, heavy); // Left drawline = tabular.leftLine(cell) || (col > 0 && tabular.rightLine(tabular.cellIndex(row, col - 1))); - tabline(pi, x, y, x, y + h, 0, 0, drawline); + tabline(pi, x, y, x, y + h, 0, 0, colour, drawline); // Right x -= tabular.interColumnSpace(cell); @@ -4478,7 +4662,7 @@ void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y, drawline = tabular.rightLine(cell) || (next_cell_col < tabular.ncols() && tabular.leftLine(tabular.cellIndex(row, next_cell_col))); - tabline(pi, x + w, y, x + w, y + h, 0, 0, drawline); + tabline(pi, x + w, y, x + w, y + h, 0, 0, colour, drawline); } @@ -4508,7 +4692,7 @@ void InsetTabular::edit(Cursor & cur, bool front, EntryDirection) } -void InsetTabular::updateBuffer(ParIterator const & it, UpdateType utype) +void InsetTabular::updateBuffer(ParIterator const & it, UpdateType utype, bool const /*deleted*/) { // In a longtable, tell captions what the current float is Counters & cnts = buffer().masterBuffer()->params().documentClass().counters(); @@ -5010,6 +5194,8 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) } break; + case LFUN_CHANGE_ACCEPT: + case LFUN_CHANGE_REJECT: case LFUN_FONT_EMPH: case LFUN_FONT_BOLD: case LFUN_FONT_BOLDSYMBOL: @@ -5033,14 +5219,55 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_WORD_CAPITALIZE: case LFUN_WORD_UPCASE: case LFUN_WORD_LOWCASE: - case LFUN_CHARS_TRANSPOSE: + case LFUN_CHARS_TRANSPOSE: { + bool const ct = (act == LFUN_CHANGE_ACCEPT || act == LFUN_CHANGE_REJECT); if (cur.selIsMultiCell()) { row_type rs, re; col_type cs, ce; getSelection(cur, rs, re, cs, ce); Cursor tmpcur = cur; for (row_type r = rs; r <= re; ++r) { + if (ct && cs == 0 && ce == tabular.ncols() - 1) { + // whole row selected + if (act == LFUN_CHANGE_ACCEPT) { + if (tabular.row_info[r].change.inserted()) + tabular.row_info[r].change.setUnchanged(); + else if (tabular.row_info[r].change.deleted()) { + tabular.deleteRow(r, true); + --re; + continue; + } + } else { + if (tabular.row_info[r].change.deleted()) + tabular.row_info[r].change.setUnchanged(); + else if (tabular.row_info[r].change.inserted()) { + tabular.deleteRow(r, true); + --re; + continue; + } + } + } for (col_type c = cs; c <= ce; ++c) { + if (ct && rs == 0 && re == tabular.nrows() - 1) { + // whole col selected + if (act == LFUN_CHANGE_ACCEPT) { + if (tabular.column_info[c].change.inserted()) + tabular.column_info[c].change.setUnchanged(); + else if (tabular.column_info[c].change.deleted()) { + tabular.deleteColumn(c, true); + --ce; + continue; + } + } else { + if (tabular.column_info[c].change.deleted()) + tabular.column_info[c].change.setUnchanged(); + else if (tabular.column_info[c].change.inserted()) { + tabular.deleteColumn(c, true); + --ce; + continue; + } + } + } // cursor follows cell: tmpcur.idx() = tabular.cellIndex(r, c); // select this cell only: @@ -5054,11 +5281,53 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cell(tmpcur.idx())->dispatch(tmpcur, cmd); } } + if (ct) { + tabular.updateIndexes(); + // cursor might be invalid + cur.fixIfBroken(); + // change bar might need to be redrawn + cur.screenUpdateFlags(Update::Force); + cur.forceBufferUpdate(); + } break; } else { cell(cur.idx())->dispatch(cur, cmd); break; } + } + + case LFUN_CHANGE_NEXT: + case LFUN_CHANGE_PREVIOUS: { + // BufferView::dispatch has already moved the cursor, we just + // need to select here if we have a changed row or column + if (tabular.row_info[tabular.cellRow(cur.idx())].change.changed()) { + // select row + cur.idx() = tabular.getFirstCellInRow(tabular.cellRow(cur.idx())); + cur.pit() = 0; + cur.pos() = 0; + cur.resetAnchor(); + cur.idx() = tabular.getLastCellInRow(tabular.cellRow(cur.idx())); + cur.pit() = cur.lastpit(); + cur.pos() = cur.lastpos(); + cur.selection(true); + bvcur = cur; + rowselect_ = true; + } + else if (tabular.column_info[tabular.cellColumn(cur.idx())].change.changed()) { + // select column + cur.idx() = tabular.cellIndex(0, tabular.cellColumn(cur.idx())); + cur.pit() = 0; + cur.pos() = 0; + cur.resetAnchor(); + cur.idx() = tabular.cellIndex(tabular.nrows() - 1, tabular.cellColumn(cur.idx())); + cur.pit() = cur.lastpit(); + cur.pos() = cur.lastpos(); + cur.selection(true); + bvcur = cur; + colselect_ = true; + } + break; + } case LFUN_INSET_SETTINGS: // relay this lfun to Inset, not to the cell. @@ -5615,6 +5884,37 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, return cell(cur.idx())->getStatus(cur, cmd, status); } + case LFUN_CHANGE_ACCEPT: + case LFUN_CHANGE_REJECT: { + if (cur.selIsMultiCell()) { + row_type rs, re; + col_type cs, ce; + getSelection(cur, rs, re, cs, ce); + for (row_type r = rs; r <= re; ++r) { + if (tabular.row_info[r].change.changed()) { + status.setEnabled(true); + return true; + } + for (col_type c = cs; c <= ce; ++c) { + if (tabular.column_info[c].change.changed()) { + status.setEnabled(true); + return true; + } + } + } + } else { + if (tabular.row_info[tabular.cellRow(cur.idx())].change.changed()) { + status.setEnabled(true); + return true; + } + else if (tabular.column_info[tabular.cellColumn(cur.idx())].change.changed()) { + status.setEnabled(true); + return true; + } + } + return cell(cur.idx())->getStatus(cur, cmd, status); + } + // disable in non-fixed-width cells case LFUN_PARAGRAPH_BREAK: // multirow does not allow paragraph breaks @@ -5666,18 +5966,18 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, } -Inset::DisplayType InsetTabular::display() const +Inset::RowFlags InsetTabular::rowFlags() const { if (tabular.is_long_tabular) { switch (tabular.longtabular_alignment) { case Tabular::LYX_LONGTABULAR_ALIGN_LEFT: - return AlignLeft; + return Display | AlignLeft; case Tabular::LYX_LONGTABULAR_ALIGN_CENTER: - return AlignCenter; + return Display; case Tabular::LYX_LONGTABULAR_ALIGN_RIGHT: - return AlignRight; + return Display | AlignRight; default: - return AlignCenter; + return Display; } } else return Inline; @@ -5727,7 +6027,7 @@ int InsetTabular::docbook(odocstream & os, OutputParams const & runparams) const } -docstring InsetTabular::xhtml(XHTMLStream & xs, OutputParams const & rp) const +docstring InsetTabular::xhtml(XMLStream & xs, OutputParams const & rp) const { return tabular.xhtml(xs, rp); } @@ -6763,18 +7063,18 @@ bool InsetTabular::copySelection(Cursor & cur) paste_tabular.reset(new Tabular(tabular)); for (row_type r = 0; r < rs; ++r) - paste_tabular->deleteRow(0); + paste_tabular->deleteRow(0, true); row_type const rows = re - rs + 1; while (paste_tabular->nrows() > rows) - paste_tabular->deleteRow(rows); + paste_tabular->deleteRow(rows, true); for (col_type c = 0; c < cs; ++c) - paste_tabular->deleteColumn(0); + paste_tabular->deleteColumn(0, true); col_type const columns = ce - cs + 1; while (paste_tabular->ncols() > columns) - paste_tabular->deleteColumn(columns); + paste_tabular->deleteColumn(columns, true); paste_tabular->setBuffer(tabular.buffer()); @@ -6830,9 +7130,12 @@ bool InsetTabular::pasteClipboard(Cursor & cur) // FIXME?: why do we need to do this explicitly? (EL) tabular.cellInset(r2, c2)->setBuffer(tabular.buffer()); - // FIXME: change tracking (MG) - inset->setChange(Change(buffer().params().track_changes ? + if (!lyxrc.ct_markup_copied) { + // do not paste deleted text + inset->acceptChanges(); + inset->setChange(Change(buffer().params().track_changes ? Change::INSERTED : Change::UNCHANGED)); + } cur.pos() = 0; cur.pit() = 0; } @@ -6926,6 +7229,20 @@ Text * InsetTabular::getText(int idx) const } +bool InsetTabular::isChanged() const +{ + for (idx_type idx = 0; idx < nargs(); ++idx) { + if (cell(idx)->isChanged()) + return true; + if (tabular.row_info[tabular.cellRow(idx)].change.changed()) + return true; + if (tabular.column_info[tabular.cellColumn(idx)].change.changed()) + return true; + } + return false; +} + + void InsetTabular::setChange(Change const & change) { for (idx_type idx = 0; idx < nargs(); ++idx) @@ -6937,6 +7254,19 @@ void InsetTabular::acceptChanges() { for (idx_type idx = 0; idx < nargs(); ++idx) cell(idx)->acceptChanges(); + for (row_type row = 0; row < tabular.nrows(); ++row) { + if (tabular.row_info[row].change.inserted()) + tabular.row_info[row].change.setUnchanged(); + else if (tabular.row_info[row].change.deleted()) + tabular.deleteRow(row, true); + } + for (col_type col = 0; col < tabular.ncols(); ++col) { + if (tabular.column_info[col].change.inserted()) + tabular.column_info[col].change.setUnchanged(); + else if (tabular.column_info[col].change.deleted()) + tabular.deleteColumn(col, true); + } + tabular.updateIndexes(); } @@ -6944,6 +7274,19 @@ void InsetTabular::rejectChanges() { for (idx_type idx = 0; idx < nargs(); ++idx) cell(idx)->rejectChanges(); + for (row_type row = 0; row < tabular.nrows(); ++row) { + if (tabular.row_info[row].change.deleted()) + tabular.row_info[row].change.setUnchanged(); + else if (tabular.row_info[row].change.inserted()) + tabular.deleteRow(row, true); + } + for (col_type col = 0; col < tabular.ncols(); ++col) { + if (tabular.column_info[col].change.deleted()) + tabular.column_info[col].change.setUnchanged(); + else if (tabular.column_info[col].change.inserted()) + tabular.deleteColumn(col, true); + } + tabular.updateIndexes(); }