]> git.lyx.org Git - lyx.git/blobdiff - src/BufferView_pimpl.C
changelogs
[lyx.git] / src / BufferView_pimpl.C
index a523795405e975cef6c7e109fd7346fc9c9b6424..62c17dbb500b0778d062713acdf99a9b2b192880 100644 (file)
 #include "buffer_funcs.h"
 #include "bufferlist.h"
 #include "bufferparams.h"
+#include "coordcache.h"
 #include "cursor.h"
 #include "debug.h"
 #include "dispatchresult.h"
 #include "factory.h"
 #include "FloatList.h"
 #include "funcrequest.h"
+#include "FuncStatus.h"
 #include "gettext.h"
 #include "intl.h"
-#include "iterators.h"
+#include "insetiterator.h"
 #include "lyx_cb.h" // added for Dispatch functions
 #include "lyx_main.h"
 #include "lyxfind.h"
 #include "paragraph.h"
 #include "paragraph_funcs.h"
 #include "ParagraphParameters.h"
+#include "pariterator.h"
+#include "rowpainter.h"
 #include "undo.h"
 #include "vspace.h"
 
 #include "insets/insetref.h"
+#include "insets/insettext.h"
 
 #include "frontends/Alert.h"
 #include "frontends/Dialogs.h"
 #include "graphics/Previews.h"
 
 #include "support/filetools.h"
+#include "support/forkedcontr.h"
 #include "support/globbing.h"
 #include "support/path_defines.h"
 #include "support/tostr.h"
+#include "support/types.h"
 
 #include <boost/bind.hpp>
 
+#include <functional>
+
 using lyx::pos_type;
 
 using lyx::support::AddPath;
 using lyx::support::bformat;
 using lyx::support::FileFilterList;
 using lyx::support::FileSearch;
+using lyx::support::ForkedcallsController;
 using lyx::support::IsDirWriteable;
 using lyx::support::MakeDisplayPath;
+using lyx::support::MakeAbsPath;
 using lyx::support::strToUnsignedInt;
 using lyx::support::system_lyxdir;
 
@@ -81,6 +92,7 @@ using std::istringstream;
 using std::make_pair;
 using std::min;
 using std::string;
+using std::mem_fun_ref;
 
 
 extern BufferList bufferlist;
@@ -104,17 +116,31 @@ boost::signals::connection selectioncon;
 boost::signals::connection lostcon;
 
 
+/// Get next inset of this class from current cursor position
+template <class T>
+T * getInsetByCode(LCursor & cur, InsetBase::Code code)
+{
+       T * inset = 0;
+       DocIterator it = cur;
+       if (it.nextInset() &&
+           it.nextInset()->lyxCode() == code) {
+               inset = static_cast<T*>(it.nextInset());
+       }
+       return inset;
+}
+
+
 } // anon namespace
 
 
 BufferView::Pimpl::Pimpl(BufferView & bv, LyXView * owner,
-            int xpos, int ypos, int width, int height)
+                        int width, int height)
        : bv_(&bv), owner_(owner), buffer_(0), cursor_timeout(400),
          using_xterm_cursor(false), cursor_(bv)
 {
        xsel_cache_.set = false;
 
-       workarea_.reset(WorkAreaFactory::create(xpos, ypos, width, height));
+       workarea_.reset(WorkAreaFactory::create(*owner_, width, height));
        screen_.reset(LyXScreenFactory::create(workarea()));
 
        // Setup the signals
@@ -157,19 +183,32 @@ void BufferView::Pimpl::connectBuffer(Buffer & buf)
                disconnectBuffer();
 
        errorConnection_ =
-               buf.error.connect(boost::bind(&BufferView::Pimpl::addError, this, _1));
+               buf.error.connect(
+                       boost::bind(&BufferView::Pimpl::addError, this, _1));
+
        messageConnection_ =
-               buf.message.connect(boost::bind(&LyXView::message, owner_, _1));
+               buf.message.connect(
+                       boost::bind(&LyXView::message, owner_, _1));
+
        busyConnection_ =
-               buf.busy.connect(boost::bind(&LyXView::busy, owner_, _1));
+               buf.busy.connect(
+                       boost::bind(&LyXView::busy, owner_, _1));
+
        titleConnection_ =
-               buf.updateTitles.connect(boost::bind(&LyXView::updateWindowTitle, owner_));
+               buf.updateTitles.connect(
+                       boost::bind(&LyXView::updateWindowTitle, owner_));
+
        timerConnection_ =
-               buf.resetAutosaveTimers.connect(boost::bind(&LyXView::resetAutosaveTimer, owner_));
+               buf.resetAutosaveTimers.connect(
+                       boost::bind(&LyXView::resetAutosaveTimer, owner_));
+
        readonlyConnection_ =
-               buf.readonly.connect(boost::bind(&BufferView::Pimpl::showReadonly, this, _1));
+               buf.readonly.connect(
+                       boost::bind(&BufferView::Pimpl::showReadonly, this, _1));
+
        closingConnection_ =
-               buf.closing.connect(boost::bind(&BufferView::Pimpl::buffer, this, (Buffer *)0));
+               buf.closing.connect(
+                       boost::bind(&BufferView::Pimpl::setBuffer, this, (Buffer *)0));
 }
 
 
