Fix bug 2138: copy and paste should preserve formatting between different

LyX instances. This re-enables copy/paste from the internal clipboard on
OS X (currently broken since Clipboard::isInternal() always returns false for
some reason).

	* src/insets/insettabular.C
	(InsetTabular::doDispatch): adjust to clipboard interface change
	(InsetTabular::copySelection): ditto

	* src/mathed/InsetMathGrid.C
	(InsetMathGrid::doDispatch): ditto

	* src/mathed/InsetMathNest.C
	(InsetMathNest::doDispatch): ditto

	* src/buffer.[Ch]
	(Buffer::readString): New method: Read document from a string
	(Buffer::readFile): Change return value from bool to enum (needed
	for readString). Return wrongversion if we are reading from a string
	and the version does not match.
	(Buffer::do_writeFile): make public and rename to write

	* src/CutAndPaste.C
	(putClipboard): New helper, put stuff to the system clipboard
	(void copySelectionHelper): Use putClipboard instead of
	theClipboard().put()
	(void copySelection): ditto
	(void pasteClipboard): new method for pasting in text
	(void pasteParagraphList):

	* src/frontends/Clipboard.h
	(Clipboard::get): Rename to getAsText
	(Clipboard::getAsLyX): New method for getting the system clipboard
	in LyX format
	(Clipboard::hasLyXContents): New method telling whether there is LyX
	contents in the clipboard

	* src/frontends/qt4/GuiClipboard.[Ch]: Implement the new methods

	* src/text3.C
	(LyXText::dispatch): Use pasteClipboard for pasting the system
	clipboard


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16669 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Georg Baum 2007-01-13 18:29:50 +00:00
parent e17b39d453
commit 3500af60ba
11 changed files with 235 additions and 43 deletions

View File

