* \author Jürgen Vigna
* \author Lars Gullik Bjønnes
* \author Alfredo Braunstein
+ * \author Michael Gerz
*
* Full author contact details are available in file CREDITS.
*/
#include "insetiterator.h"
#include "language.h"
#include "lfuns.h"
+#include "lyxfunc.h"
#include "lyxrc.h"
#include "lyxtext.h"
#include "lyxtextclasslist.h"
#include "support/lstrings.h"
#include "frontends/Clipboard.h"
+#include "frontends/Selection.h"
#include <boost/tuple/tuple.hpp>
-
-namespace lyx {
-
-using support::bformat;
-using frontend::Clipboard;
+#include <string>
using std::endl;
using std::for_each;
using std::string;
+namespace lyx {
+
+using support::bformat;
+using frontend::Clipboard;
+
namespace {
typedef std::pair<pit_type, int> PitPosPair;
// 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,
// when we (hopefully) have a one-for-all paste mechanism.
-bool dirty_tabular_stack_;
+bool dirty_tabular_stack_ = false;
void region(CursorSlice const & i1, CursorSlice const & i2,
ParIterator fend = par_iterator_end(in);
for (; fpit != fend; ++fpit) {
- InsetList::iterator lit = fpit->insetlist.begin();
- InsetList::iterator eit = fpit->insetlist.end();
+ InsetList::const_iterator lit = fpit->insetlist.begin();
+ InsetList::const_iterator eit = fpit->insetlist.end();
for (; lit != eit; ++lit) {
switch (lit->inset->lyxCode()) {
pars[last_paste].makeSameLayout(pars[last_paste + 1]);
mergeParagraph(buffer.params(), pars, last_paste);
} else {
- pars[last_paste + 1].stripLeadingSpaces();
+ pars[last_paste + 1].stripLeadingSpaces(buffer.params().trackChanges);
++last_paste;
}
}
return PitPosPair(endpit, endpos);
}
- // A paragraph break has to be physically removed by merging, but
- // only if either (1) change tracking is off, or (2) the para break
- // is "blue"
for (pit_type pit = startpit; pit != endpit + 1;) {
- // FIXME: Change tracking (MG)
- bool const merge = !params.trackChanges ||
- pars[pit].isInserted(pars[pit].size());
pos_type const left = (pit == startpit ? startpos : 0);
pos_type const right = (pit == endpit ? endpos : pars[pit].size() + 1);
- // Logical erase only:
- pars[pit].eraseChars(left, right, false);
- // Separate handling of para break:
+
+ bool const merge = pars[pit].isMergedOnEndOfParDeletion(params.trackChanges);
+
+ // Logically erase only, including the end-of-paragraph character
+ pars[pit].eraseChars(left, right, params.trackChanges);
+
+ // Separate handling of paragraph break:
if (merge && pit != endpit &&
(pit + 1 != endpit || pars[pit].hasSameLayout(pars[pit + 1]))) {
pos_type const thissize = pars[pit].size();
if (doclear)
- pars[pit + 1].stripLeadingSpaces();
+ pars[pit + 1].stripLeadingSpaces(params.trackChanges);
mergeParagraph(params, pars, pit);
--endpit;
if (pit == endpit)
}
+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)
if (cur.inTexted()) {
LyXText * text = cur.text();
BOOST_ASSERT(text);
- // Stuff what we got on the clipboard. Even if there is no selection.
-
- // There is a problem with having the stuffing here in that the
- // larger the selection the slower LyX will get. This can be
- // solved by running the line below only when the selection has
- // finished. The solution used currently just works, to make it
- // faster we need to be more clever and probably also have more
- // calls to theSelection().put. (Lgb)
-// theSelection().put(cur.selectionAsString(true));
-
// make sure that the depth behind the selection are restored, too
recordUndoSelection(cur);
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) =
// sometimes necessary
if (doclear)
- text->paragraphs()[begpit].stripLeadingSpaces();
+ text->paragraphs()[begpit].stripLeadingSpaces(bp.trackChanges);
// cutSelection can invalidate the cursor so we need to set
// it anew. (Lgb)
// need a valid cursor. (Lgb)
cur.clearSelection();
updateLabels(cur.buffer());
+ theSelection().haveSelection(false);
// tell tabular that a recent copy happened
dirtyTabularStack(false);
void copySelection(LCursor & cur)
{
+ 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
- theClipboard().put(cur.selectionAsString(true));
+ putClipboard(theCuts[0].first, theCuts[0].second, plaintext);
+}
+
+void copySelectionToStack(LCursor & cur)
+{
// this doesn't make sense, if there is no selection
if (!cur.selection())
return;
textclass, errorList);
updateLabels(cur.buffer());
cur.clearSelection();
- text->setCursor(cur, ppp.first, ppp.second);
+ text->setCursor(cur.top(), ppp.first, ppp.second);
}
// mathed is handled in InsetMathNest/InsetMathGrid
}
+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)
{
// this does not make sense, if there is nothing to paste
}
-// simple replacing. The font of the first selected character is used
-void replaceSelectionWithString(LCursor & cur, string const & str, bool backwards)
+void replaceSelectionWithString(LCursor & cur, docstring const & str, bool backwards)
{
recordUndo(cur);
DocIterator selbeg = cur.selectionBegin();
// Insert the new string
pos_type pos = cur.selEnd().pos();
Paragraph & par = cur.selEnd().paragraph();
- string::const_iterator cit = str.begin();
- string::const_iterator end = str.end();
+ docstring::const_iterator cit = str.begin();
+ docstring::const_iterator end = str.end();
for (; cit != end; ++cit, ++pos)
- par.insertChar(pos, (*cit), font, cur.buffer().params().trackChanges);
+ par.insertChar(pos, *cit, font, cur.buffer().params().trackChanges);
// Cut the selection
cutSelection(cur, true, false);
void eraseSelection(LCursor & cur)
{
- //lyxerr << "LCursor::eraseSelection begin: " << cur << endl;
+ //lyxerr << "cap::eraseSelection begin: " << cur << endl;
CursorSlice const & i1 = cur.selBegin();
CursorSlice const & i2 = cur.selEnd();
if (i1.inset().asInsetMath()) {
}
// need a valid cursor. (Lgb)
cur.clearSelection();
+ theSelection().haveSelection(false);
} else {
lyxerr << "can't erase this selection 1" << endl;
}
- //lyxerr << "LCursor::eraseSelection end: " << cur << endl;
+ //lyxerr << "cap::eraseSelection end: " << cur << endl;
}
void selDel(LCursor & cur)
{
- //lyxerr << "LCursor::selDel" << endl;
+ //lyxerr << "cap::selDel" << endl;
if (cur.selection())
eraseSelection(cur);
}
void selClearOrDel(LCursor & cur)
{
- //lyxerr << "LCursor::selClearOrDel" << endl;
+ //lyxerr << "cap::selClearOrDel" << endl;
if (lyxrc.auto_region_delete)
selDel(cur);
else