]> git.lyx.org Git - lyx.git/blobdiff - src/BufferView_pimpl.C
include sys/time.h
[lyx.git] / src / BufferView_pimpl.C
index b0bac3161019d4a7eefc5c2bd5a99d70768e13f0..34b5a478e357034a93c92d4a0ff62c214eb557a7 100644 (file)
@@ -8,10 +8,6 @@
 
 #include <config.h>
 
-#ifdef __GNUG__
-#pragma implementation
-#endif
-
 #include "BufferView_pimpl.h"
 #include "frontends/WorkArea.h"
 #include "frontends/screen.h"
@@ -20,6 +16,7 @@
 #include "frontends/Dialogs.h"
 #include "frontends/Alert.h"
 #include "frontends/FileDialog.h"
+#include "frontends/mouse_state.h"
 #include "lyxtext.h"
 #include "lyxrow.h"
 #include "paragraph.h"
 #include "ParagraphParameters.h"
 #include "undo_funcs.h"
 #include "funcrequest.h"
-#include "factory.h"
+#include "iterators.h"
+#include "lyxfind.h"
 
 #include "insets/insetbib.h"
 #include "insets/insettext.h"
-#include "insets/inseturl.h"
 #include "insets/insetlatexaccent.h"
 #include "insets/insettoc.h"
-#include "insets/insetref.h"
-#include "insets/insetparent.h"
 #include "insets/insetindex.h"
+#include "insets/insetref.h"
 #include "insets/insetinclude.h"
 #include "insets/insetcite.h"
 #include "insets/insetgraphics.h"
 #include "insets/insetmarginal.h"
-#include "insets/insettabular.h"
-#include "insets/insetcaption.h"
 #include "insets/insetfloatlist.h"
 
 #include "mathed/formulabase.h"
 #include "support/LAssert.h"
 #include "support/lstrings.h"
 #include "support/filetools.h"
-#include "support/lyxfunctional.h"
 
 #include <boost/bind.hpp>
 #include <boost/signals/connection.hpp>
+#include "BoostFormat.h"
 
-#include <cstdio>
-#include <ctime>
 #include <unistd.h>
 #include <sys/wait.h>
-#include <clocale>
-
 
-#ifndef CXX_GLOBAL_CSTD
-using std::tm;
-using std::localtime;
-using std::time;
-using std::setlocale;
-using std::strftime;
-#endif
 
 using std::vector;
 using std::find_if;
@@ -94,16 +77,8 @@ using std::make_pair;
 using std::min;
 
 using lyx::pos_type;
-using lyx::textclass_type;
-
-/* the selection possible is needed, that only motion events are
- * used, where the bottom press event was on the drawing area too */
-bool selection_possible = false;
 
 extern BufferList bufferlist;
-extern char ascii_type;
-
-extern int bibitemMaxWidth(BufferView *, LyXFont const &);
 
 
 namespace {
@@ -115,18 +90,15 @@ unsigned int const saved_positions_num = 20;
 // to these connections we avoid a segfault upon startup, and also at exit.
 // (Lgb)
 
+boost::signals::connection dispatchcon;
 boost::signals::connection timecon;
 boost::signals::connection doccon;
 boost::signals::connection resizecon;
-boost::signals::connection bpresscon;
-boost::signals::connection breleasecon;
-boost::signals::connection motioncon;
-boost::signals::connection doublecon;
-boost::signals::connection triplecon;
 boost::signals::connection kpresscon;
 boost::signals::connection selectioncon;
 boost::signals::connection lostcon;
 
+
 } // anon namespace
 
 
