Refactor Undo/Redo framework into an Undo class owned by a Buffer. This reduces header dependencies from Undo.h which was including lots of stuff previously. This also solves the bug where undo/redo were reset upon buffer switching. Now, each buffer has a truly independant undo/redo architecture.

In the future, when Cursor has been fixed to work correctly with multiple views of the same Buffer, we could transfer the Undo owner from Buffer to Cursor.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@21031 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Abdelrazak Younes 2007-10-18 11:51:17 +00:00
parent 01ac256b90
commit 55beda376a
23 changed files with 468 additions and 361 deletions

View File

@ -165,9 +165,7 @@ class Buffer::Impl
{
public:
Impl(Buffer & parent, FileName const & file, bool readonly);
limited_stack<Undo> undostack;
limited_stack<Undo> redostack;
BufferParams params;
LyXVC lyxvc;
string temppath;
@ -219,6 +217,9 @@ public:
///
frontend::WorkAreaManager * wa_;
///
Undo undo_;
};
@ -226,7 +227,7 @@ Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_)
: lyx_clean(true), bak_clean(true), unnamed(false), read_only(readonly_),
filename(file), file_fully_loaded(false), inset(params),
toc_backend(&parent), embedded_files(&parent), timestamp_(0),
checksum_(0), wa_(0)
checksum_(0), wa_(0), undo_(parent)
{
inset.setAutoBreakRows(true);
lyxvc.buffer(&parent);
@ -304,30 +305,6 @@ Inset & Buffer::inset() const
}
limited_stack<Undo> & Buffer::undostack()
{
return pimpl_->undostack;
}
limited_stack<Undo> const & Buffer::undostack() const
{
return pimpl_->undostack;
}
limited_stack<Undo> & Buffer::redostack()
{
return pimpl_->redostack;
}
limited_stack<Undo> const & Buffer::redostack() const
{
return pimpl_->redostack;
}
BufferParams & Buffer::params()
{
return pimpl_->params;
@ -405,6 +382,12 @@ EmbeddedFiles const & Buffer::embeddedFiles() const
return pimpl_->embedded_files;
}
Undo & Buffer::undo()
{
return pimpl_->undo_;
}
string const Buffer::getLatexName(bool const no_path) const
{

View File

@ -29,6 +29,9 @@
namespace lyx {
class BufferParams;
// FIXME: Remove!
class BufferView;
class Cursor;
class EmbeddedFiles;
class ErrorItem;
class ErrorList;
@ -301,14 +304,6 @@ public:
///
bool isMultiLingual() const;
/// Does this mean that this is buffer local?
limited_stack<Undo> & undostack();
limited_stack<Undo> const & undostack() const;
/// Does this mean that this is buffer local?
limited_stack<Undo> & redostack();
limited_stack<Undo> const & redostack() const;
///
BufferParams & params();
BufferParams const & params() const;
@ -390,6 +385,8 @@ public:
EmbeddedFiles & embeddedFiles();
EmbeddedFiles const & embeddedFiles() const;
//@}
Undo & undo();
/// This function is called when the buffer is changed.
void changed() const;

View File

@ -50,7 +50,6 @@
#include "TextClass.h"
#include "TextMetrics.h"
#include "TexRow.h"
#include "Undo.h"
#include "VSpace.h"
#include "WordLangTuple.h"
@ -273,7 +272,7 @@ void outline(OutlineOp mode, Cursor & cur)
pit_type const newpit = std::distance(bgn, dest);
pit_type const len = std::distance(start, finish);
pit_type const deletepit = pit + len;
recordUndo(cur, Undo::ATOMIC, newpit, deletepit - 1);
buf.undo().recordUndo(cur, ATOMIC_UNDO, newpit, deletepit - 1);
pars.insert(dest, start, finish);
start = boost::next(pars.begin(), deletepit);
pit = newpit;
@ -305,7 +304,7 @@ void outline(OutlineOp mode, Cursor & cur)
// One such was found:
pit_type newpit = std::distance(bgn, dest);
pit_type const len = std::distance(start, finish);
recordUndo(cur, Undo::ATOMIC, pit, newpit - 1);
buf.undo().recordUndo(cur, ATOMIC_UNDO, pit, newpit - 1);
pars.insert(dest, start, finish);
start = boost::next(bgn, pit);
pit = newpit - len;
@ -313,7 +312,7 @@ void outline(OutlineOp mode, Cursor & cur)
break;
}
case OutlineIn:
recordUndo(cur);
buf.undo().recordUndo(cur);
for (; lit != lend; ++lit) {
if ((*lit)->toclevel == thistoclevel + 1 &&
start->layout()->labeltype == (*lit)->labeltype) {
@ -323,7 +322,7 @@ void outline(OutlineOp mode, Cursor & cur)
}
break;
case OutlineOut:
recordUndo(cur);
buf.undo().recordUndo(cur);
for (; lit != lend; ++lit) {
if ((*lit)->toclevel == thistoclevel - 1 &&
start->layout()->labeltype == (*lit)->labeltype) {
@ -853,10 +852,10 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd)
switch (cmd.action) {
case LFUN_UNDO:
flag.enabled(!buffer_.undostack().empty());
flag.enabled(!buffer_.undo().hasUndoStack());
break;
case LFUN_REDO:
flag.enabled(!buffer_.redostack().empty());
flag.enabled(!buffer_.undo().hasRedoStack());
break;
case LFUN_FILE_INSERT:
case LFUN_FILE_INSERT_PLAINTEXT_PARA:
@ -1018,7 +1017,7 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd)
case LFUN_UNDO:
cur.message(_("Undo"));
cur.clearSelection();
if (!textUndo(*this)) {
if (!cur.textUndo()) {
cur.message(_("No further undo information"));
updateFlags = Update::None;
}
@ -1027,7 +1026,7 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd)
case LFUN_REDO:
cur.message(_("Redo"));
cur.clearSelection();
if (!textRedo(*this)) {
if (!cur.textRedo()) {
cur.message(_("No further redo information"));
updateFlags = Update::None;
}
@ -1346,7 +1345,7 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd)
cur.reset(buffer_.inset());
d->text_metrics_[&buffer_.text()].editXY(cur, p.x_, p.y_);
//FIXME: what to do with cur.x_target()?
finishUndo();
cur.finishUndo();
// The metrics are already up to date. see scroll()
updateFlags = Update::None;
break;
@ -1361,7 +1360,7 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd)
// FIXME: We need to verify if the cursor stayed within an inset...
//cur.reset(buffer_.inset());
d->text_metrics_[&buffer_.text()].editXY(cur, p.x_, p.y_);
finishUndo();
cur.finishUndo();
while (cur.depth() > initial_depth) {
cur.forwardInset();
}
@ -1748,7 +1747,7 @@ bool BufferView::mouseSetCursor(Cursor & cur, bool select)
else
d->cursor_.clearSelection();
finishUndo();
d->cursor_.finishUndo();
return update;
}
@ -1973,7 +1972,7 @@ void BufferView::menuInsertLyXFile(string const & filenm)
ErrorList & el = buffer_.errorList("Parse");
// Copy the inserted document error list into the current buffer one.
el = buf.errorList("Parse");
recordUndo(d->cursor_);
buffer_.undo().recordUndo(d->cursor_);
cap::pasteParagraphList(d->cursor_, buf.paragraphs(),
buf.params().getTextClassPtr(), el);
res = _("Document %1$s inserted.");
@ -2261,12 +2260,11 @@ void BufferView::insertPlaintextFile(string const & f, bool asParagraph)
Cursor & cur = cursor();
cap::replaceSelection(cur);
recordUndo(cur);
buffer_.undo().recordUndo(cur);
if (asParagraph)
cur.innerText()->insertStringAsParagraphs(cur, tmpstr);
else
cur.innerText()->insertStringAsLines(cur, tmpstr);
}
} // namespace lyx

