X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FCutAndPaste.cpp;h=8e0a72d6dda5068d155af22cb8081521f1b8a120;hb=62af7ee772f16f154225d2d0b65d77f4376b6001;hp=d79ef5a655defd744cc98ac6adf26c561194d143;hpb=c466baaa5b99e44ea25616556bd0918197f4b54c;p=lyx.git diff --git a/src/CutAndPaste.cpp b/src/CutAndPaste.cpp index d79ef5a655..8e0a72d6dd 100644 --- a/src/CutAndPaste.cpp +++ b/src/CutAndPaste.cpp @@ -40,6 +40,7 @@ #include "insets/InsetBibitem.h" #include "insets/InsetBranch.h" +#include "insets/InsetCitation.h" #include "insets/InsetCommand.h" #include "insets/InsetFlex.h" #include "insets/InsetGraphics.h" @@ -124,10 +125,23 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, if (parlist.empty()) return PasteReturnValue(pit, pos, need_update); + // Check whether we paste into an inset that does not + // produce output (needed for label duplicate check) + bool in_active_inset = cur.paragraph().inInset().producesOutput(); + if (in_active_inset) { + for (size_type sl = 0 ; sl < cur.depth() ; ++sl) { + Paragraph const & outer_par = cur[sl].paragraph(); + if (!outer_par.inInset().producesOutput()) { + in_active_inset = false; + break; + } + } + } + InsetText * target_inset = cur.inset().asInsetText(); if (!target_inset) { InsetTabular * it = cur.inset().asInsetTabular(); - target_inset = it ? it->cell(cur.idx())->asInsetText() : 0; + target_inset = it ? it->cell(cur.idx())->asInsetText() : nullptr; } LASSERT(target_inset, return PasteReturnValue(pit, pos, need_update)); @@ -141,6 +155,14 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, // Now remove all out of the pars which is NOT allowed in the // new environment and set also another font if that is required. + // Merge paragraphs that are to be pasted into a text inset + // that does not allow multiple pars. + InsetText * inset_text = target_inset->asInsetText(); + if (inset_text && !inset_text->allowMultiPar()) { + while (insertion.size() > 1) + mergeParagraph(buffer.params(), insertion, 0); + } + // Convert newline to paragraph break in ParbreakIsNewline if (target_inset->getLayout().parbreakIsNewline() || pars[pit].layout().parbreak_is_newline) { @@ -159,6 +181,41 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, } } + // Prevent to paste uncodable characters in verbatim and ERT. + // The encoding is inherited from the context here. + docstring uncodable_content; + if (target_inset->getLayout().isPassThru() && cur.getEncoding()) { + odocstringstream res; + Encoding const * e = cur.getEncoding(); + for (size_t i = 0; i != insertion.size(); ++i) { + pos_type end = insertion[i].size(); + for (pos_type j = 0; j != end; ++j) { + // skip insets + if (insertion[i].isInset(j)) + continue; + char_type const c = insertion[i].getChar(j); + if (!e->encodable(c)) { + // do not track deletion + res.put(c); + insertion[i].eraseChar(j, false); + --end; + --j; + } + } + } + docstring const uncodable = res.str(); + if (!uncodable.empty()) { + if (uncodable.size() == 1) + uncodable_content = bformat(_("The character \"%1$s\" is uncodable in this verbatim context " + "and thus has not been pasted."), + uncodable); + else + uncodable_content = bformat(_("The characters \"%1$s\" are uncodable in this verbatim context " + "and thus have not been pasted."), + uncodable); + } + } + // set the paragraphs to plain layout if necessary DocumentClassConstPtr newDocClass = buffer.params().documentClassPtr(); if (cur.inset().usePlainLayout()) { @@ -194,6 +251,9 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, // want to invalidate them. insertion.swap(in.paragraphs()); cap::switchBetweenClasses(oldDocClass, newDocClass, in, errorlist); + // Do this here since switchBetweenClasses clears the errorlist + if (!uncodable_content.empty()) + errorlist.push_back(ErrorItem(_("Uncodable content"), uncodable_content)); insertion.swap(in.paragraphs()); ParagraphList::iterator tmpbuf = insertion.begin(); @@ -227,8 +287,9 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, tmpbuf->eraseChar(i--, false); } - tmpbuf->setChange(Change(buffer.params().track_changes ? - Change::INSERTED : Change::UNCHANGED)); + if (lyxrc.ct_markup_copied) + tmpbuf->setChange(Change(buffer.params().track_changes ? + Change::INSERTED : Change::UNCHANGED)); } bool const empty = pars[pit].empty(); @@ -244,8 +305,7 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, InsetIterator const i_end = inset_iterator_end(in); for (InsetIterator it = inset_iterator_begin(in); it != i_end; ++it) { // Even though this will also be done later, it has to be done here - // since some inset might going to try to access - // the buffer() member. + // since some inset might try to access the buffer() member. it->setBuffer(const_cast(buffer)); switch (it->lyxCode()) { @@ -258,7 +318,7 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, continue; InsetLabel * lab = labels[i]; docstring const oldname = lab->getParam("name"); - lab->updateLabel(oldname); + lab->updateLabel(oldname, in_active_inset); // We need to update the buffer reference cache. need_update = true; docstring const newname = lab->getParam("name"); @@ -289,7 +349,7 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, // check for duplicates InsetLabel & lab = static_cast(*it); docstring const oldname = lab.getParam("name"); - lab.updateLabel(oldname); + lab.updateLabel(oldname, in_active_inset); // We need to update the buffer reference cache. need_update = true; docstring const newname = lab.getParam("name"); @@ -322,6 +382,16 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, break; } + case CITE_CODE: { + InsetCitation & cit = static_cast(*it); + // This actually only needs to be done if the cite engine + // differs, but we do it in general. + cit.redoLabel(); + // We need to update the list of citations. + need_update = true; + break; + } + case BIBITEM_CODE: { // check for duplicates InsetBibitem & bib = static_cast(*it); @@ -422,7 +492,7 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, // Set paragraph buffers. It's important to do this right away // before something calls Inset::buffer() and causes a crash. for (pit_type p = startpit; p <= pit; ++p) - pars[p].setBuffer(const_cast(buffer)); + pars[p].setInsetBuffers(const_cast(buffer)); // Join (conditionally) last pasted paragraph with next one, i.e., // the tail of the spliced document paragraph @@ -510,7 +580,7 @@ Buffer * copyToTempBuffer(ParagraphList const & paragraphs, DocumentClassConstPt // Use a clone for the complicated stuff so that we do not need to clean // up in order to avoid a crash. Buffer * buffer = staticbuffer->cloneBufferOnly(); - LASSERT(buffer, return 0); + LASSERT(buffer, return nullptr); // This needs doing every time. // Since setDocumentClass() causes deletion of the old document class @@ -537,7 +607,8 @@ Buffer * copyToTempBuffer(ParagraphList const & paragraphs, DocumentClassConstPt void putClipboard(ParagraphList const & paragraphs, - DocumentClassConstPtr docclass, docstring const & plaintext) + DocumentClassConstPtr docclass, docstring const & plaintext, + BufferParams const bp) { Buffer * buffer = copyToTempBuffer(paragraphs, docclass); if (!buffer) // already asserted in copyToTempBuffer() @@ -548,6 +619,12 @@ void putClipboard(ParagraphList const & paragraphs, // applications, the number that can parse it should go up in the future. buffer->params().html_math_output = BufferParams::MathML; + if (lyxrc.ct_markup_copied) { + // Copy authors to the params. We need those pointers. + for (Author const & a : bp.authors()) + buffer->params().authors().record(a); + } + // Make sure MarkAsExporting is deleted before buffer is { // The Buffer is being used to export. This is necessary so that the @@ -631,7 +708,7 @@ void copySelectionHelper(Buffer const & buf, Text const & text, // do not have a proper buffer reference. It makes // sense to add them temporarily, because the // operations below depend on that (acceptChanges included). - it->setBuffer(const_cast(buf)); + it->setInsetBuffers(const_cast(buf)); // PassThru paragraphs have the Language // latex_language. This is invalid for others, so we // need to change it to the buffer language. @@ -642,10 +719,12 @@ void copySelectionHelper(Buffer const & buf, Text const & text, // do not copy text (also nested in insets) which is marked as // deleted, unless the whole selection was deleted - if (!isFullyDeleted(copy_pars)) - acceptChanges(copy_pars, buf.params()); - else - rejectChanges(copy_pars, buf.params()); + if (!lyxrc.ct_markup_copied) { + if (!isFullyDeleted(copy_pars)) + acceptChanges(copy_pars, buf.params()); + else + rejectChanges(copy_pars, buf.params()); + } // do some final cleanup now, to make sure that the paragraphs @@ -653,7 +732,7 @@ void copySelectionHelper(Buffer const & buf, Text const & text, it = copy_pars.begin(); for (; it != it_end; ++it) { it->resetBuffer(); - it->setInsetOwner(0); + it->setInsetOwner(nullptr); } cutstack.push(make_pair(copy_pars, dc)); @@ -690,7 +769,7 @@ docstring grabAndEraseSelection(Cursor & cur) } -bool reduceSelectionToOneCell(Cursor & cur) +bool reduceSelectionToOneCell(CursorData & cur) { if (!cur.selection() || !cur.inMathed()) return false; @@ -712,7 +791,7 @@ bool reduceSelectionToOneCell(Cursor & cur) } -bool multipleCellsSelected(Cursor const & cur) +bool multipleCellsSelected(CursorData const & cur) { if (!cur.selection() || !cur.inMathed()) return false; @@ -770,11 +849,11 @@ void switchBetweenClasses(DocumentClassConstPtr oldone, // character styles and hidden table cells InsetIterator const i_end = inset_iterator_end(in); - for (InsetIterator it = inset_iterator_begin(in); it != i_end; ++it) { - InsetCode const code = it->lyxCode(); + for (InsetIterator iit = inset_iterator_begin(in); iit != i_end; ++iit) { + InsetCode const code = iit->lyxCode(); if (code == FLEX_CODE) { // FIXME: Should we verify all InsetCollapsible? - docstring const layoutName = it->layoutName(); + docstring const layoutName = iit->layoutName(); docstring const & n = newone->insetLayout(layoutName).name(); bool const is_undefined = n.empty() || n == DocumentClass::plainInsetLayout().name(); @@ -795,14 +874,14 @@ void switchBetweenClasses(DocumentClassConstPtr oldone, // To warn the user that something had to be done. errorlist.push_back(ErrorItem( _("Undefined flex inset"), s, - {it.paragraph().id(), it.pos()}, - {it.paragraph().id(), it.pos()+1})); + {iit.paragraph().id(), iit.pos()}, + {iit.paragraph().id(), iit.pos() + 1})); } else if (code == TABULAR_CODE) { // The recursion above does not catch paragraphs in "hidden" cells, // i.e., ones that are part of a multirow or multicolum. So we need // to handle those separately. // This is the cause of bug #9049. - InsetTabular * table = it->asInsetTabular(); + InsetTabular * table = iit->asInsetTabular(); table->setLayoutForHiddenCells(newtc); } } @@ -827,7 +906,7 @@ vector availableSelections(Buffer const * buf) for (; pit != pend; ++pit) { Paragraph par(*pit, 0, 46); // adapt paragraph to current buffer. - par.setBuffer(const_cast(*buf)); + par.setInsetBuffers(const_cast(*buf)); textSel += par.asString(AS_STR_INSETS); if (textSel.size() > 45) { support::truncateWithEllipsis(textSel,45); @@ -848,7 +927,7 @@ size_type numberOfSelections() namespace { -void cutSelectionHelper(Cursor & cur, CutStack & cuts, bool doclear, bool realcut, bool putclip) +void cutSelectionHelper(Cursor & cur, CutStack & cuts, bool realcut, bool putclip) { // This doesn't make sense, if there is no selection if (!cur.selection()) @@ -881,7 +960,7 @@ void cutSelectionHelper(Cursor & cur, CutStack & cuts, bool doclear, bool realcu // Even if there is no selection. if (putclip) putClipboard(cuts[0].first, cuts[0].second, - cur.selectionAsString(true)); + cur.selectionAsString(true, true), bp); } if (begpit != endpit) @@ -897,11 +976,6 @@ void cutSelectionHelper(Cursor & cur, CutStack & cuts, bool doclear, bool realcu cur.pos() = endpos; cur.pit() = endpit; - // sometimes necessary - if (doclear - && text->paragraphs()[begpit].stripLeadingSpaces(bp.track_changes)) - cur.fixIfBroken(); - // need a valid cursor. (Lgb) cur.clearSelection(); @@ -933,21 +1007,21 @@ void cutSelectionHelper(Cursor & cur, CutStack & cuts, bool doclear, bool realcu } // namespace -void cutSelection(Cursor & cur, bool doclear, bool realcut) +void cutSelection(Cursor & cur, bool realcut) { - cutSelectionHelper(cur, theCuts, doclear, realcut, true); + cutSelectionHelper(cur, theCuts, realcut, true); } -void cutSelectionToTemp(Cursor & cur, bool doclear, bool realcut) +void cutSelectionToTemp(Cursor & cur, bool realcut) { - cutSelectionHelper(cur, tempCut, doclear, realcut, false); + cutSelectionHelper(cur, tempCut, realcut, false); } void copySelection(Cursor const & cur) { - copySelection(cur, cur.selectionAsString(true)); + copySelection(cur, cur.selectionAsString(true, true)); } @@ -963,13 +1037,13 @@ void copyInset(Cursor const & cur, Inset * inset, docstring const & plaintext) theCuts.push(make_pair(pars, bp.documentClassPtr())); // stuff the selection onto the X clipboard, from an explicit copy request - putClipboard(theCuts[0].first, theCuts[0].second, plaintext); + putClipboard(theCuts[0].first, theCuts[0].second, plaintext, bp); } 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()) @@ -1002,7 +1076,10 @@ void copySelectionToStack(Cursor const & cur, CutStack & cutstack) BufferParams const & bp = cur.buffer()->params(); // FIXME This should be the plain layout...right? par.setLayout(bp.documentClass().plainLayout()); - par.insert(0, grabSelection(cur), Font(), Change(Change::UNCHANGED)); + // For pasting into text, we set the language to the paragraph language + // (rather than the default_language which is always English; see #2596) + par.insert(0, grabSelection(cur), Font(sane_font, par.getParLanguage(bp)), + Change(Change::UNCHANGED)); pars.push_back(par); cutstack.push(make_pair(pars, bp.documentClassPtr())); } @@ -1018,6 +1095,12 @@ void copySelectionToStack() } +void copySelectionToTemp(Cursor & cur) +{ + copySelectionToStack(cur, tempCut); +} + + void copySelection(Cursor const & cur, docstring const & plaintext) { // In tablemode, because copy and paste actually use special table stack @@ -1037,7 +1120,8 @@ void copySelection(Cursor const & cur, docstring const & plaintext) } // stuff the selection onto the X clipboard, from an explicit copy request - putClipboard(theCuts[0].first, theCuts[0].second, plaintext); + putClipboard(theCuts[0].first, theCuts[0].second, plaintext, + cur.buffer()->params()); } @@ -1049,7 +1133,7 @@ void saveSelection(Cursor const & cur) if (cur.selection() && cur.selBegin() == cur.bv().cursor().selBegin() && cur.selEnd() == cur.bv().cursor().selEnd()) { - LYXERR(Debug::SELECTION, "saveSelection: '" << cur.selectionAsString(true) << "'"); + LYXERR(Debug::SELECTION, "saveSelection: '" << cur.selectionAsString(true, true) << "'"); copySelectionToStack(cur, selectionBuffer); } } @@ -1089,8 +1173,8 @@ docstring selection(size_t sel_index, DocumentClassConstPtr docclass) void pasteParagraphList(Cursor & cur, ParagraphList const & parlist, - DocumentClassConstPtr docclass, ErrorList & errorList, - cap::BranchAction branchAction) + DocumentClassConstPtr docclass, ErrorList & errorList, + cap::BranchAction branchAction) { if (cur.inTexted()) { Text * text = cur.text(); @@ -1190,6 +1274,10 @@ bool pasteClipboardText(Cursor & cur, ErrorList & errorList, bool asParagraphs, if (available) available = !buffer.paragraphs().empty(); if (available && !buffer.paragraphs()[0].empty()) { + // TeX2lyx (also used in the HTML chain) assumes English as document language + // if no language is explicitly set (as is the case here). + // We thus reset the temp buffer's language to the context language + buffer.changeLanguage(buffer.language(), cur.getFont().language()); cur.recordUndo(); pasteParagraphList(cur, buffer.paragraphs(), buffer.params().documentClassPtr(), errorList); @@ -1238,7 +1326,7 @@ void pasteSimpleText(Cursor & cur, bool asParagraphs) return; cur.recordUndo(); - cutSelection(cur, true, false); + cutSelection(cur, false); if (asParagraphs) cur.text()->insertStringAsParagraphs(cur, text, cur.current_font); else @@ -1294,14 +1382,14 @@ void replaceSelectionWithString(Cursor & cur, docstring const & str) par.insertChar(pos, *cit, font, cur.buffer()->params().track_changes); // Cut the selection - cutSelection(cur, true, false); + cutSelection(cur, false); } void replaceSelection(Cursor & cur) { if (cur.selection()) - cutSelection(cur, true, false); + cutSelection(cur, false); } @@ -1369,7 +1457,7 @@ void selClearOrDel(Cursor & cur) } -docstring grabSelection(Cursor const & cur) +docstring grabSelection(CursorData const & cur) { if (!cur.selection()) return docstring();