mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-22 05:16:21 +00:00
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:
parent
01ac256b90
commit
55beda376a
@ -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
|
||||
{
|
||||
|
13
src/Buffer.h
13
src/Buffer.h
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
28
src/Cursor.h
28
src/Cursor.h
@ -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_;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
31
src/Text.cpp
31
src/Text.cpp
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
267
src/Undo.cpp
267
src/Undo.cpp
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
152
src/Undo.h
152
src/Undo.h
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -13,6 +13,7 @@
|
||||
#define FILENAME_H
|
||||
|
||||
#include <string>
|
||||
#include <ctime>
|
||||
|
||||
|
||||
namespace lyx {
|
||||
|
Loading…
Reference in New Issue
Block a user