@@ -185,13 +224,10 @@ void BufferView::Pimpl::disconnectBuffer()
 }
 
 
-bool BufferView::Pimpl::newFile(string const & filename,
-                               string const & tname,
-                               bool isNamed)
+void BufferView::Pimpl::newFile(string const & filename, string const & tname,
+       bool isNamed)
 {
-       Buffer * b = ::newFile(filename, tname, isNamed);
-       buffer(b);
-       return true;
+       setBuffer(::newFile(filename, tname, isNamed));
 }
 
 
@@ -216,14 +252,13 @@ bool BufferView::Pimpl::loadLyXFile(string const & filename, bool tolastfiles)
                        text, 0, 1,  _("&Revert"), _("&Switch to document"));
 
                if (ret != 0) {
-                       buffer(bufferlist.getBuffer(s));
+                       setBuffer(bufferlist.getBuffer(s));
                        return true;
-               } else {
-                       // FIXME: should be LFUN_REVERT
-                       if (!bufferlist.close(bufferlist.getBuffer(s), false))
-                               return false;
-                       // Fall through to new load. (Asger)
                }
+               // FIXME: should be LFUN_REVERT
+               if (!bufferlist.close(bufferlist.getBuffer(s), false))
+                       return false;
+               // Fall through to new load. (Asger)
        }
 
        Buffer * b;
@@ -248,7 +283,7 @@ bool BufferView::Pimpl::loadLyXFile(string const & filename, bool tolastfiles)
                        return false;
        }
 
-       buffer(b);
+       setBuffer(b);
        bv_->showErrorList(_("Parse"));
 
        if (tolastfiles)
@@ -288,80 +323,86 @@ int BufferView::Pimpl::top_y() const
 }
 
 