View File

@ -1552,4 +1552,78 @@ void Cursor::setCurrentFont()
}
}
bool Cursor::textUndo()
{
DocIterator dit = *this;
// Undo::textUndo() will modify dit.
if (!bv_->buffer().undo().textUndo(dit))
return false;
// Set cursor
setCursor(dit);
selection() = false;
resetAnchor();
fixIfBroken();
return true;
}
bool Cursor::textRedo()
{
DocIterator dit = *this;
// Undo::textRedo() will modify dit.
if (!bv_->buffer().undo().textRedo(dit))
return false;
// Set cursor
setCursor(dit);
selection() = false;
resetAnchor();
fixIfBroken();
return true;
}
void Cursor::finishUndo()
{
bv_->buffer().undo().finishUndo();
}
void Cursor::recordUndo(UndoKind kind, pit_type from, pit_type to)
{
bv_->buffer().undo().recordUndo(*this, kind, from, to);
}
void Cursor::recordUndo(UndoKind kind, pit_type from)
{
bv_->buffer().undo().recordUndo(*this, kind, from);
}
void Cursor::recordUndo(UndoKind kind)
{
bv_->buffer().undo().recordUndo(*this, kind);
}
void Cursor::recordUndoInset(UndoKind kind)
{
bv_->buffer().undo().recordUndoInset(*this, kind);
}
void Cursor::recordUndoFullDocument()
{
bv_->buffer().undo().recordUndoFullDocument(*this);
}
void Cursor::recordUndoSelection()
{
bv_->buffer().undo().recordUndo(*this, ATOMIC_UNDO,
selBegin().pit(), selEnd().pit());
}
} // namespace lyx

View File

@ -15,6 +15,7 @@
#include "DispatchResult.h"
#include "DocIterator.h"
#include "Font.h"
#include "Undo.h"
#include <iosfwd>
#include <vector>
@ -189,6 +190,33 @@ public:
/// output
friend std::ostream & operator<<(std::ostream & os, Cursor const & cur);
///
bool textUndo();
///
bool textRedo();
/// makes sure the next operation will be stored
void finishUndo();
/// The general case: prepare undo for an arbitrary range.
void recordUndo(UndoKind kind, pit_type from, pit_type to);
/// Convenience: prepare undo for the range between 'from' and cursor.
void recordUndo(UndoKind kind, pit_type from);
/// Convenience: prepare undo for the single paragraph or cell
/// containing the cursor
void recordUndo(UndoKind kind = ATOMIC_UNDO);
/// Convenience: prepare undo for the inset containing the cursor
void recordUndoInset(UndoKind kind = ATOMIC_UNDO);
/// Convenience: prepare undo for the whole buffer
void recordUndoFullDocument();
/// Convenience: prepare undo for the selected paragraphs
void recordUndoSelection();
public:
///
BufferView * bv_;

View File

@ -518,7 +518,7 @@ void cutSelection(Cursor & cur, bool doclear, bool realcut)
saveSelection(cur);
// make sure that the depth behind the selection are restored, too
recordUndoSelection(cur);
cur.recordUndoSelection();
pit_type begpit = cur.selBegin().pit();
pit_type endpit = cur.selEnd().pit();
@ -566,11 +566,11 @@ void cutSelection(Cursor & cur, bool doclear, bool realcut)
if (cur.selBegin().idx() != cur.selEnd().idx()) {
// The current selection spans more than one cell.
// Record all cells
recordUndoInset(cur);
cur.recordUndoInset();
} else {
// Record only the current cell to avoid a jumping
// cursor after undo
recordUndo(cur);
cur.recordUndo();
}
if (realcut)
copySelection(cur);
@ -733,7 +733,7 @@ void pasteFromStack(Cursor & cur, ErrorList & errorList, size_t sel_index)
if (!checkPastePossible(sel_index))
return;
recordUndo(cur);
cur.recordUndo();
pasteParagraphList(cur, theCuts[sel_index].first,
theCuts[sel_index].second, errorList);
cur.setSelection();
@ -757,7 +757,7 @@ void pasteClipboard(Cursor & cur, ErrorList & errorList, bool asParagraphs)
Buffer buffer("", false);
buffer.setUnnamed(true);
if (buffer.readString(lyx)) {
recordUndo(cur);
cur.recordUndo();
pasteParagraphList(cur, buffer.paragraphs(),
buffer.params().getTextClassPtr(), errorList);
cur.setSelection();
@ -770,7 +770,7 @@ void pasteClipboard(Cursor & cur, ErrorList & errorList, bool asParagraphs)
docstring const text = theClipboard().getAsText();
if (text.empty())
return;
recordUndo(cur);
cur.recordUndo();
if (asParagraphs)
cur.text()->insertStringAsParagraphs(cur, text);
else
@ -782,7 +782,7 @@ void pasteSelection(Cursor & cur, ErrorList & errorList)
{
if (selectionBuffer.empty())
return;
recordUndo(cur);
cur.recordUndo();
pasteParagraphList(cur, selectionBuffer[0].first,
selectionBuffer[0].second, errorList);
}
@ -790,7 +790,7 @@ void pasteSelection(Cursor & cur, ErrorList & errorList)
void replaceSelectionWithString(Cursor & cur, docstring const & str, bool backwards)
{
recordUndo(cur);
cur.recordUndo();
DocIterator selbeg = cur.selectionBegin();
// Get font setting before we cut

View File

@ -59,7 +59,6 @@
#include "Session.h"
#include "TextClassList.h"
#include "ToolbarBackend.h"
#include "Undo.h"
#include "insets/InsetBox.h"
#include "insets/InsetBranch.h"
@ -1798,7 +1797,9 @@ void LyXFunc::dispatch(FuncRequest const & cmd)
Buffer * buffer = lyx_view_->buffer();
TextClassPtr oldClass = buffer->params().getTextClassPtr();
recordUndoFullDocument(view());
Cursor & cur = view()->cursor();
cur.recordUndoFullDocument();
istringstream ss(argument);
Lexer lex(0,0);
@ -1818,7 +1819,6 @@ void LyXFunc::dispatch(FuncRequest const & cmd)
lyx_view_->buffer()->params().getEngine();
if (oldEngine != newEngine) {
Cursor & cur = view()->cursor();
FuncRequest fr(LFUN_INSET_REFRESH);
Inset & inset = lyx_view_->buffer()->inset();
@ -1837,7 +1837,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd)
BOOST_ASSERT(lyx_view_);
Buffer * buffer = lyx_view_->buffer();
TextClassPtr oldClass = buffer->params().getTextClassPtr();
recordUndoFullDocument(view());
view()->cursor().recordUndoFullDocument();
buffer->params().clearLayoutModules();
updateLayout(oldClass, buffer);
updateFlags = Update::Force | Update::FitCursor;
@ -1848,7 +1848,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd)
BOOST_ASSERT(lyx_view_);
Buffer * buffer = lyx_view_->buffer();
TextClassPtr oldClass = buffer->params().getTextClassPtr();
recordUndoFullDocument(view());
view()->cursor().recordUndoFullDocument();
buffer->params().addLayoutModule(argument);
updateLayout(oldClass, buffer);
updateFlags = Update::Force | Update::FitCursor;
@ -1876,7 +1876,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd)
//Save the old, possibly modular, layout for use in conversion.
TextClassPtr oldClass = buffer->params().getTextClassPtr();
recordUndoFullDocument(view());
view()->cursor().recordUndoFullDocument();
buffer->params().setBaseClass(new_class);
updateLayout(oldClass, buffer);
updateFlags = Update::Force | Update::FitCursor;

View File

