X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FCutAndPaste.C;h=88fbbb6141900187a35658d9131614bb2bbb425f;hb=0049b4d3e46a36bd4d5ce07a54555cfba2295cfd;hp=566d63016fb676e4f726ca00baf14a47ed9fb26c;hpb=c5a4f61f3377997a4b793481bd30a1a8e0627b86;p=lyx.git diff --git a/src/CutAndPaste.C b/src/CutAndPaste.C index 566d63016f..88fbbb6141 100644 --- a/src/CutAndPaste.C +++ b/src/CutAndPaste.C @@ -17,7 +17,6 @@ #include "buffer.h" #include "buffer_funcs.h" #include "bufferparams.h" -#include "BufferView.h" #include "cursor.h" #include "debug.h" #include "errorlist.h" @@ -39,26 +38,21 @@ #include "insets/insetcharstyle.h" #include "insets/insettabular.h" -#include "mathed/math_data.h" -#include "mathed/math_inset.h" -#include "mathed/math_support.h" +#include "mathed/MathData.h" +#include "mathed/InsetMath.h" +#include "mathed/MathSupport.h" #include "support/lstrings.h" -#include "frontends/Gui.h" -#include "frontends/LyXView.h" #include "frontends/Clipboard.h" #include -using lyx::pos_type; -using lyx::pit_type; -using lyx::textclass_type; -using lyx::support::bformat; +namespace lyx { -using lyx::frontend::Gui; -using lyx::frontend::Clipboard; +using support::bformat; +using frontend::Clipboard; using std::endl; using std::for_each; @@ -70,7 +64,7 @@ using std::string; namespace { -typedef std::pair PitPosPair; +typedef std::pair PitPosPair; typedef limited_stack > CutStack; @@ -81,24 +75,6 @@ CutStack theCuts(10); // when we (hopefully) have a one-for-all paste mechanism. bool dirty_tabular_stack_; -class resetParagraph : public std::unary_function { -public: - resetParagraph(Buffer const & b) : buffer_(b) {} - void operator()(Paragraph & p) const { - p.cleanChanges(); - // ERT paragraphs have the Language latex_language. - // This is invalid outside of ERT, so we need to change it - // to the buffer language. - if (p.ownerCode() == InsetBase::ERT_CODE) { - p.changeLanguage(buffer_.params(), latex_language, - buffer_.getLanguage()); - } - p.setInsetOwner(0); - } -private: - Buffer const & buffer_; -}; - void region(CursorSlice const & i1, CursorSlice const & i2, InsetBase::row_type & r1, InsetBase::row_type & r2, @@ -123,11 +99,14 @@ bool checkPastePossible(int index) pair -pasteSelectionHelper(Buffer const & buffer, - ParagraphList & pars, pit_type pit, int pos, - ParagraphList const & parlist, textclass_type textclass, - ErrorList & errorlist) +pasteSelectionHelper(LCursor & cur, ParagraphList const & parlist, + textclass_type textclass, ErrorList & errorlist) { + Buffer const & buffer = cur.buffer(); + pit_type pit = cur.pit(); + pos_type pos = cur.pos(); + ParagraphList & pars = cur.text()->paragraphs(); + if (parlist.empty()) return make_pair(PitPosPair(pit, pos), pit); @@ -147,7 +126,8 @@ pasteSelectionHelper(Buffer const & buffer, for (ParagraphList::size_type i = 0; i < insertion.size(); ++i) { for (pos_type j = 0; j < insertion[i].size(); ++j) { if (insertion[i].isNewline(j)) { - insertion[i].erase(j); + // do not track deletion of newline + insertion[i].eraseChar(j, false); breakParagraphConservative( buffer.params(), insertion, i, j); @@ -156,6 +136,17 @@ pasteSelectionHelper(Buffer const & buffer, } } + // If we are in an inset which returns forceDefaultParagraphs, + // set the paragraphs to default + if (cur.inset().forceDefaultParagraphs(cur.idx())) { + LyXLayout_ptr const layout = + buffer.params().getLyXTextClass().defaultLayout(); + ParagraphList::iterator const end = insertion.end(); + for (ParagraphList::iterator par = insertion.begin(); + par != end; ++par) + par->layout(layout); + } + // Make sure there is no class difference. InsetText in; // This works without copying any paragraph data because we have @@ -163,13 +154,13 @@ pasteSelectionHelper(Buffer const & buffer, // since we store pointers to insets at some places and we don't // want to invalidate them. insertion.swap(in.paragraphs()); - lyx::cap::switchBetweenClasses(textclass, tc, in, errorlist); + cap::switchBetweenClasses(textclass, tc, in, errorlist); insertion.swap(in.paragraphs()); ParagraphList::iterator tmpbuf = insertion.begin(); int depth_delta = pars[pit].params().depth() - tmpbuf->params().depth(); - Paragraph::depth_type max_depth = pars[pit].getMaxDepthAfter(); + depth_type max_depth = pars[pit].getMaxDepthAfter(); for (; tmpbuf != insertion.end(); ++tmpbuf) { // If we have a negative jump so that the depth would @@ -195,14 +186,12 @@ pasteSelectionHelper(Buffer const & buffer, for (pos_type i = 0; i < tmpbuf->size(); ++i) { if (tmpbuf->getChar(i) == Paragraph::META_INSET && !pars[pit].insetAllowed(tmpbuf->getInset(i)->lyxCode())) - tmpbuf->erase(i--); + // do not track deletion of invalid insets + tmpbuf->eraseChar(i--, false); } - // reset change tracking status - if (buffer.params().tracking_changes) - tmpbuf->cleanChanges(Paragraph::trackingOn); - else - tmpbuf->cleanChanges(Paragraph::trackingOff); + tmpbuf->setChange(Change(buffer.params().trackChanges ? + Change::INSERTED : Change::UNCHANGED)); } bool const empty = pars[pit].empty(); @@ -298,9 +287,8 @@ PitPosPair eraseSelectionHelper(BufferParams const & params, return PitPosPair(endpit, endpos); // Start and end is inside same paragraph - if (endpit == pit_type(pars.size()) || - startpit == endpit) { - endpos -= pars[startpit].erase(startpos, endpos); + if (endpit == pit_type(pars.size()) || startpit == endpit) { + endpos -= pars[startpit].eraseChars(startpos, endpos, params.trackChanges); return PitPosPair(endpit, endpos); } @@ -308,14 +296,14 @@ PitPosPair eraseSelectionHelper(BufferParams const & params, // only if either (1) change tracking is off, or (2) the para break // is "blue" for (pit_type pit = startpit; pit != endpit + 1;) { - bool const merge = !params.tracking_changes || - pars[pit].lookupChange(pars[pit].size()) == - Change::INSERTED; + // FIXME: Change tracking (MG) + bool const merge = !params.trackChanges || + pars[pit].isInserted(pars[pit].size()); pos_type const left = ( pit == startpit ? startpos : 0 ); pos_type const right = ( pit == endpit ? endpos : pars[pit].size() + 1 ); // Logical erase only: - pars[pit].erase(left, right); + pars[pit].eraseChars(left, right, false); // Separate handling of para break: if (merge && pit != endpit && (pit + 1 != endpit || pars[pit].hasSameLayout(pars[pit + 1]))) { @@ -349,15 +337,29 @@ void copySelectionHelper(Buffer const & buf, ParagraphList & pars, ParagraphList paragraphs(boost::next(pars.begin(), startpit), boost::next(pars.begin(), endpit + 1)); - for_each(paragraphs.begin(), paragraphs.end(), resetParagraph(buf)); + ParagraphList::iterator it = paragraphs.begin(); + ParagraphList::iterator it_end = paragraphs.end(); + + for (; it != it_end; it++) { + // ERT paragraphs have the Language latex_language. + // This is invalid outside of ERT, so we need to change it + // to the buffer language. + if (it->ownerCode() == InsetBase::ERT_CODE) { + it->changeLanguage(buf.params(), latex_language, + buf.getLanguage()); + } + it->setInsetOwner(0); + } // Cut out the end of the last paragraph. Paragraph & back = paragraphs.back(); - back.erase(end, back.size()); + // do not track deletion here; it is an internal action not visible to the user + back.eraseChars(end, back.size(), false); // Cut out the begin of the first paragraph Paragraph & front = paragraphs.front(); - front.erase(0, start); + // again, do not track deletion + front.eraseChars(0, start, false); theCuts.push(make_pair(paragraphs, tc)); } @@ -367,14 +369,13 @@ void copySelectionHelper(Buffer const & buf, ParagraphList & pars, -namespace lyx { namespace cap { -string grabAndEraseSelection(LCursor & cur) +docstring grabAndEraseSelection(LCursor & cur) { if (!cur.selection()) - return string(); - string res = grabSelection(cur); + return docstring(); + docstring res = grabSelection(cur); eraseSelection(cur); return res; } @@ -402,10 +403,11 @@ void switchBetweenClasses(textclass_type c1, textclass_type c2, it->layout(tclass2.defaultLayout()); if (!hasLayout && name != tclass1.defaultLayoutName()) { - 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()); + docstring 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"), + from_utf8(name), from_utf8(it->layout()->name()), + from_utf8(tclass1.name()), from_utf8(tclass2.name())); // To warn the user that something had to be done. errorlist.push_back(ErrorItem(_("Changed Layout"), s, it->id(), 0, @@ -425,16 +427,16 @@ void switchBetweenClasses(textclass_type c1, textclass_type c2, if (found_cs == tclass2.charstyles().end()) { // The character style is undefined in tclass2 inset.setUndefined(); - string const s = bformat(_( + docstring const s = bformat(_( "Character style %1$s is " "undefined because of class " "conversion from\n%2$s to %3$s"), - name, tclass1.name(), tclass2.name()); + from_utf8(name), from_utf8(tclass1.name()), + from_utf8(tclass2.name())); // To warn the user that something had to be done. errorlist.push_back(ErrorItem( - _("Undefined character style"), - s, it.paragraph().id(), - it.pos(), it.pos() + 1)); + _("Undefined character style"), + s, it.paragraph().id(), it.pos(), it.pos() + 1)); } else if (inset.undefined()) { // The character style is undefined in // tclass1 and is defined in tclass2 @@ -445,9 +447,9 @@ void switchBetweenClasses(textclass_type c1, textclass_type c2, } -std::vector const availableSelections(Buffer const & buffer) +std::vector const availableSelections(Buffer const & buffer) { - vector selList; + vector selList; CutStack::const_iterator cit = theCuts.begin(); CutStack::const_iterator end = theCuts.end(); @@ -455,13 +457,14 @@ std::vector const availableSelections(Buffer const & buffer) // we do not use cit-> here because gcc 2.9x does not // like it (JMarc) ParagraphList const & pars = (*cit).first; - string asciiSel; + docstring 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, "..."); + asciiSel.replace(22, docstring::npos, + from_ascii("...")); break; } } @@ -473,7 +476,7 @@ std::vector const availableSelections(Buffer const & buffer) } -lyx::size_type numberOfSelections() +size_type numberOfSelections() { return theCuts.size(); } @@ -498,9 +501,9 @@ void cutSelection(LCursor & cur, bool doclear, bool realcut) // 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 cur.bv().owner()->gui().selection().put. (Lgb) -// cur.bv().owner()->gui().selection().put(cur.selectionAsString(true)); - + // calls to theSelection().put. (Lgb) +// theSelection().put(cur.selectionAsString(true)); + // make sure that the depth behind the selection are restored, too recordUndoSelection(cur); @@ -563,7 +566,7 @@ void cutSelection(LCursor & cur, bool doclear, bool realcut) void copySelection(LCursor & cur) { // stuff the selection onto the X clipboard, from an explicit copy request - cur.bv().owner()->gui().clipboard().put(cur.selectionAsString(true)); + theClipboard().put(cur.selectionAsString(true)); // this doesn't make sense, if there is no selection if (!cur.selection()) @@ -591,11 +594,11 @@ void copySelection(LCursor & cur) if (cur.inMathed()) { //lyxerr << "copySelection in mathed" << endl; ParagraphList pars; - pars.push_back(Paragraph()); + Paragraph par; BufferParams const & bp = cur.buffer().params(); - pars.back().layout(bp.getLyXTextClass().defaultLayout()); - for_each(pars.begin(), pars.end(), resetParagraph(cur.buffer())); - pars.back().insert(0, grabSelection(cur), LyXFont()); + par.layout(bp.getLyXTextClass().defaultLayout()); + par.insert(0, grabSelection(cur), LyXFont(), Change(Change::UNCHANGED)); + pars.push_back(par); theCuts.push(make_pair(pars, bp.textclass)); } // tell tabular that a recent copy happened @@ -603,11 +606,11 @@ void copySelection(LCursor & cur) } -std::string getSelection(Buffer const & buf, size_t sel_index) +docstring getSelection(Buffer const & buf, size_t sel_index) { return sel_index < theCuts.size() ? theCuts[sel_index].first.back().asString(buf, false) - : string(); + : docstring(); } @@ -618,23 +621,18 @@ void pasteParagraphList(LCursor & cur, ParagraphList const & parlist, LyXText * text = cur.text(); BOOST_ASSERT(text); - recordUndo(cur); - pit_type endpit; PitPosPair ppp; boost::tie(ppp, endpit) = - pasteSelectionHelper(cur.buffer(), - text->paragraphs(), - cur.pit(), cur.pos(), - parlist, textclass, - errorList); + pasteSelectionHelper(cur, parlist, + textclass, errorList); updateLabels(cur.buffer()); cur.clearSelection(); text->setCursor(cur, ppp.first, ppp.second); } - // mathed is handled in MathNestInset/MathGridInset + // mathed is handled in InsetMathNest/InsetMathGrid BOOST_ASSERT(!cur.inMathed()); } @@ -645,46 +643,40 @@ void pasteSelection(LCursor & cur, ErrorList & errorList, size_t sel_index) if (!checkPastePossible(sel_index)) return; + recordUndo(cur); pasteParagraphList(cur, theCuts[sel_index].first, theCuts[sel_index].second, errorList); cur.setSelection(); } -void setSelectionRange(LCursor & cur, pos_type length) -{ - LyXText * text = cur.text(); - BOOST_ASSERT(text); - if (!length) - return; - cur.resetAnchor(); - while (length--) - text->cursorRight(cur); - cur.setSelection(); -} - - // simple replacing. The font of the first selected character is used -void replaceSelectionWithString(LCursor & cur, string const & str) +void replaceSelectionWithString(LCursor & cur, string const & str, bool backwards) { - LyXText * text = cur.text(); - BOOST_ASSERT(text); recordUndo(cur); + DocIterator selbeg = cur.selectionBegin(); // Get font setting before we cut - pos_type pos = cur.selEnd().pos(); - Paragraph & par = text->getPar(cur.selEnd().pit()); LyXFont const font = - par.getFontSettings(cur.buffer().params(), cur.selBegin().pos()); + selbeg.paragraph().getFontSettings(cur.buffer().params(), selbeg.pos()); // Insert the new string + pos_type pos = cur.selEnd().pos(); + Paragraph & par = cur.selEnd().paragraph(); string::const_iterator cit = str.begin(); string::const_iterator end = str.end(); for (; cit != end; ++cit, ++pos) - par.insertChar(pos, (*cit), font); + par.insertChar(pos, (*cit), font, cur.buffer().params().trackChanges); // Cut the selection cutSelection(cur, true, false); + + // select the replacement + if (backwards) { + selbeg.pos() += str.length(); + cur.setSelection(selbeg, -int(str.length())); + } else + cur.setSelection(selbeg, str.length()); } @@ -695,27 +687,12 @@ void replaceSelection(LCursor & cur) } -// only used by the spellchecker -void replaceWord(LCursor & cur, string const & replacestring) -{ - LyXText * text = cur.text(); - BOOST_ASSERT(text); - - replaceSelectionWithString(cur, replacestring); - setSelectionRange(cur, replacestring.length()); - - // Go back so that replacement string is also spellchecked - for (string::size_type i = 0; i < replacestring.length() + 1; ++i) - text->cursorLeft(cur); -} - - void eraseSelection(LCursor & cur) { //lyxerr << "LCursor::eraseSelection begin: " << cur << endl; CursorSlice const & i1 = cur.selBegin(); CursorSlice const & i2 = cur.selEnd(); - if (i1.inset().asMathInset()) { + if (i1.inset().asInsetMath()) { cur.top() = i1; if (i1.idx() == i2.idx()) { i1.cell().erase(i1.pos(), i2.pos()); @@ -724,7 +701,7 @@ void eraseSelection(LCursor & cur) if (cur.pos() > cur.lastpos()) cur.pos() = cur.lastpos(); } else { - MathInset * p = i1.asMathInset(); + InsetMath * p = i1.asInsetMath(); InsetBase::row_type r1, r2; InsetBase::col_type c1, c2; region(i1, i2, r1, r2, c1, c2); @@ -761,10 +738,10 @@ void selClearOrDel(LCursor & cur) } -string grabSelection(LCursor const & cur) +docstring grabSelection(LCursor const & cur) { if (!cur.selection()) - return string(); + return docstring(); // FIXME: What is wrong with the following? #if 0 @@ -779,11 +756,11 @@ string grabSelection(LCursor const & cur) CursorSlice i2 = cur.selEnd(); if (i1.idx() == i2.idx()) { - if (i1.inset().asMathInset()) { + if (i1.inset().asInsetMath()) { MathArray::const_iterator it = i1.cell().begin(); return asString(MathArray(it + i1.pos(), it + i2.pos())); } else { - return "unknown selection 1"; + return from_ascii("unknown selection 1"); } } @@ -791,20 +768,20 @@ string grabSelection(LCursor const & cur) InsetBase::col_type c1, c2; region(i1, i2, r1, r2, c1, c2); - string data; - if (i1.inset().asMathInset()) { + docstring data; + if (i1.inset().asInsetMath()) { 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))); + data += asString(i1.asInsetMath()-> + cell(i1.asInsetMath()->index(row, col))); } } } else { - data = "unknown selection 2"; + data = from_ascii("unknown selection 2"); } return data; } @@ -823,4 +800,5 @@ bool tabularStackDirty() } // namespace cap + } // namespace lyx