X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FCutAndPaste.cpp;h=761a107b6ad8be1b83054f49b6fc91b8f384457a;hb=341e4480df5d12f69d83d1a0fc8d1c1232954689;hp=fecfb6979b8b24d6f204619c61f05f2eb6f11f58;hpb=2e7d1199dfa7ec7b7d963c374a014f2a2227ae7c;p=lyx.git diff --git a/src/CutAndPaste.cpp b/src/CutAndPaste.cpp index fecfb6979b..761a107b6a 100644 --- a/src/CutAndPaste.cpp +++ b/src/CutAndPaste.cpp @@ -22,15 +22,14 @@ #include "Changes.h" #include "Cursor.h" #include "ErrorList.h" +#include "FuncCode.h" #include "FuncRequest.h" #include "InsetIterator.h" #include "InsetList.h" #include "Language.h" -#include "lfuns.h" #include "LyXFunc.h" #include "LyXRC.h" #include "Text.h" -#include "TextClassList.h" #include "Paragraph.h" #include "paragraph_funcs.h" #include "ParagraphParameters.h" @@ -38,6 +37,7 @@ #include "Undo.h" #include "insets/InsetFlex.h" +#include "insets/InsetCommand.h" #include "insets/InsetGraphics.h" #include "insets/InsetGraphicsParams.h" #include "insets/InsetTabular.h" @@ -70,7 +70,7 @@ namespace { typedef pair PitPosPair; -typedef limited_stack > CutStack; +typedef limited_stack > CutStack; CutStack theCuts(10); // persistent selection, cleared until the next selection @@ -82,22 +82,6 @@ CutStack selectionBuffer(1); bool dirty_tabular_stack_ = false; -void region(CursorSlice const & i1, CursorSlice const & i2, - Inset::row_type & r1, Inset::row_type & r2, - Inset::col_type & c1, Inset::col_type & c2) -{ - Inset & 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); -} - - bool checkPastePossible(int index) { return size_t(index) < theCuts.size() && !theCuts[index].first.empty(); @@ -106,7 +90,7 @@ bool checkPastePossible(int index) pair pasteSelectionHelper(Cursor & cur, ParagraphList const & parlist, - TextClassPtr textclass, ErrorList & errorlist) + DocumentClass const * const oldDocClass, ErrorList & errorlist) { Buffer const & buffer = cur.buffer(); pit_type pit = cur.pit(); @@ -120,7 +104,8 @@ pasteSelectionHelper(Cursor & cur, ParagraphList const & parlist, // Make a copy of the CaP paragraphs. ParagraphList insertion = parlist; - TextClassPtr const tc = buffer.params().getTextClassPtr(); + DocumentClass const * const newDocClass = + buffer.params().documentClassPtr(); // Now remove all out of the pars which is NOT allowed in the // new environment and set also another font if that is required. @@ -144,15 +129,27 @@ pasteSelectionHelper(Cursor & cur, ParagraphList const & parlist, } // set the paragraphs to empty layout if necessary - // note that we are doing this if the empty layout is - // supposed to be the default, not just if it is forced if (cur.inset().useEmptyLayout()) { - LayoutPtr const layout = - buffer.params().getTextClass().emptyLayout(); + bool forceEmptyLayout = cur.inset().forceEmptyLayout(); + Layout const & emptyLayout = newDocClass->emptyLayout(); + Layout const & defaultLayout = newDocClass->defaultLayout(); + ParagraphList::iterator const end = insertion.end(); + ParagraphList::iterator par = insertion.begin(); + for (; par != end; ++par) { + Layout const & parLayout = par->layout(); + if (forceEmptyLayout || parLayout == defaultLayout) + par->setLayout(emptyLayout); + } + } else { // check if we need to reset from empty layout + Layout const & defaultLayout = newDocClass->defaultLayout(); + Layout const & emptyLayout = newDocClass->emptyLayout(); ParagraphList::iterator const end = insertion.end(); - for (ParagraphList::iterator par = insertion.begin(); - par != end; ++par) - par->setLayout(layout); + ParagraphList::iterator par = insertion.begin(); + for (; par != end; ++par) { + Layout const & parLayout = par->layout(); + if (parLayout == emptyLayout) + par->setLayout(defaultLayout); + } } // Make sure there is no class difference. @@ -162,7 +159,7 @@ pasteSelectionHelper(Cursor & cur, ParagraphList const & parlist, // since we store pointers to insets at some places and we don't // want to invalidate them. insertion.swap(in.paragraphs()); - cap::switchBetweenClasses(textclass, tc, in, errorlist); + cap::switchBetweenClasses(oldDocClass, newDocClass, in, errorlist); insertion.swap(in.paragraphs()); ParagraphList::iterator tmpbuf = insertion.begin(); @@ -213,14 +210,55 @@ pasteSelectionHelper(Cursor & cur, ParagraphList const & parlist, // A couple of insets store buffer references so need updating. insertion.swap(in.paragraphs()); - ParIterator fpit = par_iterator_begin(in); - ParIterator fend = par_iterator_end(in); + InsetIterator const i_end = inset_iterator_end(in); + + for (InsetIterator it = inset_iterator_begin(in); it != i_end; ++it) { + + it->setBuffer(const_cast(buffer)); + + switch (it->lyxCode()) { + + case LABEL_CODE: { + // check for duplicates + InsetCommand & lab = static_cast(*it); + docstring const oldname = lab.getParam("name"); + lab.updateCommand(oldname, false); + docstring const newname = lab.getParam("name"); + if (oldname != newname) { + // adapt the references + for (InsetIterator itt = inset_iterator_begin(in); itt != i_end; ++itt) { + if (itt->lyxCode() == REF_CODE) { + InsetCommand & ref = dynamic_cast(*itt); + if (ref.getParam("reference") == oldname) + ref.setParam("reference", newname); + } + } + } + break; + } + + case BIBITEM_CODE: { + // check for duplicates + InsetCommand & bib = static_cast(*it); + docstring const oldkey = bib.getParam("key"); + bib.updateCommand(oldkey, false); + docstring const newkey = bib.getParam("key"); + if (oldkey != newkey) { + // adapt the references + for (InsetIterator itt = inset_iterator_begin(in); itt != i_end; ++itt) { + if (itt->lyxCode() == CITE_CODE) { + InsetCommand & ref = dynamic_cast(*itt); + if (ref.getParam("key") == oldkey) + ref.setParam("key", newkey); + } + } + } + break; + } - for (; fpit != fend; ++fpit) { - InsetList::const_iterator it = fpit->insetList().begin(); - InsetList::const_iterator et = fpit->insetList().end(); - for (; it != et; ++it) - it->inset->setBuffer(const_cast(&buffer)); + default: + break; // nothing + } } insertion.swap(in.paragraphs()); @@ -317,15 +355,15 @@ PitPosPair eraseSelectionHelper(BufferParams const & params, } -void putClipboard(ParagraphList const & paragraphs, TextClassPtr textclass, - docstring const & plaintext) +void putClipboard(ParagraphList const & paragraphs, + DocumentClass const * const docclass, docstring const & plaintext) { // For some strange reason gcc 3.2 and 3.3 do not accept // Buffer buffer(string(), false); Buffer buffer("", false); buffer.setUnnamed(true); buffer.paragraphs() = paragraphs; - buffer.params().setTextClass(textclass); + buffer.params().setDocumentClass(docclass); ostringstream lyx; if (buffer.write(lyx)) theClipboard().put(lyx.str(), plaintext); @@ -336,11 +374,11 @@ void putClipboard(ParagraphList const & paragraphs, TextClassPtr textclass, void copySelectionHelper(Buffer const & buf, ParagraphList & pars, pit_type startpit, pit_type endpit, - int start, int end, TextClassPtr tc, CutStack & cutstack) + int start, int end, DocumentClass const * const dc, CutStack & cutstack) { - BOOST_ASSERT(0 <= start && start <= pars[startpit].size()); - BOOST_ASSERT(0 <= end && end <= pars[endpit].size()); - BOOST_ASSERT(startpit != endpit || start <= end); + LASSERT(0 <= start && start <= pars[startpit].size(), /**/); + LASSERT(0 <= end && end <= pars[endpit].size(), /**/); + LASSERT(startpit != endpit || start <= end, /**/); // Clone the paragraphs within the selection. ParagraphList copy_pars(boost::next(pars.begin(), startpit), @@ -372,7 +410,8 @@ void copySelectionHelper(Buffer const & buf, ParagraphList & pars, // do not copy text (also nested in insets) which is marked as deleted acceptChanges(copy_pars, buf.params()); - cutstack.push(make_pair(copy_pars, tc)); + DocumentClass * d = const_cast(dc); + cutstack.push(make_pair(copy_pars, d)); } } // namespace anon @@ -382,6 +421,22 @@ void copySelectionHelper(Buffer const & buf, ParagraphList & pars, namespace cap { +void region(CursorSlice const & i1, CursorSlice const & i2, + Inset::row_type & r1, Inset::row_type & r2, + Inset::col_type & c1, Inset::col_type & c2) +{ + Inset & 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); +} + + docstring grabAndEraseSelection(Cursor & cur) { if (!cur.selection()) @@ -392,25 +447,66 @@ docstring grabAndEraseSelection(Cursor & cur) } -void switchBetweenClasses(TextClassPtr const & oldone, - TextClassPtr const & newone, InsetText & in, ErrorList & errorlist) +bool reduceSelectionToOneCell(Cursor & cur) +{ + if (!cur.selection() || !cur.inMathed()) + return false; + + CursorSlice i1 = cur.selBegin(); + CursorSlice i2 = cur.selEnd(); + if (!i1.inset().asInsetMath()) + return false; + + // the easy case: do nothing if only one cell is selected + if (i1.idx() == i2.idx()) + return true; + + cur.top().pos() = 0; + cur.resetAnchor(); + cur.top().pos() = cur.top().lastpos(); + + return true; +} + + +bool multipleCellsSelected(Cursor const & cur) +{ + if (!cur.selection() || !cur.inMathed()) + return false; + + CursorSlice i1 = cur.selBegin(); + CursorSlice i2 = cur.selEnd(); + if (!i1.inset().asInsetMath()) + return false; + + if (i1.idx() == i2.idx()) + return false; + + return true; +} + + +void switchBetweenClasses(DocumentClass const * const oldone, + DocumentClass const * const newone, InsetText & in, ErrorList & errorlist) { errorlist.clear(); - BOOST_ASSERT(!in.paragraphs().empty()); + LASSERT(!in.paragraphs().empty(), /**/); if (oldone == newone) return; - TextClass const & oldtc = *oldone; - TextClass const & newtc = *newone; + DocumentClass const & oldtc = *oldone; + DocumentClass const & newtc = *newone; // layouts ParIterator end = par_iterator_end(in); for (ParIterator it = par_iterator_begin(in); it != end; ++it) { - docstring const name = it->layout()->name(); + docstring const name = it->layout().name(); bool hasLayout = newtc.hasLayout(name); - if (hasLayout) + if (in.useEmptyLayout()) + it->setLayout(newtc.emptyLayout()); + else if (hasLayout) it->setLayout(newtc[name]); else it->setLayout(newtc.defaultLayout()); @@ -419,7 +515,7 @@ void switchBetweenClasses(TextClassPtr const & oldone, 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"), - name, it->layout()->name(), + name, it->layout().name(), from_utf8(oldtc.name()), from_utf8(newtc.name())); // To warn the user that something had to be done. errorlist.push_back(ErrorItem(_("Changed Layout"), s, @@ -455,7 +551,7 @@ void switchBetweenClasses(TextClassPtr const & oldone, } -vector const availableSelections(Buffer const & buffer) +vector availableSelections() { vector selList; @@ -469,7 +565,7 @@ vector const availableSelections(Buffer const & buffer) ParagraphList::const_iterator pit = pars.begin(); ParagraphList::const_iterator pend = pars.end(); for (; pit != pend; ++pit) { - asciiSel += pit->asString(buffer, false); + asciiSel += pit->asString(AS_STR_INSETS); if (asciiSel.size() > 25) { asciiSel.replace(22, docstring::npos, from_ascii("...")); @@ -501,7 +597,7 @@ void cutSelection(Cursor & cur, bool doclear, bool realcut) if (cur.inTexted()) { Text * text = cur.text(); - BOOST_ASSERT(text); + LASSERT(text, /**/); saveSelection(cur); @@ -518,13 +614,16 @@ void cutSelection(Cursor & cur, bool doclear, bool realcut) text->paragraphs(), begpit, endpit, cur.selBegin().pos(), endpos, - bp.getTextClassPtr(), theCuts); + bp.documentClassPtr(), theCuts); // Stuff what we got on the clipboard. // Even if there is no selection. putClipboard(theCuts[0].first, theCuts[0].second, cur.selectionAsString(true)); } + if (begpit != endpit) + cur.updateFlags(Update::Force | Update::FitCursor); + boost::tie(endpit, endpos) = eraseSelectionHelper(bp, text->paragraphs(), @@ -587,7 +686,7 @@ void copySelectionToStack(Cursor & cur, CutStack & cutstack) if (cur.inTexted()) { Text * text = cur.text(); - BOOST_ASSERT(text); + LASSERT(text, /**/); // ok we have a selection. This is always between cur.selBegin() // and sel_end cursor @@ -602,7 +701,7 @@ void copySelectionToStack(Cursor & cur, CutStack & cutstack) copySelectionHelper(cur.buffer(), pars, par, cur.selEnd().pit(), pos, cur.selEnd().pos(), - cur.buffer().params().getTextClassPtr(), cutstack); + cur.buffer().params().documentClassPtr(), cutstack); dirtyTabularStack(false); } @@ -611,10 +710,11 @@ void copySelectionToStack(Cursor & cur, CutStack & cutstack) ParagraphList pars; Paragraph par; BufferParams const & bp = cur.buffer().params(); - par.setLayout(bp.getTextClass().defaultLayout()); + // FIXME This should be the empty layout...right? + par.setLayout(bp.documentClass().emptyLayout()); par.insert(0, grabSelection(cur), Font(), Change(Change::UNCHANGED)); pars.push_back(par); - cutstack.push(make_pair(pars, bp.getTextClassPtr())); + cutstack.push(make_pair(pars, bp.documentClassPtr())); } } @@ -638,10 +738,10 @@ void copySelection(Cursor & cur, docstring const & plaintext) ParagraphList pars; Paragraph par; BufferParams const & bp = cur.buffer().params(); - par.setLayout(bp.getTextClass().defaultLayout()); + par.setLayout(bp.documentClass().emptyLayout()); par.insert(0, plaintext, Font(), Change(Change::UNCHANGED)); pars.push_back(par); - theCuts.push(make_pair(pars, bp.getTextClassPtr())); + theCuts.push(make_pair(pars, bp.documentClassPtr())); } else { copySelectionToStack(cur, theCuts); } @@ -683,34 +783,33 @@ void clearCutStack() } -docstring getSelection(Buffer const & buf, size_t sel_index) +docstring selection(size_t sel_index) { return sel_index < theCuts.size() - ? theCuts[sel_index].first.back().asString(buf, false) + ? theCuts[sel_index].first.back().asString(AS_STR_INSETS) : docstring(); } void pasteParagraphList(Cursor & cur, ParagraphList const & parlist, - TextClassPtr textclass, ErrorList & errorList) + DocumentClass const * const docclass, ErrorList & errorList) { if (cur.inTexted()) { Text * text = cur.text(); - BOOST_ASSERT(text); + LASSERT(text, /**/); pit_type endpit; PitPosPair ppp; boost::tie(ppp, endpit) = - pasteSelectionHelper(cur, parlist, - textclass, errorList); + pasteSelectionHelper(cur, parlist, docclass, errorList); updateLabels(cur.buffer()); cur.clearSelection(); text->setCursor(cur, ppp.first, ppp.second); } // mathed is handled in InsetMathNest/InsetMathGrid - BOOST_ASSERT(!cur.inMathed()); + LASSERT(!cur.inMathed(), /**/); } @@ -746,7 +845,7 @@ void pasteClipboardText(Cursor & cur, ErrorList & errorList, bool asParagraphs) if (buffer.readString(lyx)) { cur.recordUndo(); pasteParagraphList(cur, buffer.paragraphs(), - buffer.params().getTextClassPtr(), errorList); + buffer.params().documentClassPtr(), errorList); cur.setSelection(); return; } @@ -765,10 +864,10 @@ void pasteClipboardText(Cursor & cur, ErrorList & errorList, bool asParagraphs) } -void pasteClipboardGraphics(Cursor & cur, ErrorList & errorList, +void pasteClipboardGraphics(Cursor & cur, ErrorList & /* errorList */, Clipboard::GraphicsType preferedType) { - BOOST_ASSERT(theClipboard().hasGraphicsContents(preferedType)); + LASSERT(theClipboard().hasGraphicsContents(preferedType), /**/); // get picture from clipboard FileName filename = theClipboard().getAsGraphics(cur, preferedType); @@ -776,9 +875,9 @@ void pasteClipboardGraphics(Cursor & cur, ErrorList & errorList, return; // create inset for graphic - InsetGraphics * inset = new InsetGraphics; + InsetGraphics * inset = new InsetGraphics(cur.buffer()); InsetGraphicsParams params; - params.filename = EmbeddedFile(filename.absFilename(), cur.buffer().filePath()); + params.filename = support::DocFileName(filename.absFilename()); inset->setParams(params); cur.recordUndo(); cur.insert(inset); @@ -888,8 +987,10 @@ docstring grabSelection(Cursor const & cur) if (!cur.selection()) return docstring(); - // FIXME: What is wrong with the following? #if 0 + // grab selection by glueing multiple cells together. This is not what + // we want because selections spanning multiple cells will get "&" and "\\" + // seperators. ostringstream os; for (DocIterator dit = cur.selectionBegin(); dit != cur.selectionEnd(); dit.forwardPos())