-void BufferView::Pimpl::buffer(Buffer * b)
+void BufferView::Pimpl::setBuffer(Buffer * b)
 {
        lyxerr[Debug::INFO] << "Setting buffer in BufferView ("
                            << b << ')' << endl;
-       if (buffer_) {
+       if (buffer_)
                disconnectBuffer();
-               //delete bv_->text();
-               //bv_->setText(0);
+
+       // if we are closing current buffer, switch to the first in
+       // buffer list.
+       if (!b) {
+               lyxerr[Debug::INFO] << "  No Buffer!" << endl;
+               // we are closing the buffer, use the first buffer as current
+               buffer_ = bufferlist.first();
+               owner_->getDialogs().hideBufferDependent();
+       } else {
+               // set current buffer
+               buffer_ = b;
        }
 
        // reset old cursor
-       cursor_.reset();
-
-       // set current buffer
-       buffer_ = b;
-
        top_y_ = 0;
+       cursor_ = LCursor(*bv_);
 
        // if we're quitting lyx, don't bother updating stuff
        if (quitting)
                return;
 
-       // if we are closing the buffer, use the first buffer as current
-       if (!buffer_)
-               buffer_ = bufferlist.first();
-
        if (buffer_) {
                lyxerr[Debug::INFO] << "Buffer addr: " << buffer_ << endl;
                connectBuffer(*buffer_);
 
+               cursor_.push(buffer_->inset());
+               cursor_.resetAnchor();
                buffer_->text().init(bv_);
+               buffer_->text().setCurrentFont(cursor_);
 
                // If we don't have a text object for this, we make one
-               if (bv_->text() == 0)
-                       resizeCurrentBuffer();
+               //if (bv_->text() == 0)
+               //      resizeCurrentBuffer();
 
                // Buffer-dependent dialogs should be updated or
                // hidden. This should go here because some dialogs (eg ToC)
                // require bv_->text.
                owner_->getDialogs().updateBufferDependent(true);
-       } else {
-               lyxerr[Debug::INFO] << "  No Buffer!" << endl;
-               owner_->getDialogs().hideBufferDependent();
        }
 
        update();
        updateScrollbar();
        owner_->updateMenubar();
-       owner_->updateToolbar();
+       owner_->updateToolbars();
        owner_->updateLayoutChoice();
        owner_->updateWindowTitle();
 
-       // Don't forget to update the Layout
+       // This is done after the layout combox has been populated
        if (buffer_)
-               owner_->setLayout(bv_->text()->getPar(0)->layout()->name());
+               owner_->setLayout(cursor_.paragraph().layout()->name());
 
-       if (lyx::graphics::Previews::activated() && buffer_)
+       if (buffer_ && lyx::graphics::Previews::status() != LyXRC::PREVIEW_OFF)
                lyx::graphics::Previews::get().generateBufferPreviews(*buffer_);
 }
 
 
 bool BufferView::Pimpl::fitCursor()
 {
-       if (screen().fitCursor(bv_)) {
-               updateScrollbar();
-               return true;
-       }
-       return false;
+       // to get the correct y cursor info
+       lyxerr[Debug::DEBUG] << "BufferView::fitCursor" << std::endl;
+       lyx::pit_type const pit = bv_->cursor().bottom().pit();
+       bv_->text()->redoParagraph(pit);
+       refreshPar(*bv_, *bv_->text(), pit);
+
+       if (!screen().fitCursor(bv_))
+               return false;
+       updateScrollbar();
+       return true;
 }
 
 
 void BufferView::Pimpl::redoCurrentBuffer()
 {
-       lyxerr[Debug::INFO] << "BufferView::redoCurrentBuffer" << endl;
+       lyxerr[Debug::DEBUG] << "BufferView::redoCurrentBuffer" << endl;
        if (buffer_ && bv_->text()) {
                resizeCurrentBuffer();
                updateScrollbar();
@@ -372,57 +413,16 @@ void BufferView::Pimpl::redoCurrentBuffer()
 
 void BufferView::Pimpl::resizeCurrentBuffer()
 {
-       lyxerr[Debug::INFO] << "resizeCurrentBuffer" << endl;
-
-       int par = -1;
-       int selstartpar = -1;
-       int selendpar = -1;
-
-       pos_type pos = 0;
-       pos_type selstartpos = 0;
-       pos_type selendpos = 0;
-       bool sel = false;
-       bool mark_set  = false;
-
+       lyxerr[Debug::DEBUG] << "resizeCurrentBuffer" << endl;
        owner_->busy(true);
-
        owner_->message(_("Formatting document..."));
 
        LyXText * text = bv_->text();
-       lyxerr << "### resizeCurrentBuffer: text " << text << endl;
        if (!text)
                return;
 
-       LCursor & cur = bv_->cursor();
-       par = cur.par();
-       pos = cur.pos();
-       selstartpar = cur.selBegin().par();
-       selstartpos = cur.selBegin().pos();
-       selendpar = cur.selEnd().par();
-       selendpos = cur.selEnd().pos();
-       sel = cur.selection();
-       mark_set = cur.mark();
        text->init(bv_);
        update();
-
-       if (par != -1) {
-               cur.selection() = true;
-               // At this point just to avoid the Delete-Empty-Paragraph-
-               // Mechanism when setting the cursor.
-               cur.mark() = mark_set;
-               if (sel) {
-                       text->setCursor(cur, selstartpar, selstartpos);
-                       cur.resetAnchor();
-                       text->setCursor(cur, selendpar, selendpos);
-                       cur.setSelection();
-                       text->setCursor(cur, par, pos);
-               } else {
-                       text->setCursor(cur, par, pos);
-                       cur.resetAnchor();
-                       cur.selection() = false;
-               }
-       }
-
        fitCursor();
 
        switchKeyMap();
@@ -438,16 +438,17 @@ void BufferView::Pimpl::resizeCurrentBuffer()
 void BufferView::Pimpl::updateScrollbar()
 {
        if (!bv_->text()) {
-               lyxerr[Debug::GUI] << "no text in updateScrollbar" << endl;
+               lyxerr[Debug::DEBUG] << "no text in updateScrollbar" << endl;
                workarea().setScrollbarParams(0, 0, 0);
                return;
        }
 
        LyXText const & t = *bv_->text();
 
-       lyxerr[Debug::GUI] << "Updating scrollbar: h" << t.height()
-                          << ", top_y()" << top_y() << ", default height "
-                          << defaultRowHeight() << endl;
+       lyxerr[Debug::GUI]
+               << "Updating scrollbar: height: " << t.height()
+               << " top_y: " << top_y()
+               << " default height " << defaultRowHeight() << endl;
 
        workarea().setScrollbarParams(t.height(), top_y(), defaultRowHeight());
 }
@@ -472,14 +473,14 @@ void BufferView::Pimpl::scrollDocView(int value)
        int const first = top_y() + height;
        int const last = top_y() + workarea().workHeight() - height;
 
-       bv_->cursor().reset();
+       bv_->cursor().reset(bv_->buffer()->inset());
        LyXText * text = bv_->text();
-       CursorSlice & cur = bv_->cursor().front();
-       int y = text->cursorY(cur);
+       int y = text->cursorY(bv_->cursor().front());
        if (y < first)
-               text->setCursorFromCoordinates(bv_->cursor(), 0, first);
-       else if (y > last)
-               text->setCursorFromCoordinates(bv_->cursor(), 0, last);
+               y = first;
+       if (y > last)
+               y = last;
+       text->setCursorFromCoordinates(bv_->cursor(), 0, y);
 
        owner_->updateLayoutChoice();
 }
@@ -550,7 +551,7 @@ void BufferView::Pimpl::selectionRequested()
                sel = cur.selectionAsString(false);
                if (!sel.empty())
                        workarea().putClipboard(sel);
-       } 
+       }
 }
 
 