@ -26,6 +26,7 @@
#include "insetiterator.h" #include "insetiterator.h"
#include "language.h" #include "language.h"
#include "lfuns.h" #include "lfuns.h"
#include "lyxfunc.h"
#include "lyxrc.h" #include "lyxrc.h"
#include "lyxtext.h" #include "lyxtext.h"
#include "lyxtextclasslist.h" #include "lyxtextclasslist.h"
@ -324,6 +325,21 @@ PitPosPair eraseSelectionHelper(BufferParams const & params,
} }
void putClipboard(ParagraphList const & paragraphs, textclass_type textclass,
docstring const & plaintext)
{
Buffer buffer(string(), false);
buffer.setUnnamed(true);
buffer.paragraphs() = paragraphs;
buffer.params().textclass = textclass;
std::ostringstream lyx;
if (buffer.write(lyx))
theClipboard().put(lyx.str(), plaintext);
else
theClipboard().put(string(), plaintext);
}
void copySelectionHelper(Buffer const & buf, ParagraphList & pars, void copySelectionHelper(Buffer const & buf, ParagraphList & pars,
pit_type startpit, pit_type endpit, pit_type startpit, pit_type endpit,
int start, int end, textclass_type tc) int start, int end, textclass_type tc)
@ -493,9 +509,6 @@ void cutSelection(LCursor & cur, bool doclear, bool realcut)
if (cur.inTexted()) { if (cur.inTexted()) {
LyXText * text = cur.text(); LyXText * text = cur.text();
BOOST_ASSERT(text); BOOST_ASSERT(text);
// Stuff what we got on the clipboard. Even if there is no selection.
if (realcut)
theClipboard().put(cur.selectionAsString(true));
// make sure that the depth behind the selection are restored, too // make sure that the depth behind the selection are restored, too
recordUndoSelection(cur); recordUndoSelection(cur);
@ -511,6 +524,10 @@ void cutSelection(LCursor & cur, bool doclear, bool realcut)
begpit, endpit, begpit, endpit,
cur.selBegin().pos(), endpos, cur.selBegin().pos(), endpos,
bp.textclass); bp.textclass);
// Stuff what we got on the clipboard.
// Even if there is no selection.
putClipboard(theCuts[0].first, theCuts[0].second,
cur.selectionAsString(true));
} }
boost::tie(endpit, endpos) = boost::tie(endpit, endpos) =
@ -558,10 +575,16 @@ void cutSelection(LCursor & cur, bool doclear, bool realcut)
void copySelection(LCursor & cur) void copySelection(LCursor & cur)
{ {
// stuff the selection onto the X clipboard, from an explicit copy request copySelection(cur, cur.selectionAsString(true));
theClipboard().put(cur.selectionAsString(true)); }
void copySelection(LCursor & cur, docstring const & plaintext)
{
copySelectionToStack(cur); copySelectionToStack(cur);
// stuff the selection onto the X clipboard, from an explicit copy request
putClipboard(theCuts[0].first, theCuts[0].second, plaintext);
} }
@ -636,6 +659,42 @@ void pasteParagraphList(LCursor & cur, ParagraphList const & parlist,
} }
void pasteClipboard(LCursor & cur, ErrorList & errorList, bool asParagraphs)
{
// Use internal clipboard if it is the most recent one
if (theClipboard().isInternal()) {
pasteSelection(cur, errorList, 0);
return;
}
// First try LyX format
if (theClipboard().hasLyXContents()) {
string lyx = theClipboard().getAsLyX();
if (!lyx.empty()) {
Buffer buffer(string(), false);
buffer.setUnnamed(true);
if (buffer.readString(lyx)) {
recordUndo(cur);
pasteParagraphList(cur, buffer.paragraphs(),
buffer.params().textclass, errorList);
cur.setSelection();
return;
}
}
}
// Then try plain text
docstring const text = theClipboard().getAsText();
if (text.empty())
return;
recordUndo(cur);
if (asParagraphs)
cur.text()->insertStringAsParagraphs(cur, text);
else
cur.text()->insertStringAsLines(cur, text);
}
void pasteSelection(LCursor & cur, ErrorList & errorList, size_t sel_index) void pasteSelection(LCursor & cur, ErrorList & errorList, size_t sel_index)
{ {
// this does not make sense, if there is nothing to paste // this does not make sense, if there is nothing to paste

View File

@ -62,9 +62,19 @@ void replaceSelection(LCursor & cur);
void cutSelection(LCursor & cur, bool doclear = true, bool realcut = true); void cutSelection(LCursor & cur, bool doclear = true, bool realcut = true);
/// Push the current selection to the cut buffer and the system clipboard. /// Push the current selection to the cut buffer and the system clipboard.
void copySelection(LCursor & cur); void copySelection(LCursor & cur);
/**
* Push the current selection to the cut buffer and the system clipboard.
* \param plaintext plain text version of the selection for the system
* clipboard
*/
void copySelection(LCursor & cur, docstring const & plaintext);
/// Push the current selection to the cut buffer. /// Push the current selection to the cut buffer.
void copySelectionToStack(LCursor & cur); void copySelectionToStack(LCursor & cur);
/// Paste the sel_index-th element of the cut buffer. /// Replace the current selection with the clipboard contents (internal or
/// external: which is newer)
/// Does handle undo. Does only work in text, not mathed.
void pasteClipboard(LCursor & cur, ErrorList & errorList, bool asParagraphs = true);
/// Replace the current selection with cut buffer \c sel_index
/// Does handle undo. Does only work in text, not mathed. /// Does handle undo. Does only work in text, not mathed.
void pasteSelection(LCursor & cur, ErrorList &, size_t sel_index = 0); void pasteSelection(LCursor & cur, ErrorList &, size_t sel_index = 0);

View File

@ -566,6 +566,39 @@ void Buffer::insertStringAsLines(ParagraphList & pars,
} }
bool Buffer::readString(std::string const & s)
{
params().compressed = false;
// remove dummy empty par
paragraphs().clear();
LyXLex lex(0, 0);
std::istringstream is(s);
lex.setStream(is);
FileName const name(tempName());
switch (readFile(lex, name)) {
case failure:
return false;
case wrongversion: {
// We need to call lyx2lyx, so write the input to a file
std::ofstream os(name.toFilesystemEncoding().c_str());
os << s;
os.close();
return readFile(name) == success;
}
case success:
break;
}
// After we have read a file, we must ensure that the buffer
// language is set and used in the gui.
// If you know of a better place to put this, please tell me. (Lgb)
updateDocLang(params().language);
return true;
}
bool Buffer::readFile(FileName const & filename) bool Buffer::readFile(FileName const & filename)
{ {
// Check if the file is compressed. // Check if the file is compressed.
@ -578,7 +611,7 @@ bool Buffer::readFile(FileName const & filename)
paragraphs().clear(); paragraphs().clear();
LyXLex lex(0, 0); LyXLex lex(0, 0);
lex.setFile(filename); lex.setFile(filename);
if (!readFile(lex, filename)) if (readFile(lex, filename) != success)
return false; return false;
// After we have read a file, we must ensure that the buffer // After we have read a file, we must ensure that the buffer
@ -602,14 +635,15 @@ void Buffer::fully_loaded(bool const value)
} }
bool Buffer::readFile(LyXLex & lex, FileName const & filename) Buffer::ReadStatus Buffer::readFile(LyXLex & lex, FileName const & filename,
bool fromstring)
{ {
BOOST_ASSERT(!filename.empty()); BOOST_ASSERT(!filename.empty());
if (!lex.isOK()) { if (!lex.isOK()) {
Alert::error(_("Document could not be read"), Alert::error(_("Document could not be read"),
bformat(_("%1$s could not be read."), from_utf8(filename.absFilename()))); bformat(_("%1$s could not be read."), from_utf8(filename.absFilename())));
return false; return failure;
} }
lex.next(); lex.next();
@ -618,7 +652,7 @@ bool Buffer::readFile(LyXLex & lex, FileName const & filename)
if (!lex.isOK()) { if (!lex.isOK()) {
Alert::error(_("Document could not be read"), Alert::error(_("Document could not be read"),
bformat(_("%1$s could not be read."), from_utf8(filename.absFilename()))); bformat(_("%1$s could not be read."), from_utf8(filename.absFilename())));
return false; return failure;
} }
// the first token _must_ be... // the first token _must_ be...
@ -628,7 +662,7 @@ bool Buffer::readFile(LyXLex & lex, FileName const & filename)
Alert::error(_("Document format failure"), Alert::error(_("Document format failure"),
bformat(_("%1$s is not a LyX document."), bformat(_("%1$s is not a LyX document."),
from_utf8(filename.absFilename()))); from_utf8(filename.absFilename())));
return false; return failure;
} }
lex.next(); lex.next();
@ -643,6 +677,11 @@ bool Buffer::readFile(LyXLex & lex, FileName const & filename)
//lyxerr << "format: " << file_format << endl; //lyxerr << "format: " << file_format << endl;
if (file_format != LYX_FORMAT) { if (file_format != LYX_FORMAT) {
if (fromstring)
// lyx2lyx would fail
return wrongversion;
FileName const tmpfile(tempName()); FileName const tmpfile(tempName());
if (tmpfile.empty()) { if (tmpfile.empty()) {
Alert::error(_("Conversion failed"), Alert::error(_("Conversion failed"),
@ -651,7 +690,7 @@ bool Buffer::readFile(LyXLex & lex, FileName const & filename)
" file for converting it could" " file for converting it could"
" not be created."), " not be created."),
from_utf8(filename.absFilename()))); from_utf8(filename.absFilename())));
return false; return failure;
} }
FileName const lyx2lyx = libFileSearch("lyx2lyx", "lyx2lyx"); FileName const lyx2lyx = libFileSearch("lyx2lyx", "lyx2lyx");
if (lyx2lyx.empty()) { if (lyx2lyx.empty()) {
@ -661,7 +700,7 @@ bool Buffer::readFile(LyXLex & lex, FileName const & filename)
" conversion script lyx2lyx" " conversion script lyx2lyx"
" could not be found."), " could not be found."),
from_utf8(filename.absFilename()))); from_utf8(filename.absFilename())));
return false; return failure;
} }
ostringstream command; ostringstream command;
command << os::python() command << os::python()
@ -682,11 +721,11 @@ bool Buffer::readFile(LyXLex & lex, FileName const & filename)
" of LyX, but the lyx2lyx script" " of LyX, but the lyx2lyx script"
" failed to convert it."), " failed to convert it."),
from_utf8(filename.absFilename()))); from_utf8(filename.absFilename())));
return false; return failure;
} else { } else {
bool const ret = readFile(tmpfile); bool const ret = readFile(tmpfile);
// Do stuff with tmpfile name and buffer name here. // Do stuff with tmpfile name and buffer name here.
return ret; return ret ? success : failure;
} }
} }
@ -703,7 +742,7 @@ bool Buffer::readFile(LyXLex & lex, FileName const & filename)
//MacroTable::localMacros().clear(); //MacroTable::localMacros().clear();
pimpl_->file_fully_loaded = true; pimpl_->file_fully_loaded = true;
return true; return success;
} }
@ -763,20 +802,20 @@ bool Buffer::writeFile(FileName const & fname) const
if (!ofs) if (!ofs)
return false; return false;
retval = do_writeFile(ofs); retval = write(ofs);
} else { } else {
ofstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc); ofstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc);
if (!ofs) if (!ofs)
return false; return false;
retval = do_writeFile(ofs); retval = write(ofs);
} }
return retval; return retval;
} }
bool Buffer::do_writeFile(ostream & ofs) const bool Buffer::write(ostream & ofs) const
{ {
#ifdef HAVE_LOCALE #ifdef HAVE_LOCALE
// Use the standard "C" locale for file output. // Use the standard "C" locale for file output.

View File

@ -78,6 +78,13 @@ public:
buildlog ///< Literate build log buildlog ///< Literate build log
}; };
/// Result of \c readFile()
enum ReadStatus {
failure, ///< The file could not be read
success, ///< The file could not be read
wrongversion ///< The version of the file does not match ours
};
/** Constructor /** Constructor
\param file \param file
\param b optional \c false by default \param b optional \c false by default
@ -98,6 +105,8 @@ public:
/// Load the autosaved file. /// Load the autosaved file.
void loadAutoSaveFile(); void loadAutoSaveFile();
/// read a new document from a string
bool readString(std::string const &);
/// load a new file /// load a new file
bool readFile(support::FileName const & filename); bool readFile(support::FileName const & filename);
@ -143,6 +152,8 @@ public:
*/ */
bool save() const; bool save() const;
/// Write document to stream. Returns \c false if unsuccesful.
bool write(std::ostream &) const;
/// Write file. Returns \c false if unsuccesful. /// Write file. Returns \c false if unsuccesful.
bool writeFile(support::FileName const &) const; bool writeFile(support::FileName const &) const;
@ -386,9 +397,8 @@ private:
/** Inserts a file into a document /** Inserts a file into a document
\return \c false if method fails. \return \c false if method fails.
*/ */
bool readFile(LyXLex &, support::FileName const & filename); ReadStatus readFile(LyXLex &, support::FileName const & filename,
bool fromString = false);
bool do_writeFile(std::ostream & ofs) const;
/// Use the Pimpl idiom to hide the internals. /// Use the Pimpl idiom to hide the internals.
class Impl; class Impl;

