X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetTabular.cpp;h=68fff9b51f816e16746a13ee3571a60674876434;hb=110f8f67ac1afe9892dad5566d1c697044427cf0;hp=1bd757b024a14e76f5c942587152ec47e4289842;hpb=bbc6ea4a5fb42516f91108d18a40520a2aba232a;p=lyx.git diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index 1bd757b024..68fff9b51f 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -451,18 +451,42 @@ bool getTokenValue(string const & str, char const * token, Length & len) } -bool getTokenValue(string const & str, char const * token, Change::Type & change) +bool getTokenValue(string const & str, char const * token, Change & change, BufferParams & bp) { - // set the length to be zero() as default as this it should be if not + // set the change to be Change() as default as this it should be if not // in the file format. - change = Change::UNCHANGED; + change = Change(); string tmp; if (getTokenValue(str, token, tmp)) { - if (tmp == "inserted") { - change = Change::INSERTED; + 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 (tmp == "deleted") { - change = Change::DELETED; + } else if (changedata[0] == "deleted") { + change = Change(Change::DELETED, am.find(aid)->second, ct); return true; } } @@ -546,17 +570,22 @@ 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()); } -template <> -string const write_attribute(string const & name, Change::Type const & type) +string const write_attribute(string const & name, Change const & change, BufferParams const & bp) { - if (type == Change::INSERTED) - return write_attribute(name, from_ascii("inserted")); - else if (type == Change::DELETED) - return write_attribute(name, from_ascii("deleted")); + 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(); } @@ -591,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); @@ -703,7 +732,7 @@ Tabular::RowData::RowData() endlastfoot(false), newpage(false), caption(false), - change(Change::UNCHANGED) + change(Change()) {} @@ -712,7 +741,7 @@ Tabular::ColumnData::ColumnData() valignment(LYX_VALIGN_TOP), width(0), varwidth(false), - change(Change::UNCHANGED) + change(Change()) { } @@ -778,9 +807,6 @@ void Tabular::deleteRow(row_type const row, bool const force) bool const ct = force ? false : buffer().params().track_changes; for (col_type c = 0; c < ncols(); ++c) { - // mark track changes - if (ct) - cell_info[row][c].inset->setChange(Change(Change::DELETED)); // Care about multirow cells if (row + 1 < nrows() && cell_info[row][c].multirow == CELL_BEGIN_OF_MULTIROW && @@ -789,7 +815,7 @@ void Tabular::deleteRow(row_type const row, bool const force) } } if (ct) - row_info[row].change = Change::DELETED; + row_info[row].change.setDeleted(); else { row_info.erase(row_info.begin() + row); cell_info.erase(cell_info.begin() + row); @@ -819,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; } @@ -839,12 +863,11 @@ 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 = Change::INSERTED; + if (buffer().params().track_changes) { + row_info[row + 1].change.setInserted(); + updateIndexes(); + } } @@ -903,9 +926,6 @@ void Tabular::deleteColumn(col_type const col, bool const force) bool const ct = force ? false : buffer().params().track_changes; for (row_type r = 0; r < nrows(); ++r) { - // mark track changes - if (ct) - cell_info[r][col].inset->setChange(Change(Change::DELETED)); // Care about multicolumn cells if (col + 1 < ncols() && cell_info[r][col].multicolumn == CELL_BEGIN_OF_MULTICOLUMN && @@ -916,7 +936,7 @@ void Tabular::deleteColumn(col_type const col, bool const force) cell_info[r].erase(cell_info[r].begin() + col); } if (ct) - column_info[col].change = Change::DELETED; + column_info[col].change.setDeleted(); else column_info.erase(column_info.begin() + col); updateIndexes(); @@ -937,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; } @@ -960,11 +978,11 @@ 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 (buffer().params().track_changes) - column_info[col + 1].change = Change::INSERTED; + if (ct) { + column_info[col + 1].change.setInserted(); + updateIndexes(); + } } @@ -987,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; @@ -1009,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; } + } } @@ -1149,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; } @@ -1622,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); @@ -1631,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) @@ -1706,7 +1757,7 @@ void Tabular::write(ostream & os) const << write_attribute("alignment", column_info[c].alignment); if (column_info[c].alignment == LYX_ALIGN_DECIMAL) os << write_attribute("decimal_point", column_info[c].decimal_point); - os << write_attribute("change", column_info[c].change) + os << write_attribute("change", column_info[c].change, buffer().params()) << write_attribute("valignment", column_info[c].valignment) << write_attribute("width", column_info[c].p_width.asString()) << write_attribute("varwidth", column_info[c].varwidth) @@ -1728,7 +1779,7 @@ void Tabular::write(ostream & os) const os << write_attribute("interlinespace", def); else os << write_attribute("interlinespace", row_info[r].interline_space); - os << write_attribute("change", row_info[r].change) + os << write_attribute("change", row_info[r].change, buffer().params()) << write_attribute("endhead", row_info[r].endhead) << write_attribute("endfirsthead", row_info[r].endfirsthead) << write_attribute("endfoot", row_info[r].endfoot) @@ -1828,7 +1879,7 @@ void Tabular::read(Lexer & lex) getTokenValue(line, "width", column_info[c].p_width); getTokenValue(line, "special", column_info[c].align_special); getTokenValue(line, "varwidth", column_info[c].varwidth); - getTokenValue(line, "change", column_info[c].change); + getTokenValue(line, "change", column_info[c].change, buffer().params()); } for (row_type i = 0; i < nrows(); ++i) { @@ -1850,7 +1901,7 @@ void Tabular::read(Lexer & lex) getTokenValue(line, "endlastfoot", row_info[i].endlastfoot); getTokenValue(line, "newpage", row_info[i].newpage); getTokenValue(line, "caption", row_info[i].caption); - getTokenValue(line, "change", row_info[i].change); + getTokenValue(line, "change", row_info[i].change, buffer().params()); for (col_type j = 0; j < ncols(); ++j) { l_getline(is, line); if (!prefixIs(line, " 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(...) @@ -2472,15 +2524,16 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, list columns) } // 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 { @@ -2489,7 +2542,12 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, list columns) } else if (realfirstrow || have_trims) { string const cline = use_booktabs ? "\\cmidrule" : "\\cline"; col_type c = 0; - for (auto & cl : columns) { + 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; @@ -2498,7 +2556,8 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, list columns) for (col_type j = 0 ; j < c; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) ++offset; - string const firstcol = convert(c + 1 + 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; @@ -2523,7 +2582,7 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, list columns) 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"; @@ -2531,8 +2590,12 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, list columns) os << cline; if (!trim.empty()) os << "(" << trim << ")"; - os << "{" << firstcol << '-' << lastcol << "}"; - if (c == ncols() - 1) + if (firstcol > lastcol) + // This can happen with bidi (swapped columns) + os << "{" << lastcol << '-' << firstcol << "}"; + else + os << "{" << firstcol << '-' << lastcol << "}"; + if (c == columns.size() - 1) break; ++c; } @@ -2542,13 +2605,14 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, list columns) } -void Tabular::TeXBottomHLine(otexstream & os, row_type row, 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) { @@ -2591,7 +2655,7 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, list colum 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; @@ -2601,10 +2665,10 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, list colum } // 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 @@ -2612,7 +2676,12 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, list colum } else { string const cline = use_booktabs ? "\\cmidrule" : "\\cline"; col_type c = 0; - for (auto & cl : columns) { + 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; @@ -2621,7 +2690,8 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, list colum for (col_type j = 0 ; j < c; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) ++offset; - string const firstcol = convert(c + 1 + 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; @@ -2648,7 +2718,7 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, list colum 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"; @@ -2656,8 +2726,12 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, list colum os << cline; if (!trim.empty()) os << "(" << trim << ")"; - os << "{" << firstcol << '-' << lastcol << "}"; - if (c == ncols() - 1) + if (firstcol > lastcol) + // This can happen with bidi (swapped columns) + os << "{" << lastcol << '-' << firstcol << "}"; + else + os << "{" << firstcol << '-' << lastcol << "}"; + if (c == columns.size() - 1) break; ++c; } @@ -2865,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; @@ -2877,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 @@ -2886,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"; @@ -2900,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"; @@ -2912,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"; @@ -2926,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"; @@ -2947,12 +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); - //output the top line - TeXTopHLine(os, row, columns); + TeXTopHLine(os, row, columns, logical_columns); if (row_info[row].top_space_default) { if (use_booktabs) @@ -2978,14 +3051,15 @@ void Tabular::TeXRow(otexstream & os, row_type row, bool const bidi_rtl = runparams.local_font->isRightToLeft() && 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) { @@ -3100,7 +3174,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, os << '\n'; //output the bottom line - TeXBottomHLine(os, row, columns); + TeXBottomHLine(os, row, columns, logical_columns); if (row_info[row].interline_space_default) { if (use_booktabs) @@ -3149,11 +3223,17 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const 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 @@ -3368,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"; } @@ -3567,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; @@ -3618,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; @@ -3646,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); @@ -3668,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)) && @@ -3676,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)) && @@ -3691,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; } @@ -4085,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); @@ -4096,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 @@ -4113,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 @@ -4294,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); @@ -4307,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: @@ -4389,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) { @@ -4405,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. @@ -4486,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, @@ -4516,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))); @@ -4528,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; @@ -4546,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); @@ -4562,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); } @@ -4592,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(); @@ -5130,17 +5230,17 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) if (ct && cs == 0 && ce == tabular.ncols() - 1) { // whole row selected if (act == LFUN_CHANGE_ACCEPT) { - if (tabular.row_info[r].change == Change::INSERTED) - tabular.row_info[r].change = Change::UNCHANGED; - else if (tabular.row_info[r].change == Change::DELETED) { + 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 == Change::DELETED) - tabular.row_info[r].change = Change::UNCHANGED; - else if (tabular.row_info[r].change == Change::INSERTED) { + 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; @@ -5151,17 +5251,17 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) if (ct && rs == 0 && re == tabular.nrows() - 1) { // whole col selected if (act == LFUN_CHANGE_ACCEPT) { - if (tabular.column_info[c].change == Change::INSERTED) - tabular.column_info[c].change = Change::UNCHANGED; - else if (tabular.column_info[c].change == Change::DELETED) { + 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 == Change::DELETED) - tabular.column_info[c].change = Change::UNCHANGED; - else if (tabular.column_info[c].change == Change::INSERTED) { + 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; @@ -5182,8 +5282,12 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & 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 { @@ -5196,7 +5300,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) 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 != Change::UNCHANGED) { + if (tabular.row_info[tabular.cellRow(cur.idx())].change.changed()) { // select row cur.idx() = tabular.getFirstCellInRow(tabular.cellRow(cur.idx())); cur.pit() = 0; @@ -5209,7 +5313,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) bvcur = cur; rowselect_ = true; } - else if (tabular.column_info[tabular.cellColumn(cur.idx())].change != Change::UNCHANGED) { + 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; @@ -5787,23 +5891,23 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, col_type cs, ce; getSelection(cur, rs, re, cs, ce); for (row_type r = rs; r <= re; ++r) { - if (tabular.row_info[r].change != Change::UNCHANGED) { + 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 != Change::UNCHANGED) { + if (tabular.column_info[c].change.changed()) { status.setEnabled(true); return true; } } } } else { - if (tabular.row_info[tabular.cellRow(cur.idx())].change != Change::UNCHANGED) { + 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 != Change::UNCHANGED) { + else if (tabular.column_info[tabular.cellColumn(cur.idx())].change.changed()) { status.setEnabled(true); return true; } @@ -5862,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; @@ -5923,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); } @@ -6959,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()); @@ -7026,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; } @@ -7122,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) @@ -7134,17 +7255,18 @@ 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 == Change::INSERTED) - tabular.row_info[row].change = Change::UNCHANGED; - else if (tabular.row_info[row].change == Change::DELETED) + 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 == Change::INSERTED) - tabular.column_info[col].change = Change::UNCHANGED; - else if (tabular.column_info[col].change == Change::DELETED) + 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(); } @@ -7153,17 +7275,18 @@ 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 == Change::DELETED) - tabular.row_info[row].change = Change::UNCHANGED; - else if (tabular.row_info[row].change == Change::INSERTED) + 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 == Change::DELETED) - tabular.column_info[col].change = Change::UNCHANGED; - else if (tabular.column_info[col].change == Change::INSERTED) + 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(); }