@@ -592,29 +593,49 @@ void BufferView::Pimpl::workAreaResize()
 
 void BufferView::Pimpl::update()
 {
-       //lyxerr << "BufferView::update()" << endl;
+       //lyxerr << "BufferView::Pimpl::update(), buffer: " << buffer_ << endl;
        // fix cursor coordinate cache in case something went wrong
 
        // check needed to survive LyX startup
-       if (bv_->getLyXText()) {
+       if (buffer_) {
+               // update macro store
+               buffer_->buildMacros();
+
                // update all 'visible' paragraphs
-               ParagraphList::iterator beg;
-               ParagraphList::iterator end;
+               lyx::pit_type beg, end;
                getParsInRange(buffer_->paragraphs(),
                               top_y(), top_y() + workarea().workHeight(),
                               beg, end);
                bv_->text()->redoParagraphs(beg, end);
+
+               // and the scrollbar
                updateScrollbar();
        }
+
+       // remove old position cache
+       theCoords.clear();
+
+       // The real, big redraw.
        screen().redraw(*bv_);
+
+       bv_->owner()->view_state_changed();
 }
 
 
 // Callback for cursor timer
 void BufferView::Pimpl::cursorToggle()
 {
-       if (buffer_)
+       if (buffer_) {
                screen().toggleCursor(*bv_);
+
+               // Use this opportunity to deal with any child processes that
+               // have finished but are waiting to communicate this fact
+               // to the rest of LyX.
+               ForkedcallsController & fcc = ForkedcallsController::get();
+               if (fcc.processesCompleted())
+                       fcc.handleCompletedProcesses();
+       }
+
        cursor_timeout.restart();
 }
 
@@ -636,8 +657,8 @@ Change const BufferView::Pimpl::getCurrentChange()
        if (!cur.selection())
                return Change(Change::UNCHANGED);
 
-       return text->getPar(cur.selBegin())
-               ->lookupChangeFull(cur.selBegin().pos());
+       return text->getPar(cur.selBegin().pit()).
+                       lookupChangeFull(cur.selBegin().pos());
 }
 
 
