]> git.lyx.org Git - lyx.git/blobdiff - src/Text3.cpp
english_language was not used at all.
[lyx.git] / src / Text3.cpp
index c80886e9b7f914df9bb8eb1485784c3963cd5c87..3dd736b9dd698d399466b69d843bb7d5568cb530 100644 (file)
 #include "BufferView.h"
 #include "Cursor.h"
 #include "CutAndPaste.h"
-#include "support/debug.h"
 #include "DispatchResult.h"
 #include "ErrorList.h"
 #include "factory.h"
 #include "FuncRequest.h"
-#include "support/gettext.h"
 #include "InsetList.h"
 #include "Intl.h"
 #include "Language.h"
@@ -44,7 +42,6 @@
 #include "Paragraph.h"
 #include "paragraph_funcs.h"
 #include "ParagraphParameters.h"
-#include "ParIterator.h"
 #include "TextClass.h"
 #include "TextMetrics.h"
 #include "VSpace.h"
 #include "insets/InsetSpecialChar.h"
 #include "insets/InsetText.h"
 #include "insets/InsetInfo.h"
+#include "insets/InsetGraphics.h"
+#include "insets/InsetGraphicsParams.h"
 
-#include "support/lstrings.h"
-#include "support/lyxlib.h"
 #include "support/convert.h"
+#include "support/debug.h"
+#include "support/gettext.h"
+#include "support/lstrings.h"
 #include "support/lyxtime.h"
 
 #include "mathed/InsetMathHull.h"
@@ -82,7 +82,8 @@ namespace lyx {
 using cap::copySelection;
 using cap::cutSelection;
 using cap::pasteFromStack;
-using cap::pasteClipboard;
+using cap::pasteClipboardText;
+using cap::pasteClipboardGraphics;
 using cap::replaceSelection;
 
 // globals...
@@ -132,7 +133,9 @@ static void mathDispatch(Cursor & cur, FuncRequest const & cmd, bool display)
                const int old_pos = cur.pos();
 #endif
                cur.insert(new InsetMathHull(hullSimple));
-               BOOST_ASSERT(old_pos == cur.pos());
+#ifdef ENABLE_ASSERTIONS
+               LASSERT(old_pos == cur.pos(), /**/);
+#endif
                cur.nextInset()->edit(cur, true);
                // don't do that also for LFUN_MATH_MODE
                // unless you want end up with always changing
@@ -150,13 +153,14 @@ static void mathDispatch(Cursor & cur, FuncRequest const & cmd, bool display)
                // somewhere, and an ordinary formula
                // otherwise
                if (sel.find(from_ascii("\\newcommand")) == string::npos
+                               && sel.find(from_ascii("\\newlyxcommand")) == string::npos
                                && sel.find(from_ascii("\\def")) == string::npos)
                {
                        InsetMathHull * formula = new InsetMathHull;
                        istringstream is(to_utf8(sel));
-                       Lexer lex(0, 0);
+                       Lexer lex;
                        lex.setStream(is);
-                       formula->read(cur.buffer(), lex);
+                       formula->read(lex);
                        if (formula->getType() == hullNone)
                                // Don't create pseudo formulas if
                                // delimiters are left out
@@ -182,57 +186,59 @@ static void specialChar(Cursor & cur, InsetSpecialChar::Kind kind)
 static bool doInsertInset(Cursor & cur, Text * text,
        FuncRequest const & cmd, bool edit, bool pastesel)
 {
-       Inset * inset = createInset(cur.bv().buffer(), cmd);
+       Buffer & buffer = cur.bv().buffer();
+       BufferParams const & bparams = buffer.params();
+       Inset * inset = createInset(buffer, cmd);
        if (!inset)
                return false;
 
        if (InsetCollapsable * ci = inset->asInsetCollapsable())
-               ci->setLayout(cur.bv().buffer().params());
+               ci->setLayout(bparams);
 
        cur.recordUndo();
        if (cmd.action == LFUN_INDEX_INSERT) {
-               docstring ds = support::subst(text->getStringToIndex(cur), '\n', ' ');
+               docstring ds = subst(text->getStringToIndex(cur), '\n', ' ');
                text->insertInset(cur, inset);
                if (edit)
                        inset->edit(cur, true);
                // Now put this into inset
                static_cast<InsetCollapsable *>(inset)->text_.insertStringAsParagraphs(cur, ds);
-       } else {
-               bool gotsel = false;
-               if (cur.selection()) {
-                       lyx::dispatch(FuncRequest(LFUN_CUT));
-                       gotsel = true;
-               }
-               text->insertInset(cur, inset);
+               return true;
+       }
 
-               if (edit)
-                       inset->edit(cur, true);
+       bool gotsel = false;
+       if (cur.selection()) {
+               lyx::dispatch(FuncRequest(LFUN_CUT));
+               gotsel = true;
+       }
+       text->insertInset(cur, inset);
 
-               if (gotsel && pastesel) {
-                       lyx::dispatch(FuncRequest(LFUN_PASTE, "0"));
-                       InsetText * insetText = dynamic_cast<InsetText *>(inset);
-                       if (insetText && !insetText->allowMultiPar() 
-                           || cur.lastpit() == 0) {
-                               // reset first par to default
-                               LayoutPtr const layout =
-                                       cur.buffer().params().getTextClass().defaultLayout();
-                               cur.text()->paragraphs().begin()->layout(layout);
-                               cur.pos() = 0;
-                               cur.pit() = 0;
-                               // Merge multiple paragraphs -- hack
-                               while (cur.lastpit() > 0) {
-                                       mergeParagraph(cur.buffer().params(),
-                                               cur.text()->paragraphs(), 0);
-                               }
-                       } else {
-                               // reset surrounding par to default
-                               docstring const layoutname = 
-                                       cur.buffer().params().getTextClass().defaultLayoutName();
-                               cur.leaveInset(*inset);
-                               text->setLayout(cur, layoutname);
-                       }
-               }
+       if (edit)
+               inset->edit(cur, true);
+
+       if (!gotsel || !pastesel)
+               return true;
+
+       lyx::dispatch(FuncRequest(LFUN_PASTE, "0"));
+       InsetText * insetText = dynamic_cast<InsetText *>(inset);
+       if (insetText && !insetText->allowMultiPar() || cur.lastpit() == 0) {
+               // reset first par to default
+               cur.text()->paragraphs().begin()
+                       ->setEmptyOrDefaultLayout(bparams.documentClass());
+               cur.pos() = 0;
+               cur.pit() = 0;
+               // Merge multiple paragraphs -- hack
+               while (cur.lastpit() > 0)
+                       mergeParagraph(bparams, cur.text()->paragraphs(), 0);
+       } else {
+               // reset surrounding par to default
+               docstring const layoutname = insetText->useEmptyLayout()
+                       ? bparams.documentClass().emptyLayoutName()
+                       : bparams.documentClass().defaultLayoutName();
+               cur.leaveInset(*inset);
+               text->setLayout(cur, layoutname);
        }
+
        return true;
 }
 
@@ -264,40 +270,41 @@ static void outline(OutlineOp mode, Cursor & cur)
        ParagraphList::iterator finish = start;
        ParagraphList::iterator end = pars.end();
 
-       TextClass::const_iterator lit =
-               buf.params().getTextClass().begin();
-       TextClass::const_iterator const lend =
-               buf.params().getTextClass().end();
+       DocumentClass const & tc = buf.params().documentClass();
 
-       int const thistoclevel = start->layout()->toclevel;
+       int const thistoclevel = start->layout().toclevel;
        int toclevel;
+
+       // Move out (down) from this section header
+       if (finish != end)
+               ++finish;
+       // Seek the one (on same level) below
+       for (; finish != end; ++finish) {
+               toclevel = finish->layout().toclevel;
+               if (toclevel != Layout::NOT_IN_TOC && toclevel <= thistoclevel) {
+                       break;
+               }
+       }
+
        switch (mode) {
                case OutlineUp: {
-                       // Move out (down) from this section header
-                       if (finish != end)
-                               ++finish;
-                       // Seek the one (on same level) below
-                       for (; finish != end; ++finish) {
-                               toclevel = finish->layout()->toclevel;
-                               if (toclevel != Layout::NOT_IN_TOC
-                                   && toclevel <= thistoclevel) {
-                                       break;
-                               }
-                       }
+                       if (start == pars.begin())
+                               // Nothing to move.
+                               return;
                        ParagraphList::iterator dest = start;
                        // Move out (up) from this header
                        if (dest == bgn)
-                               break;
+                               return;
                        // Search previous same-level header above
                        do {
                                --dest;
-                               toclevel = dest->layout()->toclevel;
+                               toclevel = dest->layout().toclevel;
                        } while(dest != bgn
                                && (toclevel == Layout::NOT_IN_TOC
                                    || toclevel > thistoclevel));
                        // Not found; do nothing
                        if (toclevel == Layout::NOT_IN_TOC || toclevel > thistoclevel)
-                               break;
+                               return;
                        pit_type const newpit = distance(bgn, dest);
                        pit_type const len = distance(start, finish);
                        pit_type const deletepit = pit + len;
@@ -306,29 +313,21 @@ static void outline(OutlineOp mode, Cursor & cur)
                        start = boost::next(pars.begin(), deletepit);
                        pit = newpit;
                        pars.erase(start, finish);
-                       break;
+                       return;
                }
                case OutlineDown: {
-                       // Go down out of current header:
-                       if (finish != end)
-                               ++finish;
-                       // Find next same-level header:
-                       for (; finish != end; ++finish) {
-                               toclevel = finish->layout()->toclevel;
-                               if (toclevel != Layout::NOT_IN_TOC && toclevel <= thistoclevel)
-                                       break;
-                       }
-                       ParagraphList::iterator dest = finish;
+                       if (finish == end)
+                               // Nothing to move.
+                               return;
                        // Go one down from *this* header:
-                       if (dest != end)
-                               ++dest;
-                       else
-                               break;
+                       ParagraphList::iterator dest = boost::next(finish, 1);
                        // Go further down to find header to insert in front of:
                        for (; dest != end; ++dest) {
-                               toclevel = dest->layout()->toclevel;
-                               if (toclevel != Layout::NOT_IN_TOC && toclevel <= thistoclevel)
+                               toclevel = dest->layout().toclevel;
+                               if (toclevel != Layout::NOT_IN_TOC
+                                   && toclevel <= thistoclevel) {
                                        break;
+                               }
                        }
                        // One such was found:
                        pit_type newpit = distance(bgn, dest);
@@ -338,30 +337,46 @@ static void outline(OutlineOp mode, Cursor & cur)
                        start = boost::next(bgn, pit);
                        pit = newpit - len;
                        pars.erase(start, finish);
-                       break;
+                       return;
                }
-               case OutlineIn:
-                       buf.undo().recordUndo(cur);
-                       for (; lit != lend; ++lit) {
-                               if ((*lit)->toclevel == thistoclevel + 1 &&
-                                   start->layout()->labeltype == (*lit)->labeltype) {
-                                       start->layout((*lit));
-                                       break;
+               case OutlineIn: {
+                       pit_type const len = distance(start, finish);
+                       buf.undo().recordUndo(cur, ATOMIC_UNDO, pit, pit + len - 1);
+                       for (; start != finish; ++start) {
+                               toclevel = start->layout().toclevel;
+                               if (toclevel == Layout::NOT_IN_TOC)
+                                       continue;
+                               DocumentClass::const_iterator lit = tc.begin();
+                               DocumentClass::const_iterator len = tc.end();
+                               for (; lit != len; ++lit) {
+                                       if (lit->toclevel == toclevel + 1 &&
+                                           start->layout().labeltype == lit->labeltype) {
+                                               start->setLayout(*lit);
+                                               break;
+                                       }
                                }
                        }
-                       break;
-               case OutlineOut:
-                       buf.undo().recordUndo(cur);
-                       for (; lit != lend; ++lit) {
-                               if ((*lit)->toclevel == thistoclevel - 1 &&
-                                   start->layout()->labeltype == (*lit)->labeltype) {
-                                       start->layout((*lit));
-                                       break;
+                       return;
+               }
+               case OutlineOut: {
+                       pit_type const len = distance(start, finish);
+                       buf.undo().recordUndo(cur, ATOMIC_UNDO, pit, pit + len - 1);
+                       for (; start != finish; ++start) {
+                               toclevel = start->layout().toclevel;
+                               if (toclevel == Layout::NOT_IN_TOC)
+                                       continue;
+                               DocumentClass::const_iterator lit = tc.begin();
+                               DocumentClass::const_iterator len = tc.end();
+                               for (; lit != len; ++lit) {
+                                       if (lit->toclevel == toclevel - 1 &&
+                                               start->layout().labeltype == lit->labeltype) {
+                                                       start->setLayout(*lit);
+                                                       break;
+                                       }
                                }
                        }
-                       break;
-               default:
-                       break;
+                       return;
+               }
        }
 }
 
@@ -370,7 +385,7 @@ void Text::number(Cursor & cur)
 {
        FontInfo font = ignore_font;
        font.setNumber(FONT_TOGGLE);
-       toggleAndShow(cur, this, Font(font));
+       toggleAndShow(cur, this, Font(font, ignore_language));
 }
 
 
@@ -384,14 +399,17 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 {
        LYXERR(Debug::ACTION, "Text::dispatch: cmd: " << cmd);
 
+       BufferView * bv = &cur.bv();
+       TextMetrics & tm = bv->textMetrics(this);
+       if (!tm.contains(cur.pit()))
+               lyx::dispatch(FuncRequest(LFUN_SCREEN_RECENTER));
+
        // FIXME: We use the update flag to indicates wether a singlePar or a
        // full screen update is needed. We reset it here but shall we restore it
        // at the end?
        cur.noUpdate();
 
-       BOOST_ASSERT(cur.text() == this);
-       BufferView * bv = &cur.bv();
-       TextMetrics & tm = cur.bv().textMetrics(this);
+       LASSERT(cur.text() == this, /**/);
        CursorSlice oldTopSlice = cur.top();
        bool oldBoundary = cur.boundary();
        bool sel = cur.selection();
@@ -402,10 +420,6 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        // Signals that a full-screen update is required
        bool needsUpdate = !(lyxaction.funcHasFlag(cmd.action,
                LyXAction::NoUpdate) || singleParUpdate);
-       // Remember the old paragraph metric (_outer_ paragraph!)
-       ParagraphMetrics const & pm = cur.bv().parMetrics(
-               cur.bottom().text(), cur.bottom().pit());
-       Dimension olddim = pm.dim();
 
        switch (cmd.action) {
 
@@ -487,6 +501,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                } else {
                        cur.undispatched();
                }
+               cur.updateFlags(Update::FitCursor);
                break;
 
        case LFUN_BUFFER_END:
@@ -497,6 +512,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                } else {
                        cur.undispatched();
                }
+               cur.updateFlags(Update::FitCursor);
                break;
 
        case LFUN_CHAR_FORWARD:
@@ -527,29 +543,50 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_CHAR_LEFT:
        case LFUN_CHAR_LEFT_SELECT:
-               //FIXME: for visual cursor, really move left
-               if (reverseDirectionNeeded(cur)) {
-                       cmd.action = cmd.action == LFUN_CHAR_LEFT_SELECT ? 
-                                       LFUN_CHAR_FORWARD_SELECT : LFUN_CHAR_FORWARD;
+               if (lyxrc.visual_cursor) {
+                       needsUpdate |= cur.selHandle(cmd.action == LFUN_CHAR_LEFT_SELECT);
+                       needsUpdate |= cursorVisLeft(cur);
+                       if (!needsUpdate && oldTopSlice == cur.top()
+                                       && cur.boundary() == oldBoundary) {
+                               cur.undispatched();
+                               cmd = FuncRequest(LFUN_FINISHED_LEFT);
+                       }
                } else {
-                       cmd.action = cmd.action == LFUN_CHAR_LEFT_SELECT ? 
+                       if (reverseDirectionNeeded(cur)) {
+                               cmd.action = cmd.action == LFUN_CHAR_LEFT_SELECT ? 
+                                       LFUN_CHAR_FORWARD_SELECT : LFUN_CHAR_FORWARD;
+                       } else {
+                               cmd.action = cmd.action == LFUN_CHAR_LEFT_SELECT ? 
                                        LFUN_CHAR_BACKWARD_SELECT : LFUN_CHAR_BACKWARD;
+                       }
+                       dispatch(cur, cmd);
+                       return;
                }
-               dispatch(cur, cmd);
-               return;
+               break;
 
        case LFUN_CHAR_RIGHT:
        case LFUN_CHAR_RIGHT_SELECT:
-               //FIXME: for visual cursor, really move right
-               if (reverseDirectionNeeded(cur)) {
-                       cmd.action = cmd.action == LFUN_CHAR_RIGHT_SELECT ? 
-                                       LFUN_CHAR_BACKWARD_SELECT : LFUN_CHAR_BACKWARD;
+               if (lyxrc.visual_cursor) {
+                       needsUpdate |= cur.selHandle(cmd.action == LFUN_CHAR_RIGHT_SELECT);
+                       needsUpdate |= cursorVisRight(cur);
+                       if (!needsUpdate && oldTopSlice == cur.top()
+                                       && cur.boundary() == oldBoundary) {
+                               cur.undispatched();
+                               cmd = FuncRequest(LFUN_FINISHED_RIGHT);
+                       }
                } else {
-                       cmd.action = cmd.action == LFUN_CHAR_RIGHT_SELECT ? 
+                       if (reverseDirectionNeeded(cur)) {
+                               cmd.action = cmd.action == LFUN_CHAR_RIGHT_SELECT ? 
+                                       LFUN_CHAR_BACKWARD_SELECT : LFUN_CHAR_BACKWARD;
+                       } else {
+                               cmd.action = cmd.action == LFUN_CHAR_RIGHT_SELECT ? 
                                        LFUN_CHAR_FORWARD_SELECT : LFUN_CHAR_FORWARD;
+                       }
+                       dispatch(cur, cmd);
+                       return;
                }
-               dispatch(cur, cmd);
-               return;
+               break;
+               
 
        case LFUN_UP_SELECT:
        case LFUN_DOWN_SELECT:
@@ -564,10 +601,6 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                bool up = cmd.action == LFUN_UP_SELECT || cmd.action == LFUN_UP;
                bool const successful = cur.upDownInText(up, needsUpdate);
                if (successful) {
-                       // notify insets which were left and get their update flags 
-                       notifyCursorLeaves(cur.beforeDispatchCursor(), cur);
-                       cur.fixIfBroken();
-                       
                        // redraw if you leave mathed (for the decorations)
                        needsUpdate |= cur.beforeDispatchCursor().inMathed();
                } else
@@ -588,25 +621,6 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                needsUpdate |= cursorDownParagraph(cur);
                break;
 
-       case LFUN_SCREEN_UP_SELECT:
-               needsUpdate |= cur.selHandle(true);
-               if (cur.pit() == 0 && cur.textRow().pos() == 0)
-                       cur.undispatched();
-               else {
-                       tm.cursorPrevious(cur);
-               }
-               break;
-
-       case LFUN_SCREEN_DOWN_SELECT:
-               needsUpdate |= cur.selHandle(true);
-               if (cur.pit() == cur.lastpit()
-                         && cur.textRow().endpos() == cur.lastpos())
-                       cur.undispatched();
-               else {
-                       tm.cursorNext(cur);
-               }
-               break;
-
        case LFUN_LINE_BEGIN:
        case LFUN_LINE_BEGIN_SELECT:
                needsUpdate |= cur.selHandle(cmd.action == LFUN_LINE_BEGIN_SELECT);
@@ -621,16 +635,26 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_WORD_RIGHT:
        case LFUN_WORD_RIGHT_SELECT:
-               //FIXME: for visual cursor mode, really move right
-               if (reverseDirectionNeeded(cur)) {
-                       cmd.action = cmd.action == LFUN_WORD_RIGHT_SELECT ?
-                                       LFUN_WORD_BACKWARD_SELECT : LFUN_WORD_BACKWARD;
+               if (lyxrc.visual_cursor) {
+                       needsUpdate |= cur.selHandle(cmd.action == LFUN_WORD_RIGHT_SELECT);
+                       needsUpdate |= cursorVisRightOneWord(cur);
+                       if (!needsUpdate && oldTopSlice == cur.top()
+                                       && cur.boundary() == oldBoundary) {
+                               cur.undispatched();
+                               cmd = FuncRequest(LFUN_FINISHED_RIGHT);
+                       }
                } else {
-                       cmd.action = cmd.action == LFUN_WORD_RIGHT_SELECT ?
-                                       LFUN_WORD_FORWARD_SELECT : LFUN_WORD_FORWARD;
+                       if (reverseDirectionNeeded(cur)) {
+                               cmd.action = cmd.action == LFUN_WORD_RIGHT_SELECT ?
+                                               LFUN_WORD_BACKWARD_SELECT : LFUN_WORD_BACKWARD;
+                       } else {
+                               cmd.action = cmd.action == LFUN_WORD_RIGHT_SELECT ?
+                                               LFUN_WORD_FORWARD_SELECT : LFUN_WORD_FORWARD;
+                       }
+                       dispatch(cur, cmd);
+                       return;
                }
-               dispatch(cur, cmd);
-               return;
+               break;
 
        case LFUN_WORD_FORWARD:
        case LFUN_WORD_FORWARD_SELECT:
@@ -640,16 +664,26 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_WORD_LEFT:
        case LFUN_WORD_LEFT_SELECT:
-               //FIXME: for visual cursor mode, really move left
-               if (reverseDirectionNeeded(cur)) {
-                       cmd.action = cmd.action == LFUN_WORD_LEFT_SELECT ?
-                                       LFUN_WORD_FORWARD_SELECT : LFUN_WORD_FORWARD;
+               if (lyxrc.visual_cursor) {
+                       needsUpdate |= cur.selHandle(cmd.action == LFUN_WORD_LEFT_SELECT);
+                       needsUpdate |= cursorVisLeftOneWord(cur);
+                       if (!needsUpdate && oldTopSlice == cur.top()
+                                       && cur.boundary() == oldBoundary) {
+                               cur.undispatched();
+                               cmd = FuncRequest(LFUN_FINISHED_LEFT);
+                       }
                } else {
-                       cmd.action = cmd.action == LFUN_WORD_LEFT_SELECT ?
-                                       LFUN_WORD_BACKWARD_SELECT : LFUN_WORD_BACKWARD;
+                       if (reverseDirectionNeeded(cur)) {
+                               cmd.action = cmd.action == LFUN_WORD_LEFT_SELECT ?
+                                               LFUN_WORD_FORWARD_SELECT : LFUN_WORD_FORWARD;
+                       } else {
+                               cmd.action = cmd.action == LFUN_WORD_LEFT_SELECT ?
+                                               LFUN_WORD_BACKWARD_SELECT : LFUN_WORD_BACKWARD;
+                       }
+                       dispatch(cur, cmd);
+                       return;
                }
-               dispatch(cur, cmd);
-               return;
+               break;
 
        case LFUN_WORD_BACKWARD:
        case LFUN_WORD_BACKWARD_SELECT:
@@ -663,36 +697,24 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
        }
 
-       case LFUN_NEW_LINE: {
-               // Not allowed by LaTeX (labels or empty par)
-               if (cur.pos() > cur.paragraph().beginOfBody()) {
-                       // this avoids a double undo
-                       // FIXME: should not be needed, ideally
-                       if (!cur.selection())
-                               cur.recordUndo();
-                       cap::replaceSelection(cur);
-                       cur.insert(new InsetNewline);
-                       cur.posForward();
-                       moveCursor(cur, false);
-               }
+       case LFUN_NEWLINE_INSERT: {
+               InsetNewlineParams inp;
+               docstring arg = cmd.argument();
+               // this avoids a double undo
+               // FIXME: should not be needed, ideally
+               if (!cur.selection())
+                       cur.recordUndo();
+               cap::replaceSelection(cur);
+               if (arg == "linebreak")
+                       inp.kind = InsetNewlineParams::LINEBREAK;
+               else
+                       inp.kind = InsetNewlineParams::NEWLINE;
+               cur.insert(new InsetNewline(inp));
+               cur.posForward();
+               moveCursor(cur, false);
                break;
        }
        
-       case LFUN_LINE_BREAK: {
-               // Not allowed by LaTeX (labels or empty par)
-               if (cur.pos() > cur.paragraph().beginOfBody()) {
-                       // this avoids a double undo
-                       // FIXME: should not be needed, ideally
-                       if (!cur.selection())
-                               cur.recordUndo();
-                       cap::replaceSelection(cur);
-                       cur.insert(new InsetLinebreak);
-                       cur.posForward();
-                       moveCursor(cur, false);
-               }
-               break;
-       }
-
        case LFUN_CHAR_DELETE_FORWARD:
                if (!cur.selection()) {
                        if (cur.pos() == cur.paragraph().size())
@@ -830,7 +852,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        /*
                        Paragraph & par = pars_[cur.pit()];
                        if (inset->lyxCode() == LABEL_CODE
-                               && par.layout()->labeltype == LABEL_COUNTER) {
+                               && par.layout().labeltype == LABEL_COUNTER) {
                                // Go to the end of the paragraph
                                // Warning: Because of Change-Tracking, the last
                                // position is 'size()' and not 'size()-1':
@@ -842,7 +864,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        */
                        if (cur.selection())
                                cutSelection(cur, true, false);
-                       insertInset(cur, inset);
+                       cur.insert(inset);
                        cur.posForward();
                }
                break;
@@ -852,12 +874,50 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                needsUpdate |= dissolveInset(cur);
                break;
 
-       case LFUN_INSET_SETTINGS:
-               cur.inset().showInsetDialog(bv);
+       case LFUN_INSET_SETTINGS: {
+               Inset & inset = cur.inset();
+               if (cmd.getArg(0) == insetName(inset.lyxCode())) {
+                       // This inset dialog has been explicitely requested.
+                       inset.showInsetDialog(bv);
+                       break;
+               }
+               // else, if there is an inset at the cursor, access this
+               Inset * next_inset = cur.nextInset();
+               if (next_inset) {
+                       next_inset->showInsetDialog(bv);
+                       break;
+               }
+               // if not then access the underlying inset.
+               inset.showInsetDialog(bv);
                break;
+       }
+
+       case LFUN_SET_GRAPHICS_GROUP: {
+               Inset * instmp = &cur.inset();
+               if (instmp->lyxCode() != GRAPHICS_CODE) instmp = cur.nextInset();
+               if (!instmp || instmp->lyxCode() != GRAPHICS_CODE) break;
+
+               cur.recordUndoFullDocument();
+               Inset & inset = *instmp;
+               InsetGraphics & ins = static_cast<InsetGraphics &>(inset);
+
+               string id = to_utf8(cmd.argument());
+               string grp = InsetGraphics::getGroupParams(bv->buffer(), id);
+               InsetGraphicsParams tmp, inspar = ins.getParams();
+
+               if (id.empty())
+                       inspar.groupId = to_utf8(cmd.argument());
+               else {
+                       InsetGraphics::string2params(grp, bv->buffer(), tmp);
+                       tmp.filename = inspar.filename;
+                       inspar = tmp;
+               }
+
+               ins.setParams(inspar);
+       }
 
        case LFUN_SPACE_INSERT:
-               if (cur.paragraph().layout()->free_spacing)
+               if (cur.paragraph().layout().free_spacing)
                        insertChar(cur, ' ');
                else {
                        doInsertInset(cur, this, cmd, false, false);
@@ -905,22 +965,44 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                charsTranspose(cur);
                break;
 
-       case LFUN_PASTE:
+       case LFUN_PASTE: {
                cur.message(_("Paste"));
                cap::replaceSelection(cur);
-               if (cmd.argument().empty() && !theClipboard().isInternal())
-                       pasteClipboard(cur, bv->buffer().errorList("Paste"));
-               else {
-                       string const arg(to_utf8(cmd.argument()));
+
+               // without argument?
+               string const arg = to_utf8(cmd.argument());
+               if (arg.empty()) {
+                       if (theClipboard().isInternal())
+                               pasteFromStack(cur, bv->buffer().errorList("Paste"), 0);
+                       else if (theClipboard().hasGraphicsContents())
+                               pasteClipboardGraphics(cur, bv->buffer().errorList("Paste"));
+                       else
+                               pasteClipboardText(cur, bv->buffer().errorList("Paste"));
+               } else if (isStrUnsignedInt(arg)) {
+                       // we have a numerical argument
                        pasteFromStack(cur, bv->buffer().errorList("Paste"),
-                                       isStrUnsignedInt(arg) ?
-                                               convert<unsigned int>(arg) :
-                                               0);
+                                      convert<unsigned int>(arg));
+               } else {
+                       Clipboard::GraphicsType type = Clipboard::AnyGraphicsType;
+                       if (arg == "pdf")
+                               type = Clipboard::PdfGraphicsType;
+                       else if (arg == "png")
+                               type = Clipboard::PngGraphicsType;
+                       else if (arg == "jpeg")
+                               type = Clipboard::JpegGraphicsType;
+                       else if (arg == "linkback")
+                               type = Clipboard::LinkBackGraphicsType;
+                       else
+                               LASSERT(false, /**/);
+
+                       pasteClipboardGraphics(cur, bv->buffer().errorList("Paste"), type);
                }
+
                bv->buffer().errors("Paste");
                cur.clearSelection(); // bug 393
                cur.finishUndo();
                break;
+       }
 
        case LFUN_CUT:
                cutSelection(cur, true, true);
@@ -951,35 +1033,39 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
        }
 
-       case LFUN_SERVER_GET_FONT:
-               if (cur.current_font.fontInfo().shape() == ITALIC_SHAPE)
-                       cur.message(from_ascii("E"));
-               else if (cur.current_font.fontInfo().shape() == SMALLCAPS_SHAPE)
-                       cur.message(from_ascii("N"));
-               else
-                       cur.message(from_ascii("0"));
-               break;
-
        case LFUN_SERVER_GET_LAYOUT:
-               cur.message(cur.paragraph().layout()->name());
+               cur.message(cur.paragraph().layout().name());
                break;
 
        case LFUN_LAYOUT: {
                docstring layout = cmd.argument();
                LYXERR(Debug::INFO, "LFUN_LAYOUT: (arg) " << to_utf8(layout));
 
-               docstring const old_layout = cur.paragraph().layout()->name();
+               Paragraph const & para = cur.paragraph();
+               docstring const old_layout = para.layout().name();
+               DocumentClass const & tclass = bv->buffer().params().documentClass();
 
-               // Derive layout number from given argument (string)
-               // and current buffer's textclass (number)
-               TextClass const & tclass = bv->buffer().params().getTextClass();
                if (layout.empty())
                        layout = tclass.defaultLayoutName();
+
+               if (para.forceEmptyLayout()) 
+                       // in this case only the empty layout is allowed
+                       layout = tclass.emptyLayoutName();
+               else if (para.useEmptyLayout()) {
+                       // in this case, default layout maps to empty layout 
+                       if (layout == tclass.defaultLayoutName())
+                               layout = tclass.emptyLayoutName();
+               } else { 
+                       // otherwise, the empty layout maps to the default
+                       if (layout == tclass.emptyLayoutName())
+                               layout = tclass.defaultLayoutName();
+               }
+
                bool hasLayout = tclass.hasLayout(layout);
 
                // If the entry is obsolete, use the new one instead.
                if (hasLayout) {
-                       docstring const & obs = tclass[layout]->obsoleted_by();
+                       docstring const & obs = tclass[layout].obsoleted_by();
                        if (!obs.empty())
                                layout = obs;
                }
@@ -998,7 +1084,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        pit_type spit = cur.selBegin().pit();
                        pit_type epit = cur.selEnd().pit() + 1;
                        while (spit != epit) {
-                               if (pars_[spit].layout()->name() != old_layout) {
+                               if (pars_[spit].layout().name() != old_layout) {
                                        change_layout = true;
                                        break;
                                }
@@ -1014,7 +1100,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_CLIPBOARD_PASTE:
                cur.clearSelection();
-               pasteClipboard(cur, bv->buffer().errorList("Paste"),
+               pasteClipboardText(cur, bv->buffer().errorList("Paste"),
                               cmd.argument() == "paragraph");
                bv->buffer().errors("Paste");
                break;
@@ -1028,8 +1114,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                if (cmd.argument().empty())
                        break;
                docstring hexstring = cmd.argument();
-               if (lyx::support::isHex(hexstring)) {
-                       char_type c = lyx::support::hexToInt(hexstring);
+               if (isHex(hexstring)) {
+                       char_type c = hexToInt(hexstring);
                        if (c >= 32 && c < 0x10ffff) {
                                lyxerr << "Inserting c: " << c << endl;
                                docstring s = docstring(1, c);
@@ -1043,8 +1129,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                Paragraph & par = cur.paragraph();
                pos_type pos = cur.pos();
                BufferParams const & bufparams = bv->buffer().params();
-               LayoutPtr const & style = par.layout();
-               if (!style->pass_thru
+               Layout const & style = par.layout();
+               if (!style.pass_thru
                    && par.getFontSettings(bufparams, pos).language()->lang() != "hebrew") {
                        // this avoids a double undo
                        // FIXME: should not be needed, ideally
@@ -1060,14 +1146,9 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        else
                                c = par.getChar(pos - 1);
                        string arg = to_utf8(cmd.argument());
-                       if (arg == "single")
-                               cur.insert(new InsetQuotes(c,
-                                   bufparams.quotes_language,
-                                   InsetQuotes::SingleQ));
-                       else
-                               cur.insert(new InsetQuotes(c,
-                                   bufparams.quotes_language,
-                                   InsetQuotes::DoubleQ));
+                       cur.insert(new InsetQuotes(c, bufparams.quotes_language,
+                               (arg == "single") ? InsetQuotes::SingleQuotes
+                                       : InsetQuotes::DoubleQuotes));
                        cur.posForward();
                }
                else
@@ -1101,51 +1182,65 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
 
        // Single-click on work area
-       case LFUN_MOUSE_PRESS: {
-               // Right click on a footnote flag opens float menu
-               // FIXME: Why should we clear the selection in this case?
-               if (cmd.button() == mouse_button::button3)
-                       cur.clearSelection();
-
-               bool do_selection = cmd.button() == mouse_button::button1
-                       && cmd.argument() == "region-select";
-               // Set the cursor
-               bool update = bv->mouseSetCursor(cur, do_selection);
-
-               // Insert primary selection with middle mouse
-               // if there is a local selection in the current buffer,
-               // insert this
-               if (cmd.button() == mouse_button::button2) {
-                       if (cap::selection()) {
-                               // Copy the selection buffer to the clipboard
-                               // stack, because we want it to appear in the
-                               // "Edit->Paste recent" menu.
-                               cap::copySelectionToStack();
-
-                               cap::pasteSelection(bv->cursor(), 
-                                                   bv->buffer().errorList("Paste"));
-                               bv->buffer().errors("Paste");
-                               bv->buffer().markDirty();
-                               bv->cursor().finishUndo();
-                       } else {
-                               lyx::dispatch(FuncRequest(LFUN_PRIMARY_SELECTION_PASTE, "paragraph"));
+       case LFUN_MOUSE_PRESS:
+               // We are not marking a selection with the keyboard in any case.
+               cur.bv().cursor().mark() = false;
+               switch (cmd.button()) {
+               case mouse_button::button1:
+                       // Set the cursor
+                       if (!bv->mouseSetCursor(cur, cmd.argument() == "region-select"))
+                               cur.updateFlags(Update::SinglePar | Update::FitCursor);
+                       break;                  
+
+               case mouse_button::button2:
+                       // Middle mouse pasting.
+                       if (!cap::selection()) {                        
+                               // There is no local selection in the current buffer, so try to
+                               // paste primary selection instead.
+                               lyx::dispatch(FuncRequest(LFUN_PRIMARY_SELECTION_PASTE,
+                                       "paragraph"));
+                               // Nothing else to do.
+                               cur.noUpdate();
+                               return;
                        }
-               }
-
-               // we have to update after dEPM triggered
-               if (!update && cmd.button() == mouse_button::button1) {
-                       needsUpdate = false;
-                       cur.noUpdate();
-               }
+                       // Copy the selection buffer to the clipboard stack, because we want it
+                       // to appear in the "Edit->Paste recent" menu.
+                       cap::copySelectionToStack();
+                       cap::pasteSelection(bv->cursor(), bv->buffer().errorList("Paste"));
+                       cur.updateFlags(Update::Force | Update::FitCursor);
+                       bv->buffer().errors("Paste");
+                       bv->buffer().markDirty();
+                       bv->cursor().finishUndo();
+                       break;
 
+               case mouse_button::button3:
+                       if (cur.selection()) {
+                               DocIterator const selbeg = cur.selectionBegin();
+                               DocIterator const selend = cur.selectionEnd();
+                               Cursor tmpcur = cur;
+                               tm.setCursorFromCoordinates(tmpcur, cmd.x, cmd.y);
+                               // Don't do anything if we right-click a selection, a selection
+                               // context menu should popup instead.
+                               if (tmpcur < selbeg || tmpcur >= selend) {
+                                       cur.noUpdate();
+                                       return;
+                               }
+                       }
+                       if (!bv->mouseSetCursor(cur, false)) {
+                               cur.updateFlags(Update::SinglePar | Update::FitCursor);
+                               break;                  
+                       }
+               default:
+                       break;
+               } // switch (cmd.button())
                break;
-       }
 
        case LFUN_MOUSE_MOTION: {
-               // Only use motion with button 1
-               //if (cmd.button() != mouse_button::button1)
-               //      return false;
-
+               // Mouse motion with right or middle mouse do nothing for now.
+               if (cmd.button() != mouse_button::button1) {
+                       cur.noUpdate();
+                       return;
+               }
                // ignore motions deeper nested than the real anchor
                Cursor & bvcur = cur.bv().cursor();
                if (!bvcur.anchor_.hasPart(cur)) {
@@ -1170,42 +1265,52 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        else if (cmd.y < 0)
                                lyx::dispatch(FuncRequest(LFUN_UP_SELECT));
                }
-
-               if (cur.top() == old)
-                       cur.noUpdate();
-               else {
-                       // FIXME: This is brute force! But without it the selected
-                       // area is not corrected updated while moving the mouse.
-                       cur.updateFlags(Update::Force | Update::FitCursor);
-                       // don't set anchor_
-                       bvcur.setCursor(cur);
-                       bvcur.selection() = true;
-                       //lyxerr << "MOTION: " << bv->cursor() << endl;
+               // We continue with our existing selection or start a new one, so don't
+               // reset the anchor.
+               bvcur.setCursor(cur);
+               bvcur.selection() = true;
+               if (cur.top() == old) {
+                       // We didn't move one iota, so no need to update the screen.
+                       cur.updateFlags(Update::SinglePar | Update::FitCursor);
+                       //cur.noUpdate();
+                       return;
                }
                break;
        }
 
-       case LFUN_MOUSE_RELEASE: {
-               if (cmd.button() == mouse_button::button2)
-                       break;
-
-               if (cmd.button() == mouse_button::button1) {
-                       // if there is new selection, update persistent
-                       // selection, otherwise, single click does not
-                       // clear persistent selection buffer
+       case LFUN_MOUSE_RELEASE:
+               switch (cmd.button()) {
+               case mouse_button::button1:
+                       // Cursor was set at LFUN_MOUSE_PRESS or LFUN_MOUSE_MOTION time.
+                       // If there is a new selection, update persistent selection;
+                       // otherwise, single click does not clear persistent selection
+                       // buffer.
                        if (cur.selection()) {
-                               // finish selection
-                               // if double click, cur is moved to the end of word by selectWord
-                               // but bvcur is current mouse position
-                               Cursor & bvcur = cur.bv().cursor();
-                               bvcur.selection() = true;
+                               // Finish selection.
+                               // If double click, cur is moved to the end of word by selectWord
+                               // but bvcur is current mouse position.
+                               cur.bv().cursor().selection() = true;
                        }
-                       needsUpdate = false;
+                       // FIXME: We could try to handle drag and drop of selection here.
                        cur.noUpdate();
-               }
+                       return;
+
+               case mouse_button::button2:
+                       // Middle mouse pasting is handled at mouse press time,
+                       // see LFUN_MOUSE_PRESS.
+                       cur.noUpdate();
+                       return;
+
+               case mouse_button::button3:
+                       // Cursor was set at LFUN_MOUSE_PRESS time.
+                       // FIXME: If there is a selection we could try to handle a special
+                       // drag & drop context menu.
+                       cur.noUpdate();
+                       return;
+
+               } // switch (cmd.button())
 
                break;
-       }
 
        case LFUN_SELF_INSERT: {
                if (cmd.argument().empty())
@@ -1242,7 +1347,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                }
                p["target"] = (cmd.argument().empty()) ?
                        content : cmd.argument();
-               string const data = InsetCommandMailer::params2string("href", p);
+               string const data = InsetCommand::params2string("href", p);
                if (p["target"].empty()) {
                        bv->showDialog("href", data);
                } else {
@@ -1258,7 +1363,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                p["name"] = (cmd.argument().empty()) ?
                        cur.getPossibleLabel() :
                        cmd.argument();
-               string const data = InsetCommandMailer::params2string("label", p);
+               string const data = InsetCommand::params2string("label", p);
 
                if (cmd.argument().empty()) {
                        bv->showDialog("label", data);
@@ -1280,6 +1385,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        docstring ds = cur.selectionAsString(false);
                        cutSelection(cur, true, false);
                        static_cast<InsetInfo *>(inset)->setInfo(to_utf8(ds));
+                       static_cast<InsetInfo *>(inset)->updateInfo();
                }
                insertInset(cur, inset);
                cur.posForward();
@@ -1287,17 +1393,9 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        }
 #if 0
        case LFUN_LIST_INSERT:
-       case LFUN_THEOREM_INSERT:
 #endif
        case LFUN_CAPTION_INSERT:
        case LFUN_FOOTNOTE_INSERT:
-               // Open the inset, and move the current selection
-               // inside it.
-               doInsertInset(cur, this, cmd, true, true);
-               cur.posForward();
-               // These insets are numbered.
-               updateLabels(bv->buffer());
-               break;
        case LFUN_NOTE_INSERT:
        case LFUN_FLEX_INSERT:
        case LFUN_BOX_INSERT:
@@ -1308,10 +1406,14 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_MARGINALNOTE_INSERT:
        case LFUN_OPTIONAL_INSERT:
        case LFUN_ENVIRONMENT_INSERT:
+       case LFUN_INDEX_INSERT:
                // Open the inset, and move the current selection
                // inside it.
                doInsertInset(cur, this, cmd, true, true);
                cur.posForward();
+               // Some insets are numbered, others are shown in the outline pane so
+               // let's update the labels and the toc backend.
+               updateLabels(bv->buffer());
                break;
 
        case LFUN_TABULAR_INSERT:
@@ -1332,13 +1434,12 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                cur.posForward();
                ParagraphList & pars = cur.text()->paragraphs();
 
-               TextClass const & tclass = bv->buffer().params().getTextClass();
+               DocumentClass const & tclass = bv->buffer().params().documentClass();
 
                // add a separate paragraph for the caption inset
                pars.push_back(Paragraph());
                pars.back().setInsetOwner(pars[0].inInset());
-               pars.back().layout(tclass.defaultLayout());
-
+               pars.back().setEmptyOrDefaultLayout(tclass);
                int cap_pit = pars.size() - 1;
 
                // if an empty inset was created, we create an additional empty
@@ -1347,8 +1448,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                if (!content) {
                        pars.push_back(Paragraph());
                        pars.back().setInsetOwner(pars[0].inInset());
-                       pars.back().layout(tclass.defaultLayout());
-
+                       pars.back().setEmptyOrDefaultLayout(tclass);
                }
 
                // reposition the cursor to the caption
@@ -1366,11 +1466,6 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
        }
 
-       case LFUN_INDEX_INSERT:
-               doInsertInset(cur, this, cmd, true, true);
-               cur.posForward();
-               break;
-
        case LFUN_NOMENCL_INSERT: {
                FuncRequest cmd1 = cmd;
                if (cmd.argument().empty())
@@ -1393,12 +1488,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_INDEX_PRINT:
        case LFUN_NOMENCL_PRINT:
        case LFUN_TOC_INSERT:
-       case LFUN_HFILL_INSERT:
        case LFUN_LINE_INSERT:
        case LFUN_NEWPAGE_INSERT:
-       case LFUN_PAGEBREAK_INSERT:
-       case LFUN_CLEARPAGE_INSERT:
-       case LFUN_CLEARDOUBLEPAGE_INSERT:
                // do nothing fancy
                doInsertInset(cur, this, cmd, false, false);
                cur.posForward();
@@ -1433,8 +1524,10 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        string const s1 = token(s, ' ', 1);
                        int const nargs = s1.empty() ? 0 : convert<int>(s1);
                        string const s2 = token(s, ' ', 2);
-                       string const type = s2.empty() ? "newcommand" : s2;
-                       cur.insert(new MathMacroTemplate(from_utf8(token(s, ' ', 0)), nargs, false, from_utf8(type)));
+                       MacroType type = MacroTypeNewcommand;
+                       if (s2 == "def")
+                               type = MacroTypeDef;
+                       cur.insert(new MathMacroTemplate(from_utf8(token(s, ' ', 0)), nargs, false, type));
                        //cur.nextInset()->edit(cur, true);
                }
                break;
@@ -1451,15 +1544,10 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_MATH_MATRIX:
        case LFUN_MATH_DELIM:
        case LFUN_MATH_BIGDELIM: {
-               if (cur.selection())
-                       cur.clearSelection();
-               // FIXME: instead of the above, this one
-               // should be used (but it asserts with Bidi enabled)
-               // cf. http://bugzilla.lyx.org/show_bug.cgi?id=4055
-               // cap::replaceSelection(cur);
+               cap::replaceSelection(cur);
                cur.insert(new InsetMathHull(hullSimple));
                checkAndActivateInset(cur, true);
-               BOOST_ASSERT(cur.inMathed());
+               LASSERT(cur.inMathed(), /**/);
                cur.dispatch(cmd);
                break;
        }
@@ -1558,18 +1646,24 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_FINISHED_LEFT:
                LYXERR(Debug::DEBUG, "handle LFUN_FINISHED_LEFT:\n" << cur);
-               if (reverseDirectionNeeded(cur)) {
-                       ++cur.pos();
-                       cur.setCurrentFont();
-               }
+               // We're leaving an inset, going left. If the inset is LTR, we're 
+               // leaving from the front, so we should not move (remain at --- but
+               // not in --- the inset). If the inset is RTL, move left, without 
+               // entering the inset itself; i.e., move to after the inset.
+               if (cur.paragraph().getFontSettings(
+                               cur.bv().buffer().params(), cur.pos()).isRightToLeft())
+                       cursorVisLeft(cur, true);
                break;
 
        case LFUN_FINISHED_RIGHT:
                LYXERR(Debug::DEBUG, "handle LFUN_FINISHED_RIGHT:\n" << cur);
-               if (!reverseDirectionNeeded(cur)) {
-                       ++cur.pos();
-                       cur.setCurrentFont();
-               }
+               // We're leaving an inset, going right. If the inset is RTL, we're 
+               // leaving from the front, so we should not move (remain at --- but
+               // not in --- the inset). If the inset is LTR, move right, without 
+               // entering the inset itself; i.e., move to after the inset.
+               if (!cur.paragraph().getFontSettings(
+                               cur.bv().buffer().params(), cur.pos()).isRightToLeft())
+                       cursorVisRight(cur, true);
                break;
 
        case LFUN_FINISHED_BACKWARD:
@@ -1595,7 +1689,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                params2string(cur.paragraph(), data);
 
                // Will the paragraph accept changes from the dialog?
-               bool const accept = !cur.inset().forceDefaultParagraphs(cur.idx());
+               bool const accept = 
+                       cur.inset().allowParagraphCustomization(cur.idx());
 
                data = "update " + convert<string>(accept) + '\n' + data;
                bv->updateDialog("paragraph", data);
@@ -1626,7 +1721,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                break;
 
        case LFUN_FLOAT_LIST: {
-               TextClass const & tclass = bv->buffer().params().getTextClass();
+               DocumentClass const & tclass = bv->buffer().params().documentClass();
                if (tclass.floats().typeExist(to_utf8(cmd.argument()))) {
                        cur.recordUndo();
                        if (cur.selection())
@@ -1638,10 +1733,17 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                breakParagraph(cur);
                        }
 
-                       setLayout(cur, tclass.defaultLayoutName());
+                       docstring const laystr = cur.inset().useEmptyLayout() ?
+                               tclass.emptyLayoutName() :
+                               tclass.defaultLayoutName();
+                       setLayout(cur, laystr);
                        ParagraphParameters p;
                        setParagraphs(cur, p);
-                       insertInset(cur, new InsetFloatList(to_utf8(cmd.argument())));
+                       // FIXME This should be simplified when InsetFloatList takes a 
+                       // Buffer in its constructor.
+                       InsetFloatList * ifl = new InsetFloatList(to_utf8(cmd.argument()));
+                       ifl->setBuffer(bv->buffer());
+                       insertInset(cur, ifl);
                        cur.posForward();
                } else {
                        lyxerr << "Non-existent float type: "
@@ -1755,16 +1857,11 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        // FIXME: the following code should go in favor of fine grained
        // update flag treatment.
        if (singleParUpdate) {
-               // Inserting characters does not change par height
-               ParagraphMetrics const & pms
-                       = cur.bv().parMetrics(cur.bottom().text(), cur.bottom().pit());
-               if (pms.dim().height() == olddim.height()) {
-                       // if so, update _only_ this paragraph
-                       cur.updateFlags(Update::SinglePar |
-                               Update::FitCursor);
-                       return;
-               }
-               needsUpdate = true;
+               // Inserting characters does not change par height in general. So, try
+               // to update _only_ this paragraph. BufferView will detect if a full
+               // metrics update is needed anyway.
+               cur.updateFlags(Update::SinglePar | Update::FitCursor);
+               return;
        }
 
        if (!needsUpdate
@@ -1790,7 +1887,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                        FuncStatus & flag) const
 {
-       BOOST_ASSERT(cur.text() == this);
+       LASSERT(cur.text() == this, /**/);
 
        Font const & font = cur.real_current_font;
        FontInfo const & fontinfo = font.fontInfo();
@@ -1812,7 +1909,7 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                return true;
 
        case LFUN_BIBITEM_INSERT:
-               enable = (cur.paragraph().layout()->labeltype == LABEL_BIBLIO
+               enable = (cur.paragraph().layout().labeltype == LABEL_BIBLIO
                          && cur.pos() == 0);
                break;
 
@@ -1849,6 +1946,8 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                        code = NOTE_CODE;
                else if (cmd.argument() == "ref")
                        code = REF_CODE;
+               else if (cmd.argument() == "space")
+                       code = SPACE_CODE;
                else if (cmd.argument() == "toc")
                        code = TOC_CODE;
                else if (cmd.argument() == "vspace")
@@ -1863,7 +1962,7 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                code = ERT_CODE;
                break;
        case LFUN_LISTING_INSERT:
-           code = LISTINGS_CODE;
+               code = LISTINGS_CODE;
                break;
        case LFUN_FOOTNOTE_INSERT:
                code = FOOT_CODE;
@@ -1888,24 +1987,25 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_LIST_INSERT:
                code = LIST_CODE;
                break;
-       case LFUN_THEOREM_INSERT:
-               code = THEOREM_CODE;
-               break;
 #endif
        case LFUN_CAPTION_INSERT:
                code = CAPTION_CODE;
                break;
        case LFUN_NOTE_INSERT:
                code = NOTE_CODE;
+               // in commands (sections etc., only Notes are allowed)
+               enable = (cmd.argument().empty() || cmd.getArg(0) == "Note" ||
+                         !cur.paragraph().layout().isCommand());
                break;
        case LFUN_FLEX_INSERT: {
                code = FLEX_CODE;
                string s = cmd.getArg(0);
-               InsetLayout il =  cur.buffer().params().getTextClass().insetlayout(from_utf8(s));
-               if (il.lyxtype != "charstyle" &&
-                   il.lyxtype != "custom" &&
-                   il.lyxtype != "element" &&
-                   il.lyxtype != "standard")
+               InsetLayout il = 
+                       cur.buffer().params().documentClass().insetLayout(from_utf8(s));
+               if (il.lyxtype() != "charstyle" &&
+                   il.lyxtype() != "custom" &&
+                   il.lyxtype() != "element" &&
+                   il.lyxtype ()!= "standard")
                        enable = false;
                break;
                }
@@ -1926,7 +2026,7 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_OPTIONAL_INSERT:
                code = OPTARG_CODE;
                enable = cur.paragraph().insetList().count(OPTARG_CODE)
-                       < cur.paragraph().layout()->optionalargs;
+                       < cur.paragraph().layout().optionalargs;
                break;
        case LFUN_ENVIRONMENT_INSERT:
                code = BOX_CODE;
@@ -1953,7 +2053,6 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                // always allow this, since we will inset a raw quote
                // if an inset is not allowed.
                break;
-       case LFUN_HFILL_INSERT:
        case LFUN_SPECIALCHAR_INSERT:
                code = SPECIALCHAR_CODE;
                break;
@@ -2000,22 +2099,37 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                enable = cur.selection();
                break;
 
-       case LFUN_PASTE:
+       case LFUN_PASTE: {
                if (cmd.argument().empty()) {
                        if (theClipboard().isInternal())
                                enable = cap::numberOfSelections() > 0;
                        else
                                enable = !theClipboard().empty();
-               } else {
-                       string const arg = to_utf8(cmd.argument());
-                       if (isStrUnsignedInt(arg)) {
-                               unsigned int n = convert<unsigned int>(arg);
-                               enable = cap::numberOfSelections() > n;
-                       } else
-                               // unknown argument
-                               enable = false;
+                       break;
+               }
+               
+               // we have an argument
+               string const arg = to_utf8(cmd.argument());
+               if (isStrUnsignedInt(arg)) {
+                       // it's a number and therefore means the internal stack
+                       unsigned int n = convert<unsigned int>(arg);
+                       enable = cap::numberOfSelections() > n;
+                       break;
                }
+               
+               // explicit graphics type?
+               if ((arg == "pdf" && theClipboard().hasGraphicsContents(Clipboard::PdfGraphicsType))
+                   || (arg == "png" && theClipboard().hasGraphicsContents(Clipboard::PngGraphicsType))
+                   || (arg == "jpeg" && theClipboard().hasGraphicsContents(Clipboard::JpegGraphicsType))
+                   || (arg == "linkback" && theClipboard().hasGraphicsContents(Clipboard::LinkBackGraphicsType))) {
+                       enable = true;
+                       break;
+               }
+               
+               // unknown argument
+               enable = false;
                break;
+        }
 
        case LFUN_CLIPBOARD_PASTE:
                enable = !theClipboard().empty();
@@ -2037,7 +2151,7 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                if (!cmd.argument().empty()) {
                        InsetLayout il = cur.inset().getLayout(cur.buffer().params());
                        enable = cur.inset().lyxCode() == FLEX_CODE
-                                && il.lyxtype == to_utf8(cmd.argument());
+                                && il.lyxtype() == to_utf8(cmd.argument());
                } else {
                        enable = !isMainText(cur.bv().buffer()) 
                                 && cur.inset().nargs() == 1;
@@ -2059,7 +2173,12 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_OUTLINE_DOWN:
        case LFUN_OUTLINE_IN:
        case LFUN_OUTLINE_OUT:
-               enable = (cur.paragraph().layout()->toclevel != Layout::NOT_IN_TOC);
+               enable = (cur.paragraph().layout().toclevel != Layout::NOT_IN_TOC);
+               break;
+
+       case LFUN_NEWLINE_INSERT:
+               // LaTeX restrictions (labels or empty par)
+               enable = (cur.pos() > cur.paragraph().beginOfBody());
                break;
 
        case LFUN_WORD_DELETE_FORWARD:
@@ -2083,8 +2202,6 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_DOWN_SELECT:
        case LFUN_PARAGRAPH_UP_SELECT:
        case LFUN_PARAGRAPH_DOWN_SELECT:
-       case LFUN_SCREEN_UP_SELECT:
-       case LFUN_SCREEN_DOWN_SELECT:
        case LFUN_LINE_BEGIN_SELECT:
        case LFUN_LINE_END_SELECT:
        case LFUN_WORD_FORWARD_SELECT:
@@ -2095,9 +2212,7 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_PARAGRAPH_UP:
        case LFUN_PARAGRAPH_DOWN:
        case LFUN_LINE_BEGIN:
-       case LFUN_LINE_BREAK:
        case LFUN_LINE_END:
-       case LFUN_NEW_LINE:
        case LFUN_CHAR_DELETE_FORWARD:
        case LFUN_DELETE_FORWARD_SKIP:
        case LFUN_CHAR_DELETE_BACKWARD:
@@ -2112,16 +2227,12 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_CHARS_TRANSPOSE:
        case LFUN_SERVER_GET_XY:
        case LFUN_SERVER_SET_XY:
-       case LFUN_SERVER_GET_FONT:
        case LFUN_SERVER_GET_LAYOUT:
        case LFUN_LAYOUT:
        case LFUN_DATE_INSERT:
        case LFUN_SELF_INSERT:
        case LFUN_LINE_INSERT:
        case LFUN_NEWPAGE_INSERT:
-       case LFUN_PAGEBREAK_INSERT:
-       case LFUN_CLEARPAGE_INSERT:
-       case LFUN_CLEARDOUBLEPAGE_INSERT:
        case LFUN_MATH_DISPLAY:
        case LFUN_MATH_IMPORT_SELECTION:
        case LFUN_MATH_MODE:
@@ -2166,6 +2277,7 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_BUFFER_BEGIN_SELECT:
        case LFUN_BUFFER_END_SELECT:
        case LFUN_UNICODE_INSERT:
+       case LFUN_SET_GRAPHICS_GROUP:
                // these are handled in our dispatch()
                enable = true;
                break;