From ba0a69bcd964c1962ddfb0ac01f92127da26171c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andr=C3=A9=20P=C3=B6nitz?= Date: Sun, 18 Apr 2004 07:32:34 +0000 Subject: [PATCH] partial fix for cut and paste git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8658 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/CutAndPaste.C | 683 ++++++++++++++++++++++++++++------------------ src/CutAndPaste.h | 19 +- src/cursor.C | 168 +----------- src/cursor.h | 17 -- src/paragraph.C | 3 +- src/text3.C | 5 +- 6 files changed, 449 insertions(+), 446 deletions(-) diff --git a/src/CutAndPaste.C b/src/CutAndPaste.C index 0cd4a1a334..2ed08ebf0a 100644 --- a/src/CutAndPaste.C +++ b/src/CutAndPaste.C @@ -19,8 +19,12 @@ #include "bufferparams.h" #include "BufferView.h" #include "cursor.h" +#include "debug.h" #include "errorlist.h" +#include "funcrequest.h" #include "gettext.h" +#include "lfuns.h" +#include "lyxrc.h" #include "lyxtext.h" #include "lyxtextclasslist.h" #include "paragraph.h" @@ -32,6 +36,10 @@ #include "insets/insettabular.h" +#include "mathed/math_data.h" +#include "mathed/math_inset.h" +#include "mathed/math_support.h" + #include "support/lstrings.h" #include @@ -42,6 +50,7 @@ using lyx::textclass_type; using lyx::support::bformat; +using std::endl; using std::for_each; using std::make_pair; using std::pair; @@ -55,7 +64,7 @@ typedef std::pair PitPosPair; typedef limited_stack > CutStack; -CutStack cuts(10); +CutStack theCuts(10); struct resetOwnerAndChanges : public std::unary_function { void operator()(Paragraph & p) const { @@ -64,83 +73,153 @@ struct resetOwnerAndChanges : public std::unary_function { } }; -} // namespace anon +void region(CursorSlice const & i1, CursorSlice const & i2, + InsetBase::row_type & r1, InsetBase::row_type & r2, + InsetBase::col_type & c1, InsetBase::col_type & c2) +{ + InsetBase & p = i1.inset(); + c1 = p.col(i1.idx()); + c2 = p.col(i2.idx()); + if (c1 > c2) + std::swap(c1, c2); + r1 = p.row(i1.idx()); + r2 = p.row(i2.idx()); + if (r1 > r2) + std::swap(r1, r2); +} -namespace lyx { -namespace cap { +bool checkPastePossible(int index) +{ + return size_t(index) < theCuts.size() && !theCuts[index].first.empty(); +} -int SwitchLayoutsBetweenClasses(textclass_type c1, textclass_type c2, - ParagraphList & pars, ErrorList & errorlist) + +pair +pasteSelectionHelper(Buffer const & buffer, ParagraphList & pars, + par_type pit, int pos, + textclass_type tc, size_t cut_index, ErrorList & errorlist) { - BOOST_ASSERT(!pars.empty()); - int ret = 0; - if (c1 == c2) - return ret; + if (!checkPastePossible(cut_index)) + return make_pair(PitPosPair(pit, pos), pit); - LyXTextClass const & tclass1 = textclasslist[c1]; - LyXTextClass const & tclass2 = textclasslist[c2]; + BOOST_ASSERT (pos <= pars[pit].size()); - InsetText in; - std::swap(in.paragraphs(), pars); + // Make a copy of the CaP paragraphs. + ParagraphList insertion = theCuts[cut_index].first; + textclass_type const textclass = theCuts[cut_index].second; - ParIterator end = par_iterator_end(in); - for (ParIterator it = par_iterator_begin(in); it != end; ++it) { - string const name = it->layout()->name(); - bool hasLayout = tclass2.hasLayout(name); + // Now remove all out of the pars which is NOT allowed in the + // new environment and set also another font if that is required. - if (hasLayout) - it->layout(tclass2[name]); - else - it->layout(tclass2.defaultLayout()); + // Make sure there is no class difference. + lyx::cap::SwitchLayoutsBetweenClasses(textclass, tc, insertion, + errorlist); - if (!hasLayout && name != tclass1.defaultLayoutName()) { - ++ret; - string const s = bformat( - _("Layout had to be changed from\n%1$s to %2$s\n" - "because of class conversion from\n%3$s to %4$s"), - name, it->layout()->name(), tclass1.name(), tclass2.name()); - // To warn the user that something had to be done. - errorlist.push_back(ErrorItem("Changed Layout", s, - it->id(), 0, - it->size())); + ParagraphList::iterator tmpbuf = insertion.begin(); + int depth_delta = pars[pit].params().depth() - tmpbuf->params().depth(); + + Paragraph::depth_type max_depth = pars[pit].getMaxDepthAfter(); + + for (; tmpbuf != insertion.end(); ++tmpbuf) { + // If we have a negative jump so that the depth would + // go below 0 depth then we have to redo the delta to + // this new max depth level so that subsequent + // paragraphs are aligned correctly to this paragraph + // at level 0. + if (int(tmpbuf->params().depth()) + depth_delta < 0) + depth_delta = 0; + + // Set the right depth so that we are not too deep or shallow. + tmpbuf->params().depth(tmpbuf->params().depth() + depth_delta); + if (tmpbuf->params().depth() > max_depth) + tmpbuf->params().depth(max_depth); + + // Only set this from the 2nd on as the 2nd depends + // for maxDepth still on pit. + if (tmpbuf != insertion.begin()) + max_depth = tmpbuf->getMaxDepthAfter(); + + // Set the inset owner of this paragraph. + tmpbuf->setInsetOwner(pars[pit].inInset()); + for (pos_type i = 0; i < tmpbuf->size(); ++i) { + if (tmpbuf->getChar(i) == Paragraph::META_INSET) { + if (!pars[pit].insetAllowed(tmpbuf->getInset(i)->lyxCode())) + tmpbuf->erase(i--); + } } } - std::swap(in.paragraphs(), pars); - return ret; -} + // Make the buf exactly the same layout as the cursor paragraph. + insertion.begin()->makeSameLayout(pars[pit]); -std::vector const availableSelections(Buffer const & buffer) -{ - vector selList; + // Prepare the paragraphs and insets for insertion. + // A couple of insets store buffer references so need updating. + InsetText in; + std::swap(in.paragraphs(), insertion); - CutStack::const_iterator cit = cuts.begin(); - CutStack::const_iterator end = cuts.end(); - for (; cit != end; ++cit) { - // we do not use cit-> here because gcc 2.9x does not - // like it (JMarc) - ParagraphList const & pars = (*cit).first; - string asciiSel; - ParagraphList::const_iterator pit = pars.begin(); - ParagraphList::const_iterator pend = pars.end(); - for (; pit != pend; ++pit) { - asciiSel += pit->asString(buffer, false); - if (asciiSel.size() > 25) { - asciiSel.replace(22, string::npos, "..."); + ParIterator fpit = par_iterator_begin(in); + ParIterator fend = par_iterator_end(in); + + for (; fpit != fend; ++fpit) { + InsetList::iterator lit = fpit->insetlist.begin(); + InsetList::iterator eit = fpit->insetlist.end(); + + for (; lit != eit; ++lit) { + switch (lit->inset->lyxCode()) { + case InsetOld::TABULAR_CODE: { + InsetTabular * it = static_cast(lit->inset); + it->buffer(const_cast(&buffer)); break; } + + default: + break; // nothing + } } + } + std::swap(in.paragraphs(), insertion); - selList.push_back(asciiSel); + // Split the paragraph for inserting the buf if necessary. + bool did_split = false; + if (pars[pit].size() || pit + 1 == par_type(pars.size())) { + breakParagraphConservative(buffer.params(), pars, pit, pos); + did_split = true; } - return selList; + // Paste it! + pars.insert(pars.begin() + pit + 1, insertion.begin(), insertion.end()); + mergeParagraph(buffer.params(), pars, pit); + + par_type last_paste = pit + insertion.size() - 1; + + // Store the new cursor position. + pit = last_paste; + pos = pars[last_paste].size(); + + // Maybe some pasting. + if (did_split && last_paste + 1 != par_type(pars.size())) { + if (pars[last_paste + 1].hasSameLayout(pars[last_paste])) { + mergeParagraph(buffer.params(), pars, last_paste); + } else if (pars[last_paste + 1].empty()) { + pars[last_paste + 1].makeSameLayout(pars[last_paste]); + mergeParagraph(buffer.params(), pars, last_paste); + } else if (pars[last_paste].empty()) { + pars[last_paste].makeSameLayout(pars[last_paste + 1]); + mergeParagraph(buffer.params(), pars, last_paste); + } else { + pars[last_paste + 1].stripLeadingSpaces(); + ++last_paste; + } + } + + return make_pair(PitPosPair(pit, pos), last_paste + 1); } -PitPosPair eraseSelection(BufferParams const & params, ParagraphList & pars, +PitPosPair eraseSelectionHelper(BufferParams const & params, + ParagraphList & pars, par_type startpit, par_type endpit, int startpos, int endpos, bool doclear) { @@ -210,7 +289,7 @@ PitPosPair eraseSelection(BufferParams const & params, ParagraphList & pars, } -bool copySelection(ParagraphList & pars, +void copySelectionHelper(ParagraphList & pars, par_type startpit, par_type endpit, int start, int end, textclass_type tc) { @@ -230,226 +309,187 @@ bool copySelection(ParagraphList & pars, Paragraph & front = paragraphs.front(); front.erase(0, start); - cuts.push(make_pair(paragraphs, tc)); - - return true; + theCuts.push(make_pair(paragraphs, tc)); } -PitPosPair cutSelection(BufferParams const & params, ParagraphList & pars, - par_type startpit, par_type endpit, + +PitPosPair cutSelectionHelper(BufferParams const & params, + ParagraphList & pars, par_type startpit, par_type endpit, int startpos, int endpos, textclass_type tc, bool doclear) { - copySelection(pars, startpit, endpit, startpos, endpos, tc); - return eraseSelection(params, pars, startpit, endpit, startpos, - endpos, doclear); + copySelectionHelper(pars, startpit, endpit, startpos, endpos, tc); + return eraseSelectionHelper(params, pars, startpit, endpit, + startpos, endpos, doclear); } -pair -pasteSelection(Buffer const & buffer, ParagraphList & pars, - par_type pit, int pos, - textclass_type tc, size_t cut_index, ErrorList & errorlist) -{ - if (!checkPastePossible()) - return make_pair(PitPosPair(pit, pos), pit); - - BOOST_ASSERT (pos <= pars[pit].size()); - - // Make a copy of the CaP paragraphs. - ParagraphList insertion = cuts[cut_index].first; - textclass_type const textclass = cuts[cut_index].second; - - // Now remove all out of the pars which is NOT allowed in the - // new environment and set also another font if that is required. +} // namespace anon - // Make sure there is no class difference. - SwitchLayoutsBetweenClasses(textclass, tc, insertion, - errorlist); - ParagraphList::iterator tmpbuf = insertion.begin(); - int depth_delta = pars[pit].params().depth() - tmpbuf->params().depth(); - Paragraph::depth_type max_depth = pars[pit].getMaxDepthAfter(); - for (; tmpbuf != insertion.end(); ++tmpbuf) { - // If we have a negative jump so that the depth would - // go below 0 depth then we have to redo the delta to - // this new max depth level so that subsequent - // paragraphs are aligned correctly to this paragraph - // at level 0. - if (int(tmpbuf->params().depth()) + depth_delta < 0) - depth_delta = 0; +namespace lyx { +namespace cap { - // Set the right depth so that we are not too deep or shallow. - tmpbuf->params().depth(tmpbuf->params().depth() + depth_delta); - if (tmpbuf->params().depth() > max_depth) - tmpbuf->params().depth(max_depth); +string grabAndEraseSelection(LCursor & cur) +{ + if (!cur.selection()) + return string(); + string res = grabSelection(cur); + eraseSelection(cur); + cur.selection() = false; + return res; +} - // Only set this from the 2nd on as the 2nd depends - // for maxDepth still on pit. - if (tmpbuf != insertion.begin()) - max_depth = tmpbuf->getMaxDepthAfter(); - // Set the inset owner of this paragraph. - tmpbuf->setInsetOwner(pars[pit].inInset()); - for (pos_type i = 0; i < tmpbuf->size(); ++i) { - if (tmpbuf->getChar(i) == Paragraph::META_INSET) { - if (!pars[pit].insetAllowed(tmpbuf->getInset(i)->lyxCode())) - tmpbuf->erase(i--); - } - } - } +int SwitchLayoutsBetweenClasses(textclass_type c1, textclass_type c2, + ParagraphList & pars, ErrorList & errorlist) +{ + BOOST_ASSERT(!pars.empty()); + int ret = 0; + if (c1 == c2) + return ret; - // Make the buf exactly the same layout as the cursor paragraph. - insertion.begin()->makeSameLayout(pars[pit]); + LyXTextClass const & tclass1 = textclasslist[c1]; + LyXTextClass const & tclass2 = textclasslist[c2]; - // Prepare the paragraphs and insets for insertion. - // A couple of insets store buffer references so need updating. InsetText in; - std::swap(in.paragraphs(), insertion); - - ParIterator fpit = par_iterator_begin(in); - ParIterator fend = par_iterator_end(in); + std::swap(in.paragraphs(), pars); - for (; fpit != fend; ++fpit) { - InsetList::iterator lit = fpit->insetlist.begin(); - InsetList::iterator eit = fpit->insetlist.end(); + ParIterator end = par_iterator_end(in); + for (ParIterator it = par_iterator_begin(in); it != end; ++it) { + string const name = it->layout()->name(); + bool hasLayout = tclass2.hasLayout(name); - for (; lit != eit; ++lit) { - switch (lit->inset->lyxCode()) { - case InsetOld::TABULAR_CODE: { - InsetTabular * it = static_cast(lit->inset); - it->buffer(const_cast(&buffer)); - break; - } + if (hasLayout) + it->layout(tclass2[name]); + else + it->layout(tclass2.defaultLayout()); - default: - break; // nothing - } + if (!hasLayout && name != tclass1.defaultLayoutName()) { + ++ret; + string const s = bformat( + _("Layout had to be changed from\n%1$s to %2$s\n" + "because of class conversion from\n%3$s to %4$s"), + name, it->layout()->name(), tclass1.name(), tclass2.name()); + // To warn the user that something had to be done. + errorlist.push_back(ErrorItem("Changed Layout", s, + it->id(), 0, + it->size())); } } - std::swap(in.paragraphs(), insertion); - - // Split the paragraph for inserting the buf if necessary. - bool did_split = false; - if (pars[pit].size() || pit + 1 == par_type(pars.size())) { - breakParagraphConservative(buffer.params(), pars, pit, pos); - did_split = true; - } - - // Paste it! - pars.insert(pars.begin() + pit + 1, insertion.begin(), insertion.end()); - mergeParagraph(buffer.params(), pars, pit); + std::swap(in.paragraphs(), pars); + return ret; +} - par_type last_paste = pit + insertion.size() - 1; - // Store the new cursor position. - pit = last_paste; - pos = pars[last_paste].size(); +std::vector const availableSelections(Buffer const & buffer) +{ + vector selList; - // Maybe some pasting. - if (did_split && last_paste + 1 != par_type(pars.size())) { - if (pars[last_paste + 1].hasSameLayout(pars[last_paste])) { - mergeParagraph(buffer.params(), pars, last_paste); - } else if (pars[last_paste + 1].empty()) { - pars[last_paste + 1].makeSameLayout(pars[last_paste]); - mergeParagraph(buffer.params(), pars, last_paste); - } else if (pars[last_paste].empty()) { - pars[last_paste].makeSameLayout(pars[last_paste + 1]); - mergeParagraph(buffer.params(), pars, last_paste); - } else { - pars[last_paste + 1].stripLeadingSpaces(); - ++last_paste; + CutStack::const_iterator cit = theCuts.begin(); + CutStack::const_iterator end = theCuts.end(); + for (; cit != end; ++cit) { + // we do not use cit-> here because gcc 2.9x does not + // like it (JMarc) + ParagraphList const & pars = (*cit).first; + string asciiSel; + ParagraphList::const_iterator pit = pars.begin(); + ParagraphList::const_iterator pend = pars.end(); + for (; pit != pend; ++pit) { + asciiSel += pit->asString(buffer, false); + if (asciiSel.size() > 25) { + asciiSel.replace(22, string::npos, "..."); + break; + } } - } - - return make_pair(PitPosPair(pit, pos), last_paste + 1); -} + selList.push_back(asciiSel); + } -pair -pasteSelection(Buffer const & buffer, ParagraphList & pars, - par_type pit, int pos, textclass_type tc, ErrorList & errorlist) -{ - return pasteSelection(buffer, pars, pit, pos, tc, 0, errorlist); + return selList; } int nrOfParagraphs() { - return cuts.empty() ? 0 : cuts[0].first.size(); -} - - -bool checkPastePossible() -{ - return !cuts.empty() && !cuts[0].first.empty(); + return theCuts.empty() ? 0 : theCuts[0].first.size(); } void cutSelection(LCursor & cur, bool doclear, bool realcut) { - LyXText * text = cur.text(); - BOOST_ASSERT(text); - // Stuff what we got on the clipboard. Even if there is no selection. - - // There is a problem with having the stuffing here in that the - // larger the selection the slower LyX will get. This can be - // solved by running the line below only when the selection has - // finished. The solution used currently just works, to make it - // faster we need to be more clever and probably also have more - // calls to stuffClipboard. (Lgb) - cur.bv().stuffClipboard(cur.selectionAsString(true)); + if (cur.inTexted()) { + LyXText * text = cur.text(); + BOOST_ASSERT(text); + // Stuff what we got on the clipboard. Even if there is no selection. + + // There is a problem with having the stuffing here in that the + // larger the selection the slower LyX will get. This can be + // solved by running the line below only when the selection has + // finished. The solution used currently just works, to make it + // faster we need to be more clever and probably also have more + // calls to stuffClipboard. (Lgb) + cur.bv().stuffClipboard(cur.selectionAsString(true)); + + // This doesn't make sense, if there is no selection + if (!cur.selection()) + return; + + // OK, we have a selection. This is always between cur.selBegin() + // and cur.selEnd() + + // make sure that the depth behind the selection are restored, too + recordUndoSelection(cur); + par_type begpit = cur.selBegin().par(); + par_type endpit = cur.selEnd().par(); + + int endpos = cur.selEnd().pos(); + + BufferParams const & bp = cur.buffer().params(); + if (realcut) { + copySelectionHelper(text->paragraphs(), + begpit, endpit, + cur.selBegin().pos(), endpos, + bp.textclass); + } - // This doesn't make sense, if there is no selection - if (!cur.selection()) - return; + boost::tie(endpit, endpos) = + eraseSelectionHelper(bp, + text->paragraphs(), + begpit, endpit, + cur.selBegin().pos(), endpos, + doclear); + + // sometimes necessary + if (doclear) + text->paragraphs()[begpit].stripLeadingSpaces(); + + text->redoParagraphs(begpit, begpit + 1); + // cutSelection can invalidate the cursor so we need to set + // it anew. (Lgb) + // we prefer the end for when tracking changes + cur.pos() = endpos; + cur.par() = endpit; + + // need a valid cursor. (Lgb) + cur.clearSelection(); + text->updateCounters(); + } - // OK, we have a selection. This is always between cur.selBegin() - // and cur.selEnd() - - // make sure that the depth behind the selection are restored, too - recordUndoSelection(cur); - par_type begpit = cur.selBegin().par(); - par_type endpit = cur.selEnd().par(); - - int endpos = cur.selEnd().pos(); - - BufferParams const & bufparams = cur.buffer().params(); - boost::tie(endpit, endpos) = realcut ? - cutSelection(bufparams, - text->paragraphs(), - begpit, endpit, - cur.selBegin().pos(), endpos, - bufparams.textclass, - doclear) - : eraseSelection(bufparams, - text->paragraphs(), - begpit, endpit, - cur.selBegin().pos(), endpos, - doclear); - // sometimes necessary - if (doclear) - text->paragraphs()[begpit].stripLeadingSpaces(); - - text->redoParagraphs(begpit, begpit + 1); - // cutSelection can invalidate the cursor so we need to set - // it anew. (Lgb) - // we prefer the end for when tracking changes - cur.pos() = endpos; - cur.par() = endpit; - - // need a valid cursor. (Lgb) - cur.clearSelection(); - text->updateCounters(); + if (cur.inMathed()) { + lyxerr << "cutSelection in mathed" << endl; + LCursor tmp = cur; + copySelection(cur); + cur.selection() = false; + eraseSelection(tmp); + } } void copySelection(LCursor & cur) { - LyXText * text = cur.text(); - BOOST_ASSERT(text); // stuff the selection onto the X clipboard, from an explicit copy request cur.bv().stuffClipboard(cur.selectionAsString(true)); @@ -457,54 +497,85 @@ void copySelection(LCursor & cur) if (!cur.selection()) return; - // ok we have a selection. This is always between cur.selBegin() - // and sel_end cursor + if (cur.inTexted()) { + LyXText * text = cur.text(); + BOOST_ASSERT(text); + // ok we have a selection. This is always between cur.selBegin() + // and sel_end cursor + + // copy behind a space if there is one + ParagraphList & pars = text->paragraphs(); + pos_type pos = cur.selBegin().pos(); + par_type par = cur.selBegin().par(); + while (pos < pars[par].size() + && pars[par].isLineSeparator(pos) + && (par != cur.selEnd().par() || pos < cur.selEnd().pos())) + ++pos; + + copySelectionHelper(pars, par, cur.selEnd().par(), + pos, cur.selEnd().pos(), cur.buffer().params().textclass); + } + + if (cur.inMathed()) { + lyxerr << "copySelection in mathed" << endl; + ParagraphList pars; + pars.push_back(Paragraph()); + BufferParams const & bp = cur.buffer().params(); + pars.back().layout(bp.getLyXTextClass().defaultLayout()); + for_each(pars.begin(), pars.end(), resetOwnerAndChanges()); + pars.back().insert(0, grabSelection(cur), LyXFont()); + theCuts.push(make_pair(pars, bp.textclass)); + } +} - // copy behind a space if there is one - ParagraphList & pars = text->paragraphs(); - pos_type pos = cur.selBegin().pos(); - par_type par = cur.selBegin().par(); - while (pos < pars[par].size() - && pars[par].isLineSeparator(pos) - && (par != cur.selEnd().par() || pos < cur.selEnd().pos())) - ++pos; - copySelection(pars, par, cur.selEnd().par(), - pos, cur.selEnd().pos(), cur.buffer().params().textclass); +std::string getSelection(Buffer const & buf, size_t sel_index) +{ + return sel_index < theCuts.size() + ? theCuts[sel_index].first.back().asString(buf, false) + : string(); } void pasteSelection(LCursor & cur, size_t sel_index) { - LyXText * text = cur.text(); - BOOST_ASSERT(text); // this does not make sense, if there is nothing to paste - if (!checkPastePossible()) + lyxerr << "#### pasteSelection " << sel_index << endl; + if (!checkPastePossible(sel_index)) return; - recordUndo(cur); + if (cur.inTexted()) { + LyXText * text = cur.text(); + BOOST_ASSERT(text); - par_type endpit; - PitPosPair ppp; + recordUndo(cur); - ErrorList el; + par_type endpit; + PitPosPair ppp; - boost::tie(ppp, endpit) = - pasteSelection(cur.buffer(), - text->paragraphs(), - cur.par(), cur.pos(), - cur.buffer().params().textclass, - sel_index, el); - bufferErrors(cur.buffer(), el); - cur.bv().showErrorList(_("Paste")); + ErrorList el; - text->redoParagraphs(cur.par(), endpit); + boost::tie(ppp, endpit) = + pasteSelectionHelper(cur.buffer(), + text->paragraphs(), + cur.par(), cur.pos(), + cur.buffer().params().textclass, + sel_index, el); + bufferErrors(cur.buffer(), el); + cur.bv().showErrorList(_("Paste")); - cur.clearSelection(); - cur.resetAnchor(); - text->setCursor(cur, ppp.first, ppp.second); - cur.setSelection(); - text->updateCounters(); + text->redoParagraphs(cur.par(), endpit); + + cur.clearSelection(); + cur.resetAnchor(); + text->setCursor(cur, ppp.first, ppp.second); + cur.setSelection(); + text->updateCounters(); + } + + if (cur.inMathed()) { + lyxerr << "### should be handled in MathNest/GridInset" << endl; + } } @@ -566,5 +637,93 @@ void replaceWord(LCursor & cur, string const & replacestring) } +void eraseSelection(LCursor & cur) +{ + //lyxerr << "LCursor::eraseSelection" << endl; + CursorSlice const & i1 = cur.selBegin(); + CursorSlice const & i2 = cur.selEnd(); +#ifdef WITH_WARNINGS +#warning FIXME +#endif + if (i1.inset().asMathInset()) { + if (i1.idx() == i2.idx()) { + i1.cell().erase(i1.pos(), i2.pos()); + } else { + MathInset * p = i1.asMathInset(); + InsetBase::row_type r1, r2; + InsetBase::col_type c1, c2; + region(i1, i2, r1, r2, c1, c2); + for (InsetBase::row_type row = r1; row <= r2; ++row) + for (InsetBase::col_type col = c1; col <= c2; ++col) + p->cell(p->index(row, col)).clear(); + } + cur.back() = i1; + } else { + lyxerr << "can't erase this selection 1" << endl; + } + //lyxerr << "LCursor::eraseSelection end" << endl; +} + + +void selDel(LCursor & cur) +{ + //lyxerr << "LCursor::selDel" << endl; + if (cur.selection()) { + eraseSelection(cur); + cur.selection() = false; + } +} + + +void selClearOrDel(LCursor & cur) +{ + //lyxerr << "LCursor::selClearOrDel" << endl; + if (lyxrc.auto_region_delete) + selDel(cur); + else + cur.selection() = false; +} + + +string grabSelection(LCursor & cur) +{ + if (!cur.selection()) + return string(); + + CursorSlice i1 = cur.selBegin(); + CursorSlice i2 = cur.selEnd(); + + if (i1.idx() == i2.idx()) { + if (i1.inset().asMathInset()) { + MathArray::const_iterator it = i1.cell().begin(); + return asString(MathArray(it + i1.pos(), it + i2.pos())); + } else { + return "unknown selection 1"; + } + } + + InsetBase::row_type r1, r2; + InsetBase::col_type c1, c2; + region(i1, i2, r1, r2, c1, c2); + + string data; + if (i1.inset().asMathInset()) { + for (InsetBase::row_type row = r1; row <= r2; ++row) { + if (row > r1) + data += "\\\\"; + for (InsetBase::col_type col = c1; col <= c2; ++col) { + if (col > c1) + data += '&'; + data += asString(i1.asMathInset()-> + cell(i1.asMathInset()->index(row, col))); + } + } + } else { + data = "unknown selection 2"; + } + return data; +} + + } // namespace cap } // namespace lyx diff --git a/src/CutAndPaste.h b/src/CutAndPaste.h index 7e52bcea53..f5759024ea 100644 --- a/src/CutAndPaste.h +++ b/src/CutAndPaste.h @@ -31,6 +31,8 @@ namespace cap { /// std::vector const availableSelections(Buffer const & buffer); +/// +std::string getSelection(Buffer const & buffer, size_t sel_index); /// void cutSelection(LCursor & cur, bool doclear, bool realcut); @@ -60,12 +62,25 @@ int SwitchLayoutsBetweenClasses(lyx::textclass_type c1, lyx::textclass_type c2, ParagraphList & par, ErrorList &); -/// -bool checkPastePossible(); // only used by the spellchecker void replaceWord(LCursor & cur, std::string const & replacestring); +/// +std::string grabSelection(LCursor & cur); +/// +void eraseSelection(LCursor & cur); +/// +std::string grabAndEraseSelection(LCursor & cur); +// other selection methods +/// +void selCut(LCursor & cur); +/// +void selDel(LCursor & cur); +/// clears or deletes selection depending on lyxrc setting +void selClearOrDel(LCursor & cur); +/// pastes n-th element of cut buffer +void selPaste(LCursor & cur, size_t n); } // namespace cap } // namespce lyx diff --git a/src/cursor.C b/src/cursor.C index d8cc1ba53a..82bfc82d6a 100644 --- a/src/cursor.C +++ b/src/cursor.C @@ -36,9 +36,7 @@ #include "insets/insettext.h" #include "mathed/math_data.h" -#include "mathed/math_support.h" #include "mathed/math_inset.h" -#include "mathed/math_braceinset.h" #include "mathed/math_macrotable.h" #include "support/limited_stack.h" @@ -60,31 +58,6 @@ using std::min; using std::swap; - -// our own cut buffer -limited_stack theCutBuffer; - - -namespace { - -void region(CursorSlice const & i1, CursorSlice const & i2, - LCursor::row_type & r1, LCursor::row_type & r2, - LCursor::col_type & c1, LCursor::col_type & c2) -{ - InsetBase & p = i1.inset(); - c1 = p.col(i1.idx()); - c2 = p.col(i2.idx()); - if (c1 > c2) - swap(c1, c2); - r1 = p.row(i1.idx()); - r2 = p.row(i2.idx()); - if (r1 > r2) - swap(r1, r2); -} - -} - - LCursor::LCursor(BufferView & bv) : DocIterator(), bv_(&bv), anchor_(), x_target_(-1), selection_(false), mark_(false) @@ -408,121 +381,6 @@ void LCursor::info(std::ostream & os) const } -string LCursor::grabSelection() -{ - if (!selection()) - return string(); - - CursorSlice i1 = selBegin(); - CursorSlice i2 = selEnd(); - - if (i1.idx() == i2.idx()) { - if (i1.inset().asMathInset()) { - MathArray::const_iterator it = i1.cell().begin(); - return asString(MathArray(it + i1.pos(), it + i2.pos())); - } else { - return "unknown selection 1"; - } - } - - row_type r1, r2; - col_type c1, c2; - region(i1, i2, r1, r2, c1, c2); - - string data; - if (i1.inset().asMathInset()) { - for (row_type row = r1; row <= r2; ++row) { - if (row > r1) - data += "\\\\"; - for (col_type col = c1; col <= c2; ++col) { - if (col > c1) - data += '&'; - data += asString(i1.asMathInset()->cell(i1.asMathInset()->index(row, col))); - } - } - } else { - data = "unknown selection 2"; - } - return data; -} - - -void LCursor::eraseSelection() -{ - //lyxerr << "LCursor::eraseSelection" << endl; - CursorSlice const & i1 = selBegin(); - CursorSlice const & i2 = selEnd(); -#ifdef WITH_WARNINGS -#warning FIXME -#endif - if (i1.inset().asMathInset()) { - if (i1.idx() == i2.idx()) { - i1.cell().erase(i1.pos(), i2.pos()); - } else { - MathInset * p = i1.asMathInset(); - row_type r1, r2; - col_type c1, c2; - region(i1, i2, r1, r2, c1, c2); - for (row_type row = r1; row <= r2; ++row) - for (col_type col = c1; col <= c2; ++col) - p->cell(p->index(row, col)).clear(); - } - back() = i1; - } else { - lyxerr << "can't erase this selection 1" << endl; - } - //lyxerr << "LCursor::eraseSelection end" << endl; -} - - -string LCursor::grabAndEraseSelection() -{ - if (!selection()) - return string(); - string res = grabSelection(); - eraseSelection(); - selection() = false; - return res; -} - - -void LCursor::selCopy() -{ - if (selection()) { - theCutBuffer.push(grabSelection()); - selection() = false; - } else { - //theCutBuffer.erase(); - } -} - - -void LCursor::selCut() -{ - theCutBuffer.push(grabAndEraseSelection()); -} - - -void LCursor::selDel() -{ - //lyxerr << "LCursor::selDel" << endl; - if (selection()) { - eraseSelection(); - selection() = false; - } -} - - -void LCursor::selPaste(size_t n) -{ - selClearOrDel(); - if (n < theCutBuffer.size()) - paste(theCutBuffer[n]); - //grabSelection(); - selection() = false; -} - - void LCursor::selHandle(bool sel) { //lyxerr << "LCursor::selHandle" << endl; @@ -538,16 +396,6 @@ void LCursor::selHandle(bool sel) } -void LCursor::selClearOrDel() -{ - //lyxerr << "LCursor::selClearOrDel" << endl; - if (lyxrc.auto_region_delete) - selDel(); - else - selection() = false; -} - - std::ostream & operator<<(std::ostream & os, LCursor const & cur) { for (size_t i = 0, n = cur.size(); i != n; ++i) { @@ -682,7 +530,7 @@ void LCursor::insert(char c) //lyxerr << "LCursor::insert char '" << c << "'" << endl; BOOST_ASSERT(!empty()); if (inMathed()) { - selClearOrDel(); + lyx::cap::selClearOrDel(*this); insert(new MathCharInset(c)); } else { text()->insertChar(*this, c); @@ -694,7 +542,7 @@ void LCursor::insert(MathAtom const & t) { //lyxerr << "LCursor::insert MathAtom: " << endl; macroModeClose(); - selClearOrDel(); + lyx::cap::selClearOrDel(*this); plainInsert(t); lyxerr << "LCursor::insert MathAtom: cur:\n" << *this << endl; } @@ -723,7 +571,7 @@ void LCursor::niceInsert(string const & t) void LCursor::niceInsert(MathAtom const & t) { macroModeClose(); - string safe = grabAndEraseSelection(); + string safe = lyx::cap::grabAndEraseSelection(*this); plainInsert(t); // enter the new inset and move the contents of the selection if possible if (t->isActive()) { @@ -740,7 +588,7 @@ void LCursor::insert(MathArray const & ar) { macroModeClose(); if (selection()) - eraseSelection(); + lyx::cap::eraseSelection(*this); cell().insert(pos(), ar); pos() += ar.size(); } @@ -751,7 +599,7 @@ bool LCursor::backspace() autocorrect() = false; if (selection()) { - selDel(); + lyx::cap::selDel(*this); return true; } @@ -791,7 +639,7 @@ bool LCursor::erase() return true; if (selection()) { - selDel(); + lyx::cap::selDel(*this); return true; } @@ -884,7 +732,7 @@ void LCursor::handleNest(MathAtom const & a, int c) { //lyxerr << "LCursor::handleNest: " << c << endl; MathAtom t = a; - asArray(grabAndEraseSelection(), t.nucleus()->cell(c)); + asArray(lyx::cap::grabAndEraseSelection(*this), t.nucleus()->cell(c)); insert(t); posLeft(); pushLeft(*nextInset()); @@ -1138,7 +986,7 @@ void LCursor::handleFont(string const & font) string safe; if (selection()) { macroModeClose(); - safe = grabAndEraseSelection(); + safe = lyx::cap::grabAndEraseSelection(*this); } if (lastpos() != 0) { diff --git a/src/cursor.h b/src/cursor.h index 16ae747aa5..e99a8a06bd 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -81,24 +81,7 @@ public: /// access start of selection DocIterator selectionEnd() const; /// - std::string grabSelection(); - /// - void eraseSelection(); - /// - std::string grabAndEraseSelection(); - // other selection methods - /// - void selCopy(); - /// - void selCut(); - /// - void selDel(); - /// pastes n-th element of cut buffer - void selPaste(size_t n); - /// void selHandle(bool selecting); - /// clears or deletes selection depending on lyxrc setting - void selClearOrDel(); // std::string selectionAsString(bool label) const; /// diff --git a/src/paragraph.C b/src/paragraph.C index 0e1dd01a90..5a7131ab3c 100644 --- a/src/paragraph.C +++ b/src/paragraph.C @@ -1570,8 +1570,7 @@ bool Paragraph::isMultiLingual(BufferParams const & bparams) const // Convert the paragraph to a string. // Used for building the table of contents -string const Paragraph::asString(Buffer const & buffer, - bool label) const +string const Paragraph::asString(Buffer const & buffer, bool label) const { OutputParams runparams; return asString(buffer, runparams, label); diff --git a/src/text3.C b/src/text3.C index a5b9962d04..d4e09ee7bf 100644 --- a/src/text3.C +++ b/src/text3.C @@ -158,9 +158,8 @@ namespace { cur.dispatch(FuncRequest(LFUN_MATH_MUTATE, "simple")); cur.dispatch(FuncRequest(LFUN_INSERT_MATH, sel)); } else { - cur.insert(new MathMacroTemplate); - //cur.dispatch(FuncRequest(LFUN_RIGHT)); - //cur.dispatch(FuncRequest(LFUN_INSERT_MATH, sel)); + istringstream is(sel); + cur.insert(new MathMacroTemplate(is)); } } cur.message(N_("Math editor mode")); -- 2.39.2