@@ -143,16 +115,8 @@ BufferView::Pimpl::Pimpl(BufferView * bv, LyXView * owner,
                .connect(boost::bind(&BufferView::Pimpl::scrollDocView, this, _1));
        resizecon = workarea().workAreaResize
                .connect(boost::bind(&BufferView::Pimpl::workAreaResize, this));
-       bpresscon = workarea().workAreaButtonPress
-               .connect(boost::bind(&BufferView::Pimpl::workAreaButtonPress, this, _1, _2, _3));
-       breleasecon = workarea().workAreaButtonRelease
-               .connect(boost::bind(&BufferView::Pimpl::workAreaButtonRelease, this, _1, _2, _3));
-       motioncon = workarea().workAreaMotionNotify
-               .connect(boost::bind(&BufferView::Pimpl::workAreaMotionNotify, this, _1, _2, _3));
-       doublecon = workarea().workAreaDoubleClick
-               .connect(boost::bind(&BufferView::Pimpl::doubleClick, this, _1, _2, _3));
-       triplecon = workarea().workAreaTripleClick
-               .connect(boost::bind(&BufferView::Pimpl::tripleClick, this, _1, _2, _3));
+       dispatchcon = workarea().dispatch
+               .connect(boost::bind(&BufferView::Pimpl::dispatch, this, _1));
        kpresscon = workarea().workAreaKeyPress
                .connect(boost::bind(&BufferView::Pimpl::workAreaKeyPress, this, _1, _2));
        selectioncon = workarea().selectionRequested
@@ -188,7 +152,7 @@ Painter & BufferView::Pimpl::painter() const
 void BufferView::Pimpl::buffer(Buffer * b)
 {
        lyxerr[Debug::INFO] << "Setting buffer in BufferView ("
-                           << b << ")" << endl;
+                           << b << ')' << endl;
        if (buffer_) {
                buffer_->delUser(bv_);
 
@@ -206,7 +170,9 @@ void BufferView::Pimpl::buffer(Buffer * b)
        // set current buffer
        buffer_ = b;
 
-       if (bufferlist.getState() == BufferList::CLOSING) return;
+       // 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_) {
@@ -299,8 +265,8 @@ int BufferView::Pimpl::resizeCurrentBuffer()
        bool selection = false;
        bool mark_set  = false;
 
-       owner_->prohibitInput();
-
+       owner_->busy(true);
        owner_->message(_("Formatting document..."));
 
        if (bv_->text) {
@@ -332,6 +298,8 @@ int BufferView::Pimpl::resizeCurrentBuffer()
                        //      bv_->text->owner(bv_);
                        if (lyxerr.debugging())
                                textcache.show(lyxerr, "resizeCurrentBuffer");
+
+                       buffer_->resizeInsets(bv_);
                } else {
                        bv_->text = new LyXText(bv_);
                        bv_->text->init(bv_);
@@ -362,7 +330,7 @@ int BufferView::Pimpl::resizeCurrentBuffer()
        bv_->text->first_y = screen().topCursorVisible(bv_->text->cursor, bv_->text->first_y);
 
        switchKeyMap();
-       owner_->allowInput();
+       owner_->busy(false);
 
        updateScrollbar();
 
@@ -388,9 +356,9 @@ void BufferView::Pimpl::updateScrollbar()
        LyXText const & t = *bv_->text;
 
        lyxerr[Debug::GUI] << "Updating scrollbar: h " << t.height << ", first_y "
-               << t.first_y << ", default height " << t.defaultHeight() << endl;
+               << t.first_y << ", default height " << defaultRowHeight() << endl;
 
-       workarea().setScrollbarParams(t.height, t.first_y, t.defaultHeight());
+       workarea().setScrollbarParams(t.height, t.first_y, defaultRowHeight());
 }
 
 
@@ -398,17 +366,17 @@ void BufferView::Pimpl::scrollDocView(int value)
 {
        lyxerr[Debug::GUI] << "scrollDocView of " << value << endl;
 
-       if (!buffer_) return;
+       if (!buffer_)
+               return;
 
        screen().draw(bv_->text, bv_, value);
 
-       if (!lyxrc.cursor_follows_scrollbar) {
+       if (!lyxrc.cursor_follows_scrollbar)
                return;
-       }
 
        LyXText * vbt = bv_->text;
 
-       int const height = vbt->defaultHeight();
+       int const height = defaultRowHeight();
        int const first = static_cast<int>((bv_->text->first_y + height));
        int const last = static_cast<int>((bv_->text->first_y + workarea().workHeight() - height));
 
@@ -419,253 +387,33 @@ void BufferView::Pimpl::scrollDocView(int value)
 }
 
 
-int BufferView::Pimpl::scroll(long time)
-{
-       if (!buffer_)
-               return 0;
-
-       LyXText const * t = bv_->text;
-
-       double const diff = t->defaultHeight()
-               + double(time) * double(time) * 0.125;
-
-       scrollDocView(int(diff));
-       workarea().setScrollbarParams(t->height, t->first_y, t->defaultHeight());
-       return 0;
-}
-
-
-void BufferView::Pimpl::workAreaKeyPress(LyXKeySymPtr key,
-                                        key_modifier::state state)
-{
-       bv_->owner()->getLyXFunc().processKeySym(key, state);
-}
-
-
-void BufferView::Pimpl::workAreaMotionNotify(int x, int y, mouse_button::state state)
-{
-       // Only use motion with button 1
-       if (!(state & mouse_button::button1))
-               return;
-
-       if (!buffer_)
-               return;
-
-       // Check for inset locking
-       if (bv_->theLockingInset()) {
-               LyXCursor cursor = bv_->text->cursor;
-               LyXFont font = bv_->text->getFont(buffer_,
-                                                 cursor.par(), cursor.pos());
-               int width = bv_->theLockingInset()->width(bv_, font);
-               int inset_x = font.isVisibleRightToLeft()
-                       ? cursor.ix() - width : cursor.ix();
-               int start_x = inset_x + bv_->theLockingInset()->scroll();
-
-               FuncRequest cmd(bv_, LFUN_MOUSE_MOTION,
-                                 x - start_x, y - cursor.iy() + bv_->text->first_y, state);
-               bv_->theLockingInset()->localDispatch(cmd);
-               return;
-       }
-
-       // The test for not selection possible is needed, that only motion
-       // events are used, where the bottom press event was on
-       //  the drawing area too
-       if (!selection_possible)
-               return;
-
-       screen().hideCursor();
-
-       Row * cursorrow = bv_->text->cursor.row();
-       bv_->text->setCursorFromCoordinates(bv_, x, y + bv_->text->first_y);
-#if 0
-       // sorry for this but I have a strange error that the y value jumps at
-       // a certain point. This seems like an error in my xforms library or
-       // in some other local environment, but I would like to leave this here
-       // for the moment until I can remove this (Jug 20020418)
-       if (y_before < bv_->text->cursor.y())
-               lyxerr << y_before << ":" << bv_->text->cursor.y() << endl;
-#endif
-       // This is to allow jumping over large insets
-       if (cursorrow == bv_->text->cursor.row()) {
-               if (y >= int(workarea().workHeight())) {
-                       bv_->text->cursorDown(bv_, false);
-               } else if (y < 0) {
-                       bv_->text->cursorUp(bv_, false);
-               }
-       }
-
-       if (!bv_->text->selection.set())
-               update(bv_->text, BufferView::UPDATE); // Maybe an empty line was deleted
-
-       bv_->text->setSelection(bv_);
-       screen().toggleToggle(bv_->text, bv_);
-       fitCursor();
-       showCursor();
-}
-
-
-// Single-click on work area
-void BufferView::Pimpl::workAreaButtonPress(int xpos, int ypos,
-                                           mouse_button::state button)
+void BufferView::Pimpl::scroll(int lines)
 {
-       if (!buffer_)
-               return;
-
-       // ok ok, this is a hack (for xforms)
-       if (button == mouse_button::button4) {
-               scroll(-lyxrc.wheel_jump);
-               // We shouldn't go further down as we really should only do the
-               // scrolling and be done with this. Otherwise we may open some
-               // dialogs (Jug 20020424).
-               return;
-       } else if (button == mouse_button::button5) {
-               scroll(lyxrc.wheel_jump);
-               // We shouldn't go further down as we really should only do the
-               // scrolling and be done with this. Otherwise we may open some
-               // dialogs (Jug 20020424).
-               return;
-       }
-
-       Inset * inset_hit = checkInsetHit(bv_->text, xpos, ypos);
-
-       // Middle button press pastes if we have a selection
-       // We do this here as if the selection was inside an inset
-       // it could get cleared on the unlocking of the inset so
-       // we have to check this first
-       bool paste_internally = false;
-       if (button == mouse_button::button2 && bv_->getLyXText()->selection.set()) {
-               owner_->dispatch(FuncRequest(LFUN_COPY));
-               paste_internally = true;
-       }
-
-       int const screen_first = bv_->text->first_y;
-
-       if (bv_->theLockingInset()) {
-               // We are in inset locking mode
-
-               // Check whether the inset was hit. If not reset mode,
-               // otherwise give the event to the inset
-               if (inset_hit == bv_->theLockingInset()) {
-                       FuncRequest cmd(bv_, LFUN_MOUSE_PRESS, xpos, ypos, button);
-                       bv_->theLockingInset()->localDispatch(cmd);
-                       return;
-               }
-               bv_->unlockInset(bv_->theLockingInset());
-       }
-
-       if (!inset_hit)
-               selection_possible = true;
-       screen().hideCursor();
-
-       // Clear the selection
-       screen().toggleSelection(bv_->text, bv_);
-       bv_->text->clearSelection();
-       bv_->text->fullRebreak(bv_);
-       update();
-       updateScrollbar();
-
-       // Single left click in math inset?
-       if (isHighlyEditableInset(inset_hit)) {
-               // Highly editable inset, like math
-               UpdatableInset * inset = static_cast<UpdatableInset *>(inset_hit);
-               selection_possible = false;
-               owner_->updateLayoutChoice();
-               owner_->message(inset->editMessage());
-               //inset->edit(bv_, xpos, ypos, button);
-               // We just have to lock the inset before calling a PressEvent on it!
-               // we don't need the edit() call here! (Jug20020329)
-               if (!bv_->lockInset(inset)) {
-                       lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
-               }
-               FuncRequest cmd(bv_, LFUN_MOUSE_PRESS, xpos, ypos, button);
-               inset->localDispatch(cmd);
-               return;
-       }
-       // I'm not sure we should continue here if we hit an inset (Jug20020403)
-
-       // Right click on a footnote flag opens float menu
-       if (button == mouse_button::button3) {
-               selection_possible = false;
-               return;
-       }
-
-       if (!inset_hit) // otherwise it was already set in checkInsetHit(...)
-               bv_->text->setCursorFromCoordinates(bv_, xpos, ypos + screen_first);
-       finishUndo();
-       bv_->text->selection.cursor = bv_->text->cursor;
-       bv_->text->cursor.x_fix(bv_->text->cursor.x());
-
-       owner_->updateLayoutChoice();
-       if (fitCursor()) {
-               selection_possible = false;
-       }
-
-       // Insert primary selection with middle mouse
-       // if there is a local selection in the current buffer,
-       // insert this
-       if (button == mouse_button::button2) {
-               if (paste_internally)
-                       owner_->dispatch(FuncRequest(LFUN_PASTE));
-               else
-                       owner_->dispatch(FuncRequest(LFUN_PASTESELECTION, "paragraph"));
-               selection_possible = false;
+       if (!buffer_) {
                return;
        }
-}
 
+       LyXText const * t = bv_->text;
+       int const line_height = defaultRowHeight();
 
-void BufferView::Pimpl::doubleClick(int /*x*/, int /*y*/, mouse_button::state button)
-{
-       if (!buffer_)
-               return;
+       // The new absolute coordinate
+       int new_first_y = t->first_y + lines * line_height;
 
-       LyXText * text = bv_->getLyXText();
+       // Restrict to a valid value
+       new_first_y = std::min(t->height - 4 * line_height, new_first_y);
+       new_first_y = std::max(0, new_first_y);
 
-       if (text->bv_owner && bv_->theLockingInset())
-               return;
+       scrollDocView(new_first_y);
 
-       if (button == mouse_button::button1) {
-               if (text->bv_owner) {
-                       screen().hideCursor();
-                       screen().toggleSelection(text, bv_);
-                       text->selectWord(bv_, LyXText::WHOLE_WORD_STRICT);
-                       screen().toggleSelection(text, bv_, false);
-               } else {
-                       text->selectWord(bv_, LyXText::WHOLE_WORD_STRICT);
-               }
-               // This will fit the cursor on the screen if necessary
-               update(text, BufferView::SELECT|BufferView::FITCUR);
-               workarea().haveSelection(bv_->getLyXText()->selection.set());
-       }
+       // Update the scrollbar.
+       workarea().setScrollbarParams(t->height, t->first_y, defaultRowHeight());
 }
 
 
-void BufferView::Pimpl::tripleClick(int /*x*/, int /*y*/, mouse_button::state button)
+void BufferView::Pimpl::workAreaKeyPress(LyXKeySymPtr key,
+                                        key_modifier::state state)
 {
-       if (!buffer_)
-               return;
-
-       LyXText * text = bv_->getLyXText();
-
-       if (text->bv_owner && bv_->theLockingInset())
-           return;
-
-       if (button == mouse_button::button1) {
-               if (text->bv_owner) {
-                       screen().hideCursor();
-                       screen().toggleSelection(text, bv_);
-               }
-               text->cursorHome(bv_);
-               text->selection.cursor = text->cursor;
-               text->cursorEnd(bv_);
-               text->setSelection(bv_);
-               if (text->bv_owner) {
-                       screen().toggleSelection(text, bv_, false);
-               }
-               // This will fit the cursor on the screen if necessary
-               update(text, BufferView::SELECT|BufferView::FITCUR);
-               workarea().haveSelection(bv_->getLyXText()->selection.set());
-       }
+       bv_->owner()->getLyXFunc().processKeySym(key, state);
 }
 
 
@@ -707,207 +455,6 @@ void BufferView::Pimpl::selectionLost()
 }
 
 
-void BufferView::Pimpl::workAreaButtonRelease(int x, int y,
-                                             mouse_button::state button)
-{
-       // do nothing if we used the mouse wheel
-       if (!buffer_ || button == mouse_button::button4 || button == mouse_button::button5)
-               return;
-
-       // If we hit an inset, we have the inset coordinates in these
-       // and inset_hit points to the inset.  If we do not hit an
-       // inset, inset_hit is 0, and inset_x == x, inset_y == y.
-       Inset * inset_hit = checkInsetHit(bv_->text, x, y);
-
-       if (bv_->theLockingInset()) {
-               // We are in inset locking mode.
-
-               // LyX does a kind of work-area grabbing for insets.
-               // Only a ButtonPress FuncRequest outside the inset will
-               // force a insetUnlock.
-               FuncRequest cmd(bv_, LFUN_MOUSE_RELEASE, x, y, button);
-               bv_->theLockingInset()->localDispatch(cmd);
-               return;
-       }
-
-       selection_possible = false;
-
-       if (button == mouse_button::button2)
-               return;
-
-       // finish selection
-       if (button == mouse_button::button1) {
-               workarea().haveSelection(bv_->getLyXText()->selection.set());
-       }
-
-       switchKeyMap();
-       owner_->view_state_changed();
-       owner_->updateMenubar();
-       owner_->updateToolbar();
-
-       // Did we hit an editable inset?
-       if (inset_hit) {
-               selection_possible = false;
-
-               // if we reach this point with a selection, it
-               // must mean we are currently selecting.
-               // But we don't want to open the inset
-               // because that is annoying for the user.
-               // So just pretend we didn't hit it.
-               // this is OK because a "kosher" ButtonRelease
-               // will follow a ButtonPress that clears
-               // the selection.
-               // Note this also fixes selection drawing
-               // problems if we end up opening an inset
-               if (bv_->getLyXText()->selection.set())
-                       return;
-
-               // CHECK fix this proper in 0.13
-               // well, maybe 13.0 !!!!!!!!!
-
-               // Following a ref shouldn't issue
-               // a push on the undo-stack
-               // anylonger, now that we have
-               // keybindings for following
-               // references and returning from
-               // references.  IMHO though, it
-               // should be the inset's own business
-               // to push or not push on the undo
-               // stack. They don't *have* to
-               // alter the document...
-               // (Joacim)
-               // ...or maybe the SetCursorParUndo()
-               // below isn't necessary at all anylonger?
-               if (inset_hit->lyxCode() == Inset::REF_CODE) {
-                       setCursorParUndo(bv_);
-               }
-
-               owner_->message(inset_hit->editMessage());
-
-               if (isHighlyEditableInset(inset_hit)) {
-                       // Highly editable inset, like math
-                       UpdatableInset *inset = (UpdatableInset *)inset_hit;
-                       FuncRequest cmd(bv_, LFUN_MOUSE_RELEASE, x, y, button);
-                       inset->localDispatch(cmd);
-               } else {
-                       FuncRequest cmd(bv_, LFUN_MOUSE_RELEASE, x, y, button);
-                       inset_hit->localDispatch(cmd);
-                       // IMO this is a grosshack! Inset's should be changed so that
-                       // they call the actions they have to do with the insetButtonRel.
-                       // function and not in the edit(). This should be changed
-                       // (Jug 20020329)
-#ifdef WITH_WARNINGS
-#warning Please remove donot call inset->edit() here (Jug 20020812)
-#endif
-                       inset_hit->edit(bv_, x, y, button);
-               }
-               return;
-       }
-
-       // Maybe we want to edit a bibitem ale970302
-       if (bv_->text->cursor.par()->bibkey) {
-               bool const is_rtl = bv_->text->cursor.par()->isRightToLeftPar(buffer_->params);
-               int const width = bibitemMaxWidth(bv_, buffer_->params.getLyXTextClass().defaultfont());
-               if ((is_rtl && x > bv_->text->workWidth(bv_)-20-width) ||
-                   (!is_rtl && x < 20+width)) {
-                       bv_->text->cursor.par()->bibkey->edit(bv_, 0, 0, mouse_button::none);
-               }
-       }
-
-       return;
-}
-
-
-Box BufferView::Pimpl::insetDimensions(LyXText const & text,
-                                      LyXCursor const & cursor) const
-{
-       Paragraph /*const*/ & par = *cursor.par();
-       pos_type const pos = cursor.pos();
-
-       lyx::Assert(par.getInset(pos));
-
-       Inset const & inset(*par.getInset(pos));
-
-       LyXFont const & font = text.getFont(buffer_, &par, pos);
-
-       int const width = inset.width(bv_, font);
-       int const inset_x = font.isVisibleRightToLeft()
-               ? (cursor.ix() - width) : cursor.ix();
-
-       return Box(
-               inset_x + inset.scroll(),
-               inset_x + width,
-               cursor.iy() - inset.ascent(bv_, font),
-               cursor.iy() + inset.descent(bv_, font));
-}
-
-
-Inset * BufferView::Pimpl::checkInset(LyXText const & text,
-                                     LyXCursor const & cursor,
-                                     int & x, int & y) const
-{
-       pos_type const pos(cursor.pos());
-       Paragraph /*const*/ & par(*cursor.par());
-
-       if (pos >= par.size() || !par.isInset(pos)) {
-               return 0;
-       }
-
-       Inset /*const*/ * inset = par.getInset(pos);
-
-       if (!isEditableInset(inset)) {
-               return 0;
-       }
-
-       Box b(insetDimensions(text, cursor));
-
-       if (!b.contained(x, y)) {
-               lyxerr[Debug::GUI] << "Missed inset at x,y " << x << "," << y
-                       << " box " << b << endl;
-               return 0;
-       }
-
-       text.setCursor(bv_, &par, pos, true);
-
-       x -= b.x1;
-       // The origin of an inset is on the baseline
-       y -= text.cursor.iy();
-
-       return inset;
-}
-
-
-Inset * BufferView::Pimpl::checkInsetHit(LyXText * text, int & x, int & y)
-{
-       int y_tmp = y + text->first_y;
-
-       LyXCursor cursor;
-       text->setCursorFromCoordinates(bv_, cursor, x, y_tmp);
-
-       Inset * inset = checkInset(*text, cursor, x, y_tmp);
-
-       if (inset) {
-               y = y_tmp;
-               return inset;
-       }
-
-       // look at previous position
-
-       if (cursor.pos() == 0) {
-               return 0;
-       }
-
-       // move back one
-       text->setCursor(bv_, cursor, cursor.par(), cursor.pos() - 1, true);
-
-       inset = checkInset(*text, cursor, x, y_tmp);
-       if (inset) {
-               y = y_tmp;
-       }
-       return inset;
-}
-
-
 void BufferView::Pimpl::workAreaResize()
 {
        static int work_area_width;
@@ -1059,10 +606,6 @@ void BufferView::Pimpl::cursorToggle()
                return;
        }
 
-       /* FIXME */
-       extern void reapSpellchecker(void);
-       reapSpellchecker();
-
        if (!bv_->theLockingInset()) {
                screen().cursorToggle(bv_);
        } else {
@@ -1081,6 +624,21 @@ bool BufferView::Pimpl::available() const
 }
 
 
+Change const BufferView::Pimpl::getCurrentChange()
+{
+       if (!bv_->buffer()->params.tracking_changes) 
+               return Change(Change::UNCHANGED);
+
+       LyXText * t(bv_->getLyXText());
+       if (!t->selection.set())
+               return Change(Change::UNCHANGED);
+       LyXCursor const & cur(t->selection.start);
+       return cur.par()->lookupChangeFull(cur.pos());
+}
+
+
 void BufferView::Pimpl::beforeChange(LyXText * text)
 {
        toggleSelection();
@@ -1097,8 +655,12 @@ void BufferView::Pimpl::savePosition(unsigned int i)
                                      bv_->text->cursor.pos());
        if (i > 0) {
                ostringstream str;
-               str << _("Saved bookmark") << ' ' << i;
-               owner_->message(str.str().c_str());
+#if USE_BOOST_FORMAT
+               str << boost::format(_("Saved bookmark %1$d")) % i;
+#else
+               str << _("Saved bookmark ") << i;
+#endif
+               owner_->message(STRCONV(str.str()));
        }
 }
 
@@ -1129,8 +691,12 @@ void BufferView::Pimpl::restorePosition(unsigned int i)
        update(bv_->text, BufferView::SELECT | BufferView::FITCUR);
        if (i > 0) {
                ostringstream str;
-               str << _("Moved to bookmark") << ' ' << i;
-               owner_->message(str.str().c_str());
+#if USE_BOOST_FORMAT
+               str << boost::format(_("Moved to bookmark %1$d")) % i;
+#else
+               str << _("Moved to bookmark ") << i;
+#endif
+               owner_->message(STRCONV(str.str()));
        }
 }
 
@@ -1242,36 +808,6 @@ void BufferView::Pimpl::stuffClipboard(string const & stuff) const
  */
 
 
-void BufferView::Pimpl::moveCursorUpdate(bool selecting, bool fitcur)
-{
-       LyXText * lt = bv_->getLyXText();
-
-       if (selecting || lt->selection.mark()) {
-               lt->setSelection(bv_);
-               if (lt->bv_owner)
-                       toggleToggle();
-               else
-                       updateInset(lt->inset_owner, false);
-       }
-       if (lt->bv_owner) {
-               if (fitcur)
-                       update(lt, BufferView::SELECT|BufferView::FITCUR);
-               else
-                       update(lt, BufferView::SELECT);
-               showCursor();
-       } else if (bv_->text->status() != LyXText::UNCHANGED) {
-               bv_->theLockingInset()->hideInsetCursor(bv_);
-               update(bv_->text, BufferView::SELECT|BufferView::FITCUR);
-               showCursor();
-       }
-
-       if (!lt->selection.set())
-               workarea().haveSelection(false);
-
-       switchKeyMap();
-}
-
-
 Inset * BufferView::Pimpl::getInsetByCode(Inset::Code code)
 {
 #if 0
@@ -1345,7 +881,7 @@ void BufferView::Pimpl::MenuInsertLyXFile(string const & filen)
                                  string(AddPath(system_lyxdir, "examples"))));
 
                FileDialog::Result result =
