X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FCutAndPaste.C;h=36c863428ff1f183dce6c9092f39c18c789aea12;hb=c544107e324090c6eafb4c56749da2624b9b1122;hp=fea5382d1bd578993663c16238d068c9d899cefb;hpb=717121eba662c8cb8c20575b611ed90006087e8b;p=lyx.git diff --git a/src/CutAndPaste.C b/src/CutAndPaste.C index fea5382d1b..36c863428f 100644 --- a/src/CutAndPaste.C +++ b/src/CutAndPaste.C @@ -1,83 +1,101 @@ -/* This file is part of - * ====================================================== +/* \file CutAndPaste.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. * - * LyX, The Document Processor + * \author Juergen Vigna + * \author Lars Gullik Bjønnes + * \author Alfredo Braunstein * - * Copyright 1995-2001 The LyX Team. - * - * ====================================================== */ + * Full author contact details are available in file CREDITS + */ #include #include "CutAndPaste.h" #include "BufferView.h" #include "buffer.h" +#include "errorlist.h" #include "paragraph.h" #include "ParagraphParameters.h" #include "lyxtext.h" #include "lyxcursor.h" -#include "gettext.h" #include "iterators.h" #include "lyxtextclasslist.h" #include "undo_funcs.h" +#include "gettext.h" #include "paragraph_funcs.h" #include "debug.h" +#include "insets/insetinclude.h" +#include "insets/insettabular.h" -#include "insets/inseterror.h" - -#include "support/BoostFormat.h" #include "support/LAssert.h" +#include "support/lstrings.h" +#include "support/limited_stack.h" using std::endl; using std::pair; using std::make_pair; using std::for_each; +using std::vector; +using namespace lyx::support; using lyx::pos_type; using lyx::textclass_type; -extern BufferView * current_view; - -// Jürgen, note that this means that you cannot currently have a list -// of selections cut/copied. So IMHO later we should have a -// list/vector/deque that we could store -// struct selection_item { -// Paragraph * buf; -// LyXTextClassList::size_type textclass; -// }; -// in and some method of choosing beween them (based on the first few chars -// in the selection probably.) This would be a nice feature and quite -// easy to implement. (Lgb) -// -// Sure but I just cleaned up this code for now with the same functionality -// as before. I also want to add a XClipboard function so that we can copy -// text from LyX to some other X-application in the form of ASCII or in the -// form of LaTeX (or Docbook depending on the document-class!). Think how nice -// it could be to select a math-inset do a "Copy to X-Clipboard as LaTeX" and -// then do a middle mouse button click in the application you want and have -// the whole formula there in LaTeX-Code. (Jug) + +typedef limited_stack > CutStack; namespace { -// FIXME: stupid name -ParagraphList paragraphs; -textclass_type textclass = 0; +CutStack cuts(10); } // namespace anon -PitPosPair CutAndPaste::cutSelection(ParagraphList & pars, + +std::vector +CutAndPaste::availableSelections(Buffer const & buffer) +{ + vector selList; + + 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, "..."); + break; + } + } + + selList.push_back(asciiSel); + } + + return selList; +} + + +PitPosPair CutAndPaste::cutSelection(BufferParams const & params, + ParagraphList & pars, ParagraphList::iterator startpit, ParagraphList::iterator endpit, int startpos, int endpos, textclass_type tc, bool doclear) { copySelection(startpit, endpit, startpos, endpos, tc); - return eraseSelection(pars, startpit, endpit, startpos, + return eraseSelection(params, pars, startpit, endpit, startpos, endpos, doclear); } -PitPosPair CutAndPaste::eraseSelection(ParagraphList & pars, +PitPosPair CutAndPaste::eraseSelection(BufferParams const & params, + ParagraphList & pars, ParagraphList::iterator startpit, ParagraphList::iterator endpit, int startpos, int endpos, bool doclear) @@ -137,10 +155,7 @@ PitPosPair CutAndPaste::eraseSelection(ParagraphList & pars, if (all_erased && (startpit->hasSameLayout(*boost::next(startpit)) || boost::next(startpit)->empty())) { -#warning current_view used here. -// should we pass buffer or buffer->params around? - Buffer * buffer = current_view->buffer(); - mergeParagraph(buffer->params, pars, &*startpit); + mergeParagraph(params, pars, startpit); // this because endpar gets deleted here! endpit = startpit; endpos = startpos; @@ -166,13 +181,11 @@ bool CutAndPaste::copySelection(ParagraphList::iterator startpit, ParagraphList::iterator endpit, int start, int end, textclass_type tc) { - lyx::Assert(&*startpit); - lyx::Assert(&*endpit); - lyx::Assert(0 <= start && start <= startpit->size()); - lyx::Assert(0 <= end && end <= endpit->size()); - lyx::Assert(startpit != endpit || start <= end); + Assert(0 <= start && start <= startpit->size()); + Assert(0 <= end && end <= endpit->size()); + Assert(startpit != endpit || start <= end); - textclass = tc; + ParagraphList paragraphs; // Clone the paragraphs within the selection. ParagraphList::iterator postend = boost::next(endpit); @@ -188,48 +201,52 @@ bool CutAndPaste::copySelection(ParagraphList::iterator startpit, Paragraph & front = paragraphs.front(); front.erase(0, start); + cuts.push(make_pair(paragraphs, tc)); + return true; } pair -CutAndPaste::pasteSelection(ParagraphList & pars, +CutAndPaste::pasteSelection(Buffer const & buffer, + ParagraphList & pars, ParagraphList::iterator pit, int pos, - textclass_type tc) + textclass_type tc, + ErrorList & errorlist) +{ + return pasteSelection(buffer, pars, pit, pos, tc, 0, errorlist); +} + + +pair +CutAndPaste::pasteSelection(Buffer const & buffer, + ParagraphList & pars, + ParagraphList::iterator pit, int pos, + textclass_type tc, size_t cut_index, + ErrorList & errorlist) { if (!checkPastePossible()) return make_pair(PitPosPair(pit, pos), pit); - lyx::Assert (pos <= pit->size()); + Assert (pos <= pit->size()); - // make a copy of the simple cut_buffer -#if 1 - ParagraphList simple_cut_clone; - ParagraphList::iterator it = paragraphs.begin(); - ParagraphList::iterator end = paragraphs.end(); - for (; it != end; ++it) { - simple_cut_clone.push_back(new Paragraph(*it, false)); - } -#else - // Later we want it done like this: - ParagraphList simple_cut_clone = paragraphs; -#endif - // now remove all out of the buffer which is NOT allowed in the - // new environment and set also another font if that is required - ParagraphList::iterator tmpbuf = paragraphs.begin(); - int depth_delta = pit->params().depth() - tmpbuf->params().depth(); - // Temporary set *par as previous of tmpbuf as we might have - // to realize the font. - tmpbuf->previous(&*pit); + // Make a copy of the CaP paragraphs. + ParagraphList simple_cut_clone = cuts[cut_index].first; + textclass_type const textclass = cuts[cut_index].second; - // make sure there is no class difference -#warning current_view used here - SwitchLayoutsBetweenClasses(textclass, tc, &*tmpbuf, - current_view->buffer()->params); + // Now remove all out of the pars which is NOT allowed in the + // new environment and set also another font if that is required. + + // Make sure there is no class difference. + SwitchLayoutsBetweenClasses(textclass, tc, simple_cut_clone, + errorlist); + + ParagraphList::iterator tmpbuf = simple_cut_clone.begin(); + int depth_delta = pit->params().depth() - tmpbuf->params().depth(); Paragraph::depth_type max_depth = pit->getMaxDepthAfter(); - for (; tmpbuf != paragraphs.end(); ++tmpbuf) { + for (; tmpbuf != simple_cut_clone.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 @@ -237,15 +254,18 @@ CutAndPaste::pasteSelection(ParagraphList & pars, // 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. + + // 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->previous() != pit) + + // Only set this from the 2nd on as the 2nd depends + // for maxDepth still on pit. + if (tmpbuf != simple_cut_clone.begin()) max_depth = tmpbuf->getMaxDepthAfter(); - // set the inset owner of this paragraph + + // Set the inset owner of this paragraph. tmpbuf->setInsetOwner(pit->inInset()); for (pos_type i = 0; i < tmpbuf->size(); ++i) { if (tmpbuf->getChar(i) == Paragraph::META_INSET) { @@ -253,7 +273,7 @@ CutAndPaste::pasteSelection(ParagraphList & pars, tmpbuf->erase(i--); } } else { - LyXFont f1 = tmpbuf->getFont(current_view->buffer()->params, i, outerFont(tmpbuf, pars)); + LyXFont f1 = tmpbuf->getFont(buffer.params, i, outerFont(pit, pars)); LyXFont f2 = f1; if (!pit->checkInsertChar(f1)) { tmpbuf->erase(i--); @@ -264,63 +284,89 @@ CutAndPaste::pasteSelection(ParagraphList & pars, } } - // now reset it to 0 - paragraphs.begin()->previous(0); + // Make the buf exactly the same layout than + // the cursor paragraph. + simple_cut_clone.begin()->makeSameLayout(*pit); + + // Prepare the paragraphs and insets for insertion + // A couple of insets store buffer references so need + // updating + ParIterator fpit(simple_cut_clone.begin(), simple_cut_clone); + ParIterator fend(simple_cut_clone.end(), simple_cut_clone); + + 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::INCLUDE_CODE: { + InsetInclude * ii = static_cast(lit->inset); + InsetInclude::Params ip = ii->params(); + ip.masterFilename_ = buffer.fileName(); + ii->set(ip); + break; + } - // make the buf exactly the same layout than - // the cursor paragraph - paragraphs.begin()->makeSameLayout(*pit); + case InsetOld::TABULAR_CODE: { + InsetTabular * it = static_cast(lit->inset); + it->buffer(const_cast(&buffer)); + break; + } - // find the end of the buffer - // FIXME: change this to end() - 1 - ParagraphList::iterator lastbuffer = paragraphs.begin(); - while (boost::next(lastbuffer) != paragraphs.end()) - ++lastbuffer; + default: + break; // nothing + } + } + } bool paste_the_end = false; - // open the paragraph for inserting the buf - // if necessary - if (pit->size() > pos || !pit->next()) { - breakParagraphConservative(current_view->buffer()->params, - pars, &*pit, pos); + // Open the paragraph for inserting the buf + // if necessary. + if (pit->size() > pos || boost::next(pit) == pars.end()) { + breakParagraphConservative(buffer.params, + pars, pit, pos); paste_the_end = true; } - // set the end for redoing later + + // Set the end for redoing later. ParagraphList::iterator endpit = boost::next(boost::next(pit)); - // paste it! - lastbuffer->next(pit->next()); - pit->next()->previous(&*lastbuffer); - - pit->next(&*paragraphs.begin()); - paragraphs.begin()->previous(&*pit); - - if (boost::next(pit) == lastbuffer) - lastbuffer = pit; - - mergeParagraph(current_view->buffer()->params, pars, pit); - // store the new cursor position - pit = lastbuffer; - pos = lastbuffer->size(); - // maybe some pasting - if (boost::next(lastbuffer) != paragraphs.end() && paste_the_end) { - if (boost::next(lastbuffer)->hasSameLayout(*lastbuffer)) { - mergeParagraph(current_view->buffer()->params, pars, - lastbuffer); - } else if (!boost::next(lastbuffer)->size()) { - boost::next(lastbuffer)->makeSameLayout(*lastbuffer); - mergeParagraph(current_view->buffer()->params, pars, - lastbuffer); - } else if (!lastbuffer->size()) { - lastbuffer->makeSameLayout(*boost::next(lastbuffer)); - mergeParagraph(current_view->buffer()->params, pars, - lastbuffer); + // Paste it! + + ParagraphList::iterator past_pit = boost::next(pit); + pars.splice(past_pit, simple_cut_clone); + ParagraphList::iterator last_paste = boost::prior(past_pit); + + // If we only inserted one paragraph. + if (boost::next(pit) == last_paste) + last_paste = pit; + + mergeParagraph(buffer.params, pars, pit); + + // Store the new cursor position. + pit = last_paste; + pos = last_paste->size(); + + // Maybe some pasting. +#warning CHECK! Are we comparing last_paste to the wrong list here? (Lgb) + if (boost::next(last_paste) != pars.end() && + paste_the_end) { + if (boost::next(last_paste)->hasSameLayout(*last_paste)) { + mergeParagraph(buffer.params, pars, + last_paste); + } else if (boost::next(last_paste)->empty()) { + boost::next(last_paste)->makeSameLayout(*last_paste); + mergeParagraph(buffer.params, pars, + last_paste); + } else if (last_paste->empty()) { + last_paste->makeSameLayout(*boost::next(last_paste)); + mergeParagraph(buffer.params, pars, + last_paste); } else - boost::next(lastbuffer)->stripLeadingSpaces(); + boost::next(last_paste)->stripLeadingSpaces(); } - // restore the simple cut buffer - paragraphs = simple_cut_clone; return make_pair(PitPosPair(pit, pos), endpit); } @@ -328,62 +374,43 @@ CutAndPaste::pasteSelection(ParagraphList & pars, int CutAndPaste::nrOfParagraphs() { - return paragraphs.size(); + return cuts.empty() ? 0 : cuts[0].first.size(); } int CutAndPaste::SwitchLayoutsBetweenClasses(textclass_type c1, textclass_type c2, - Paragraph * par, - BufferParams const & /*bparams*/) + ParagraphList & pars, + ErrorList & errorlist) { + Assert(!pars.empty()); + int ret = 0; - if (!par || c1 == c2) + if (c1 == c2) return ret; LyXTextClass const & tclass1 = textclasslist[c1]; LyXTextClass const & tclass2 = textclasslist[c2]; - ParIterator end = ParIterator(); - for (ParIterator it = ParIterator(par); it != end; ++it) { - par = *it; - string const name = par->layout()->name(); + ParIterator end = ParIterator(pars.end(), pars); + for (ParIterator it = ParIterator(pars.begin(), pars); it != end; ++it) { + string const name = it->layout()->name(); bool hasLayout = tclass2.hasLayout(name); if (hasLayout) - par->layout(tclass2[name]); + it->layout(tclass2[name]); else - par->layout(tclass2.defaultLayout()); + it->layout(tclass2.defaultLayout()); if (!hasLayout && name != tclass1.defaultLayoutName()) { ++ret; -#if USE_BOOST_FORMAT - boost::format fmt(_("Layout had to be changed from\n" - "%1$s to %2$s\n" - "because of class conversion from\n" - "%3$s to %4$s")); - fmt % name - % par->layout()->name() - % tclass1.name() - % tclass2.name(); - - string const s = fmt.str(); -#else - string const s = _("Layout had to be changed from\n") - + name + _(" to ") - + par->layout()->name() - + _("\nbecause of class conversion from\n") - + tclass1.name() + _(" to ") - + tclass2.name(); -#endif - freezeUndo(); - InsetError * new_inset = new InsetError(s); - LyXText * txt = current_view->getLyXText(); - LyXCursor cur = txt->cursor; - txt->setCursorIntern(par, 0); - txt->insertInset(new_inset); - txt->fullRebreak(); - txt->setCursorIntern(cur.par(), cur.pos()); - unFreezeUndo(); + 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())); } } return ret; @@ -392,5 +419,5 @@ int CutAndPaste::SwitchLayoutsBetweenClasses(textclass_type c1, bool CutAndPaste::checkPastePossible() { - return !paragraphs.empty(); + return !cuts.empty() && !cuts[0].first.empty(); }