@@ -645,9 +666,10 @@ void BufferView::Pimpl::savePosition(unsigned int i)
 {
        if (i >= saved_positions_num)
                return;
+       BOOST_ASSERT(bv_->cursor().inTexted());
        saved_positions[i] = Position(buffer_->fileName(),
-                                     bv_->text()->cursorPar()->id(),
-                                     bv_->text()->cursor().pos());
+                                     bv_->cursor().paragraph().id(),
+                                     bv_->cursor().pos());
        if (i > 0)
                owner_->message(bformat(_("Saved bookmark %1$s"), tostr(i)));
 }
@@ -671,16 +693,14 @@ void BufferView::Pimpl::restorePosition(unsigned int i)
                        ::loadLyXFile(b, fname); // don't ask, just load it
                }
                if (b)
-                       buffer(b);
+                       setBuffer(b);
        }
 
        ParIterator par = buffer_->getParFromID(saved_positions[i].par_id);
        if (par == buffer_->par_iterator_end())
                return;
 
-       bv_->text()->setCursor(
-               bv_->cursor(),
-               bv_->text()->parOffset(par.pit()),
+       bv_->text()->setCursor(bv_->cursor(), par.pit(),
                min(par->size(), saved_positions[i].par_pos));
 
        if (i > 0)
@@ -739,42 +759,6 @@ void BufferView::Pimpl::stuffClipboard(string const & stuff) const
 }
 
 
-InsetBase * BufferView::Pimpl::getInsetByCode(InsetBase::Code code)
-{
-#warning Does not work for mathed
-       // Ok, this is a little bit too brute force but it
-       // should work for now. Better infrastructure is coming. (Lgb)
-
-       Buffer * buf = bv_->buffer();
-       Buffer::inset_iterator beg = buf->inset_iterator_begin();
-       Buffer::inset_iterator end = buf->inset_iterator_end();
-
-       bool cursor_par_seen = false;
-
-       LCursor & cur = bv_->cursor();
-       ParagraphList::iterator pit =  bv_->getLyXText()->getPar(cur.par());
-
-       for (; beg != end; ++beg) {
-               if (beg.getPar() == pit)
-                       cursor_par_seen = true;
-               if (cursor_par_seen) {
-                       if (beg.getPar() == pit && beg.getPos() >= cur.pos())
-                               break;
-                       if (beg.getPar() != pit)
-                               break;
-               }
-       }
-       if (beg != end) {
-               // Now find the first inset that matches code.
-               for (; beg != end; ++beg) {
-                       if (beg->lyxCode() == code)
-                               return &(*beg);
-               }
-       }
-       return 0;
-}
-
-
 void BufferView::Pimpl::MenuInsertLyXFile(string const & filenm)
 {
        string filename = filenm;
@@ -820,12 +804,19 @@ void BufferView::Pimpl::MenuInsertLyXFile(string const & filenm)
 
        string const disp_fn = MakeDisplayPath(filename);
        owner_->message(bformat(_("Inserting document %1$s..."), disp_fn));
-       if (bv_->insertLyXFile(filename))
-               owner_->message(bformat(_("Document %1$s inserted."),
-                                       disp_fn));
-       else
-               owner_->message(bformat(_("Could not insert document %1$s"),
-                                       disp_fn));
+
+       bv_->cursor().clearSelection();
+       bv_->text()->breakParagraph(bv_->cursor());
+
+       BOOST_ASSERT(bv_->cursor().inTexted());
+
+       string const fname = MakeAbsPath(filename);
+       bool const res = bv_->buffer()->readFile(fname, bv_->cursor().pit());
+       bv_->resize();
+
+       string s = res ? _("Document %1$s inserted.")
+                      : _("Could not insert document %1$s");
+       owner_->message(bformat(s, disp_fn));
 }
 
 