-                       fileDlg.Select(initpath,
+                       fileDlg.open(initpath,
                                       _("*.lyx| LyX Documents (*.lyx)"));
 
                if (result.first == FileDialog::Later)
@@ -1367,43 +903,88 @@ void BufferView::Pimpl::MenuInsertLyXFile(string const & filen)
        string const disp_fn(MakeDisplayPath(filename));
 
        ostringstream s1;
-       s1 << _("Inserting document") << ' '
-          << disp_fn << " ...";
-       owner_->message(s1.str().c_str());
+#if USE_BOOST_FORMAT
+       s1 << boost::format(_("Inserting document %1$s...")) % disp_fn;
+#else
+       s1 << _("Inserting document ") << disp_fn << _("...");
+#endif
+       owner_->message(STRCONV(s1.str()));
        bool const res = bv_->insertLyXFile(filename);
        if (res) {
                ostringstream str;
-               str << _("Document") << ' ' << disp_fn
-                   << ' ' << _("inserted.");
-               owner_->message(str.str().c_str());
+#if USE_BOOST_FORMAT
+               str << boost::format(_("Document %1$s inserted.")) % disp_fn;
+#else
+               str << _("Document ") << disp_fn << _(" inserted.");
+#endif
+               owner_->message(STRCONV(str.str()));
        } else {
                ostringstream str;
-               str << _("Could not insert document") << ' '
-                   << disp_fn;
-               owner_->message(str.str().c_str());
+#if USE_BOOST_FORMAT
+               str << boost::format(_("Could not insert document %1$s")) % disp_fn;
+#else
+               str << _("Could not insert document ") << disp_fn;
+#endif
+               owner_->message(STRCONV(str.str()));
        }
 }
 
 