@ -44,7 +44,6 @@
#include "Paragraph.h"
#include "paragraph_funcs.h"
#include "ParagraphParameters.h"
#include "Undo.h"
#include "TextMetrics.h"
#include "VSpace.h"
#include "WordLangTuple.h"
@ -438,7 +437,7 @@ void Text::insertChar(Cursor & cur, char_type c)
BOOST_ASSERT(this == cur.text());
BOOST_ASSERT(c != Paragraph::META_INSET);
recordUndo(cur, Undo::INSERT);
cur.recordUndo(INSERT_UNDO);
TextMetrics const & tm = cur.bv().textMetrics(this);
Buffer const & buffer = cur.buffer();
@ -566,11 +565,11 @@ void Text::insertChar(Cursor & cur, char_type c)
// cur.updateFlags(Update::Force);
setCursor(cur.top(), cur.pit(), cur.pos() + 1);
charInserted();
charInserted(cur);
}
void Text::charInserted()
void Text::charInserted(Cursor & cur)
{
// Here we call finishUndo for every 20 characters inserted.
// This is from my experience how emacs does it. (Lgb)
@ -578,7 +577,7 @@ void Text::charInserted()
if (counter < 20) {
++counter;
} else {
finishUndo();
cur.finishUndo();
counter = 0;
}
}
@ -664,7 +663,7 @@ void Text::acceptOrRejectChanges(Cursor & cur, ChangeOp op)
if (!cur.selection())
return;
recordUndoSelection(cur, Undo::ATOMIC);
cur.recordUndoSelection();
pit_type begPit = cur.selectionBegin().pit();
pit_type endPit = cur.selectionEnd().pit();
@ -753,7 +752,7 @@ void Text::acceptOrRejectChanges(Cursor & cur, ChangeOp op)
//
finishUndo();
cur.finishUndo();
cur.clearSelection();
setCursorIntern(cur, begPit, begPos);
cur.updateFlags(Update::Force);
@ -851,7 +850,7 @@ void Text::changeCase(Cursor & cur, Text::TextCase action)
cursorRightOneWord(cur);
}
recordUndoSelection(cur, Undo::ATOMIC);
cur.recordUndoSelection();
pit_type begPit = from.pit();
pit_type endPit = to.pit();
@ -953,7 +952,7 @@ bool Text::handleBibitems(Cursor & cur)
}
Paragraph const & prevpar = prevcur.paragraph();
if (cur.pit() > 0 && par.layout() == prevpar.layout()) {
recordUndo(cur, Undo::ATOMIC, prevcur.pit());
cur.recordUndo(ATOMIC_UNDO, prevcur.pit());
mergeParagraph(bufparams, cur.text()->paragraphs(),
prevcur.pit());
updateLabels(cur.buffer());
@ -978,7 +977,7 @@ bool Text::erase(Cursor & cur)
if (cur.pos() != cur.lastpos()) {
// this is the code for a normal delete, not pasting
// any paragraphs
recordUndo(cur, Undo::DELETE);
cur.recordUndo(DELETE_UNDO);
if(!par.eraseChar(cur.pos(), cur.buffer().params().trackChanges)) {
// the character has been logically deleted only => skip it
cur.top().forwardPos();
@ -1032,14 +1031,14 @@ bool Text::backspacePos0(Cursor & cur)
// is it an empty paragraph?
if (cur.lastpos() == 0
|| (cur.lastpos() == 1 && par.isSeparator(0))) {
recordUndo(cur, Undo::ATOMIC, prevcur.pit(), cur.pit());
cur.recordUndo(ATOMIC_UNDO, prevcur.pit(), cur.pit());
plist.erase(boost::next(plist.begin(), cur.pit()));
needsUpdate = true;
}
// is previous par empty?
else if (prevcur.lastpos() == 0
|| (prevcur.lastpos() == 1 && prevpar.isSeparator(0))) {
recordUndo(cur, Undo::ATOMIC, prevcur.pit(), cur.pit());
cur.recordUndo(ATOMIC_UNDO, prevcur.pit(), cur.pit());
plist.erase(boost::next(plist.begin(), prevcur.pit()));
needsUpdate = true;
}
@ -1049,7 +1048,7 @@ bool Text::backspacePos0(Cursor & cur)
// Correction: Pasting is always allowed with standard-layout
else if (par.layout() == prevpar.layout()
|| par.layout() == tclass.defaultLayout()) {
recordUndo(cur, Undo::ATOMIC, prevcur.pit());
cur.recordUndo(ATOMIC_UNDO, prevcur.pit());
mergeParagraph(bufparams, plist, prevcur.pit());
needsUpdate = true;
}
@ -1085,7 +1084,7 @@ bool Text::backspace(Cursor & cur)
} else {
// this is the code for a normal backspace, not pasting
// any paragraphs
recordUndo(cur, Undo::DELETE);
cur.recordUndo(DELETE_UNDO);
// We used to do cursorLeftIntern() here, but it is
// not a good idea since it triggers the auto-delete
// mechanism. So we do a cursorLeftIntern()-lite,
@ -1115,7 +1114,7 @@ bool Text::dissolveInset(Cursor & cur) {
if (isMainText(cur.bv().buffer()) || cur.inset().nargs() != 1)
return false;
recordUndoInset(cur);
cur.recordUndoInset();
cur.selHandle(false);
// save position
pos_type spos = cur.pos();
@ -1456,7 +1455,7 @@ void Text::charsTranspose(Cursor & cur)
// Track the changes if Change Tracking is enabled.
bool const trackChanges = cur.buffer().params().trackChanges;
recordUndo(cur);
cur.recordUndo();
par.eraseChar(pos2, trackChanges);
par.eraseChar(pos1, trackChanges);

View File

@ -287,7 +287,7 @@ private:
/// handle the case where bibitems were deleted
bool handleBibitems(Cursor & cur);
///
void charInserted();
void charInserted(Cursor & cur);
/// set 'number' font property
void number(Cursor & cur);

View File

@ -48,7 +48,6 @@
#include "Server.h"
#include "ServerSocket.h"
#include "TextMetrics.h"
#include "Undo.h"
#include "VSpace.h"
#include "frontends/FontMetrics.h"
@ -292,7 +291,7 @@ void Text::changeDepth(Cursor & cur, DEPTH_CHANGE type)
BOOST_ASSERT(this == cur.text());
pit_type const beg = cur.selBegin().pit();
pit_type const end = cur.selEnd().pit() + 1;
recordUndoSelection(cur);
cur.recordUndoSelection();
int max_depth = (beg != 0 ? pars_[beg - 1].getMaxDepthAfter() : 0);
for (pit_type pit = beg; pit != end; ++pit) {
@ -340,7 +339,7 @@ void Text::setFont(Cursor & cur, Font const & font, bool toggleall)
return;
// Ok, we have a selection.
recordUndoSelection(cur);
cur.recordUndoSelection();
setFont(cur.bv(), cur.selectionBegin().top(),
cur.selectionEnd().top(), font, toggleall);
@ -812,7 +811,7 @@ bool Text::deleteEmptyParagraphMechanism(Cursor & cur,
if (oldpar.empty() || (oldpar.size() == 1 && oldpar.isLineSeparator(0))) {
// Delete old par.
recordUndo(old, Undo::ATOMIC,
old.recordUndo(ATOMIC_UNDO,
max(old.pit() - 1, pit_type(0)),
min(old.pit() + 1, old.lastpit()));
ParagraphList & plist = old.text()->paragraphs();
@ -893,13 +892,13 @@ void Text::deleteEmptyParagraphMechanism(pit_type first, pit_type last, bool tra
void Text::recUndo(Cursor & cur, pit_type first, pit_type last) const
{
recordUndo(cur, Undo::ATOMIC, first, last);
cur.recordUndo(ATOMIC_UNDO, first, last);
}
void Text::recUndo(Cursor & cur, pit_type par) const
{
recordUndo(cur, Undo::ATOMIC, par, par);
cur.recordUndo(ATOMIC_UNDO, par, par);
}
} // namespace lyx

View File

@ -44,7 +44,6 @@
#include "paragraph_funcs.h"
#include "ParagraphParameters.h"
#include "TextMetrics.h"
#include "Undo.h"
#include "VSpace.h"
#include "ParIterator.h"
@ -118,14 +117,14 @@ static void moveCursor(Cursor & cur, bool selecting)
static void finishChange(Cursor & cur, bool selecting)
{
finishUndo();
cur.finishUndo();
moveCursor(cur, selecting);
}
static void mathDispatch(Cursor & cur, FuncRequest const & cmd, bool display)
{
recordUndo(cur);
cur.recordUndo();
docstring sel = cur.selectionAsString(false);
// It may happen that sel is empty but there is a selection
@ -176,7 +175,7 @@ static void mathDispatch(Cursor & cur, FuncRequest const & cmd, bool display)
static void specialChar(Cursor & cur, InsetSpecialChar::Kind kind)
{
recordUndo(cur);
cur.recordUndo();
cap::replaceSelection(cur);
cur.insert(new InsetSpecialChar(kind));
cur.posRight();
@ -190,7 +189,7 @@ static bool doInsertInset(Cursor & cur, Text * text,
if (!inset)
return false;
recordUndo(cur);
cur.recordUndo();
if (cmd.action == LFUN_INDEX_INSERT) {
docstring ds = support::subst(text->getStringToIndex(cur), '\n', ' ');
text->insertInset(cur, inset);
@ -290,7 +289,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_PARAGRAPH_MOVE_DOWN: {
pit_type const pit = cur.pit();
recUndo(cur, pit, pit + 1);
finishUndo();
cur.finishUndo();
std::swap(pars_[pit], pars_[pit + 1]);
updateLabels(cur.buffer());
needsUpdate = true;
@ -301,7 +300,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_PARAGRAPH_MOVE_UP: {
pit_type const pit = cur.pit();
recUndo(cur, pit - 1, pit);
finishUndo();
cur.finishUndo();
std::swap(pars_[pit], pars_[pit - 1]);
updateLabels(cur.buffer());
--cur.pit();
@ -325,7 +324,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
}
}
recordUndo(cur);
cur.recordUndo();
par.params().startOfAppendix(start);
// we can set the refreshing parameters now
@ -508,7 +507,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
// this avoids a double undo
// FIXME: should not be needed, ideally
if (!cur.selection())
recordUndo(cur);
cur.recordUndo();
cap::replaceSelection(cur);
cur.insert(new InsetNewline);
cur.posRight();
@ -639,7 +638,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
}
case LFUN_INSET_INSERT: {
recordUndo(cur);
cur.recordUndo();
Inset * inset = createInset(bv, cmd);
if (inset) {
// FIXME (Abdel 01/02/2006):
@ -740,7 +739,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
}
bv->buffer().errors("Paste");
cur.clearSelection(); // bug 393
finishUndo();
cur.finishUndo();
break;
case LFUN_CUT:
@ -870,7 +869,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
// this avoids a double undo
// FIXME: should not be needed, ideally
if (!cur.selection())
recordUndo(cur);
cur.recordUndo();
cap::replaceSelection(cur);
pos = cur.pos();
char_type c;
@ -947,7 +946,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
bv->buffer().errorList("Paste"));
bv->buffer().errors("Paste");
bv->buffer().markDirty();
finishUndo();
bv->cursor().finishUndo();
} else {
lyx::dispatch(FuncRequest(LFUN_PRIMARY_SELECTION_PASTE, "paragraph"));
}
@ -1200,7 +1199,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
Inset * inset = createInset(&cur.bv(), cmd);
if (!inset)
break;
recordUndo(cur);
cur.recordUndo();
cur.clearSelection();
insertInset(cur, inset);
// Show the dialog for the nomenclature entry, since the
@ -1437,7 +1436,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_FLOAT_LIST: {
TextClass const & tclass = bv->buffer().params().getTextClass();
if (tclass.floats().typeExist(to_utf8(cmd.argument()))) {
recordUndo(cur);
cur.recordUndo();
if (cur.selection())
cutSelection(cur, true, false);
breakParagraph(cur);
@ -1958,7 +1957,7 @@ void Text::pasteString(Cursor & cur, docstring const & clip,
{
cur.clearSelection();
if (!clip.empty()) {
recordUndo(cur);
cur.recordUndo();
if (asParagraphs)
insertStringAsParagraphs(cur, clip);
else

View File

@ -38,7 +38,6 @@
#include "ParIterator.h"
#include "rowpainter.h"
#include "Text.h"
#include "Undo.h"
#include "VSpace.h"
#include "frontends/FontMetrics.h"
@ -1592,7 +1591,7 @@ void TextMetrics::cursorPrevious(Cursor & cur)
// simplest solution is to move to the previous row instead.
cur.dispatch(FuncRequest(cur.selection()? LFUN_UP_SELECT: LFUN_UP));
finishUndo();
cur.finishUndo();
cur.updateFlags(Update::Force | Update::FitCursor);
}
@ -1612,7 +1611,7 @@ void TextMetrics::cursorNext(Cursor & cur)
cur.dispatch(
FuncRequest(cur.selection()? LFUN_DOWN_SELECT: LFUN_DOWN));
finishUndo();
cur.finishUndo();
cur.updateFlags(Update::Force | Update::FitCursor);
}

View File

@ -8,6 +8,7 @@
* \author John Levon
* \author André Pönitz
* \author Jürgen Vigna
* \author Abdelrazak Younes
*
* Full author contact details are available in file CREDITS.
*/
@ -17,13 +18,13 @@
#include "Undo.h"
#include "Buffer.h"
#include "BufferParams.h"
#include "buffer_funcs.h"
#include "Cursor.h"
#include "debug.h"
#include "BufferView.h"
#include "Text.h"
#include "DocIterator.h"
#include "Paragraph.h"
#include "ParagraphList.h"
#include "Text.h"
#include "mathed/MathSupport.h"
#include "mathed/MathData.h"
@ -32,20 +33,117 @@
#include <algorithm>
using std::advance;
using std::endl;
namespace lyx {
using std::advance;
using std::endl;
/**
These are the elements put on the undo stack. Each object contains complete
paragraphs from some cell and sufficient information to restore the cursor
state.
The cell is given by a DocIterator pointing to this cell, the 'interesting'
range of paragraphs by counting them from begin and end of cell,
respectively.
The cursor is also given as DocIterator and should point to some place in
the stored paragraph range. In case of math, we simply store the whole
cell, as there usually is just a simple paragraph in a cell.
The idea is to store the contents of 'interesting' paragraphs in some
structure ('Undo') _before_ it is changed in some edit operation.
Obviously, the stored ranged should be as small as possible. However, it
there is a lower limit: The StableDocIterator pointing stored in the undo
class must be valid after the changes, too, as it will used as a pointer
where to insert the stored bits when performining undo.
*/
struct UndoElement
{
/// Which kind of operation are we recording for?
UndoKind kind;
/// the position of the cursor
StableDocIterator cursor;
/// the position of the cell described
StableDocIterator cell;
/// counted from begin of cell
pit_type from;
/// complement to end of this cell
pit_type end;
/// the contents of the saved Paragraphs (for texted)
ParagraphList * pars;
/// the contents of the saved MathData (for mathed)
MathData * array;
/// Only used in case of full backups
BufferParams bparams;
/// Only used in case of full backups
bool isFullBuffer;
};
struct Undo::Private
{
Private(Buffer & buffer): buffer_(buffer) {}
// Returns false if no undo possible.
bool textUndoOrRedo(DocIterator & cur, bool isUndoOperation);
///
void doRecordUndo(UndoKind kind,
DocIterator const & cell,
pit_type first_pit,
pit_type last_pit,
DocIterator const & cur,
bool isFullBuffer,
bool isUndoOperation);
///
void recordUndo(UndoKind kind,
DocIterator & cur,
pit_type first_pit,
pit_type last_pit);
///
Buffer & buffer_;
/// Undo stack.
limited_stack<UndoElement> undostack;
/// Redo stack.
limited_stack<UndoElement> redostack;
/// The flag used by Undo::finishUndo().
bool undo_finished;
};
Undo::Undo(Buffer & buffer): d(new Undo::Private(buffer))
{
}
Undo::~Undo()
{
delete d;
}
bool Undo::hasUndoStack() const
{
return !d->undostack.empty();
}
bool Undo::hasRedoStack() const
{
return !d->redostack.empty();
}
namespace {
/// The flag used by finishUndo().
bool undo_finished;
std::ostream & operator<<(std::ostream & os, Undo const & undo)
std::ostream & operator<<(std::ostream & os, UndoElement const & undo)
{
return os << " from: " << undo.from << " end: " << undo.end
<< " cell:\n" << undo.cell
@ -60,25 +158,26 @@ bool samePar(StableDocIterator const & i1, StableDocIterator const & i2)
return i1 == tmpi2;
}
} // namespace anon
void doRecordUndo(Undo::undo_kind kind,
void Undo::Private::doRecordUndo(UndoKind kind,
DocIterator const & cell,
pit_type first_pit, pit_type last_pit,
DocIterator const & cur,
BufferParams const & bparams,
bool isFullBuffer,
limited_stack<Undo> & stack)
bool isUndoOperation)
{
if (first_pit > last_pit)
std::swap(first_pit, last_pit);
// create the position information of the Undo entry
Undo undo;
UndoElement undo;
undo.array = 0;
undo.pars = 0;
undo.kind = kind;
undo.cell = cell;
undo.cursor = cur;
undo.bparams = bparams ;
undo.bparams = buffer_.params();
undo.isFullBuffer = isFullBuffer;
//lyxerr << "recordUndo: cur: " << cur << endl;
//lyxerr << "recordUndo: pos: " << cur.pos() << endl;
@ -86,11 +185,14 @@ void doRecordUndo(Undo::undo_kind kind,
undo.from = first_pit;
undo.end = cell.lastpit() - last_pit;
limited_stack<UndoElement> & stack = isUndoOperation ?
undostack : redostack;
// Undo::ATOMIC are always recorded (no overlapping there).
// As nobody wants all removed character appear one by one when undoing,
// we want combine 'similar' non-ATOMIC undo recordings to one.
if (!undo_finished
&& kind != Undo::ATOMIC
&& kind != ATOMIC_UNDO
&& !stack.empty()
&& samePar(stack.top().cell, undo.cell)
&& stack.top().kind == undo.kind
@ -125,53 +227,58 @@ void doRecordUndo(Undo::undo_kind kind,
}
void recordUndo(Undo::undo_kind kind,
Cursor & cur, pit_type first_pit, pit_type last_pit,
limited_stack<Undo> & stack)
void Undo::Private::recordUndo(UndoKind kind, DocIterator & cur,
pit_type first_pit, pit_type last_pit)
{
BOOST_ASSERT(first_pit <= cur.lastpit());
BOOST_ASSERT(last_pit <= cur.lastpit());
doRecordUndo(kind, cur, first_pit, last_pit, cur,
cur.bv().buffer().params(), false, stack);
false, true);
undo_finished = false;
redostack.clear();
//lyxerr << "undostack:\n";
//for (size_t i = 0, n = buf.undostack().size(); i != n && i < 6; ++i)
// lyxerr << " " << i << ": " << buf.undostack()[i] << std::endl;
}
// Returns false if no undo possible.
bool textUndoOrRedo(BufferView & bv,
limited_stack<Undo> & stack, limited_stack<Undo> & otherstack)
bool Undo::Private::textUndoOrRedo(DocIterator & cur, bool isUndoOperation)
{
finishUndo();
undo_finished = true;
if (stack.empty()) {
limited_stack<UndoElement> & stack = isUndoOperation ?
undostack : redostack;
if (stack.empty())
// Nothing to do.
return false;
}
limited_stack<UndoElement> & otherstack = isUndoOperation ?
redostack : undostack;
// Adjust undo stack and get hold of current undo data.
Undo undo = stack.top();
UndoElement undo = stack.top();
stack.pop();
// We will store in otherstack the part of the document under 'undo'
Buffer & buf = bv.buffer();
DocIterator cell_dit = undo.cell.asDocIterator(&buf.inset());
DocIterator cell_dit = undo.cell.asDocIterator(&buffer_.inset());
doRecordUndo(Undo::ATOMIC, cell_dit,
undo.from, cell_dit.lastpit() - undo.end, bv.cursor(),
undo.bparams, undo.isFullBuffer,
otherstack);
doRecordUndo(ATOMIC_UNDO, cell_dit,
undo.from, cell_dit.lastpit() - undo.end, cur,
undo.isFullBuffer, !isUndoOperation);
// This does the actual undo/redo.
//lyxerr << "undo, performing: " << undo << std::endl;
bool labelsUpdateNeeded = false;
DocIterator dit = undo.cell.asDocIterator(&buf.inset());
DocIterator dit = undo.cell.asDocIterator(&buffer_.inset());
if (undo.isFullBuffer) {
BOOST_ASSERT(undo.pars);
// This is a full document
otherstack.top().bparams = buf.params();
buf.params() = undo.bparams;
std::swap(buf.paragraphs(), *undo.pars);
otherstack.top().bparams = buffer_.params();
buffer_.params() = undo.bparams;
std::swap(buffer_.paragraphs(), *undo.pars);
delete undo.pars;
undo.pars = 0;
} else if (dit.inMathed()) {
@ -215,103 +322,71 @@ bool textUndoOrRedo(BufferView & bv,
BOOST_ASSERT(undo.pars == 0);
BOOST_ASSERT(undo.array == 0);
// Set cursor
Cursor & cur = bv.cursor();
cur.setCursor(undo.cursor.asDocIterator(&buf.inset()));
cur.selection() = false;
cur.resetAnchor();
cur.fixIfBroken();
cur = undo.cursor.asDocIterator(&buffer_.inset());
if (labelsUpdateNeeded)
updateLabels(buf);
finishUndo();
updateLabels(buffer_);
undo_finished = true;
return true;
}
} // namespace anon
void finishUndo()
void Undo::finishUndo()
{
// Make sure the next operation will be stored.
undo_finished = true;
d->undo_finished = true;
}
bool textUndo(BufferView & bv)
bool Undo::textUndo(DocIterator & cur)
{
return textUndoOrRedo(bv, bv.buffer().undostack(),
bv.buffer().redostack());
return d->textUndoOrRedo(cur, true);
}
bool textRedo(BufferView & bv)
bool Undo::textRedo(DocIterator & cur)
{
return textUndoOrRedo(bv, bv.buffer().redostack(),
bv.buffer().undostack());
return d->textUndoOrRedo(cur, false);
}
void recordUndo(Undo::undo_kind kind,
Cursor & cur, pit_type first, pit_type last)
void Undo::recordUndo(DocIterator & cur, UndoKind kind)
{
Buffer & buf = cur.bv().buffer();
recordUndo(kind, cur, first, last, buf.undostack());
buf.redostack().clear();
//lyxerr << "undostack:\n";
//for (size_t i = 0, n = buf.undostack().size(); i != n && i < 6; ++i)
// lyxerr << " " << i << ": " << buf.undostack()[i] << std::endl;
d->recordUndo(kind, cur, cur.pit(), cur.pit());
}
void recordUndo(Cursor & cur, Undo::undo_kind kind)
void Undo::recordUndoInset(DocIterator & cur, UndoKind kind)
{
recordUndo(kind, cur, cur.pit(), cur.pit());
DocIterator c = cur;
c.pop_back();
d->doRecordUndo(kind, c, c.pit(), c.pit(), cur, false, true);
}
void recordUndoInset(Cursor & cur, Undo::undo_kind kind)
void Undo::recordUndo(DocIterator & cur, UndoKind kind, pit_type from)
{
Cursor c = cur;
c.pop();
Buffer & buf = cur.bv().buffer();
doRecordUndo(kind, c, c.pit(), c.pit(), cur,
buf.params(), false, buf.undostack());
d->recordUndo(kind, cur, cur.pit(), from);
}
void recordUndoSelection(Cursor & cur, Undo::undo_kind kind)
{
recordUndo(kind, cur, cur.selBegin().pit(), cur.selEnd().pit());
}
void recordUndo(Cursor & cur, Undo::undo_kind kind, pit_type from)
{
recordUndo(kind, cur, cur.pit(), from);
}
void recordUndo(Cursor & cur, Undo::undo_kind kind,
void Undo::recordUndo(DocIterator & cur, UndoKind kind,
pit_type from, pit_type to)
{
recordUndo(kind, cur, from, to);
d->recordUndo(kind, cur, from, to);
}
void recordUndoFullDocument(BufferView * bv)
void Undo::recordUndoFullDocument(DocIterator & cur)
{
Buffer & buf = bv->buffer();
doRecordUndo(
Undo::ATOMIC,
doc_iterator_begin(buf.inset()),
0, buf.paragraphs().size() - 1,
bv->cursor(),
buf.params(),
d->doRecordUndo(
ATOMIC_UNDO,
doc_iterator_begin(d->buffer_.inset()),
0, d->buffer_.paragraphs().size() - 1,
cur,
true,
buf.undostack()
true
);
undo_finished = false;
}

View File

@ -9,6 +9,7 @@
* \author John Levon
* \author André Pönitz
* \author Jürgen Vigna
* \author Abdelrazak Younes
*
* Full author contact details are available in file CREDITS.
*/
@ -16,95 +17,33 @@
#ifndef UNDO_H
#define UNDO_H
#include "DocIterator.h"
#include "BufferParams.h"
#include "support/types.h"
#include <string>
namespace lyx {
class Buffer;
class BufferParams;
class BufferView;
class DocIterator;
class Cursor;
class MathData;
class ParagraphList;
/**
These are the elements put on the undo stack. Each object contains complete
paragraphs from some cell and sufficient information to restore the cursor
state.
The cell is given by a DocIterator pointing to this cell, the 'interesting'
range of paragraphs by counting them from begin and end of cell,
respectively.
The cursor is also given as DocIterator and should point to some place in
the stored paragraph range. In case of math, we simply store the whole
cell, as there usually is just a simple paragraph in a cell.
The idea is to store the contents of 'interesting' paragraphs in some
structure ('Undo') _before_ it is changed in some edit operation.
Obviously, the stored ranged should be as small as possible. However, it
there is a lower limit: The StableDocIterator pointing stored in the undo
class must be valid after the changes, too, as it will used as a pointer
where to insert the stored bits when performining undo.
*/
class Undo {
public:
/// This is used to combine consecutive undo recordings of the same kind.
enum undo_kind {
/**
* Insert something - these will combine to one big chunk
* when many inserts come after each other.
*/
INSERT,
/**
* Delete something - these will combine to one big chunk
* when many deletes come after each other.
*/
DELETE,
/// Atomic - each of these will have its own entry in the stack
ATOMIC
};
/// Which kind of operation are we recording for?
undo_kind kind;
/// the position of the cursor
StableDocIterator cursor;
/// the position of the cell described
StableDocIterator cell;
/// counted from begin of cell
pit_type from;
/// complement to end of this cell
pit_type end;
/// the contents of the saved Paragraphs (for texted)
ParagraphList * pars;
/// the contents of the saved MathData (for mathed)
MathData * array;
/// Only used in case of full backups
BufferParams bparams;
/// Only used in case of full backups
bool isFullBuffer;
/// This is used to combine consecutive undo recordings of the same kind.
enum UndoKind {
/**
* Insert something - these will combine to one big chunk
* when many inserts come after each other.
*/
INSERT_UNDO,
/**
* Delete something - these will combine to one big chunk
* when many deletes come after each other.
*/
DELETE_UNDO,
/// Atomic - each of these will have its own entry in the stack
ATOMIC_UNDO
};
/// this will undo the last action - returns false if no undo possible
bool textUndo(BufferView & bv);
/// this will redo the last undo - returns false if no redo possible
bool textRedo(BufferView & bv);
/// makes sure the next operation will be stored
void finishUndo();
/**
* Record undo information - call with the current cursor and the 'other
* end' of the range of changed paragraphs. So we give an inclusive range.
@ -115,31 +54,54 @@ void finishUndo();
* Right now we use recordUndoInset if more than one cell is changed,
* but that puts the cursor in front of the inset after undo. We would need
* something like
* recordUndoGrid(Cursor & cur, Undo::undo_kind kind, idx_type from, idx_type to);
* recordUndoGrid(DocIterator & cur, UndoKind kind, idx_type from, idx_type to);
* and store the cell information in class Undo.
*/
class Undo
{
public:
/// The general case: prepare undo for an arbitrary range.
/// FIXME: replace Cursor with DocIterator. This is not possible right
/// now because we need access to Buffer->params()!.
void recordUndo(Cursor & cur, Undo::undo_kind kind,
pit_type from, pit_type to);
Undo(Buffer &);
/// Convenience: prepare undo for the range between 'from' and cursor.
void recordUndo(Cursor & cur, Undo::undo_kind kind, pit_type from);
~Undo();
/// Convenience: prepare undo for the single paragraph or cell
/// containing the cursor
void recordUndo(Cursor & cur, Undo::undo_kind kind = Undo::ATOMIC);
/// Convenience: prepare undo for the inset containing the cursor
void recordUndoInset(Cursor & cur, Undo::undo_kind kind = Undo::ATOMIC);
/// Convenience: prepare undo for the selected paragraphs
void recordUndoSelection(Cursor & cur, Undo::undo_kind kind = Undo::ATOMIC);
/// this will undo the last action - returns false if no undo possible
bool textUndo(DocIterator &);
/// this will redo the last undo - returns false if no redo possible
bool textRedo(DocIterator &);
/// makes sure the next operation will be stored
void finishUndo();
///
bool hasUndoStack() const;
///
bool hasRedoStack() const;
/// The general case: prepare undo for an arbitrary range.
void recordUndo(DocIterator & cur, UndoKind kind,
pit_type from, pit_type to);
/// Convenience: prepare undo for the range between 'from' and cursor.
void recordUndo(DocIterator & cur, UndoKind kind, pit_type from);
/// Convenience: prepare undo for the single paragraph or cell
/// containing the cursor
void recordUndo(DocIterator & cur, UndoKind kind = ATOMIC_UNDO);
/// Convenience: prepare undo for the inset containing the cursor
void recordUndoInset(DocIterator & cur, UndoKind kind = ATOMIC_UNDO);
/// Convenience: prepare undo for the whole buffer
void recordUndoFullDocument(DocIterator & cur);
private:
struct Private;
Private * const d;
};
/// Convenience: prepare undo for the whole buffer
void recordUndoFullDocument(BufferView * bv);
} // namespace lyx
#endif // UNDO_FUNCS_H
#endif // UNDO_H

View File

@ -44,7 +44,6 @@
#include "ParagraphParameters.h"
#include "ParIterator.h"
#include "TextMetrics.h"
#include "Undo.h"
#include "support/convert.h"
#include "support/lstrings.h"
@ -3154,7 +3153,7 @@ docstring const InsetTabular::editMessage() const
void InsetTabular::edit(Cursor & cur, bool left)
{
//lyxerr << "InsetTabular::edit: " << this << endl;
finishUndo();
cur.finishUndo();
cur.selection() = false;
cur.push(*this);
if (left) {
@ -3384,7 +3383,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_CUT:
if (tablemode(cur)) {
if (copySelection(cur)) {
recordUndoInset(cur, Undo::DELETE);
cur.recordUndoInset(DELETE_UNDO);
cutSelection(cur);
}
}
@ -3395,7 +3394,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_CHAR_DELETE_BACKWARD:
case LFUN_CHAR_DELETE_FORWARD:
if (tablemode(cur)) {
recordUndoInset(cur, Undo::DELETE);
cur.recordUndoInset(DELETE_UNDO);
cutSelection(cur);
}
else
@ -3406,7 +3405,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
if (!cur.selection())
break;
if (tablemode(cur)) {
finishUndo();
cur.finishUndo();
copySelection(cur);
} else
cell(cur.idx())->dispatch(cur, cmd);
@ -3437,7 +3436,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_PASTE:
if (tabularStackDirty() && theClipboard().isInternal()) {
recordUndoInset(cur, Undo::INSERT);
cur.recordUndoInset(INSERT_UNDO);
pasteClipboard(cur);
break;
}
@ -4127,7 +4126,7 @@ void InsetTabular::tabularFeatures(Cursor & cur,
break;
}
recordUndoInset(cur, Undo::ATOMIC);
cur.recordUndoInset(ATOMIC_UNDO);
getSelection(cur, sel_row_start, sel_row_end, sel_col_start, sel_col_end);
row_type const row = tabular.cellRow(cur.idx());

View File

@ -44,7 +44,6 @@
#include "sgml.h"
#include "TextMetrics.h"
#include "TexRow.h"
#include "Undo.h"
#include "frontends/alert.h"
#include "frontends/Painter.h"
@ -217,7 +216,7 @@ void InsetText::edit(Cursor & cur, bool left)
int const pos = left ? 0 : paragraphs().back().size();
text_.setCursor(cur.top(), pit, pos);
cur.clearSelection();
finishUndo();
cur.finishUndo();
}

View File

@ -16,6 +16,7 @@
#include "lyxfind.h"
#include "Buffer.h"
#include "BufferParams.h"
#include "Cursor.h"
#include "CutAndPaste.h"
#include "buffer_funcs.h"
@ -26,7 +27,6 @@
#include "Text.h"
#include "Paragraph.h"
#include "ParIterator.h"
#include "Undo.h"
#include "frontends/alert.h"
@ -177,7 +177,7 @@ int replaceAll(BufferView * bv,
if (!searchAllowed(bv, searchstr) || buf.isReadonly())
return 0;
recordUndoFullDocument(bv);
bv->cursor().recordUndoFullDocument();
MatchString const match(searchstr, cs, mw);
int num = 0;

View File

@ -20,7 +20,6 @@
#include "Cursor.h"
#include "FuncRequest.h"
#include "gettext.h"
#include "Undo.h"
#include "support/lstrings.h"
@ -72,7 +71,7 @@ void InsetMathCases::doDispatch(Cursor & cur, FuncRequest & cmd)
//lyxerr << "*** InsetMathCases: request: " << cmd << endl;
switch (cmd.action) {
case LFUN_TABULAR_FEATURE: {
recordUndo(cur);
cur.recordUndo();
docstring const & s = cmd.argument();
if (s == "add-vline-left" || s == "add-vline-right") {
cur.undispatched();

View File

@ -23,7 +23,6 @@
#include "debug.h"
#include "FuncRequest.h"
#include "gettext.h"
#include "Undo.h"
#include "frontends/Clipboard.h"
#include "frontends/Painter.h"
@ -1081,7 +1080,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
// multiple cells. Unfortunately this puts the cursor in front
// of the inset after undo. This is (especilally for large
// grids) annoying.
recordUndoInset(cur);
cur.recordUndoInset();
//autocorrect_ = false;
//macroModeClose();
//if (selection_) {
@ -1097,7 +1096,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
break;
case LFUN_CELL_SPLIT:
recordUndo(cur);
cur.recordUndo();
splitCell(cur);
break;
@ -1121,7 +1120,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
break;
case LFUN_BREAK_LINE: {
recordUndoInset(cur);
cur.recordUndoInset();
row_type const r = cur.row();
addRow(r);
@ -1142,7 +1141,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
}
case LFUN_TABULAR_FEATURE: {
recordUndoInset(cur);
cur.recordUndoInset();
//lyxerr << "handling tabular-feature " << to_utf8(cmd.argument()) << endl;
istringstream is(to_utf8(cmd.argument()));
string s;
@ -1272,12 +1271,12 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
if (grid.nargs() == 1) {
// single cell/part of cell
recordUndo(cur);
cur.recordUndo();
cur.cell().insert(cur.pos(), grid.cell(0));
cur.pos() += grid.cell(0).size();
} else {
// multiple cells
recordUndoInset(cur);
cur.recordUndoInset();
col_type const numcols =
min(grid.ncols(), ncols() - col(cur.idx()));
row_type const numrows =
@ -1299,7 +1298,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
cell(i).append(grid.cell(grid.index(r, c)));
}
cur.clearSelection(); // bug 393
finishUndo();
cur.finishUndo();
break;
}

View File

@ -42,7 +42,6 @@
#include "sgml.h"
#include "Text.h"
#include "TextPainter.h"
#include "Undo.h"
#include "insets/RenderPreview.h"
#include "insets/InsetLabel.h"
@ -1052,7 +1051,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_BREAK_LINE:
// some magic for the common case
if (type_ == hullSimple || type_ == hullEquation) {
recordUndoInset(cur);
cur.recordUndoInset();
bool const align =
cur.bv().buffer().params().use_amsmath == BufferParams::package_on;
mutate(align ? hullAlign : hullEqnArray);
@ -1065,7 +1064,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_MATH_NUMBER:
//lyxerr << "toggling all numbers" << endl;
if (display()) {
recordUndoInset(cur);
cur.recordUndoInset();
bool old = numberedType();
if (type_ == hullMultline)
numbered(nrows() - 1, !old);
@ -1079,7 +1078,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_MATH_NONUMBER:
if (display()) {
recordUndoInset(cur);
cur.recordUndoInset();
row_type r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
bool old = numbered(r);
cur.message(old ? _("No number") : _("Number"));
@ -1088,7 +1087,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
break;
case LFUN_LABEL_INSERT: {
recordUndoInset(cur);
cur.recordUndoInset();
row_type r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
docstring old_label = label(r);
docstring const default_label = from_ascii(
@ -1116,7 +1115,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
InsetCommandParams p("label");
InsetCommandMailer::string2params(name, to_utf8(cmd.argument()), p);
docstring str = p["name"];
recordUndoInset(cur);
cur.recordUndoInset();
row_type const r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
str = support::trim(str);
if (!str.empty())
@ -1134,12 +1133,12 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
}
case LFUN_MATH_EXTERN:
recordUndoInset(cur);
cur.recordUndoInset();
doExtern(cur, cmd);
break;
case LFUN_MATH_MUTATE: {
recordUndoInset(cur);
cur.recordUndoInset();
row_type row = cur.row();
col_type col = cur.col();
mutate(hullType(cmd.argument()));
@ -1155,7 +1154,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
}
case LFUN_MATH_DISPLAY: {
recordUndoInset(cur);
cur.recordUndoInset();
mutate(type_ == hullSimple ? hullEquation : hullSimple);
cur.idx() = 0;
cur.pos() = cur.lastpos();
@ -1287,7 +1286,7 @@ void InsetMathHull::handleFont(Cursor & cur, docstring const & arg,
{
// this whole function is a hack and won't work for incremental font
// changes...
recordUndo(cur);
cur.recordUndo();
if (cur.inset().asInsetMath()->name() == font)
cur.handleFont(to_utf8(font));
else {
@ -1299,7 +1298,7 @@ void InsetMathHull::handleFont(Cursor & cur, docstring const & arg,
void InsetMathHull::handleFont2(Cursor & cur, docstring const & arg)
{
recordUndo(cur);
cur.recordUndo();
Font font;
bool b;
font.fromString(to_utf8(arg), b);

View File

@ -46,7 +46,6 @@
#include "gettext.h"
#include "Text.h"
#include "OutputParams.h"
#include "Undo.h"
#include "support/lstrings.h"
#include "support/textutils.h"
@ -416,10 +415,10 @@ void InsetMathNest::handleFont
// changes...
if (cur.inset().asInsetMath()->name() == font) {
recordUndoInset(cur, Undo::ATOMIC);
cur.recordUndoInset();
cur.handleFont(to_utf8(font));
} else {
recordUndo(cur, Undo::ATOMIC);
cur.recordUndo();
cur.handleNest(createInsetMath(font));
cur.insert(arg);
}
@ -428,7 +427,7 @@ void InsetMathNest::handleFont
void InsetMathNest::handleFont2(Cursor & cur, docstring const & arg)
{
recordUndo(cur, Undo::ATOMIC);
cur.recordUndo();
Font font;
bool b;
font.fromString(to_utf8(arg), b);
@ -447,7 +446,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
switch (cmd.action) {
case LFUN_PASTE: {
recordUndo(cur);
cur.recordUndo();
cur.message(_("Paste"));
replaceSelection(cur);
docstring topaste;
@ -461,12 +460,12 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
}
cur.niceInsert(topaste);
cur.clearSelection(); // bug 393
finishUndo();
cur.finishUndo();
break;
}
case LFUN_CUT:
recordUndo(cur);
cur.recordUndo();
cutSelection(cur, true, true);
cur.message(_("Cut"));
// Prevent stale position >= size crash
@ -670,9 +669,9 @@ goto_char_backwards:
case LFUN_CHAR_DELETE_BACKWARD:
if (cur.pos() == 0)
// May affect external cell:
recordUndoInset(cur, Undo::ATOMIC);
cur.recordUndoInset();
else
recordUndo(cur, Undo::ATOMIC);
cur.recordUndo();
// if the inset can not be removed from within, delete it
if (!cur.backspace()) {
FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD);
@ -684,9 +683,9 @@ goto_char_backwards:
case LFUN_CHAR_DELETE_FORWARD:
if (cur.pos() == cur.lastpos())
// May affect external cell:
recordUndoInset(cur, Undo::ATOMIC);
cur.recordUndoInset();
else
recordUndo(cur, Undo::ATOMIC);
cur.recordUndo();
// if the inset can not be removed from within, delete it
if (!cur.erase()) {
FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD);
@ -704,14 +703,14 @@ goto_char_backwards:
break;
case LFUN_INSET_TOGGLE:
recordUndo(cur);
cur.recordUndo();
lock(!lock());
cur.popRight();
break;
case LFUN_SELF_INSERT:
if (cmd.argument().size() != 1) {
recordUndo(cur);
cur.recordUndo();
docstring const arg = cmd.argument();
if (!interpretString(cur, arg))
cur.insert(arg);
@ -727,7 +726,7 @@ goto_char_backwards:
// A side effect is that an undo before the macro is finished
// undoes the complete macro, not only the last character.
if (!cur.inMacroMode())
recordUndo(cur);
cur.recordUndo();
// spacial handling of space. If we insert an inset
// via macro mode, we want to put the cursor inside it
@ -766,7 +765,7 @@ goto_char_backwards:
if (cmd.argument().empty()) {
// do superscript if LyX handles
// deadkeys
recordUndo(cur, Undo::ATOMIC);
cur.recordUndo();
script(cur, true, grabAndEraseSelection(cur));
}
break;
@ -875,13 +874,13 @@ goto_char_backwards:
case LFUN_MATH_SIZE:
#if 0
recordUndo(cur);
cur.recordUndo();
cur.setSize(arg);
#endif
break;
case LFUN_MATH_MATRIX: {
recordUndo(cur, Undo::ATOMIC);
cur.recordUndo();
unsigned int m = 1;
unsigned int n = 1;
docstring v_align;
@ -906,7 +905,7 @@ goto_char_backwards:
ls = '(';
if (rs.empty())
rs = ')';
recordUndo(cur, Undo::ATOMIC);
cur.recordUndo();
cur.handleNest(MathAtom(new InsetMathDelim(ls, rs)));
break;
}
@ -925,7 +924,7 @@ goto_char_backwards:
// We mimic LFUN_MATH_DELIM in case we have an empty left
// or right delimiter.
if (have_l || have_r) {
recordUndo(cur, Undo::ATOMIC);
cur.recordUndo();
docstring const selection = grabAndEraseSelection(cur);
selClearOrDel(cur);
if (have_l)
@ -943,31 +942,31 @@ goto_char_backwards:
case LFUN_SPACE_INSERT:
case LFUN_MATH_SPACE:
recordUndo(cur, Undo::ATOMIC);
cur.recordUndo();
cur.insert(MathAtom(new InsetMathSpace(from_ascii(","))));
break;
case LFUN_ERT_INSERT:
// interpret this as if a backslash was typed
recordUndo(cur, Undo::ATOMIC);
cur.recordUndo();
interpretChar(cur, '\\');
break;
case LFUN_MATH_SUBSCRIPT:
// interpret this as if a _ was typed
recordUndo(cur, Undo::ATOMIC);
cur.recordUndo();
interpretChar(cur, '_');
break;
case LFUN_MATH_SUPERSCRIPT:
// interpret this as if a ^ was typed
recordUndo(cur, Undo::ATOMIC);
cur.recordUndo();
interpretChar(cur, '^');
break;
case LFUN_QUOTE_INSERT:
// interpret this as if a straight " was typed
recordUndo(cur, Undo::ATOMIC);
cur.recordUndo();
interpretChar(cur, '\"');
break;
@ -975,7 +974,7 @@ goto_char_backwards:
// handling such that "self-insert" works on "arbitrary stuff" too, and
// math-insert only handles special math things like "matrix".
case LFUN_MATH_INSERT: {
recordUndo(cur, Undo::ATOMIC);
cur.recordUndo();
if (cmd.argument() == "^" || cmd.argument() == "_") {
interpretChar(cur, cmd.argument()[0]);
} else
@ -997,7 +996,7 @@ goto_char_backwards:
case LFUN_INSET_INSERT: {
MathData ar;
if (createInsetMath_fromDialogStr(cmd.argument(), ar)) {
recordUndo(cur);
cur.recordUndo();
cur.insert(ar);
} else
cur.undispatched();
@ -1005,7 +1004,7 @@ goto_char_backwards:
}
case LFUN_INSET_DISSOLVE:
if (!asHullInset()) {
recordUndoInset(cur, Undo::ATOMIC);
cur.recordUndoInset();
cur.pullArg();
}
break;

View File

@ -20,7 +20,6 @@
#include "Cursor.h"
#include "debug.h"
#include "FuncRequest.h"
#include "Undo.h"
#include <boost/assert.hpp>
@ -673,18 +672,18 @@ bool InsetMathScript::notifyCursorLeaves(Cursor & cur)
// Case of two scripts. In this case, 1 = super, 2 = sub
if (cur.idx() == 2 && cell(2).empty()) {
// must be a subscript...
recordUndoInset(cur);
cur.recordUndoInset();
removeScript(false);
return true;
} else if (cur.idx() == 1 && cell(1).empty()) {
// must be a superscript...
recordUndoInset(cur);
cur.recordUndoInset();
removeScript(true);
return true;
}
} else if (nargs() > 1 && cur.idx() == 1 && cell(1).empty()) {
// could be either subscript or super script
recordUndoInset(cur);
cur.recordUndoInset();
removeScript(cell_1_is_up_);
// Let the script inset commit suicide. This is
// modelled on Cursor.pullArg(), but tries not to

View File

@ -13,6 +13,7 @@
#define FILENAME_H
#include <string>
#include <ctime>
namespace lyx {