Am Mittwoch, 10. Januar 2007 10:39 schrieb Abdelrazak Younes:

> This I agree is a good goal. I was afraid that you intended to replaced 
> the internal Clipboard for all platforms. If that is not the case then I 
> think this will be a very good contribution to 1.5 new Clipboard 
> functionality. An html formatted Clipboard would be nice also.

I cleaned the patch up and tested it a bit more. The clipboard does now 
only go through a file if lyx2lyx is used. I also removed some debugging 
stuff and put the remaining one in an if(debugging), because that avoids 
some string conversions (fromqstr() etc).

Bennet, do you see any speed improvement? BTW it is normal that copy/paste 
to/from other apps looses formatting. We are not using html on the 
clipboard yet, I would prefer to wait with this until we use mime types 
for our formats.

José, can this version go in please?


Georg
Index: src/insets/insettabular.C
===================================================================
--- src/insets/insettabular.C	(Revision 16642)
+++ src/insets/insettabular.C	(Arbeitskopie)
@@ -723,7 +723,7 @@ void InsetTabular::doDispatch(LCursor & 
 	case LFUN_CLIPBOARD_PASTE:
 	case LFUN_PRIMARY_SELECTION_PASTE: {
 		docstring const clip = (cmd.action == LFUN_CLIPBOARD_PASTE) ?
-			theClipboard().get() :
+			theClipboard().getAsText() :
 			theSelection().get();
 		if (clip.empty())
 			break;
@@ -1814,10 +1814,13 @@ bool InsetTabular::copySelection(LCursor
 	odocstringstream os;
 	OutputParams const runparams;
 	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
 	// FIXME: this is a workaround for bug 1919. Should be removed for 1.5,
 	// when we (hopefully) have a one-for-all paste mechanism.
+	// This must be called after cap::copySelection.
 	dirtyTabularStack(true);
 
 	return true;
Index: src/mathed/InsetMathGrid.C
===================================================================
--- src/mathed/InsetMathGrid.C	(Revision 16642)
+++ src/mathed/InsetMathGrid.C	(Arbeitskopie)
@@ -1213,7 +1213,7 @@ void InsetMathGrid::doDispatch(LCursor &
 		cap::replaceSelection(cur);
 		docstring topaste;
 		if (cmd.argument().empty() && !theClipboard().isInternal())
-			topaste = theClipboard().get();
+			topaste = theClipboard().getAsText();
 		else {
 			idocstringstream is(cmd.argument());
 			int n = 0;
Index: src/mathed/InsetMathNest.C
===================================================================
--- src/mathed/InsetMathNest.C	(Revision 16642)
+++ src/mathed/InsetMathNest.C	(Arbeitskopie)
@@ -440,7 +440,7 @@ void InsetMathNest::doDispatch(LCursor &
 		replaceSelection(cur);
 		docstring topaste;
 		if (cmd.argument().empty() && !theClipboard().isInternal())
-			topaste = theClipboard().get();
+			topaste = theClipboard().getAsText();
 		else {
 			size_t n = 0;
 			idocstringstream is(cmd.argument());
Index: src/buffer.C
===================================================================
--- src/buffer.C	(Revision 16642)
+++ src/buffer.C	(Arbeitskopie)
@@ -566,6 +566,26 @@ void Buffer::insertStringAsLines(Paragra
 }
 
 
+bool Buffer::read(std::istream & is)
+{
+	params().compressed = false;
+
+	// remove dummy empty par
+	paragraphs().clear();
+	LyXLex lex(0, 0);
+	lex.setStream(is);
+	if (!readFile(lex, tempName()))
+		return false;
+
+	// 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)
 {
 	// Check if the file is compressed.
@@ -763,20 +783,20 @@ bool Buffer::writeFile(FileName const & 
 		if (!ofs)
 			return false;
 
-		retval = do_writeFile(ofs);
+		retval = write(ofs);
 	} else {
 		ofstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc);
 		if (!ofs)
 			return false;
 
-		retval = do_writeFile(ofs);
+		retval = write(ofs);
 	}
 
 	return retval;
 }
 
 
-bool Buffer::do_writeFile(ostream & ofs) const
+bool Buffer::write(ostream & ofs) const
 {
 #ifdef HAVE_LOCALE
 	// Use the standard "C" locale for file output.
Index: src/CutAndPaste.C
===================================================================
--- src/CutAndPaste.C	(Revision 16642)
+++ src/CutAndPaste.C	(Arbeitskopie)
@@ -26,6 +26,7 @@
 #include "insetiterator.h"
 #include "language.h"
 #include "lfuns.h"
+#include "lyxfunc.h"
 #include "lyxrc.h"
 #include "lyxtext.h"
 #include "lyxtextclasslist.h"
@@ -324,6 +325,21 @@ PitPosPair eraseSelectionHelper(BufferPa
 }
 
 
+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,
 	pit_type startpit, pit_type endpit,
 	int start, int end, textclass_type tc)
@@ -493,9 +509,6 @@ void cutSelection(LCursor & cur, bool do
 	if (cur.inTexted()) {
 		LyXText * text = cur.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
 		recordUndoSelection(cur);
@@ -511,6 +524,10 @@ void cutSelection(LCursor & cur, bool do
 				begpit, endpit,
 				cur.selBegin().pos(), endpos,
 				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) =
@@ -558,10 +575,16 @@ void cutSelection(LCursor & cur, bool do
 
 void copySelection(LCursor & cur)
 {
-	// stuff the selection onto the X clipboard, from an explicit copy request
-	theClipboard().put(cur.selectionAsString(true));
+	copySelection(cur, cur.selectionAsString(true));
+}
+
 
+void copySelection(LCursor & cur, docstring const & plaintext)
+{
 	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,39 @@ void pasteParagraphList(LCursor & cur, P
 }
 
 
+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);
+			std::istringstream is(lyx);
+			if (buffer.read(is)) {
+				recordUndo(cur);
+				pasteParagraphList(cur, buffer.paragraphs(),
+					buffer.params().textclass, errorList);
+				cur.setSelection();
+				return;
+			}
+		}
+	}
+
+	// Then try plain text
+	if (asParagraphs)
+		dispatch(FuncRequest(LFUN_PRIMARY_SELECTION_PASTE, "paragraph"));
+	else
+		dispatch(FuncRequest(LFUN_PRIMARY_SELECTION_PASTE));
+}
+
+
 void pasteSelection(LCursor & cur, ErrorList & errorList, size_t sel_index)
 {
 	// this does not make sense, if there is nothing to paste
Index: src/buffer.h
===================================================================
--- src/buffer.h	(Revision 16642)
+++ src/buffer.h	(Arbeitskopie)
@@ -98,6 +98,8 @@ public:
 	/// Load the autosaved file.
 	void loadAutoSaveFile();
 
+	/// read a new document from a stream
+	bool read(std::istream &);
 	/// load a new file
 	bool readFile(support::FileName const & filename);
 
@@ -143,6 +145,8 @@ public:
 	*/
 	bool save() const;
 
+	/// Write document to stream. Returns \c false if unsuccesful.
+	bool write(std::ostream &) const;
 	/// Write file. Returns \c false if unsuccesful.
 	bool writeFile(support::FileName const &) const;
 
@@ -387,8 +391,6 @@ private:
 	*/
 	bool readFile(LyXLex &, support::FileName const & filename);
 
-	bool do_writeFile(std::ostream & ofs) const;
-
 	/// Use the Pimpl idiom to hide the internals.
 	class Impl;
 	/// The pointer never changes although *pimpl_'s contents may.
Index: src/CutAndPaste.h
===================================================================
--- src/CutAndPaste.h	(Revision 16642)
+++ src/CutAndPaste.h	(Arbeitskopie)
@@ -62,9 +62,19 @@ void replaceSelection(LCursor & cur);
 void cutSelection(LCursor & cur, bool doclear = true, bool realcut = true);
 /// Push the current selection to the cut buffer and the system clipboard.
 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.
 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.
 void pasteSelection(LCursor & cur, ErrorList &, size_t sel_index = 0);
 
Index: src/frontends/Clipboard.h
===================================================================
--- src/frontends/Clipboard.h	(Revision 16642)
+++ src/frontends/Clipboard.h	(Arbeitskopie)
@@ -28,18 +28,29 @@ public:
 	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
 	 * 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
 	 * 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.
 	/// \retval true if the system clipboard has been set within LyX.
 	virtual bool isInternal() const = 0;
Index: src/frontends/qt4/GuiClipboard.C
===================================================================
--- src/frontends/qt4/GuiClipboard.C	(Revision 16642)
+++ src/frontends/qt4/GuiClipboard.C	(Arbeitskopie)
@@ -19,6 +19,7 @@
 
 #include <QApplication>
 #include <QClipboard>
+#include <QMimeData>
 #include <QString>
 
 #include "support/lstrings.h"
@@ -26,15 +27,50 @@ using lyx::support::internalLineEnding;
 using lyx::support::externalLineEnding;
 
 using std::endl;
+using std::string;
+
+
+namespace {
+
+char const * const mime_type = "application/x-lyx";
+
+}
+
 
 namespace lyx {
 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);
-	lyxerr[Debug::ACTION] << "GuiClipboard::get: " << fromqstr(str)
-	                      << endl;
+	if (lyxerr.debugging(Debug::ACTION))
+		lyxerr[Debug::ACTION] << "GuiClipboard::getAsText(): `"
+		                      << fromqstr(str) << "'" << endl;
 	if (str.isNull())
 		return docstring();
 
@@ -42,12 +78,31 @@ docstring const GuiClipboard::get() cons
 }
 
 
-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);
 }
 
 
Index: src/frontends/qt4/GuiClipboard.h
===================================================================
--- src/frontends/qt4/GuiClipboard.h	(Revision 16642)
+++ src/frontends/qt4/GuiClipboard.h	(Arbeitskopie)
@@ -30,8 +30,10 @@ public:
 	/** Clipboard overloaded methods
 	 */
 	//@{
-	docstring const get() const;
-	void put(docstring const & str);
+	std::string const getAsLyX() const;
+	docstring const getAsText() const;
+	void put(std::string const & lyx, docstring const & text);
+	bool hasLyXContents() const;
 	bool isInternal() const;
 	bool empty() const;
 	//@}
Index: src/text3.C
===================================================================
--- src/text3.C	(Revision 16642)
+++ src/text3.C	(Arbeitskopie)
@@ -76,6 +76,7 @@ namespace lyx {
 
 using cap::copySelection;
 using cap::cutSelection;
+using cap::pasteClipboard;
 using cap::pasteSelection;
 using cap::replaceSelection;
 
@@ -758,15 +759,15 @@ void LyXText::dispatch(LCursor & cur, Fu
 		cur.message(_("Paste"));
 		cap::replaceSelection(cur);
 		if (cmd.argument().empty() && !theClipboard().isInternal())
-			pasteString(cur, theClipboard().get(), true);
+			pasteClipboard(cur, bv->buffer()->errorList("Paste"));
 		else {
 			string const arg(to_utf8(cmd.argument()));
 			pasteSelection(cur, bv->buffer()->errorList("Paste"),
 					isStrUnsignedInt(arg) ?
 						convert<unsigned int>(arg) :
 						0);
-			bv->buffer()->errors("Paste");
 		}
+		bv->buffer()->errors("Paste");
 		cur.clearSelection(); // bug 393
 		bv->switchKeyMap();
 		finishUndo();
@@ -865,8 +866,10 @@ void LyXText::dispatch(LCursor & cur, Fu
 	}
 
 	case LFUN_CLIPBOARD_PASTE:
-		pasteString(cur, theClipboard().get(),
-		            cmd.argument() == "paragraph");
+		cur.clearSelection();
+		pasteClipboard(cur, bv->buffer()->errorList("Paste"),
+		               cmd.argument() == "paragraph");
+		bv->buffer()->errors("Paste");
 		break;
 
 	case LFUN_PRIMARY_SELECTION_PASTE:

Reply via email to