* \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 "buffer.h"
#include "buffer_funcs.h"
#include "bufferparams.h"
-#include "BufferView.h"
#include "cursor.h"
#include "debug.h"
#include "errorlist.h"
#include "funcrequest.h"
#include "gettext.h"
#include "insetiterator.h"
+#include "language.h"
#include "lfuns.h"
+#include "lyxfunc.h"
#include "lyxrc.h"
#include "lyxtext.h"
#include "lyxtextclasslist.h"
#include "paragraph.h"
#include "paragraph_funcs.h"
#include "ParagraphParameters.h"
-#include "ParagraphList_fwd.h"
#include "pariterator.h"
#include "undo.h"
#include "insets/insetcharstyle.h"
#include "insets/insettabular.h"
-#include "mathed/math_data.h"
-#include "mathed/math_inset.h"
-#include "mathed/math_support.h"
+#include "mathed/MathData.h"
+#include "mathed/InsetMath.h"
+#include "mathed/MathSupport.h"
#include "support/lstrings.h"
-#include <boost/tuple/tuple.hpp>
+#include "frontends/Clipboard.h"
+#include "frontends/Selection.h"
-using lyx::pos_type;
-using lyx::pit_type;
-using lyx::textclass_type;
+#include <boost/current_function.hpp>
+#include <boost/tuple/tuple.hpp>
-using lyx::support::bformat;
+#include <string>
using std::endl;
using std::for_each;
using std::string;
+namespace lyx {
+
+using support::bformat;
+using frontend::Clipboard;
+
namespace {
-typedef std::pair<lyx::pit_type, int> PitPosPair;
+typedef std::pair<pit_type, int> PitPosPair;
typedef limited_stack<pair<ParagraphList, textclass_type> > CutStack;
CutStack theCuts(10);
+// persistent selection, cleared until the next selection
+CutStack selectionBuffer(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,
// when we (hopefully) have a one-for-all paste mechanism.
-bool dirty_tabular_stack_;
-
-class resetOwnerAndChanges : public std::unary_function<Paragraph, void> {
-public:
- void operator()(Paragraph & p) const {
- p.cleanChanges();
- p.setInsetOwner(0);
- }
-};
+bool dirty_tabular_stack_ = false;
void region(CursorSlice const & i1, CursorSlice const & i2,
pair<PitPosPair, pit_type>
-pasteSelectionHelper(Buffer const & buffer,
- ParagraphList & pars, pit_type pit, int pos,
- ParagraphList const & parlist, textclass_type textclass,
- ErrorList & errorlist)
+pasteSelectionHelper(LCursor & cur, ParagraphList const & parlist,
+ textclass_type textclass, ErrorList & errorlist)
{
+ Buffer const & buffer = cur.buffer();
+ pit_type pit = cur.pit();
+ pos_type pos = cur.pos();
+ ParagraphList & pars = cur.text()->paragraphs();
+
if (parlist.empty())
return make_pair(PitPosPair(pit, pos), pit);
for (ParagraphList::size_type i = 0; i < insertion.size(); ++i) {
for (pos_type j = 0; j < insertion[i].size(); ++j) {
if (insertion[i].isNewline(j)) {
- insertion[i].erase(j);
+ // do not track deletion of newline
+ insertion[i].eraseChar(j, false);
breakParagraphConservative(
buffer.params(),
insertion, i, j);
}
}
+ // If we are in an inset which returns forceDefaultParagraphs,
+ // set the paragraphs to default
+ if (cur.inset().forceDefaultParagraphs(cur.idx())) {
+ LyXLayout_ptr const layout =
+ buffer.params().getLyXTextClass().defaultLayout();
+ ParagraphList::iterator const end = insertion.end();
+ for (ParagraphList::iterator par = insertion.begin();
+ par != end; ++par)
+ par->layout(layout);
+ }
+
// Make sure there is no class difference.
- lyx::cap::SwitchBetweenClasses(textclass, tc, insertion, errorlist);
+ InsetText in;
+ // This works without copying any paragraph data because we have
+ // a specialized swap method for ParagraphList. This is important
+ // since we store pointers to insets at some places and we don't
+ // want to invalidate them.
+ insertion.swap(in.paragraphs());
+ cap::switchBetweenClasses(textclass, tc, in, errorlist);
+ insertion.swap(in.paragraphs());
ParagraphList::iterator tmpbuf = insertion.begin();
int depth_delta = pars[pit].params().depth() - tmpbuf->params().depth();
- Paragraph::depth_type max_depth = pars[pit].getMaxDepthAfter();
+ depth_type max_depth = pars[pit].getMaxDepthAfter();
for (; tmpbuf != insertion.end(); ++tmpbuf) {
// If we have a negative jump so that the depth would
for (pos_type i = 0; i < tmpbuf->size(); ++i) {
if (tmpbuf->getChar(i) == Paragraph::META_INSET &&
!pars[pit].insetAllowed(tmpbuf->getInset(i)->lyxCode()))
- tmpbuf->erase(i--);
+ // do not track deletion of invalid insets
+ tmpbuf->eraseChar(i--, false);
}
+
+ tmpbuf->setChange(Change(buffer.params().trackChanges ?
+ Change::INSERTED : Change::UNCHANGED));
}
bool const empty = pars[pit].empty();
// Prepare the paragraphs and insets for insertion.
// A couple of insets store buffer references so need updating.
- InsetText in;
- std::swap(in.paragraphs(), insertion);
+ insertion.swap(in.paragraphs());
ParIterator fpit = par_iterator_begin(in);
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()) {
}
}
}
- std::swap(in.paragraphs(), insertion);
+ insertion.swap(in.paragraphs());
// Split the paragraph for inserting the buf if necessary.
if (!empty)
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);
// Start and end is inside same paragraph
- if (endpit == pit_type(pars.size()) ||
- startpit == endpit) {
- endpos -= pars[startpit].erase(startpos, endpos);
+ if (endpit == pit_type(pars.size()) || startpit == endpit) {
+ endpos -= pars[startpit].eraseChars(startpos, endpos, params.trackChanges);
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;) {
- bool const merge = !params.tracking_changes ||
- pars[pit].lookupChange(pars[pit].size()) ==
- Change::INSERTED;
- pos_type const left = ( pit == startpit ? startpos : 0 );
- pos_type const right = ( pit == endpit ? endpos :
- pars[pit].size() + 1 );
- // Logical erase only:
- pars[pit].erase(left, right);
- // Separate handling of para break:
+ pos_type const left = (pit == startpit ? startpos : 0);
+ pos_type const right = (pit == endpit ? endpos : pars[pit].size() + 1);
+
+ 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 &&
- pars[pit].hasSameLayout(pars[pit + 1])) {
+ (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 copySelectionHelper(ParagraphList & pars,
+void putClipboard(ParagraphList const & paragraphs, textclass_type textclass,
+ docstring const & plaintext)
+{
+ // For some strange reason gcc 3.2 and 3.3 do not accept
+ // Buffer buffer(string(), false);
+ Buffer buffer("", 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)
+ int start, int end, textclass_type tc, CutStack & cutstack)
{
BOOST_ASSERT(0 <= start && start <= pars[startpit].size());
BOOST_ASSERT(0 <= end && end <= pars[endpit].size());
BOOST_ASSERT(startpit != endpit || start <= end);
// Clone the paragraphs within the selection.
- ParagraphList paragraphs(boost::next(pars.begin(), startpit),
- boost::next(pars.begin(), endpit + 1));
-
- for_each(paragraphs.begin(), paragraphs.end(), resetOwnerAndChanges());
-
- // Cut out the end of the last paragraph.
- Paragraph & back = paragraphs.back();
- back.erase(end, back.size());
+ ParagraphList copy_pars(boost::next(pars.begin(), startpit),
+ boost::next(pars.begin(), endpit + 1));
+
+ // Remove the end of the last paragraph; afterwards, remove the beginning
+ // of the first paragraph. Keep this order - there may only be one paragraph!
+ // Do not track deletions here; this is an internal action not visible to the user
+ Paragraph & back = copy_pars.back();
+ back.eraseChars(end, back.size(), false);
+ Paragraph & front = copy_pars.front();
+ front.eraseChars(0, start, false);
+
+ ParagraphList::iterator it = copy_pars.begin();
+ ParagraphList::iterator it_end = copy_pars.end();
+
+ for (; it != it_end; it++) {
+ // ERT paragraphs have the Language latex_language.
+ // This is invalid outside of ERT, so we need to change it
+ // to the buffer language.
+ if (it->ownerCode() == InsetBase::ERT_CODE) {
+ it->changeLanguage(buf.params(), latex_language,
+ buf.getLanguage());
+ }
+ it->setInsetOwner(0);
+ }
- // Cut out the begin of the first paragraph
- Paragraph & front = paragraphs.front();
- front.erase(0, start);
+ // do not copy text (also nested in insets) which is marked as deleted
+ // acceptChanges() is defined for LyXText rather than ParagraphList
+ // Thus we must wrap copy_pars into a LyXText object and cross our fingers
+ LyXText lt;
+ copy_pars.swap(lt.paragraphs());
+ lt.acceptChanges(buf.params());
+ copy_pars.swap(lt.paragraphs());
- theCuts.push(make_pair(paragraphs, tc));
+ cutstack.push(make_pair(copy_pars, tc));
}
} // namespace anon
-namespace lyx {
namespace cap {
-string grabAndEraseSelection(LCursor & cur)
+docstring grabAndEraseSelection(LCursor & cur)
{
if (!cur.selection())
- return string();
- string res = grabSelection(cur);
+ return docstring();
+ docstring res = grabSelection(cur);
eraseSelection(cur);
return res;
}
-void SwitchBetweenClasses(textclass_type c1, textclass_type c2,
- ParagraphList & pars, ErrorList & errorlist)
+void switchBetweenClasses(textclass_type c1, textclass_type c2,
+ InsetText & in, ErrorList & errorlist)
{
- BOOST_ASSERT(!pars.empty());
+ BOOST_ASSERT(!in.paragraphs().empty());
if (c1 == c2)
return;
LyXTextClass const & tclass1 = textclasslist[c1];
LyXTextClass const & tclass2 = textclasslist[c2];
- InsetText in;
- std::swap(in.paragraphs(), pars);
-
// layouts
ParIterator end = par_iterator_end(in);
for (ParIterator it = par_iterator_begin(in); it != end; ++it) {
it->layout(tclass2.defaultLayout());
if (!hasLayout && name != tclass1.defaultLayoutName()) {
- string const s = bformat(
- _("Layout had to be changed from\n%1$s to %2$s\n"
- "because of class conversion from\n%3$s to %4$s"),
- name, it->layout()->name(), tclass1.name(), tclass2.name());
+ docstring const s = bformat(
+ _("Layout had to be changed from\n%1$s to %2$s\n"
+ "because of class conversion from\n%3$s to %4$s"),
+ from_utf8(name), from_utf8(it->layout()->name()),
+ from_utf8(tclass1.name()), from_utf8(tclass2.name()));
// To warn the user that something had to be done.
errorlist.push_back(ErrorItem(_("Changed Layout"), s,
it->id(), 0,
if (found_cs == tclass2.charstyles().end()) {
// The character style is undefined in tclass2
inset.setUndefined();
- string const s = bformat(_(
+ docstring const s = bformat(_(
"Character style %1$s is "
"undefined because of class "
"conversion from\n%2$s to %3$s"),
- name, tclass1.name(), tclass2.name());
+ from_utf8(name), from_utf8(tclass1.name()),
+ from_utf8(tclass2.name()));
// To warn the user that something had to be done.
errorlist.push_back(ErrorItem(
- _("Undefined character style"),
- s, it.paragraph().id(),
- it.pos(), it.pos() + 1));
+ _("Undefined character style"),
+ s, it.paragraph().id(), it.pos(), it.pos() + 1));
} else if (inset.undefined()) {
// The character style is undefined in
// tclass1 and is defined in tclass2
}
}
}
-
- std::swap(in.paragraphs(), pars);
}
-std::vector<string> const availableSelections(Buffer const & buffer)
+std::vector<docstring> const availableSelections(Buffer const & buffer)
{
- vector<string> selList;
+ vector<docstring> selList;
CutStack::const_iterator cit = theCuts.begin();
CutStack::const_iterator end = theCuts.end();
// we do not use cit-> here because gcc 2.9x does not
// like it (JMarc)
ParagraphList const & pars = (*cit).first;
- string asciiSel;
+ docstring asciiSel;
ParagraphList::const_iterator pit = pars.begin();
ParagraphList::const_iterator pend = pars.end();
for (; pit != pend; ++pit) {
asciiSel += pit->asString(buffer, false);
if (asciiSel.size() > 25) {
- asciiSel.replace(22, string::npos, "...");
+ asciiSel.replace(22, docstring::npos,
+ from_ascii("..."));
break;
}
}
}
-lyx::size_type numberOfSelections()
+size_type numberOfSelections()
{
return theCuts.size();
}
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 stuffClipboard. (Lgb)
-// cur.bv().stuffClipboard(cur.selectionAsString(true));
// make sure that the depth behind the selection are restored, too
recordUndoSelection(cur);
BufferParams const & bp = cur.buffer().params();
if (realcut) {
- copySelectionHelper(text->paragraphs(),
+ copySelectionHelper(cur.buffer(),
+ text->paragraphs(),
begpit, endpit,
cur.selBegin().pos(), endpos,
- bp.textclass);
+ bp.textclass, theCuts);
+ // 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) =
cur.selBegin().pos(), endpos,
doclear);
- // sometimes necessary
- if (doclear)
- text->paragraphs()[begpit].stripLeadingSpaces();
-
// cutSelection can invalidate the cursor so we need to set
// it anew. (Lgb)
// we prefer the end for when tracking changes
cur.pos() = endpos;
cur.pit() = endpit;
+ // sometimes necessary
+ if (doclear
+ && text->paragraphs()[begpit].stripLeadingSpaces(bp.trackChanges))
+ cur.fixIfBroken();
+
// need a valid cursor. (Lgb)
cur.clearSelection();
- updateCounters(cur.buffer());
+ updateLabels(cur.buffer());
+ theSelection().haveSelection(false);
// tell tabular that a recent copy happened
dirtyTabularStack(false);
void copySelection(LCursor & cur)
{
- // stuff the selection onto the X clipboard, from an explicit copy request
- cur.bv().stuffClipboard(cur.selectionAsString(true));
+ copySelection(cur, cur.selectionAsString(true));
+}
+
+namespace {
+
+void copySelectionToStack(LCursor & cur, CutStack & cutstack)
+{
// this doesn't make sense, if there is no selection
if (!cur.selection())
return;
ParagraphList & pars = text->paragraphs();
pos_type pos = cur.selBegin().pos();
pit_type par = cur.selBegin().pit();
- while (pos < pars[par].size()
- && pars[par].isLineSeparator(pos)
- && (par != cur.selEnd().pit() || pos < cur.selEnd().pos()))
+ while (pos < pars[par].size() &&
+ pars[par].isLineSeparator(pos) &&
+ (par != cur.selEnd().pit() || pos < cur.selEnd().pos()))
++pos;
- copySelectionHelper(pars, par, cur.selEnd().pit(),
- pos, cur.selEnd().pos(), cur.buffer().params().textclass);
+ copySelectionHelper(cur.buffer(), pars, par, cur.selEnd().pit(),
+ pos, cur.selEnd().pos(), cur.buffer().params().textclass, cutstack);
}
if (cur.inMathed()) {
- lyxerr << "copySelection in mathed" << endl;
+ //lyxerr << "copySelection in mathed" << endl;
ParagraphList pars;
- pars.push_back(Paragraph());
+ Paragraph par;
BufferParams const & bp = cur.buffer().params();
- pars.back().layout(bp.getLyXTextClass().defaultLayout());
- for_each(pars.begin(), pars.end(), resetOwnerAndChanges());
- pars.back().insert(0, grabSelection(cur), LyXFont());
- theCuts.push(make_pair(pars, bp.textclass));
+ par.layout(bp.getLyXTextClass().defaultLayout());
+ par.insert(0, grabSelection(cur), LyXFont(), Change(Change::UNCHANGED));
+ pars.push_back(par);
+ cutstack.push(make_pair(pars, bp.textclass));
}
- // tell tabular that a recent copy happened
- dirtyTabularStack(false);
+}
+
+}
+
+
+void copySelectionToStack()
+{
+ if (!selectionBuffer.empty())
+ theCuts.push(selectionBuffer[0]);
}
-std::string getSelection(Buffer const & buf, size_t sel_index)
+void copySelection(LCursor & cur, docstring const & plaintext)
+{
+ // In tablemode, because copy and paste actually use special table stack
+ // we do not attemp to get selected paragraphs under cursor. Instead, a
+ // paragraph with the plain text version is generated so that table cells
+ // can be pasted as pure text somewhere else.
+ if (cur.selBegin().idx() != cur.selEnd().idx()) {
+ ParagraphList pars;
+ Paragraph par;
+ BufferParams const & bp = cur.buffer().params();
+ par.layout(bp.getLyXTextClass().defaultLayout());
+ par.insert(0, plaintext, LyXFont(), Change(Change::UNCHANGED));
+ pars.push_back(par);
+ theCuts.push(make_pair(pars, bp.textclass));
+ } else
+ copySelectionToStack(cur, theCuts);
+
+ // stuff the selection onto the X clipboard, from an explicit copy request
+ putClipboard(theCuts[0].first, theCuts[0].second, plaintext);
+}
+
+
+void saveSelection(LCursor & cur)
+{
+ LYXERR(Debug::ACTION) << BOOST_CURRENT_FUNCTION << ": `"
+ << to_utf8(cur.selectionAsString(true)) << "'."
+ << endl;
+
+ if (cur.selection())
+ copySelectionToStack(cur, selectionBuffer);
+ // tell X whether we now have a valid selection
+ theSelection().haveSelection(cur.selection());
+}
+
+
+bool selection()
+{
+ return !selectionBuffer.empty();
+}
+
+
+void clearSelection()
+{
+ selectionBuffer.clear();
+}
+
+
+docstring getSelection(Buffer const & buf, size_t sel_index)
{
return sel_index < theCuts.size()
? theCuts[sel_index].first.back().asString(buf, false)
- : string();
+ : docstring();
}
void pasteParagraphList(LCursor & cur, ParagraphList const & parlist,
- textclass_type textclass)
+ textclass_type textclass, ErrorList & errorList)
{
if (cur.inTexted()) {
LyXText * text = cur.text();
BOOST_ASSERT(text);
- recordUndo(cur);
-
pit_type endpit;
PitPosPair ppp;
- ErrorList el;
boost::tie(ppp, endpit) =
- pasteSelectionHelper(cur.buffer(),
- text->paragraphs(),
- cur.pit(), cur.pos(),
- parlist, textclass,
- el);
- bufferErrors(cur.buffer(), el);
- updateCounters(cur.buffer());
+ pasteSelectionHelper(cur, parlist,
+ 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 MathNestInset/MathGridInset
+ // mathed is handled in InsetMathNest/InsetMathGrid
BOOST_ASSERT(!cur.inMathed());
}
-void pasteSelection(LCursor & cur, size_t sel_index)
+void pasteFromStack(LCursor & cur, ErrorList & errorList, size_t sel_index)
{
// this does not make sense, if there is nothing to paste
if (!checkPastePossible(sel_index))
return;
+ recordUndo(cur);
pasteParagraphList(cur, theCuts[sel_index].first,
- theCuts[sel_index].second);
- cur.bv().showErrorList(_("Paste"));
+ theCuts[sel_index].second, errorList);
cur.setSelection();
+ saveSelection(cur);
+}
+
+
+void pasteClipboard(LCursor & cur, ErrorList & errorList, bool asParagraphs)
+{
+ // Use internal clipboard if it is the most recent one
+ if (theClipboard().isInternal()) {
+ pasteFromStack(cur, errorList, 0);
+ return;
+ }
+
+ // First try LyX format
+ if (theClipboard().hasLyXContents()) {
+ string lyx = theClipboard().getAsLyX();
+ if (!lyx.empty()) {
+ // For some strange reason gcc 3.2 and 3.3 do not accept
+ // Buffer buffer(string(), false);
+ Buffer buffer("", 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 setSelectionRange(LCursor & cur, pos_type length)
+void pasteSelection(LCursor & cur, ErrorList & errorList)
{
- LyXText * text = cur.text();
- BOOST_ASSERT(text);
- if (!length)
+ if (selectionBuffer.empty())
return;
- cur.resetAnchor();
- while (length--)
- text->cursorRight(cur);
+ recordUndo(cur);
+ pasteParagraphList(cur, selectionBuffer[0].first,
+ selectionBuffer[0].second, errorList);
cur.setSelection();
}
-// simple replacing. The font of the first selected character is used
-void replaceSelectionWithString(LCursor & cur, string const & str)
+void replaceSelectionWithString(LCursor & cur, docstring const & str, bool backwards)
{
- LyXText * text = cur.text();
- BOOST_ASSERT(text);
recordUndo(cur);
+ DocIterator selbeg = cur.selectionBegin();
// Get font setting before we cut
- pos_type pos = cur.selEnd().pos();
- Paragraph & par = text->getPar(cur.selEnd().pit());
LyXFont const font =
- par.getFontSettings(cur.buffer().params(), cur.selBegin().pos());
+ selbeg.paragraph().getFontSettings(cur.buffer().params(), selbeg.pos());
// Insert the new string
- string::const_iterator cit = str.begin();
- string::const_iterator end = str.end();
+ pos_type pos = cur.selEnd().pos();
+ Paragraph & par = cur.selEnd().paragraph();
+ docstring::const_iterator cit = str.begin();
+ docstring::const_iterator end = str.end();
for (; cit != end; ++cit, ++pos)
- par.insertChar(pos, (*cit), font);
+ par.insertChar(pos, *cit, font, cur.buffer().params().trackChanges);
// Cut the selection
cutSelection(cur, true, false);
+
+ // select the replacement
+ if (backwards) {
+ selbeg.pos() += str.length();
+ cur.setSelection(selbeg, -int(str.length()));
+ } else
+ cur.setSelection(selbeg, str.length());
+ saveSelection(cur);
}
}
-// only used by the spellchecker
-void replaceWord(LCursor & cur, string const & replacestring)
-{
- LyXText * text = cur.text();
- BOOST_ASSERT(text);
-
- replaceSelectionWithString(cur, replacestring);
- setSelectionRange(cur, replacestring.length());
-
- // Go back so that replacement string is also spellchecked
- for (string::size_type i = 0; i < replacestring.length() + 1; ++i)
- text->cursorLeft(cur);
-}
-
-
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().asMathInset()) {
+ if (i1.inset().asInsetMath()) {
cur.top() = i1;
if (i1.idx() == i2.idx()) {
i1.cell().erase(i1.pos(), i2.pos());
if (cur.pos() > cur.lastpos())
cur.pos() = cur.lastpos();
} else {
- MathInset * p = i1.asMathInset();
+ InsetMath * p = i1.asInsetMath();
InsetBase::row_type r1, r2;
InsetBase::col_type c1, c2;
region(i1, i2, r1, r2, c1, c2);
}
// 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
}
-string grabSelection(LCursor const & cur)
+docstring grabSelection(LCursor const & cur)
{
if (!cur.selection())
- return string();
+ return docstring();
// FIXME: What is wrong with the following?
#if 0
CursorSlice i2 = cur.selEnd();
if (i1.idx() == i2.idx()) {
- if (i1.inset().asMathInset()) {
+ if (i1.inset().asInsetMath()) {
MathArray::const_iterator it = i1.cell().begin();
return asString(MathArray(it + i1.pos(), it + i2.pos()));
} else {
- return "unknown selection 1";
+ return from_ascii("unknown selection 1");
}
}
InsetBase::col_type c1, c2;
region(i1, i2, r1, r2, c1, c2);
- string data;
- if (i1.inset().asMathInset()) {
+ docstring data;
+ if (i1.inset().asInsetMath()) {
for (InsetBase::row_type row = r1; row <= r2; ++row) {
if (row > r1)
data += "\\\\";
for (InsetBase::col_type col = c1; col <= c2; ++col) {
if (col > c1)
data += '&';
- data += asString(i1.asMathInset()->
- cell(i1.asMathInset()->index(row, col)));
+ data += asString(i1.asInsetMath()->
+ cell(i1.asInsetMath()->index(row, col)));
}
}
} else {
- data = "unknown selection 2";
+ data = from_ascii("unknown selection 2");
}
return data;
}
} // namespace cap
+
} // namespace lyx