View File

@ -28,18 +28,29 @@ public:
virtual ~Clipboard() {} virtual ~Clipboard() {}
/** /**
* Get the window system clipboard contents. * Get the system clipboard contents. The format is as written in
* .lyx files (may even be an older version than ours if it comes
* from an older LyX).
* Does not convert plain text to LyX if only plain text is available.
* This should be called when the user requests to paste from the * This should be called when the user requests to paste from the
* clipboard. * clipboard.
*/ */
virtual docstring const get() const = 0; virtual std::string const getAsLyX() const = 0;
/// Get the contents of the window system clipboard in plain text format.
virtual docstring const getAsText() const = 0;
/** /**
* Fill the window system clipboard. * Fill the system clipboard. The format of \p lyx is as written in
* .lyx files, the format of \p text is plain text.
* We put the clipboard contents in LyX format and plain text into
* the system clipboard if supported, so that it is useful for other
* applications as well as other instances of LyX.
* This should be called when the user requests to cut or copy to * This should be called when the user requests to cut or copy to
* the clipboard. * the clipboard.
*/ */
virtual void put(docstring const &) = 0; virtual void put(std::string const & lyx, docstring const & text) = 0;
/// Does the clipboard contain LyX contents?
virtual bool hasLyXContents() const = 0;
/// state of clipboard. /// state of clipboard.
/// \retval true if the system clipboard has been set within LyX. /// \retval true if the system clipboard has been set within LyX.
virtual bool isInternal() const = 0; virtual bool isInternal() const = 0;