+void BufferView::Pimpl::trackChanges()
+{
+       Buffer * buf(bv_->buffer());
+       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();
+               }
+               buf->params.tracking_changes = true;
+
+               // we cannot allow undos beyond the freeze point
+               buf->undostack.clear();
+       } else {
+               bv_->update(bv_->text, BufferView::SELECT | BufferView::FITCUR);
+               bv_->text->setCursor(bv_, &(*buf->paragraphs.begin()), 0);
+#warning changes FIXME 
+               //moveCursorUpdate(false);
+
+               bool found = lyxfind::findNextChange(bv_);
+               if (found) {
+                       owner_->getDialogs().showMergeChanges();
+                       return;
+               }
+
+               ParIterator const end = buf->par_iterator_end();
+               for (ParIterator it = buf->par_iterator_begin(); it != end; ++it) {
+                       (*it)->untrackChanges();
+               }
+               buf->params.tracking_changes = false;
+       }
+       buf->redostack.clear();
+}
+
+
 bool BufferView::Pimpl::dispatch(FuncRequest const & ev)
 {
-       lyxerr[Debug::ACTION] << "BufferView::Pimpl::Dispatch: action["
-         << ev.action <<"] arg[" << ev.argument << "]" << endl;
+       lyxerr[Debug::ACTION] << "BufferView::Pimpl::Dispatch:"
+               << " action[" << ev.action << ']'
+               << " arg[" << ev.argument << ']'
+               << " x[" << ev.x << ']'
+               << " y[" << ev.y << ']'
+               << " button[" << ev.button() << ']'
+               << endl;
+
+       // e.g. Qt mouse press when no buffer
+       if (!buffer_)
+               return false;
 
        LyXTextClass const & tclass = buffer_->params.getLyXTextClass();
 
        switch (ev.action) {
 
-       case LFUN_TOC_INSERT:
-       {
-               InsetCommandParams p;
-               p.setCmdName("tableofcontents");
-               Inset * inset = new InsetTOC(p);
-               if (!insertInset(inset, tclass.defaultLayoutName()))
-                       delete inset;
-               break;
-       }
-
        case LFUN_SCROLL_INSET:
                // this is not handled here as this function is only active
                // if we have a locking_inset and that one is (or contains)
@@ -1561,107 +1142,6 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & ev)
        }
        break;
 
-       case LFUN_HTMLURL:
-       case LFUN_URL:
-       {
-               InsetCommandParams p;
-               if (ev.action == LFUN_HTMLURL)
-                       p.setCmdName("htmlurl");
-               else
-                       p.setCmdName("url");
-               owner_->getDialogs().createUrl(p.getAsString());
-       }
-       break;
-
-       case LFUN_INSERT_URL:
-       {
-               InsetCommandParams p;
-               p.setFromString(ev.argument);
-
-               InsetUrl * inset = new InsetUrl(p);
-               if (!insertInset(inset))
-                       delete inset;
-               else
-                       updateInset(inset, true);
-       }
-       break;
-
-#if 0
-       case LFUN_INSET_LIST:
-       case LFUN_INSET_THEOREM:
-#endif
-       case LFUN_INSERT_NOTE:
-       case LFUN_INSET_ERT:
-       case LFUN_INSET_EXTERNAL:
-       case LFUN_INSET_FLOAT:
-       case LFUN_INSET_FOOTNOTE:
-       case LFUN_INSET_MARGINAL:
-       case LFUN_INSET_MINIPAGE:
-       case LFUN_INSET_OPTARG:
-       case LFUN_INSET_WIDE_FLOAT:
-       {
-               FuncRequest cmd = ev;
-               cmd.setView(bv_);
-               Inset * inset = createInset(cmd);
-               if (inset) {
-                       bool gotsel = false;
-
-                       if (bv_->getLyXText()->selection.set()) {
-                               bv_->getLyXText()->cutSelection(bv_, true, false);
-                               gotsel = true;
-                       }
-
-                       if (insertInset(inset)) {
-                               inset->edit(bv_);
-                               if (gotsel)
-                                       owner_->dispatch(FuncRequest(LFUN_PASTESELECTION));
-                       }
-                       else
-                               delete inset;
-               }
-               break;
-       }
-
-       case LFUN_INSET_CAPTION:
-       {
-               // Do we have a locking inset...
-               if (bv_->theLockingInset()) {
-                       lyxerr << "Locking inset code: "
-                              << static_cast<int>(bv_->theLockingInset()->lyxCode());
-                       InsetCaption * new_inset =
-                               new InsetCaption(buffer_->params);
-                       new_inset->setOwner(bv_->theLockingInset());
-                       new_inset->setAutoBreakRows(true);
-                       new_inset->setDrawFrame(0, InsetText::LOCKED);
-                       new_inset->setFrameColor(0, LColor::captionframe);
-                       if (insertInset(new_inset))
-                               new_inset->edit(bv_);
-                       else
-                               delete new_inset;
-               }
-       }
-       break;
-
-       case LFUN_TABULAR_INSERT:
-       {
-               if (ev.argument.empty()) {
-                       owner_->getDialogs().showTabularCreate();
-                       break;
-               }
-
-               int r = 2;
-               int c = 2;
-               ::sscanf(ev.argument.c_str(),"%d%d", &r, &c);
-               InsetTabular * new_inset =
-                       new InsetTabular(*buffer_, r, c);
-               bool const rtl =
-                       bv_->getLyXText()->real_current_font.isRightToLeft();
-               if (!open_new_inset(new_inset, rtl))
-                       delete new_inset;
-       }
-       break;
-
-
        // --- accented characters ---------------------------
 
        case LFUN_UMLAUT:
