X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FCutAndPaste.cpp;h=f611d59395b8b9681b5a0d20c89435f1c684c52e;hb=c8230ab0d0a919530c43c29395f4d9961498bf15;hp=d5aa08712558b87578ec493fdb73224a564fefb6;hpb=e1492a3ab175588198664c803bf50188439937e7;p=lyx.git diff --git a/src/CutAndPaste.cpp b/src/CutAndPaste.cpp index d5aa087125..f611d59395 100644 --- a/src/CutAndPaste.cpp +++ b/src/CutAndPaste.cpp @@ -86,6 +86,8 @@ typedef limited_stack > CutStack; CutStack theCuts(10); // persistent selection, cleared until the next selection CutStack selectionBuffer(1); +// temporary scratch area +CutStack tempCut(1); // store whether the tabular stack is newer than the normal copy stack // FIXME: this is a workaround for bug 1919. Should be removed for 1.5, @@ -111,7 +113,7 @@ struct PasteReturnValue { PasteReturnValue pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, - DocumentClassConstPtr oldDocClass, Buffer * tmpbuffer, + DocumentClassConstPtr oldDocClass, cap::BranchAction branchAction, ErrorList & errorlist) { Buffer const & buffer = *cur.buffer(); @@ -157,6 +159,38 @@ 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) { + 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()) { @@ -192,6 +226,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(); @@ -241,7 +278,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 + // 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. it->setBuffer(const_cast(buffer)); @@ -355,12 +392,15 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, || (is_child && (branchlist.find(name) || buffer.masterBuffer()->params().branchlist().find(name)))) break; - if (tmpbuffer) { + switch(branchAction) { + case cap::BRANCH_ADD: { // This is for a temporary buffer, so simply create the branch. // Must not use lyx::dispatch(), since tmpbuffer has no view. DispatchResult dr; - tmpbuffer->dispatch(FuncRequest(LFUN_BRANCH_ADD, name), dr); - } else { + const_cast(buffer).dispatch(FuncRequest(LFUN_BRANCH_ADD, name), dr); + break; + } + case cap::BRANCH_ASK: { docstring text = bformat( _("The pasted branch \"%1$s\" is undefined.\n" "Do you want to add it to the document's branch list?"), @@ -369,6 +409,10 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, text, 0, 1, _("&Add"), _("&Don't Add")) != 0) break; lyx::dispatch(FuncRequest(LFUN_BRANCH_ADD, name)); + break; + } + case cap::BRANCH_IGNORE: + break; } // We need to update the list of branches. need_update = true; @@ -462,7 +506,7 @@ PitPosPair eraseSelectionHelper(BufferParams const & params, // Separate handling of paragraph break: if (merge && pit != endpit && - (pit + 1 != endpit + (pit + 1 != endpit || pars[pit].hasSameLayout(pars[endpit]) || pars[endpit].size() == endpos)) { if (pit + 1 == endpit) @@ -521,13 +565,13 @@ Buffer * copyToTempBuffer(ParagraphList const & paragraphs, DocumentClassConstPt // temporary Buffer, since it does a lot of things to fix them up. DocIterator dit = doc_iterator_begin(buffer, &buffer->inset()); ErrorList el; - pasteSelectionHelper(dit, paragraphs, docclass, buffer, el); + pasteSelectionHelper(dit, paragraphs, docclass, cap::BRANCH_ADD, el); return buffer; } -void putClipboard(ParagraphList const & paragraphs, +void putClipboard(ParagraphList const & paragraphs, DocumentClassConstPtr docclass, docstring const & plaintext) { Buffer * buffer = copyToTempBuffer(paragraphs, docclass); @@ -627,7 +671,7 @@ void copySelectionHelper(Buffer const & buf, Text const & text, // latex_language. This is invalid for others, so we // need to change it to the buffer language. if (it->isPassThru()) - it->changeLanguage(buf.params(), + it->changeLanguage(buf.params(), latex_language, buf.language()); } @@ -643,16 +687,14 @@ void copySelectionHelper(Buffer const & buf, Text const & text, // are not linked to something else. it = copy_pars.begin(); for (; it != it_end; ++it) { - it->setBuffer(*static_cast(0)); + it->resetBuffer(); it->setInsetOwner(0); } cutstack.push(make_pair(copy_pars, dc)); } -} // namespace anon - - +} // namespace namespace cap { @@ -696,11 +738,11 @@ bool reduceSelectionToOneCell(Cursor & cur) // 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; } @@ -709,15 +751,15 @@ 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; } @@ -730,7 +772,7 @@ void switchBetweenClasses(DocumentClassConstPtr oldone, LBUFERR(!in.paragraphs().empty()); if (oldone == newone) return; - + DocumentClass const & oldtc = *oldone; DocumentClass const & newtc = *newone; @@ -766,14 +808,14 @@ void switchBetweenClasses(DocumentClassConstPtr oldone, for (InsetIterator it = inset_iterator_begin(in); it != i_end; ++it) { InsetCode const code = it->lyxCode(); if (code == FLEX_CODE) { - // FIXME: Should we verify all InsetCollapsable? + // FIXME: Should we verify all InsetCollapsible? docstring const layoutName = it->layoutName(); docstring const & n = newone->insetLayout(layoutName).name(); bool const is_undefined = n.empty() || n == DocumentClass::plainInsetLayout().name(); if (!is_undefined) continue; - + // The flex inset is undefined in newtc docstring const oldname = from_utf8(oldtc.name()); docstring const newname = from_utf8(newtc.name()); @@ -839,8 +881,9 @@ size_type numberOfSelections() return theCuts.size(); } +namespace { -void cutSelection(Cursor & cur, bool doclear, bool realcut) +void cutSelectionHelper(Cursor & cur, CutStack & cuts, bool doclear, bool realcut, bool putclip) { // This doesn't make sense, if there is no selection if (!cur.selection()) @@ -868,11 +911,12 @@ void cutSelection(Cursor & cur, bool doclear, bool realcut) *text, begpit, endpit, cur.selBegin().pos(), endpos, - bp.documentClassPtr(), theCuts); + bp.documentClassPtr(), cuts); // Stuff what we got on the clipboard. // Even if there is no selection. - putClipboard(theCuts[0].first, theCuts[0].second, - cur.selectionAsString(true)); + if (putclip) + putClipboard(cuts[0].first, cuts[0].second, + cur.selectionAsString(true)); } if (begpit != endpit) @@ -922,6 +966,19 @@ void cutSelection(Cursor & cur, bool doclear, bool realcut) } } +} // namespace + +void cutSelection(Cursor & cur, bool doclear, bool realcut) +{ + cutSelectionHelper(cur, theCuts, doclear, realcut, true); +} + + +void cutSelectionToTemp(Cursor & cur, bool doclear, bool realcut) +{ + cutSelectionHelper(cur, tempCut, doclear, realcut, false); +} + void copySelection(Cursor const & cur) { @@ -964,7 +1021,7 @@ void copySelectionToStack(Cursor const & cur, CutStack & cutstack) // and sel_end cursor copySelectionHelper(*cur.buffer(), *text, cur.selBegin().pit(), cur.selEnd().pit(), - cur.selBegin().pos(), cur.selEnd().pos(), + cur.selBegin().pos(), cur.selEnd().pos(), cur.buffer()->params().documentClassPtr(), cutstack); // Reset the dirty_tabular_stack_ flag only when something @@ -986,7 +1043,7 @@ void copySelectionToStack(Cursor const & cur, CutStack & cutstack) } } -} +} // namespace void copySelectionToStack() @@ -1024,7 +1081,7 @@ void saveSelection(Cursor const & cur) // This function is called, not when a selection is formed, but when // a selection is cleared. Therefore, multiple keyboard selection // will not repeatively trigger this function (bug 3877). - if (cur.selection() + if (cur.selection() && cur.selBegin() == cur.bv().cursor().selBegin() && cur.selEnd() == cur.bv().cursor().selEnd()) { LYXERR(Debug::SELECTION, "saveSelection: '" << cur.selectionAsString(true) << "'"); @@ -1048,6 +1105,7 @@ void clearSelection() void clearCutStack() { theCuts.clear(); + tempCut.clear(); } @@ -1066,14 +1124,15 @@ docstring selection(size_t sel_index, DocumentClassConstPtr docclass) void pasteParagraphList(Cursor & cur, ParagraphList const & parlist, - DocumentClassConstPtr docclass, ErrorList & errorList) + DocumentClassConstPtr docclass, ErrorList & errorList, + cap::BranchAction branchAction) { if (cur.inTexted()) { Text * text = cur.text(); LBUFERR(text); PasteReturnValue prv = - pasteSelectionHelper(cur, parlist, docclass, 0, errorList); + pasteSelectionHelper(cur, parlist, docclass, branchAction, errorList); cur.forceBufferUpdate(); cur.clearSelection(); text->setCursor(cur, prv.pit, prv.pos); @@ -1092,7 +1151,20 @@ bool pasteFromStack(Cursor & cur, ErrorList & errorList, size_t sel_index) cur.recordUndo(); pasteParagraphList(cur, theCuts[sel_index].first, - theCuts[sel_index].second, errorList); + theCuts[sel_index].second, errorList, BRANCH_ASK); + return true; +} + + +bool pasteFromTemp(Cursor & cur, ErrorList & errorList) +{ + // this does not make sense, if there is nothing to paste + if (tempCut.empty() || tempCut[0].first.empty()) + return false; + + cur.recordUndo(); + pasteParagraphList(cur, tempCut[0].first, + tempCut[0].second, errorList, BRANCH_IGNORE); return true; }