View File

@ -19,6 +19,7 @@
#include <QApplication> #include <QApplication>
#include <QClipboard> #include <QClipboard>
#include <QMimeData>
#include <QString> #include <QString>
#include "support/lstrings.h" #include "support/lstrings.h"
@ -26,15 +27,50 @@ using lyx::support::internalLineEnding;
using lyx::support::externalLineEnding; using lyx::support::externalLineEnding;
using std::endl; using std::endl;
using std::string;
namespace {
char const * const mime_type = "application/x-lyx";
}
namespace lyx { namespace lyx {
namespace frontend { namespace frontend {
docstring const GuiClipboard::get() const string const GuiClipboard::getAsLyX() const
{ {
lyxerr[Debug::ACTION] << "GuiClipboard::getAsLyX(): `";
// We don't convert encodings here since the encoding of the
// clipboard contents is specified in the data itself
QMimeData const * source =
qApp->clipboard()->mimeData(QClipboard::Clipboard);
if (!source) {
lyxerr[Debug::ACTION] << "' (no QMimeData)" << endl;
return string();
}
if (source->hasFormat(mime_type)) {
// data from ourself or some other LyX instance
QByteArray const ar = source->data(mime_type);
string const s(ar.data(), ar.count());
if (lyxerr.debugging(Debug::ACTION))
lyxerr[Debug::ACTION] << s << "'" << endl;
return s;
}
lyxerr[Debug::ACTION] << "'" << endl;
return string();
}
docstring const GuiClipboard::getAsText() const
{
// text data from other applications
QString const str = qApp->clipboard()->text(QClipboard::Clipboard); QString const str = qApp->clipboard()->text(QClipboard::Clipboard);
lyxerr[Debug::ACTION] << "GuiClipboard::get: " << fromqstr(str) if (lyxerr.debugging(Debug::ACTION))
<< endl; lyxerr[Debug::ACTION] << "GuiClipboard::getAsText(): `"
<< fromqstr(str) << "'" << endl;
if (str.isNull()) if (str.isNull())
return docstring(); return docstring();
@ -42,12 +78,31 @@ docstring const GuiClipboard::get() const
} }
void GuiClipboard::put(docstring const & str) void GuiClipboard::put(string const & lyx, docstring const & text)
{ {
lyxerr[Debug::ACTION] << "GuiClipboard::put: " << lyx::to_utf8(str) << endl; if (lyxerr.debugging(Debug::ACTION))
lyxerr[Debug::ACTION] << "GuiClipboard::put(`" << lyx << "' `"
<< to_utf8(text) << "')" << endl;
// We don't convert the encoding of lyx since the encoding of the
// clipboard contents is specified in the data itself
QMimeData * data = new QMimeData;
if (!lyx.empty()) {
QByteArray const qlyx(lyx.c_str(), lyx.size());
data->setData(mime_type, qlyx);
}
// Don't test for text.empty() since we want to be able to clear the
// clipboard.
QString const qtext = toqstr(text);
data->setText(qtext);
qApp->clipboard()->setMimeData(data, QClipboard::Clipboard);
}
qApp->clipboard()->setText(toqstr(externalLineEnding(str)),
QClipboard::Clipboard); bool GuiClipboard::hasLyXContents() const
{
QMimeData const * const source =
qApp->clipboard()->mimeData(QClipboard::Clipboard);
return source && source->hasFormat(mime_type);
} }

View File

@ -30,8 +30,10 @@ public:
/** Clipboard overloaded methods /** Clipboard overloaded methods
*/ */
//@{ //@{
docstring const get() const; std::string const getAsLyX() const;
void put(docstring const & str); docstring const getAsText() const;
void put(std::string const & lyx, docstring const & text);
bool hasLyXContents() const;
bool isInternal() const; bool isInternal() const;
bool empty() const; bool empty() const;
//@} //@}

View File

@ -723,7 +723,7 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
case LFUN_CLIPBOARD_PASTE: case LFUN_CLIPBOARD_PASTE:
case LFUN_PRIMARY_SELECTION_PASTE: { case LFUN_PRIMARY_SELECTION_PASTE: {
docstring const clip = (cmd.action == LFUN_CLIPBOARD_PASTE) ? docstring const clip = (cmd.action == LFUN_CLIPBOARD_PASTE) ?
theClipboard().get() : theClipboard().getAsText() :
theSelection().get(); theSelection().get();
if (clip.empty()) if (clip.empty())
break; break;
@ -1814,10 +1814,13 @@ bool InsetTabular::copySelection(LCursor & cur)
odocstringstream os; odocstringstream os;
OutputParams const runparams; OutputParams const runparams;
paste_tabular->plaintext(cur.buffer(), os, runparams, 0, true, '\t'); paste_tabular->plaintext(cur.buffer(), os, runparams, 0, true, '\t');
theClipboard().put(os.str()); // Needed for the "Edit->Paste recent" menu and the system clipboard.
cap::copySelection(cur, os.str());
// mark tabular stack dirty // mark tabular stack dirty
// FIXME: this is a workaround for bug 1919. Should be removed for 1.5, // FIXME: this is a workaround for bug 1919. Should be removed for 1.5,
// when we (hopefully) have a one-for-all paste mechanism. // when we (hopefully) have a one-for-all paste mechanism.
// This must be called after cap::copySelection.
dirtyTabularStack(true); dirtyTabularStack(true);
return true; return true;

View File

@ -1213,7 +1213,7 @@ void InsetMathGrid::doDispatch(LCursor & cur, FuncRequest & cmd)
cap::replaceSelection(cur); cap::replaceSelection(cur);
docstring topaste; docstring topaste;
if (cmd.argument().empty() && !theClipboard().isInternal()) if (cmd.argument().empty() && !theClipboard().isInternal())
topaste = theClipboard().get(); topaste = theClipboard().getAsText();
else { else {
idocstringstream is(cmd.argument()); idocstringstream is(cmd.argument());
int n = 0; int n = 0;

View File

@ -440,7 +440,7 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
replaceSelection(cur); replaceSelection(cur);
docstring topaste; docstring topaste;
if (cmd.argument().empty() && !theClipboard().isInternal()) if (cmd.argument().empty() && !theClipboard().isInternal())
topaste = theClipboard().get(); topaste = theClipboard().getAsText();
else { else {
size_t n = 0; size_t n = 0;
idocstringstream is(cmd.argument()); idocstringstream is(cmd.argument());

View File

@ -76,6 +76,7 @@ namespace lyx {
using cap::copySelection; using cap::copySelection;
using cap::cutSelection; using cap::cutSelection;
using cap::pasteClipboard;
using cap::pasteSelection; using cap::pasteSelection;
using cap::replaceSelection; using cap::replaceSelection;
@ -758,15 +759,15 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
cur.message(_("Paste")); cur.message(_("Paste"));
cap::replaceSelection(cur); cap::replaceSelection(cur);
if (cmd.argument().empty() && !theClipboard().isInternal()) if (cmd.argument().empty() && !theClipboard().isInternal())
pasteString(cur, theClipboard().get(), true); pasteClipboard(cur, bv->buffer()->errorList("Paste"));
else { else {
string const arg(to_utf8(cmd.argument())); string const arg(to_utf8(cmd.argument()));
pasteSelection(cur, bv->buffer()->errorList("Paste"), pasteSelection(cur, bv->buffer()->errorList("Paste"),
isStrUnsignedInt(arg) ? isStrUnsignedInt(arg) ?
convert<unsigned int>(arg) : convert<unsigned int>(arg) :
0); 0);
bv->buffer()->errors("Paste");
} }
bv->buffer()->errors("Paste");
cur.clearSelection(); // bug 393 cur.clearSelection(); // bug 393
bv->switchKeyMap(); bv->switchKeyMap();
finishUndo(); finishUndo();
@ -865,8 +866,10 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd)
} }
case LFUN_CLIPBOARD_PASTE: case LFUN_CLIPBOARD_PASTE:
pasteString(cur, theClipboard().get(), cur.clearSelection();
cmd.argument() == "paragraph"); pasteClipboard(cur, bv->buffer()->errorList("Paste"),
cmd.argument() == "paragraph");
bv->buffer()->errors("Paste");
break; break;
case LFUN_PRIMARY_SELECTION_PASTE: case LFUN_PRIMARY_SELECTION_PASTE: