#include "funcrequest.h"
#include "iterators.h"
#include "lfuns.h"
+#include "lyxfunc.h" // only for setMessage()
#include "lyxrc.h"
-#include "lyxtext.h"
#include "lyxrow.h"
+#include "lyxtext.h"
#include "paragraph.h"
#include "insets/updatableinset.h"
#include "mathed/math_support.h"
#include "support/limited_stack.h"
+#include "support/std_sstream.h"
+
+#include "frontends/LyXView.h"
#include <boost/assert.hpp>
DispatchResult LCursor::dispatch(FuncRequest const & cmd0)
{
- //lyxerr << "\nLCursor::dispatch: cmd: " << cmd0 << endl << *this << endl;
+ lyxerr << "\nLCursor::dispatch: cmd: " << cmd0 << endl << *this << endl;
FuncRequest cmd = cmd0;
-
- for (int i = cursor_.size() - 1; i >= 1; --i) {
- current_ = i;
- CursorSlice const & citem = cursor_[i];
- lyxerr << "trying to dispatch to inset " << citem.inset_ << endl;
- DispatchResult res = inset()->dispatch(*this, cmd);
- if (res.dispatched()) {
- lyxerr << " successfully dispatched to inset " << citem.inset_ << endl;
- return DispatchResult(true, true);
- }
- // remove one level of cursor
- switch (res.val()) {
+ disp_.update(true);
+ disp_.val(NONE);
+ for (current_ = cursor_.size() - 1; current_ >= 1; --current_) {
+ // the inset's dispatch() is supposed to reset the update and
+ // val flags if necessary
+ inset()->dispatch(*this, cmd);
+
+ // "Mutate" the request for semi-handled requests that need
+ // additional handling in outer levels.
+ switch (disp_.val()) {
+ case NONE:
+ // the inset handled the event fully
+ current_ = cursor_.size() - 1;
+ return DispatchResult(true, true);
case FINISHED:
- pop(i);
+ // the inset handled the event partially
cmd = FuncRequest(LFUN_FINISHED_LEFT);
break;
case FINISHED_RIGHT:
- pop(i);
cmd = FuncRequest(LFUN_FINISHED_RIGHT);
break;
case FINISHED_UP:
- pop(i);
cmd = FuncRequest(LFUN_FINISHED_UP);
break;
case FINISHED_DOWN:
- pop(i);
cmd = FuncRequest(LFUN_FINISHED_DOWN);
break;
default:
- lyxerr << "not handled on level " << i << " val: " << res.val() << endl;
+ //lyxerr << "not handled on level " << current_
+ // << " val: " << disp_.val() << endl;
break;
}
}
- lyxerr << "trying to dispatch to main text " << bv_->text() << endl;
- DispatchResult res = bv_->text()->dispatch(*this, cmd);
- lyxerr << " result: " << res.val() << endl;
- return res;
+ BOOST_ASSERT(current_ == 0);
+ bv_->text()->dispatch(*this, cmd);
+ //lyxerr << " result: " << res.val() << endl;
+ current_ = cursor_.size() - 1;
+ return disp_;
}
void LCursor::pop(int depth)
{
- //lyxerr << "LCursor::pop() to depth " << depth << endl;
- while (int(cursor_.size()) > depth)
+ while (int(cursor_.size()) > depth + 1)
pop();
+ lyxerr << "LCursor::pop() result: " << *this << endl;
}
void LCursor::pop()
{
- BOOST_ASSERT(!cursor_.empty());
- //lyxerr << "LCursor::pop() a level" << endl;
- if (cursor_.size() <= 1)
- lyxerr << "### TRYING TO POP FROM EMPTY CURSOR" << endl;
- else {
- cursor_.pop_back();
- anchor_.pop_back();
- current_ = cursor_.size() - 1;
- }
- //lyxerr << "LCursor::pop() current now: " << current_ << endl;
+ BOOST_ASSERT(cursor_.size() >= 1);
+ cursor_.pop_back();
+ anchor_.pop_back();
+ current_ = cursor_.size() - 1;
}
}
inset()->notifyCursorLeaves(idx());
pop();
- posRight();
+ ++pos();
return true;
}
LyXText * LCursor::innerText() const
{
BOOST_ASSERT(!cursor_.empty());
- //lyxerr << "LCursor::innerText() depth: " << cursor_.size() << endl;
if (cursor_.size() > 1) {
// go up until first non-0 text is hit
// (innermost text is 0 in mathed)
CursorSlice const & LCursor::innerTextSlice() const
{
BOOST_ASSERT(!cursor_.empty());
- //lyxerr << "LCursor::innerTextSlice() depth: " << cursor_.size() << endl;
if (cursor_.size() > 1) {
// go up until first non-0 text is hit
// (innermost text is 0 in mathed)
void LCursor::getDim(int & asc, int & des) const
{
BOOST_ASSERT(!cursor_.empty());
- LyXText * text = innerText();
-#warning crashes with text-in-math
- if (0 && text) {
- RowList::iterator const rit = text->cursorRow();
- if (rit != text->endRow()) {
- asc = rit->baseline();
- des = rit->height() - asc;
- } else {
- asc = 10;
- des = 10;
- }
- } else {
+ if (inMathed()) {
+ BOOST_ASSERT(inset());
+ BOOST_ASSERT(inset()->asMathInset());
+ //inset()->asMathInset()->getCursorDim(asc, des);
asc = 10;
des = 10;
- //innerInset()->getCursorDim(asc, des);
+ } else {
+ Row const & row = textRow();
+ asc = row.baseline();
+ des = row.height() - asc;
}
}
BOOST_ASSERT(!cursor_.empty());
x = 0;
y = 0;
- if (cursor_.size() <= 1) {
+ if (cursor_.size() == 1) {
x = bv_->text()->cursorX(cursor_.front());
y = bv_->text()->cursorY(cursor_.front());
} else {
+ if (!inset()) {
+ lyxerr << "#### LCursor::getPos: " << *this << endl;
+ BOOST_ASSERT(inset());
+ }
inset()->getCursorPos(cursor_.back(), x, y);
// getCursorPos gives _screen_ coordinates. We need to add
// top_y to get document coordinates. This is hidden in cached_y_.
// inset.yo_, so getCursor() returns an old value.
// Ugly as you like.
}
- lyxerr << "#### LCursor::getPos: x: " << x << " y: " << y << endl;
+ //lyxerr << "#### LCursor::getPos: " << *this
+ // << " x: " << x << " y: " << y << endl;
}
{
if (!selection())
return cursor_.back();
- // can't use std::min as this creates a new object
return anchor() < cursor_.back() ? anchor() : cursor_.back();
}
{
if (!selection())
return cursor_.back();
+ // can't use std::min as this returns a const ref
return anchor() < cursor_.back() ? anchor() : cursor_.back();
}
CursorSlice & LCursor::selEnd()
{
- if (selection())
+ if (!selection())
return cursor_.back();
+ // can't use std::min as this returns a const ref
return anchor() > cursor_.back() ? anchor() : cursor_.back();
}
Paragraph & LCursor::paragraph()
{
+ BOOST_ASSERT(inTexted());
return current_ ? current().paragraph() : *bv_->text()->getPar(par());
}
Paragraph const & LCursor::paragraph() const
{
+ BOOST_ASSERT(inTexted());
return current_ ? current().paragraph() : *bv_->text()->getPar(par());
}
+Row & LCursor::textRow()
+{
+ return *paragraph().getRow(pos());
+}
+
+
+Row const & LCursor::textRow() const
+{
+ return *paragraph().getRow(pos());
+}
+
+
+LCursor::par_type LCursor::lastpar() const
+{
+ return inMathed() ? 0 : text()->paragraphs().size() - 1;
+}
+
+
LCursor::pos_type LCursor::lastpos() const
{
InsetBase * inset = current().inset();
}
+LCursor::row_type LCursor::crow() const
+{
+ return paragraph().row(pos());
+}
+
+
+LCursor::row_type LCursor::lastcrow() const
+{
+ return paragraph().rows.size();
+}
+
+
size_t LCursor::nargs() const
{
// assume 1x1 grid for 'plain text'
}
-void LCursor::info(std::ostream & os)
+void LCursor::info(std::ostream & os) const
{
for (int i = 1, n = depth(); i < n; ++i) {
cursor_[i].inset()->infoize(os);
os << " ";
}
-#warning FIXME
- //if (pos() != 0)
- // prevAtom()->infoize2(os);
+ if (pos() != 0)
+ prevInset()->infoize2(os);
// overwite old message
os << " ";
}
void LCursor::eraseSelection()
{
- CursorSlice i1 = selBegin();
- CursorSlice i2 = selEnd();
+ //lyxerr << "LCursor::eraseSelection" << endl;
+ CursorSlice const & i1 = selBegin();
+ CursorSlice const & i2 = selEnd();
#warning FIXME
if (i1.inset()->asMathInset()) {
if (i1.idx_ == i2.idx_) {
} else {
lyxerr << "can't erase this selection 1" << endl;
}
+ //lyxerr << "LCursor::eraseSelection end" << endl;
}
void LCursor::selDel()
{
+ //lyxerr << "LCursor::selDel" << endl;
if (selection()) {
eraseSelection();
selection() = false;
void LCursor::selHandle(bool sel)
{
+ //lyxerr << "LCursor::selHandle" << endl;
if (sel == selection())
return;
resetAnchor();
}
-void LCursor::selStart()
-{
- resetAnchor();
- selection() = true;
-}
-
-
void LCursor::selClearOrDel()
{
+ //lyxerr << "LCursor::selClearOrDel" << endl;
if (lyxrc.auto_region_delete)
selDel();
else
std::ostream & operator<<(std::ostream & os, LCursor const & cur)
{
- os << "\n";
for (size_t i = 0, n = cur.cursor_.size(); i != n; ++i)
- os << " (" << cur.cursor_[i] << " | " << cur.anchor_[i] << "\n";
- return os << "current: " << cur.current_ << endl;
+ os << " " << cur.cursor_[i] << " | " << cur.anchor_[i] << "\n";
+ os << " current: " << cur.current_ << endl;
+ os << " selection: " << cur.selection_ << endl;
+ return os;
}
// we can't move into anything new during selection
if (depth() == anchor_.size())
return false;
- if (t.nucleus() != anchor_[depth()].inset())
+ if (!ptr_cmp(t.nucleus(), anchor_[depth()].inset()))
return false;
return true;
}
-void LCursor::insert2(string const & str)
-{
- MathArray ar;
- asArray(str, ar);
- insert(ar);
-}
-
-
void LCursor::insert(string const & str)
{
- lyxerr << "inserting '" << str << "'" << endl;
+ lyxerr << "LCursor::insert str '" << str << "'" << endl;
selClearOrDel();
+#if 0
for (string::const_iterator it = str.begin(); it != str.end(); ++it)
plainInsert(MathAtom(new MathCharInset(*it)));
+#else
+ MathArray ar;
+ asArray(str, ar);
+ insert(ar);
+#endif
}
void LCursor::insert(char c)
{
- lyxerr << "inserting '" << c << "'" << endl;
+ //lyxerr << "LCursor::insert char '" << c << "'" << endl;
selClearOrDel();
plainInsert(MathAtom(new MathCharInset(c)));
}
void LCursor::insert(MathAtom const & t)
{
+ //lyxerr << "LCursor::insert MathAtom: " << endl;
macroModeClose();
selClearOrDel();
plainInsert(t);
}
+void LCursor::insert(InsetBase * inset)
+{
+ if (inMathed())
+ insert(MathAtom(inset));
+ else
+ text()->insertInset(*this, inset);
+}
+
+
void LCursor::niceInsert(string const & t)
{
- lyxerr << "*** LCursor::niceInsert 1: " << t << endl;
MathArray ar;
asArray(t, ar);
if (ar.size() == 1)
void LCursor::niceInsert(MathAtom const & t)
{
- lyxerr << "*** LCursor::niceInsert 2: " << t << endl;
macroModeClose();
string safe = grabAndEraseSelection();
plainInsert(t);
// enter the new inset and move the contents of the selection if possible
if (t->isActive()) {
posLeft();
+ // be careful here: don't use 'pushLeft(t)' as this we need to
+ // push the clone, not the original
pushLeft(nextAtom().nucleus());
paste(safe);
}
- lyxerr << "*** LCursor::niceInsert 3: " << t << endl;
}
}
// delete empty cells if possible
-#warning FIXME
- //if (cell().empty() && inset()->idxDelete(idx()))
- // return true;
+ if (pos() == lastpos() && inset()->idxDelete(idx()))
+ return true;
// special behaviour when in last position of cell
if (pos() == lastpos()) {
}
-void LCursor::drawSelection(PainterInfo & pi)
-{
- if (!selection())
- return;
- CursorSlice i1 = selBegin();
- CursorSlice i2 = selEnd();
- i1.asMathInset()->drawSelection(pi, i1.idx_, i1.pos_, i2.idx_, i2.pos_);
-}
-
-
void LCursor::handleNest(MathAtom const & a, int c)
{
+ //lyxerr << "LCursor::handleNest: " << c << endl;
MathAtom t = a;
asArray(grabAndEraseSelection(), t.nucleus()->cell(c));
insert(t);
posLeft();
- pushLeft(t.nucleus());
+ pushLeft(nextAtom().nucleus());
}
MathHullInset * LCursor::formula() const
{
- for (int i = cursor_.size() - 1; i >= 1; --i)
- if (cursor_[i].inset()->lyxCode() == InsetBase::MATH_CODE)
- return static_cast<MathHullInset *>(cursor_[i].inset());
+ for (int i = cursor_.size() - 1; i >= 1; --i) {
+ MathInset * inset = cursor_[i].inset()->asMathInset();
+ if (inset && inset->asHullInset())
+ return static_cast<MathHullInset *>(inset);
+ }
return 0;
}
void LCursor::pullArg()
{
-#warning look here
-#if 0
+#warning Look here
MathArray ar = cell();
- if (popLeft()) {
+ if (popLeft() && inMathed()) {
plainErase();
cell().insert(pos(), ar);
resetAnchor();
} else {
- formula()->mutateToText();
+ //formula()->mutateToText();
}
-#endif
}
<< idx() << ' ' << nargs()
<< " in: " << inset() << endl;
}
- idx() = min(idx(), nargs() - 1);
+ idx() = min(idx(), lastidx());
if (pos() > lastpos()) {
lyxerr << "this should not really happen - 2: "
bool LCursor::goUpDown(bool up)
{
- // Be warned: The 'logic' implemented in this function is highly fragile.
- // A distance of one pixel or a '<' vs '<=' _really_ matters.
- // So fiddle around with it only if you know what you are doing!
+ // Be warned: The 'logic' implemented in this function is highly
+ // fragile. A distance of one pixel or a '<' vs '<=' _really
+ // matters. So fiddle around with it only if you think you know
+ // what you are doing!
int xo = 0;
int yo = 0;
getPos(xo, yo);
double best_dist = 1e10;
CursorBase it = cursor_;
- it.back().pos(0);
+ it.back().pos() = 0;
CursorBase et = cursor_;
- int n = et.back().asMathInset()->cell(et.back().idx_).size();
- et.back().pos(n);
+ et.back().pos() = et.back().asMathInset()->cell(et.back().idx_).size();
for (int i = 0; ; ++i) {
int xo, yo;
CursorSlice & cur = it.back();
bool LCursor::script(bool up)
{
// Hack to get \\^ and \\_ working
+ lyxerr << "handling script: up: " << up << endl;
if (inMacroMode() && macroName() == "\\") {
if (up)
niceInsert(createMathInset("mathcircumflex"));
idx() = up;
pos() = 0;
} else if (pos() != 0 && prevAtom()->asScriptInset()) {
- prevAtom().nucleus()->asScriptInset()->ensure(up);
- posLeft();
- push(inset());
+ --pos();
+ nextAtom().nucleus()->asScriptInset()->ensure(up);
+ push(nextInset());
idx() = up;
pos() = lastpos();
} else if (pos() != 0) {
--pos();
- cell()[pos()]
- = MathAtom(new MathScriptInset(nextAtom(), up));
- push(inset());
+ cell()[pos()] = MathAtom(new MathScriptInset(nextAtom(), up));
+ push(nextInset());
idx() = up;
pos() = 0;
} else {
plainInsert(MathAtom(new MathScriptInset(up)));
- posLeft();
+ --pos();
nextAtom().nucleus()->asScriptInset()->ensure(up);
- push(inset());
+ push(nextInset());
idx() = up;
pos() = 0;
}
} else if (popLeft() && pos() != lastpos()) {
// ... or enclosing inset if we are in the last inset position
nextAtom().nucleus()->lock(!nextAtom()->lock());
- posRight();
+ ++pos();
}
}
void LCursor::handleFont(string const & font)
{
+ lyxerr << "LCursor::handleFont: " << font << endl;
string safe;
if (selection()) {
macroModeClose();
}
-void LCursor::releaseMathCursor()
+bool LCursor::inMathed() const
{
- if (inMathed())
- formula()->insetUnlock(bv());
+ return formula();
}
-bool LCursor::inMathed() const
+bool LCursor::inTexted() const
{
- return formula();
+ return !formula();
+}
+
+
+InsetBase * LCursor::nextInset()
+{
+ if (pos() == lastpos())
+ return 0;
+ if (inMathed())
+ return nextAtom().nucleus();
+ return paragraph().isInset(pos()) ? paragraph().getInset(pos()) : 0;
+}
+
+
+InsetBase * LCursor::prevInset()
+{
+ if (pos() == 0)
+ return 0;
+ if (inMathed())
+ return prevAtom().nucleus();
+ return paragraph().isInset(pos() - 1) ? paragraph().getInset(pos() - 1) : 0;
+}
+
+
+InsetBase const * LCursor::prevInset() const
+{
+ if (pos() == 0)
+ return 0;
+ if (inMathed())
+ return prevAtom().nucleus();
+ return paragraph().isInset(pos() - 1) ? paragraph().getInset(pos() - 1) : 0;
+}
+
+
+void LCursor::message(string const & msg) const
+{
+ bv().owner()->getLyXFunc().setMessage(msg);
+}
+
+
+void LCursor::errorMessage(string const & msg) const
+{
+ bv().owner()->getLyXFunc().setErrorMessage(msg);
+}
+
+
+string LCursor::selectionAsString(bool label) const
+{
+ if (!selection())
+ return string();
+
+ if (inTexted()) {
+ Buffer const & buffer = *bv().buffer();
+
+ // should be const ...
+ ParagraphList::iterator startpit = text()->getPar(selBegin());
+ ParagraphList::iterator endpit = text()->getPar(selEnd());
+ size_t const startpos = selBegin().pos();
+ size_t const endpos = selEnd().pos();
+
+ if (startpit == endpit)
+ return startpit->asString(buffer, startpos, endpos, label);
+
+ // First paragraph in selection
+ string result =
+ startpit->asString(buffer, startpos, startpit->size(), label) + "\n\n";
+
+ // The paragraphs in between (if any)
+ ParagraphList::iterator pit = startpit;
+ for (++pit; pit != endpit; ++pit)
+ result += pit->asString(buffer, 0, pit->size(), label) + "\n\n";
+
+ // Last paragraph in selection
+ result += endpit->asString(buffer, 0, endpos, label);
+
+ return result;
+ }
+
+#warning an mathed?
+ return string();
+}
+
+
+string LCursor::currentState()
+{
+ if (inMathed()) {
+ std::ostringstream os;
+ info(os);
+ return os.str();
+ }
+ return text() ? text()->currentState(*this) : string();
+}
+
+
+// only used by the spellchecker
+void LCursor::replaceWord(string const & replacestring)
+{
+ LyXText * t = text();
+ BOOST_ASSERT(t);
+
+ t->replaceSelectionWithString(*this, replacestring);
+ t->setSelectionRange(*this, replacestring.length());
+
+ // Go back so that replacement string is also spellchecked
+ for (string::size_type i = 0; i < replacestring.length() + 1; ++i)
+ t->cursorLeft(*this, true);
+}
+
+
+void LCursor::update()
+{
+ bv().update();
+}
+
+
+string LCursor::getPossibleLabel()
+{
+ return inMathed() ? "eq:" : text()->getPossibleLabel(*this);
+}
+
+
+void LCursor::notdispatched()
+{
+ disp_.dispatched(false);
+}
+
+
+void LCursor::dispatched(dispatch_result_t res)
+{
+ disp_.val(res);
+}
+
+
+void LCursor::noupdate()
+{
+ disp_.update(false);
}