#include "FuncCode.h"
#include "FuncRequest.h"
#include "Language.h"
+#include "LyXAction.h"
#include "LyXFunc.h" // only for setMessage()
#include "LyXRC.h"
-#include "paragraph_funcs.h"
#include "Paragraph.h"
#include "ParIterator.h"
#include "Row.h"
return true;
}
-docstring parbreak(Paragraph const & par)
-{
- odocstringstream os;
- os << '\n';
- // only add blank line if we're not in an ERT or Listings inset
- if (par.ownerCode() != ERT_CODE && par.ownerCode() != LISTINGS_CODE)
- os << '\n';
- return os.str();
-}
-
} // namespace anon
Cursor::Cursor(BufferView & bv)
: DocIterator(&bv.buffer()), bv_(&bv), anchor_(),
x_target_(-1), textTargetOffset_(0),
- selection_(false), mark_(false), logicalpos_(false),
- current_font(inherit_font)
+ selection_(false), mark_(false), word_selection_(false),
+ logicalpos_(false), current_font(inherit_font)
{}
-void Cursor::reset(Inset & inset)
+void Cursor::reset()
{
clear();
- push_back(CursorSlice(inset));
- anchor_ = doc_iterator_begin(&inset.buffer(), &inset);
+ push_back(CursorSlice(buffer()->inset()));
+ anchor_ = doc_iterator_begin(buffer());
anchor_.clear();
clearTargetX();
selection_ = false;
}
+bool Cursor::getStatus(FuncRequest const & cmd, FuncStatus & status) const
+{
+ Cursor cur = *this;
+
+ // Try to fix cursor in case it is broken.
+ cur.fixIfBroken();
+
+ // Is this a function that acts on inset at point?
+ Inset * inset = cur.nextInset();
+ if (lyxaction.funcHasFlag(cmd.action, LyXAction::AtPoint)
+ && inset && inset->getStatus(cur, cmd, status))
+ return true;
+
+ // This is, of course, a mess. Better create a new doc iterator and use
+ // this in Inset::getStatus. This might require an additional
+ // BufferView * arg, though (which should be avoided)
+ //Cursor safe = *this;
+ bool res = false;
+ for ( ; cur.depth(); cur.pop()) {
+ //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
+ LASSERT(cur.idx() <= cur.lastidx(), /**/);
+ LASSERT(cur.pit() <= cur.lastpit(), /**/);
+ LASSERT(cur.pos() <= cur.lastpos(), /**/);
+
+ // The inset's getStatus() will return 'true' if it made
+ // a definitive decision on whether it want to handle the
+ // request or not. The result of this decision is put into
+ // the 'status' parameter.
+ if (cur.inset().getStatus(cur, cmd, status)) {
+ res = true;
+ break;
+ }
+ }
+ return res;
+}
+
+
void Cursor::dispatch(FuncRequest const & cmd0)
{
LYXERR(Debug::DEBUG, "cmd: " << cmd0 << '\n' << *this);
fixIfBroken();
FuncRequest cmd = cmd0;
Cursor safe = *this;
+
+ buffer()->undo().beginUndoGroup();
+ // Is this a function that acts on inset at point?
+ if (lyxaction.funcHasFlag(cmd.action, LyXAction::AtPoint)
+ && nextInset()) {
+ result().dispatched(true);
+ result().update(Update::FitCursor | Update::Force);
+ FuncRequest tmpcmd = cmd;
+ LYXERR(Debug::DEBUG, "Cursor::dispatch: (AtPoint) cmd: "
+ << cmd0 << endl << *this);
+ nextInset()->dispatch(*this, tmpcmd);
+ if (result().dispatched())
+ return;
+ }
+
// store some values to be used inside of the handlers
beforeDispatchCursor_ = *this;
for (; depth(); pop(), boundary(false)) {
// are possible which would change it
beforeDispatchCursor_ = safe.beforeDispatchCursor_;
}
+ buffer()->undo().endUndoGroup();
}
LASSERT(!empty(), /**/);
for (int i = depth() - 1; i >= 0; --i) {
int res = operator[](i).inset().currentMode();
- if (res != Inset::UNDECIDED_MODE)
+ bool locked_mode = operator[](i).inset().lockedMode();
+ // Also return UNDECIDED_MODE when the mode is locked,
+ // as in this case it is treated the same as TEXT_MODE
+ if (res != Inset::UNDECIDED_MODE || locked_mode)
return res;
}
return Inset::TEXT_MODE;
void Cursor::clearSelection()
{
setSelection(false);
+ setWordSelection(false);
setMark(false);
resetAnchor();
}
}
-void Cursor::niceInsert(docstring const & t, Parse::flags f)
+void Cursor::niceInsert(docstring const & t, Parse::flags f, bool enter)
{
- MathData ar;
+ MathData ar(buffer());
asArray(t, ar, f);
- if (ar.size() == 1)
+ if (ar.size() == 1 && (enter || selection()))
niceInsert(ar[0]);
else
insert(ar);
macroModeClose();
docstring const safe = cap::grabAndEraseSelection(*this);
plainInsert(t);
- // enter the new inset and move the contents of the selection if possible
+ // If possible, enter the new inset and move the contents of the selection
if (t->isActive()) {
posBackward();
// be careful here: don't use 'pushBackward(t)' as this we need to
// push the clone, not the original
pushBackward(*nextInset());
// We may not use niceInsert here (recursion)
- MathData ar;
+ MathData ar(buffer());
asArray(safe, ar);
insert(ar);
}
return false;
InsetMathUnknown * p = activeMacro();
p->finalize();
- MathData selection;
+ MathData selection(buffer());
asArray(p->selection(), selection);
docstring const s = p->name();
--pos();
InsetMathNest * const in = inset().asInsetMath()->asNestInset();
if (in && in->interpretString(*this, s))
return true;
- MathAtom atom = createInsetMath(name);
+ MathAtom atom = buffer()->getMacro(name, *this, false) ?
+ MathAtom(new MathMacro(buffer(), name)) : createInsetMath(name, buffer());
// try to put argument into macro, if we just inserted a macro
bool macroArg = false;
// finally put the macro argument behind, if needed
if (macroArg) {
- if (selection.size() > 1)
+ if (selection.size() > 1 || selection[0]->asScriptInset())
plainInsert(MathAtom(new InsetMathBrace(selection)));
else
insert(selection);
<< pos() << ' ' << lastpos() << " in idx: " << idx()
<< " in atom: '";
odocstringstream os;
- WriteStream wi(os, false, true, false);
+ WriteStream wi(os, false, true, WriteStream::wsDefault);
inset().asInsetMath()->write(wi);
lyxerr << to_utf8(os.str()) << endl;
pos() = lastpos();
operator=(dummy);
}
} else {
- // if there is a selection, we stay out of any inset, and just jump to the right position:
+ // if there is a selection, we stay out of any inset,
+ // and just jump to the right position:
Cursor old = *this;
+ int next_row = row;
if (up) {
if (row > 0) {
- top().pos() = min(tm.x2pos(pit(), row - 1, xo), top().lastpos());
+ --next_row;
} else if (pit() > 0) {
--pit();
TextMetrics & tm = bv_->textMetrics(text());
if (!tm.contains(pit()))
tm.newParMetricsUp();
ParagraphMetrics const & pmcur = tm.parMetrics(pit());
- top().pos() = min(tm.x2pos(pit(), pmcur.rows().size() - 1, xo), top().lastpos());
+ next_row = pmcur.rows().size() - 1;
}
} else {
if (row + 1 < int(pm.rows().size())) {
- top().pos() = min(tm.x2pos(pit(), row + 1, xo), top().lastpos());
+ ++next_row;
} else if (pit() + 1 < int(text()->paragraphs().size())) {
++pit();
TextMetrics & tm = bv_->textMetrics(text());
if (!tm.contains(pit()))
tm.newParMetricsDown();
- top().pos() = min(tm.x2pos(pit(), 0, xo), top().lastpos());
+ next_row = 0;
}
}
+ top().pos() = min(tm.x2pos(pit(), next_row, xo), top().lastpos());
+
+ int const xpos = tm.x2pos(pit(), next_row, xo);
+ bool const at_end_row = xpos == tm.x2pos(pit(), next_row, tm.width());
+ bool const at_beg_row = xpos == tm.x2pos(pit(), next_row, 0);
+
+ if (at_end_row && at_beg_row)
+ // make sure the cursor ends up on this row
+ boundary(false);
+ else
+ boundary(at_end_row);
updateNeeded |= bv().checkDepm(*this, old);
}
} else {
// cursor in between. split cell
MathData::iterator bt = cell().begin();
- MathAtom at = createInsetMath(from_utf8(font));
- at.nucleus()->cell(0) = MathData(bt, bt + pos());
+ MathAtom at = createInsetMath(from_utf8(font), buffer());
+ at.nucleus()->cell(0) = MathData(buffer(), bt, bt + pos());
cell().erase(bt, bt + pos());
popBackward();
plainInsert(at);
}
+static docstring parbreak(InsetCode code)
+{
+ odocstringstream os;
+ os << '\n';
+ // only add blank line if we're not in an ERT or Listings inset
+ if (code != ERT_CODE && code != LISTINGS_CODE)
+ os << '\n';
+ return os.str();
+}
+
+
docstring Cursor::selectionAsString(bool with_label) const
{
if (!selection())
return docstring();
+ if (inMathed())
+ return cap::grabSelection(*this);
+
int const label = with_label
? AS_STR_LABEL | AS_STR_INSETS : AS_STR_INSETS;
- if (inTexted()) {
- idx_type const startidx = selBegin().idx();
- idx_type const endidx = selEnd().idx();
- if (startidx != endidx) {
- // multicell selection
- InsetTabular * table = inset().asInsetTabular();
- LASSERT(table, return docstring());
- return table->asString(startidx, endidx);
- }
-
- ParagraphList const & pars = text()->paragraphs();
-
- pit_type const startpit = selBegin().pit();
- pit_type const endpit = selEnd().pit();
- size_t const startpos = selBegin().pos();
- size_t const endpos = selEnd().pos();
-
- if (startpit == endpit)
- return pars[startpit].asString(startpos, endpos, label);
-
- // First paragraph in selection
- docstring result = pars[startpit].
- asString(startpos, pars[startpit].size(), label)
- + parbreak(pars[startpit]);
-
- // The paragraphs in between (if any)
- for (pit_type pit = startpit + 1; pit != endpit; ++pit) {
- Paragraph const & par = pars[pit];
- result += par.asString(0, par.size(), label)
- + parbreak(pars[pit]);
- }
+ idx_type const startidx = selBegin().idx();
+ idx_type const endidx = selEnd().idx();
+ if (startidx != endidx) {
+ // multicell selection
+ InsetTabular * table = inset().asInsetTabular();
+ LASSERT(table, return docstring());
+ return table->asString(startidx, endidx);
+ }
+
+ ParagraphList const & pars = text()->paragraphs();
- // Last paragraph in selection
- result += pars[endpit].asString(0, endpos, label);
+ pit_type const startpit = selBegin().pit();
+ pit_type const endpit = selEnd().pit();
+ size_t const startpos = selBegin().pos();
+ size_t const endpos = selEnd().pos();
- return result;
+ if (startpit == endpit)
+ return pars[startpit].asString(startpos, endpos, label);
+
+ // First paragraph in selection
+ docstring result = pars[startpit].
+ asString(startpos, pars[startpit].size(), label)
+ + parbreak(inset().lyxCode());
+
+ // The paragraphs in between (if any)
+ for (pit_type pit = startpit + 1; pit != endpit; ++pit) {
+ Paragraph const & par = pars[pit];
+ result += par.asString(0, par.size(), label)
+ + parbreak(inset().lyxCode());
}
- if (inMathed())
- return cap::grabSelection(*this);
+ // Last paragraph in selection
+ result += pars[endpit].asString(0, endpos, label);
- return docstring();
+ return result;
}
CursorSlice const & sl = innerTextSlice();
Text const & text = *sl.text();
Font font = text.getPar(sl.pit()).getFont(
- bv().buffer().params(), sl.pos(), outerFont(sl.pit(), text.paragraphs()));
+ bv().buffer().params(), sl.pos(), text.outerFont(sl.pit()));
return font.language()->encoding();
}
// get font at the position
Font font = par.getFont(buffer()->params(), pos,
- outerFont(sl.pit(), text.paragraphs()));
+ text.outerFont(sl.pit()));
return font;
}
// notify everything on top of the common part in old cursor,
// but stop if the inset claims the cursor to be invalid now
for (size_type j = i; j < old.depth(); ++j) {
- Cursor insetPos = old;
- insetPos.cutOff(j);
- if (old[j].inset().notifyCursorLeaves(insetPos, cur))
+ Cursor inset_pos = old;
+ inset_pos.cutOff(j);
+ if (old[j].inset().notifyCursorLeaves(inset_pos, cur))
return true;
}