@@ -835,9 +826,9 @@ void BufferView::Pimpl::trackChanges()
        bool const tracking = buf->params().tracking_changes;
 
        if (!tracking) {
-               ParIterator const end = buf->par_iterator_end();
-               for (ParIterator it = buf->par_iterator_begin(); it != end; ++it)
-                       it->trackChanges();
+               for_each(buf->par_iterator_begin(),
+                        buf->par_iterator_end(),
+                        bind(&Paragraph::trackChanges, _1, Change::UNCHANGED));
                buf->params().tracking_changes = true;
 
                // we cannot allow undos beyond the freeze point
@@ -845,16 +836,19 @@ void BufferView::Pimpl::trackChanges()
        } else {
                update();
                bv_->text()->setCursor(bv_->cursor(), 0, 0);
+#ifdef WITH_WARNINGS
 #warning changes FIXME
+#endif
                bool found = lyx::find::findNextChange(bv_);
                if (found) {
                        owner_->getDialogs().show("changes");
                        return;
                }
 
-               ParIterator const end = buf->par_iterator_end();
-               for (ParIterator it = buf->par_iterator_begin(); it != end; ++it)
-                       it->untrackChanges();
+               for_each(buf->par_iterator_begin(),
+                        buf->par_iterator_end(),
+                        mem_fun_ref(&Paragraph::untrackChanges));
+
                buf->params().tracking_changes = false;
        }
 