@@ -1714,8 +1194,11 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & ev)
                InsetCitation * inset = new InsetCitation(p);
                if (!insertInset(inset))
                        delete inset;
-               else
+               else {
+                       inset->setLoadingBuffer(bv_->buffer(), false);
                        updateInset(inset, true);
+               }
+
        }
        break;
 
@@ -1755,9 +1238,8 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & ev)
        {
                InsetBibtex * inset =
                        static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
-               if (inset) {
+               if (inset)
                        inset->delDatabase(ev.argument);
-               }
        }
        break;
 
@@ -1765,56 +1247,16 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & ev)
        {
                InsetBibtex * inset =
                        static_cast<InsetBibtex*>(getInsetByCode(Inset::BIBTEX_CODE));
-               if (inset) {
+               if (inset)
                        inset->setOptions(ev.argument);
-               }
        }
        break;
 
-       case LFUN_INDEX_INSERT:
-       {
-               string entry = ev.argument;
-               if (entry.empty())
-                       entry = bv_->getLyXText()->getStringToIndex(bv_);
-
-               if (entry.empty()) {
-                       owner_->getDialogs().createIndex();
-                       break;
-               }
-
-               InsetIndex * inset = new InsetIndex(InsetCommandParams("index", entry));
-
-               if (!insertInset(inset)) {
-                       delete inset;
-               } else {
-                       updateInset(inset, true);
-               }
-       }
-       break;
-
-       case LFUN_INDEX_PRINT:
-       {
-               InsetCommandParams p("printindex");
-               Inset * inset = new InsetPrintIndex(p);
-               if (!insertInset(inset, tclass.defaultLayoutName()))
-                       delete inset;
-       }
-       break;
-
-       case LFUN_PARENTINSERT:
-       {
-               InsetCommandParams p("lyxparent", ev.argument);
-               Inset * inset = new InsetParent(p, *buffer_);
-               if (!insertInset(inset, tclass.defaultLayoutName()))
-                       delete inset;
-       }
-
-       break;
-
        case LFUN_CHILD_INSERT:
        {
                InsetInclude::Params p;
-               p.cparams.setFromString(ev.argument);
+               if (!ev.argument.empty())
+                       p.cparams.setFromString(ev.argument);
                p.masterFilename_ = buffer_->fileName();
 
                InsetInclude * inset = new InsetInclude(p);
@@ -1828,7 +1270,7 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & ev)
        break;
 
        case LFUN_FLOAT_LIST:
