mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-22 05:16:21 +00:00
Implement change tracking of column/row addition/deletion
Fixes #8469 File format change
This commit is contained in:
parent
bf7f4d716c
commit
bbc6ea4a5f
@ -7,6 +7,10 @@ changes happened in particular if possible. A good example would be
|
||||
|
||||
-----------------------
|
||||
|
||||
2020-01-11 Jürgen Spitzmüller <spitz@lyx.org>
|
||||
* Format incremented to 592: Add tabular column/row tag changed=[added|deleted]
|
||||
which tracks whether a whole row/column has been inserted/deleted in ct.
|
||||
|
||||
2020-01-10 Jürgen Spitzmüller <spitz@lyx.org>
|
||||
* Format incremented to 591: Add buffer param \postpone_fragile_content
|
||||
(option to toggle the movement of labels and stuff of moving arguments).
|
||||
|
@ -3689,6 +3689,24 @@ def revert_postpone_fragile(document):
|
||||
|
||||
del document.header[i]
|
||||
|
||||
def revert_colrow_tracking(document):
|
||||
" Remove change tag from tabular columns/rows "
|
||||
i = 0
|
||||
while True:
|
||||
i = find_token(document.body, "\\begin_inset Tabular", i+1)
|
||||
if i == -1:
|
||||
return
|
||||
j = find_end_of_inset(document.body, i+1)
|
||||
if j == -1:
|
||||
document.warning("Malformed LyX document: Could not find end of tabular.")
|
||||
continue
|
||||
for k in range(i, j):
|
||||
m = re.search('^<column.*change="([^"]+)".*>$', document.body[k])
|
||||
if m:
|
||||
document.body[k] = document.body[k].replace(' change="' + m.group(1) + '"', '')
|
||||
m = re.search('^<row.*change="([^"]+)".*>$', document.body[k])
|
||||
if m:
|
||||
document.body[k] = document.body[k].replace(' change="' + m.group(1) + '"', '')
|
||||
|
||||
##
|
||||
# Conversion hub
|
||||
@ -3742,10 +3760,12 @@ convert = [
|
||||
[588, []],
|
||||
[589, [convert_totalheight]],
|
||||
[590, [convert_changebars]],
|
||||
[591, [convert_postpone_fragile]]
|
||||
[591, [convert_postpone_fragile]],
|
||||
[592, []]
|
||||
]
|
||||
|
||||
revert = [[590, [revert_postpone_fragile]],
|
||||
revert = [[591, [revert_colrow_tracking]],
|
||||
[590, [revert_postpone_fragile]],
|
||||
[589, [revert_changebars]],
|
||||
[588, [revert_totalheight]],
|
||||
[587, [revert_memoir_endnotes,revert_enotez,revert_theendnotes]],
|
||||
|
@ -1539,12 +1539,18 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
|
||||
|
||||
case LFUN_CHANGE_NEXT:
|
||||
findNextChange(this);
|
||||
if (cur.inset().isTable())
|
||||
// In tables, there might be whole changed rows or columns
|
||||
cur.dispatch(cmd);
|
||||
// FIXME: Move this LFUN to Buffer so that we don't have to do this:
|
||||
dr.screenUpdate(Update::Force | Update::FitCursor);
|
||||
break;
|
||||
|
||||
case LFUN_CHANGE_PREVIOUS:
|
||||
findPreviousChange(this);
|
||||
if (cur.inset().isTable())
|
||||
// In tables, there might be whole changed rows or columns
|
||||
cur.dispatch(cmd);
|
||||
// FIXME: Move this LFUN to Buffer so that we don't have to do this:
|
||||
dr.screenUpdate(Update::Force | Update::FitCursor);
|
||||
break;
|
||||
|
@ -451,6 +451,25 @@ bool getTokenValue(string const & str, char const * token, Length & len)
|
||||
}
|
||||
|
||||
|
||||
bool getTokenValue(string const & str, char const * token, Change::Type & change)
|
||||
{
|
||||
// set the length to be zero() as default as this it should be if not
|
||||
// in the file format.
|
||||
change = Change::UNCHANGED;
|
||||
string tmp;
|
||||
if (getTokenValue(str, token, tmp)) {
|
||||
if (tmp == "inserted") {
|
||||
change = Change::INSERTED;
|
||||
return true;
|
||||
} else if (tmp == "deleted") {
|
||||
change = Change::DELETED;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool getTokenValue(string const & str, char const * token, Length & len, bool & flag)
|
||||
{
|
||||
len = Length();
|
||||
@ -531,6 +550,16 @@ string const write_attribute(string const & name, Length const & value)
|
||||
return value.zero() ? string() : write_attribute(name, value.asString());
|
||||
}
|
||||
|
||||
template <>
|
||||
string const write_attribute(string const & name, Change::Type const & type)
|
||||
{
|
||||
if (type == Change::INSERTED)
|
||||
return write_attribute(name, from_ascii("inserted"));
|
||||
else if (type == Change::DELETED)
|
||||
return write_attribute(name, from_ascii("deleted"));
|
||||
return string();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@ -673,7 +702,8 @@ Tabular::RowData::RowData()
|
||||
endfoot(false),
|
||||
endlastfoot(false),
|
||||
newpage(false),
|
||||
caption(false)
|
||||
caption(false),
|
||||
change(Change::UNCHANGED)
|
||||
{}
|
||||
|
||||
|
||||
@ -681,7 +711,8 @@ Tabular::ColumnData::ColumnData()
|
||||
: alignment(LYX_ALIGN_CENTER),
|
||||
valignment(LYX_VALIGN_TOP),
|
||||
width(0),
|
||||
varwidth(false)
|
||||
varwidth(false),
|
||||
change(Change::UNCHANGED)
|
||||
{
|
||||
}
|
||||
|
||||
@ -738,15 +769,17 @@ 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) {
|
||||
// mark track changes
|
||||
if (buffer().params().track_changes)
|
||||
if (ct)
|
||||
cell_info[row][c].inset->setChange(Change(Change::DELETED));
|
||||
// Care about multirow cells
|
||||
if (row + 1 < nrows() &&
|
||||
@ -755,7 +788,9 @@ void Tabular::deleteRow(row_type const row)
|
||||
cell_info[row + 1][c].multirow = CELL_BEGIN_OF_MULTIROW;
|
||||
}
|
||||
}
|
||||
if (!buffer().params().track_changes) {
|
||||
if (ct)
|
||||
row_info[row].change = Change::DELETED;
|
||||
else {
|
||||
row_info.erase(row_info.begin() + row);
|
||||
cell_info.erase(cell_info.begin() + row);
|
||||
}
|
||||
@ -808,6 +843,8 @@ void Tabular::insertRow(row_type const row, bool copy)
|
||||
if (buffer().params().track_changes)
|
||||
cellInfo(i).inset->setChange(Change(Change::INSERTED));
|
||||
}
|
||||
if (buffer().params().track_changes)
|
||||
row_info[row + 1].change = Change::INSERTED;
|
||||
}
|
||||
|
||||
|
||||
@ -857,15 +894,17 @@ 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) {
|
||||
// mark track changes
|
||||
if (buffer().params().track_changes)
|
||||
if (ct)
|
||||
cell_info[r][col].inset->setChange(Change(Change::DELETED));
|
||||
// Care about multicolumn cells
|
||||
if (col + 1 < ncols() &&
|
||||
@ -873,10 +912,12 @@ 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;
|
||||
}
|
||||
if (!buffer().params().track_changes)
|
||||
if (!ct)
|
||||
cell_info[r].erase(cell_info[r].begin() + col);
|
||||
}
|
||||
if (!buffer().params().track_changes)
|
||||
if (ct)
|
||||
column_info[col].change = Change::DELETED;
|
||||
else
|
||||
column_info.erase(column_info.begin() + col);
|
||||
updateIndexes();
|
||||
}
|
||||
@ -922,6 +963,8 @@ void Tabular::insertColumn(col_type const col, bool copy)
|
||||
if (buffer().params().track_changes)
|
||||
cellInfo(i).inset->setChange(Change(Change::INSERTED));
|
||||
}
|
||||
if (buffer().params().track_changes)
|
||||
column_info[col + 1].change = Change::INSERTED;
|
||||
}
|
||||
|
||||
|
||||
@ -1662,8 +1705,9 @@ void Tabular::write(ostream & os) const
|
||||
os << "<column"
|
||||
<< 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("valignment", column_info[c].valignment)
|
||||
os << write_attribute("decimal_point", column_info[c].decimal_point);
|
||||
os << write_attribute("change", column_info[c].change)
|
||||
<< write_attribute("valignment", column_info[c].valignment)
|
||||
<< write_attribute("width", column_info[c].p_width.asString())
|
||||
<< write_attribute("varwidth", column_info[c].varwidth)
|
||||
<< write_attribute("special", column_info[c].align_special)
|
||||
@ -1684,7 +1728,8 @@ void Tabular::write(ostream & os) const
|
||||
os << write_attribute("interlinespace", def);
|
||||
else
|
||||
os << write_attribute("interlinespace", row_info[r].interline_space);
|
||||
os << write_attribute("endhead", row_info[r].endhead)
|
||||
os << write_attribute("change", row_info[r].change)
|
||||
<< write_attribute("endhead", row_info[r].endhead)
|
||||
<< write_attribute("endfirsthead", row_info[r].endfirsthead)
|
||||
<< write_attribute("endfoot", row_info[r].endfoot)
|
||||
<< write_attribute("endlastfoot", row_info[r].endlastfoot)
|
||||
@ -1783,6 +1828,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);
|
||||
}
|
||||
|
||||
for (row_type i = 0; i < nrows(); ++i) {
|
||||
@ -1804,6 +1850,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);
|
||||
for (col_type j = 0; j < ncols(); ++j) {
|
||||
l_getline(is, line);
|
||||
if (!prefixIs(line, "<cell")) {
|
||||
@ -5072,14 +5119,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 == Change::INSERTED)
|
||||
tabular.row_info[r].change = Change::UNCHANGED;
|
||||
else if (tabular.row_info[r].change == 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) {
|
||||
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 == Change::INSERTED)
|
||||
tabular.column_info[c].change = Change::UNCHANGED;
|
||||
else if (tabular.column_info[c].change == 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) {
|
||||
tabular.deleteColumn(c, true);
|
||||
--ce;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// cursor follows cell:
|
||||
tmpcur.idx() = tabular.cellIndex(r, c);
|
||||
// select this cell only:
|
||||
@ -5093,7 +5181,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
|
||||
cell(tmpcur.idx())->dispatch(tmpcur, cmd);
|
||||
}
|
||||
}
|
||||
if (act == LFUN_CHANGE_ACCEPT || act == LFUN_CHANGE_REJECT) {
|
||||
if (ct) {
|
||||
// cursor might be invalid
|
||||
cur.fixIfBroken();
|
||||
}
|
||||
@ -5102,6 +5190,40 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
|
||||
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 != Change::UNCHANGED) {
|
||||
// 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 != Change::UNCHANGED) {
|
||||
// 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.
|
||||
@ -5658,6 +5780,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 != Change::UNCHANGED) {
|
||||
status.setEnabled(true);
|
||||
return true;
|
||||
}
|
||||
for (col_type c = cs; c <= ce; ++c) {
|
||||
if (tabular.column_info[c].change != Change::UNCHANGED) {
|
||||
status.setEnabled(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (tabular.row_info[tabular.cellRow(cur.idx())].change != Change::UNCHANGED) {
|
||||
status.setEnabled(true);
|
||||
return true;
|
||||
}
|
||||
else if (tabular.column_info[tabular.cellColumn(cur.idx())].change != Change::UNCHANGED) {
|
||||
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
|
||||
@ -6980,6 +7133,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)
|
||||
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)
|
||||
tabular.deleteColumn(col, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6987,6 +7152,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)
|
||||
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)
|
||||
tabular.deleteColumn(col, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -537,7 +537,7 @@ public:
|
||||
///
|
||||
void appendRow(row_type row);
|
||||
///
|
||||
void deleteRow(row_type row);
|
||||
void deleteRow(row_type row, bool const force = false);
|
||||
///
|
||||
void copyRow(row_type row);
|
||||
///
|
||||
@ -549,7 +549,7 @@ public:
|
||||
///
|
||||
void appendColumn(col_type column);
|
||||
///
|
||||
void deleteColumn(col_type column);
|
||||
void deleteColumn(col_type column, bool const force = false);
|
||||
///
|
||||
void copyColumn(col_type column);
|
||||
///
|
||||
@ -785,6 +785,8 @@ public:
|
||||
bool newpage;
|
||||
/// caption
|
||||
bool caption;
|
||||
///
|
||||
Change::Type change;
|
||||
};
|
||||
///
|
||||
typedef std::vector<RowData> row_vector;
|
||||
@ -808,6 +810,8 @@ public:
|
||||
docstring decimal_point;
|
||||
///
|
||||
bool varwidth;
|
||||
///
|
||||
Change::Type change;
|
||||
};
|
||||
///
|
||||
typedef std::vector<ColumnData> column_vector;
|
||||
|
@ -32,8 +32,8 @@ extern char const * const lyx_version_info;
|
||||
|
||||
// Do not remove the comment below, so we get merge conflict in
|
||||
// independent branches. Instead add your own.
|
||||
#define LYX_FORMAT_LYX 591 // spitz: postpone_fragile_content
|
||||
#define LYX_FORMAT_TEX2LYX 591
|
||||
#define LYX_FORMAT_LYX 592 // spitz: row/column change tracking
|
||||
#define LYX_FORMAT_TEX2LYX 592
|
||||
|
||||
#if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX
|
||||
#ifndef _MSC_VER
|
||||
|
Loading…
Reference in New Issue
Block a user