From 02028c0b12ba94093e4e77494e7158a58f1631e5 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Sun, 23 Jul 2017 18:13:33 +0200 Subject: [PATCH] Move some Cursor methods to CursorData Basically, everything that does not depend on a BufferView should move there. Some methods that do not seem to need a BufferView, like selHandle or IdxFirst or push actually depend on it and could not be moved. This allows to simplify a few uses of recordUndo helpers. - Move some methods to DocIterator: nextMath, prevMath, getPossibleLabel, getEncoding; - Move some methods to CursorData: setCursor, setCursorSelectionTo, (setCursorTo|normal|reset)Anchor, (set|clear)Selection, sel(|ection)(Begin|End), selectionAsString, info, currentState, (mark|clear|check)NewWordPosition, fixIfBroken, sanitize, all undo related methods, reset, isInside, leaveInset, current mode; - kill some unused methods: macromode, replaceWord, setScreenPos, touch, markInsert, markErase; - Move code around to group things, and add a few comments (a lot remains to be done). This changes lead to some related changes in other classes: removal, change of parameter. No intended change. --- src/Buffer.cpp | 2 +- src/Cursor.cpp | 1368 ++++++++++++++++------------------ src/Cursor.h | 354 +++++---- src/CutAndPaste.cpp | 8 +- src/CutAndPaste.h | 6 +- src/DocIterator.cpp | 39 +- src/DocIterator.h | 14 +- src/Text.cpp | 4 +- src/Text.h | 5 +- src/insets/InsetGraphics.cpp | 2 +- src/insets/InsetLabel.cpp | 2 +- src/mathed/InsetMathHull.cpp | 36 - src/mathed/InsetMathHull.h | 2 - src/mathed/InsetMathNest.cpp | 2 +- src/mathed/MathData.cpp | 5 - src/mathed/MathData.h | 2 - 16 files changed, 896 insertions(+), 955 deletions(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index c564a7dccf..a781f2ada3 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -5011,7 +5011,7 @@ void Buffer::updateBuffer(ParIterator & parit, UpdateType utype) const * non-const. This would however be costly in * terms of code duplication. */ - const_cast(this)->undo().recordUndo(CursorData(parit)); + CursorData(parit).recordUndo(); parit->params().depth(maxdepth); } maxdepth = parit->getMaxDepthAfter(); diff --git a/src/Cursor.cpp b/src/Cursor.cpp index cc9b76eee0..3f5bff854c 100644 --- a/src/Cursor.cpp +++ b/src/Cursor.cpp @@ -15,17 +15,13 @@ #include #include "Buffer.h" -#include "BufferParams.h" #include "BufferView.h" #include "CoordCache.h" #include "Cursor.h" #include "CutAndPaste.h" #include "DispatchResult.h" -#include "Encoding.h" -#include "Font.h" #include "FuncCode.h" #include "FuncRequest.h" -#include "Language.h" #include "Layout.h" #include "LyXAction.h" #include "LyXRC.h" @@ -118,27 +114,26 @@ DocIterator bruteFind(Cursor const & c, int x, int y) } // namespace +// +// CursorData +// + + CursorData::CursorData() - : DocIterator(), anchor_(), - selection_(false), mark_(false), word_selection_(false), - current_font(inherit_font), - autocorrect_(false), macromode_(false) + : DocIterator(), anchor_(), selection_(false), mark_(false), + word_selection_(false), current_font(inherit_font), autocorrect_(false) {} CursorData::CursorData(Buffer * buffer) - : DocIterator(buffer), anchor_(), - selection_(false), mark_(false), word_selection_(false), - current_font(inherit_font), - autocorrect_(false), macromode_(false) + : DocIterator(buffer), anchor_(), selection_(false), mark_(false), + word_selection_(false), current_font(inherit_font), autocorrect_(false) {} CursorData::CursorData(DocIterator const & dit) - : DocIterator(dit), anchor_(), - selection_(false), mark_(false), word_selection_(false), - current_font(inherit_font), - autocorrect_(false), macromode_(false) + : DocIterator(dit), anchor_(), selection_(false), mark_(false), + word_selection_(false), current_font(inherit_font), autocorrect_(false) {} @@ -165,11 +160,510 @@ ostream & operator<<(ostream & os, CursorData const & cur) } -LyXErr & operator<<(LyXErr & os, CursorData const & cur) -{ - os.stream() << cur; - return os; -} +LyXErr & operator<<(LyXErr & os, CursorData const & cur) +{ + os.stream() << cur; + return os; +} + + +void CursorData::reset() +{ + clear(); + push_back(CursorSlice(buffer()->inset())); + anchor_ = doc_iterator_begin(buffer()); + anchor_.clear(); + new_word_ = doc_iterator_begin(buffer()); + new_word_.clear(); + selection_ = false; + mark_ = false; +} + + +void CursorData::setCursor(DocIterator const & cur) +{ + DocIterator::operator=(cur); +} + + +void CursorData::setCursorSelectionTo(DocIterator dit) +{ + size_t i = 0; + // normalise dit + while (i < dit.depth() && i < anchor_.depth() && dit[i] == anchor_[i]) + ++i; + if (i != dit.depth()) { + // otherwise the cursor is already normal + if (i == anchor_.depth()) + // dit is a proper extension of the anchor_ + dit.cutOff(i - 1); + else if (i + 1 < dit.depth()) { + // one has dit[i] != anchor_[i] but either dit[i-1] == anchor_[i-1] + // or i == 0. Remove excess. + dit.cutOff(i); + if (dit[i] > anchor_[i]) + // place dit after the inset it was in + ++dit.pos(); + } + } + setCursor(dit); + setSelection(); +} + + +void CursorData::setCursorToAnchor() +{ + if (selection()) { + DocIterator normal = anchor_; + while (depth() < normal.depth()) + normal.pop_back(); + if (depth() < anchor_.depth() && top() <= anchor_[depth() - 1]) + ++normal.pos(); + setCursor(normal); + } +} + + +CursorSlice CursorData::normalAnchor() const +{ + if (!selection()) + return top(); + // LASSERT: There have been several bugs around this code, that seem + // to involve failures to reset the anchor. We can at least not crash + // in release mode by resetting it ourselves. + if (anchor_.depth() < depth()) { + LYXERR0("Cursor is deeper than anchor. PLEASE REPORT.\nCursor is" + << *this); + const_cast(anchor_) = *this; + } + + CursorSlice normal = anchor_[depth() - 1]; + if (depth() < anchor_.depth() && top() <= normal) { + // anchor is behind cursor -> move anchor behind the inset + ++normal.pos(); + } + return normal; +} + + +void CursorData::setSelection() +{ + selection(true); + if (idx() == normalAnchor().idx() && + pit() == normalAnchor().pit() && + pos() == normalAnchor().pos()) + selection(false); +} + + +void CursorData::setSelection(DocIterator const & where, int n) +{ + setCursor(where); + selection(true); + anchor_ = where; + pos() += n; +} + + +void CursorData::resetAnchor() +{ + anchor_ = *this; + checkNewWordPosition(); +} + + +CursorSlice CursorData::selBegin() const +{ + if (!selection()) + return top(); + return normalAnchor() < top() ? normalAnchor() : top(); +} + + +CursorSlice CursorData::selEnd() const +{ + if (!selection()) + return top(); + return normalAnchor() > top() ? normalAnchor() : top(); +} + + +DocIterator CursorData::selectionBegin() const +{ + if (!selection()) + return *this; + + DocIterator di; + // FIXME: This is a work-around for the problem that + // CursorSlice doesn't keep track of the boundary. + if (normalAnchor() == top()) + di = anchor_.boundary() > boundary() ? anchor_ : *this; + else + di = normalAnchor() < top() ? anchor_ : *this; + di.resize(depth()); + return di; +} + + +DocIterator CursorData::selectionEnd() const +{ + if (!selection()) + return *this; + + DocIterator di; + // FIXME: This is a work-around for the problem that + // CursorSlice doesn't keep track of the boundary. + if (normalAnchor() == top()) + di = anchor_.boundary() < boundary() ? anchor_ : *this; + else + di = normalAnchor() > top() ? anchor_ : *this; + + if (di.depth() > depth()) { + di.resize(depth()); + ++di.pos(); + } + return di; +} + + +namespace { + +docstring parbreak(CursorData const * cur) +{ + odocstringstream os; + os << '\n'; + // only add blank line if we're not in a ParbreakIsNewline situation + if (!cur->inset().getLayout().parbreakIsNewline() + && !cur->paragraph().layout().parbreak_is_newline) + os << '\n'; + return os.str(); +} + +} + + +docstring CursorData::selectionAsString(bool with_label) const +{ + if (!selection()) + return docstring(); + + if (inMathed()) + return cap::grabSelection(*this); + + int const label = with_label + ? AS_STR_LABEL | AS_STR_INSETS : AS_STR_INSETS; + + idx_type const startidx = selBegin().idx(); + idx_type const endidx = selEnd().idx(); + if (startidx != endidx) { + // multicell selection + InsetTabular * table = inset().asInsetTabular(); + LASSERT(table, return docstring()); + return table->asString(startidx, endidx); + } + + ParagraphList const & pars = text()->paragraphs(); + + pit_type const startpit = selBegin().pit(); + pit_type const endpit = selEnd().pit(); + size_t const startpos = selBegin().pos(); + size_t const endpos = selEnd().pos(); + + if (startpit == endpit) + return pars[startpit].asString(startpos, endpos, label); + + // First paragraph in selection + docstring result = pars[startpit]. + asString(startpos, pars[startpit].size(), label) + + parbreak(this); + + // The paragraphs in between (if any) + for (pit_type pit = startpit + 1; pit != endpit; ++pit) { + Paragraph const & par = pars[pit]; + result += par.asString(0, par.size(), label) + + parbreak(this); + } + + // Last paragraph in selection + result += pars[endpit].asString(0, endpos, label); + + return result; +} + + +void CursorData::info(odocstream & os, bool devel_mode) const +{ + for (int i = 1, n = depth(); i < n; ++i) { + operator[](i).inset().infoize(os); + os << " "; + } + if (pos() != 0) { + Inset const * inset = prevInset(); + // prevInset() can return 0 in certain case. + if (inset) + prevInset()->infoize2(os); + } + if (devel_mode) { + InsetMath * math = inset().asInsetMath(); + if (math) + os << _(", Inset: ") << math->id(); + os << _(", Cell: ") << idx(); + os << _(", Position: ") << pos(); + } + +} + +docstring CursorData::currentState(bool devel_mode) const +{ + if (inMathed()) { + odocstringstream os; + info(os, devel_mode); + return os.str(); + } + + if (inTexted()) + return text()->currentState(*this, devel_mode); + + return docstring(); +} + + +void CursorData::markNewWordPosition() +{ + if (lyxrc.spellcheck_continuously && inTexted() && new_word_.empty()) { + FontSpan nw = locateWord(WHOLE_WORD); + if (nw.size() == 1) { + LYXERR(Debug::DEBUG, "start new word: " + << " par: " << pit() + << " pos: " << nw.first); + new_word_ = *this; + } + } +} + + +void CursorData::clearNewWordPosition() +{ + if (!new_word_.empty()) { + LYXERR(Debug::DEBUG, "clear new word: " + << " par: " << pit() + << " pos: " << pos()); + new_word_.resize(0); + } +} + + +void CursorData::checkNewWordPosition() +{ + if (!lyxrc.spellcheck_continuously || new_word_.empty()) + return ; + if (!inTexted()) + clearNewWordPosition(); + else { + // forget the position of the current new word if + // 1) the paragraph changes or + // 2) the count of nested insets changes or + // 3) the cursor pos is out of paragraph bound + if (pit() != new_word_.pit() || + depth() != new_word_.depth() || + new_word_.pos() > new_word_.lastpos()) { + clearNewWordPosition(); + } else if (new_word_.fixIfBroken()) + // 4) or the remembered position was "broken" + clearNewWordPosition(); + else { + FontSpan nw = locateWord(WHOLE_WORD); + if (!nw.empty()) { + FontSpan ow = new_word_.locateWord(WHOLE_WORD); + if (nw.intersect(ow).empty()) + clearNewWordPosition(); + else + LYXERR(Debug::DEBUG, "new word: " + << " par: " << pit() + << " pos: " << nw.first << ".." << nw.last); + } else { + clearNewWordPosition(); + } + } + } +} + + +void CursorData::clearSelection() +{ + selection(false); + setWordSelection(false); + setMark(false); + resetAnchor(); +} + + +bool CursorData::fixIfBroken() +{ + bool const broken_cursor = DocIterator::fixIfBroken(); + bool const broken_anchor = anchor_.fixIfBroken(); + + if (broken_cursor || broken_anchor) { + clearNewWordPosition(); + clearSelection(); + return true; + } + return false; +} + + +void CursorData::sanitize() +{ + DocIterator::sanitize(); + if (selection()) + anchor_.sanitize(); + else + resetAnchor(); +} + + +bool CursorData::isInside(Inset const * p) const +{ + for (size_t i = 0; i != depth(); ++i) + if (&operator[](i).inset() == p) + return true; + return false; +} + + +void CursorData::leaveInset(Inset const & inset) +{ + for (size_t i = 0; i != depth(); ++i) { + if (&operator[](i).inset() == &inset) { + resize(i); + return; + } + } +} + + +bool CursorData::textUndo() +{ + if (!buffer()->undo().textUndo(*this)) + return false; + sanitize(); + return true; +} + + +bool CursorData::textRedo() +{ + if (!buffer()->undo().textRedo(*this)) + return false; + sanitize(); + return true; +} + + +void CursorData::finishUndo() const +{ + buffer()->undo().finishUndo(); +} + + +void CursorData::beginUndoGroup() const +{ + buffer()->undo().beginUndoGroup(*this); +} + + +void CursorData::endUndoGroup() const +{ + buffer()->undo().endUndoGroup(*this); +} + + +void CursorData::recordUndo(pit_type from, pit_type to) const +{ + buffer()->undo().recordUndo(*this, from, to); +} + + +void CursorData::recordUndo(pit_type from) const +{ + buffer()->undo().recordUndo(*this, from, pit()); +} + + +void CursorData::recordUndo(UndoKind kind) const +{ + buffer()->undo().recordUndo(*this, kind); +} + + +void CursorData::recordUndoInset(Inset const * in) const +{ + buffer()->undo().recordUndoInset(*this, in); +} + + +void CursorData::recordUndoFullBuffer() const +{ + buffer()->undo().recordUndoFullBuffer(*this); +} + + +void CursorData::recordUndoBufferParams() const +{ + buffer()->undo().recordUndoBufferParams(*this); +} + + +void CursorData::recordUndoSelection() const +{ + if (inMathed()) { + if (cap::multipleCellsSelected(*this)) + recordUndoInset(); + else + recordUndo(); + } else { + buffer()->undo().recordUndo(*this, + selBegin().pit(), selEnd().pit()); + } +} + + +int CursorData::currentMode() +{ + LASSERT(!empty(), return Inset::UNDECIDED_MODE); + for (int i = depth() - 1; i >= 0; --i) { + int res = operator[](i).inset().currentMode(); + bool locked_mode = operator[](i).inset().lockedMode(); + // Also return UNDECIDED_MODE when the mode is locked, + // as in this case it is treated the same as TEXT_MODE + if (res != Inset::UNDECIDED_MODE || locked_mode) + return res; + } + return Inset::TEXT_MODE; +} + + +bool CursorData::confirmDeletion(bool const before) const +{ + if (!selection()) { + if (Inset const * inset = before ? prevInset() : nextInset()) + return inset->confirmDeletion(); + } else { + DocIterator dit = selectionBegin(); + CursorSlice const end = selectionEnd().top(); + for (; dit.top() < end; dit.top().forwardPos()) + if (Inset const * inset = dit.nextInset()) + if (inset->confirmDeletion()) + return true; + } + return false; +} + + + +// +// Cursor +// // be careful: this is called from the bv's constructor, too, so @@ -183,59 +677,8 @@ Cursor::Cursor(BufferView & bv) void Cursor::reset() { - clear(); - push_back(CursorSlice(buffer()->inset())); - anchor_ = doc_iterator_begin(buffer()); - anchor_.clear(); - new_word_ = doc_iterator_begin(buffer()); - new_word_.clear(); + CursorData::reset(); clearTargetX(); - selection_ = false; - mark_ = false; -} - - -void Cursor::setCursor(DocIterator const & cur) -{ - DocIterator::operator=(cur); -} - - -void Cursor::setCursorSelectionTo(DocIterator dit) -{ - size_t i = 0; - // normalise dit - while (i < dit.depth() && i < anchor_.depth() && dit[i] == anchor_[i]) - ++i; - if (i != dit.depth()) { - // otherwise the cursor is already normal - if (i == anchor_.depth()) - // dit is a proper extension of the anchor_ - dit.cutOff(i - 1); - else if (i + 1 < dit.depth()) { - // one has dit[i] != anchor_[i] but either dit[i-1] == anchor_[i-1] - // or i == 0. Remove excess. - dit.cutOff(i); - if (dit[i] > anchor_[i]) - // place dit after the inset it was in - ++dit.pos(); - } - } - setCursor(dit); - setSelection(); -} - - -void Cursor::setCursorToAnchor() -{ - if (selection()) { - DocIterator normal = anchor_; - while (depth() < normal.depth()) - normal.pop_back(); - if (depth() < anchor_.depth() && top() <= anchor_[depth() - 1]) - ++normal.pos(); - setCursor(normal); - } } @@ -386,6 +829,19 @@ DispatchResult const & Cursor::result() const } +void Cursor::message(docstring const & msg) const +{ + disp_.setMessage(msg); +} + + +void Cursor::errorMessage(docstring const & msg) const +{ + disp_.setMessage(msg); + disp_.setError(true); +} + + BufferView & Cursor::bv() const { LBUFERR(bv_); @@ -439,21 +895,6 @@ bool Cursor::popForward() } -int Cursor::currentMode() -{ - LASSERT(!empty(), return Inset::UNDECIDED_MODE); - for (int i = depth() - 1; i >= 0; --i) { - int res = operator[](i).inset().currentMode(); - bool locked_mode = operator[](i).inset().lockedMode(); - // Also return UNDECIDED_MODE when the mode is locked, - // as in this case it is treated the same as TEXT_MODE - if (res != Inset::UNDECIDED_MODE || locked_mode) - return res; - } - return Inset::TEXT_MODE; -} - - void Cursor::getPos(int & x, int & y) const { Point p = bv().getPos(*this); @@ -470,74 +911,6 @@ Row const & Cursor::textRow() const } -void Cursor::resetAnchor() -{ - anchor_ = *this; - checkNewWordPosition(); -} - - -void Cursor::markNewWordPosition() -{ - if (lyxrc.spellcheck_continuously && inTexted() && new_word_.empty()) { - FontSpan nw = locateWord(WHOLE_WORD); - if (nw.size() == 1) { - LYXERR(Debug::DEBUG, "start new word: " - << " par: " << pit() - << " pos: " << nw.first); - new_word_ = *this; - } - } -} - - -void Cursor::clearNewWordPosition() -{ - if (!new_word_.empty()) { - LYXERR(Debug::DEBUG, "clear new word: " - << " par: " << pit() - << " pos: " << pos()); - new_word_.resize(0); - } -} - - -void Cursor::checkNewWordPosition() -{ - if (!lyxrc.spellcheck_continuously || new_word_.empty()) - return ; - if (!inTexted()) - clearNewWordPosition(); - else { - // forget the position of the current new word if - // 1) the paragraph changes or - // 2) the count of nested insets changes or - // 3) the cursor pos is out of paragraph bound - if (pit() != new_word_.pit() || - depth() != new_word_.depth() || - new_word_.pos() > new_word_.lastpos()) { - clearNewWordPosition(); - } else if (new_word_.fixIfBroken()) - // 4) or the remembered position was "broken" - clearNewWordPosition(); - else { - FontSpan nw = locateWord(WHOLE_WORD); - if (!nw.empty()) { - FontSpan ow = new_word_.locateWord(WHOLE_WORD); - if (nw.intersect(ow).empty()) - clearNewWordPosition(); - else - LYXERR(Debug::DEBUG, "new word: " - << " par: " << pit() - << " pos: " << nw.first << ".." << nw.last); - } else { - clearNewWordPosition(); - } - } - } -} - - bool Cursor::posVisRight(bool skip_inset) { Cursor new_cur = *this; // where we will move to @@ -870,148 +1243,44 @@ bool Cursor::posVisToNewRow(bool movingLeft) } else { // move to next row in this par pos() = row.endpos(); boundary(false); - } - } - - // make sure we're at left-/right-most pos in new row - posVisToRowExtremity(!movingLeft); - - return true; -} - - -void Cursor::posVisToRowExtremity(bool left) -{ - LYXERR(Debug::RTL, "entering extremity: " << pit() << "," << pos() << "," - << (boundary() ? 1 : 0)); - - TextMetrics const & tm = bv_->textMetrics(text()); - // Looking for extremities is like clicking on the left or the - // right of the row. - int x = tm.origin().x_ + (left ? 0 : textRow().width()); - bool b = false; - pos() = tm.getPosNearX(textRow(), x, b); - boundary(b); - - LYXERR(Debug::RTL, "leaving extremity: " << pit() << "," << pos() << "," - << (boundary() ? 1 : 0)); -} - - -bool Cursor::reverseDirectionNeeded() const -{ - /* - * We determine the directions based on the direction of the - * bottom() --- i.e., outermost --- paragraph, because that is - * the only way to achieve consistency of the arrow's movements - * within a paragraph, and thus avoid situations in which the - * cursor gets stuck. - */ - return bottom().paragraph().isRTL(bv().buffer().params()); -} - - -CursorSlice Cursor::normalAnchor() const -{ - if (!selection()) - return top(); - // LASSERT: There have been several bugs around this code, that seem - // to involve failures to reset the anchor. We can at least not crash - // in release mode by resetting it ourselves. - if (anchor_.depth() < depth()) { - LYXERR0("Cursor is deeper than anchor. PLEASE REPORT.\nCursor is" - << *this); - const_cast(anchor_) = *this; - } - - CursorSlice normal = anchor_[depth() - 1]; - if (depth() < anchor_.depth() && top() <= normal) { - // anchor is behind cursor -> move anchor behind the inset - ++normal.pos(); - } - return normal; -} - - -CursorSlice Cursor::selBegin() const -{ - if (!selection()) - return top(); - return normalAnchor() < top() ? normalAnchor() : top(); -} - - -CursorSlice Cursor::selEnd() const -{ - if (!selection()) - return top(); - return normalAnchor() > top() ? normalAnchor() : top(); -} - - -DocIterator Cursor::selectionBegin() const -{ - if (!selection()) - return *this; - - DocIterator di; - // FIXME: This is a work-around for the problem that - // CursorSlice doesn't keep track of the boundary. - if (normalAnchor() == top()) - di = anchor_.boundary() > boundary() ? anchor_ : *this; - else - di = normalAnchor() < top() ? anchor_ : *this; - di.resize(depth()); - return di; -} - - -DocIterator Cursor::selectionEnd() const -{ - if (!selection()) - return *this; - - DocIterator di; - // FIXME: This is a work-around for the problem that - // CursorSlice doesn't keep track of the boundary. - if (normalAnchor() == top()) - di = anchor_.boundary() < boundary() ? anchor_ : *this; - else - di = normalAnchor() > top() ? anchor_ : *this; - - if (di.depth() > depth()) { - di.resize(depth()); - ++di.pos(); + } } - return di; -} + // make sure we're at left-/right-most pos in new row + posVisToRowExtremity(!movingLeft); -void Cursor::setSelection() -{ - selection(true); - if (idx() == normalAnchor().idx() && - pit() == normalAnchor().pit() && - pos() == normalAnchor().pos()) - selection(false); + return true; } -void Cursor::setSelection(DocIterator const & where, int n) +void Cursor::posVisToRowExtremity(bool left) { - setCursor(where); - selection(true); - anchor_ = where; - pos() += n; + LYXERR(Debug::RTL, "entering extremity: " << pit() << "," << pos() << "," + << (boundary() ? 1 : 0)); + + TextMetrics const & tm = bv_->textMetrics(text()); + // Looking for extremities is like clicking on the left or the + // right of the row. + int x = tm.origin().x_ + (left ? 0 : textRow().width()); + bool b = false; + pos() = tm.getPosNearX(textRow(), x, b); + boundary(b); + + LYXERR(Debug::RTL, "leaving extremity: " << pit() << "," << pos() << "," + << (boundary() ? 1 : 0)); } -void Cursor::clearSelection() +bool Cursor::reverseDirectionNeeded() const { - selection(false); - setWordSelection(false); - setMark(false); - resetAnchor(); + /* + * We determine the directions based on the direction of the + * bottom() --- i.e., outermost --- paragraph, because that is + * the only way to achieve consistency of the arrow's movements + * within a paragraph, and thus avoid situations in which the + * cursor gets stuck. + */ + return bottom().paragraph().isRTL(bv().buffer().params()); } @@ -1044,29 +1313,6 @@ void Cursor::updateTextTargetOffset() } -void Cursor::info(odocstream & os, bool devel_mode) const -{ - for (int i = 1, n = depth(); i < n; ++i) { - operator[](i).inset().infoize(os); - os << " "; - } - if (pos() != 0) { - Inset const * inset = prevInset(); - // prevInset() can return 0 in certain case. - if (inset) - prevInset()->infoize2(os); - } - if (devel_mode) { - InsetMath * math = inset().asInsetMath(); - if (math) - os << _(", Inset: ") << math->id(); - os << _(", Cell: ") << idx(); - os << _(", Position: ") << pos(); - } - -} - - bool Cursor::selHandle(bool sel) { //lyxerr << "Cursor::selHandle" << endl; @@ -1082,6 +1328,31 @@ bool Cursor::selHandle(bool sel) selection(sel); return true; } + + +bool Cursor::atFirstOrLastRow(bool up) +{ + TextMetrics const & tm = bv_->textMetrics(text()); + ParagraphMetrics const & pm = tm.parMetrics(pit()); + + int row; + if (pos() && boundary()) + row = pm.pos2row(pos() - 1); + else + row = pm.pos2row(pos()); + + if (up) { + if (pit() == 0 && row == 0) + return true; + } else { + if (pit() + 1 >= int(text()->paragraphs().size()) && + row + 1 >= int(pm.rows().size())) + return true; + } + return false; +} + + } // namespace lyx @@ -1105,26 +1376,6 @@ bool Cursor::selHandle(bool sel) namespace lyx { -bool Cursor::isInside(Inset const * p) const -{ - for (size_t i = 0; i != depth(); ++i) - if (&operator[](i).inset() == p) - return true; - return false; -} - - -void Cursor::leaveInset(Inset const & inset) -{ - for (size_t i = 0; i != depth(); ++i) { - if (&operator[](i).inset() == &inset) { - resize(i); - return; - } - } -} - - bool Cursor::openable(MathAtom const & t) const { if (!t->isActive()) @@ -1146,32 +1397,12 @@ bool Cursor::openable(MathAtom const & t) const } -void Cursor::setScreenPos(int x, int /*y*/) -{ - setTargetX(x); - //bruteFind(*this, x, y, 0, bv().workWidth(), 0, bv().workHeight()); -} - - - void Cursor::plainErase() { cell().erase(pos()); } -void Cursor::markInsert() -{ - insert(char_type(0)); -} - - -void Cursor::markErase() -{ - cell().erase(pos()); -} - - void Cursor::plainInsert(MathAtom const & t) { cell().insert(pos(), t); @@ -1182,13 +1413,6 @@ void Cursor::plainInsert(MathAtom const & t) } -void Cursor::insert(docstring const & str) -{ - for (char_type c : str) - insert(c); -} - - void Cursor::insert(char_type c) { //lyxerr << "Cursor::insert char '" << c << "'" << endl; @@ -1202,12 +1426,10 @@ void Cursor::insert(char_type c) } -void Cursor::insert(MathAtom const & t) +void Cursor::insert(docstring const & str) { - //lyxerr << "Cursor::insert MathAtom '" << t << "'" << endl; - macroModeClose(); - cap::selClearOrDel(*this); - plainInsert(t); + for (char_type c : str) + insert(c); } @@ -1226,8 +1448,32 @@ void Cursor::insert(Inset * inset0) } +void Cursor::insert(MathAtom const & t) +{ + LATTEST(inMathed()); + //lyxerr << "Cursor::insert MathAtom '" << t << "'" << endl; + macroModeClose(); + cap::selClearOrDel(*this); + plainInsert(t); +} + + +void Cursor::insert(MathData const & ar) +{ + LATTEST(inMathed()); + macroModeClose(); + if (selection()) + cap::eraseSelection(*this); + cell().insert(pos(), ar); + pos() += ar.size(); + // FIXME audit setBuffer calls + inset().setBuffer(bv_->buffer()); +} + + int Cursor::niceInsert(docstring const & t, Parse::flags f, bool enter) { + LATTEST(inMathed()); MathData ar(buffer()); asArray(t, ar, f); if (ar.size() == 1 && (enter || selection())) @@ -1240,6 +1486,7 @@ int Cursor::niceInsert(docstring const & t, Parse::flags f, bool enter) void Cursor::niceInsert(MathAtom const & t) { + LATTEST(inMathed()); macroModeClose(); docstring const safe = cap::grabAndEraseSelection(*this); plainInsert(t); @@ -1266,18 +1513,6 @@ void Cursor::niceInsert(MathAtom const & t) } -void Cursor::insert(MathData const & ar) -{ - macroModeClose(); - if (selection()) - cap::eraseSelection(*this); - cell().insert(pos(), ar); - pos() += ar.size(); - // FIXME audit setBuffer calls - inset().setBuffer(bv_->buffer()); -} - - bool Cursor::backspace(bool const force) { if (selection()) { @@ -1401,6 +1636,43 @@ bool Cursor::down() } +void Cursor::handleNest(MathAtom const & a, int c) +{ + //lyxerr << "Cursor::handleNest: " << c << endl; + MathAtom t = a; + asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(c)); + insert(t); + posBackward(); + pushBackward(*nextInset()); +} + + +int Cursor::targetX() const +{ + if (x_target() != -1) + return x_target(); + int x = 0; + int y = 0; + getPos(x, y); + return x; +} + + +int Cursor::textTargetOffset() const +{ + return textTargetOffset_; +} + + +void Cursor::setTargetX() +{ + int x; + int y; + getPos(x, y); + setTargetX(x); +} + + bool Cursor::macroModeClose() { if (!inMacroMode()) @@ -1477,55 +1749,12 @@ bool Cursor::macroModeClose() // finally put the macro argument behind, if needed if (macroArg) { if (selection.size() > 1 || selection[0]->asScriptInset()) - plainInsert(MathAtom(new InsetMathBrace(selection))); - else - insert(selection); - } - - return true; -} - - -docstring Cursor::macroName() -{ - return inMacroMode() ? activeMacro()->name() : docstring(); -} - - -void Cursor::handleNest(MathAtom const & a, int c) -{ - //lyxerr << "Cursor::handleNest: " << c << endl; - MathAtom t = a; - asArray(cap::grabAndEraseSelection(*this), t.nucleus()->cell(c)); - insert(t); - posBackward(); - pushBackward(*nextInset()); -} - - -int Cursor::targetX() const -{ - if (x_target() != -1) - return x_target(); - int x = 0; - int y = 0; - getPos(x, y); - return x; -} - - -int Cursor::textTargetOffset() const -{ - return textTargetOffset_; -} - - -void Cursor::setTargetX() -{ - int x; - int y; - getPos(x, y); - setTargetX(x); + plainInsert(MathAtom(new InsetMathBrace(selection))); + else + insert(selection); + } + + return true; } @@ -1552,6 +1781,12 @@ InsetMathUnknown const * Cursor::activeMacro() const } +docstring Cursor::macroName() +{ + return inMacroMode() ? activeMacro()->name() : docstring(); +} + + void Cursor::pullArg() { // FIXME: Look here @@ -1566,18 +1801,6 @@ void Cursor::pullArg() } -void Cursor::touch() -{ - // FIXME: look here -#if 0 - DocIterator::const_iterator it = begin(); - DocIterator::const_iterator et = end(); - for ( ; it != et; ++it) - it->cell().touch(); -#endif -} - - void Cursor::normalize() { if (idx() > lastidx()) { @@ -1717,18 +1940,6 @@ bool Cursor::upDownInMath(bool up) } -InsetMath & Cursor::nextMath() -{ - return *nextAtom().nucleus(); -} - - -InsetMath & Cursor::prevMath() -{ - return *prevAtom().nucleus(); -} - - bool Cursor::mathForward(bool word) { LASSERT(inMathed(), return false); @@ -1806,29 +2017,6 @@ bool Cursor::mathBackward(bool word) } -bool Cursor::atFirstOrLastRow(bool up) -{ - TextMetrics const & tm = bv_->textMetrics(text()); - ParagraphMetrics const & pm = tm.parMetrics(pit()); - - int row; - if (pos() && boundary()) - row = pm.pos2row(pos() - 1); - else - row = pm.pos2row(pos()); - - if (up) { - if (pit() == 0 && row == 0) - return true; - } else { - if (pit() + 1 >= int(text()->paragraphs().size()) && - row + 1 >= int(pm.rows().size())) - return true; - } - return false; -} - - bool Cursor::upDownInText(bool up, bool & updateNeeded) { LASSERT(text(), return false); @@ -2026,121 +2214,6 @@ void Cursor::handleFont(string const & font) } -void Cursor::message(docstring const & msg) const -{ - disp_.setMessage(msg); -} - - -void Cursor::errorMessage(docstring const & msg) const -{ - disp_.setMessage(msg); - disp_.setError(true); -} - - -namespace { - -docstring parbreak(Cursor const * cur) -{ - odocstringstream os; - os << '\n'; - // only add blank line if we're not in a ParbreakIsNewline situation - if (!cur->inset().getLayout().parbreakIsNewline() - && !cur->paragraph().layout().parbreak_is_newline) - os << '\n'; - return os.str(); -} - -} // namespace - - -docstring Cursor::selectionAsString(bool with_label) const -{ - if (!selection()) - return docstring(); - - if (inMathed()) - return cap::grabSelection(*this); - - int const label = with_label - ? AS_STR_LABEL | AS_STR_INSETS : AS_STR_INSETS; - - idx_type const startidx = selBegin().idx(); - idx_type const endidx = selEnd().idx(); - if (startidx != endidx) { - // multicell selection - InsetTabular * table = inset().asInsetTabular(); - LASSERT(table, return docstring()); - return table->asString(startidx, endidx); - } - - ParagraphList const & pars = text()->paragraphs(); - - pit_type const startpit = selBegin().pit(); - pit_type const endpit = selEnd().pit(); - size_t const startpos = selBegin().pos(); - size_t const endpos = selEnd().pos(); - - if (startpit == endpit) - return pars[startpit].asString(startpos, endpos, label); - - // First paragraph in selection - docstring result = pars[startpit]. - asString(startpos, pars[startpit].size(), label) - + parbreak(this); - - // The paragraphs in between (if any) - for (pit_type pit = startpit + 1; pit != endpit; ++pit) { - Paragraph const & par = pars[pit]; - result += par.asString(0, par.size(), label) - + parbreak(this); - } - - // Last paragraph in selection - result += pars[endpit].asString(0, endpos, label); - - return result; -} - - -docstring Cursor::currentState(bool devel_mode) const -{ - if (inMathed()) { - odocstringstream os; - info(os, devel_mode); - return os.str(); - } - - if (inTexted()) - return text()->currentState(*this, devel_mode); - - return docstring(); -} - - -docstring Cursor::getPossibleLabel() const -{ - return inMathed() ? from_ascii("eq:") : text()->getPossibleLabel(*this); -} - - -Encoding const * Cursor::getEncoding() const -{ - if (empty()) - return 0; - BufferParams const & bp = bv().buffer().params(); - if (bp.useNonTeXFonts) - return encodings.fromLyXName("utf8-plain"); - - CursorSlice const & sl = innerTextSlice(); - Text const & text = *sl.text(); - Font font = text.getPar(sl.pit()).getFont(bp, sl.pos(), - text.outerFont(sl.pit())); - return font.language()->encoding(); -} - - void Cursor::undispatched() const { disp_.dispatched(false); @@ -2218,29 +2291,11 @@ Font Cursor::getFont() const } -bool Cursor::fixIfBroken() -{ - bool const broken_cursor = DocIterator::fixIfBroken(); - bool const broken_anchor = anchor_.fixIfBroken(); - - if (broken_cursor || broken_anchor) { - clearNewWordPosition(); - clearSelection(); - return true; - } - return false; -} - - void Cursor::sanitize() { - setBuffer(&bv_->buffer()); - DocIterator::sanitize(); + setBuffer(buffer()); + CursorData::sanitize(); new_word_.sanitize(); - if (selection()) - anchor_.sanitize(); - else - resetAnchor(); } @@ -2327,92 +2382,6 @@ void Cursor::setCurrentFont() } -bool Cursor::textUndo() -{ - if (!buffer()->undo().textUndo(*this)) - return false; - sanitize(); - return true; -} - - -bool Cursor::textRedo() -{ - if (!buffer()->undo().textRedo(*this)) - return false; - sanitize(); - return true; -} - - -void Cursor::finishUndo() const -{ - buffer()->undo().finishUndo(); -} - - -void Cursor::beginUndoGroup() const -{ - buffer()->undo().beginUndoGroup(*this); -} - - -void Cursor::endUndoGroup() const -{ - buffer()->undo().endUndoGroup(*this); -} - - -void Cursor::recordUndo(pit_type from, pit_type to) const -{ - buffer()->undo().recordUndo(*this, from, to); -} - - -void Cursor::recordUndo(pit_type from) const -{ - buffer()->undo().recordUndo(*this, from, pit()); -} - - -void Cursor::recordUndo(UndoKind kind) const -{ - buffer()->undo().recordUndo(*this, kind); -} - - -void Cursor::recordUndoInset(Inset const * in) const -{ - buffer()->undo().recordUndoInset(*this, in); -} - - -void Cursor::recordUndoFullBuffer() const -{ - buffer()->undo().recordUndoFullBuffer(*this); -} - - -void Cursor::recordUndoBufferParams() const -{ - buffer()->undo().recordUndoBufferParams(*this); -} - - -void Cursor::recordUndoSelection() const -{ - if (inMathed()) { - if (cap::multipleCellsSelected(*this)) - recordUndoInset(); - else - recordUndo(); - } else { - buffer()->undo().recordUndo(*this, - selBegin().pit(), selEnd().pit()); - } -} - - void Cursor::checkBufferStructure() { Buffer const * master = buffer()->masterBuffer(); @@ -2430,23 +2399,6 @@ void Cursor::checkBufferStructure() } -bool Cursor::confirmDeletion(bool const before) const -{ - if (!selection()) { - if (Inset const * inset = before ? prevInset() : nextInset()) - return inset->confirmDeletion(); - } else { - DocIterator dit = selectionBegin(); - CursorSlice const end = selectionEnd().top(); - for (; dit.top() < end; dit.top().forwardPos()) - if (Inset const * inset = dit.nextInset()) - if (inset->confirmDeletion()) - return true; - } - return false; -} - - void Cursor::moveToClosestEdge(int const x, bool const edit) { if (Inset const * inset = nextInset()) { diff --git a/src/Cursor.h b/src/Cursor.h index 4c9d41d0cf..6c5e5e6783 100644 --- a/src/Cursor.h +++ b/src/Cursor.h @@ -72,7 +72,6 @@ class Row; // these should go class InsetMathUnknown; -class Encoding; /** * This class describes the position of a cursor within a document, @@ -93,7 +92,136 @@ public: friend std::ostream & operator<<(std::ostream & os, CursorData const & cur); friend LyXErr & operator<<(LyXErr & os, CursorData const & cur); + /// reset cursor bottom to the beginning of the top inset + // (sort of 'chroot' environment...) + void reset(); + /// sets cursor part + /// this (intentionally) does neither touch anchor nor selection status + void setCursor(DocIterator const & it); + /// set the cursor to dit normalised against the anchor, and set selection. + void setCursorSelectionTo(DocIterator dit); + /// sets the cursor to the normalized selection anchor + void setCursorToAnchor(); + + // + // selection + // + /// selection active? + bool selection() const { return selection_; } + /// set selection; this is lower level than (set|clear)Selection + void selection(bool sel) { selection_ = sel; } + /// do we have a multicell selection? + bool selIsMultiCell() const + { return selection_ && selBegin().idx() != selEnd().idx(); } + /// do we have a multiline selection? + bool selIsMultiLine() const + { return selection_ && selBegin().pit() != selEnd().pit(); } + /// + void setWordSelection(bool set) { word_selection_ = set; } + /// + bool wordSelection() { return word_selection_; } + /// did we place the anchor? + bool mark() const { return mark_; } + /// did we place the anchor? + void setMark(bool mark) { mark_ = mark; } + /// + void setSelection(); + /// set selection at given position + void setSelection(DocIterator const & where, int n); + /// + void clearSelection(); + + /// access to normalized selection anchor + CursorSlice normalAnchor() const; + /// access to real selection anchor + DocIterator const & realAnchor() const { return anchor_; } + DocIterator & realAnchor() { return anchor_; } + /// sets anchor to cursor position + void resetAnchor(); + /// access to owning BufferView + + /// access start of selection + CursorSlice selBegin() const; + /// access end of selection + CursorSlice selEnd() const; + /// access start of selection + DocIterator selectionBegin() const; + /// access end of selection + DocIterator selectionEnd() const; + + /// + docstring selectionAsString(bool with_label) const; + /// get some interesting description of top position + void info(odocstream & os, bool devel_mode) const; + /// + docstring currentState(bool devel_mode) const; + + /// auto-correct mode + bool autocorrect() const { return autocorrect_; } + /// auto-correct mode + bool & autocorrect() { return autocorrect_; } + + /// fix cursor in circumstances that should never happen. + /// \retval true if a fix occurred. + bool fixIfBroken(); + /// Repopulate the slices insets from bottom to top. Useful + /// for stable iterators or Undo data. + void sanitize(); + /// + bool isInside(Inset const *) const; + /// make sure we are outside of given inset + void leaveInset(Inset const & inset); + + /// + bool textUndo(); + /// + bool textRedo(); + + /// makes sure the next operation will be stored + void finishUndo() const; + /// open a new group of undo operations. Groups can be nested. + void beginUndoGroup() const; + /// end the current undo group + void endUndoGroup() const; + + /// The general case: prepare undo for an arbitrary range. + void recordUndo(pit_type from, pit_type to) const; + /// Convenience: prepare undo for the range between 'from' and cursor. + void recordUndo(pit_type from) const; + /// Convenience: prepare undo for the single paragraph or cell + /// containing the cursor + void recordUndo(UndoKind kind = ATOMIC_UNDO) const; + /// Convenience: prepare undo for the inset containing the cursor + void recordUndoInset(Inset const * inset = 0) const; + /// Convenience: prepare undo for the whole buffer + void recordUndoFullBuffer() const; + /// Convenience: prepare undo for buffer parameters + void recordUndoBufferParams() const; + /// Convenience: prepare undo for the selected paragraphs or cells + void recordUndoSelection() const; + + /// hook for text input to maintain the "new born word" + void markNewWordPosition(); + /// The position of the new born word + /// As the user is entering a word without leaving it + /// the result is not empty. When not in text mode + /// and after leaving the word the result is empty. + DocIterator newWord() const { return new_word_; } + + /// are we in math mode (2), text mode (1) or unsure (0)? + int currentMode(); + + /// Return true if the next or previous inset has confirmDeletion depending + /// on the boolean before. If there is a selection, return true if at least + /// one inset in the selection has confirmDeletion. + bool confirmDeletion(bool before = false) const; + protected: + /// validate the "new born word" position + void checkNewWordPosition(); + /// clear the "new born word" position + void clearNewWordPosition(); + /// the anchor position DocIterator anchor_; /// do we have a selection? @@ -112,13 +240,13 @@ public: protected: + /// the start of the new born word + DocIterator new_word_; // // math specific stuff that could be promoted to "global" later // /// do we allow autocorrection bool autocorrect_; - /// are we entering a macro name? - bool macromode_; }; @@ -129,12 +257,6 @@ public: /// create the cursor of a BufferView explicit Cursor(BufferView & bv); - /// returns true if we made a decision - bool getStatus(FuncRequest const & cmd, FuncStatus & flag) const; - /// dispatch from innermost inset upwards - void dispatch(FuncRequest const & cmd); - /// get the resut of the last dispatch - DispatchResult const & result() const; /// add a new cursor slice void push(Inset & inset); /// add a new cursor slice, place cursor at front (move backwards) @@ -145,56 +267,23 @@ public: bool popBackward(); /// pop one slice off the cursor stack and go forward bool popForward(); - /// make sure we are outside of given inset - void leaveInset(Inset const & inset); /// set the cursor data void setCursorData(CursorData const & data); - /// sets cursor part - /// this (intentionally) does neither touch anchor nor selection status - void setCursor(DocIterator const & it); - /// set the cursor to dit normalised against the anchor, and set selection. - void setCursorSelectionTo(DocIterator dit); - /// sets the cursor to the normalized selection anchor - void setCursorToAnchor(); + + /// returns true if we made a decision + bool getStatus(FuncRequest const & cmd, FuncStatus & flag) const; + /// dispatch from innermost inset upwards + void dispatch(FuncRequest const & cmd); + /// display a message + void message(docstring const & msg) const; + /// display an error message + void errorMessage(docstring const & msg) const; + /// get the resut of the last dispatch + DispatchResult const & result() const; /// void setCurrentFont(); - // - // selection - // - /// selection active? - bool selection() const { return selection_; } - /// set selection; this is lower level than (set|clear)Selection - void selection(bool sel) { selection_ = sel; } - /// do we have a multicell selection? - bool selIsMultiCell() const - { return selection_ && selBegin().idx() != selEnd().idx(); } - /// do we have a multiline selection? - bool selIsMultiLine() const - { return selection_ && selBegin().pit() != selEnd().pit(); } - /// - void setWordSelection(bool set) { word_selection_ = set; } - /// - bool wordSelection() { return word_selection_; } - /// did we place the anchor? - bool mark() const { return mark_; } - /// did we place the anchor? - void setMark(bool mark) { mark_ = mark; } - /// - void setSelection(); - /// set selection at given position - void setSelection(DocIterator const & where, int n); - /// - void clearSelection(); - /// access start of selection - CursorSlice selBegin() const; - /// access end of selection - CursorSlice selEnd() const; - /// access start of selection - DocIterator selectionBegin() const; - /// access end of selection - DocIterator selectionEnd() const; /** * Update the selection status and save permanent * selection if needed. @@ -202,19 +291,6 @@ public: * @return whether the selection status has changed */ bool selHandle(bool selecting); - /// - docstring selectionAsString(bool with_label) const; - /// - docstring currentState(bool devel_mode) const; - - /// auto-correct mode - bool autocorrect() const { return autocorrect_; } - /// auto-correct mode - bool & autocorrect() { return autocorrect_; } - /// are we entering a macro name? - bool macromode() const { return macromode_; } - /// are we entering a macro name? - bool & macromode() { return macromode_; } /// returns x,y position void getPos(int & x, int & y) const; @@ -265,12 +341,28 @@ public: /// Should interpretation of the arrow keys be reversed? bool reverseDirectionNeeded() const; - /// insert an inset - void insert(Inset *); + /// + /// Insertion (mathed and texted) + /// /// insert a single char void insert(char_type c); /// insert a string void insert(docstring const & str); + /// insert an inset + void insert(Inset *); + /// + /// Insertion (mathed only) + /// + /// insert a math atom + void insert(MathAtom const &); + /// insert a string of atoms + void insert(MathData const &); + /// Like insert, but moves the selection inside the inset if possible + void niceInsert(MathAtom const & at); + /// return the number of inserted array items + /// FIXME: document properly + int niceInsert(docstring const & str, Parse::flags f = Parse::NORMAL, + bool enter = true); /// FIXME: rename to something sensible showing difference to x_target() /// in pixels from left of screen, set to current position if unset @@ -288,24 +380,11 @@ public: /// distance between actual and targeted position during last up/down in text int textTargetOffset() const; - /// access to normalized selection anchor - CursorSlice normalAnchor() const; - /// access to real selection anchor - DocIterator const & realAnchor() const { return anchor_; } - DocIterator & realAnchor() { return anchor_; } - /// sets anchor to cursor position - void resetAnchor(); - /// access to owning BufferView BufferView & bv() const; - /// get some interesting description of top position - void info(odocstream & os, bool devel_mode) const; - /// are we in math mode (2), text mode (1) or unsure (0)? - int currentMode(); /// reset cursor bottom to the beginning of the top inset // (sort of 'chroot' environment...) void reset(); - /// for spellchecking - void replaceWord(std::string const & replacestring); + /** * the event was not (yet) dispatched. * @@ -337,72 +416,23 @@ public: * Not using noScreenUpdate() should never be wrong. */ void noScreenUpdate() const; - /// fix cursor in circumstances that should never happen. - /// \retval true if a fix occurred. - bool fixIfBroken(); + /// Repopulate the slices insets from bottom to top. Useful /// for stable iterators or Undo data. void sanitize(); - /// - bool textUndo(); - /// - bool textRedo(); - - /// makes sure the next operation will be stored - void finishUndo() const; - - /// open a new group of undo operations. Groups can be nested. - void beginUndoGroup() const; - - /// end the current undo group - void endUndoGroup() const; - - /// The general case: prepare undo for an arbitrary range. - void recordUndo(pit_type from, pit_type to) const; - - /// Convenience: prepare undo for the range between 'from' and cursor. - void recordUndo(pit_type from) const; - - /// Convenience: prepare undo for the single paragraph or cell - /// containing the cursor - void recordUndo(UndoKind kind = ATOMIC_UNDO) const; - - /// Convenience: prepare undo for the inset containing the cursor - void recordUndoInset(Inset const * inset = 0) const; - - /// Convenience: prepare undo for the whole buffer - void recordUndoFullBuffer() const; - - /// Convenience: prepare undo for buffer parameters - void recordUndoBufferParams() const; - - /// Convenience: prepare undo for the selected paragraphs or cells - void recordUndoSelection() const; - /// void checkBufferStructure(); - /// hook for text input to maintain the "new born word" - void markNewWordPosition(); - - /// The position of the new born word - /// As the user is entering a word without leaving it - /// the result is not empty. When not in text mode - /// and after leaving the word the result is empty. - DocIterator newWord() const { return new_word_; } - - /// Return true if the next or previous inset has confirmDeletion depending - /// on the boolean before. If there is a selection, return true if at least - /// one inset in the selection has confirmDeletion. - bool confirmDeletion(bool before = false) const; - /// Determine if x falls to the left or to the side of the middle of the /// inset, and advance the cursor to match this position. If edit is true, /// keep the cursor in front of the inset if it matter for dialogs. /// Note: it does not handle RTL text yet, and is only used in math for now. void moveToClosestEdge(int x, bool edit = false); + /// whether the cursor is either at the first or last row + bool atFirstOrLastRow(bool up); + public: //private: @@ -411,12 +441,6 @@ public: /// void saveBeforeDispatchPosXY(); -private: - /// validate the "new born word" position - void checkNewWordPosition(); - /// clear the "new born word" position - void clearNewWordPosition(); - private: /// BufferView * bv_; @@ -437,8 +461,6 @@ private: int x_target_; /// if a x_target cannot be hit exactly in a text, put the difference here int textTargetOffset_; - /// the start of the new born word - DocIterator new_word_; /// position before dispatch started DocIterator beforeDispatchCursor_; /// cursor screen coordinates before dispatch started @@ -454,10 +476,6 @@ private: /////////////////////////////////////////////////////////////////// public: - /// - void insert(MathAtom const &); - /// - void insert(MathData const &); /// return false for empty math insets /// Use force to skip the confirmDeletion check. bool erase(bool force = false); @@ -469,8 +487,6 @@ public: /// move the cursor up by sending an internal LFUN_DOWN, /// return true if fullscreen update is needed bool down(); - /// whether the cursor is either at the first or last row - bool atFirstOrLastRow(bool up); /// move up/down in a text inset, called for LFUN_UP/DOWN, /// return true if successful, updateNeeded set to true if fullscreen /// update is needed, otherwise it's not touched @@ -478,10 +494,6 @@ public: /// move up/down in math or any non text inset, call for LFUN_UP/DOWN /// return true if successful bool upDownInMath(bool up); - /// - InsetMath & nextMath(); - /// - InsetMath & prevMath(); /// move forward in math. word: whether to skip a whole "word" (insets with /// the same mathclass) bool mathForward(bool word); @@ -491,18 +503,9 @@ public: void plainErase(); /// void plainInsert(MathAtom const & at); - /// - void niceInsert(MathAtom const & at); - /// return the number of inserted array items - int niceInsert(docstring const & str, Parse::flags f = Parse::NORMAL, - bool enter = true); - /// in pixels from top of screen - void setScreenPos(int x, int y); - /// current offset in the top cell - - /// interpret name a name of a macro. Returns true if - /// something got inserted. + /// interpret name of a macro. Returns true if something got + /// inserted. bool macroModeClose(); /// are we currently typing the name of a macro? bool inMacroMode() const; @@ -510,42 +513,25 @@ public: InsetMathUnknown * activeMacro(); /// get access to the macro we are currently typing InsetMathUnknown const * activeMacro() const; + /// the name of the macro we are currently inputting + docstring macroName(); + /// replace selected stuff with at, placing the former // selection in given cell of atom void handleNest(MathAtom const & at, int cell = 0); - /// - bool isInside(Inset const *) const; /// make sure cursor position is valid /// FIXME: It does a subset of fixIfBroken. Maybe merge them? void normalize(); - /// mark current cursor trace for redraw - void touch(); - /// hack for reveal codes - void markInsert(); - void markErase(); /// injects content of a cell into parent void pullArg(); /// split font inset etc void handleFont(std::string const & font); - /// display a message - void message(docstring const & msg) const; - /// display an error message - void errorMessage(docstring const & msg) const; - /// - docstring getPossibleLabel() const; - - /// the name of the macro we are currently inputting - docstring macroName(); - /// where in the curent cell does the macro name start? - int macroNamePos(); /// can we enter the inset? bool openable(MathAtom const &) const; - /// - Encoding const * getEncoding() const; /// font at cursor position Font getFont() const; }; diff --git a/src/CutAndPaste.cpp b/src/CutAndPaste.cpp index daa647591e..6d9bf101f4 100644 --- a/src/CutAndPaste.cpp +++ b/src/CutAndPaste.cpp @@ -690,7 +690,7 @@ docstring grabAndEraseSelection(Cursor & cur) } -bool reduceSelectionToOneCell(Cursor & cur) +bool reduceSelectionToOneCell(CursorData & cur) { if (!cur.selection() || !cur.inMathed()) return false; @@ -712,7 +712,7 @@ bool reduceSelectionToOneCell(Cursor & cur) } -bool multipleCellsSelected(Cursor const & cur) +bool multipleCellsSelected(CursorData const & cur) { if (!cur.selection() || !cur.inMathed()) return false; @@ -969,7 +969,7 @@ void copyInset(Cursor const & cur, Inset * inset, docstring const & plaintext) namespace { -void copySelectionToStack(Cursor const & cur, CutStack & cutstack) +void copySelectionToStack(CursorData const & cur, CutStack & cutstack) { // this doesn't make sense, if there is no selection if (!cur.selection()) @@ -1369,7 +1369,7 @@ void selClearOrDel(Cursor & cur) } -docstring grabSelection(Cursor const & cur) +docstring grabSelection(CursorData const & cur) { if (!cur.selection()) return docstring(); diff --git a/src/CutAndPaste.h b/src/CutAndPaste.h index 43a89c33d0..66df6b5904 100644 --- a/src/CutAndPaste.h +++ b/src/CutAndPaste.h @@ -127,7 +127,7 @@ void switchBetweenClasses(DocumentClassConstPtr c1, /// Get the current selection as a string. Does not change the selection. /// Does only work if the whole selection is in mathed. -docstring grabSelection(Cursor const & cur); +docstring grabSelection(CursorData const & cur); /// Erase the current selection. /// Does not handle undo. Does only work if the whole selection is in mathed. /// Calls saveSelection. @@ -136,9 +136,9 @@ void eraseSelection(Cursor & cur); /// cells, the cursor is moved the end of the current cell and the anchor to the /// start. If the selection is inside only one cell, nothing is done. Return /// true if the selection now does not span multiple cells anymore. -bool reduceSelectionToOneCell(Cursor & cur); +bool reduceSelectionToOneCell(CursorData & cur); /// Returns true if multiple cells are selected in mathed. -bool multipleCellsSelected(Cursor const & cur); +bool multipleCellsSelected(CursorData const & cur); /// Erase the selection and return it as a string. /// Does not handle undo. Does only work if the whole selection is in mathed. docstring grabAndEraseSelection(Cursor & cur); diff --git a/src/DocIterator.cpp b/src/DocIterator.cpp index 38f2393224..58b91dff36 100644 --- a/src/DocIterator.cpp +++ b/src/DocIterator.cpp @@ -15,9 +15,12 @@ #include "DocIterator.h" #include "Buffer.h" +#include "BufferParams.h" +#include "Encoding.h" +#include "Font.h" #include "InsetList.h" +#include "Language.h" #include "Paragraph.h" -#include "LyXRC.h" #include "Text.h" #include "mathed/MathData.h" @@ -156,6 +159,18 @@ Inset * DocIterator::realInset() const } +InsetMath & DocIterator::nextMath() +{ + return *nextAtom().nucleus(); +} + + +InsetMath & DocIterator::prevMath() +{ + return *prevAtom().nucleus(); +} + + MathAtom & DocIterator::prevAtom() const { LASSERT(!empty(), /**/); @@ -688,6 +703,28 @@ void DocIterator::append(DocIterator::idx_type idx, pos_type pos) } +docstring DocIterator::getPossibleLabel() const +{ + return inMathed() ? from_ascii("eq:") : text()->getPossibleLabel(*this); +} + + +Encoding const * DocIterator::getEncoding() const +{ + if (empty()) + return 0; + BufferParams const & bp = buffer()->params(); + if (bp.useNonTeXFonts) + return encodings.fromLyXName("utf8-plain"); + + CursorSlice const & sl = innerTextSlice(); + Text const & text = *sl.text(); + Font font = text.getPar(sl.pit()).getFont(bp, sl.pos(), + text.outerFont(sl.pit())); + return font.language()->encoding(); +} + + ostream & operator<<(ostream & os, DocIterator const & dit) { for (size_t i = 0, n = dit.depth(); i != n; ++i) diff --git a/src/DocIterator.h b/src/DocIterator.h index 4aff05cd0b..9582ea30f9 100644 --- a/src/DocIterator.h +++ b/src/DocIterator.h @@ -20,12 +20,13 @@ namespace lyx { class DocIterator; +class Encoding; +class FontSpan; +class InsetIterator; class LyXErr; class MathAtom; class Paragraph; class Text; -class InsetIterator; -class FontSpan; DocIterator doc_iterator_begin(Buffer const * buf, Inset const * inset = 0); DocIterator doc_iterator_end(Buffer const * buf, Inset const * inset = 0); @@ -149,6 +150,10 @@ public: // /// return the mathed cell this cursor is in MathData & cell() const; + /// + InsetMath & nextMath(); + /// + InsetMath & prevMath(); /// the mathatom left of the cursor MathAtom & prevAtom() const; /// the mathatom right of the cursor @@ -257,6 +262,11 @@ public: /// push one CursorSlice on top and set its index and position void append(idx_type idx, pos_type pos); + /// + docstring getPossibleLabel() const; + + /// + Encoding const * getEncoding() const; private: friend class InsetIterator; friend DocIterator doc_iterator_begin(Buffer const * buf, Inset const * inset); diff --git a/src/Text.cpp b/src/Text.cpp index e1c37faf3a..84f7857678 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -1896,7 +1896,7 @@ bool Text::read(Lexer & lex, // Returns the current font and depth as a message. -docstring Text::currentState(Cursor const & cur, bool devel_mode) const +docstring Text::currentState(CursorData const & cur, bool devel_mode) const { LBUFERR(this == cur.text()); Buffer & buf = *cur.buffer(); @@ -1973,7 +1973,7 @@ docstring Text::currentState(Cursor const & cur, bool devel_mode) const } -docstring Text::getPossibleLabel(Cursor const & cur) const +docstring Text::getPossibleLabel(DocIterator const & cur) const { pit_type pit = cur.pit(); diff --git a/src/Text.h b/src/Text.h index 8621e883a7..4fc86ff72a 100644 --- a/src/Text.h +++ b/src/Text.h @@ -24,6 +24,7 @@ class BufferParams; class BufferView; class CompletionList; class Cursor; +class CursorData; class CursorSlice; class DocIterator; class ErrorList; @@ -158,7 +159,7 @@ public: Paragraph & getPar(pit_type pit) { return pars_[pit]; } // Returns the current font and depth as a message. // When \param devel_mode is true, add more precise information - docstring currentState(Cursor const & cur, bool devel_mode) const; + docstring currentState(CursorData const & cur, bool devel_mode) const; /** Find the word under \c from in the relative location * defined by \c word_location. @@ -280,7 +281,7 @@ public: double spacing(Paragraph const & par) const; /// make a suggestion for a label /// FIXME: replace Cursor with DocIterator. - docstring getPossibleLabel(Cursor const & cur) const; + docstring getPossibleLabel(DocIterator const & cur) const; /// is this paragraph right-to-left? bool isRTL(Paragraph const & par) const; diff --git a/src/insets/InsetGraphics.cpp b/src/insets/InsetGraphics.cpp index 94182a7326..9c63adeb13 100644 --- a/src/insets/InsetGraphics.cpp +++ b/src/insets/InsetGraphics.cpp @@ -1159,7 +1159,7 @@ void unifyGraphicsGroups(Buffer & b, string const & argument) InsetGraphics & ins = static_cast(*it); InsetGraphicsParams inspar = ins.getParams(); if (params.groupId == inspar.groupId) { - b.undo().recordUndo(CursorData(it)); + CursorData(it).recordUndo(); params.filename = inspar.filename; ins.setParams(params); } diff --git a/src/insets/InsetLabel.cpp b/src/insets/InsetLabel.cpp index 789a774ac6..b9e8f10383 100644 --- a/src/insets/InsetLabel.cpp +++ b/src/insets/InsetLabel.cpp @@ -115,7 +115,7 @@ void InsetLabel::updateReferences(docstring const & old_label, Buffer::References::const_iterator end = refs.end(); for (; it != end; ++it) { ugh.resetBuffer(it->second.buffer()); - it->second.buffer()->undo().recordUndo(CursorData(it->second)); + CursorData(it->second).recordUndo(); if (it->first->lyxCode() == MATH_REF_CODE) { InsetMathRef * mi = it->first->asInsetMath()->asRefInset(); mi->changeTarget(new_label); diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp index 78175f3f70..892b9df44b 100644 --- a/src/mathed/InsetMathHull.cpp +++ b/src/mathed/InsetMathHull.cpp @@ -2243,42 +2243,6 @@ void InsetMathHull::edit(Cursor & cur, bool front, EntryDirection entry_from) } -void InsetMathHull::revealCodes(Cursor & cur) const -{ - if (!cur.inMathed()) - return; - odocstringstream os; - cur.info(os, false); - cur.message(os.str()); -/* - // write something to the minibuffer - // translate to latex - cur.markInsert(bv); - ostringstream os; - write(os); - string str = os.str(); - cur.markErase(bv); - string::size_type pos = 0; - string res; - for (string::iterator it = str.begin(); it != str.end(); ++it) { - if (*it == '\n') - res += ' '; - else if (*it == '\0') { - res += " -X- "; - pos = it - str.begin(); - } - else - res += *it; - } - if (pos > 30) - res = res.substr(pos - 30); - if (res.size() > 60) - res = res.substr(0, 60); - cur.message(res); -*/ -} - - ///////////////////////////////////////////////////////////////////// diff --git a/src/mathed/InsetMathHull.h b/src/mathed/InsetMathHull.h index 183b851ba5..7f1b916702 100644 --- a/src/mathed/InsetMathHull.h +++ b/src/mathed/InsetMathHull.h @@ -284,8 +284,6 @@ public: /// virtual void mutateToText(); /// - virtual void revealCodes(Cursor & cur) const; - /// bool editable() const { return true; } /// void edit(Cursor & cur, bool front, diff --git a/src/mathed/InsetMathNest.cpp b/src/mathed/InsetMathNest.cpp index 8d7c110a4a..803c946551 100644 --- a/src/mathed/InsetMathNest.cpp +++ b/src/mathed/InsetMathNest.cpp @@ -896,7 +896,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd) int y = 0; istringstream is(to_utf8(cmd.argument())); is >> x >> y; - cur.setScreenPos(x, y); + cur.setTargetX(x); break; } diff --git a/src/mathed/MathData.cpp b/src/mathed/MathData.cpp index beb1299b9a..d242a86f72 100644 --- a/src/mathed/MathData.cpp +++ b/src/mathed/MathData.cpp @@ -212,11 +212,6 @@ bool MathData::contains(MathData const & ar) const } -void MathData::touch() const -{ -} - - bool MathData::addToMathRow(MathRow & mrow, MetricsInfo & mi) const { bool has_contents = false; diff --git a/src/mathed/MathData.h b/src/mathed/MathData.h index 2f6ab22acd..f8c35ccab3 100644 --- a/src/mathed/MathData.h +++ b/src/mathed/MathData.h @@ -137,8 +137,6 @@ public: void metricsT(TextMetricsInfo const & mi, Dimension & dim) const; /// redraw cell using cache metrics information void drawT(TextPainter & pi, int x, int y) const; - /// mark cell for re-drawing - void touch() const; /// approximate the math class of the data MathClass mathClass() const; -- 2.39.2