-               if (floatList.typeExist(ev.argument)) {
+               if (tclass.floats().typeExist(ev.argument)) {
                        Inset * inset = new InsetFloatList(ev.argument);
                        if (!insertInset(inset, tclass.defaultLayoutName()))
                                delete inset;
@@ -1859,72 +1301,75 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & ev)
        }
                break;
 
-       case LFUN_DATE_INSERT:  // jdblair: date-insert cmd
-       {
-               time_t now_time_t = time(NULL);
-               struct tm * now_tm = localtime(&now_time_t);
-               setlocale(LC_TIME, "");
-               string arg;
-               if (!ev.argument.empty())
-                       arg = ev.argument;
-               else
-                       arg = lyxrc.date_insert_format;
-               char datetmp[32];
-               int const datetmp_len =
-                       ::strftime(datetmp, 32, arg.c_str(), now_tm);
-
-               LyXText * lt = bv_->getLyXText();
-
-               for (int i = 0; i < datetmp_len; i++) {
-                       lt->insertChar(bv_, datetmp[i]);
-                       update(lt,
-                              BufferView::SELECT
-                              | BufferView::FITCUR
-                              | BufferView::CHANGE);
+       case LFUN_TRACK_CHANGES:
+               trackChanges();
+               break;
+       case LFUN_MERGE_CHANGES:
+               owner_->getDialogs().showMergeChanges();
+               break;
+       case LFUN_ACCEPT_ALL_CHANGES: {
+               bv_->update(bv_->text, BufferView::SELECT | BufferView::FITCUR);
+               bv_->text->setCursor(bv_, &(*bv_->buffer()->paragraphs.begin()), 0);
+#warning FIXME changes 
+               //moveCursorUpdate(false);
+
+               while (lyxfind::findNextChange(bv_)) {
+                       bv_->getLyXText()->acceptChange(bv_);
                }
+               update(bv_->text,
+                       BufferView::SELECT | BufferView::FITCUR | BufferView::CHANGE);
+               break;
+       }
+       case LFUN_REJECT_ALL_CHANGES: {
+               bv_->update(bv_->text, BufferView::SELECT | BufferView::FITCUR);
+               bv_->text->setCursor(bv_, &(*bv_->buffer()->paragraphs.begin()), 0);
+#warning FIXME changes 
+               //moveCursorUpdate(false);
 
-               lt->selection.cursor = lt->cursor;
-               moveCursorUpdate(false);
+               while (lyxfind::findNextChange(bv_)) {
+                       bv_->getLyXText()->rejectChange(bv_);
+               }
+               update(bv_->text,
+                       BufferView::SELECT | BufferView::FITCUR | BufferView::CHANGE);
+               break;
+       }
+       case LFUN_ACCEPT_CHANGE: {
+               bv_->getLyXText()->acceptChange(bv_);
+               update(bv_->text,
+                       BufferView::SELECT | BufferView::FITCUR | BufferView::CHANGE);
+               break;
        }
-       break;
 
+       case LFUN_REJECT_CHANGE: {
+               bv_->getLyXText()->rejectChange(bv_);
+               update(bv_->text,
+                       BufferView::SELECT | BufferView::FITCUR | BufferView::CHANGE);
+               break;
+       }
        case LFUN_UNKNOWN_ACTION:
                ev.errorMessage(N_("Unknown function!"));
                break;
 
        default:
-               FuncRequest cmd = ev;
-               cmd.setView(bv_);
-               return bv_->getLyXText()->dispatch(cmd);
+               return bv_->getLyXText()->dispatch(FuncRequest(ev, bv_));
        } // end of switch
 
        return true;
 }
 
 
-// Open and lock an updatable inset
-bool BufferView::Pimpl::open_new_inset(UpdatableInset * new_inset, bool behind)
-{
-       LyXText * lt = bv_->getLyXText();
-
-       beforeChange(lt);
-       finishUndo();
-       if (!insertInset(new_inset)) {
-               delete new_inset;
-               return false;
-       }
-       new_inset->edit(bv_, !behind);
-       return true;
-}
-
-
 bool BufferView::Pimpl::insertInset(Inset * inset, string const & lout)
 {
        // if we are in a locking inset we should try to insert the
        // inset there otherwise this is a illegal function now
        if (bv_->theLockingInset()) {
                if (bv_->theLockingInset()->insetAllowed(inset))
-                   return bv_->theLockingInset()->insertInset(bv_, inset);
+                       return bv_->theLockingInset()->insertInset(bv_, inset);
                return false;
        }