@@ -864,109 +858,143 @@ void BufferView::Pimpl::trackChanges()
 
 bool BufferView::Pimpl::workAreaDispatch(FuncRequest const & cmd0)
 {
-       //
-       // this is only called for mouse related events (including
-       // LFUN_FILE_OPEN generated by drag-and-drop)
-       //
+       lyxerr << "BufferView::Pimpl::workAreaDispatch: request: "
+         << cmd0 << std::endl;
+       // this is only called for mouse related events including
+       // LFUN_FILE_OPEN generated by drag-and-drop.
        FuncRequest cmd = cmd0;
-       cmd.y += bv_->top_y();
-       //lyxerr << "*** workAreaDispatch: request: " << cmd << std::endl;
-       LCursor cur(*bv_);
-       cur.selection() = bv_->cursor().selection();
-       switch (cmd.action) {
 
-#if 0
-       case LFUN_MOUSE_MOTION: {
-               if (!available())
-                       return false;
-               FuncRequest cmd1 = cmd;
-               InsetBase * inset = cur.inset();
-               DispatchResult res;
-               if (inset) {
-                       res = inset->dispatch(cur, cmd);
-               } else {
-                       res = bv_->text()->dispatch(cur, cmd);
-               }
-
-               if (fitCursor() || res.update()) {
-                       update();
-                       cur.updatePos();
-               }
+       // handle drag&drop
+       if (cmd.action == LFUN_FILE_OPEN) {
+               owner_->dispatch(cmd);
                return true;
        }
-#else
-       case LFUN_MOUSE_MOTION: 
-#endif
 
-       case LFUN_MOUSE_PRESS:
-       case LFUN_MOUSE_RELEASE:
-       case LFUN_MOUSE_DOUBLE:
-       case LFUN_MOUSE_TRIPLE: {
-               // We pass those directly to the Bufferview, since
-               // otherwise selection handling breaks down
+       cmd.y += bv_->top_y();
+       if (!bv_->buffer())
+               return false;
 
-               // Doesn't go through lyxfunc, so we need to update
-               // the layout choice etc. ourselves
+       LCursor cur(*bv_);
+       cur.push(bv_->buffer()->inset());
+       cur.selection() = bv_->cursor().selection();
 
-               // e.g. Qt mouse press when no buffer
-               if (!available())
-                       return false;
+       // Doesn't go through lyxfunc, so we need to update
+       // the layout choice etc. ourselves
 
-               screen().hideCursor();
+       // e.g. Qt mouse press when no buffer
+       if (!available())
+               return false;
 
-               // either the inset under the cursor or the
-               // surrounding LyXText will handle this event.
+       screen().hideCursor();
 
-               // built temporary path to inset
-               InsetBase * inset = bv_->text()->editXY(cur, cmd.x, cmd.y);
-               lyxerr << "hit inset at tip: " << inset << endl;
-               lyxerr << "created temp cursor:\n" << cur << endl;
+       // Either the inset under the cursor or the
+       // surrounding LyXText will handle this event.
+
+       // Build temporary cursor.
+       InsetBase * inset = bv_->text()->editXY(cur, cmd.x, cmd.y);
+       lyxerr << " * created temp cursor: " << inset << endl;
+       lyxerr << " * hit inset at tip: " << inset << endl;
+       lyxerr << " * created temp cursor:" << cur << endl;
+
+       // Put anchor at the same position.
+       cur.resetAnchor();
+
+       // Try to dispatch to an non-editable inset near this position
+       // via the temp cursor. If the inset wishes to change the real
+       // cursor it has to do so explicitly by using
+       //  cur.bv().cursor() = cur;  (or similar)
+       if (inset)
+               inset->dispatch(cur, cmd);
+
+       // Now dispatch to the temporary cursor. If the real cursor should
+       // be modified, the inset's dispatch has to do so explicitly.
+       if (!cur.result().dispatched())
+               cur.dispatch(cmd);
+
+       if (cur.result().dispatched()) {
+               // Redraw if requested or necessary.
+               if (fitCursor() || cur.result().update())
+                       update();
+       }
 
-               // Try to dispatch to an non-editable inset near this position
-               DispatchResult res;
-               if (inset)
-                       inset->dispatch(cur, cmd);
+       // see workAreaKeyPress
+       cursor_timeout.restart();
+       screen().showCursor(*bv_);
 
-               // Dispatch to the temp cursor.
-               // An inset (or LyXText) can assign this to bv->cursor()
-               // if it wishes to do so.
-               if (!res.dispatched())
-                       res = cur.dispatch(cmd);
+       // skip these when selecting
+       if (cmd.action != LFUN_MOUSE_MOTION) {
+               owner_->updateLayoutChoice();
+               owner_->updateToolbars();
+       }
 
-               if (fitCursor() || res.update())
-                       update();
+       // slight hack: this is only called currently when we
+       // clicked somewhere, so we force through the display
+       // of the new status here.
+       owner_->clearMessage();
+       return true;
+}
 
-               // see workAreaKeyPress
-               cursor_timeout.restart();
-               screen().showCursor(*bv_);
 
-               // skip these when selecting
-               if (cmd.action != LFUN_MOUSE_MOTION) {
-                       owner_->updateLayoutChoice();
-                       owner_->updateToolbar();
-               }
+FuncStatus BufferView::Pimpl::getStatus(FuncRequest const & cmd)
+{
+       Buffer * buf = bv_->buffer();
 
-               // slight hack: this is only called currently when we
-               // clicked somewhere, so we force through the display
-               // of the new status here.
-               owner_->clearMessage();
-               return true;
-       }
+       FuncStatus flag;
 
-       case LFUN_FILE_OPEN:
-               owner_->dispatch(cmd);
-               return true;
+       switch (cmd.action) {
+
+       case LFUN_UNDO:
+               flag.enabled(!buf->undostack().empty());
+               break;
+       case LFUN_REDO:
+               flag.enabled(!buf->redostack().empty());
+               break;
+       case LFUN_FILE_INSERT:
+       case LFUN_FILE_INSERT_ASCII_PARA:
+       case LFUN_FILE_INSERT_ASCII:
+       case LFUN_FONT_STATE:
+       case LFUN_INSERT_LABEL:
+       case LFUN_BOOKMARK_SAVE:
+       case LFUN_REF_GOTO:
+       case LFUN_WORD_FIND:
+       case LFUN_WORD_REPLACE:
+       case LFUN_MARK_OFF:
+       case LFUN_MARK_ON:
+       case LFUN_SETMARK:
+       case LFUN_CENTER:
+       case LFUN_BEGINNINGBUF:
+       case LFUN_ENDBUF:
+       case LFUN_BEGINNINGBUFSEL:
+       case LFUN_ENDBUFSEL:
+               flag.enabled(true);
+               break;
+       case LFUN_BOOKMARK_GOTO:
+               flag.enabled(bv_->isSavedPosition(strToUnsignedInt(cmd.argument)));
+               break;
+       case LFUN_TRACK_CHANGES:
+               flag.enabled(true);
+               flag.setOnOff(buf->params().tracking_changes);
+               break;
 
+       case LFUN_MERGE_CHANGES:
+       case LFUN_ACCEPT_CHANGE: // what about these two
+       case LFUN_REJECT_CHANGE: // what about these two
+       case LFUN_ACCEPT_ALL_CHANGES:
+       case LFUN_REJECT_ALL_CHANGES:
+               flag.enabled(buf && buf->params().tracking_changes);
+               break;
        default:
-               BOOST_ASSERT(false);
+               flag.enabled(false);
        }
-       return true;
+
+       return flag;
 }
 
 
+
 bool BufferView::Pimpl::dispatch(FuncRequest const & cmd)
 {
-       //lyxerr << "*** BufferView::Pimpl: request: " << cmd << std::endl;
+       //lyxerr << "BufferView::Pimpl::dispatch  cmd: " << cmd << std::endl;
        // Make sure that the cached BufferView is correct.
        lyxerr[Debug::ACTION] << "BufferView::Pimpl::Dispatch:"
                << " action[" << cmd.action << ']'
@@ -1018,16 +1046,6 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd)
                cur.message(cur.currentState());
                break;
 
-       case LFUN_INSERT_LABEL: {
-               // Try and generate a valid label
-               string const contents = cmd.argument.empty() ?
-                       cur.getPossibleLabel() : cmd.argument;
-               InsetCommandParams icp("label", contents);
-               string data = InsetCommandMailer::params2string("label", icp);
-               owner_->getDialogs().show("label", data, 0);
-               break;
-       }
-
        case LFUN_BOOKMARK_SAVE:
                savePosition(strToUnsignedInt(cmd.argument));
                break;
@@ -1040,7 +1058,8 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd)
                string label = cmd.argument;
                if (label.empty()) {
                        InsetRef * inset =
-                               static_cast<InsetRef*>(getInsetByCode(InsetBase::REF_CODE));
+                               getInsetByCode<InsetRef>(bv_->cursor(),
+                                                        InsetBase::REF_CODE);
                        if (inset) {
                                label = inset->getContents();
                                savePosition(0);
@@ -1061,8 +1080,10 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd)
                break;
 
        case LFUN_ACCEPT_ALL_CHANGES: {
-               bv_->cursor().reset();
+               bv_->cursor().reset(bv_->buffer()->inset());
+#ifdef WITH_WARNINGS
 #warning FIXME changes
+#endif
                while (lyx::find::findNextChange(bv_))
                        bv_->getLyXText()->acceptChange(bv_->cursor());
                update();
@@ -1070,11 +1091,12 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd)
        }
 
        case LFUN_REJECT_ALL_CHANGES: {
-               bv_->cursor().reset();
+               bv_->cursor().reset(bv_->buffer()->inset());
+#ifdef WITH_WARNINGS
 #warning FIXME changes
+#endif
                while (lyx::find::findNextChange(bv_))
                        bv_->getLyXText()->rejectChange(bv_->cursor());
-               update();
                break;
        }
 
@@ -1088,7 +1110,6 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd)
 
        case LFUN_MARK_OFF:
                cur.clearSelection();
-               update();
                cur.resetAnchor();
                cur.message(N_("Mark off"));
                break;
@@ -1096,7 +1117,6 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd)
        case LFUN_MARK_ON:
                cur.clearSelection();
                cur.mark() = true;
-               update();
                cur.resetAnchor();
                cur.message(N_("Mark on"));
                break;
@@ -1111,17 +1131,28 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd)
                        cur.message(N_("Mark set"));
                }
                cur.resetAnchor();
-               update();
-               break;
-
-       case LFUN_UNKNOWN_ACTION:
-               cur.errorMessage(N_("Unknown function!"));
                break;
 
        case LFUN_CENTER:
                bv_->center();
                break;
 
+       case LFUN_BEGINNINGBUFSEL:
+               bv_->cursor().reset(bv_->buffer()->inset());
+               if (!cur.selection())
+                       cur.resetAnchor();
+               bv_->text()->cursorTop(cur);
+               finishUndo();
+               break;
+
+       case LFUN_ENDBUFSEL:
+               bv_->cursor().reset(bv_->buffer()->inset());
+               if (!cur.selection())
+                       cur.resetAnchor();
+               bv_->text()->cursorBottom(cur);
+               finishUndo();
+               break;
+
        default:
                return false;
        }